instana 1.197.0 → 1.198.0.pre1

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: a25aa837fcbb248cb39db1f57b7bdc8904810d5e63d87be7e12d912b7b9aea67
4
- data.tar.gz: 836dc1f8d7ffc4c8c19e3fa90867a306fe7d407fb88a14481d44bde1dc482285
3
+ metadata.gz: 0b2d93394311ee04b29279b946a5b2d6bf74e567aecbeccef6ffa13b07224002
4
+ data.tar.gz: ba3febaf1f2089a0547ae9e30596de784bcc7636bb98906c287638233cfdc8a6
5
5
  SHA512:
6
- metadata.gz: b8f3ba0fbf4a015ff1522a3c24e6b219594d2c266bc46427a93979e6ee159272d2c23a8fc53e4720021c5c531ad64ffd1d1f2644b8eb41497aaf8950c99ed8b6
7
- data.tar.gz: 44e5b93aff42f542eaee494128e973a9447210fbffde21c4b361f1b00729c8b3378634241d64039453ea3dda0dc2a0d207473a0c5631f1f09e77726b2a827532
6
+ metadata.gz: 74d25b236d861ec5eb144780a34e7b44b13f747ca843ee7bc25c3387eba63fbe0f3128a63bf19828a17e7bd02ebe51164f9f72c52070bd46a2d291e433ab4caa
7
+ data.tar.gz: 2ce25e5cea1b1a38831a481e571603fe99b67143ee7653c38081e1df5c8989f13f02e6490dad28500c63fff99277937b9be7052d0f7cf679ce0c46ce36cb5c21
@@ -15,7 +15,9 @@ module Instana
15
15
  end
16
16
 
17
17
  def setup
18
- @delegate = if @fargate_metadata_uri && ENV.key?('INSTANA_ENDPOINT_URL')
18
+ @delegate = if ENV.key?('_HANDLER')
19
+ ServerlessAgent.new([Snapshot::LambdaFunction.new])
20
+ elsif @fargate_metadata_uri && ENV.key?('INSTANA_ENDPOINT_URL')
19
21
  ServerlessAgent.new(fargate_snapshots)
20
22
  else
21
23
  HostAgent.new
@@ -33,9 +33,10 @@ module Instana
33
33
  end
34
34
 
35
35
  def initialize(host, port, use_ssl: false)
36
+ timeout = Integer(ENV.fetch('INSTANA_TIMEOUT', 500))
36
37
  @host = host
37
38
  @port = port
38
- @client = Net::HTTP.start(host, port, use_ssl: use_ssl)
39
+ @client = Net::HTTP.start(host, port, use_ssl: use_ssl, read_timeout: timeout)
39
40
  end
40
41
 
41
42
  # Send a request to the backend. If data is a {Hash},
@@ -39,12 +39,10 @@ module Instana
39
39
 
40
40
  # @return [Hash, NilClass] the backend friendly description of the current in process collector
41
41
  def source
42
- return @source if @source
43
-
44
42
  snapshot = @snapshots.detect { |s| s.respond_to?(:source) }
45
43
 
46
44
  if snapshot
47
- @source = snapshot.source
45
+ snapshot.source
48
46
  else
49
47
  @logger.warn('Unable to find a snapshot which provides a source.')
50
48
  {}
@@ -58,21 +56,10 @@ module Instana
58
56
 
59
57
  # @return [Hash] values which are removed from urls sent to the backend
60
58
  def secret_values
61
- # TODO: Parse from env
62
59
  matcher, *keys = @secrets.split(/[:,]/)
63
60
  {'matcher' => matcher, 'list' => keys}
64
61
  end
65
62
 
66
- private
67
-
68
- def request_headers
69
- {
70
- 'X-Instana-Host' => host_name,
71
- 'X-Instana-Key' => ENV['INSTANA_AGENT_KEY'],
72
- 'X-Instana-Time' => (Time.now.to_i * 1000).to_s
73
- }
74
- end
75
-
76
63
  def send_bundle
77
64
  spans = @processor.queued_spans
