datadog-lambda 0.5.0 → 1.10.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8037783498999fb1a3291a4b6c72d13933efc9c4056b08f96e560debf804797d
4
- data.tar.gz: 8f1f8794b9fd7a7886715afe3d41e9398e0d110ace2279c5bec2e2a34d2d60d7
3
+ metadata.gz: c19e8514981117ae88bdaa4d17f7a3a5db19595d39336100ac581e0cf330be1d
4
+ data.tar.gz: 5d2c0ef21fb1fb0d33759f0b3430daebe88100e4f626b20f6dd9512739c6b62c
5
5
  SHA512:
6
- metadata.gz: 98545e61a901be1b3441ba52d197ea69dfe6eee9469d571b2a77e979d4f73c56e133cc0d9502c003342a5a78ee50fea4ca4fb0af6ad7bd3a47d9bd8d5aede373
7
- data.tar.gz: d27d0e7a1a9774347fa5865ce508b09f91137b56e400614ad15c06ba3492a977e1734b2015d380f1d14c36b896ace3bfc64e4e4839b2533280c8d411c30503c7
6
+ metadata.gz: 6cab42dc833290ea7742def1dda6e4bb4a89ebb7f90240e053cdbcd8f8a338fbaaa98069dc48fdc6d823fb087a90c946c097bd012014e31b84629995f296fe0a
7
+ data.tar.gz: 4092f19c6b544307e2a82492fd13ce2241d2e0820df2b81da53a6adbd4ec3da0aa9b6d04a56c528b822f93df36e8122985d1a5c0584773d867c3f787feb46eba
@@ -7,6 +7,7 @@
7
7
  # This product includes software developed at Datadog (https://www.datadoghq.com/).
8
8
  # Copyright 2019 Datadog, Inc.
9
9
  #
10
+ # rubocop:disable Metrics/ModuleLength
10
11
 
11
12
  require 'datadog/lambda/trace/listener'
12
13
  require 'datadog/lambda/utils/logger'
@@ -19,17 +20,42 @@ module Datadog
19
20
  # custom metrics
20
21
  module Lambda
21
22
  @is_cold_start = true
23
+ @patch_http = true
24
+
25
+ # Configures Datadog's APM tracer with lambda specific defaults.
26
+ # Same options can be given as Datadog.configure in tracer
27
+ # See https://github.com/DataDog/dd-trace-rb/blob/master/docs/GettingStarted.md#quickstart-for-ruby-applications
28
+ def self.configure_apm
29
+ require 'ddtrace'
30
+ require 'ddtrace/sync_writer'
31
+
32
+ @patch_http = false
33
+ # Needed to keep trace flushes on a single line
34
+ $stdout.sync = true
35
+
36
+ Datadog.configure do |c|
37
+ c.tracer writer: Datadog::SyncWriter.new(
38
+ transport: Datadog::Transport::IO.default
39
+ )
40
+ c.tags = { "_dd.origin": 'lambda' }
41
+ yield(c) if block_given?
42
+ end
43
+ end
44
+
22
45
  # Wrap the body of a lambda invocation
23
46
  # @param event [Object] event sent to lambda
24
47
  # @param context [Object] lambda context
25
48
  # @param block [Proc] implementation of the handler function.
26
49
  def self.wrap(event, context, &block)
27
50
  Datadog::Utils.update_log_level
28
- @listener ||= Trace::Listener.new
51
+ @listener ||= initialize_listener
29
52
  @listener.on_start(event: event)
30
53
  record_enhanced('invocations', context)
31
54
  begin
32
- res = block.call
55
+ cold = @is_cold_start
56
+ res = @listener.on_wrap(request_context: context, cold_start: cold) do
57
+ block.call
58
+ end
33
59
  rescue StandardError => e
34
60
  record_enhanced('errors', context)
35
61
  raise e
@@ -42,7 +68,8 @@ module Datadog
42
68
 
