summaryrefslogtreecommitdiff
path: root/lib/gitlab/tracing/rails/action_view_subscriber.rb
blob: 88816e1fb32148bee5d7729b4a0af6722e06498c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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