gitlab-labkit 0.13.4 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.gitlab/CODEOWNERS +1 -0
  3. data/.rubocop.yml +3 -0
  4. data/gitlab-labkit.gemspec +8 -3
  5. data/lib/gitlab-labkit.rb +29 -0
  6. data/lib/labkit/context.rb +12 -2
  7. data/lib/labkit/excon_publisher.rb +148 -0
  8. data/lib/labkit/httpclient_publisher.rb +66 -0
  9. data/lib/labkit/logging/grpc/server_interceptor.rb +6 -1
  10. data/lib/labkit/middleware/sidekiq/tracing/client.rb +1 -1
  11. data/lib/labkit/middleware/sidekiq/tracing/server.rb +1 -1
  12. data/lib/labkit/middleware/sidekiq/tracing/sidekiq_common.rb +14 -1
  13. data/lib/labkit/net_http_publisher.rb +88 -0
  14. data/lib/labkit/system.rb +13 -0
  15. data/lib/labkit/tracing.rb +4 -1
  16. data/lib/labkit/tracing/abstract_instrumenter.rb +47 -0
  17. data/lib/labkit/tracing/external_http.rb +26 -0
  18. data/lib/labkit/tracing/external_http/request_instrumenter.rb +33 -0
  19. data/lib/labkit/tracing/rails.rb +0 -2
  20. data/lib/labkit/tracing/rails/action_view.rb +14 -0
  21. data/lib/labkit/tracing/rails/action_view/render_collection_instrumenter.rb +7 -2
  22. data/lib/labkit/tracing/rails/action_view/render_partial_instrumenter.rb +7 -2
  23. data/lib/labkit/tracing/rails/action_view/render_template_instrumenter.rb +7 -2
  24. data/lib/labkit/tracing/rails/action_view/subscriber.rb +1 -1
  25. data/lib/labkit/tracing/rails/active_record/sql_instrumenter.rb +1 -1
  26. data/lib/labkit/tracing/rails/active_record/subscriber.rb +1 -1
  27. data/lib/labkit/tracing/rails/active_support/cache_delete_instrumenter.rb +1 -1
  28. data/lib/labkit/tracing/rails/active_support/cache_fetch_hit_instrumenter.rb +1 -1
  29. data/lib/labkit/tracing/rails/active_support/cache_generate_instrumenter.rb +1 -1
  30. data/lib/labkit/tracing/rails/active_support/cache_read_instrumenter.rb +1 -1
  31. data/lib/labkit/tracing/rails/active_support/cache_write_instrumenter.rb +1 -1
  32. data/lib/labkit/tracing/rails/active_support/subscriber.rb +1 -1
  33. data/lib/labkit/tracing/tracing_common.rb +20 -0
  34. data/lib/labkit/tracing/tracing_utils.rb +2 -0
  35. metadata +89 -12
  36. data/lib/labkit/tracing/rails/abstract_instrumenter.rb +0 -46
  37. data/lib/labkit/tracing/rails/rails_common.rb +0 -21
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5e864e350d93a5e548f45e62e01a17d202417b8a704b312459a2bbc473e138a5
4
- data.tar.gz: 3d4c3eca906b444e92a58f998b39053d749ab2ced25d749fee287bb890b68d78
3
+ metadata.gz: a1af5bacbedb8ce602015ad3de86ac23ddd28e2e17e78fac4dfb9d232ebe164f
4
+ data.tar.gz: caa3cb59ed0f1521530b7edfaa17234dcee23f7cdfca628d6aa2aac183fb3b4e
5
5
  SHA512:
6
- metadata.gz: 481b991d04eeb4dd91f4774656676044b10fac05aba31bdd2d1a84c2bd94b71b0a5e444c2d7639957cf63aecdba6bbc3a61548564414645b849a901449ec025b
7
- data.tar.gz: 44be5b6acde66b7d2ba1fed2413e85a9edeaff9cd66deab4b878b31498f7fdb77d015f6ebabfe8c6d52a4ba7fe2b26b5c6f2e1433a8c276a9f35b662516e7f14
6
+ metadata.gz: 36c847453715c4e1206839927383371369cfca346e1c2736f28b37a1425530047ea6d6c16bb5a7b732c7aa5d29eb2ab7a86f443b316d2abfbeae22828dcf04a9
7
+ data.tar.gz: f6c53e51b35f5e504f8f01d5b38578cc9ebdf41b34239385df4c7c0b8499be7ddfb375614e922297cff52affff96d8287477681153e854bf2fd86aa7ade9a425
@@ -0,0 +1 @@
1
+ * @andrewn @ayufan @reprazent
data/.rubocop.yml CHANGED
@@ -28,6 +28,9 @@ Style/StringLiterals:
28
28
  Style/StringLiteralsInInterpolation:
29
29
  EnforcedStyle: double_quotes
30
30
 
31
+ Style/UseLambda:
32
+ Enabled: false
33
+
31
34
  Layout/MultilineMethodCallIndentation:
32
35
  Enabled: No
33
36
 
@@ -19,19 +19,24 @@ Gem::Specification.new do |spec|
19
19
  spec.required_ruby_version = ">= 2.4.0"
20
20
 
21
21
  # Please maintain alphabetical order for dependencies
22
- spec.add_runtime_dependency "actionpack", ">= 5.0.0", "< 6.1.0"
23
- spec.add_runtime_dependency "activesupport", ">= 5.0.0", "< 6.1.0"
22
+ spec.add_runtime_dependency "actionpack", ">= 5.0.0", "< 7.0.0"
23
+ spec.add_runtime_dependency "activesupport", ">= 5.0.0", "< 7.0.0"
24
24
  spec.add_runtime_dependency "grpc", "~> 1.19" # Be sure to update the "grpc-tools" dev_depenency too
25
25
  spec.add_runtime_dependency "jaeger-client", "~> 1.1"
26
26
  spec.add_runtime_dependency "opentracing", "~> 0.4"
27
+ spec.add_runtime_dependency "pg_query", "~> 1.3"
27
28
  spec.add_runtime_dependency "redis", ">3.0.0", "<5.0.0"
28
- spec.add_runtime_dependency "gitlab-pg_query", "~> 1.3"
29
29
 
