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 +4 -4
- data/lib/instana/backend/agent.rb +3 -1
- data/lib/instana/backend/request_client.rb +2 -1
- data/lib/instana/backend/serverless_agent.rb +12 -17
- data/lib/instana/base.rb +2 -0
- data/lib/instana/serverless.rb +133 -0
- data/lib/instana/setup.rb +3 -0
- data/lib/instana/snapshot/lambda_function.rb +7 -4
- data/lib/instana/tracing/span.rb +2 -2
- data/lib/instana/version.rb +1 -1
- data/test/backend/agent_test.rb +13 -0
- data/test/serverless_test.rb +323 -0
- data/test/snapshot/lambda_function_test.rb +37 -0
- data/test/tracing/id_management_test.rb +4 -0
- data/test/tracing/span_context_test.rb +2 -1
- metadata +9 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0b2d93394311ee04b29279b946a5b2d6bf74e567aecbeccef6ffa13b07224002
|
|
4
|
+
data.tar.gz: ba3febaf1f2089a0547ae9e30596de784bcc7636bb98906c287638233cfdc8a6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
data/lib/instana/tracing/span.rb
CHANGED
|
@@ -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
|
data/lib/instana/version.rb
CHANGED
data/test/backend/agent_test.rb
CHANGED
|
@@ -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.
|
|
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-
|
|
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:
|
|
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
|