78
65
  bundle = {
@@ -90,6 +77,16 @@ module Instana
90
77
  @logger.warn("Recived a `#{response.code}` when sending data.")
91
78
  end
92
79
 
80
+ private
81
+
82
+ def request_headers
83
+ {
84
+ 'X-Instana-Host' => host_name,
85
+ 'X-Instana-Key' => ENV['INSTANA_AGENT_KEY'],
86
+ 'X-Instana-Time' => (Time.now.to_i * 1000).to_s
87
+ }
88
+ end
89
+
93
90
  def agent_snapshots
94
91
  @snapshots.map do |snapshot|
95
92
  begin # rubocop:disable Style/RedundantBegin, Lint/RedundantCopDisableDirective
@@ -102,12 +99,10 @@ module Instana
102
99
  end
103
100
 
104
101
  def host_name
105
- return @host_name if @host_name
106
-
107
102
  snapshot = @snapshots.detect { |s| s.respond_to?(:host_name) }
108
103
 
109
104
  if snapshot
110
- @host_name = snapshot.host_name
105
+ snapshot.host_name
111
106
  else
112
107
  @logger.warn('Unable to find a snapshot which provides a host_name.')
113
108
  ''
data/lib/instana/base.rb CHANGED
@@ -13,6 +13,7 @@ module Instana
13
13
  attr_accessor :config
14
14
  attr_accessor :pid
15
15
  attr_reader :secrets
16
+ attr_reader :serverless
16
17
 
17
18
  ##
18
19
  # setup
@@ -25,6 +26,7 @@ module Instana
25
26
  @tracer = ::Instana::Tracer.new
26
27
  @processor = ::Instana::Processor.new
27
28
  @secrets = ::Instana::Secrets.new
29
+ @serverless = ::Instana::Serverless.new
28
30
  end
29
31
 
30
32
  def logger
@@ -0,0 +1,133 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ require 'base64'
5
+ require 'zlib'
6
+
7
+ require 'instana/instrumentation/instrumented_request'
8
+
9
+ module Instana
10
+ # @since 1.198.0
11
+ class Serverless
12
+ def initialize(agent: ::Instana.agent, tracer: ::Instana.tracer, logger: ::Instana.logger)
13
+ @agent = agent
14
+ @tracer = tracer
15
+ @logger = logger
16
+ end
17
+
18
+ def wrap_aws(event, context, &block)
19
+ Thread.current[:instana_function_arn] = [context.invoked_function_arn, context.function_version].join(':')
20
+ trigger, event_tags, span_context = trigger_from_event(event)
21
+
22
+ tags = {
23
+ lambda: {
24
+ arn: context.invoked_function_arn,
25
+ functionName: context.function_name,
26
+ functionVersion: context.function_version,
27
+ runtime: 'ruby',
28
+ trigger: trigger
29
+ }
30
+ }
31
+
32
+ if event_tags.key?(:http)
33
+ tags = tags.merge(event_tags)
34
+ else
35
+ tags[:lambda] = tags[:lambda].merge(event_tags)
36
+ end
37
+
38
+ @tracer.start_or_continue_trace(:'aws.lambda.entry', tags, span_context, &block)
39
+ ensure
40
+ begin
41
+ @agent.send_bundle
42
+ rescue StandardError => e
43
+ @logger.error(e.message)
44
+ end
45
+ Thread.current[:instana_function_arn] = nil
46
+ end
47
+
48
+ private
49
+
50
+ def trigger_from_event(event) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
51
+ case event
52
+ when ->(e) { e.is_a?(Hash) && e.key?('requestContext') && e['requestContext'].key?('elb') }
53
+ request = InstrumentedRequest.new(event_to_rack(event))
54
+ ['aws:application.load.balancer', {http: request.request_tags}, request.incoming_context]
55
+ when ->(e) { e.is_a?(Hash) && e.key?('httpMethod') && e.key?('path') && e.key?('headers') }
56
+ request = InstrumentedRequest.new(event_to_rack(event))
57
+ ['aws:api.gateway', {http: request.request_tags}, request.incoming_context]
58
+ when ->(e) { e.is_a?(Hash) && e['source'] == 'aws.events' && e['detail-type'] == 'Scheduled Event' }
59
+ tags = decode_cloudwatch_events(event)
60
+ ['aws:cloudwatch.events', {cw: tags}, {}]
61
+ when ->(e) { e.is_a?(Hash) && e.key?('awslogs') }
62
+ tags = decode_cloudwatch_logs(event)
63
+ ['aws:cloudwatch.logs', {cw: tags}, {}]
64
+ when ->(e) { e.is_a?(Hash) && e.key?('Records') && e['Records'].is_a?(Array) && e['Records'].first && e['Records'].first['source'] == 'aws:s3' }
65
+ tags = decode_s3(event)
66
+ ['aws:s3', {s3: tags}, {}]
67
+ when ->(e) { e.is_a?(Hash) && e.key?('Records') && e['Records'].is_a?(Array) && e['Records'].first && e['Records'].first['source'] == 'aws:sqs' }
68
+ tags = decode_sqs(event)
69
+ ['aws:sqs', {sqs: tags}, {}]
70
+ else
71
+ ['aws:api.gateway.noproxy', {}, {}]
72
+ end
73
+ end
74
+
75
+ def event_to_rack(event)
76
+ event['headers']
77
+ .transform_keys { |k| "HTTP_#{k.gsub('-', '_').upcase}" }
78
+ .merge(
79
+ 'QUERY_STRING' => URI.encode_www_form(event['queryStringParameters'] || {}),
80
+ 'PATH_INFO' => event['path'],
81
+ 'REQUEST_METHOD' => event['httpMethod']
82
+ )
83
+ end
84
+
85
+ def decode_cloudwatch_events(event)
86
+ {
87
+ events: {
88
+ id: event['id'],
89
+ resources: event['resources']
90
+ }
91
+ }
92
+ end
93
+
94
+ def decode_cloudwatch_logs(event)
95
+ logs = begin
96
+ payload = JSON.parse(Zlib::Inflate.inflate(Base64.decode64(event['awslogs']['data'])))
97
+
98
+ {
99
+ group: payload['logGroup'],
100
+ stream: payload['logStream']
101
+ }
102
+ rescue StandardError => e
103
+ {
104
+ decodingError: e.message
105
+ }
106
+ end
107
+
108
+ {logs: logs}
109
+ end
110
+
111
+ def decode_s3(event)
112
+ span_events = event['Records'].map do |record|
113
+ {
114
+ name: record['eventName'],
115
+ bucket: record['s3'] && record['s3']['bucket'] ? record['s3']['bucket']['name'] : nil,
116
+ object: record['s3'] && record['s3']['object'] ? record['s3']['object']['key'] : nil
117
+ }
118
+ end
119
+
120
+ {events: span_events}
121
+ end
122
+
123
+ def decode_sqs(event)
124
+ span_events = event['Records'].map do |record|
125
+ {
126
+ queue: record['eventSourceARN']
127
+ }
128
+ end
129
+
130
+ {messages: span_events}
131
+ end
132
+ end
133
+ end
data/lib/instana/setup.rb CHANGED
@@ -9,6 +9,8 @@ require "instana/secrets"
9
9
  require "instana/tracer"
10
10
  require "instana/tracing/processor"
11
11
 
12
+ require 'instana/serverless'
13
+
12
14
  require 'instana/activator'
13
15
 
14
16
  require 'instana/backend/request_client'
@@ -21,6 +23,7 @@ require 'instana/snapshot/fargate_process'
21
23
  require 'instana/snapshot/fargate_task'
22
24
  require 'instana/snapshot/fargate_container'
23
25
  require 'instana/snapshot/docker_container'
26
+ require 'instana/snapshot/lambda_function'
24
27
 
25
28
  require 'instana/backend/host_agent_lookup'
26
29
  require 'instana/backend/host_agent_activation_observer'
@@ -1,5 +1,8 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
1
4
  module Instana
2
- module Backend
5
+ module Snapshot
3
6
  # @since 1.198.0
4
7
  class LambdaFunction
5
8
  ID = "com.instana.plugin.aws.lambda".freeze
@@ -22,15 +25,15 @@ module Instana
22
25
 
23
26
  def source
24
27
  {
25
-
28
+ hl: true,
29
+ cp: "aws",
30
+ e: entity_id
26
31
  }
27
32
  end
28
33
 
29
34
  def host_name
30
35
  entity_id
31
36
  end
32
-
33
-
34
37
  end
35
38
  end
36
39
  end
@@ -6,8 +6,8 @@ module Instana
6
6
  REGISTERED_SPANS = [ :actioncontroller, :actionview, :activerecord, :excon,
7
7
  :memcache, :'net-http', :rack, :render, :'rpc-client',
8
8
  :'rpc-server', :'sidekiq-client', :'sidekiq-worker',
9
- :redis, :'resque-client', :'resque-worker', :'graphql.server', :dynamodb, :s3, :sns, :sqs ].freeze
10
- ENTRY_SPANS = [ :rack, :'resque-worker', :'rpc-server', :'sidekiq-worker', :'graphql.server', :sqs ].freeze
9
+ :redis, :'resque-client', :'resque-worker', :'graphql.server', :dynamodb, :s3, :sns, :sqs, :'aws.lambda.entry' ].freeze
10
+ ENTRY_SPANS = [ :rack, :'resque-worker', :'rpc-server', :'sidekiq-worker', :'graphql.server', :sqs, :'aws.lambda.entry' ].freeze
11
11
  EXIT_SPANS = [ :activerecord, :excon, :'net-http', :'resque-client',
12
12
  :'rpc-client', :'sidekiq-client', :redis, :dynamodb, :s3, :sns, :sqs ].freeze