30
30
  # Please maintain alphabetical order for dev dependencies
31
+ spec.add_development_dependency "excon", "~> 0.78.1"
32
+ spec.add_development_dependency "faraday", "~> 1.2.0"
31
33
  spec.add_development_dependency "grpc-tools", "~> 1.19"
34
+ spec.add_development_dependency "httparty", "~> 0.17.3"
35
+ spec.add_development_dependency "httpclient", "~> 2.8.3"
32
36
  spec.add_development_dependency "pry", "~> 0.12"
33
37
  spec.add_development_dependency "rack", "~> 2.0"
34
38
  spec.add_development_dependency "rake", "~> 12.3"
39
+ spec.add_development_dependency "rest-client", "~> 2.1.0"
35
40
  spec.add_development_dependency "rspec", "~> 3.8.0"
36
41
  spec.add_development_dependency "rspec-parameterized", "~> 0.4"
37
42
  spec.add_development_dependency "rubocop", "~> 0.65.0"
data/lib/gitlab-labkit.rb CHANGED
@@ -7,11 +7,40 @@ require "active_support/all"
7
7
  # infrastructural concerns, partcularly related to
8
8
  # observability.
9
9
  module Labkit
10
+ autoload :System, "labkit/system"
11
+
10
12
  autoload :Correlation, "labkit/correlation"
11
13
  autoload :Context, "labkit/context"
12
14
  autoload :Tracing, "labkit/tracing"
13
15
  autoload :Logging, "labkit/logging"
14
16
  autoload :Middleware, "labkit/middleware"
17
+
18
+ # Publishers to publish notifications whenever a HTTP reqeust is made.
19
+ # A broadcasted notification's payload in topic "request.external_http" includes:
20
+ # + method (String): "GET"
21
+ # + code (String): "200" # This is the status code read directly from HTTP response
22
+ # + duration (Float - seconds): 0.234
23
+ # + host (String): "gitlab.com"
24
+ # + port (Integer): 80,
25
+ # + path (String): "/gitlab-org/gitlab"
26
+ # + scheme (String): "https"
27
+ # + query (String): "field_a=1&field_b=2"
28
+ # + fragment (String): "issue-number-1"
29
+ # + proxy_host (String - Optional): "proxy.gitlab.com"
30
+ # + proxy_port (Integer - Optional): 80
31
+ # + exception (Array<String> - Optional): ["Net::ReadTimeout", "Net::ReadTimeout with #<TCPSocket:(closed)>"]
32
+ # + exception_object (Error Object - Optional): #<Net::ReadTimeout: Net::ReadTimeout>
33
+ #
34
+ # Usage:
35
+ #
36
+ # ActiveSupport::Notifications.subscribe "request.external_http" do |name, started, finished, unique_id, data|
37
+ # puts "#{name} | #{started} | #{finished} | #{unique_id} | #{data.inspect}"
38
+ # end
39
+ #
40
+ EXTERNAL_HTTP_NOTIFICATION_TOPIC = "request.external_http"
41
+ autoload :NetHttpPublisher, "labkit/net_http_publisher"
42
+ autoload :ExconPublisher, "labkit/excon_publisher"
43
+ autoload :HTTPClientPublisher, "labkit/httpclient_publisher"
15
44
  end
16
45
 
17
46
  # rubocop:enable Naming/FileName
@@ -23,7 +23,7 @@ module Labkit
23
23
  RAW_KEYS = [CORRELATION_ID_KEY].freeze
24
24
  HEADER_PREFIX = "X-Gitlab-"
25
25
  KNOWN_KEYS = %w[user project root_namespace subscription_plan caller_id
26
- related_class feature_category].freeze
26
+ remote_ip related_class feature_category client_id].freeze
27
27
 
28
28
  class << self
29
29
  def with_context(attributes = {})
@@ -106,6 +106,12 @@ module Labkit
106
106
  end
107
107
  end
108
108
 
109
+ def get_attribute(attribute)
110
+ raw = call_or_value(data[log_key(attribute)])
111
+
112
+ call_or_value(raw)
113
+ end
114
+
109
115
  protected
110
116
 
111
117
  def assign_attributes(attributes)
@@ -130,9 +136,13 @@ module Labkit
130
136
 
131
137
  attr_reader :data
132
138
 
139
+ def call_or_value(value)
140
+ value.respond_to?(:call) ? value.call : value
141
+ end
142
+
133
143
  def expand_data
134
144
  data.transform_values do |value|
135
- value = value.respond_to?(:call) ? value.call : value
145
+ value = call_or_value(value)
136
146
 
137
147
  value.presence
