gitlab-labkit 1.4.0 → 1.5.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.
- checksums.yaml +4 -4
- data/gitlab-labkit.gemspec +5 -1
- data/lib/gitlab-labkit.rb +2 -0
- data/lib/labkit/logging/field_validator.rb +10 -11
- data/lib/labkit/middleware/sidekiq/tracing/client.rb +1 -1
- data/lib/labkit/middleware/sidekiq/tracing/server.rb +1 -1
- data/lib/labkit/tracing/README.md +716 -0
- data/lib/labkit/tracing/abstract_instrumenter.rb +1 -1
- data/lib/labkit/tracing/adapters/base_span.rb +35 -0
- data/lib/labkit/tracing/adapters/base_tracer.rb +39 -0
- data/lib/labkit/tracing/adapters/opentelemetry_span.rb +73 -0
- data/lib/labkit/tracing/adapters/opentelemetry_tracer.rb +102 -0
- data/lib/labkit/tracing/adapters/opentracing_span.rb +70 -0
- data/lib/labkit/tracing/adapters/opentracing_tracer.rb +50 -0
- data/lib/labkit/tracing/auto_initialize.rb +46 -0
- data/lib/labkit/tracing/factory.rb +26 -38
- data/lib/labkit/tracing/grpc/client_interceptor.rb +1 -1
- data/lib/labkit/tracing/grpc/server_interceptor.rb +2 -2
- data/lib/labkit/tracing/jaeger_factory.rb +12 -9
- data/lib/labkit/tracing/open_telemetry_factory.rb +218 -0
- data/lib/labkit/tracing/open_tracing_factory.rb +48 -0
- data/lib/labkit/tracing/rack_middleware.rb +1 -1
- data/lib/labkit/tracing/railtie.rb +15 -0
- data/lib/labkit/tracing/tracing_utils.rb +37 -34
- data/lib/labkit/tracing.rb +108 -5
- data/lib/labkit/user_experience_sli/null.rb +2 -0
- metadata +74 -1
|
@@ -7,7 +7,7 @@ module Labkit
|
|
|
7
7
|
# https://edgeapi.rubyonrails.org/classes/ActiveSupport/Notifications/Instrumenter.html#method-c-new
|
|
8
8
|
class AbstractInstrumenter
|
|
9
9
|
def start(_name, _id, payload)
|
|
10
|
-
scope =
|
|
10
|
+
scope = Labkit::Tracing::TracingUtils.tracer.start_active_span(span_name(payload))
|
|
11
11
|
|
|
12
12
|
scope_stack.push scope
|
|
13
13
|
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Labkit
|
|
4
|
+
module Tracing
|
|
5
|
+
module Adapters
|
|
6
|
+
class BaseSpan
|
|
7
|
+
attr_reader :span
|
|
8
|
+
|
|
9
|
+
def initialize(span)
|
|
10
|
+
@span = span
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def set_tag(_key, _value)
|
|
14
|
+
raise NotImplementedError, "#{self.class.name}#set_tag must be implemented"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def log_event(_name, **_attributes)
|
|
18
|
+
raise NotImplementedError, "#{self.class.name}#log_event must be implemented"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def set_error(_exception)
|
|
22
|
+
raise NotImplementedError, "#{self.class.name}#set_error must be implemented"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def finish(**_opts)
|
|
26
|
+
raise NotImplementedError, "#{self.class.name}#finish must be implemented"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def context
|
|
30
|
+
raise NotImplementedError, "#{self.class.name}#context must be implemented"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Labkit
|
|
4
|
+
module Tracing
|
|
5
|
+
module Adapters
|
|
6
|
+
class BaseTracer
|
|
7
|
+
attr_reader :tracer
|
|
8
|
+
|
|
9
|
+
def initialize(tracer)
|
|
10
|
+
@tracer = tracer
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def start_span(_operation_name, child_of: nil, tags: {}, start_time: nil)
|
|
14
|
+
raise NotImplementedError, "#{self.class.name}#start_span must be implemented"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def in_span(_operation_name, child_of: nil, tags: {}, &_block)
|
|
18
|
+
raise NotImplementedError, "#{self.class.name}#in_span must be implemented"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def extract_context(_carrier, format: nil)
|
|
22
|
+
raise NotImplementedError, "#{self.class.name}#extract_context must be implemented"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def inject_context(_span_context, _carrier, format: nil)
|
|
26
|
+
raise NotImplementedError, "#{self.class.name}#inject_context must be implemented"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def active_span
|
|
30
|
+
raise NotImplementedError, "#{self.class.name}#active_span must be implemented"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def start_active_span(_operation_name, tags: nil)
|
|
34
|
+
raise NotImplementedError, "#{self.class.name}#start_active_span must be implemented"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Internal adapter for OpenTelemetry span compatibility.
|
|
4
|
+
# This is not part of the public Labkit API.
|
|
5
|
+
#
|
|
6
|
+
# Applications should use OpenTelemetry APIs directly via:
|
|
7
|
+
# - Labkit::Tracing.tracer (returns OpenTelemetry::Trace::Tracer)
|
|
8
|
+
# - Labkit::Tracing.current_span (returns OpenTelemetry::Trace::Span)
|
|
9
|
+
#
|
|
10
|
+
# These adapters exist for:
|
|
11
|
+
# - Internal Labkit instrumentation (Rails, Redis, etc.)
|
|
12
|
+
# - Backward compatibility with OpenTracing connections
|
|
13
|
+
#
|
|
14
|
+
# @api private
|
|
15
|
+
|
|
16
|
+
module Labkit
|
|
17
|
+
module Tracing
|
|
18
|
+
module Adapters
|
|
19
|
+
class OpentelemetrySpan < BaseSpan
|
|
20
|
+
def set_tag(key, value)
|
|
21
|
+
span.set_attribute(key, value)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def log_event(name, **attributes)
|
|
25
|
+
span.add_event(name, attributes: stringify_keys(attributes))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def set_error(exception)
|
|
29
|
+
return if exception.blank?
|
|
30
|
+
|
|
31
|
+
span.set_attribute("error", true)
|
|
32
|
+
span.add_event("exception", attributes: stringify_keys(kv_tags_for_exception(exception)))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def finish(**opts)
|
|
36
|
+
if opts[:end_timestamp]
|
|
37
|
+
span.finish(end_timestamp: opts[:end_timestamp])
|
|
38
|
+
else
|
|
39
|
+
span.finish
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def context
|
|
44
|
+
span.context
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def stringify_keys(hash)
|
|
50
|
+
hash.transform_keys(&:to_s)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def kv_tags_for_exception(exception)
|
|
54
|
+
case exception
|
|
55
|
+
when Exception
|
|
56
|
+
{
|
|
57
|
+
event: "error",
|
|
58
|
+
'error.kind': exception.class.to_s,
|
|
59
|
+
message: Labkit::Logging::Sanitizer.sanitize_field(exception.message),
|
|
60
|
+
stack: exception.backtrace&.join('\n')
|
|
61
|
+
}
|
|
62
|
+
else
|
|
63
|
+
{
|
|
64
|
+
event: "error",
|
|
65
|
+
'error.kind': exception.class.to_s,
|
|
66
|
+
'error.object': Labkit::Logging::Sanitizer.sanitize_field(exception.to_s)
|
|
67
|
+
}
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Internal adapter for OpenTelemetry tracer compatibility.
|
|
4
|
+
# This is not part of the public Labkit API.
|
|
5
|
+
#
|
|
6
|
+
# Applications should use OpenTelemetry APIs directly via:
|
|
7
|
+
# - Labkit::Tracing.tracer (returns OpenTelemetry::Trace::Tracer)
|
|
8
|
+
# - Labkit::Tracing.current_span (returns OpenTelemetry::Trace::Span)
|
|
9
|
+
#
|
|
10
|
+
# These adapters exist for:
|
|
11
|
+
# - Internal Labkit instrumentation (Rails, Redis, etc.)
|
|
12
|
+
# - Backward compatibility with OpenTracing connections
|
|
13
|
+
#
|
|
14
|
+
# @api private
|
|
15
|
+
|
|
16
|
+
module Labkit
|
|
17
|
+
module Tracing
|
|
18
|
+
module Adapters
|
|
19
|
+
class OpentelemetryTracer < BaseTracer
|
|
20
|
+
def start_span(operation_name, child_of: nil, tags: {}, start_time: nil)
|
|
21
|
+
attributes = tags || {}
|
|
22
|
+
opts = { attributes: attributes }
|
|
23
|
+
opts[:with_parent] = child_of if child_of
|
|
24
|
+
opts[:start_timestamp] = start_time if start_time
|
|
25
|
+
|
|
26
|
+
span = tracer.start_span(operation_name, **opts)
|
|
27
|
+
OpentelemetrySpan.new(span)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def in_span(operation_name, child_of: nil, tags: {})
|
|
31
|
+
attributes = tags || {}
|
|
32
|
+
|
|
33
|
+
if child_of
|
|
34
|
+
span = tracer.start_span(operation_name, with_parent: child_of, attributes: attributes)
|
|
35
|
+
ctx = OpenTelemetry::Trace.context_with_span(span)
|
|
36
|
+
|
|
37
|
+
result = nil
|
|
38
|
+
OpenTelemetry::Context.with_current(ctx) do
|
|
39
|
+
adapter = OpentelemetrySpan.new(span)
|
|
40
|
+
result = yield(adapter)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
span.finish
|
|
44
|
+
result
|
|
45
|
+
else
|
|
46
|
+
tracer.in_span(operation_name, attributes: attributes) do |span|
|
|
47
|
+
adapter = OpentelemetrySpan.new(span)
|
|
48
|
+
yield(adapter)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def extract_context(carrier, format: nil) # rubocop:disable Lint/UnusedMethodArgument
|
|
54
|
+
# Format parameter is ignored for OpenTelemetry - propagation format is configured
|
|
55
|
+
# globally via OTEL_PROPAGATORS environment variable, not per-call like OpenTracing.
|
|
56
|
+
# The parameter exists only for BaseTracer API compatibility.
|
|
57
|
+
OpenTelemetry.propagation.extract(carrier)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def inject_context(span_wrapper, carrier, format: nil) # rubocop:disable Lint/UnusedMethodArgument
|
|
61
|
+
# Format parameter is ignored for OpenTelemetry - propagation format is configured
|
|
62
|
+
# globally via OTEL_PROPAGATORS environment variable, not per-call like OpenTracing.
|
|
63
|
+
# The parameter exists only for BaseTracer API compatibility.
|
|
64
|
+
#
|
|
65
|
+
# span_wrapper is expected to be a BaseSpan (e.g., OpentelemetrySpan) that wraps
|
|
66
|
+
# the actual OpenTelemetry span. We unwrap it to get the OTel span object.
|
|
67
|
+
span = span_wrapper.respond_to?(:span) ? span_wrapper.span : span_wrapper
|
|
68
|
+
context = OpenTelemetry::Trace.context_with_span(span)
|
|
69
|
+
OpenTelemetry.propagation.inject(carrier, context: context)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def active_span
|
|
73
|
+
OpenTelemetry::Trace.current_span
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def start_active_span(operation_name, tags: nil)
|
|
77
|
+
attributes = tags || {}
|
|
78
|
+
raw_span = tracer.start_span(operation_name, attributes: attributes)
|
|
79
|
+
ctx = OpenTelemetry::Trace.context_with_span(raw_span)
|
|
80
|
+
token = OpenTelemetry::Context.attach(ctx)
|
|
81
|
+
|
|
82
|
+
OpenTelemetryScope.new(raw_span, token)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
class OpenTelemetryScope
|
|
86
|
+
attr_reader :span
|
|
87
|
+
|
|
88
|
+
def initialize(raw_span, token)
|
|
89
|
+
@span = OpentelemetrySpan.new(raw_span)
|
|
90
|
+
@raw_span = raw_span
|
|
91
|
+
@token = token
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def close
|
|
95
|
+
@raw_span.finish
|
|
96
|
+
OpenTelemetry::Context.detach(@token)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Labkit
|
|
4
|
+
module Tracing
|
|
5
|
+
module Adapters
|
|
6
|
+
class OpentracingSpan < BaseSpan
|
|
7
|
+
attr_reader :scope
|
|
8
|
+
|
|
9
|
+
def initialize(span_or_scope)
|
|
10
|
+
if span_or_scope.respond_to?(:span)
|
|
11
|
+
@scope = span_or_scope
|
|
12
|
+
@span = span_or_scope.span
|
|
13
|
+
else
|
|
14
|
+
@scope = nil
|
|
15
|
+
@span = span_or_scope
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def set_tag(key, value)
|
|
20
|
+
span.set_tag(key, value)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def log_event(name, **attributes)
|
|
24
|
+
span.log_kv(**attributes, event: name)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def set_error(exception)
|
|
28
|
+
return if exception.blank?
|
|
29
|
+
|
|
30
|
+
span.set_tag("error", true)
|
|
31
|
+
span.log_kv(**kv_tags_for_exception(exception))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def finish(**opts)
|
|
35
|
+
if opts[:end_timestamp]
|
|
36
|
+
span.finish(end_time: opts[:end_timestamp])
|
|
37
|
+
else
|
|
38
|
+
span.finish
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
scope&.close
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def context
|
|
45
|
+
span.context
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def kv_tags_for_exception(exception)
|
|
51
|
+
case exception
|
|
52
|
+
when Exception
|
|
53
|
+
{
|
|
54
|
+
event: "error",
|
|
55
|
+
'error.kind': exception.class.to_s,
|
|
56
|
+
message: Labkit::Logging::Sanitizer.sanitize_field(exception.message),
|
|
57
|
+
stack: exception.backtrace&.join('\n')
|
|
58
|
+
}
|
|
59
|
+
else
|
|
60
|
+
{
|
|
61
|
+
event: "error",
|
|
62
|
+
'error.kind': exception.class.to_s,
|
|
63
|
+
'error.object': Labkit::Logging::Sanitizer.sanitize_field(exception.to_s)
|
|
64
|
+
}
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Labkit
|
|
4
|
+
module Tracing
|
|
5
|
+
module Adapters
|
|
6
|
+
class OpentracingTracer < BaseTracer
|
|
7
|
+
def start_span(operation_name, child_of: nil, tags: {}, start_time: nil)
|
|
8
|
+
opts = {}
|
|
9
|
+
opts[:child_of] = child_of if child_of
|
|
10
|
+
opts[:tags] = tags if tags
|
|
11
|
+
opts[:start_time] = start_time if start_time
|
|
12
|
+
|
|
13
|
+
span = tracer.start_span(operation_name, **opts)
|
|
14
|
+
OpentracingSpan.new(span)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def in_span(operation_name, child_of: nil, tags: {})
|
|
18
|
+
scope = tracer.start_active_span(operation_name, child_of: child_of, tags: tags)
|
|
19
|
+
adapter = OpentracingSpan.new(scope)
|
|
20
|
+
|
|
21
|
+
begin
|
|
22
|
+
yield(adapter)
|
|
23
|
+
ensure
|
|
24
|
+
adapter.finish
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def extract_context(carrier, format: OpenTracing::FORMAT_TEXT_MAP)
|
|
29
|
+
tracer.extract(format, carrier)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def inject_context(span_context, carrier, format: OpenTracing::FORMAT_TEXT_MAP)
|
|
33
|
+
tracer.inject(span_context, format, carrier)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def active_span
|
|
37
|
+
OpenTracing.active_span
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def start_active_span(operation_name, tags: nil)
|
|
41
|
+
if tags
|
|
42
|
+
OpenTracing.start_active_span(operation_name, tags: tags)
|
|
43
|
+
else
|
|
44
|
+
OpenTracing.start_active_span(operation_name)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "cgi"
|
|
4
|
+
require "active_support/core_ext/object/blank"
|
|
5
|
+
|
|
6
|
+
module Labkit
|
|
7
|
+
module Tracing
|
|
8
|
+
module AutoInitialize
|
|
9
|
+
def self.detect_service_name(connection_string)
|
|
10
|
+
return Labkit::Tracing::DEFAULT_SERVICE_NAME unless connection_string
|
|
11
|
+
|
|
12
|
+
if connection_string =~ /[?&]service_name=([^&]+)/
|
|
13
|
+
CGI.unescape(Regexp.last_match(1))
|
|
14
|
+
else
|
|
15
|
+
Labkit::Tracing::DEFAULT_SERVICE_NAME
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.initialize!
|
|
20
|
+
connection_string = ENV.fetch("GITLAB_TRACING", nil)
|
|
21
|
+
return if connection_string.nil? || connection_string.empty?
|
|
22
|
+
|
|
23
|
+
service_name = detect_service_name(connection_string)
|
|
24
|
+
|
|
25
|
+
Factory.create_tracer(service_name, connection_string) do |c|
|
|
26
|
+
require "opentelemetry/instrumentation/all"
|
|
27
|
+
c.use_all
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
enable_labkit_instrumentation
|
|
31
|
+
rescue StandardError => e
|
|
32
|
+
warn "Labkit::Tracing auto-initialization failed: #{e.message}"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.enable_labkit_instrumentation
|
|
36
|
+
Rails::ActiveRecord::Subscriber.instrument if defined?(::ActiveRecord)
|
|
37
|
+
Rails::ActionView::Subscriber.instrument if defined?(::ActionView)
|
|
38
|
+
Rails::ActiveSupport::Subscriber.instrument if defined?(::ActiveSupport)
|
|
39
|
+
Redis.instrument if defined?(::Redis)
|
|
40
|
+
ExternalHttp.instrument
|
|
41
|
+
rescue StandardError => e
|
|
42
|
+
warn "Labkit::Tracing: LabKit instrumentation setup failed: #{e.message}"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -1,58 +1,46 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "cgi"
|
|
4
|
-
|
|
5
3
|
module Labkit
|
|
6
4
|
module Tracing
|
|
7
5
|
# Factory provides tools for setting up and configuring the
|
|
8
6
|
# distributed tracing system within the process, given the
|
|
9
7
|
# tracing connection string
|
|
10
8
|
class Factory
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
# When the probabilistic sampler is used, by default 0.1% of requests will be traced
|
|
10
|
+
DEFAULT_PROBABILISTIC_RATE = 0.001
|
|
11
|
+
|
|
12
|
+
# @param service_name [String] The service name for the tracer
|
|
13
|
+
# @param connection_string [String] The connection string (e.g., "otlp://localhost:4318")
|
|
14
|
+
# @yield [config] Optional configuration block for OpenTelemetry SDK customization (OTLP only)
|
|
15
|
+
# @yieldparam config [OpenTelemetry::SDK::Configurator] The SDK configurator
|
|
16
|
+
# @return [Tracer, nil] The configured tracer or nil if initialization fails
|
|
17
|
+
def self.create_tracer(service_name, connection_string, &config_block)
|
|
14
18
|
return unless connection_string.present?
|
|
15
19
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
JaegerFactory.create_tracer(service_name, opentracing_details[:options])
|
|
20
|
+
tracer =
|
|
21
|
+
if Tracing.otlp_connection?(connection_string)
|
|
22
|
+
OpenTelemetryFactory.create_tracer(service_name, connection_string, &config_block)
|
|
23
|
+
elsif Tracing.opentracing_connection?(connection_string)
|
|
24
|
+
warn_opentracing_block_ignored if config_block
|
|
25
|
+
OpenTracingFactory.create_tracer(service_name, connection_string)
|
|
23
26
|
else
|
|
24
|
-
raise "Unknown
|
|
27
|
+
raise "Unknown protocol"
|
|
25
28
|
end
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
rescue StandardError => e
|
|
29
|
-
warn "Unable to instantiate tracer: #{e}"
|
|
30
|
-
nil
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def self.parse_connection_string(connection_string)
|
|
35
|
-
parsed = URI.parse(connection_string)
|
|
30
|
+
Tracing.configured_service_name = service_name
|
|
36
31
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
tracer
|
|
33
|
+
rescue StandardError => e
|
|
34
|
+
warn "Unable to instantiate tracer: #{e}"
|
|
35
|
+
nil
|
|
40
36
|
end
|
|
41
|
-
private_class_method :parse_connection_string
|
|
42
|
-
|
|
43
|
-
def self.parse_query(query)
|
|
44
|
-
return {} unless query
|
|
45
|
-
|
|
46
|
-
CGI.parse(query).symbolize_keys.transform_values(&:first)
|
|
47
|
-
end
|
|
48
|
-
private_class_method :parse_query
|
|
49
|
-
|
|
50
|
-
def self.valid_uri?(uri)
|
|
51
|
-
return false unless uri
|
|
52
37
|
|
|
53
|
-
|
|
38
|
+
def self.warn_opentracing_block_ignored
|
|
39
|
+
warn "Warning: Configuration block provided but ignored - " \
|
|
40
|
+
"OpenTracing connection strings don't support SDK customization. " \
|
|
41
|
+
"Use OTLP (otlp://) for OpenTelemetry SDK features."
|
|
54
42
|
end
|
|
55
|
-
private_class_method :
|
|
43
|
+
private_class_method :warn_opentracing_block_ignored
|
|
56
44
|
end
|
|
57
45
|
end
|
|
58
46
|
end
|
|
@@ -36,7 +36,7 @@ module Labkit
|
|
|
36
36
|
tags = { "component" => "grpc", "span.kind" => "client", "grpc.method" => method, "grpc.type" => grpc_type }
|
|
37
37
|
|
|
38
38
|
TracingUtils.with_tracing(operation_name: "grpc:#{method}", tags: tags) do |span|
|
|
39
|
-
|
|
39
|
+
TracingUtils.tracer.inject_context(span, metadata)
|
|
40
40
|
|
|
41
41
|
yield
|
|
42
42
|
end
|
|
@@ -42,13 +42,13 @@ module Labkit
|
|
|
42
42
|
private
|
|
43
43
|
|
|
44
44
|
def wrap_with_tracing(call, method, grpc_type)
|
|
45
|
-
context = TracingUtils.tracer.
|
|
45
|
+
context = TracingUtils.tracer.extract_context(call.metadata)
|
|
46
46
|
method_name = "/#{rpc_split(method).join("/")}"
|
|
47
47
|
tags = {
|
|
48
48
|
"component" => "grpc",
|
|
49
49
|
"span.kind" => "server",
|
|
50
50
|
"grpc.method" => method_name,
|
|
51
|
-
"grpc.type" => grpc_type
|
|
51
|
+
"grpc.type" => grpc_type
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
TracingUtils.with_tracing(operation_name: "grpc:#{method_name}", child_of: context, tags: tags) do |_span|
|
|
@@ -4,14 +4,12 @@ require "active_support"
|
|
|
4
4
|
require "active_support/core_ext"
|
|
5
5
|
|
|
6
6
|
require "jaeger/client"
|
|
7
|
+
require "opentracing"
|
|
7
8
|
|
|
8
9
|
module Labkit
|
|
9
10
|
module Tracing
|
|
10
11
|
# JaegerFactory will configure Jaeger distributed tracing
|
|
11
12
|
class JaegerFactory
|
|
12
|
-
# When the probabilistic sampler is used, by default 0.1% of requests will be traced
|
|
13
|
-
DEFAULT_PROBABILISTIC_RATE = 0.001
|
|
14
|
-
|
|
15
13
|
# The default port for the Jaeger agent UDP listener
|
|
16
14
|
DEFAULT_UDP_PORT = 6831
|
|
17
15
|
|
|
@@ -31,7 +29,7 @@ module Labkit
|
|
|
31
29
|
kwargs = {
|
|
32
30
|
service_name: service_name,
|
|
33
31
|
sampler: get_sampler(options[:sampler], options[:sampler_param]),
|
|
34
|
-
reporter: get_reporter(service_name, options[:http_endpoint], options[:udp_endpoint], headers)
|
|
32
|
+
reporter: get_reporter(service_name, options[:http_endpoint], options[:udp_endpoint], headers)
|
|
35
33
|
}.compact
|
|
36
34
|
|
|
37
35
|
extra_params = options.except(:sampler, :sampler_param, :http_endpoint, :udp_endpoint, :strict_parsing, :debug)
|
|
@@ -43,7 +41,12 @@ module Labkit
|
|
|
43
41
|
warn message
|
|
44
42
|
end
|
|
45
43
|
|
|
46
|
-
Jaeger::Client.build(**kwargs)
|
|
44
|
+
tracer = Jaeger::Client.build(**kwargs)
|
|
45
|
+
|
|
46
|
+
# Set as global tracer for consistency with OpenTelemetry behavior
|
|
47
|
+
OpenTracing.global_tracer = tracer if tracer
|
|
48
|
+
|
|
49
|
+
tracer
|
|
47
50
|
end
|
|
48
51
|
|
|
49
52
|
def self.build_headers(options)
|
|
@@ -60,14 +63,14 @@ module Labkit
|
|
|
60
63
|
headers["Authorization"] = "Basic " + Base64.strict_encode64("#{user}:#{password}")
|
|
61
64
|
end
|
|
62
65
|
|
|
63
|
-
|
|
66
|
+
headers
|
|
64
67
|
end
|
|
65
68
|
private_class_method :build_headers
|
|
66
69
|
|
|
67
70
|
def self.get_sampler(sampler_type, sampler_param)
|
|
68
71
|
case sampler_type
|
|
69
72
|
when "probabilistic"
|
|
70
|
-
sampler_rate = sampler_param ? sampler_param.to_f : DEFAULT_PROBABILISTIC_RATE
|
|
73
|
+
sampler_rate = sampler_param ? sampler_param.to_f : Factory::DEFAULT_PROBABILISTIC_RATE
|
|
71
74
|
Jaeger::Samplers::Probabilistic.new(rate: sampler_rate)
|
|
72
75
|
when "const"
|
|
73
76
|
const_value = sampler_param == "1"
|
|
@@ -92,7 +95,7 @@ module Labkit
|
|
|
92
95
|
private_class_method :get_reporter
|
|
93
96
|
|
|
94
97
|
def self.get_http_sender(encoder, address, headers)
|
|
95
|
-
Jaeger::HttpSender.new(url: address, headers: headers, encoder: encoder, logger: Logger.new(
|
|
98
|
+
Jaeger::HttpSender.new(url: address, headers: headers, encoder: encoder, logger: Logger.new($stdout))
|
|
96
99
|
end
|
|
97
100
|
private_class_method :get_http_sender
|
|
98
101
|
|
|
@@ -101,7 +104,7 @@ module Labkit
|
|
|
101
104
|
host = pair[0]
|
|
102
105
|
port = pair[1] ? pair[1].to_i : DEFAULT_UDP_PORT
|
|
103
106
|
|
|
104
|
-
Jaeger::UdpSender.new(host: host, port: port, encoder: encoder, logger: Logger.new(
|
|
107
|
+
Jaeger::UdpSender.new(host: host, port: port, encoder: encoder, logger: Logger.new($stdout))
|
|
105
108
|
end
|
|
106
109
|
private_class_method :get_udp_sender
|
|
107
110
|
end
|