gitlab-labkit 0.13.2 → 0.15.0

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.gitlab-ci.yml +4 -4
  4. data/.gitlab/CODEOWNERS +1 -0
  5. data/.rubocop.yml +3 -0
  6. data/.ruby-version +1 -1
  7. data/gitlab-labkit.gemspec +8 -2
  8. data/lib/gitlab-labkit.rb +29 -0
  9. data/lib/labkit/context.rb +12 -1
  10. data/lib/labkit/excon_publisher.rb +148 -0
  11. data/lib/labkit/httpclient_publisher.rb +66 -0
  12. data/lib/labkit/logging/grpc/server_interceptor.rb +3 -1
  13. data/lib/labkit/logging/sanitizer.rb +8 -0
  14. data/lib/labkit/middleware/sidekiq/tracing/client.rb +1 -1
  15. data/lib/labkit/middleware/sidekiq/tracing/server.rb +1 -1
  16. data/lib/labkit/middleware/sidekiq/tracing/sidekiq_common.rb +14 -1
  17. data/lib/labkit/net_http_publisher.rb +88 -0
  18. data/lib/labkit/system.rb +13 -0
  19. data/lib/labkit/tracing.rb +9 -0
  20. data/lib/labkit/tracing/abstract_instrumenter.rb +47 -0
  21. data/lib/labkit/tracing/external_http.rb +26 -0
  22. data/lib/labkit/tracing/external_http/request_instrumenter.rb +33 -0
  23. data/lib/labkit/tracing/jaeger_factory.rb +1 -1
  24. data/lib/labkit/tracing/rails.rb +0 -2
  25. data/lib/labkit/tracing/rails/action_view.rb +14 -0
  26. data/lib/labkit/tracing/rails/action_view/render_collection_instrumenter.rb +7 -2
  27. data/lib/labkit/tracing/rails/action_view/render_partial_instrumenter.rb +7 -2
  28. data/lib/labkit/tracing/rails/action_view/render_template_instrumenter.rb +7 -2
  29. data/lib/labkit/tracing/rails/action_view/subscriber.rb +1 -1
  30. data/lib/labkit/tracing/rails/active_record/sql_instrumenter.rb +3 -2
  31. data/lib/labkit/tracing/rails/active_record/subscriber.rb +1 -1
  32. data/lib/labkit/tracing/rails/active_support/cache_delete_instrumenter.rb +1 -1
  33. data/lib/labkit/tracing/rails/active_support/cache_fetch_hit_instrumenter.rb +1 -1
  34. data/lib/labkit/tracing/rails/active_support/cache_generate_instrumenter.rb +1 -1
  35. data/lib/labkit/tracing/rails/active_support/cache_read_instrumenter.rb +1 -1
  36. data/lib/labkit/tracing/rails/active_support/cache_write_instrumenter.rb +1 -1
  37. data/lib/labkit/tracing/rails/active_support/subscriber.rb +1 -1
  38. data/lib/labkit/tracing/tracing_common.rb +20 -0
  39. data/lib/labkit/tracing/tracing_utils.rb +3 -1
  40. metadata +99 -8
  41. data/lib/labkit/tracing/rails/abstract_instrumenter.rb +0 -46
  42. 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: 458dd268746446a442c85e56a58ebc2005a169822856cf041e30444c649cd02a
4
- data.tar.gz: 73613e1ad1aacf1f67bd9875622e97475600f65a2a5624b0cf39c79ba434b300
3
+ metadata.gz: 26359f4fec97f64445df7d373d67cd7344e415d4b8db5adedce24d02f03228ec
4
+ data.tar.gz: 11f8e6195ec18d7a3ea81b2b533609ae68f76f50f55ae32fb5b3c4b41434ebaf
5
5
  SHA512:
6
- metadata.gz: 111b312fac281429728c2e33c2e57548c643b7ead4079c86ae6ab766c670b23417e336610acb4a7b1fe6d9e297f6d2080192029e04a229b8956f1a9293cb0ce9
7
- data.tar.gz: 17ea39978f5cd418ffe33f6fe2baf931fcd76cf3bfe7c47cfca9a0acdedf97cf2078ff64a18a10c0735f9bc87e3ad7a76369191a3394dfcb8a74a6bebe16406d
6
+ metadata.gz: 2fb683c423ec1e34fc92b5dda0e2973b2259768a6dccf5fca9c6f3d7089d3130bf8e820ca8e751f27c325399b0739a73ae145667702f395e98e09dd58ff18fac
7
+ data.tar.gz: 1dbab7f8469391b9d6105aef90d3cc0af93ac87622a49052780ce843be941f592f4174fa5bff493cf528c8e1aceef1aad0352b992215309935e6f1edbd5bacfd
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  Gemfile.lock
2
2
  *.gem
3
3
  node_modules
4
+ .bundle
data/.gitlab-ci.yml CHANGED
@@ -14,6 +14,10 @@ workflow:
14
14
  - bundle install