13
13
  HTTP_SPANS = [ :rack, :excon, :'net-http' ].freeze
@@ -2,6 +2,6 @@
2
2
  # (c) Copyright Instana Inc. 2016
3
3
 
4
4
  module Instana
5
- VERSION = "1.197.0"
5
+ VERSION = "1.198.0.pre1"
6
6
  VERSION_FULL = "instana-#{VERSION}"
7
7
  end
@@ -43,6 +43,19 @@ class AgentTest < Minitest::Test
43
43
  ENV['ECS_CONTAINER_METADATA_URI'] = nil
44
44
  end
45
45
 
46
+ def test_lambda
47
+ ENV['_HANDLER'] = 'TEST_FUNCTION'
48
+ ENV['INSTANA_ENDPOINT_URL'] = 'http://example.com'
49
+
50
+ subject = Instana::Backend::Agent.new
51
+ assert_nil subject.delegate
52
+ subject.setup
53
+ assert subject.delegate.is_a?(Instana::Backend::ServerlessAgent)
54
+ ensure
55
+ ENV['_HANDLER'] = nil
56
+ ENV['INSTANA_ENDPOINT_URL'] = nil
57
+ end
58
+
46
59
  def test_delegate_super
47
60
  subject = Instana::Backend::Agent.new
48
61
  assert_raises NoMethodError do
