diff options
author | Andrew Newdigate <andrew@gitlab.com> | 2019-01-28 16:47:48 +0300 |
---|---|---|
committer | Andrew Newdigate <andrew@gitlab.com> | 2019-01-30 14:38:19 +0300 |
commit | d022ce865502c051c9177fc0f5b2453eae7e7cc2 (patch) | |
tree | a2cb931fc9b75dfe538979b1e478048b2a0591de /lib | |
parent | c2b3f64cb44114e69ddeeb453412ad4dd762baf9 (diff) |
Add OpenTracing instrumentation for Action View Render events
This change adds three new instrumentations, driven through rails
notifications: render_template.action_view,
render_collection.action_view and render_partial.action_view.
These can help developers understand why renders are taking a long
time which may in turn help them to improve their performance.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/gitlab/tracing/rails/action_view_subscriber.rb | 75 | ||||
-rw-r--r-- | lib/gitlab/tracing/rails/active_record_subscriber.rb | 27 | ||||
-rw-r--r-- | lib/gitlab/tracing/rails/rails_common.rb | 24 |
3 files changed, 118 insertions, 8 deletions
diff --git a/lib/gitlab/tracing/rails/action_view_subscriber.rb b/lib/gitlab/tracing/rails/action_view_subscriber.rb new file mode 100644 index 00000000000..88816e1fb32 --- /dev/null +++ b/lib/gitlab/tracing/rails/action_view_subscriber.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +module Gitlab + module Tracing + module Rails + class ActionViewSubscriber + include RailsCommon + + COMPONENT_TAG = 'ActionView' + RENDER_TEMPLATE_NOTIFICATION_TOPIC = 'render_template.action_view' + RENDER_COLLECTION_NOTIFICATION_TOPIC = 'render_collection.action_view' + RENDER_PARTIAL_NOTIFICATION_TOPIC = 'render_partial.action_view' + + # Instruments Rails ActionView events for opentracing. + # Returns a lambda, which, when called will unsubscribe from the notifications + def self.instrument + subscriber = new + + subscriptions = [ + ActiveSupport::Notifications.subscribe(RENDER_TEMPLATE_NOTIFICATION_TOPIC) do |_, start, finish, _, payload| + subscriber.notify_render_template(start, finish, payload) + end, + ActiveSupport::Notifications.subscribe(RENDER_COLLECTION_NOTIFICATION_TOPIC) do |_, start, finish, _, payload| + subscriber.notify_render_collection(start, finish, payload) + end, + ActiveSupport::Notifications.subscribe(RENDER_PARTIAL_NOTIFICATION_TOPIC) do |_, start, finish, _, payload| + subscriber.notify_render_partial(start, finish, payload) + end + ] + + create_unsubscriber subscriptions + end + + # For more information on the payloads: https://guides.rubyonrails.org/active_support_instrumentation.html + def notify_render_template(start, finish, payload) + generate_span_for_notification("render_template", start, finish, payload, tags_for_render_template(payload)) + end + + def notify_render_collection(start, finish, payload) + generate_span_for_notification("render_collection", start, finish, payload, tags_for_render_collection(payload)) + end + + def notify_render_partial(start, finish, payload) + generate_span_for_notification("render_partial", start, finish, payload, tags_for_render_partial(payload)) + end + + private + + def tags_for_render_template(payload) + { + 'component' => COMPONENT_TAG, + 'template.id' => payload[:identifier], + 'template.layout' => payload[:layout] + } + end + + def tags_for_render_collection(payload) + { + 'component' => COMPONENT_TAG, + 'template.id' => payload[:identifier], + 'template.count' => payload[:count] || 0, + 'template.cache.hits' => payload[:cache_hits] || 0 + } + end + + def tags_for_render_partial(payload) + { + 'component' => COMPONENT_TAG, + 'template.id' => payload[:identifier] + } + end + end + end + end +end diff --git a/lib/gitlab/tracing/rails/active_record_subscriber.rb b/lib/gitlab/tracing/rails/active_record_subscriber.rb index 214eac47e14..32f5658e57e 100644 --- a/lib/gitlab/tracing/rails/active_record_subscriber.rb +++ b/lib/gitlab/tracing/rails/active_record_subscriber.rb @@ -4,24 +4,37 @@ module Gitlab module Tracing module Rails class ActiveRecordSubscriber - include Gitlab::Tracing::Common + include RailsCommon ACTIVE_RECORD_NOTIFICATION_TOPIC = 'sql.active_record' - DEFAULT_OPERATION_NAME = "sqlquery" + OPERATION_NAME_PREFIX = 'active_record:' + DEFAULT_OPERATION_NAME = 'sqlquery' + # Instruments Rails ActiveRecord events for opentracing. + # Returns a lambda, which, when called will unsubscribe from the notifications def self.instrument subscriber = new - ActiveSupport::Notifications.subscribe(ACTIVE_RECORD_NOTIFICATION_TOPIC) do |_, start, finish, _, payload| + subscription = ActiveSupport::Notifications.subscribe(ACTIVE_RECORD_NOTIFICATION_TOPIC) do |_, start, finish, _, payload| subscriber.notify(start, finish, payload) end + + create_unsubscriber [subscription] end # For more information on the payloads: https://guides.rubyonrails.org/active_support_instrumentation.html def notify(start, finish, payload) - operation_name = payload[:name].presence || DEFAULT_OPERATION_NAME - exception = payload[:exception] - tags = { + generate_span_for_notification(notification_name(payload), start, finish, payload, tags_for_notification(payload)) + end + + private + + def notification_name(payload) + OPERATION_NAME_PREFIX + (payload[:name].presence || DEFAULT_OPERATION_NAME) + end + + def tags_for_notification(payload) + { 'component' => 'ActiveRecord', 'span.kind' => 'client', 'db.type' => 'sql', @@ -29,8 +42,6 @@ module Gitlab 'db.cached' => payload[:cached] || false, 'db.statement' => payload[:sql] } - - postnotify_span("active_record:#{operation_name}", start, finish, tags: tags, exception: exception) end end end diff --git a/lib/gitlab/tracing/rails/rails_common.rb b/lib/gitlab/tracing/rails/rails_common.rb new file mode 100644 index 00000000000..88e914f62f8 --- /dev/null +++ b/lib/gitlab/tracing/rails/rails_common.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module Gitlab + module Tracing + module Rails + module RailsCommon + extend ActiveSupport::Concern + include Gitlab::Tracing::Common + + class_methods do + def create_unsubscriber(subscriptions) + -> { subscriptions.each { |subscriber| ActiveSupport::Notifications.unsubscribe(subscriber) } } + end + end + + def generate_span_for_notification(operation_name, start, finish, payload, tags) + exception = payload[:exception] + + postnotify_span(operation_name, start, finish, tags: tags, exception: exception) + end + end + end + end +end |