138
148
  end.compact
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Labkit
4
+ ##
5
+ # A middleware for Excon HTTP library to publish a notification
6
+ # whenever a HTTP request is triggered.
7
+ #
8
+ # Excon supports a middleware system that allows request/response
9
+ # interception freely. Whenever a new Excon connection is created, a list of
10
+ # default middlewares is injected. This list of middlewares can be altered
11
+ # thanks to Excon.defaults accessor. ExconPublisher is inserted into this
12
+ # list. It affects all connections created in future. There is a limitation
13
+ # that this approach doesn't work if a user decides to override the default
14
+ # middleware list. It is unlikely though, at least in the dependency tree of
15
+ # GitLab.
16
+ #
17
+ # ExconPublisher instance is created once and shared between all Excon
18
+ # connections later. Each connection may be triggered by different threads in
19
+ # parallel. In such cases, a connection objects creates multiple sockets for
20
+ # each thread. Therfore in the implementation of this middleware, the
21
+ # instrumation payload for each connection is stored inside a thread-isolated
22
+ # storage.
23
+ #
24
+ # For more information:
25
+ # https://github.com/excon/excon/blob/81a0130537f2f8cd00d6daafb05d02d9a90dc9f7/lib/excon/middlewares/base.rb
26
+ # https://github.com/excon/excon/blob/fa3ec51e9bb062a12846a1cfff09534e76c99f4b/lib/excon/constants.rb#L146
27
+ # https://github.com/excon/excon/blob/fa3ec51e9bb062a12846a1cfff09534e76c99f4b/lib/excon/connection.rb#L474
28
+ class ExconPublisher
29
+ @prepend_mutex = Mutex.new
30
+
31
+ def self.labkit_prepend!
32
+ @prepend_mutex.synchronize do
33
+ return if !defined?(Excon) || @prepended
34
+
35
+ defaults = Excon.defaults
36
+ defaults[:middlewares] << ExconPublisher
37
+
38
+ @prepended = true
39
+ end
40
+ end
41
+
42
+ def initialize(stack)
43
+ @stack = stack
44
+ @instrumenter = ActiveSupport::Notifications.instrumenter
45
+ end
46
+
47
+ def request_call(datum)
48
+ payload = start_payload(datum)
49
+ store_connection_payload(datum, payload)
50
+ @instrumenter.start(::Labkit::EXTERNAL_HTTP_NOTIFICATION_TOPIC, payload)
51
+ @stack.request_call(datum)
52
+ end
53
+
54
+ def response_call(datum)
55
+ payload = fetch_connection_payload(datum)
56
+
57
+ return @stack.response_call(datum) if payload.nil?
58
+
59
+ calculate_duration(payload)
60
+ payload[:code] = datum[:response][:status].to_s
61
+
62
+ @instrumenter.finish(::Labkit::EXTERNAL_HTTP_NOTIFICATION_TOPIC, payload)
63
+ @stack.response_call(datum)
64
+ ensure
65
+ remove_connection_payload(datum)
66
+ end
67
+
68
+ def error_call(datum)
69
+ payload = fetch_connection_payload(datum)
70
+
71
+ return @stack.error_call(datum) if payload.nil?
72
+
73
+ calculate_duration(payload)
74
+
75
+ if datum[:error].is_a?(Exception)
76
+ payload[:exception] = [datum[:error].class.name, datum[:error].message]
77
+ payload[:exception_object] = datum[:error]
78
+ elsif datum[:error].is_a?(String)
79
+ exception = StandardError.new(datum[:error])
80
+ payload[:exception] = [exception.class.name, exception.message]
81
+ payload[:exception_object] = exception
82
+ end
83
+
84
+ @instrumenter.finish(::Labkit::EXTERNAL_HTTP_NOTIFICATION_TOPIC, payload)
85
+ @stack.error_call(datum)
86
+ ensure
87
+ remove_connection_payload(datum)
88
+ end
89
+
90
+ private
91
+
92
+ def start_payload(datum)
93
+ payload = {
94
+ method: datum[:method].to_s.upcase,
95
+ host: nil_or_string(datum[:host]),
96
+ path: nil_or_string(datum[:path]),
97
+ port: nil_or_int(datum[:port]),
98
+ scheme: nil_or_string(datum[:scheme]),
99
+ query: generate_query_string(datum[:query]),
100
+ start_time: ::Labkit::System.monotonic_time,
101
+ }
102
+ unless datum[:proxy].nil?
103
+ payload[:proxy_host] = datum[:proxy][:host]
104
+ payload[:proxy_port] = datum[:proxy][:port]
105
+ end
106
+ payload
107
+ end
108
+
109
+ def calculate_duration(payload)
110
+ start_time = payload.delete(:start_time) || ::Labkit::System.monotonic_time
111
+ payload[:duration] = (::Labkit::System.monotonic_time - start_time).to_f
112
+ end
113
+
114
+ def connection_payload
115
+ Thread.current[:__labkit_http_excon_payload] ||= {}
116
+ end
117
+
118
+ def store_connection_payload(datum, payload)
119
+ connection_payload[datum[:connection]] = payload
120
+ end
121
+
122
+ def fetch_connection_payload(datum)
123
+ connection_payload.fetch(datum[:connection], nil)
124
+ end
125
+
126
+ def remove_connection_payload(datum)
127
+ connection_payload.delete(datum[:connection])
128
+ end
129
+
130
+ def nil_or_string(str)
131
+ str&.to_s
132
+ end
133
+
134
+ def nil_or_int(int)
135
+ int&.to_i
136
+ rescue
137
+ nil
138
+ end
139
+
140
+ def generate_query_string(query)
141
+ if query.is_a?(Hash)
142
+ query.to_query
143
+ else
144
+ nil_or_string(query)
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Labkit
4
+ ##
5
+ # Prepend to HTTPClient class to publish an ActiveSupport::Notifcation
6
+ # whenever a HTTP request is triggered.
7
+ #
8
+ # Similar to Net::HTTP, this HTTP client redirects all calls to
9
+ # HTTPClient#do_get_block. HTTPClient is prepended with HTTPClientPublisher.
10
+ # Although HTTPClient supports request filter (a kind of middleware), its
11
+ # support is strictly limited. The request and response passed into the
12
+ # filter don't contain connection information. The response doesn't even
13
+ # contain any link to the request object. It's impossible to fit this filter
14
+ # mechanism into our subscribing model.
15
+ #
16
+ # For more information;
17
+ # https://github.com/nahi/httpclient/blob/d3091b095a1b29f65f4531a70a8e581e75be035e/lib/httpclient.rb#L1233
18
+ module HTTPClientPublisher
19
+ @prepend_mutex = Mutex.new
20
+
21
+ def self.labkit_prepend!
22
+ @prepend_mutex.synchronize do
23
+ return if !defined?(HTTPClient) || @prepended
24
+
25
+ HTTPClient.prepend(self)
26
+ @prepended = true
27
+ end
28
+ end
29
+
30
+ def do_get_block(req, proxy, conn, &block)
31
+ start_time = ::Labkit::System.monotonic_time
32
+ ActiveSupport::Notifications.instrument ::Labkit::EXTERNAL_HTTP_NOTIFICATION_TOPIC, create_request_payload(req, proxy) do |payload|
33
+ response =
34
+ begin
35
+ super
36
+ ensure
37
+ payload[:duration] = (::Labkit::System.monotonic_time - start_time).to_f
38
+ end
39
+ payload[:code] = response.status_code.to_s
40
+ response
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def create_request_payload(request, proxy)
47
+ http_header = request.http_header
48
+ payload = {
49
+ method: http_header.request_method,
50
+ host: http_header.request_uri.host,
51
+ path: http_header.request_uri.path,
52
+ port: http_header.request_uri.port,
53
+ scheme: http_header.request_uri.scheme,
54
+ query: http_header.request_uri.query,
55
+ fragment: http_header.request_uri.fragment,
56
+ }
57
+
58
+ unless proxy.nil?
59
+ payload[:proxy_host] = proxy.host
60
+ payload[:proxy_port] = proxy.port
61
+ end
62
+
63
+ payload
64
+ end
65
+ end
66
+ end
@@ -55,7 +55,7 @@ module Labkit
55
55
 