43
69
  # Gets the current tracing context
44
70
  def self.trace_context
45
- Datadog::Trace.trace_context
71
+ context = Hash[Datadog::Trace.trace_context]
72
+ context
46
73
  end
47
74
 
48
75
  # Send a custom distribution metric
@@ -55,34 +82,59 @@ module Datadog
55
82
  raise 'value must be a number' unless value.is_a?(Numeric)
56
83
 
57
84
  time ||= Time.now
58
- tag_list = ['dd_lambda_layer:datadog-ruby25']
85
+ time_ms = time.to_f.to_i
86
+
87
+ tag_list = ["dd_lambda_layer:datadog-ruby#{dd_lambda_layer_tag}"]
59
88
  tags.each do |tag|
60
89
  tag_list.push("#{tag[0]}:#{tag[1]}")
61
90
  end
62
- time_ms = time.to_f.to_i
63
- metric = { e: time_ms, m: name, t: tag_list, v: value }.to_json
64
- puts metric
91
+ metric = { e: time_ms, m: name, t: tag_list, v: value }
92
+ puts metric.to_json
93
+ end
94
+
95
+ def self.dd_lambda_layer_tag
96
+ RUBY_VERSION[0, 3].tr('.', '')
65
97
  end
66
98
 
67
99
  # Generate tags for enhanced metrics
68
100
  # @param context [Object] https://docs.aws.amazon.com/lambda/latest/dg/ruby-context.html
69
101
  # @return [hash] a hash of the enhanced metrics tags
102
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
70
103
  def self.gen_enhanced_tags(context)
71
104
  arn_parts = context.invoked_function_arn.split(':')