15
15
  - bundle exec rake verify build install
16
16
 
17
+ test:2.7:
18
+ image: ruby:2.7
19
+ <<: *test_definition
20
+
17
21
  test:2.6:
18
22
  image: ruby:2.6
19
23
  <<: *test_definition
@@ -22,10 +26,6 @@ test:2.5:
22
26
  image: ruby:2.5
23
27
  <<: *test_definition
24
28
 
25
- test:2.4:
26
- image: ruby:2.4
27
- <<: *test_definition
28
-
29
29
  deploy:
30
30
  stage: deploy
31
31
  script:
@@ -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
 
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.6.3
1
+ 2.7.2
@@ -19,18 +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
29
 
29
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"
30
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"
31
36
  spec.add_development_dependency "pry", "~> 0.12"
32
37
  spec.add_development_dependency "rack", "~> 2.0"
33
38
  spec.add_development_dependency "rake", "~> 12.3"
39
+ spec.add_development_dependency "rest-client", "~> 2.1.0"
34
40
  spec.add_development_dependency "rspec", "~> 3.8.0"
35
41
  spec.add_development_dependency "rspec-parameterized", "~> 0.4"
36
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
@@ -21,8 +21,9 @@ module Labkit
21
21
  LOG_KEY = "meta"
22
22
  CORRELATION_ID_KEY = "correlation_id"
23
23
  RAW_KEYS = [CORRELATION_ID_KEY].freeze
24
+ HEADER_PREFIX = "X-Gitlab-"
24
25
  KNOWN_KEYS = %w[user project root_namespace subscription_plan caller_id
25
- related_class feature_category].freeze
26
+ remote_ip related_class feature_category].freeze
26
27
 
27
28
  class << self
28
29
  def with_context(attributes = {})
@@ -67,6 +68,10 @@ module Labkit
67
68
  @known_log_keys ||= (KNOWN_KEYS.map(&method(:log_key)) + RAW_KEYS).freeze
68
69
  end
69
70
 
71
+ def header_name(name)
72
+ HEADER_PREFIX + log_key(name).titlecase(keep_id_suffix: true).gsub(/\W/, "-")
73
+ end
74
+
70
75
  private
71
76
 
72
77
  def contexts
@@ -95,6 +100,12 @@ module Labkit
95
100
  data[CORRELATION_ID_KEY]
96
101
  end
97
102
 
103
+ def to_headers
104
+ to_h.except(CORRELATION_ID_KEY).transform_keys do |key|
105
+ self.class.header_name(key)
106
+ end
107
+ end
108
+
98
109
  protected
99
110
 
100
111
  def assign_attributes(attributes)
@@ -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,8 @@ module Labkit
77
77
  time: Time.now.utc.strftime("%Y-%m-%dT%H:%M:%S.%LZ"),
78
78
  )
79
79
 
80
+ message["exception"] = ex.message if ex
81
+
80
82
  @log_file.puts(JSON.dump(message))
81
83
  end
82
84
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "pg_query"
4
+
3
5
  module Labkit
4
6
  module Logging
5
7
  # Sanitizer provides log message sanitization, removing
@@ -22,6 +24,12 @@ module Labkit
22
24
  content
23
25
  end
24
26
 
27
+ def self.sanitize_sql(sql)
28
+ PgQuery.normalize(sql)
29
+ rescue PgQuery::ParseError
30
+ ""
31
+ end
32
+
25
33
  # Ensures that URLS are sanitized to hide credentials
26
34
  def self.mask_url(url)
27
35
  url = url.to_s.strip
@@ -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
 
@@ -28,6 +31,12 @@ module Labkit
28
31
  ENV["GITLAB_TRACING_URL"]
29
32
  end
30
33
 
34
+ # Check if the current request is being traced.
35
+ def self.sampled?
36
+ context = OpenTracing.active_span&.context
37
+ context&.respond_to?(:sampled?) && context&.sampled?
38
+ end
39
+
31
40
  def self.stacktrace_operations
32
41
  @stacktrace_operations ||= Set.new(ENV["GITLAB_TRACING_INCLUDE_STACKTRACE"].to_s.split(",").map(&:strip))
33
42
  end
@@ -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
@@ -37,7 +37,7 @@ module Labkit
37
37
  warn message
38
38
  end
39
39
 
40
- Jaeger::Client.build(kwargs)
40
+ Jaeger::Client.build(**kwargs)
41
41
  end
42
42
 
43
43
  def self.get_sampler(sampler_type, sampler_param)
@@ -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
 
@@ -14,13 +14,14 @@ module Labkit
14
14
  end
15
15
 
16
16
  def tags(payload)
