elastic-apm 1.1.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of elastic-apm might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rspec +1 -0
- data/.rubocop.yml +7 -1
- data/CHANGELOG.md +45 -0
- data/Gemfile +17 -12
- data/bench/app.rb +1 -2
- data/bench/benchmark.rb +1 -1
- data/bench/stackprof.rb +1 -1
- data/docs/api.asciidoc +115 -76
- data/docs/configuration.asciidoc +232 -167
- data/docs/context.asciidoc +7 -3
- data/docs/custom-instrumentation.asciidoc +17 -28
- data/docs/index.asciidoc +13 -7
- data/docs/supported-technologies.asciidoc +65 -0
- data/elastic-apm.gemspec +3 -2
- data/lib/elastic_apm.rb +272 -121
- data/lib/elastic_apm/agent.rb +56 -107
- data/lib/elastic_apm/config.rb +130 -106
- data/lib/elastic_apm/config/duration.rb +25 -0
- data/lib/elastic_apm/config/size.rb +28 -0
- data/lib/elastic_apm/context_builder.rb +1 -0
- data/lib/elastic_apm/deprecations.rb +19 -0
- data/lib/elastic_apm/error.rb +5 -2
- data/lib/elastic_apm/error/exception.rb +1 -1
- data/lib/elastic_apm/error_builder.rb +5 -0
- data/lib/elastic_apm/instrumenter.rb +121 -53
- data/lib/elastic_apm/internal_error.rb +1 -0
- data/lib/elastic_apm/{log.rb → logging.rb} +16 -11
- data/lib/elastic_apm/metadata.rb +20 -0
- data/lib/elastic_apm/metadata/process_info.rb +26 -0
- data/lib/elastic_apm/metadata/service_info.rb +56 -0
- data/lib/elastic_apm/metadata/system_info.rb +30 -0
- data/lib/elastic_apm/middleware.rb +31 -15
- data/lib/elastic_apm/normalizers/action_controller.rb +1 -1
- data/lib/elastic_apm/normalizers/action_mailer.rb +1 -1
- data/lib/elastic_apm/normalizers/action_view.rb +3 -3
- data/lib/elastic_apm/normalizers/active_record.rb +2 -1
- data/lib/elastic_apm/railtie.rb +1 -1
- data/lib/elastic_apm/span.rb +59 -29
- data/lib/elastic_apm/span/context.rb +30 -4
- data/lib/elastic_apm/span_helpers.rb +1 -1
- data/lib/elastic_apm/spies/delayed_job.rb +7 -7
- data/lib/elastic_apm/spies/elasticsearch.rb +4 -4
- data/lib/elastic_apm/spies/http.rb +38 -0
- data/lib/elastic_apm/spies/mongo.rb +22 -11
- data/lib/elastic_apm/spies/net_http.rb +7 -4
- data/lib/elastic_apm/spies/rake.rb +5 -6
- data/lib/elastic_apm/spies/redis.rb +1 -1
- data/lib/elastic_apm/spies/sequel.rb +9 -7
- data/lib/elastic_apm/spies/sidekiq.rb +5 -5
- data/lib/elastic_apm/spies/tilt.rb +2 -2
- data/lib/elastic_apm/sql_summarizer.rb +3 -3
- data/lib/elastic_apm/stacktrace_builder.rb +6 -6
- data/lib/elastic_apm/subscriber.rb +3 -3
- data/lib/elastic_apm/traceparent.rb +62 -0
- data/lib/elastic_apm/transaction.rb +62 -93
- data/lib/elastic_apm/transport/base.rb +98 -0
- data/lib/elastic_apm/transport/connection.rb +175 -0
- data/lib/elastic_apm/transport/filters.rb +45 -0
- data/lib/elastic_apm/transport/filters/request_body_filter.rb +31 -0
- data/lib/elastic_apm/transport/filters/secrets_filter.rb +59 -0
- data/lib/elastic_apm/transport/serializers.rb +58 -0
- data/lib/elastic_apm/transport/serializers/error_serializer.rb +59 -0
- data/lib/elastic_apm/transport/serializers/span_serializer.rb +30 -0
- data/lib/elastic_apm/transport/serializers/transaction_serializer.rb +33 -0
- data/lib/elastic_apm/transport/worker.rb +73 -0
- data/lib/elastic_apm/util.rb +11 -8
- data/lib/elastic_apm/version.rb +1 -1
- metadata +40 -21
- data/.travis.yml +0 -5
- data/docs/troubleshooting.asciidoc +0 -28
- data/lib/elastic_apm/filters.rb +0 -46
- data/lib/elastic_apm/filters/request_body_filter.rb +0 -33
- data/lib/elastic_apm/filters/secrets_filter.rb +0 -59
- data/lib/elastic_apm/http.rb +0 -139
- data/lib/elastic_apm/process_info.rb +0 -24
- data/lib/elastic_apm/serializers.rb +0 -28
- data/lib/elastic_apm/serializers/errors.rb +0 -61
- data/lib/elastic_apm/serializers/transactions.rb +0 -51
- data/lib/elastic_apm/service_info.rb +0 -54
- data/lib/elastic_apm/system_info.rb +0 -28
- data/lib/elastic_apm/util/dig.rb +0 -31
- data/lib/elastic_apm/util/inspector.rb +0 -61
- data/lib/elastic_apm/worker.rb +0 -106
@@ -5,9 +5,9 @@ module ElasticAPM
|
|
5
5
|
module Spies
|
6
6
|
# @api private
|
7
7
|
class DelayedJobSpy
|
8
|
-
CLASS_SEPARATOR = '.'
|
9
|
-
METHOD_SEPARATOR = '#'
|
10
|
-
TYPE = 'Delayed::Job'
|
8
|
+
CLASS_SEPARATOR = '.'
|
9
|
+
METHOD_SEPARATOR = '#'
|
10
|
+
TYPE = 'Delayed::Job'
|
11
11
|
|
12
12
|
def install
|
13
13
|
::Delayed::Backend::Base.class_eval do
|
@@ -22,15 +22,15 @@ module ElasticAPM
|
|
22
22
|
|
23
23
|
def self.invoke_job(job, *args, &block)
|
24
24
|
job_name = name_from_payload(job.payload_object)
|
25
|
-
transaction = ElasticAPM.
|
25
|
+
transaction = ElasticAPM.start_transaction(job_name, TYPE)
|
26
26
|
job.invoke_job_without_apm(*args, &block)
|
27
|
-
transaction.
|
27
|
+
transaction.done 'success'
|
28
28
|
rescue ::Exception => e
|
29
29
|
ElasticAPM.report(e, handled: false)
|
30
|
-
transaction.
|
30
|
+
transaction.done 'error'
|
31
31
|
raise
|
32
32
|
ensure
|
33
|
-
|
33
|
+
ElasticAPM.end_transaction
|
34
34
|
end
|
35
35
|
|
36
36
|
def self.name_from_payload(payload_object)
|
@@ -5,8 +5,8 @@ module ElasticAPM
|
|
5
5
|
module Spies
|
6
6
|
# @api private
|
7
7
|
class ElasticsearchSpy
|
8
|
-
NAME_FORMAT = '%s %s'
|
9
|
-
TYPE = 'db.elasticsearch'
|
8
|
+
NAME_FORMAT = '%s %s'
|
9
|
+
TYPE = 'db.elasticsearch'
|
10
10
|
|
11
11
|
# rubocop:disable Metrics/MethodLength
|
12
12
|
def install
|
@@ -16,9 +16,9 @@ module ElasticAPM
|
|
16
16
|
def perform_request(method, path, *args, &block)
|
17
17
|
name = format(NAME_FORMAT, method, path)
|
18
18
|
statement = args[0].is_a?(String) ? args[0] : args[0].to_json
|
19
|
-
context = Span::Context.new(statement: statement)
|
19
|
+
context = Span::Context.new(db: { statement: statement })
|
20
20
|
|
21
|
-
ElasticAPM.
|
21
|
+
ElasticAPM.with_span name, TYPE, context: context do
|
22
22
|
perform_request_without_apm(method, path, *args, &block)
|
23
23
|
end
|
24
24
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ElasticAPM
|
4
|
+
# @api private
|
5
|
+
module Spies
|
6
|
+
# @api private
|
7
|
+
class HTTPSpy
|
8
|
+
# rubocop:disable Metrics/MethodLength
|
9
|
+
def install
|
10
|
+
::HTTP::Client.class_eval do
|
11
|
+
alias perform_without_apm perform
|
12
|
+
|
13
|
+
def perform(req, options)
|
14
|
+
unless (transaction = ElasticAPM.current_transaction)
|
15
|
+
return perform_without_apm(req, options)
|
16
|
+
end
|
17
|
+
|
18
|
+
method = req.verb.to_s.upcase
|
19
|
+
host = req.uri.host
|
20
|
+
|
21
|
+
name = "#{method} #{host}"
|
22
|
+
type = "ext.http_rb.#{method}"
|
23
|
+
|
24
|
+
ElasticAPM.with_span name, type do |span|
|
25
|
+
req['Elastic-Apm-Traceparent'] =
|
26
|
+
transaction.traceparent.to_header(span_id: span.id)
|
27
|
+
|
28
|
+
perform_without_apm(req, options)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
# rubocop:enable Metrics/MethodLength
|
34
|
+
end
|
35
|
+
|
36
|
+
register 'HTTP', 'http', HTTPSpy.new
|
37
|
+
end
|
38
|
+
end
|
@@ -14,7 +14,7 @@ module ElasticAPM
|
|
14
14
|
|
15
15
|
# @api private
|
16
16
|
class Subscriber
|
17
|
-
TYPE = 'db.mongodb.query'
|
17
|
+
TYPE = 'db.mongodb.query'
|
18
18
|
|
19
19
|
def initialize
|
20
20
|
@events = {}
|
@@ -37,21 +37,32 @@ module ElasticAPM
|
|
37
37
|
def push_event(event)
|
38
38
|
return unless ElasticAPM.current_transaction
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
40
|
+
span =
|
41
|
+
ElasticAPM.start_span(
|
42
|
+
event.command_name.to_s,
|
43
|
+
TYPE,
|
44
|
+
context: build_context(event)
|
45
|
+
)
|
46
|
+
|
47
47
|
@events[event.operation_id] = span
|
48
48
|
end
|
49
49
|
|
50
50
|
def pop_event(event)
|
51
|
-
return unless ElasticAPM.
|
52
|
-
|
51
|
+
return unless (curr = ElasticAPM.current_span)
|
53
52
|
span = @events.delete(event.operation_id)
|
54
|
-
|
53
|
+
|
54
|
+
curr == span && ElasticAPM.end_span
|
55
|
+
end
|
56
|
+
|
57
|
+
def build_context(event)
|
58
|
+
Span::Context.new(
|
59
|
+
db: {
|
60
|
+
instance: event.database_name,
|
61
|
+
statement: nil,
|
62
|
+
type: 'mongodb',
|
63
|
+
user: nil
|
64
|
+
}
|
65
|
+
)
|
55
66
|
end
|
56
67
|
end
|
57
68
|
end
|
@@ -5,13 +5,13 @@ module ElasticAPM
|
|
5
5
|
module Spies
|
6
6
|
# @api private
|
7
7
|
class NetHTTPSpy
|
8
|
-
# rubocop:disable Metrics/MethodLength
|
8
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
9
9
|
def install
|
10
10
|
Net::HTTP.class_eval do
|
11
11
|
alias request_without_apm request
|
12
12
|
|
13
13
|
def request(req, body = nil, &block)
|
14
|
-
unless ElasticAPM.current_transaction
|
14
|
+
unless (transaction = ElasticAPM.current_transaction)
|
15
15
|
return request_without_apm(req, body, &block)
|
16
16
|
end
|
17
17
|
|
@@ -23,13 +23,16 @@ module ElasticAPM
|
|
23
23
|
name = "#{method} #{host}"
|
24
24
|
type = "ext.net_http.#{method}"
|
25
25
|
|
26
|
-
ElasticAPM.
|
26
|
+
ElasticAPM.with_span name, type do |span|
|
27
|
+
req['Elastic-Apm-Traceparent'] =
|
28
|
+
transaction.traceparent.to_header(span_id: span.id)
|
29
|
+
|
27
30
|
request_without_apm(req, body, &block)
|
28
31
|
end
|
29
32
|
end
|
30
33
|
end
|
31
34
|
end
|
32
|
-
# rubocop:enable Metrics/MethodLength
|
35
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
33
36
|
end
|
34
37
|
|
35
38
|
register 'Net::HTTP', 'net/http', NetHTTPSpy.new
|
@@ -6,7 +6,6 @@ module ElasticAPM
|
|
6
6
|
# @api private
|
7
7
|
class RakeSpy
|
8
8
|
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
9
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
10
9
|
def install
|
11
10
|
::Rake::Task.class_eval do
|
12
11
|
alias execute_without_apm execute
|
@@ -18,19 +17,20 @@ module ElasticAPM
|
|
18
17
|
return execute_without_apm(*args)
|
19
18
|
end
|
20
19
|
|
21
|
-
transaction =
|
20
|
+
transaction =
|
21
|
+
ElasticAPM.start_transaction("Rake::Task[#{name}]", 'Rake')
|
22
22
|
|
23
23
|
begin
|
24
24
|
result = execute_without_apm(*args)
|
25
25
|
|
26
|
-
transaction.
|
26
|
+
transaction.result = 'success' if transaction
|
27
27
|
rescue StandardError => e
|
28
|
-
transaction.
|
28
|
+
transaction.result = 'error' if transaction
|
29
29
|
ElasticAPM.report(e)
|
30
30
|
|
31
31
|
raise
|
32
32
|
ensure
|
33
|
-
|
33
|
+
ElasticAPM.end_transaction
|
34
34
|
ElasticAPM.stop
|
35
35
|
end
|
36
36
|
|
@@ -38,7 +38,6 @@ module ElasticAPM
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
41
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
42
41
|
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
43
42
|
end
|
44
43
|
register 'Rake::Task', 'rake', RakeSpy.new
|
@@ -7,12 +7,18 @@ module ElasticAPM
|
|
7
7
|
module Spies
|
8
8
|
# @api private
|
9
9
|
class SequelSpy
|
10
|
-
TYPE = 'db.sequel.sql'
|
10
|
+
TYPE = 'db.sequel.sql'
|
11
11
|
|
12
12
|
def self.summarizer
|
13
13
|
@summarizer ||= SqlSummarizer.new
|
14
14
|
end
|
15
15
|
|
16
|
+
def self.build_context(sql, opts)
|
17
|
+
Span::Context.new(
|
18
|
+
db: { statement: sql, type: 'sql', user: opts[:user] }
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
16
22
|
# rubocop:disable Metrics/MethodLength
|
17
23
|
def install
|
18
24
|
require 'sequel/database/logging'
|
@@ -27,13 +33,9 @@ module ElasticAPM
|
|
27
33
|
|
28
34
|
summarizer = ElasticAPM::Spies::SequelSpy.summarizer
|
29
35
|
name = summarizer.summarize sql
|
30
|
-
context =
|
31
|
-
statement: sql,
|
32
|
-
type: 'sql',
|
33
|
-
user: opts[:user]
|
34
|
-
)
|
36
|
+
context = ElasticAPM::Spies::SequelSpy.build_context(sql, opts)
|
35
37
|
|
36
|
-
ElasticAPM.
|
38
|
+
ElasticAPM.with_span(name, TYPE, context: context, &block)
|
37
39
|
end
|
38
40
|
end
|
39
41
|
end
|
@@ -6,25 +6,25 @@ module ElasticAPM
|
|
6
6
|
# @api private
|
7
7
|
class SidekiqSpy
|
8
8
|
ACTIVE_JOB_WRAPPER =
|
9
|
-
'ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper'
|
9
|
+
'ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper'
|
10
10
|
|
11
11
|
# @api private
|
12
12
|
class Middleware
|
13
13
|
# rubocop:disable Metrics/MethodLength
|
14
14
|
def call(_worker, job, queue)
|
15
15
|
name = SidekiqSpy.name_for(job)
|
16
|
-
transaction = ElasticAPM.
|
16
|
+
transaction = ElasticAPM.start_transaction(name, 'Sidekiq')
|
17
17
|
ElasticAPM.set_tag(:queue, queue)
|
18
18
|
|
19
19
|
yield
|
20
20
|
|
21
|
-
transaction.
|
21
|
+
transaction.done :success if transaction
|
22
22
|
rescue ::Exception => e
|
23
23
|
ElasticAPM.report(e, handled: false)
|
24
|
-
transaction.
|
24
|
+
transaction.done :error if transaction
|
25
25
|
raise
|
26
26
|
ensure
|
27
|
-
|
27
|
+
ElasticAPM.end_transaction
|
28
28
|
end
|
29
29
|
# rubocop:enable Metrics/MethodLength
|
30
30
|
end
|
@@ -5,7 +5,7 @@ module ElasticAPM
|
|
5
5
|
module Spies
|
6
6
|
# @api private
|
7
7
|
class TiltSpy
|
8
|
-
TYPE = 'template.tilt'
|
8
|
+
TYPE = 'template.tilt'
|
9
9
|
|
10
10
|
def install
|
11
11
|
::Tilt::Template.class_eval do
|
@@ -14,7 +14,7 @@ module ElasticAPM
|
|
14
14
|
def render(*args, &block)
|
15
15
|
name = options[:__elastic_apm_template_name] || 'Unknown template'
|
16
16
|
|
17
|
-
ElasticAPM.
|
17
|
+
ElasticAPM.with_span name, TYPE do
|
18
18
|
render_without_apm(*args, &block)
|
19
19
|
end
|
20
20
|
end
|
@@ -5,8 +5,8 @@ require 'elastic_apm/util/lru_cache'
|
|
5
5
|
module ElasticAPM
|
6
6
|
# @api private
|
7
7
|
class SqlSummarizer
|
8
|
-
DEFAULT = 'SQL'
|
9
|
-
TABLE_REGEX = %{["'`]?([A-Za-z0-9]+)}
|
8
|
+
DEFAULT = 'SQL'
|
9
|
+
TABLE_REGEX = %{["'`]?([A-Za-z0-9]+)}
|
10
10
|
|
11
11
|
REGEXES = {
|
12
12
|
/^BEGIN/i => 'BEGIN',
|
@@ -17,7 +17,7 @@ module ElasticAPM
|
|
17
17
|
/^DELETE FROM #{TABLE_REGEX}/i => 'DELETE FROM '
|
18
18
|
}.freeze
|
19
19
|
|
20
|
-
FORMAT = '%s%s'
|
20
|
+
FORMAT = '%s%s'
|
21
21
|
|
22
22
|
def self.cache
|
23
23
|
@cache ||= Util::LruCache.new
|
@@ -6,14 +6,14 @@ require 'elastic_apm/util/lru_cache'
|
|
6
6
|
module ElasticAPM
|
7
7
|
# @api private
|
8
8
|
class StacktraceBuilder
|
9
|
-
JAVA_FORMAT = /^(.+)\.([^\.]+)\(([^\:]+)\:(\d+)\)
|
10
|
-
RUBY_FORMAT = /^(.+?):(\d+)(?::in `(.+?)')
|
9
|
+
JAVA_FORMAT = /^(.+)\.([^\.]+)\(([^\:]+)\:(\d+)\)$/.freeze
|
10
|
+
RUBY_FORMAT = /^(.+?):(\d+)(?::in `(.+?)')?$/.freeze
|
11
11
|
|
12
|
-
RUBY_VERS_REGEX = %r{ruby(/gems)?[-/](\d+\.)+\d}
|
13
|
-
JRUBY_ORG_REGEX = %r{org/jruby}
|
12
|
+
RUBY_VERS_REGEX = %r{ruby(/gems)?[-/](\d+\.)+\d}.freeze
|
13
|
+
JRUBY_ORG_REGEX = %r{org/jruby}.freeze
|
14
14
|
|
15
|
-
def initialize(
|
16
|
-
@config =
|
15
|
+
def initialize(config)
|
16
|
+
@config = config
|
17
17
|
@cache = Util::LruCache.new(2048, &method(:build_frame))
|
18
18
|
end
|
19
19
|
|
@@ -6,7 +6,7 @@ require 'elastic_apm/normalizers'
|
|
6
6
|
module ElasticAPM
|
7
7
|
# @api private
|
8
8
|
class Subscriber
|
9
|
-
include
|
9
|
+
include Logging
|
10
10
|
|
11
11
|
def initialize(agent)
|
12
12
|
@agent = agent
|
@@ -40,7 +40,7 @@ module ElasticAPM
|
|
40
40
|
nil
|
41
41
|
else
|
42
42
|
name, type, context = normalized
|
43
|
-
@agent.
|
43
|
+
@agent.start_span(name, type, context: context)
|
44
44
|
end
|
45
45
|
|
46
46
|
transaction.notifications << Notification.new(id, span)
|
@@ -54,7 +54,7 @@ module ElasticAPM
|
|
54
54
|
next unless notification.id == id
|
55
55
|
|
56
56
|
if (span = notification.span)
|
57
|
-
span.
|
57
|
+
@agent.end_span if span == @agent.current_span
|
58
58
|
end
|
59
59
|
return
|
60
60
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ElasticAPM
|
4
|
+
# @api private
|
5
|
+
class Traceparent
|
6
|
+
class InvalidTraceparentHeader < StandardError; end
|
7
|
+
|
8
|
+
VERSION = '00'
|
9
|
+
HEX_REGEX = /[^[:xdigit:]]/.freeze
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@version = VERSION
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.from_transaction(transaction)
|
16
|
+
new.tap do |t|
|
17
|
+
t.trace_id = SecureRandom.hex(16)
|
18
|
+
t.recorded = transaction.sampled?
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# rubocop:disable Metrics/AbcSize
|
23
|
+
def self.parse(header)
|
24
|
+
raise InvalidTraceparentHeader unless header.length == 55
|
25
|
+
raise InvalidTraceparentHeader unless header[0..1] == VERSION
|
26
|
+
|
27
|
+
new.tap do |t|
|
28
|
+
t.version, t.trace_id, t.span_id, t.flags =
|
29
|
+
header.split('-').tap do |values|
|
30
|
+
values[-1] = Util.hex_to_bits(values[-1])
|
31
|
+
end
|
32
|
+
|
33
|
+
raise InvalidTraceparentHeader if HEX_REGEX =~ t.trace_id
|
34
|
+
raise InvalidTraceparentHeader if HEX_REGEX =~ t.span_id
|
35
|
+
end
|
36
|
+
end
|
37
|
+
# rubocop:enable Metrics/AbcSize
|
38
|
+
|
39
|
+
attr_accessor :header, :version, :trace_id, :span_id, :recorded
|
40
|
+
|
41
|
+
alias :recorded? :recorded
|
42
|
+
|
43
|
+
def flags=(flags)
|
44
|
+
@flags = flags
|
45
|
+
|
46
|
+
self.recorded = flags[7] == '1'
|
47
|
+
end
|
48
|
+
|
49
|
+
def flags
|
50
|
+
format('0000000%d', recorded? ? 1 : 0)
|
51
|
+
end
|
52
|
+
|
53
|
+
def hex_flags
|
54
|
+
format('%02x', flags.to_i(2))
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_header(span_id: nil)
|
58
|
+
span_id ||= self.span_id
|
59
|
+
format('%s-%s-%s-%s', version, trace_id, span_id, hex_flags)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|