72
- {
105
+ # Check if we have an alias or version
106
+ function_alias = arn_parts[7].nil? ? nil : arn_parts[7]
107
+
108
+ tags = {
73
109
  functionname: context.function_name,
74
110
  region: arn_parts[3],
75
111
  account_id: arn_parts[4],
76
112
  memorysize: context.memory_limit_in_mb,
77
113
  cold_start: @is_cold_start,
78
- runtime: "Ruby #{RUBY_VERSION}"
114
+ runtime: "Ruby #{RUBY_VERSION}",
115
+ resource: context.function_name
79
116
  }
117
+ # If we have an alias...
118
+ unless function_alias.nil?
119
+ # If the alis version is $Latest, drop the $ for ddog tag convention.
120
+ if function_alias.start_with?('$')
121
+ function_alias[0] = ''
122
+ # If the alias is not a version number add the executed version tag
123
+ elsif !/\A\d+\z/.match(function_alias)
124
+ tags[:executedversion] = context.function_version
125
+ end
126
+ # Append the alias to the resource tag
127
+ tags[:resource] = context.function_name + ':' + function_alias
128
+ end
129
+
130
+ tags
80
131
  rescue StandardError => e
81
132
  Datadog::Utils.logger.error 'Unable to parse Lambda context' \
82
133
  "#{context}: #{e}"
83
134
  {}
84
135
  end
85
136
 
137
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
86
138
  # Format and add tags to enhanced metrics
87
139
  # This method wraps the metric method, checking the DD_ENHANCED_METRICS
88
140
  # environment variable, adding 'aws.lambda.enhanced' to the metric name,
@@ -90,13 +142,13 @@ module Datadog
90
142
  # @param metric_name [String] basic name of the metric
91
143
  # @param context [Object] AWS Ruby Lambda Context
92
144
  # @return [boolean] false if the metric was not added for some reason,
93
- # true otherwise (for ease of testing)
145
+ # true otherwise (for ease of testing
94
146
 
95
147
  def self.record_enhanced(metric_name, context)
96
148
  return false unless do_enhanced_metrics?
97
149
 
98
150
  etags = gen_enhanced_tags(context)
99
- metric("aws.lambda.enhanced.#{metric_name}", 1, etags)
151
+ metric("aws.lambda.enhanced.#{metric_name}", 1, **etags)
100
152
  true
101
153
  end
102
154
 
@@ -105,9 +157,26 @@ module Datadog
105
157
  # enhanced metrics
106
158
  def self.do_enhanced_metrics?
107
159
  dd_enhanced_metrics = ENV['DD_ENHANCED_METRICS']
108
- return false if dd_enhanced_metrics.nil?
160
+ return true if dd_enhanced_metrics.nil?
109
161
 
110
162
  dd_enhanced_metrics.downcase == 'true'
111
163
  end
164
+
165
+ def self.initialize_listener
166
+ handler = ENV['_HANDLER'].nil? ? 'handler' : ENV['_HANDLER']
167
+ function = ENV['AWS_LAMBDA_FUNCTION_NAME']
168
+ merge_xray_traces = false
169
+ merge_xray_traces_env = ENV['DD_MERGE_DATADOG_XRAY_TRACES']
170
+ unless merge_xray_traces_env.nil?
171
+ merge_xray_traces = merge_xray_traces_env.downcase == 'true'
172
+ Datadog::Utils.logger.debug("Setting merge traces #{merge_xray_traces}")
173
+ end
174
+
175
+ Trace::Listener.new(handler_name: handler,
176
+ function_name: function,
177
+ patch_http: @patch_http,
178
+ merge_xray_traces: merge_xray_traces)
179
+ end
112
180
  end
113
181
  end
182
+ # rubocop:enable Metrics/ModuleLength
@@ -20,5 +20,11 @@ module Datadog
20
20
  DD_XRAY_SUBSEGMENT_NAME = 'datadog-metadata'
21
21
  DD_XRAY_SUBSEGMENT_KEY = 'trace'
22
22
  DD_XRAY_SUBSEGMENT_NAMESPACE = 'datadog'
23
+ SOURCE_XRAY = 'XRAY'
24
+ SOURCE_EVENT = 'EVENT'
25
+ XRAY_ENV_VAR = '_X_AMZN_TRACE_ID'
26
+ XRAY_UDP_PORT = 2000
27
+ LOCAL_HOST = '127.0.0.1'
28
+ AWS_XRAY_DAEMON_ADDRESS_ENV_VAR = 'AWS_XRAY_DAEMON_ADDRESS'
23
29
  end
24
30
  end
@@ -8,8 +8,8 @@
8
8
  # Copyright 2019 Datadog, Inc.
9
9
  #
10
10
 
11
- require 'aws-xray-sdk'
12
11
  require 'datadog/lambda/trace/constants'
12
+ require 'datadog/lambda/trace/xray'
13
13
  require 'datadog/lambda/utils/logger'
14
14
 
15
15
  module Datadog
@@ -17,56 +17,19 @@ module Datadog
17
17
  # lambda events/X-Ray
18
18
  module Trace
19
19
  class << self
20
- def extract_trace_context(event)
20
+ def extract_trace_context(event, merge_xray_traces)
21
21
  context = read_trace_context_from_event(event)
22
22
  unless context.nil?
23
23
  begin
24
24
  add_trace_context_to_xray(context)
25
25
  rescue StandardError => e
26
- Datadog::Utils.logger.error("couldn't add metadata to xray #{e}")
26
+ Datadog::Utils.logger.debug("couldn't add metadata to xray #{e}")
27
27
  end
28
28
  return context
29
29
  end
30
- read_trace_context_from_xray
31
- end
32
-
33
- def add_trace_context_to_xray(context)
34
- seg = XRay.recorder.begin_subsegment(
35
- DD_XRAY_SUBSEGMENT_NAME,
36
- namespace: DD_XRAY_SUBSEGMENT_NAMESPACE
37
- )
38
- data = {
39
- "parent-id": context[:parent_id],
40
- "sampling-priority": context[:sample_mode].to_s,
41
- "trace-id": context[:trace_id]
42
- }
43
- seg.metadata(namespace: DD_XRAY_SUBSEGMENT_NAMESPACE)
44
- .update("#{DD_XRAY_SUBSEGMENT_KEY}": data)
45
- XRay.recorder.end_subsegment
46
- end
30
+ return nil unless merge_xray_traces
47
31
 
48
- def current_trace_context(trace_context)
49
- entity = XRay.recorder.current_entity
50
- parent_id = entity.id
51
- {
52
- trace_id: trace_context[:trace_id],
53
- parent_id: convert_to_apm_parent_id(parent_id),
54
- sample_mode: trace_context[:sample_mode]
55
- }
56
- end
57
-
58
- def read_trace_context_from_xray
59
- segment = XRay.recorder.current_entity
60
- parent_id = segment.id
61
- mode = segment.sampled ? SAMPLE_MODE_USER_KEEP : SAMPLE_MODE_USER_REJECT
62
- {
63
- trace_id: convert_to_apm_trace_id(segment.trace_id),
64
- parent_id: convert_to_apm_parent_id(parent_id),
65
- sample_mode: mode
66
- }
67
- rescue StandardError => e
68
- Datadog::Utils.logger.error("couldn't read xray trace header #{e}")
69
- nil
32
+ read_trace_context_from_xray
70
33
  end
71
34
 
72
35
  def read_trace_context_from_event(event)
@@ -79,7 +42,8 @@ module Datadog
79
42
  {
80
43
  trace_id: headers[DD_TRACE_ID_HEADER],
81
44
  parent_id: headers[DD_PARENT_ID_HEADER],
82
- sample_mode: headers[DD_SAMPLING_PRIORITY_HEADER].to_i
45
+ sample_mode: headers[DD_SAMPLING_PRIORITY_HEADER].to_i,
46
+ source: SOURCE_EVENT
83
47
  }
84
48
  end
85
49
 
@@ -99,32 +63,6 @@ module Datadog
99
63
  end
100
64
  true
101
65
  end
102
-
103
- def convert_to_apm_trace_id(xray_trace_id)
104
- parts = xray_trace_id.split('-')
105
- return nil if parts.length < 3
106
-
107
- last_part = parts[2]
108
- return nil if last_part.length != 24
109
- # Make sure every character is hex
110
- return nil if last_part.upcase[/\H/]
111
-
112
- hex = last_part.to_i(16)
113
- last_63_bits = hex & 0x7fffffffffffffff
114
- last_63_bits.to_s(10)
115
- end
116
-
117
- def convert_to_apm_parent_id(xray_parent_id)
118
- return nil if xray_parent_id.length != 16
119
- return nil if xray_parent_id.upcase[/\H/]
120
-
121
- hex = xray_parent_id.to_i(16)
122
- hex.to_s(10)
123
- end
124
-
125
- def convert_to_sample_mode(xray_sampled)
126
- xray_sampled == '1' ? SAMPLE_MODE_USER_KEEP : SAMPLE_MODE_USER_REJECT
127
- end
128
66
  end
129
67
  end
130
68
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ # ddtrace is an optional dependency for the ruby package
4
+ begin
5
+ require 'ddtrace'
6
+ rescue LoadError
7
+ Datadog::Utils.logger.debug 'dd-trace unavailable'
8
+ end
9
+
10
+ module Datadog
11
+ # TraceListener tracks tracing context information
12
+ module Trace
13
+ class <<self
14
+ def apply_datadog_trace_context(context)
15
+ unless context.nil?
16
+ trace_id = context[:trace_id].to_i
17
+ span_id = context[:parent_id].to_i
18
+ sampling_priority = context[:sample_mode]
19
+ Datadog.tracer.provider.context = Datadog::Context.new(
20
+ trace_id: trace_id,
21
+ span_id: span_id,
22
+ sampling_priority: sampling_priority
23
+ )
24
+ end
25
+ rescue StandardError
26
+ Datadog::Utils.logger.debug 'dd-trace unavailable'
27
+ end
28
+
29
+ def wrap_datadog(options, &block)
30
+ tracer_available = false
31
+ begin
32
+ Datadog.tracer
33
+ tracer_available = true
34
+ rescue StandardError
35
+ Datadog::Utils.logger.debug 'dd-trace unavailable'
36
+ end
37
+ return block.call unless tracer_available
38
+
39
+ Datadog.tracer.trace('aws.lambda', options) do |_span|
40
+ block.call
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -9,27 +9,25 @@
9
9
  #
10
10
 
11
11
  require 'datadog/lambda/trace/context'
12
- require 'datadog/lambda/trace/xray_lambda'
13
12
  require 'datadog/lambda/trace/patch_http'
14
-
15
- require 'aws-xray-sdk'
13
+ require 'datadog/lambda/trace/ddtrace'
16
14
 
17
15
  module Datadog
18
16
  module Trace
19
17
  # TraceListener tracks tracing context information
20
18
  class Listener
21
- def initialize
22
- XRay.recorder.configure(
23
- patch: %I[aws_sdk],
24
- context: Datadog::Trace::LambdaContext.new,
25
- streamer: Datadog::Trace::LambdaStreamer.new,
26
- emitter: Datadog::Trace::LambdaEmitter.new
27
- )
28
- Datadog::Trace.patch_http
19
+ def initialize(handler_name:, function_name:, patch_http:,
20
+ merge_xray_traces:)
21
+ @handler_name = handler_name
22
+ @function_name = function_name
23
+ @merge_xray_traces = merge_xray_traces
24
+
25
+ Datadog::Trace.patch_http if patch_http
29
26
  end
30
27
 
31
28
  def on_start(event:)
32
- trace_context = Datadog::Trace.extract_trace_context(event)
29
+ trace_context = Datadog::Trace.extract_trace_context(event,
30
+ @merge_xray_traces)
33
31
  Datadog::Trace.trace_context = trace_context
34
32
  Datadog::Utils.logger.debug "extracted trace context #{trace_context}"
35
33
  rescue StandardError => e
@@ -37,6 +35,42 @@ module Datadog
37
35
  end
38
36
 
39
37
  def on_end; end
38
+
39
+ def on_wrap(request_context:, cold_start:, &block)
40
+ options = get_option_tags(
41
+ request_context: request_context,
42
+ cold_start: cold_start
43
+ )
44
+ context = Datadog::Trace.trace_context
45
+ source = context[:source] if context
46
+ options[:tags]['_dd.parent_source'] = source if source && source != 'ddtrace'
47
+ options[:resource] = @function_name
48
+ options[:service] = 'aws.lambda'
49
+ options[:span_type] = 'serverless'
50
+ Datadog::Trace.apply_datadog_trace_context(Datadog::Trace.trace_context)
51
+ Datadog::Trace.wrap_datadog(options) do
52
+ block.call
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def get_option_tags(request_context:, cold_start:)
59
+ function_arn = request_context.invoked_function_arn.downcase
60
+ tk = function_arn.split(':')
61
+ function_arn = tk.length > 7 ? tk[0, 7].join(':') : function_arn
62
+ function_version = tk.length > 7 ? tk[7] : '$LATEST'
63
+ options = {
64
+ tags: {
65
+ cold_start: cold_start,
66
+ function_arn: function_arn,
67
+ function_version: function_version,
68
+ request_id: request_context.aws_request_id,
69
+ resource_names: request_context.function_name
70
+ }
71
+ }
72
+ options
73
+ end
40
74
  end
41
75
  end
42
76
  end
@@ -36,11 +36,7 @@ module Datadog
36
36
  Datadog::Trace.trace_context
37
37
  )