@@ -0,0 +1,323 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ require 'test_helper'
5
+
6
+ class ServerlessTest < Minitest::Test
7
+ def setup
8
+ @mock_agent = Minitest::Mock.new
9
+ @mock_agent.expect(:send_bundle, true, [])
10
+ @subject = Instana::Serverless.new(agent: @mock_agent)
11
+ end
12
+
13
+ def teardown
14
+ @mock_agent.verify
15
+ end
16
+
17
+ def test_lambda_send_error
18
+ mock_logger = Minitest::Mock.new
19
+ mock_logger.expect(:error, true, [String])
20
+
21
+ @mock_agent.expect(:send_bundle, true) { |_args| raise StandardError, 'error' }
22
+
23
+ mock_context = OpenStruct.new(
24
+ invoked_function_arn: 'test_arn',
25
+ function_name: 'test_function',
26
+ function_version: '$TEST'
27
+ )
28
+
29
+ subject = Instana::Serverless.new(agent: @mock_agent, logger: mock_logger)
30
+ subject.wrap_aws(nil, mock_context) { 0 }
31
+ subject.wrap_aws(nil, mock_context) { 0 }
32
+
33
+ mock_logger.verify
34
+ end
35
+
36
+ def test_lambda_data
37
+ clear_all!
38
+
39
+ mock_context = OpenStruct.new(
40
+ invoked_function_arn: 'test_arn',
41
+ function_name: 'test_function',
42
+ function_version: '$TEST'
43
+ )
44
+
45
+ @subject.wrap_aws(nil, mock_context) { 0 }
46
+
47
+ lambda_span, *rest = Instana.processor.queued_spans
48
+ assert rest.empty?
49
+
50
+ data = lambda_span[:data][:lambda]
51
+
52
+ assert_equal 'aws:api.gateway.noproxy', lambda_span[:data][:lambda][:trigger]
53
+
54
+ assert_equal mock_context.invoked_function_arn, data[:arn]
55
+ assert_equal mock_context.function_name, data[:functionName]
56
+ assert_equal mock_context.function_version, data[:functionVersion]
57
+ assert_equal 'ruby', data[:runtime]
58
+ end
59
+
60
+ def test_lambda_http
61
+ clear_all!
62
+
63
+ mock_id = Instana::Util.generate_id
64
+ mock_context = OpenStruct.new(
65
+ invoked_function_arn: 'test_arn',
66
+ function_name: 'test_function',
67
+ function_version: '$TEST'
68
+ )
69
+ mock_http = {
70
+ "headers" => {
71
+ "Accept" => "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
72
+ "Accept-Encoding" => "gzip, deflate",
73
+ "Accept-Language" => "en-US,en;q=0.5",
74
+ "Connection" => "keep-alive",
75
+ "Host" => "127.0.0.1:3000",
76
+ "Upgrade-Insecure-Requests" => "1",
77
+ "User-Agent" => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:87.0) Gecko/20100101 Firefox/87.0",
78
+ "X-Forwarded-Port" => "3000",
79
+ "X-Forwarded-Proto" => "http",
80
+ 'X-Instana-S' => mock_id,
81
+ 'X-Instana-T' => mock_id,
82
+ 'X-Instana-L' => '1'
83
+ },
84
+ "httpMethod" => "GET",
85
+ "path" => "/hello",
86
+ "queryStringParameters" => {"test" => "abcde"}
87
+ }
88
+
89
+ @subject.wrap_aws(mock_http, mock_context) { 0 }
90
+
91
+ lambda_span, *rest = Instana.processor.queued_spans
92
+ assert rest.empty?
93
+
94
+ data = lambda_span[:data][:http]
95
+
96
+ assert_equal 'aws:api.gateway', lambda_span[:data][:lambda][:trigger]
97
+ assert_equal mock_id, lambda_span[:t]
98
+ assert_equal mock_id, lambda_span[:p]
99
+
100
+ assert_equal 'GET', data[:method]
101
+ assert_equal '/hello', data[:url]
102
+ assert_equal '127.0.0.1:3000', data[:host]
103
+ assert_equal 'test=abcde', data[:params]
104
+ end
105
+
106
+ def test_lambda_alb
107
+ clear_all!
108
+
109
+ mock_id = Instana::Util.generate_id
110
+ mock_context = OpenStruct.new(
111
+ invoked_function_arn: 'test_arn',
112
+ function_name: 'test_function',
113
+ function_version: '$TEST'
114
+ )
115
+ mock_http = {
116
+ "headers" => {
117
+ "Accept" => "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
118
+ "Accept-Encoding" => "gzip, deflate",
119
+ "Accept-Language" => "en-US,en;q=0.5",
120
+ "Connection" => "keep-alive",
121
+ "Host" => "127.0.0.1:3000",
122
+ "Upgrade-Insecure-Requests" => "1",
123
+ "User-Agent" => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:87.0) Gecko/20100101 Firefox/87.0",
124
+ "X-Forwarded-Port" => "3000",
125
+ "X-Forwarded-Proto" => "http",
126
+ 'X-Instana-S' => mock_id,
127
+ 'X-Instana-T' => mock_id,
128
+ 'X-Instana-L' => '1'
129
+ },
130
+ "httpMethod" => "GET",
131
+ "path" => "/hello",
132
+ "requestContext" => { "elb" => {} }
133
+ }
134
+
135
+ @subject.wrap_aws(mock_http, mock_context) { 0 }
136
+
137
+ lambda_span, *rest = Instana.processor.queued_spans
138
+ assert rest.empty?
139
+
140
+ data = lambda_span[:data][:http]
141
+
142
+ assert_equal 'aws:application.load.balancer', lambda_span[:data][:lambda][:trigger]
143
+ assert_equal mock_id, lambda_span[:t]
144
+ assert_equal mock_id, lambda_span[:p]
145
+
146
+ assert_equal 'GET', data[:method]
147
+ assert_equal '/hello', data[:url]
148
+ assert_equal '127.0.0.1:3000', data[:host]
149
+ assert_equal '', data[:params]
150
+ end
151
+
152
+ def test_lambda_cw_event
153
+ clear_all!
154
+
155
+ mock_context = OpenStruct.new(
156
+ invoked_function_arn: 'test_arn',
157
+ function_name: 'test_function',
158
+ function_version: '$TEST'
159
+ )
160
+ mock_event = {
161
+ "detail-type" => "Scheduled Event",
162
+ "source" => "aws.events",
163
+ "id" => "test",
164
+ "resources" => ["test"]
165
+ }
166
+
167
+ @subject.wrap_aws(mock_event, mock_context) { 0 }
168
+
169
+ lambda_span, *rest = Instana.processor.queued_spans
170
+ assert rest.empty?
171
+
172
+ data = lambda_span[:data][:lambda][:cw][:events]
173
+
174
+ assert_equal 'aws:cloudwatch.events', lambda_span[:data][:lambda][:trigger]
175
+ assert_equal 'test', data[:id]
176
+ assert_equal ["test"], data[:resources]
177
+ end
178
+
179
+ def test_lambda_cw_logs
180
+ clear_all!
181
+
182
+ mock_context = OpenStruct.new(
183
+ invoked_function_arn: 'test_arn',
184
+ function_name: 'test_function',
185
+ function_version: '$TEST'
186
+ )
187
+ mock_event = {
188
+ "awslogs" => {"data" => File.read('test/support/serverless/cloudwatch_log.bin')}
189
+ }
190
+
191
+ @subject.wrap_aws(mock_event, mock_context) { 0 }
192
+
193
+ lambda_span, *rest = Instana.processor.queued_spans
194
+ assert rest.empty?
195
+
196
+ data = lambda_span[:data][:lambda][:cw][:logs]
197
+
198
+ assert_equal 'aws:cloudwatch.logs', lambda_span[:data][:lambda][:trigger]
199
+ assert_equal '/aws/lambda/echo-nodejs', data[:group]
200
+ assert_equal '2019/03/13/[$LATEST]94fa867e5374431291a7fc14e2f56ae7', data[:stream]
201
+ end
202
+
203
+ def test_lambda_cw_error
204
+ clear_all!
205
+
206
+ mock_context = OpenStruct.new(
207
+ invoked_function_arn: 'test_arn',
208
+ function_name: 'test_function',
209
+ function_version: '$TEST'
210
+ )
211
+ mock_event = {
212
+ "awslogs" => {"data" => "error"}
213
+ }
214
+
215
+ @subject.wrap_aws(mock_event, mock_context) { 0 }
216
+
217
+ lambda_span, *rest = Instana.processor.queued_spans
218
+ assert rest.empty?
219
+
220
+ data = lambda_span[:data][:lambda][:cw][:logs]
221
+
222
+ assert_equal 'aws:cloudwatch.logs', lambda_span[:data][:lambda][:trigger]
223
+ assert_equal 'incorrect header check', data[:decodingError]
224
+ end
225
+
226
+ def test_lambda_s3
227
+ clear_all!
228
+
229
+ mock_context = OpenStruct.new(
230
+ invoked_function_arn: 'test_arn',
231
+ function_name: 'test_function',
232
+ function_version: '$TEST'
233
+ )
234
+ mock_event = {
235
+ "Records" => [
236
+ {
237
+ "source" => "aws:s3",
238
+ "eventName" => "test",
239
+ "s3" => {
240
+ "bucket" => {"name" => "test_bucket"},
241
+ "object" => {"key" => "test_key"}
242
+ }
243
+ }
244
+ ]
245
+ }
246
+
247
+ @subject.wrap_aws(mock_event, mock_context) { 0 }
248
+
249
+ lambda_span, *rest = Instana.processor.queued_spans
250
+ assert rest.empty?
251
+
252
+ data = lambda_span[:data][:lambda][:s3]
253
+
254
+ assert_equal 'aws:s3', lambda_span[:data][:lambda][:trigger]
255
+ assert_equal 1, data[:events].length
256
+
257
+ assert_equal 'test', data[:events].first[:name]
258
+ assert_equal 'test_bucket', data[:events].first[:bucket]
259
+ assert_equal 'test_key', data[:events].first[:object]
260
+ end
261
+
262
+ def test_lambda_s3_no_object
263
+ clear_all!
264
+
265
+ mock_context = OpenStruct.new(
266
+ invoked_function_arn: 'test_arn',
267
+ function_name: 'test_function',
268
+ function_version: '$TEST'
269
+ )
270
+ mock_event = {
271
+ "Records" => [
272
+ {
273
+ "source" => "aws:s3",
274
+ "eventName" => "test"
275
+ }
276
+ ]
277
+ }
278
+
279
+ @subject.wrap_aws(mock_event, mock_context) { 0 }
280
+
281
+ lambda_span, *rest = Instana.processor.queued_spans
282
+ assert rest.empty?
283
+
284
+ data = lambda_span[:data][:lambda][:s3]
285
+
286
+ assert_equal 'aws:s3', lambda_span[:data][:lambda][:trigger]
287
+ assert_equal 1, data[:events].length
288
+
289
+ assert_equal 'test', data[:events].first[:name]
290
+ assert_nil data[:events].first[:bucket]
291
+ assert_nil data[:events].first[:object]
292
+ end
293
+
294
+ def test_lambda_sqs
295
+ clear_all!
296
+
297
+ mock_context = OpenStruct.new(
298
+ invoked_function_arn: 'test_arn',
299
+ function_name: 'test_function',
300
+ function_version: '$TEST'
301
+ )
302
+ mock_event = {
303
+ "Records" => [
304
+ {
305
+ "source" => "aws:sqs",
306
+ "eventSourceARN" => "test_arn"
307
+ }
308
+ ]
309
+ }
310
+
311
+ @subject.wrap_aws(mock_event, mock_context) { 0 }
312
+
313
+ lambda_span, *rest = Instana.processor.queued_spans
314
+ assert rest.empty?
315
+
316
+ data = lambda_span[:data][:lambda][:sqs]
317
+
318
+ assert_equal 'aws:sqs', lambda_span[:data][:lambda][:trigger]
319
+ assert_equal 1, data[:messages].length
320
+
321
+ assert_equal 'test_arn', data[:messages].first[:queue]
322
+ end
323
+ end
@@ -0,0 +1,37 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ require 'test_helper'
5
+
6
+ class LambdaFunctionTest < Minitest::Test
7
+ def setup
8
+ @subject = Instana::Snapshot::LambdaFunction.new
9
+ end
10
+
11
+ def test_snapshot
12
+ Thread.current[:instana_function_arn] = 'test'
13
+
14
+ assert_equal Instana::Snapshot::LambdaFunction::ID, @subject.snapshot[:name]
15
+ assert_equal Thread.current[:instana_function_arn], @subject.snapshot[:entityId]
16
+ ensure
17
+ Thread.current[:instana_function_arn] = nil
18
+ end
19
+
20
+ def test_source
21
+ Thread.current[:instana_function_arn] = 'test'
22
+
23
+ assert @subject.source[:hl]
24
+ assert_equal 'aws', @subject.source[:cp]
25
+ assert_equal Thread.current[:instana_function_arn], @subject.source[:e]
26
+ ensure
27
+ Thread.current[:instana_function_arn] = nil
28
+ end
29
+
30
+ def test_host_name
31
+ Thread.current[:instana_function_arn] = 'test'
32
+
33
+ assert_equal Thread.current[:instana_function_arn], @subject.host_name
34
+ ensure
35
+ Thread.current[:instana_function_arn] = nil
36
+ end
37
+ end
@@ -68,6 +68,10 @@ class TracerIDMgmtTest < Minitest::Test
68
68
  # Bogus Array arg
