datadog 2.21.0 → 2.23.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/CHANGELOG.md +106 -2
- data/ext/LIBDATADOG_DEVELOPMENT.md +3 -0
- data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -1
- data/ext/datadog_profiling_native_extension/collectors_stack.c +4 -0
- data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +1 -1
- data/ext/datadog_profiling_native_extension/extconf.rb +6 -4
- data/ext/datadog_profiling_native_extension/heap_recorder.c +1 -1
- data/ext/libdatadog_api/datadog_ruby_common.h +1 -1
- data/ext/libdatadog_api/ddsketch.c +106 -0
- data/ext/libdatadog_api/feature_flags.c +554 -0
- data/ext/libdatadog_api/feature_flags.h +5 -0
- data/ext/libdatadog_api/init.c +5 -0
- data/ext/libdatadog_api/library_config.c +34 -25
- data/ext/libdatadog_api/process_discovery.c +19 -13
- data/ext/libdatadog_extconf_helpers.rb +1 -1
- data/lib/datadog/appsec/api_security/endpoint_collection/grape_route_serializer.rb +26 -0
- data/lib/datadog/appsec/api_security/endpoint_collection/rails_collector.rb +59 -0
- data/lib/datadog/appsec/api_security/endpoint_collection/rails_route_serializer.rb +29 -0
- data/lib/datadog/appsec/api_security/endpoint_collection/sinatra_route_serializer.rb +26 -0
- data/lib/datadog/appsec/api_security/endpoint_collection.rb +10 -0
- data/lib/datadog/appsec/api_security/route_extractor.rb +23 -6
- data/lib/datadog/appsec/api_security/sampler.rb +7 -4
- data/lib/datadog/appsec/assets/blocked.html +8 -0
- data/lib/datadog/appsec/assets/blocked.json +1 -1
- data/lib/datadog/appsec/assets/blocked.text +3 -1
- data/lib/datadog/appsec/assets/waf_rules/README.md +30 -36
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +359 -4
- data/lib/datadog/appsec/assets/waf_rules/strict.json +43 -2
- data/lib/datadog/appsec/assets.rb +1 -1
- data/lib/datadog/appsec/compressed_json.rb +1 -1
- data/lib/datadog/appsec/configuration/settings.rb +9 -0
- data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +3 -1
- data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +3 -2
- data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +3 -1
- data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +3 -1
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +9 -4
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +5 -1
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +7 -2
- data/lib/datadog/appsec/contrib/rails/patcher.rb +30 -0
- data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +3 -1
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +10 -4
- data/lib/datadog/appsec/event.rb +12 -14
- data/lib/datadog/appsec/metrics/collector.rb +19 -3
- data/lib/datadog/appsec/metrics/telemetry_exporter.rb +2 -1
- data/lib/datadog/appsec/monitor/gateway/watcher.rb +4 -4
- data/lib/datadog/appsec/remote.rb +29 -13
- data/lib/datadog/appsec/response.rb +18 -4
- data/lib/datadog/appsec/security_engine/result.rb +28 -9
- data/lib/datadog/appsec/security_engine/runner.rb +17 -7
- data/lib/datadog/appsec/security_event.rb +5 -7
- data/lib/datadog/core/configuration/components.rb +44 -9
- data/lib/datadog/core/configuration/config_helper.rb +1 -1
- data/lib/datadog/core/configuration/settings.rb +14 -0
- data/lib/datadog/core/configuration/stable_config.rb +10 -0
- data/lib/datadog/core/configuration/supported_configurations.rb +330 -299
- data/lib/datadog/core/configuration.rb +1 -1
- data/lib/datadog/core/ddsketch.rb +19 -0
- data/lib/datadog/core/environment/ext.rb +6 -0
- data/lib/datadog/core/environment/process.rb +79 -0
- data/lib/datadog/core/environment/yjit.rb +2 -1
- data/lib/datadog/core/feature_flags.rb +61 -0
- data/lib/datadog/core/pin.rb +4 -8
- data/lib/datadog/core/process_discovery.rb +4 -2
- data/lib/datadog/core/remote/client/capabilities.rb +7 -0
- data/lib/datadog/core/remote/component.rb +4 -6
- data/lib/datadog/core/remote/transport/config.rb +2 -10
- data/lib/datadog/core/remote/transport/http/config.rb +9 -9
- data/lib/datadog/core/remote/transport/http/negotiation.rb +17 -8
- data/lib/datadog/core/remote/transport/http.rb +2 -0
- data/lib/datadog/core/remote/transport/negotiation.rb +2 -18
- data/lib/datadog/core/remote/worker.rb +25 -37
- data/lib/datadog/core/tag_builder.rb +0 -4
- data/lib/datadog/core/tag_normalizer.rb +84 -0
- data/lib/datadog/core/telemetry/component.rb +18 -3
- data/lib/datadog/core/telemetry/emitter.rb +6 -6
- data/lib/datadog/core/telemetry/event/app_endpoints_loaded.rb +30 -0
- data/lib/datadog/core/telemetry/event/app_started.rb +52 -49
- data/lib/datadog/core/telemetry/event/synth_app_client_configuration_change.rb +1 -1
- data/lib/datadog/core/telemetry/event.rb +1 -0
- data/lib/datadog/core/telemetry/logger.rb +2 -2
- data/lib/datadog/core/telemetry/logging.rb +2 -8
- data/lib/datadog/core/telemetry/transport/http/telemetry.rb +5 -6
- data/lib/datadog/core/telemetry/transport/telemetry.rb +1 -2
- data/lib/datadog/core/transport/http/client.rb +69 -0
- data/lib/datadog/core/transport/response.rb +4 -1
- data/lib/datadog/core/utils/array.rb +29 -0
- data/lib/datadog/{appsec/api_security → core/utils}/lru_cache.rb +10 -21
- data/lib/datadog/core/utils/network.rb +22 -1
- data/lib/datadog/core/utils/only_once_successful.rb +6 -2
- data/lib/datadog/core/utils.rb +2 -0
- data/lib/datadog/data_streams/configuration/settings.rb +49 -0
- data/lib/datadog/data_streams/configuration.rb +11 -0
- data/lib/datadog/data_streams/ext.rb +11 -0
- data/lib/datadog/data_streams/extensions.rb +16 -0
- data/lib/datadog/data_streams/pathway_context.rb +169 -0
- data/lib/datadog/data_streams/processor.rb +509 -0
- data/lib/datadog/data_streams/transport/http/api.rb +33 -0
- data/lib/datadog/data_streams/transport/http/client.rb +21 -0
- data/lib/datadog/data_streams/transport/http/stats.rb +87 -0
- data/lib/datadog/data_streams/transport/http.rb +41 -0
- data/lib/datadog/data_streams/transport/stats.rb +60 -0
- data/lib/datadog/data_streams.rb +100 -0
- data/lib/datadog/di/boot.rb +1 -0
- data/lib/datadog/di/component.rb +14 -16
- data/lib/datadog/di/context.rb +70 -0
- data/lib/datadog/di/el/compiler.rb +164 -0
- data/lib/datadog/di/el/evaluator.rb +159 -0
- data/lib/datadog/di/el/expression.rb +42 -0
- data/lib/datadog/di/el.rb +5 -0
- data/lib/datadog/di/error.rb +29 -0
- data/lib/datadog/di/instrumenter.rb +163 -48
- data/lib/datadog/di/probe.rb +55 -15
- data/lib/datadog/di/probe_builder.rb +39 -1
- data/lib/datadog/di/probe_manager.rb +13 -4
- data/lib/datadog/di/probe_notification_builder.rb +105 -67
- data/lib/datadog/di/proc_responder.rb +32 -0
- data/lib/datadog/di/serializer.rb +151 -7
- data/lib/datadog/di/transport/diagnostics.rb +2 -2
- data/lib/datadog/di/transport/http/diagnostics.rb +2 -4
- data/lib/datadog/di/transport/http/input.rb +2 -4
- data/lib/datadog/di/transport/http.rb +6 -2
- data/lib/datadog/di/transport/input.rb +64 -4
- data/lib/datadog/open_feature/component.rb +60 -0
- data/lib/datadog/open_feature/configuration.rb +27 -0
- data/lib/datadog/open_feature/evaluation_engine.rb +69 -0
- data/lib/datadog/open_feature/exposures/batch_builder.rb +32 -0
- data/lib/datadog/open_feature/exposures/buffer.rb +43 -0
- data/lib/datadog/open_feature/exposures/deduplicator.rb +30 -0
- data/lib/datadog/open_feature/exposures/event.rb +60 -0
- data/lib/datadog/open_feature/exposures/reporter.rb +40 -0
- data/lib/datadog/open_feature/exposures/worker.rb +116 -0
- data/lib/datadog/open_feature/ext.rb +14 -0
- data/lib/datadog/open_feature/native_evaluator.rb +38 -0
- data/lib/datadog/open_feature/noop_evaluator.rb +26 -0
- data/lib/datadog/open_feature/provider.rb +141 -0
- data/lib/datadog/open_feature/remote.rb +74 -0
- data/lib/datadog/open_feature/resolution_details.rb +35 -0
- data/lib/datadog/open_feature/transport.rb +72 -0
- data/lib/datadog/open_feature.rb +19 -0
- data/lib/datadog/opentelemetry/configuration/settings.rb +159 -0
- data/lib/datadog/opentelemetry/metrics.rb +110 -0
- data/lib/datadog/opentelemetry/sdk/configurator.rb +25 -1
- data/lib/datadog/opentelemetry/sdk/metrics_exporter.rb +38 -0
- data/lib/datadog/opentelemetry.rb +3 -0
- data/lib/datadog/profiling/collectors/code_provenance.rb +15 -6
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +1 -1
- data/lib/datadog/profiling/collectors/idle_sampling_helper.rb +1 -1
- data/lib/datadog/profiling/profiler.rb +4 -0
- data/lib/datadog/profiling/tag_builder.rb +36 -3
- data/lib/datadog/profiling.rb +1 -2
- data/lib/datadog/single_step_instrument.rb +1 -1
- data/lib/datadog/tracing/component.rb +6 -17
- data/lib/datadog/tracing/configuration/dynamic.rb +2 -2
- data/lib/datadog/tracing/configuration/ext.rb +9 -0
- data/lib/datadog/tracing/configuration/settings.rb +77 -3
- data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +4 -4
- data/lib/datadog/tracing/contrib/action_pack/utils.rb +1 -2
- data/lib/datadog/tracing/contrib/active_job/log_injection.rb +21 -7
- data/lib/datadog/tracing/contrib/active_job/patcher.rb +5 -1
- data/lib/datadog/tracing/contrib/aws/instrumentation.rb +4 -2
- data/lib/datadog/tracing/contrib/component.rb +2 -2
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -1
- data/lib/datadog/tracing/contrib/excon/configuration/settings.rb +11 -3
- data/lib/datadog/tracing/contrib/faraday/configuration/settings.rb +11 -7
- data/lib/datadog/tracing/contrib/grape/configuration/settings.rb +7 -3
- data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +7 -0
- data/lib/datadog/tracing/contrib/graphql/ext.rb +1 -0
- data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +74 -44
- data/lib/datadog/tracing/contrib/http/configuration/settings.rb +11 -3
- data/lib/datadog/tracing/contrib/httpclient/configuration/settings.rb +11 -3
- data/lib/datadog/tracing/contrib/httprb/configuration/settings.rb +11 -3
- data/lib/datadog/tracing/contrib/kafka/instrumentation/consumer.rb +66 -0
- data/lib/datadog/tracing/contrib/kafka/instrumentation/producer.rb +66 -0
- data/lib/datadog/tracing/contrib/kafka/patcher.rb +14 -0
- data/lib/datadog/tracing/contrib/karafka/framework.rb +30 -0
- data/lib/datadog/tracing/contrib/karafka/monitor.rb +11 -0
- data/lib/datadog/tracing/contrib/karafka/patcher.rb +32 -0
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +59 -27
- data/lib/datadog/tracing/contrib/rack/route_inference.rb +53 -0
- data/lib/datadog/tracing/contrib/rails/middlewares.rb +2 -2
- data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +4 -1
- data/lib/datadog/tracing/contrib/roda/instrumentation.rb +3 -1
- data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +3 -1
- data/lib/datadog/tracing/contrib/status_range_matcher.rb +7 -0
- data/lib/datadog/tracing/contrib/waterdrop/configuration/settings.rb +27 -0
- data/lib/datadog/tracing/contrib/waterdrop/distributed/propagation.rb +48 -0
- data/lib/datadog/tracing/contrib/waterdrop/ext.rb +17 -0
- data/lib/datadog/tracing/contrib/waterdrop/integration.rb +43 -0
- data/lib/datadog/tracing/contrib/waterdrop/middleware.rb +46 -0
- data/lib/datadog/tracing/contrib/waterdrop/patcher.rb +46 -0
- data/lib/datadog/tracing/contrib/waterdrop/producer.rb +50 -0
- data/lib/datadog/tracing/contrib/waterdrop.rb +37 -0
- data/lib/datadog/tracing/contrib.rb +1 -0
- data/lib/datadog/tracing/metadata/ext.rb +9 -1
- data/lib/datadog/tracing/transport/http/client.rb +12 -26
- data/lib/datadog/tracing/transport/trace_formatter.rb +11 -0
- data/lib/datadog/tracing/transport/traces.rb +3 -5
- data/lib/datadog/version.rb +2 -2
- data/lib/datadog.rb +2 -0
- metadata +92 -16
- data/ext/libdatadog_api/macos_development.md +0 -26
- data/lib/datadog/core/remote/transport/http/client.rb +0 -49
- data/lib/datadog/core/telemetry/transport/http/client.rb +0 -49
- data/lib/datadog/di/transport/http/client.rb +0 -47
|
@@ -29,7 +29,11 @@ module Datadog
|
|
|
29
29
|
# In https://github.com/DataDog/dd-trace-rb/pull/1398#issuecomment-797378810 we have a discussion of alternatives,
|
|
30
30
|
# including an alternative implementation that is Ractor-safe once spent.
|
|
31
31
|
class OnlyOnceSuccessful < OnlyOnce
|
|
32
|
-
def initialize(limit =
|
|
32
|
+
def initialize(limit = nil)
|
|
33
|
+
if limit && limit <= 0
|
|
34
|
+
raise ArgumentError, "Limit must be a positive integer if provided: #{limit}"
|
|
35
|
+
end
|
|
36
|
+
|
|
33
37
|
super()
|
|
34
38
|
|
|
35
39
|
@limit = limit
|
|
@@ -71,7 +75,7 @@ module Datadog
|
|
|
71
75
|
end
|
|
72
76
|
|
|
73
77
|
def limited?
|
|
74
|
-
!@limit.nil?
|
|
78
|
+
!@limit.nil?
|
|
75
79
|
end
|
|
76
80
|
|
|
77
81
|
def reset_ran_once_state_for_tests
|
data/lib/datadog/core/utils.rb
CHANGED
|
@@ -38,6 +38,8 @@ module Datadog
|
|
|
38
38
|
|
|
39
39
|
# Ensure `str` is a valid UTF-8, ready to be
|
|
40
40
|
# sent through the tracer transport.
|
|
41
|
+
# DEV-3.0: This method should unconditionally handle invalid byte sequences
|
|
42
|
+
# DEV-3.0: and return a safe string to display.
|
|
41
43
|
#
|
|
42
44
|
# @param [String,#to_s] str object to be converted to a UTF-8 string
|
|
43
45
|
# @param [Boolean] binary whether to expect binary data in the `str` parameter
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../core/environment/variable_helpers'
|
|
4
|
+
require_relative '../ext'
|
|
5
|
+
|
|
6
|
+
module Datadog
|
|
7
|
+
module DataStreams
|
|
8
|
+
module Configuration
|
|
9
|
+
# Configuration settings for Data Streams Monitoring.
|
|
10
|
+
module Settings
|
|
11
|
+
def self.extended(base)
|
|
12
|
+
base = base.singleton_class unless base.is_a?(Class)
|
|
13
|
+
add_settings!(base)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.add_settings!(base)
|
|
17
|
+
base.class_eval do
|
|
18
|
+
# Data Streams Monitoring configuration
|
|
19
|
+
# @public_api
|
|
20
|
+
settings :data_streams do
|
|
21
|
+
# Whether Data Streams Monitoring is enabled. When enabled, the library will
|
|
22
|
+
# collect and report data lineage information for messaging systems.
|
|
23
|
+
#
|
|
24
|
+
# @default `DD_DATA_STREAMS_ENABLED` environment variable, otherwise `false`.
|
|
25
|
+
# @return [Boolean]
|
|
26
|
+
option :enabled do |o|
|
|
27
|
+
o.type :bool
|
|
28
|
+
o.env Ext::ENV_ENABLED
|
|
29
|
+
o.default false
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# The interval (in seconds) at which Data Streams Monitoring stats are flushed.
|
|
33
|
+
#
|
|
34
|
+
# @default 10.0
|
|
35
|
+
# @env '_DD_TRACE_STATS_WRITER_INTERVAL'
|
|
36
|
+
# @return [Float]
|
|
37
|
+
# @!visibility private
|
|
38
|
+
option :interval do |o|
|
|
39
|
+
o.type :float
|
|
40
|
+
o.env '_DD_TRACE_STATS_WRITER_INTERVAL'
|
|
41
|
+
o.default 10.0
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'configuration'
|
|
4
|
+
require_relative '../core/configuration'
|
|
5
|
+
|
|
6
|
+
module Datadog
|
|
7
|
+
module DataStreams
|
|
8
|
+
# Extends Datadog with Data Streams Monitoring features
|
|
9
|
+
module Extensions
|
|
10
|
+
# Inject Data Streams settings into global configuration.
|
|
11
|
+
def self.activate!
|
|
12
|
+
Core::Configuration::Settings.extend(Configuration::Settings)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'stringio'
|
|
4
|
+
require_relative '../core/utils/base64'
|
|
5
|
+
|
|
6
|
+
module Datadog
|
|
7
|
+
module DataStreams
|
|
8
|
+
# Represents a pathway context for data streams monitoring
|
|
9
|
+
class PathwayContext
|
|
10
|
+
# The current pathway hash value (result of FNV-1a hash function)
|
|
11
|
+
attr_accessor :hash
|
|
12
|
+
# When the pathway started
|
|
13
|
+
attr_accessor :pathway_start
|
|
14
|
+
# When the current edge started
|
|
15
|
+
attr_accessor :current_edge_start
|
|
16
|
+
# The hash value of the parent checkpoint
|
|
17
|
+
attr_accessor :parent_hash
|
|
18
|
+
# The direction tag of the previous checkpoint (e.g., 'direction:in', 'direction:out'), or nil if none
|
|
19
|
+
attr_accessor :previous_direction
|
|
20
|
+
# Hash value of the closest checkpoint in opposite direction (used for loop detection)
|
|
21
|
+
attr_accessor :closest_opposite_direction_hash
|
|
22
|
+
# Edge start time of the closest opposite direction checkpoint
|
|
23
|
+
attr_accessor :closest_opposite_direction_edge_start
|
|
24
|
+
|
|
25
|
+
def initialize(hash_value:, pathway_start:, current_edge_start:)
|
|
26
|
+
@hash = hash_value
|
|
27
|
+
@pathway_start = pathway_start
|
|
28
|
+
@current_edge_start = current_edge_start
|
|
29
|
+
@parent_hash = nil
|
|
30
|
+
|
|
31
|
+
@previous_direction = nil
|
|
32
|
+
@closest_opposite_direction_hash = 0
|
|
33
|
+
@closest_opposite_direction_edge_start = current_edge_start
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def encode_b64
|
|
37
|
+
Core::Utils::Base64.strict_encode64(encode)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Decode pathway context from base64 encoded string
|
|
41
|
+
def self.decode_b64(encoded_ctx)
|
|
42
|
+
return nil unless encoded_ctx && !encoded_ctx.empty?
|
|
43
|
+
|
|
44
|
+
begin
|
|
45
|
+
binary_data = Core::Utils::Base64.strict_decode64(encoded_ctx)
|
|
46
|
+
decode(binary_data)
|
|
47
|
+
rescue ArgumentError => e
|
|
48
|
+
# Invalid base64 encoding - may indicate version mismatch or corruption
|
|
49
|
+
Datadog.logger.debug("Failed to decode DSM pathway context: #{e.message}")
|
|
50
|
+
nil
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def encode
|
|
57
|
+
# Format:
|
|
58
|
+
# - 8 bytes: hash value (little-endian)
|
|
59
|
+
# - VarInt: pathway start time (milliseconds)
|
|
60
|
+
# - VarInt: current edge start time (milliseconds)
|
|
61
|
+
[@hash].pack('Q') <<
|
|
62
|
+
encode_var_int_64(time_to_ms(@pathway_start)) <<
|
|
63
|
+
encode_var_int_64(time_to_ms(@current_edge_start))
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Decode pathway context from binary data
|
|
67
|
+
def self.decode(binary_data)
|
|
68
|
+
return nil unless binary_data && binary_data.bytesize >= 8
|
|
69
|
+
|
|
70
|
+
reader = StringIO.new(binary_data)
|
|
71
|
+
|
|
72
|
+
# Extract 8-byte hash (little-endian)
|
|
73
|
+
hash_bytes = reader.read(8)
|
|
74
|
+
return nil unless hash_bytes
|
|
75
|
+
|
|
76
|
+
hash_value = hash_bytes.unpack1('Q') # : Integer
|
|
77
|
+
|
|
78
|
+
# Extract pathway start time (VarInt milliseconds)
|
|
79
|
+
pathway_start_ms = decode_varint(reader)
|
|
80
|
+
return nil unless pathway_start_ms
|
|
81
|
+
|
|
82
|
+
# Extract current edge start time (VarInt milliseconds)
|
|
83
|
+
current_edge_start_ms = decode_varint(reader)
|
|
84
|
+
return nil unless current_edge_start_ms
|
|
85
|
+
|
|
86
|
+
# Convert milliseconds to Time objects
|
|
87
|
+
pathway_start = ms_to_time(pathway_start_ms)
|
|
88
|
+
current_edge_start = ms_to_time(current_edge_start_ms)
|
|
89
|
+
|
|
90
|
+
new(
|
|
91
|
+
hash_value: hash_value,
|
|
92
|
+
pathway_start: pathway_start,
|
|
93
|
+
current_edge_start: current_edge_start
|
|
94
|
+
)
|
|
95
|
+
rescue EOFError
|
|
96
|
+
# Not enough data in binary stream
|
|
97
|
+
nil
|
|
98
|
+
end
|
|
99
|
+
private_class_method :decode
|
|
100
|
+
|
|
101
|
+
# Encode an unsigned 64-bit integer using LEB128 variable-length encoding.
|
|
102
|
+
#
|
|
103
|
+
# This implements unsigned LEB128 (Little Endian Base 128) encoding as specified
|
|
104
|
+
# in DWARF5 standard section 7.6:
|
|
105
|
+
# https://dwarfstd.org/doc/DWARF5.pdf#page=301
|
|
106
|
+
#
|
|
107
|
+
# Each byte uses 7 bits for data and 1 bit to indicate continuation.
|
|
108
|
+
# The high bit is set if more bytes follow, clear for the final byte.
|
|
109
|
+
#
|
|
110
|
+
# @param value [Integer] Unsigned integer value to encode
|
|
111
|
+
# @return [String] Binary string of encoded bytes
|
|
112
|
+
def encode_var_int_64(value)
|
|
113
|
+
bytes = []
|
|
114
|
+
while value >= 0x80
|
|
115
|
+
bytes << ((value & 0x7F) | 0x80)
|
|
116
|
+
value >>= 7
|
|
117
|
+
end
|
|
118
|
+
bytes << value
|
|
119
|
+
bytes.pack('C*')
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Decode an unsigned LEB128 variable-length integer from IO stream.
|
|
123
|
+
#
|
|
124
|
+
# This implements unsigned LEB128 (Little Endian Base 128) decoding as specified
|
|
125
|
+
# in DWARF5 standard section 7.6:
|
|
126
|
+
# https://dwarfstd.org/doc/DWARF5.pdf#page=301
|
|
127
|
+
#
|
|
128
|
+
# VarInt format: Each byte uses 7 bits for data, 1 bit for continuation
|
|
129
|
+
# - High bit set = more bytes follow
|
|
130
|
+
# - High bit clear = final byte
|
|
131
|
+
# - Data bits accumulated in little-endian order
|
|
132
|
+
#
|
|
133
|
+
# @param io [StringIO] IO stream to read from
|
|
134
|
+
# @return [Integer, nil] Decoded unsigned integer, or nil if malformed
|
|
135
|
+
def self.decode_varint(io)
|
|
136
|
+
value = 0
|
|
137
|
+
shift = 0
|
|
138
|
+
|
|
139
|
+
loop do
|
|
140
|
+
byte = io.readbyte
|
|
141
|
+
|
|
142
|
+
# Add this byte's 7 data bits to our value
|
|
143
|
+
value |= (byte & 0x7F) << shift
|
|
144
|
+
|
|
145
|
+
# If high bit is clear, we're done
|
|
146
|
+
return value unless (byte & 0x80).nonzero?
|
|
147
|
+
|
|
148
|
+
shift += 7
|
|
149
|
+
|
|
150
|
+
# Safety: prevent infinite decoding
|
|
151
|
+
return nil if shift >= 64
|
|
152
|
+
end
|
|
153
|
+
rescue EOFError
|
|
154
|
+
# Stream ended unexpectedly - malformed data
|
|
155
|
+
nil
|
|
156
|
+
end
|
|
157
|
+
private_class_method :decode_varint
|
|
158
|
+
|
|
159
|
+
def self.ms_to_time(milliseconds)
|
|
160
|
+
::Time.at(milliseconds / 1000.0)
|
|
161
|
+
end
|
|
162
|
+
private_class_method :ms_to_time
|
|
163
|
+
|
|
164
|
+
def time_to_ms(time)
|
|
165
|
+
(time.to_f * 1000).to_i
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|