56
56
  private
57
57
 
58
- def log_request(method, call)
58
+ def log_request(method, _call)
59
59
  start = Time.now
60
60
  code = ::GRPC::Core::StatusCodes::OK
61
61
 
@@ -77,6 +77,11 @@ module Labkit
77
77
  time: Time.now.utc.strftime("%Y-%m-%dT%H:%M:%S.%LZ"),
78
78
  )
79
79
 
80
+ if ex
81
+ message["exception"] = ex.message
82
+ message["exception_backtrace"] = ex.backtrace[0..5] if ex.backtrace
83
+ end
84
+
80
85
  @log_file.puts(JSON.dump(message))
81
86
  end
82
87
  end
@@ -15,7 +15,7 @@ module Labkit
15
15
  SPAN_KIND = "client"
16
16
 
17
17
  def call(_worker_class, job, _queue, _redis_pool)
18
- Labkit::Tracing::TracingUtils.with_tracing(operation_name: "sidekiq:#{job["class"]}", tags: tags_from_job(job, SPAN_KIND)) do |span|
18
+ Labkit::Tracing::TracingUtils.with_tracing(operation_name: "sidekiq:#{job_class(job)}", tags: tags_from_job(job, SPAN_KIND)) do |span|
19
19
  # Inject the details directly into the job
20
20
  Labkit::Tracing::TracingUtils.tracer.inject(span.context, OpenTracing::FORMAT_TEXT_MAP, job)
21
21
 
@@ -17,7 +17,7 @@ module Labkit
17
17
  def call(_worker, job, _queue)
18
18
  context = Labkit::Tracing::TracingUtils.tracer.extract(OpenTracing::FORMAT_TEXT_MAP, job)
19
19
 
20
- Labkit::Tracing::TracingUtils.with_tracing(operation_name: "sidekiq:#{job["class"]}", child_of: context, tags: tags_from_job(job, SPAN_KIND)) { |_span| yield }
20
+ Labkit::Tracing::TracingUtils.with_tracing(operation_name: "sidekiq:#{job_class(job)}", child_of: context, tags: tags_from_job(job, SPAN_KIND)) { |_span| yield }
21
21
  end
22
22
  end
23
23
  end
@@ -6,15 +6,28 @@ module Labkit
6
6
  module Tracing
7
7
  # SidekiqCommon is a mixin for the sidekiq middleware components
8
8
  module SidekiqCommon
9
+ def job_class(job)
10
+ # Active Job wrapping can be found at
11
+ # https://github.com/rails/rails/blob/v6.0.3.1/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb
12
+ job["wrapped"].presence || job["class"].presence || "undefined"
13
+ end
14
+
15
+ def wrapped?(job)
16
+ job["wrapped"].present?
17
+ end
18
+
9
19
  def tags_from_job(job, kind)
10
- {
20
+ tags = {
11
21
  "component" => "sidekiq",
12
22
  "span.kind" => kind,
23
+ "sidekiq.wrapped" => wrapped?(job),
13
24
  "sidekiq.queue" => job["queue"],
14
25
  "sidekiq.jid" => job["jid"],
15
26
  "sidekiq.retry" => job["retry"].to_s,
16
27
  "sidekiq.args" => job["args"]&.join(", "),
17
28
  }
29
+ tags["sidekiq.at"] = job["at"] if job["at"]
30
+ tags
18
31
  end
19
32
  end
20
33
  end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Labkit
4
+ ##
5
+ # Prepend to Ruby's Net/HTTP standard HTTP library to publish a notification
6
+ # whenever a HTTP request is triggered. Net::HTTP has different class methods
7
+ # for each http method. Those methods are delegated to corresponding instance
8
+ # methods. Eventually, `request` method is call to dispatch the HTTP request.
9
+ # Therefore, a prepender that override `request` method covers all HTTP
10
+ # calls.
11
+ #
12
+ # For more information:
13
+ # https://github.com/ruby/ruby/blob/9b9cbbbc17bb5840581c7da37fd0feb0a7d4c1f3/lib/net/http.rb#L1510
14
+ #
15
+ # Note: some use cases to take care of
16
+ # - Create a request from input URI
17
+ # - Create a request from input host, port, and path string
18
+ # - Create a singular request and closes the connection immediately
19
+ # - Create a persistent connection and perform multiple HTTP requests
20
+ # - Notification payload must separate URI components
21
+ # - Create a post request with a body
22
+ # - Create a post request with form data
23
+ # - Create a request with basic authentication
24
+ # - Make a request via a proxy server
25
+ # - Streaming
26
+ module NetHttpPublisher
27
+ @prepend_mutex = Mutex.new
28
+
29
+ def self.labkit_prepend!
30
+ @prepend_mutex.synchronize do
31
+ return if @prepended
32
+
33
+ require "net/http"
34
+ Net::HTTP.prepend(self)
35
+ @prepended = true
36
+ end
37
+ end
38
+
39
+ def request(request, *args, &block)
40
+ return super unless started?
41
+
42
+ start_time = ::Labkit::System.monotonic_time
43
+
44
+ ActiveSupport::Notifications.instrument ::Labkit::EXTERNAL_HTTP_NOTIFICATION_TOPIC, create_request_payload(request) do |payload|
45
+ response =
46
+ begin
47
+ super
48
+ ensure
49
+ payload[:duration] = (::Labkit::System.monotonic_time - start_time).to_f
50
+ end
51
+ payload[:code] = response.code
52
+ response
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def create_request_payload(request)
59
+ payload = {
60
+ method: request.method,
61
+ }
62
+
63
+ if request.uri.nil?
64
+ path_uri = URI(request.path)
65
+ payload[:host] = address
66
+ payload[:path] = path_uri.path
67
+ payload[:port] = port
68
+ payload[:scheme] = use_ssl? ? "https" : "http"
69
+ payload[:query] = path_uri.query
70
+ payload[:fragment] = path_uri.fragment
71
+ else
72
+ payload[:host] = request.uri.host
73
+ payload[:path] = request.uri.path
74
+ payload[:port] = request.uri.port
75
+ payload[:scheme] = request.uri.scheme
76
+ payload[:query] = request.uri.query
77
+ payload[:fragment] = request.uri.fragment
78
+ end
79
+
80
+ if proxy?
81
+ payload[:proxy_host] = proxy_address
82
+ payload[:proxy_port] = proxy_port
83
+ end
84
+
85
+ payload
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Labkit
4
+ # A helper class to store system-related methods used in metrics, tracing, and logging
5
+ module System
6
+ # Returns the current monotonic clock time as seconds with microseconds precision.
7
+ #
8
+ # Returns the time as a Float.
9
+ def self.monotonic_time
10
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_second)
11
+ end
12
+ end
13
+ end
@@ -5,6 +5,8 @@ require "active_support/all"
5
5
  module Labkit