69
69
  bogus_result = Instana::Util.header_to_id([1234])
70
70
  assert_equal '', bogus_result
71
+
72
+ # Invalid characters/length
73
+ bogus_result = Instana::Util.header_to_id('qwerty')
74
+ assert_equal '', bogus_result
71
75
  end
72
76
 
73
77
  def test_long_id_trim
@@ -15,7 +15,8 @@ class SpanContextTest < Minitest::Test
15
15
  end
16
16
 
17
17
  def test_flags_level_zero
18
- subject = Instana::SpanContext.new('trace', 'span', 0)
18
+ subject = Instana::SpanContext.new('trace', 'span', 0, {external_state: 'cn=test'})
19
19
  assert_equal '00-000000000000000000000000000trace-000000000000span-00', subject.trace_parent_header
20
+ assert_equal 'cn=test', subject.trace_state_header
20
21
  end
21
22
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: instana
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.197.0
4
+ version: 1.198.0.pre1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Giacomo Lombardo
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-04-06 00:00:00.000000000 Z
11
+ date: 2021-04-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -255,6 +255,7 @@ files:
255
255
  - lib/instana/open_tracing/instana_tracer.rb
256
256
  - lib/instana/rack.rb
257
257
  - lib/instana/secrets.rb
258
+ - lib/instana/serverless.rb
258
259
  - lib/instana/setup.rb