38
38
 
39
- req[Datadog::Trace::DD_SAMPLING_PRIORITY_HEADER.to_sym] =
40
- context[:sample_mode]
41
- req[Datadog::Trace::DD_PARENT_ID_HEADER.to_sym] = context[:parent_id]
42
- req[Datadog::Trace::DD_TRACE_ID_HEADER.to_sym] = context[:trace_id]
43
- logger.debug("added context #{context} to request")
39
+ req = add_ctx_to_req(req, context)
44
40
  rescue StandardError => e
45
41
  trace = e.backtrace.join("\n ")
46
42
  logger.debug(
@@ -49,6 +45,17 @@ module Datadog
49
45
  end
50
46
  super(req, body, &block)
51
47
  end
48
+
49
+ private
50
+
51
+ def add_ctx_to_req(req, context)
52
+ req[Datadog::Trace::DD_SAMPLING_PRIORITY_HEADER.to_sym] =
53
+ context[:sample_mode]
54
+ req[Datadog::Trace::DD_PARENT_ID_HEADER.to_sym] = context[:parent_id]
55
+ req[Datadog::Trace::DD_TRACE_ID_HEADER.to_sym] = context[:trace_id]
56
+ logger.debug("added context #{context} to request")
57
+ req
58
+ end
52
59
  end
53
60
  end
54
61
  end
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Unless explicitly stated otherwise all files in this repository are licensed
5
+ # under the Apache License Version 2.0.
6
+ #
7
+ # This product includes software developed at Datadog (https://www.datadoghq.com/).
8
+ # Copyright 2019 Datadog, Inc.
9
+ #
10
+ require 'datadog/lambda/trace/constants'
11
+ require 'datadog/lambda/utils/logger'
12
+ require 'securerandom'
13
+ require 'json'
14
+ require 'socket'
15
+
16
+ module Datadog
17
+ # Trace contains utilities related to reading/writing trace context from
18
+ # lambda events/X-Ray
19
+ module Trace
20
+ class << self
21
+ def read_trace_context_from_xray
22
+ header = ENV[XRAY_ENV_VAR]
23
+ segment = parse_xray_trace_context_header(header)
24
+ trace_id = convert_to_apm_trace_id(segment[:xray_trace_id])
25
+ parent_id = convert_to_apm_parent_id(segment[:xray_parent_id])
26
+ sample_mode = convert_to_sample_mode(segment[:xray_sample_mode])
27
+
28
+ if trace_id.nil? || parent_id.nil? || sample_mode.nil?
29
+ Datadog::Utils.logger.error("couldn't read xray header #{header}")
30
+ return nil
31
+ end
32
+ {
33
+ trace_id: trace_id,
34
+ parent_id: parent_id,
35
+ sample_mode: sample_mode,
36
+ source: SOURCE_XRAY
37
+ }
38
+ end
39
+
40
+ def add_trace_context_to_xray(context)
41
+ data = generate_xray_metadata_subsegment(context)
42
+ send_xray_daemon_data(data)
43
+ Datadog::Utils.logger.debug("sent metadata to xray #{data}")
44
+ end
45
+
46
+ def generate_xray_metadata_subsegment(context)
47
+ header = ENV[XRAY_ENV_VAR]
48
+ segment = parse_xray_trace_context_header(header)
49
+
50
+ {
51
+ "id": SecureRandom.hex(8),
52
+ "trace_id": segment[:xray_trace_id],
53
+ "parent_id": segment[:xray_parent_id],
54
+ "name": DD_XRAY_SUBSEGMENT_NAME,
55
+ "start_time": Time.now.to_f,
56
+ "end_time": Time.now.to_f,
57
+ "type": 'subsegment',
58
+ "metadata": {
59
+ "datadog": {
60
+ "trace": {
61
+ "parent-id": context[:parent_id],
62
+ "sampling-priority": context[:sample_mode].to_s,
63
+ "trace-id": context[:trace_id]
64
+ }
65
+ }
66
+ }
67
+ }.to_json
68
+ end
69
+
70
+ def current_trace_context(trace_context)
71
+ trace_context = Hash[trace_context]
72
+ begin
73
+ # This will only succeed if the user has imported xray themselves
74
+ entity = XRay.recorder.current_entity
75
+ trace_context[:parent_id] = convert_to_apm_parent_id(entity.id)
76
+ rescue StandardError
77
+ Datadog::Utils.logger.debug("couldn't fetch xray entity")
78
+ end
79
+ trace_context
80
+ end
81
+
82
+ def send_xray_daemon_data(data)
83
+ xray_daemon_env = ENV[AWS_XRAY_DAEMON_ADDRESS_ENV_VAR]
84
+ socket = XRAY_UDP_PORT
85
+ address = LOCAL_HOST
86
+ address, socket = xray_daemon_env.split(':') unless xray_daemon_env.nil?
87
+
88
+ sock = UDPSocket.open
89
+ message = "{\"format\": \"json\", \"version\": 1}\n#{data}"
90
+ sock.send(message, 0, address, socket)
91
+ end
92
+
93
+ def parse_xray_trace_context_header(header)
94
+ Datadog::Utils.logger.debug("Reading trace context from env #{header}")
95
+ trace_id, parent_id, sampled = header.split(';')
96
+ .map { |v| parse_assignment(v) }
97
+
98
+ return nil if trace_id.nil? || parent_id.nil? || sampled. nil?
99
+
100
+ {
101
+ xray_trace_id: trace_id,
102
+ xray_parent_id: parent_id,
103
+ xray_sample_mode: sampled
104
+ }
105
+ end
106
+
107
+ def parse_assignment(value)
108
+ return nil if value.nil?
109
+
110
+ _, raw_value, * = value.split('=')
111
+ raw_value
112
+ end
113
+
114
+ def convert_to_apm_trace_id(xray_trace_id)
115
+ parts = xray_trace_id.split('-')
116
+ return nil if parts.length < 3
117
+
118
+ last_part = parts[2]
119
+ return nil if last_part.length != 24
120
+ # Make sure every character is hex
121
+ return nil if last_part.upcase[/\H/]
122
+
123
+ hex = last_part.to_i(16)
124
+ last_63_bits = hex & 0x7fffffffffffffff
125
+ last_63_bits.to_s(10)
126
+ end
127
+
128
+ def convert_to_apm_parent_id(xray_parent_id)
129
+ return nil if xray_parent_id.length != 16
130
+ return nil if xray_parent_id.upcase[/\H/]
131
+
132
+ hex = xray_parent_id.to_i(16)
133
+ hex.to_s(10)
134
+ end
135
+
136
+ def convert_to_sample_mode(xray_sampled)
137
+ xray_sampled == '1' ? SAMPLE_MODE_USER_KEEP : SAMPLE_MODE_USER_REJECT
138
+ end
139
+ end
140
+ end
141
+ end
@@ -11,8 +11,8 @@
11
11
  module Datadog
12
12
  module Lambda
13
13
  module VERSION
14
- MAJOR = 0
15
- MINOR = 5
14
+ MAJOR = 1
15
+ MINOR = 10
16
16
  PATCH = 0
17
17
  PRE = nil
18
18
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: datadog-lambda
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 1.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Datadog, Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-01-27 00:00:00.000000000 Z
11
+ date: 2020-08-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-xray-sdk
@@ -16,14 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.11'
19
+ version: 0.11.3
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.11'
26
+ version: 0.11.3
27
+ - !ruby/object:Gem::Dependency
28
+ name: ddtrace
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.4'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.4'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rake
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -93,12 +107,13 @@ files:
93
107
  - lib/datadog/lambda.rb
94
108
  - lib/datadog/lambda/trace/constants.rb
95
109
  - lib/datadog/lambda/trace/context.rb
110
+ - lib/datadog/lambda/trace/ddtrace.rb
96
111
  - lib/datadog/lambda/trace/listener.rb
97
112
  - lib/datadog/lambda/trace/patch_http.rb
98
- - lib/datadog/lambda/trace/xray_lambda.rb
113
+ - lib/datadog/lambda/trace/xray.rb
99
114
  - lib/datadog/lambda/utils/logger.rb
100
115
  - lib/datadog/lambda/version.rb
101
- homepage: https://github.com/DataDog/dd-lambda-rb
116
+ homepage: https://github.com/DataDog/datadog-lambda-rb
102
117
  licenses:
103
118
  - Apache-2.0
104
119
  metadata:
@@ -118,8 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
118
133
  - !ruby/object:Gem::Version
119
134
  version: '0'
120
135
  requirements: []
121
- rubyforge_project:
122
- rubygems_version: 2.7.6
136
+ rubygems_version: 3.0.3
123
137
  signing_key:
124
138
  specification_version: 4
125
139
  summary: Instruments your Ruby AWS Lambda functions with Datadog
@@ -1,84 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #
4
- # Unless explicitly stated otherwise all files in this repository are licensed
5
- # under the Apache License Version 2.0.
6
- #
7
- # This product includes software developed at Datadog (https://www.datadoghq.com/).
8
- # Copyright 2019 Datadog, Inc.
9
- #
10
-
11
- require 'aws-xray-sdk'
12
-
13
- module Datadog
14
- module Trace
15
- # Workaround to XRay not being supported in Lambda
16
- # https://github.com/aws/aws-xray-sdk-ruby/issues/20
17
- class LambdaStreamer < XRay::DefaultStreamer
18
- def initialize
19
- @stream_threshold = 1 # Stream every subsegment as it is available
20
- end
21
- end
22
-
23
- # LambdaEmitter filters out spans generated from the lambda daemon
24
- class LambdaEmitter < XRay::DefaultEmitter
25
- def should_send?(entity:)
26
- entity.name != '127.0.0.1' # Do not send localhost entities.
27
- end
28
-
29
- def send_entity(entity:)
30
- return nil unless should_send?(entity: entity)
31
-
32
- super
33
- end
34
- end
35
-
36
- # LambdaContext updated the trace id based on the curren trace header,
37
- # using a FacadeSegment
38
- class LambdaContext < XRay::DefaultContext
39
- def handle_context_missing
40
- nil
41
- end
42
-
43
- def check_context
44
- # Create a new FacadeSegment if the _X_AMZN_TRACE_ID changes.
45
- return if ENV['_X_AMZN_TRACE_ID'] == @current_trace_id
46
-
47
- # puts "XRAY: Starting new segment for #{ENV['_X_AMZN_TRACE_ID']}"
48
- @current_trace_id = ENV['_X_AMZN_TRACE_ID']
49
- trace_header = XRay::TraceHeader.from_header_string(
50
- header_str: @current_trace_id
51
- )
52
- segment = FacadeSegment.new(trace_id: trace_header.root,
53
- parent_id: trace_header.parent_id,
54
- id: trace_header.parent_id,
55
- name: 'lambda_context',
56
- sampled: trace_header.sampled)
57
- store_entity(entity: segment)
58
- end
59
-
60
- def current_entity
61
- # ensure the FacadeSegment is current whenever the current_entity is
62
- # retrieved
63
- check_context
64
- super
65
- end
66
- end
67
-
68
- # FacadeSegment is used to create a mock root span, that segments/
69
- # subsegments can be attached to. This span will never be submitted to the
70
- # X-Ray daemon
71
- class FacadeSegment < XRay::Segment
72
- def initialize(trace_id: nil, name: nil, parent_id: nil, id: nil,
73
- sampled: true)
74
- super(trace_id: trace_id, name: name, parent_id: parent_id)
75
- @id = id
76
- @sampled = sampled
77
- end
78
-
79
- def ready_to_send?
80
- false # never send this facade.
81
- end
82
- end
83
- end
84
- end