6
6
  # Tracing provides distributed tracing functionality
7
7
  module Tracing
8
+ autoload :AbstractInstrumenter, "labkit/tracing/abstract_instrumenter"
9
+ autoload :TracingCommon, "labkit/tracing/tracing_common"
8
10
  autoload :Factory, "labkit/tracing/factory"
9
11
  autoload :GRPC, "labkit/tracing/grpc"
10
12
  autoload :GRPCInterceptor, "labkit/tracing/grpc_interceptor" # Deprecated
@@ -12,6 +14,7 @@ module Labkit
12
14
  autoload :RackMiddleware, "labkit/tracing/rack_middleware"
13
15
  autoload :Rails, "labkit/tracing/rails"
14
16
  autoload :Redis, "labkit/tracing/redis"
17
+ autoload :ExternalHttp, "labkit/tracing/external_http"
15
18
  autoload :Sidekiq, "labkit/tracing/sidekiq"
16
19
  autoload :TracingUtils, "labkit/tracing/tracing_utils"
17
20
 
@@ -31,7 +34,7 @@ module Labkit
31
34
  # Check if the current request is being traced.
32
35
  def self.sampled?
33
36
  context = OpenTracing.active_span&.context
34
- context && context.respond_to?(:sampled?) && context.sampled?
37
+ context&.respond_to?(:sampled?) && context&.sampled?
35
38
  end
36
39
 
37
40
  def self.stacktrace_operations
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "opentracing"
4
+ require "active_support/all"
5
+
6
+ module Labkit
7
+ module Tracing
8
+ # https://edgeapi.rubyonrails.org/classes/ActiveSupport/Notifications/Instrumenter.html#method-c-new
9
+ class AbstractInstrumenter
10
+ def start(_name, _id, payload)
11
+ scope = OpenTracing.start_active_span(span_name(payload))
12
+
13
+ scope_stack.push scope
14
+ end
15
+
16
+ def finish(_name, _id, payload)
17
+ scope = scope_stack.pop
18
+ span = scope.span
19
+
20
+ Labkit::Tracing::TracingUtils.log_common_fields_on_span(span, span_name(payload))
21
+
22
+ # exception_object is the standard exception payload from ActiveSupport::Notifications
23
+ # https://github.com/rails/rails/blob/v6.0.3.1/activesupport/lib/active_support/notifications/instrumenter.rb#L26
24
+ exception = payload[:exception_object].presence || payload[:exception].presence
25
+ Labkit::Tracing::TracingUtils.log_exception_on_span(span, exception)
26
+
27
+ tags(payload).each do |k, v|
28
+ span.set_tag(k, v)
29
+ end
30
+
31
+ scope.close
32
+ end
33
+
34
+ def scope_stack
35
+ Thread.current[:_labkit_trace_scope_stack] ||= []
36
+ end
37
+
38
+ def span_name(_payload)
39
+ raise "span_name not implemented"
40
+ end
41
+
42
+ def tags(_payload)
43
+ {}
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Labkit
4
+ module Tracing
5
+ # Instrument external HTTP calls made by the HTTP client libraries. This
6
+ # tracing instrumenter listens to the events broadcasted from the
7
+ # publishers injected into the libraries whenever there is a request.
8
+ module ExternalHttp
9
+ include Labkit::Tracing::TracingCommon
10
+
11
+ autoload :RequestInstrumenter, "labkit/tracing/external_http/request_instrumenter"
12
+
13
+ def self.instrument
14
+ Labkit::NetHttpPublisher.labkit_prepend!
15
+ Labkit::ExconPublisher.labkit_prepend!
16
+ Labkit::HTTPClientPublisher.labkit_prepend!
17
+
18
+ subscriptions = [
19
+ ::ActiveSupport::Notifications.subscribe(::Labkit::EXTERNAL_HTTP_NOTIFICATION_TOPIC, RequestInstrumenter.new),
20
+ ]
21
+
22
+ create_unsubscriber subscriptions
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Labkit
4
+ module Tracing
5
+ module ExternalHttp
6
+ # For more information on the payloads: lib/labkit/net_http_publisher.rb
7
+ class RequestInstrumenter < Labkit::Tracing::AbstractInstrumenter
8
+ def span_name(_payload)
9
+ "external_http:request"
10
+ end
11
+
12
+ def tags(payload)
13
+ # Duration is calculated by start and end time
14
+ # Exception is already captured in lib/labkit/tracing/tracing_utils.rb
15
+ tags = {
16
+ "component" => "external_http",
17
+ "method" => payload[:method],
18
+ "code" => payload[:code],
19
+ "host" => payload[:host],
20
+ "port" => payload[:port],
21
+ "path" => payload[:path],
22
+ "scheme" => payload[:scheme],
23
+ }
24
+ unless payload[:proxy_host].nil?
25
+ tags["proxy_host"] = payload[:proxy_host]
26
+ tags["proxy_port"] = payload[:proxy_port]
27
+ end
28
+ tags
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -4,11 +4,9 @@ module Labkit
4
4
  module Tracing
5
5
  # Rails provides classes for instrumenting Rails events
6
6
  module Rails
7
- autoload :AbstractInstrumenter, "labkit/tracing/rails/abstract_instrumenter"
8
7
  autoload :ActionView, "labkit/tracing/rails/action_view"
