datadog 2.31.0 → 2.32.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/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +17 -7
- data/ext/datadog_profiling_native_extension/collectors_thread_context.c +11 -4
- data/ext/datadog_profiling_native_extension/collectors_thread_context.h +6 -0
- data/ext/datadog_profiling_native_extension/extconf.rb +5 -4
- data/ext/datadog_profiling_native_extension/http_transport.c +10 -5
- data/ext/libdatadog_api/di.c +48 -0
- data/ext/libdatadog_api/extconf.rb +7 -4
- data/ext/libdatadog_extconf_helpers.rb +37 -0
- data/lib/datadog/ai_guard/configuration.rb +105 -2
- data/lib/datadog/ai_guard/evaluation.rb +1 -0
- data/lib/datadog/ai_guard/ext.rb +1 -0
- data/lib/datadog/appsec/autoload.rb +1 -1
- data/lib/datadog/appsec/component.rb +1 -1
- data/lib/datadog/appsec/configuration.rb +414 -1
- data/lib/datadog/appsec/contrib/devise/patches/signin_tracking_patch.rb +2 -1
- data/lib/datadog/appsec/contrib/rack/gateway/request.rb +1 -1
- data/lib/datadog/appsec/contrib/rails/patcher.rb +2 -2
- data/lib/datadog/appsec/metrics/telemetry.rb +13 -1
- data/lib/datadog/appsec/security_engine/runner.rb +1 -1
- data/lib/datadog/appsec/trace_keeper.rb +18 -6
- data/lib/datadog/appsec/utils/http/url_encoded.rb +2 -2
- data/lib/datadog/core/configuration/components.rb +1 -1
- data/lib/datadog/core/configuration/settings.rb +3 -0
- data/lib/datadog/core/configuration/supported_configurations.rb +2 -0
- data/lib/datadog/core/configuration.rb +1 -1
- data/lib/datadog/core/contrib/rails/utils.rb +1 -1
- data/lib/datadog/core/crashtracking/component.rb +3 -3
- data/lib/datadog/core/diagnostics/environment_logger.rb +3 -1
- data/lib/datadog/core/environment/container.rb +2 -2
- data/lib/datadog/core/feature_flags.rb +1 -1
- data/lib/datadog/core/metrics/client.rb +5 -5
- data/lib/datadog/core/remote/client.rb +1 -1
- data/lib/datadog/core/remote/component.rb +2 -2
- data/lib/datadog/core/runtime/metrics.rb +1 -1
- data/lib/datadog/core/telemetry/emitter.rb +1 -1
- data/lib/datadog/core/telemetry/event/app_started.rb +2 -2
- data/lib/datadog/core/transport/http.rb +2 -0
- data/lib/datadog/core/utils.rb +1 -1
- data/lib/datadog/core/workers/async.rb +1 -1
- data/lib/datadog/core.rb +1 -1
- data/lib/datadog/data_streams/configuration.rb +40 -1
- data/lib/datadog/data_streams/pathway_context.rb +1 -1
- data/lib/datadog/data_streams/processor.rb +1 -1
- data/lib/datadog/data_streams.rb +1 -1
- data/lib/datadog/di/base.rb +8 -5
- data/lib/datadog/di/code_tracker.rb +179 -1
- data/lib/datadog/di/component.rb +1 -1
- data/lib/datadog/di/configuration.rb +235 -2
- data/lib/datadog/di/instrumenter.rb +46 -26
- data/lib/datadog/di/probe_builder.rb +1 -1
- data/lib/datadog/di/probe_file_loader.rb +2 -2
- data/lib/datadog/di/probe_manager.rb +6 -6
- data/lib/datadog/di/probe_notification_builder.rb +1 -1
- data/lib/datadog/di/probe_notifier_worker.rb +2 -2
- data/lib/datadog/di/remote.rb +6 -6
- data/lib/datadog/di/serializer.rb +1 -1
- data/lib/datadog/di/transport/input.rb +3 -3
- data/lib/datadog/error_tracking/configuration.rb +55 -2
- data/lib/datadog/kit/enable_core_dumps.rb +1 -1
- data/lib/datadog/open_feature/component.rb +18 -1
- data/lib/datadog/open_feature/evaluation_engine.rb +3 -3
- data/lib/datadog/open_feature/exposures/reporter.rb +1 -1
- data/lib/datadog/open_feature/exposures/worker.rb +1 -1
- data/lib/datadog/open_feature/hooks/flag_eval_hook.rb +49 -0
- data/lib/datadog/open_feature/metrics/flag_eval_metrics.rb +149 -0
- data/lib/datadog/open_feature/provider.rb +19 -1
- data/lib/datadog/open_feature/remote.rb +1 -1
- data/lib/datadog/open_feature/transport.rb +1 -1
- data/lib/datadog/opentelemetry/metrics.rb +3 -3
- data/lib/datadog/opentelemetry/sdk/configurator.rb +1 -1
- data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +1 -1
- data/lib/datadog/profiling/collectors/code_provenance.rb +35 -9
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +31 -2
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +8 -2
- data/lib/datadog/profiling/collectors/info.rb +16 -3
- data/lib/datadog/profiling/component.rb +3 -5
- data/lib/datadog/profiling/exporter.rb +37 -12
- data/lib/datadog/profiling/ext.rb +0 -2
- data/lib/datadog/profiling/flush.rb +21 -12
- data/lib/datadog/profiling/http_transport.rb +12 -1
- data/lib/datadog/profiling/load_native_extension.rb +1 -1
- data/lib/datadog/profiling/profiler.rb +13 -1
- data/lib/datadog/profiling/scheduler.rb +2 -2
- data/lib/datadog/profiling/tasks/exec.rb +8 -3
- data/lib/datadog/profiling/tasks/help.rb +1 -0
- data/lib/datadog/profiling/tasks/setup.rb +2 -2
- data/lib/datadog/single_step_instrument.rb +1 -1
- data/lib/datadog/symbol_database/configuration.rb +65 -0
- data/lib/datadog/symbol_database/extractor.rb +915 -0
- data/lib/datadog/symbol_database/file_hash.rb +46 -0
- data/lib/datadog/symbol_database/logger.rb +43 -0
- data/lib/datadog/symbol_database/scope.rb +98 -0
- data/lib/datadog/symbol_database/service_version.rb +57 -0
- data/lib/datadog/symbol_database/symbol.rb +66 -0
- data/lib/datadog/symbol_database/transport/http/endpoint.rb +28 -0
- data/lib/datadog/symbol_database/transport/http.rb +45 -0
- data/lib/datadog/symbol_database/transport.rb +54 -0
- data/lib/datadog/symbol_database/uploader.rb +166 -0
- data/lib/datadog/symbol_database.rb +49 -0
- data/lib/datadog/tracing/buffer.rb +3 -3
- data/lib/datadog/tracing/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +5 -3
- data/lib/datadog/tracing/contrib/action_view/events/render_template.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/discard.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_at.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/enqueue_retry.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/perform.rb +1 -1
- data/lib/datadog/tracing/contrib/active_job/events/retry_stopped.rb +1 -1
- data/lib/datadog/tracing/contrib/active_model_serializers/events/render.rb +1 -1
- data/lib/datadog/tracing/contrib/active_model_serializers/events/serialize.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +2 -2
- data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/events/sql.rb +1 -1
- data/lib/datadog/tracing/contrib/active_record/utils.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +1 -1
- data/lib/datadog/tracing/contrib/active_support/notifications/subscription.rb +2 -2
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +1 -1
- data/lib/datadog/tracing/contrib/component.rb +1 -1
- data/lib/datadog/tracing/contrib/configuration/resolver.rb +7 -4
- data/lib/datadog/tracing/contrib/dalli/quantize.rb +1 -1
- data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/excon/middleware.rb +2 -2
- data/lib/datadog/tracing/contrib/extensions.rb +9 -0
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +2 -2
- data/lib/datadog/tracing/contrib/grape/endpoint.rb +5 -5
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +2 -2
- data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +2 -2
- data/lib/datadog/tracing/contrib/http/instrumentation.rb +2 -2
- data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +6 -2
- data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +2 -2
- data/lib/datadog/tracing/contrib/kafka/instrumentation/consumer.rb +2 -2
- data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +2 -2
- data/lib/datadog/tracing/contrib/karafka/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +3 -3
- data/lib/datadog/tracing/contrib/opensearch/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/presto/instrumentation.rb +3 -3
- data/lib/datadog/tracing/contrib/rack/patcher.rb +1 -1
- data/lib/datadog/tracing/contrib/rack/request_queue.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/log_injection.rb +1 -1
- data/lib/datadog/tracing/contrib/rails/runner.rb +1 -1
- data/lib/datadog/tracing/contrib/rake/instrumentation.rb +2 -2
- data/lib/datadog/tracing/contrib/redis/quantize.rb +1 -1
- data/lib/datadog/tracing/contrib/redis/tags.rb +1 -1
- data/lib/datadog/tracing/contrib/sidekiq/utils.rb +1 -1
- data/lib/datadog/tracing/contrib/stripe/request.rb +1 -1
- data/lib/datadog/tracing/contrib.rb +8 -0
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +3 -1
- data/lib/datadog/tracing/distributed/baggage.rb +59 -5
- data/lib/datadog/tracing/distributed/datadog.rb +11 -11
- data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +1 -1
- data/lib/datadog/tracing/distributed/propagation.rb +2 -2
- data/lib/datadog/tracing/distributed/trace_context.rb +74 -32
- data/lib/datadog/tracing/event.rb +1 -1
- data/lib/datadog/tracing/metadata/tagging.rb +2 -2
- data/lib/datadog/tracing/pipeline.rb +1 -1
- data/lib/datadog/tracing/remote.rb +1 -1
- data/lib/datadog/tracing/sampling/rule.rb +1 -1
- data/lib/datadog/tracing/sampling/rule_sampler.rb +2 -2
- data/lib/datadog/tracing/sampling/span/rule_parser.rb +2 -2
- data/lib/datadog/tracing/span_operation.rb +3 -3
- data/lib/datadog/tracing/trace_operation.rb +4 -4
- data/lib/datadog/tracing/tracer.rb +5 -5
- data/lib/datadog/tracing/transport/io/client.rb +1 -1
- data/lib/datadog/tracing/workers.rb +2 -1
- data/lib/datadog/version.rb +1 -1
- metadata +18 -9
- data/lib/datadog/ai_guard/configuration/settings.rb +0 -113
- data/lib/datadog/appsec/configuration/settings.rb +0 -423
- data/lib/datadog/data_streams/configuration/settings.rb +0 -49
- data/lib/datadog/di/configuration/settings.rb +0 -243
- data/lib/datadog/error_tracking/configuration/settings.rb +0 -63
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'digest/sha1'
|
|
4
|
+
|
|
5
|
+
module Datadog
|
|
6
|
+
module SymbolDatabase
|
|
7
|
+
# Computes Git-style SHA-1 hashes of Ruby source files for backend commit inference.
|
|
8
|
+
#
|
|
9
|
+
# Uses Git's blob hash algorithm: SHA1("blob <size>\0<content>")
|
|
10
|
+
# Hashes enable the backend to correlate runtime code with Git repository history,
|
|
11
|
+
# identifying which commit is actually deployed.
|
|
12
|
+
#
|
|
13
|
+
# Called by: Extractor (when building MODULE scopes)
|
|
14
|
+
# Stores result in: Scope's language_specifics[:file_hash]
|
|
15
|
+
# Returns: 40-character hex string or nil if file unreadable
|
|
16
|
+
#
|
|
17
|
+
# @api private
|
|
18
|
+
module FileHash
|
|
19
|
+
module_function
|
|
20
|
+
|
|
21
|
+
# Compute Git-style SHA-1 hash of a file.
|
|
22
|
+
# Uses Git's blob hash algorithm: SHA1("blob <size>\0<content>")
|
|
23
|
+
# Returns nil on any error (file not found, permission denied, etc.)
|
|
24
|
+
#
|
|
25
|
+
# @param file_path [String] Path to the file
|
|
26
|
+
# @param logger [#debug] Logger for error reporting
|
|
27
|
+
# @return [String, nil] 40-character hex-encoded SHA-1 hash, or nil if error
|
|
28
|
+
def compute(file_path, logger:)
|
|
29
|
+
return nil unless file_path
|
|
30
|
+
return nil unless File.exist?(file_path)
|
|
31
|
+
|
|
32
|
+
content = File.read(file_path, mode: 'rb')
|
|
33
|
+
size = content.bytesize
|
|
34
|
+
git_blob = "blob #{size}\0#{content}"
|
|
35
|
+
|
|
36
|
+
# SHA-1 is required here to match Git's blob hash format for commit inference.
|
|
37
|
+
# This is not a security vulnerability - we're computing file content hashes
|
|
38
|
+
# to match against Git objects, not using SHA-1 for authentication/integrity.
|
|
39
|
+
Digest::SHA1.hexdigest(git_blob) # nosemgrep: ruby.lang.security.weak-hashes-sha1.weak-hashes-sha1
|
|
40
|
+
rescue => e
|
|
41
|
+
logger.debug { "symdb: file hash failed for #{file_path}: #{e.class}: #{e.message}" }
|
|
42
|
+
nil
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'forwardable'
|
|
4
|
+
|
|
5
|
+
module Datadog
|
|
6
|
+
module SymbolDatabase
|
|
7
|
+
# Logger facade that adds a config-gated +trace+ method.
|
|
8
|
+
#
|
|
9
|
+
# Wraps any logger (customer-provided or default) and delegates
|
|
10
|
+
# standard methods. The +trace+ method is a sub-debug level that
|
|
11
|
+
# is a no-op unless DD_TRACE_DEBUG is set, avoiding overhead for
|
|
12
|
+
# high-frequency log sites (per-module filtering, dedup checks).
|
|
13
|
+
#
|
|
14
|
+
# @api private
|
|
15
|
+
class Logger
|
|
16
|
+
extend Forwardable
|
|
17
|
+
|
|
18
|
+
# @param settings [Configuration::Settings] Tracer settings (reads trace_logging flag)
|
|
19
|
+
# @param target [::Logger] Underlying logger to delegate to
|
|
20
|
+
def initialize(settings, target)
|
|
21
|
+
@settings = settings
|
|
22
|
+
@target = target
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
attr_reader :settings
|
|
26
|
+
|
|
27
|
+
# Only debug and warn are delegated by design — symbol database
|
|
28
|
+
# extraction logs only at debug (high-volume diagnostics) and warn
|
|
29
|
+
# (user-actionable problems). Adding info/error would invite
|
|
30
|
+
# log-level drift; explicit additions can be made if needed.
|
|
31
|
+
def_delegators :@target, :debug, :warn
|
|
32
|
+
|
|
33
|
+
# Log at trace level (sub-debug). No-op unless DD_TRACE_DEBUG is set.
|
|
34
|
+
# @yield Block that returns the log message string
|
|
35
|
+
# @return [void]
|
|
36
|
+
def trace(&block)
|
|
37
|
+
if settings.symbol_database.internal.trace_logging
|
|
38
|
+
debug(&block)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
module Datadog
|
|
6
|
+
module SymbolDatabase
|
|
7
|
+
# Represents a scope in the hierarchical symbol structure (FILE → MODULE/CLASS → METHOD).
|
|
8
|
+
#
|
|
9
|
+
# Scopes form a tree structure representing Ruby code organization. Each scope contains:
|
|
10
|
+
# - Metadata: name, source file, line range, scope type (MODULE/CLASS/METHOD/etc.)
|
|
11
|
+
# - Symbols: Variables, constants, parameters defined in this scope
|
|
12
|
+
# - Nested scopes: Child scopes (e.g., methods within a class)
|
|
13
|
+
#
|
|
14
|
+
# Created by: Extractor (during symbol extraction)
|
|
15
|
+
# Used by: ScopeBatcher (batching), ServiceVersion (wrapping for upload)
|
|
16
|
+
# Serialized to: JSON via to_h/to_json for upload to agent
|
|
17
|
+
#
|
|
18
|
+
# @api private
|
|
19
|
+
class Scope
|
|
20
|
+
attr_reader :scope_type, :name, :source_file, :start_line, :end_line,
|
|
21
|
+
# Ranges of executable lines [{start:, end:}]. Three states:
|
|
22
|
+
# - nil: not computed (source unreadable, native/C-extension method)
|
|
23
|
+
# - []: computed but no executable lines found (comments/whitespace only)
|
|
24
|
+
# - non-empty: computed, contains executable line ranges
|
|
25
|
+
# nil and [] both serialize as injectible_lines?: false on METHOD
|
|
26
|
+
# scopes. Key is absent on non-METHOD scopes.
|
|
27
|
+
:injectible_lines,
|
|
28
|
+
:language_specifics, :symbols, :scopes
|
|
29
|
+
|
|
30
|
+
# Initialize a new Scope
|
|
31
|
+
# @param scope_type [String] Type of scope (FILE, MODULE, CLASS, METHOD)
|
|
32
|
+
# @param name [String, nil] Name of the scope (class name, method name, etc.)
|
|
33
|
+
# @param source_file [String, nil] Path to source file
|
|
34
|
+
# @param start_line [Integer, nil] Starting line number (UNKNOWN_MIN_LINE for unknown)
|
|
35
|
+
# @param end_line [Integer, nil] Ending line number (UNKNOWN_MAX_LINE for entire file)
|
|
36
|
+
# @param injectible_lines [Array<Hash>, nil] Ranges of executable lines [{start:, end:}]
|
|
37
|
+
# @param language_specifics [Hash, nil] Ruby-specific metadata
|
|
38
|
+
# @param symbols [Array<Symbol>, nil] Symbols defined in this scope
|
|
39
|
+
# @param scopes [Array<Scope>, nil] Nested child scopes
|
|
40
|
+
def initialize(
|
|
41
|
+
scope_type:,
|
|
42
|
+
name: nil,
|
|
43
|
+
source_file: nil,
|
|
44
|
+
start_line: nil,
|
|
45
|
+
end_line: nil,
|
|
46
|
+
injectible_lines: nil,
|
|
47
|
+
language_specifics: nil,
|
|
48
|
+
symbols: nil,
|
|
49
|
+
scopes: nil
|
|
50
|
+
)
|
|
51
|
+
@scope_type = scope_type
|
|
52
|
+
@name = name
|
|
53
|
+
@source_file = source_file
|
|
54
|
+
@start_line = start_line
|
|
55
|
+
@end_line = end_line
|
|
56
|
+
@injectible_lines = injectible_lines
|
|
57
|
+
@language_specifics = language_specifics || {}
|
|
58
|
+
@symbols = symbols || []
|
|
59
|
+
@scopes = scopes || []
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# @return [Boolean] true when injectible_lines is non-nil and non-empty
|
|
63
|
+
def injectible_lines?
|
|
64
|
+
!injectible_lines.nil? && !injectible_lines.empty?
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Convert scope to Hash for JSON serialization.
|
|
68
|
+
# Removes nil values to reduce payload size.
|
|
69
|
+
# @return [Hash] Scope as hash with symbol keys
|
|
70
|
+
def to_h
|
|
71
|
+
h = {
|
|
72
|
+
scope_type: scope_type,
|
|
73
|
+
name: name,
|
|
74
|
+
source_file: source_file,
|
|
75
|
+
start_line: start_line,
|
|
76
|
+
end_line: end_line,
|
|
77
|
+
language_specifics: language_specifics.empty? ? nil : language_specifics,
|
|
78
|
+
symbols: symbols.empty? ? nil : symbols.map(&:to_h),
|
|
79
|
+
scopes: scopes.empty? ? nil : scopes.map(&:to_h),
|
|
80
|
+
}
|
|
81
|
+
h.compact!
|
|
82
|
+
# Injectable lines only on METHOD scopes (per spec — not on CLASS/MODULE/FILE).
|
|
83
|
+
# Always emit has_injectible_lines (even when false) on METHOD scopes.
|
|
84
|
+
if scope_type == 'METHOD'
|
|
85
|
+
h[:has_injectible_lines] = injectible_lines? # steep:ignore ArgumentTypeMismatch
|
|
86
|
+
h[:injectible_lines] = injectible_lines if injectible_lines && !injectible_lines.empty?
|
|
87
|
+
end
|
|
88
|
+
h
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Serialize scope to JSON.
|
|
92
|
+
# @return [String] JSON string representation
|
|
93
|
+
def to_json(_state = nil)
|
|
94
|
+
JSON.generate(to_h)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
module Datadog
|
|
6
|
+
module SymbolDatabase
|
|
7
|
+
# Top-level container wrapping scopes for upload to the agent.
|
|
8
|
+
#
|
|
9
|
+
# ServiceVersion is the root object serialized to JSON for symbol database uploads.
|
|
10
|
+
# Contains service metadata (name, env, version) and all extracted scopes.
|
|
11
|
+
# The language field identifies the tracer.
|
|
12
|
+
#
|
|
13
|
+
# Created by: Uploader (wraps scopes array before serialization)
|
|
14
|
+
# Contains: Array of top-level Scope objects (FILE scopes)
|
|
15
|
+
# Serialized to: JSON via to_json, then GZIP compressed for upload
|
|
16
|
+
#
|
|
17
|
+
# @api private
|
|
18
|
+
class ServiceVersion
|
|
19
|
+
attr_reader :service, :env, :version, :language, :scopes
|
|
20
|
+
|
|
21
|
+
# Initialize a new ServiceVersion
|
|
22
|
+
# @param service [String] Service name (required, from DD_SERVICE)
|
|
23
|
+
# @param env [String] Environment (from DD_ENV, defaults to "none")
|
|
24
|
+
# @param version [String] Version (from DD_VERSION, defaults to "none")
|
|
25
|
+
# @param scopes [Array<Scope>] Top-level scopes (required)
|
|
26
|
+
# @raise [ArgumentError] if service empty or scopes not an array
|
|
27
|
+
def initialize(service:, env:, version:, scopes:)
|
|
28
|
+
raise ArgumentError, 'service is required' if service.nil? || service.empty?
|
|
29
|
+
raise ArgumentError, 'scopes must be an array' unless scopes.is_a?(Array)
|
|
30
|
+
|
|
31
|
+
@service = service
|
|
32
|
+
@env = env.to_s.empty? ? 'none' : env.to_s
|
|
33
|
+
@version = version.to_s.empty? ? 'none' : version.to_s
|
|
34
|
+
@language = 'ruby'
|
|
35
|
+
@scopes = scopes
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Convert service version to Hash for JSON serialization.
|
|
39
|
+
# @return [Hash] ServiceVersion as hash with symbol keys
|
|
40
|
+
def to_h
|
|
41
|
+
{
|
|
42
|
+
service: service,
|
|
43
|
+
env: env,
|
|
44
|
+
version: version,
|
|
45
|
+
language: language,
|
|
46
|
+
scopes: scopes.map(&:to_h),
|
|
47
|
+
}
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Serialize service version to JSON.
|
|
51
|
+
# @return [String] JSON string representation
|
|
52
|
+
def to_json(_state = nil)
|
|
53
|
+
JSON.generate(to_h)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
module Datadog
|
|
6
|
+
module SymbolDatabase
|
|
7
|
+
# Represents a symbol (variable, parameter, field, constant) within a scope.
|
|
8
|
+
#
|
|
9
|
+
# Symbols are the actual identifiers extracted from Ruby code:
|
|
10
|
+
# - Instance variables (@var) - FIELD type
|
|
11
|
+
# - Class variables (@@var) - STATIC_FIELD type
|
|
12
|
+
# - Constants (CONST) - STATIC_FIELD type
|
|
13
|
+
# - Method parameters (arg) - ARG type
|
|
14
|
+
# - Local variables (var) - LOCAL type (not yet implemented)
|
|
15
|
+
#
|
|
16
|
+
# Created by: Extractor (during class/method introspection)
|
|
17
|
+
# Contained in: Scope objects (symbols array)
|
|
18
|
+
# Serialized to: JSON via to_h/to_json
|
|
19
|
+
#
|
|
20
|
+
# @api private
|
|
21
|
+
class Symbol
|
|
22
|
+
attr_reader :symbol_type, :name, :line, :type, :language_specifics
|
|
23
|
+
|
|
24
|
+
# Initialize a new Symbol
|
|
25
|
+
# @param symbol_type [String] Type: FIELD, STATIC_FIELD, ARG, LOCAL
|
|
26
|
+
# @param name [String] Symbol name (variable name, parameter name)
|
|
27
|
+
# @param line [Integer] Line number (UNKNOWN_MIN_LINE for entire scope, UNKNOWN_MAX_LINE for method-level only)
|
|
28
|
+
# @param type [String, nil] Type annotation (optional, Ruby is dynamic)
|
|
29
|
+
# @param language_specifics [Hash, nil] Symbol-specific metadata
|
|
30
|
+
def initialize(
|
|
31
|
+
symbol_type:,
|
|
32
|
+
name:,
|
|
33
|
+
line:,
|
|
34
|
+
type: nil,
|
|
35
|
+
language_specifics: nil
|
|
36
|
+
)
|
|
37
|
+
@symbol_type = symbol_type
|
|
38
|
+
@name = name
|
|
39
|
+
@line = line
|
|
40
|
+
@type = type
|
|
41
|
+
@language_specifics = language_specifics
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Convert symbol to Hash for JSON serialization.
|
|
45
|
+
# Removes nil values to reduce payload size.
|
|
46
|
+
# @return [Hash] Symbol as hash with symbol keys
|
|
47
|
+
def to_h
|
|
48
|
+
h = {
|
|
49
|
+
symbol_type: symbol_type,
|
|
50
|
+
name: name,
|
|
51
|
+
line: line,
|
|
52
|
+
type: type,
|
|
53
|
+
language_specifics: language_specifics,
|
|
54
|
+
}
|
|
55
|
+
h.compact!
|
|
56
|
+
h
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Serialize symbol to JSON.
|
|
60
|
+
# @return [String] JSON string representation
|
|
61
|
+
def to_json(_state = nil)
|
|
62
|
+
JSON.generate(to_h)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../../core/transport/http/api/endpoint'
|
|
4
|
+
|
|
5
|
+
module Datadog
|
|
6
|
+
module SymbolDatabase
|
|
7
|
+
module Transport
|
|
8
|
+
module HTTP
|
|
9
|
+
module API
|
|
10
|
+
# POST endpoint for symbol database uploads. Multipart form-data
|
|
11
|
+
# is triggered by setting `env.form` on the request (handled in
|
|
12
|
+
# `Core::Transport::HTTP::Adapters::Net`); the multipart library
|
|
13
|
+
# sets Content-Type itself.
|
|
14
|
+
class Endpoint < Datadog::Core::Transport::HTTP::API::Endpoint
|
|
15
|
+
attr_reader :encoder
|
|
16
|
+
|
|
17
|
+
# @param path [String] URL path for the endpoint
|
|
18
|
+
# @param encoder [#encode] Encoder for request data
|
|
19
|
+
def initialize(path, encoder)
|
|
20
|
+
super(:post, path)
|
|
21
|
+
@encoder = encoder
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../core/encoding'
|
|
4
|
+
require_relative '../../core/transport/http'
|
|
5
|
+
require_relative 'http/endpoint'
|
|
6
|
+
require_relative '../transport'
|
|
7
|
+
|
|
8
|
+
module Datadog
|
|
9
|
+
module SymbolDatabase
|
|
10
|
+
module Transport
|
|
11
|
+
# Namespace for HTTP transport components
|
|
12
|
+
module HTTP
|
|
13
|
+
# POST endpoint for the agent's symbol database intake.
|
|
14
|
+
# Multipart form-data is dispatched via `env.form` from the
|
|
15
|
+
# `Symbols::Client` subclass.
|
|
16
|
+
SYMBOLS_ENDPOINT = API::Endpoint.new(
|
|
17
|
+
'/symdb/v1/input',
|
|
18
|
+
Datadog::Core::Encoding::JSONEncoder,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
# Builds a transport for the symbols upload endpoint.
|
|
22
|
+
# @param agent_settings [Core::Configuration::AgentSettingsResolver::AgentSettings]
|
|
23
|
+
# Agent connection settings (host, port, timeout, etc.)
|
|
24
|
+
# @param logger [Logger] Logger instance
|
|
25
|
+
# @param headers [Hash, nil] Optional additional headers
|
|
26
|
+
# @return [Symbols::Transport] Transport for the symbols endpoint
|
|
27
|
+
def self.symbols(
|
|
28
|
+
agent_settings:,
|
|
29
|
+
logger:,
|
|
30
|
+
headers: nil
|
|
31
|
+
)
|
|
32
|
+
Core::Transport::HTTP.build(
|
|
33
|
+
logger: logger,
|
|
34
|
+
agent_settings: agent_settings,
|
|
35
|
+
headers: headers,
|
|
36
|
+
) do |transport|
|
|
37
|
+
transport.api 'symbols', SYMBOLS_ENDPOINT, default: true
|
|
38
|
+
|
|
39
|
+
yield(transport) if block_given?
|
|
40
|
+
end.to_transport(SymbolDatabase::Transport::Symbols::Transport)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../core/transport/request'
|
|
4
|
+
require_relative '../core/transport/transport'
|
|
5
|
+
require_relative '../core/transport/http/client'
|
|
6
|
+
require_relative '../core/transport/http/env'
|
|
7
|
+
|
|
8
|
+
module Datadog
|
|
9
|
+
module SymbolDatabase
|
|
10
|
+
module Transport
|
|
11
|
+
# Transport classes for the symbols upload endpoint.
|
|
12
|
+
# Mirrors the per-purpose split used by DI (`DI::Transport::Input::*`).
|
|
13
|
+
module Symbols
|
|
14
|
+
# Request wrapper carrying the multipart form for a symbols upload.
|
|
15
|
+
class Request < Core::Transport::Request
|
|
16
|
+
attr_reader :form
|
|
17
|
+
|
|
18
|
+
# @param form [Hash] Multipart form data with UploadIO objects
|
|
19
|
+
def initialize(form)
|
|
20
|
+
@form = form
|
|
21
|
+
# Multipart upload — no parcel; the Net adapter reads form data
|
|
22
|
+
# off the env directly.
|
|
23
|
+
super(nil)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# HTTP client for symbol database uploads.
|
|
28
|
+
# Extends Core::Transport::HTTP::Client to set `env.form`, which the
|
|
29
|
+
# Net adapter (lib/datadog/core/transport/http/adapters/net.rb) detects
|
|
30
|
+
# and dispatches as multipart/form-data.
|
|
31
|
+
class Client < Core::Transport::HTTP::Client
|
|
32
|
+
# @param request [Request] Symbols upload request
|
|
33
|
+
# @return [Core::Transport::HTTP::Env] Env with form data set
|
|
34
|
+
def build_env(request)
|
|
35
|
+
Core::Transport::HTTP::Env.new(request, form: request.form)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Transport for the symbols upload endpoint.
|
|
40
|
+
class Transport < Core::Transport::Transport
|
|
41
|
+
self.http_client_class = Client
|
|
42
|
+
|
|
43
|
+
# Send a symbols upload to the agent.
|
|
44
|
+
# @param form [Hash] Multipart form data with UploadIO objects
|
|
45
|
+
# @return [Core::Transport::Response] Response from agent
|
|
46
|
+
def send_symbols(form)
|
|
47
|
+
request = Request.new(form)
|
|
48
|
+
client.send_request(:symbols, request)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'zlib'
|
|
5
|
+
require 'stringio'
|
|
6
|
+
require_relative '../core/environment/identity'
|
|
7
|
+
require_relative '../core/vendor/multipart-post/multipart/post/composite_read_io'
|
|
8
|
+
require_relative 'service_version'
|
|
9
|
+
require_relative 'transport/http'
|
|
10
|
+
|
|
11
|
+
module Datadog
|
|
12
|
+
module SymbolDatabase
|
|
13
|
+
# Uploads symbol database payloads to the Datadog agent via HTTP multipart.
|
|
14
|
+
#
|
|
15
|
+
# Handles the complete upload process:
|
|
16
|
+
# 1. Wraps scopes in ServiceVersion (adds service/env/version metadata)
|
|
17
|
+
# 2. Serializes to JSON
|
|
18
|
+
# 3. Compresses with GZIP (always, ~40:1 ratio expected)
|
|
19
|
+
# 4. Builds multipart form: event.json (metadata) + symbols_{pid}.json.gz (data)
|
|
20
|
+
# 5. POSTs to agent at /symdb/v1/input via Core::Transport::HTTP
|
|
21
|
+
# No retries — single attempt. Any failure is logged at debug and discarded.
|
|
22
|
+
#
|
|
23
|
+
# Uses Core::Transport::HTTP infrastructure (consistent with DI, Profiling, DataStreams).
|
|
24
|
+
# Headers: DD-API-KEY, Datadog-Container-ID, Datadog-Entity-ID (automatic from transport)
|
|
25
|
+
#
|
|
26
|
+
# Called by: ScopeBatcher.perform_upload (when batch ready)
|
|
27
|
+
# Calls: Transport::HTTP for network, Zlib for compression
|
|
28
|
+
#
|
|
29
|
+
# @api private
|
|
30
|
+
class Uploader
|
|
31
|
+
MAX_PAYLOAD_SIZE = 50 * 1024 * 1024 # 50MB
|
|
32
|
+
|
|
33
|
+
# Initialize uploader.
|
|
34
|
+
# @param settings [Configuration::Settings] Tracer settings (for service, env, version metadata)
|
|
35
|
+
# @param agent_settings [Configuration::AgentSettings] Agent connection settings
|
|
36
|
+
# @param logger [Logger] Logger instance
|
|
37
|
+
# @param telemetry [Telemetry, nil] Optional telemetry component for error reporting
|
|
38
|
+
def initialize(settings:, agent_settings:, logger:, telemetry: nil)
|
|
39
|
+
@settings = settings
|
|
40
|
+
@agent_settings = agent_settings
|
|
41
|
+
@logger = logger
|
|
42
|
+
@telemetry = telemetry
|
|
43
|
+
|
|
44
|
+
@transport = Transport::HTTP.symbols(
|
|
45
|
+
agent_settings: agent_settings,
|
|
46
|
+
logger: @logger,
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Upload a batch of scopes to the agent.
|
|
51
|
+
# Wraps in ServiceVersion, serializes to JSON, compresses with GZIP,
|
|
52
|
+
# builds multipart form, and POSTs to /symdb/v1/input via transport.
|
|
53
|
+
# No retries — single attempt, matching Python behavior.
|
|
54
|
+
# @param scopes [Array<Scope>] Scopes to upload
|
|
55
|
+
# @return [void]
|
|
56
|
+
def upload_scopes(scopes)
|
|
57
|
+
return if scopes.empty?
|
|
58
|
+
|
|
59
|
+
json_data = build_symbol_payload(scopes)
|
|
60
|
+
compressed_data = Zlib.gzip(json_data)
|
|
61
|
+
|
|
62
|
+
# Symbols for very large applications (>50MB after gzip) are dropped:
|
|
63
|
+
# the upload is skipped and the customer sees no autocomplete /
|
|
64
|
+
# symbol probe results for those classes. Java handles the same case
|
|
65
|
+
# by splitting the payload across multiple requests; we have not
|
|
66
|
+
# implemented splitting here. Deferred for a post-MVP follow-up.
|
|
67
|
+
if compressed_data.bytesize > MAX_PAYLOAD_SIZE
|
|
68
|
+
@logger.debug { "symdb: payload too large: #{compressed_data.bytesize}/#{MAX_PAYLOAD_SIZE} bytes, skipping" }
|
|
69
|
+
return
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
perform_http_upload(compressed_data, scopes.size)
|
|
73
|
+
rescue => e
|
|
74
|
+
@logger.debug { "symdb: upload failed: #{e.class}: #{e.message}" }
|
|
75
|
+
@telemetry&.report(e, description: 'symdb: upload failed')
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
# Build JSON payload from scopes.
|
|
81
|
+
# @param scopes [Array<Scope>] Scopes to serialize
|
|
82
|
+
# @return [String] JSON string
|
|
83
|
+
def build_symbol_payload(scopes)
|
|
84
|
+
ServiceVersion.new(
|
|
85
|
+
service: @settings.service,
|
|
86
|
+
env: @settings.env,
|
|
87
|
+
version: @settings.version,
|
|
88
|
+
scopes: scopes,
|
|
89
|
+
).to_json
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Perform HTTP POST with multipart form-data via transport layer.
|
|
93
|
+
# @param compressed_data [String] GZIP compressed JSON payload
|
|
94
|
+
# @param scope_count [Integer] Number of scopes (for logging)
|
|
95
|
+
# @return [void]
|
|
96
|
+
def perform_http_upload(compressed_data, scope_count)
|
|
97
|
+
form = build_multipart_form(compressed_data)
|
|
98
|
+
response = @transport.send_symbols(form)
|
|
99
|
+
handle_response(response, scope_count)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Build multipart form-data with event metadata and compressed symbols.
|
|
103
|
+
# @param compressed_data [String] GZIP compressed JSON payload
|
|
104
|
+
# @return [Hash] Form data hash with UploadIO objects
|
|
105
|
+
def build_multipart_form(compressed_data)
|
|
106
|
+
event_io = StringIO.new(build_event_metadata)
|
|
107
|
+
file_io = StringIO.new(compressed_data)
|
|
108
|
+
|
|
109
|
+
event_upload = Datadog::Core::Vendor::Multipart::Post::UploadIO.new(
|
|
110
|
+
event_io,
|
|
111
|
+
'application/json',
|
|
112
|
+
'event.json',
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
file_upload = Datadog::Core::Vendor::Multipart::Post::UploadIO.new(
|
|
116
|
+
file_io,
|
|
117
|
+
'application/gzip',
|
|
118
|
+
"symbols_#{Process.pid}.json.gz",
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
{
|
|
122
|
+
'event' => event_upload,
|
|
123
|
+
'file' => file_upload,
|
|
124
|
+
}
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Build event.json metadata part.
|
|
128
|
+
# @return [String] JSON string for event metadata
|
|
129
|
+
def build_event_metadata
|
|
130
|
+
JSON.generate(
|
|
131
|
+
ddsource: 'ruby',
|
|
132
|
+
service: @settings.service,
|
|
133
|
+
runtimeId: Datadog::Core::Environment::Identity.id,
|
|
134
|
+
parentId: nil, # Fork tracking deferred for MVP
|
|
135
|
+
type: 'symdb',
|
|
136
|
+
)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Handle HTTP response and track metrics.
|
|
140
|
+
# @param response [Core::Transport::Response] HTTP response from agent
|
|
141
|
+
# @param scope_count [Integer] Number of scopes uploaded
|
|
142
|
+
# @return [Boolean] true if successful, false otherwise
|
|
143
|
+
def handle_response(response, scope_count)
|
|
144
|
+
if response.internal_error?
|
|
145
|
+
@logger.debug { "symdb: upload failed: #{response.error.class}: #{response.error}" } # steep:ignore NoMethod
|
|
146
|
+
return false
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
case response.code
|
|
150
|
+
when 200..299
|
|
151
|
+
@logger.debug { "symdb: uploaded #{scope_count} scopes successfully" }
|
|
152
|
+
true
|
|
153
|
+
when 429
|
|
154
|
+
@logger.debug { "symdb: upload rejected: rate limited (429)" }
|
|
155
|
+
false
|
|
156
|
+
when 500..599
|
|
157
|
+
@logger.debug { "symdb: upload rejected: server error (#{response.code})" }
|
|
158
|
+
false
|
|
159
|
+
else
|
|
160
|
+
@logger.debug { "symdb: upload rejected: #{response.code}" }
|
|
161
|
+
false
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
# Namespace for Datadog symbol database upload.
|
|
5
|
+
#
|
|
6
|
+
# @api private
|
|
7
|
+
module SymbolDatabase
|
|
8
|
+
# Sentinel value for unknown or unavailable minimum line number.
|
|
9
|
+
#
|
|
10
|
+
# Used for:
|
|
11
|
+
# 1. start_line when exact line cannot be determined (e.g., modules without methods)
|
|
12
|
+
# 2. Symbol line numbers for FIELD, STATIC_FIELD, ARG symbols to indicate
|
|
13
|
+
# the symbol is available throughout the entire enclosing scope
|
|
14
|
+
#
|
|
15
|
+
# Backend behavior: line=0 means symbol completes in every line of the scope
|
|
16
|
+
#
|
|
17
|
+
# Reference: Symbol Database Backend RFC, section "Edge Cases"
|
|
18
|
+
# - "We use 0 for FIELD, STATIC_FIELD and ARG. It means that the symbol
|
|
19
|
+
# will be completed in every line of the enclosing scope (CLASS or METHOD)."
|
|
20
|
+
#
|
|
21
|
+
# @see https://www.postgresql.org/docs/current/datatype-numeric.html
|
|
22
|
+
UNKNOWN_MIN_LINE = 0
|
|
23
|
+
|
|
24
|
+
# Sentinel value for unknown or unavailable maximum line number.
|
|
25
|
+
#
|
|
26
|
+
# Used for:
|
|
27
|
+
# 1. end_line when exact boundaries cannot be determined (e.g., modules, classes
|
|
28
|
+
# without methods, fallback when introspection fails)
|
|
29
|
+
# 2. LOCAL symbol line numbers when exact line is unknown (future feature)
|
|
30
|
+
#
|
|
31
|
+
# Value: 2147483647 (PostgreSQL signed INT_MAX, 2^31 - 1)
|
|
32
|
+
#
|
|
33
|
+
# Backend behavior:
|
|
34
|
+
# - For scopes: indicates "entire file" or "unknown end"
|
|
35
|
+
# - For LOCAL symbols (future): included in method probe completions but excluded
|
|
36
|
+
# from line probe completions
|
|
37
|
+
#
|
|
38
|
+
# Protocol specification:
|
|
39
|
+
# - "If the symbols of the scope should be available to all lines in the
|
|
40
|
+
# source_file of the scope, use start_line = 0 and end_line = 2147483647
|
|
41
|
+
# (maximum signed integer, postgres int max)."
|
|
42
|
+
# - "For LOCAL symbols, we use 2147483647 (signed int max) to avoid completing
|
|
43
|
+
# the symbol for line probes, but keep it in the method for method probe completions."
|
|
44
|
+
#
|
|
45
|
+
# Reference: Symbol Database Backend RFC, section "Scope" and "Edge Cases"
|
|
46
|
+
# @see https://www.postgresql.org/docs/current/datatype-numeric.html
|
|
47
|
+
UNKNOWN_MAX_LINE = 2147483647
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -56,7 +56,7 @@ module Datadog
|
|
|
56
56
|
@buffer_spans += trace.length
|
|
57
57
|
rescue => e
|
|
58
58
|
Datadog.logger.debug(
|
|
59
|
-
"Failed to measure queue accept. Cause: #{e.class}: #{e} Source: #{Array(e.backtrace).first}"
|
|
59
|
+
"Failed to measure queue accept. Cause: #{e.class}: #{e.message} Source: #{Array(e.backtrace).first}"
|
|
60
60
|
)
|
|
61
61
|
end
|
|
62
62
|
|
|
@@ -66,7 +66,7 @@ module Datadog
|
|
|
66
66
|
@buffer_spans -= trace.length
|
|
67
67
|
rescue => e
|
|
68
68
|
Datadog.logger.debug(
|
|
69
|
-
"Failed to measure queue drop. Cause: #{e.class}: #{e} Source: #{Array(e.backtrace).first}"
|
|
69
|
+
"Failed to measure queue drop. Cause: #{e.class}: #{e.message} Source: #{Array(e.backtrace).first}"
|
|
70
70
|
)
|
|
71
71
|
end
|
|
72
72
|
|
|
@@ -91,7 +91,7 @@ module Datadog
|
|
|
91
91
|
@buffer_spans = 0
|
|
92
92
|
rescue => e
|
|
93
93
|
Datadog.logger.debug(
|
|
94
|
-
"Failed to measure queue. Cause: #{e.class}: #{e} Source: #{Array(e.backtrace).first}"
|
|
94
|
+
"Failed to measure queue. Cause: #{e.class}: #{e.message} Source: #{Array(e.backtrace).first}"
|
|
95
95
|
)
|
|
96
96
|
end
|
|
97
97
|
end
|