gitlab-labkit 0.13.1 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
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 +130 -0
  11. data/lib/labkit/httpclient_publisher.rb +66 -0
  12. data/lib/labkit/logging/grpc/server_interceptor.rb +2 -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: a70f566d4ed676fa90486f0117f74d52a839d2720103cf2c909ecfdb1e762b6e
4
- data.tar.gz: 21614ae6e31149551dd15337957ff079c7c40536710d8911e697087e7a15bde3
3
+ metadata.gz: 2b2b166e9a540a6314a2c5e863e7f109f6c3763f2649aa459dfec41a5018e57f
4
+ data.tar.gz: 7dc9c77305e855d930420dca4e59cba0e18bd990fae24a7a44e871a7e03e84ed
5
5
  SHA512:
6
- metadata.gz: 94946b83b7e1f15fbcbd641b44332a78a9c578a26d2261f22ceb916266bb5f5ddf14652ec7485cc774f03ab051c4e78de1380501a6e35517121e526c170caca3
7
- data.tar.gz: 9feec573a60e49eea6e86bc9ed85b615a0ca60bca10228a49fdea2afbb9296b8bfbccac646dc3cecb4e1bd71e8bd8f53efe1c77305c2cf0098b5dff0ac808ae6
6
+ metadata.gz: 81819b7e4fd168c805e286f9315dd5a757423367938619021dcb7e81d5ad41a6f057224bfc046d96a132354688b33b0b4ed2c3e2196dfa09725176bb32b6ca3e
7
+ data.tar.gz: 35d67adc6f7561609f617df26af9a3942e77cd1b66000523584308bd160c88062dc0fcd1ed6e0d9662f1af6a5c6436c80fe80b53d5b6b4c86ba1e880b24f5a61
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  Gemfile.lock
2
2
  *.gem
3
3
  node_modules
4
+ .bundle
@@ -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
@@ -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
 
@@ -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
+ spec.add_runtime_dependency "gitlab-pg_query", "~> 1.3"
24
25
  spec.add_runtime_dependency "grpc", "~> 1.19" # Be sure to update the "grpc-tools" dev_depenency too
25
26
  spec.add_runtime_dependency "jaeger-client", "~> 1.1"
26
27
  spec.add_runtime_dependency "opentracing", "~> 0.4"
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"
@@ -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,130 @@
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: datum[:host],
96
+ path: datum[:path],
97
+ port: datum[:port],
98
+ scheme: datum[:scheme],
99
+ query: 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
+ end
130
+ 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
 
@@ -67,6 +67,7 @@ module Labkit
67
67
  ensure
68
68
  service_name, method_name = rpc_split(method)
69
69
  message = @default_tags.merge(
70
+ 'grpc.start_time': start.utc.rfc3339,
70
71
  'grpc.time_ms': ((Time.now - start) * 1000.0).truncate(3),
71
72
  'grpc.code': CODE_STRINGS.fetch(code, code.to_s),
72
73
  'grpc.method': method_name,
@@ -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.1
4
+ version: 0.14.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-21 00:00:00.000000000 Z
11
+ date: 2021-01-13 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,21 @@ 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
+ - !ruby/object:Gem::Dependency
54
+ name: gitlab-pg_query
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '1.3'
60
+ type: :runtime
61
+ prerelease: false
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '1.3'
53
67
  - !ruby/object:Gem::Dependency
54
68
  name: grpc
55
69
  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