9
8
  autoload :ActiveRecord, "labkit/tracing/rails/active_record"
10
9
  autoload :ActiveSupport, "labkit/tracing/rails/active_support"
11
- autoload :RailsCommon, "labkit/tracing/rails/rails_common"
12
10
 
13
11
  ActionViewSubscriber = ActionView::Subscriber
14
12
  ActiveRecordSubscriber = ActiveRecord::Subscriber
@@ -10,6 +10,20 @@ module Labkit
10
10
  autoload :Subscriber, "labkit/tracing/rails/action_view/subscriber"
11
11
 
12
12
  COMPONENT_TAG = "ActionView"
13
+
14
+ # Returns identifier relative to Rails.root. Rails supports different template types and returns corresponding identifiers:
15
+ # - Text template: the identifier is "text template"
16
+ # - Html template: the identifier is "html template"
17
+ # - Inline template: the identifier is "inline template"
18
+ # - Raw template: the identifier is the file path of the template
19
+ # Therefore, the amount of returned identifiers is static.
20
+ def self.template_identifier(payload)
21
+ return if !defined?(::Rails.root) || payload[:identifier].nil?
22
+
23
+ # Rails.root returns a Pathname object, whose `to_s` methods returns an absolute path without ending "/"
24
+ # Source: https://github.com/rails/rails/blob/v6.0.3.1/railties/lib/rails.rb#L64
25
+ payload[:identifier].sub("#{::Rails.root}/", "")
26
+ end
13
27
  end
14
28
  end
15
29
  end
@@ -5,9 +5,14 @@ module Labkit
5
5
  module Rails
6
6
  module ActionView
7
7
  # For more information on the payloads: https://guides.rubyonrails.org/active_support_instrumentation.html
8
- class RenderCollectionInstrumenter < AbstractInstrumenter
8
+ class RenderCollectionInstrumenter < Labkit::Tracing::AbstractInstrumenter
9
9
  def span_name(payload)
10
- "render_collection"
10
+ identifier = ActionView.template_identifier(payload)
11
+ if identifier.nil?
12
+ "render_collection"
13
+ else
14
+ "render_collection:#{identifier}"
15
+ end
11
16
  end
12
17
 
13
18
  def tags(payload)
@@ -5,9 +5,14 @@ module Labkit
5
5
  module Rails
6
6
  module ActionView
7
7
  # For more information on the payloads: https://guides.rubyonrails.org/active_support_instrumentation.html
8
- class RenderPartialInstrumenter < AbstractInstrumenter
8
+ class RenderPartialInstrumenter < Labkit::Tracing::AbstractInstrumenter
9
9
  def span_name(payload)
10
- "render_partial"
10
+ identifier = ActionView.template_identifier(payload)
11
+ if identifier.nil?
12
+ "render_partial"
13
+ else
14
+ "render_partial:#{identifier}"
15
+ end
11
16
  end
12
17
 
13
18
  def tags(payload)
@@ -5,9 +5,14 @@ module Labkit
5
5
  module Rails
6
6
  module ActionView
7
7
  # For more information on the payloads: https://guides.rubyonrails.org/active_support_instrumentation.html
8
- class RenderTemplateInstrumenter < AbstractInstrumenter
8
+ class RenderTemplateInstrumenter < Labkit::Tracing::AbstractInstrumenter
9
9
  def span_name(payload)
10
- "render_template"
10
+ identifier = ActionView.template_identifier(payload)
11
+ if identifier.nil?
12
+ "render_template"
13
+ else
14
+ "render_template:#{identifier}"
15
+ end
11
16
  end
12
17
 
13
18
  def tags(payload)
@@ -7,7 +7,7 @@ module Labkit
7
7
  # ActionView bridges action view notifications to
8
8
  # the distributed tracing subsystem
9
9
  class Subscriber
10
- include RailsCommon
10
+ include Labkit::Tracing::TracingCommon
11
11
 
12
12
  RENDER_TEMPLATE_NOTIFICATION_TOPIC = "render_template.action_view"
13
13
  RENDER_COLLECTION_NOTIFICATION_TOPIC = "render_collection.action_view"
@@ -5,7 +5,7 @@ module Labkit
5
5
  module Rails
6
6
  module ActiveRecord
7
7
  # For more information on the payloads: https://guides.rubyonrails.org/active_support_instrumentation.html
8
- class SqlInstrumenter < AbstractInstrumenter
8
+ class SqlInstrumenter < Labkit::Tracing::AbstractInstrumenter
9
9
  OPERATION_NAME_PREFIX = "active_record:"
10
10
  DEFAULT_OPERATION_NAME = "sqlquery"
11
11
 
@@ -7,7 +7,7 @@ module Labkit
7
7
  # ActiveRecord bridges active record notifications to
8
8
  # the distributed tracing subsystem
9
9
  class Subscriber
10
- include RailsCommon
10
+ include Labkit::Tracing::TracingCommon
11
11
 
12
12
  ACTIVE_RECORD_NOTIFICATION_TOPIC = "sql.active_record"
13
13
 
@@ -5,7 +5,7 @@ module Labkit
5
5
  module Rails
6
6
  module ActiveSupport
7
7
  # For more information on the payloads: https://guides.rubyonrails.org/active_support_instrumentation.html
8
- class CacheDeleteInstrumenter < AbstractInstrumenter
8
+ class CacheDeleteInstrumenter < Labkit::Tracing::AbstractInstrumenter
9
9
  def span_name(payload)
10
10
  "cache_delete"
11
11
  end
@@ -5,7 +5,7 @@ module Labkit
5
5
  module Rails
6
6
  module ActiveSupport
7
7
  # For more information on the payloads: https://guides.rubyonrails.org/active_support_instrumentation.html
8
- class CacheFetchHitInstrumenter < AbstractInstrumenter
8
+ class CacheFetchHitInstrumenter < Labkit::Tracing::AbstractInstrumenter
9
9
  def span_name(payload)
10
10
  "cache_fetch_hit"
11
11
  end
@@ -5,7 +5,7 @@ module Labkit
5
5
  module Rails
6
6
  module ActiveSupport
7
7
  # For more information on the payloads: https://guides.rubyonrails.org/active_support_instrumentation.html