17
+ sql = Labkit::Logging::Sanitizer.sanitize_sql(payload[:sql]) if Labkit::Tracing.sampled? && payload[:sql]
17
18
  {
18
19
  "component" => COMPONENT_TAG,
19
20
  "span.kind" => "client",
20
21
  "db.type" => "sql",
21
22
  "db.connection_id" => payload[:connection_id],
22
23
  "db.cached" => payload[:cached] || false,
23
- "db.statement" => payload[:sql],
24
+ "db.statement" => sql,
24
25
  }
25
26
  end
26
27
  end
@@ -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,8 +48,10 @@ 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
- span.log_kv(kv_tags_for_exception(exception))
54
+ span.log_kv(**kv_tags_for_exception(exception))
53
55
  end
54
56
 
55
57
  # Generate key-value tags for an exception
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.2
4
+ version: 0.15.0
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-10-28 00:00:00.000000000 Z
11
+ date: 2021-02-10 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
@@ -112,6 +126,34 @@ dependencies:
112
126
  - - "<"
113
127
  - !ruby/object:Gem::Version
114
128
  version: 5.0.0
129
+ - !ruby/object:Gem::Dependency
130
+ name: excon
131
+ requirement: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - "~>"
134
+ - !ruby/object:Gem::Version
135
+ version: 0.78.1
136
+ type: :development
137
+ prerelease: false
138
+ version_requirements: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - "~>"
141
+ - !ruby/object:Gem::Version
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
115
157
  - !ruby/object:Gem::Dependency
116
158
  name: grpc-tools
117
159
  requirement: !ruby/object:Gem::Requirement
@@ -126,6 +168,34 @@ dependencies:
126
168
  - - "~>"
127
169
  - !ruby/object:Gem::Version
128
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
129
199
  - !ruby/object:Gem::Dependency
130
200
  name: pry
131
201
  requirement: !ruby/object:Gem::Requirement
@@ -168,6 +238,20 @@ dependencies:
168
238
  - - "~>"
169
239
  - !ruby/object:Gem::Version
170
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
171
255
  - !ruby/object:Gem::Dependency
172
256
  name: rspec
173
257
  requirement: !ruby/object:Gem::Requirement
@@ -261,6 +345,7 @@ extra_rdoc_files: []
261
345
  files:
262
346
  - ".gitignore"
263
347
  - ".gitlab-ci.yml"
348
+ - ".gitlab/CODEOWNERS"
264
349
  - ".rspec"
265
350
  - ".rubocop.yml"
266
351
  - ".ruby-version"
@@ -278,6 +363,8 @@ files:
278
363
  - lib/labkit/correlation/grpc/client_interceptor.rb
279
364
  - lib/labkit/correlation/grpc/grpc_common.rb
280
365
  - lib/labkit/correlation/grpc/server_interceptor.rb
366
+ - lib/labkit/excon_publisher.rb
367
+ - lib/labkit/httpclient_publisher.rb
281
368
  - lib/labkit/logging.rb
282
369
  - lib/labkit/logging/grpc.rb
283
370
  - lib/labkit/logging/grpc/server_interceptor.rb
@@ -294,7 +381,12 @@ files:
294
381
  - lib/labkit/middleware/sidekiq/tracing/client.rb
295
382
  - lib/labkit/middleware/sidekiq/tracing/server.rb
296
383
  - lib/labkit/middleware/sidekiq/tracing/sidekiq_common.rb
384
+ - lib/labkit/net_http_publisher.rb
385
+ - lib/labkit/system.rb
297
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
298
390
  - lib/labkit/tracing/factory.rb
299
391
  - lib/labkit/tracing/grpc.rb
300
392
  - lib/labkit/tracing/grpc/client_interceptor.rb
@@ -303,7 +395,6 @@ files:
303
395
  - lib/labkit/tracing/jaeger_factory.rb
304
396
  - lib/labkit/tracing/rack_middleware.rb
305
397
  - lib/labkit/tracing/rails.rb
306
- - lib/labkit/tracing/rails/abstract_instrumenter.rb
307
398
  - lib/labkit/tracing/rails/action_view.rb
308
399
  - lib/labkit/tracing/rails/action_view/render_collection_instrumenter.rb
309
400
  - lib/labkit/tracing/rails/action_view/render_partial_instrumenter.rb
@@ -319,10 +410,10 @@ files:
319
410
  - lib/labkit/tracing/rails/active_support/cache_read_instrumenter.rb
320
411
  - lib/labkit/tracing/rails/active_support/cache_write_instrumenter.rb
321
412
  - lib/labkit/tracing/rails/active_support/subscriber.rb
322
- - lib/labkit/tracing/rails/rails_common.rb
323
413
  - lib/labkit/tracing/redis.rb
324
414
  - lib/labkit/tracing/redis/redis_interceptor.rb
325
415
  - lib/labkit/tracing/redis/redis_interceptor_helper.rb
416
+ - lib/labkit/tracing/tracing_common.rb
326
417
  - lib/labkit/tracing/tracing_utils.rb
327
418
  homepage: https://gitlab.com/gitlab-org/labkit-ruby
328
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