259
260
  - lib/instana/snapshot/deltable.rb
260
261
  - lib/instana/snapshot/docker_container.rb
@@ -307,11 +308,13 @@ files:
307
308
  - test/instrumentation/sidekiq-client_test.rb
308
309
  - test/instrumentation/sidekiq-worker_test.rb
309
310
  - test/secrets_test.rb
311
+ - test/serverless_test.rb
310
312
  - test/snapshot/deltable_test.rb
311
313
  - test/snapshot/docker_container_test.rb
312
314
  - test/snapshot/fargate_container_test.rb
313
315
  - test/snapshot/fargate_process_test.rb
314
316
  - test/snapshot/fargate_task_test.rb
317
+ - test/snapshot/lambda_function_test.rb
315
318
  - test/snapshot/ruby_process_test.rb
316
319
  - test/support/apps/active_record/active_record.rb
317
320
  - test/support/apps/grpc/boot.rb
@@ -358,9 +361,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
358
361
  version: '2.1'
359
362
  required_rubygems_version: !ruby/object:Gem::Requirement
360
363
  requirements:
361
- - - ">="
364
+ - - ">"
362
365
  - !ruby/object:Gem::Version
363
- version: '0'
366
+ version: 1.3.1
364
367
  requirements: []
365
368
  rubygems_version: 3.2.6
366
369
  signing_key:
@@ -368,6 +371,7 @@ specification_version: 4
368
371
  summary: Ruby Distributed Tracing & Metrics Sensor for Instana
369
372
  test_files:
370
373
  - test/config_test.rb
374
+ - test/serverless_test.rb
371
375
  - test/activator_test.rb
372
376
  - test/tracing/span_context_test.rb
373
377
  - test/tracing/span_test.rb
@@ -382,6 +386,7 @@ test_files:
382
386
  - test/snapshot/deltable_test.rb
383
387
  - test/snapshot/fargate_task_test.rb
384
388
  - test/snapshot/ruby_process_test.rb
389
+ - test/snapshot/lambda_function_test.rb
385
390
  - test/snapshot/fargate_container_test.rb
386
391
  - test/backend/host_agent_activation_observer_test.rb
387
392
  - test/backend/host_agent_reporting_observer_test.rb