8
- class CacheGenerateInstrumenter < AbstractInstrumenter
8
+ class CacheGenerateInstrumenter < Labkit::Tracing::AbstractInstrumenter
9
9
  def span_name(payload)
10
10
  "cache_generate"
11
11
  end
@@ -5,7 +5,7 @@ module Labkit
5
5
  module Rails
6
6
  module ActiveSupport
7
7
  # For more information on the payloads: https://guides.rubyonrails.org/active_support_instrumentation.html
8
- class CacheReadInstrumenter < AbstractInstrumenter
8
+ class CacheReadInstrumenter < Labkit::Tracing::AbstractInstrumenter
9
9
  def span_name(payload)
10
10
  "cache_read"
11
11
  end
@@ -5,7 +5,7 @@ module Labkit
5
5
  module Rails
6
6
  module ActiveSupport
7
7
  # For more information on the payloads: https://guides.rubyonrails.org/active_support_instrumentation.html
8
- class CacheWriteInstrumenter < AbstractInstrumenter
8
+ class CacheWriteInstrumenter < Labkit::Tracing::AbstractInstrumenter
9
9
  def span_name(payload)
10
10
  "cache_write"
11
11
  end
@@ -7,7 +7,7 @@ module Labkit
7
7
  # ActiveSupport bridges action active support notifications to
8
8
  # the distributed tracing subsystem
9
9
  class Subscriber
10
- include RailsCommon
10
+ include Labkit::Tracing::TracingCommon
11
11
 
12
12
  CACHE_READ_TOPIC = "cache_read.active_support"
13
13
  CACHE_GENERATE_TOPIC = "cache_generate.active_support"
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/all"
4
+
5
+ module Labkit
6
+ module Tracing
7
+ # TracingCommon is a mixin for providing instrumentation
8
+ # functionality for the instrumentation classes based on
9
+ # ActiveSupport::Notifications
10
+ module TracingCommon
11
+ extend ::ActiveSupport::Concern
12
+
13
+ class_methods do
14
+ def create_unsubscriber(subscriptions)
15
+ -> { subscriptions.each { |subscriber| ::ActiveSupport::Notifications.unsubscribe(subscriber) } }
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -48,6 +48,8 @@ module Labkit
48
48
 
49
49
  # Add exception logging to a span
50
50
  def self.log_exception_on_span(span, exception)
51
+ return if exception.blank?
52
+
51
53
  span.set_tag("error", true)
52
54
  span.log_kv(**kv_tags_for_exception(exception))
53
55
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-labkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.4
4
+ version: 0.16.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Newdigate
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-12-14 00:00:00.000000000 Z
11
+ date: 2021-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: 5.0.0
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: 6.1.0
22
+ version: 7.0.0
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  version: 5.0.0
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: 6.1.0
32
+ version: 7.0.0
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: activesupport
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -39,7 +39,7 @@ dependencies:
39
39
  version: 5.0.0
40
40
  - - "<"
41
41
  - !ruby/object:Gem::Version
42
- version: 6.1.0
42
+ version: 7.0.0
43
43
  type: :runtime
44
44
  prerelease: false
45
45
  version_requirements: !ruby/object:Gem::Requirement
@@ -49,7 +49,7 @@ dependencies:
49
49
  version: 5.0.0
50
50
  - - "<"
51
51
  - !ruby/object:Gem::Version
52
- version: 6.1.0
52
+ version: 7.0.0
53
53
  - !ruby/object:Gem::Dependency
54
54
  name: grpc
55
55
  requirement: !ruby/object:Gem::Requirement
@@ -92,6 +92,20 @@ dependencies:
92
92
  - - "~>"
93
93
  - !ruby/object:Gem::Version
94
94
  version: '0.4'
95
+ - !ruby/object:Gem::Dependency
96
+ name: pg_query
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '1.3'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - "~>"
107
+ - !ruby/object:Gem::Version
108
+ version: '1.3'
95
109
  - !ruby/object:Gem::Dependency
96
110
  name: redis
97
111
  requirement: !ruby/object:Gem::Requirement
@@ -113,19 +127,33 @@ dependencies:
113
127
  - !ruby/object:Gem::Version
114
128
  version: 5.0.0
115
129
  - !ruby/object:Gem::Dependency
116
- name: gitlab-pg_query
130
+ name: excon
117
131
  requirement: !ruby/object:Gem::Requirement
118
132
  requirements:
119
133
  - - "~>"
120
134
  - !ruby/object:Gem::Version
121
- version: '1.3'
122
- type: :runtime
135
+ version: 0.78.1
136
+ type: :development
123
137
  prerelease: false
124
138
  version_requirements: !ruby/object:Gem::Requirement
125
139
  requirements:
126
140
  - - "~>"
127
141
  - !ruby/object:Gem::Version
128
- version: '1.3'
142
+ version: 0.78.1
143
+ - !ruby/object:Gem::Dependency
144
+ name: faraday
145
+ requirement: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - "~>"
148
+ - !ruby/object:Gem::Version
149
+ version: 1.2.0
150
+ type: :development
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - "~>"
155
+ - !ruby/object:Gem::Version
156
+ version: 1.2.0
129
157
  - !ruby/object:Gem::Dependency
130
158
  name: grpc-tools
131
159
  requirement: !ruby/object:Gem::Requirement
@@ -140,6 +168,34 @@ dependencies:
140
168
  - - "~>"
141
169
  - !ruby/object:Gem::Version
142
170
  version: '1.19'
171
+ - !ruby/object:Gem::Dependency
172
+ name: httparty
173
+ requirement: !ruby/object:Gem::Requirement
174
+ requirements:
175
+ - - "~>"
176
+ - !ruby/object:Gem::Version
177
+ version: 0.17.3
178
+ type: :development
179
+ prerelease: false
180
+ version_requirements: !ruby/object:Gem::Requirement
181
+ requirements:
182
+ - - "~>"
183
+ - !ruby/object:Gem::Version
184
+ version: 0.17.3
185
+ - !ruby/object:Gem::Dependency
186
+ name: httpclient
187
+ requirement: !ruby/object:Gem::Requirement
188
+ requirements:
189
+ - - "~>"
190
+ - !ruby/object:Gem::Version
191
+ version: 2.8.3
192
+ type: :development
193
+ prerelease: false
194
+ version_requirements: !ruby/object:Gem::Requirement
195
+ requirements:
196
+ - - "~>"
197
+ - !ruby/object:Gem::Version
198
+ version: 2.8.3
143
199
  - !ruby/object:Gem::Dependency
144
200
  name: pry
145
201
  requirement: !ruby/object:Gem::Requirement
@@ -182,6 +238,20 @@ dependencies:
182
238
  - - "~>"
183
239
  - !ruby/object:Gem::Version
184
240
  version: '12.3'
241
+ - !ruby/object:Gem::Dependency
242
+ name: rest-client
243
+ requirement: !ruby/object:Gem::Requirement
244
+ requirements:
245
+ - - "~>"
246
+ - !ruby/object:Gem::Version
247
+ version: 2.1.0
248
+ type: :development
249
+ prerelease: false
250
+ version_requirements: !ruby/object:Gem::Requirement
251
+ requirements:
252
+ - - "~>"
253
+ - !ruby/object:Gem::Version
254
+ version: 2.1.0
185
255
  - !ruby/object:Gem::Dependency
186
256
  name: rspec
187
257
  requirement: !ruby/object:Gem::Requirement
@@ -275,6 +345,7 @@ extra_rdoc_files: []
275
345
  files:
276
346
  - ".gitignore"
277
347
  - ".gitlab-ci.yml"
348
+ - ".gitlab/CODEOWNERS"
278
349
  - ".rspec"
279
350
  - ".rubocop.yml"
280
351
  - ".ruby-version"
@@ -292,6 +363,8 @@ files:
292
363
  - lib/labkit/correlation/grpc/client_interceptor.rb
293
364
  - lib/labkit/correlation/grpc/grpc_common.rb
294
365
  - lib/labkit/correlation/grpc/server_interceptor.rb
366
+ - lib/labkit/excon_publisher.rb
367
+ - lib/labkit/httpclient_publisher.rb
295
368
  - lib/labkit/logging.rb
296
369
  - lib/labkit/logging/grpc.rb
297
370
  - lib/labkit/logging/grpc/server_interceptor.rb
@@ -308,7 +381,12 @@ files:
308
381
  - lib/labkit/middleware/sidekiq/tracing/client.rb
309
382
  - lib/labkit/middleware/sidekiq/tracing/server.rb
310
383
  - lib/labkit/middleware/sidekiq/tracing/sidekiq_common.rb
384
+ - lib/labkit/net_http_publisher.rb
385
+ - lib/labkit/system.rb
311
386
  - lib/labkit/tracing.rb
387
+ - lib/labkit/tracing/abstract_instrumenter.rb
388
+ - lib/labkit/tracing/external_http.rb
389
+ - lib/labkit/tracing/external_http/request_instrumenter.rb
312
390
  - lib/labkit/tracing/factory.rb
313
391
  - lib/labkit/tracing/grpc.rb
314
392
  - lib/labkit/tracing/grpc/client_interceptor.rb
@@ -317,7 +395,6 @@ files:
317
395
  - lib/labkit/tracing/jaeger_factory.rb
318
396
  - lib/labkit/tracing/rack_middleware.rb
319
397
  - lib/labkit/tracing/rails.rb
320
- - lib/labkit/tracing/rails/abstract_instrumenter.rb
321
398
  - lib/labkit/tracing/rails/action_view.rb
322
399
  - lib/labkit/tracing/rails/action_view/render_collection_instrumenter.rb
323
400
  - lib/labkit/tracing/rails/action_view/render_partial_instrumenter.rb
@@ -333,10 +410,10 @@ files:
333
410
  - lib/labkit/tracing/rails/active_support/cache_read_instrumenter.rb
334
411
  - lib/labkit/tracing/rails/active_support/cache_write_instrumenter.rb
335
412
  - lib/labkit/tracing/rails/active_support/subscriber.rb
336
- - lib/labkit/tracing/rails/rails_common.rb
337
413
  - lib/labkit/tracing/redis.rb
338
414
  - lib/labkit/tracing/redis/redis_interceptor.rb
339
415
  - lib/labkit/tracing/redis/redis_interceptor_helper.rb
416
+ - lib/labkit/tracing/tracing_common.rb
340
417
  - lib/labkit/tracing/tracing_utils.rb
341
418
  homepage: https://gitlab.com/gitlab-org/labkit-ruby
342
419
  licenses:
@@ -1,46 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "active_support/all"
4
-
5
- module Labkit
6
- module Tracing
7
- module Rails
8
- # https://edgeapi.rubyonrails.org/classes/ActiveSupport/Notifications/Instrumenter.html#method-c-new
9
- class AbstractInstrumenter
10
- def start(name, id, payload)
11
- scope = OpenTracing.start_active_span(span_name(payload))
12
-
13
- scope_stack.push scope
14
- end
15
-
16
- def finish(name, id, payload)
17
- scope = scope_stack.pop
18
- span = scope.span
19
-
20
- Labkit::Tracing::TracingUtils.log_common_fields_on_span(span, span_name(payload))
21
-
22
- exception = payload[:exception]
23
- Labkit::Tracing::TracingUtils.log_exception_on_span(span, exception) if exception
24
-
25
- tags(payload).each do |k, v|
26
- span.set_tag(k, v)
27
- end
28
-
29
- scope.close
30
- end
31
-
32
- def scope_stack
33
- Thread.current[:_labkit_trace_scope_stack] ||= []
34
- end
35
-
36
- def span_name(payload)
37
- raise "span_name not implemented"
38
- end
39
-
40
- def tags(payload)
41
- {}
42
- end
43
- end
44
- end
45
- end
46
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "active_support/all"
4
-
5
- module Labkit
6
- module Tracing
7
- module Rails
8
- # RailsCommon is a mixin for providing instrumentation
9
- # functionality for the rails instrumentation classes
10
- module RailsCommon
11
- extend ::ActiveSupport::Concern
12
-
13
- class_methods do
14
- def create_unsubscriber(subscriptions)
15
- -> { subscriptions.each { |subscriber| ::ActiveSupport::Notifications.unsubscribe(subscriber) } }
16
- end
17
- end
18
- end
19
- end
20
- end
21
- end