instana 1.201.0.pre1 → 1.203.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +14 -5
  3. data/.github/ISSUE_TEMPLATE/bug.yml +39 -0
  4. data/.github/ISSUE_TEMPLATE/config.yml +5 -0
  5. data/Appraisals +1 -0
  6. data/README.md +1 -1
  7. data/gemfiles/aws_30.gemfile +1 -0
  8. data/lib/instana/activator.rb +2 -0
  9. data/lib/instana/activators/action_mailer.rb +22 -0
  10. data/lib/instana/activators/active_job.rb +21 -0
  11. data/lib/instana/activators/aws_sdk_lambda.rb +20 -0
  12. data/lib/instana/backend/host_agent_reporting_observer.rb +2 -4
  13. data/lib/instana/config.rb +4 -1
  14. data/lib/instana/frameworks/rails.rb +5 -5
  15. data/lib/instana/instrumentation/action_mailer.rb +22 -0
  16. data/lib/instana/instrumentation/active_job.rb +52 -0
  17. data/lib/instana/instrumentation/aws_sdk_lambda.rb +37 -0
  18. data/lib/instana/instrumentation/resque.rb +11 -1
  19. data/lib/instana/instrumented_logger.rb +26 -0
  20. data/lib/instana/serverless.rb +24 -3
  21. data/lib/instana/setup.rb +2 -0
  22. data/lib/instana/tracing/processor.rb +1 -0
  23. data/lib/instana/tracing/span.rb +6 -3
  24. data/lib/instana/version.rb +1 -1
  25. data/test/instrumentation/aws_test.rb +35 -0
  26. data/test/instrumentation/rails_action_mailer_test.rb +37 -0
  27. data/test/instrumentation/rails_active_job_test.rb +65 -0
  28. data/test/instrumentation/rails_active_record_database_missing_test.rb +43 -0
  29. data/test/instrumentation/resque_test.rb +57 -6
  30. data/test/serverless_test.rb +46 -0
  31. data/test/support/apps/resque/jobs/resque_fast_job.rb +3 -1
  32. data/test/test_helper.rb +10 -1
  33. data/test/tracing/instrumented_logger_test.rb +39 -0
  34. metadata +21 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5a69d1f908c617f99a74724260ecf5f1d32ed9dc16d3630abf9b93d05a4c3a0b
4
- data.tar.gz: 8dd9c2a52af9267fdb12af599c50e19bc7fed2fe7012dd19f2b61f66234e7489
3
+ metadata.gz: b2eef31bcb3f06d8ec7323f4e9093d6e332f73e101c1faf1f73e5d07a5593512
4
+ data.tar.gz: c5d1af0df01f2c5f99955996cfe6f2fe969f47407522cecb945d47776ea053ee
5
5
  SHA512:
6
- metadata.gz: 1646aca3f210450cb60d00f679737ea54a9b72ab4822c9e60ca2ad012430dd8e05f86dab0e3cc5959276fcf42fe54206b26018ab5f257e361312830bf30824c8
7
- data.tar.gz: 324e040afb6e61d5815dd35599ad0af0cab11be1470b08c95e18fcd99e8e325aec1528689fe1b0f07ad986784428ddff0484a3d92547c4d94885b5744b76ec2d
6
+ metadata.gz: daca4cc08bbe967dbae87795dc90e5b54e72447ee05aa8ceafd1166bc8ada1f873d682c452e83d9bd47fff6fccf9b941adb82476acbf2bc96df110e488261640
7
+ data.tar.gz: 971f5af221ccc75e6ad199e962a34e528cd1adaa07cf1cc7c5681a903cfefb8cf5aa536b97fb708cc0c40b969adc5cb330aa5e8f7c37de65a2bb3c1d6495c3ad
data/.circleci/config.yml CHANGED
@@ -132,12 +132,12 @@ commands:
132
132
  name: Install Depdendecies
133
133
  command: |
134
134
  bundle check || bundle install
135
- run_tests:
135
+ run_sonarqube:
136
136
  steps:
137
137
  - run:
138
- name: Run Tests
138
+ name: Install Java
139
139
  command: |
140
- bundle exec rake
140
+ sudo apt-get install openjdk-11-jdk
141
141
  - run:
142
142
  name: Run SonarQube to capture coverage
143
143
  command: |
@@ -147,8 +147,16 @@ commands:
147
147
  -Dsonar.projectKey=ruby-sensor \
148
148
  -Dsonar.sources=. \
149
149
  -Dsonar.host.url="${SONARQUBE_URL}" \
150
- -Dsonar.login="${SONARQUBE_LOGIN}" \
151
- -Dsonar.ruby.coverage.reportPaths=coverage/coverage.json
150
+ -Dsonar.login="${SONARQUBE_LOGIN}"
151
+ run_tests:
152
+ steps:
153
+ - run:
154
+ name: Run Tests
155
+ command: |
156
+ mkdir _junit
157
+ bundle exec rake
158
+ - store_test_results:
159
+ path: ~/_junit
152
160
  run_rubocop:
153
161
  steps:
154
162
  - run:
@@ -201,6 +209,7 @@ jobs:
201
209
  - checkout
202
210
  - setup
203
211
  - run_rubocop
212
+ - run_sonarqube
204
213
  publish:
205
214
  executor: ruby_27
206
215
  steps:
@@ -0,0 +1,39 @@
1
+ name: Bug Report
2
+ description: File a bug report
3
+ title: "[Bug]: "
4
+ labels: [bug]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Thank you for taking the time to fill out this report. Remember that these issues are public and if you need to discuss implementation specific issues securely, please [use our support portal](https://support.instana.com/hc/en-us).
10
+ - type: textarea
11
+ id: problem-description
12
+ attributes:
13
+ label: Problem Description
14
+ description: What was the issue that caused you to file this bug?
15
+ validations:
16
+ required: true
17
+ - type: textarea
18
+ id: mcve
19
+ attributes:
20
+ label: Minimal, Complete, Verifiable, Example
21
+ description: Can you provide steps needed to reproduce this issue outside of your application?
22
+ validations:
23
+ required: false
24
+ - type: textarea
25
+ id: gemfile-lock
26
+ attributes:
27
+ label: Gemfile.lock
28
+ description: Please paste the contents of the Gemfile.lock for the application that was affected by this bug.
29
+ render: shell
30
+ validations:
31
+ required: true
32
+ - type: textarea
33
+ id: ruby-version
34
+ attributes:
35
+ label: Ruby Version
36
+ description: What version of Ruby was the application running under when it encountered this bug?
37
+ render: shell
38
+ validations:
39
+ required: true
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Instana Support Portal
4
+ url: https://support.instana.com
5
+ about: Please ask questions related to your installation there.
data/Appraisals CHANGED
@@ -6,6 +6,7 @@ appraise 'aws-30' do
6
6
  gem 'aws-sdk-s3', '~> 1.59'
7
7
  gem 'aws-sdk-sns', '~> 1.38'
8
8
  gem 'aws-sdk-sqs', '~> 1.36'
9
+ gem 'aws-sdk-lambda', '~> 1.62'
9
10
  end
10
11
 
11
12
  appraise 'cuba-30' do
data/README.md CHANGED
@@ -77,5 +77,5 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/instan
77
77
 
78
78
  ## More
79
79
 
80
- Want to instrument other languages? See our [Node.js](https://github.com/instana/nodejs-sensor), [Go](https://github.com/instana/golang-sensor), [Python](https://github.com/instana/python-sensor) repositories or [many other supported technologies](https://www.instana.com/supported-technologies/).
80
+ Want to instrument other languages? See our [Node.js](https://github.com/instana/nodejs), [Go](https://github.com/instana/golang-sensor), [Python](https://github.com/instana/python-sensor) repositories or [many other supported technologies](https://www.instana.com/supported-technologies/).
81
81
 
@@ -17,5 +17,6 @@ gem "aws-sdk-dynamodb", "~> 1.59"
17
17
  gem "aws-sdk-s3", "~> 1.59"
18
18
  gem "aws-sdk-sns", "~> 1.38"
19
19
  gem "aws-sdk-sqs", "~> 1.36"
20
+ gem "aws-sdk-lambda", "~> 1.62"
20
21
 
21
22
  gemspec path: "../"
@@ -46,11 +46,13 @@ end
46
46
  Dir["#{__dir__}/activators/*.rb"]
47
47
  .sort
48
48
  .select do |f|
49
+ # :nocov:
49
50
  if ENV['INSTANA_ACTIVATE_SET']
50
51
  base = File.basename(f, '.rb')
51
52
  ENV.fetch('INSTANA_ACTIVATE_SET', '').split(',').include?(base)
52
53
  else
53
54
  true
54
55
  end
56
+ # :nocov:
55
57
  end
56
58
  .each { |f| require(f) }
@@ -0,0 +1,22 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ module Instana
5
+ module Activators
6
+ class ActionMailer < Activator
7
+ def can_instrument?
8
+ defined?(::ActionMailer::Base)
9
+ end
10
+
11
+ def instrument
12
+ require 'instana/instrumentation/action_mailer'
13
+
14
+ ::ActionMailer::Base
15
+ .singleton_class
16
+ .prepend(Instana::Instrumentation::ActionMailer)
17
+
18
+ true
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,21 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ module Instana
5
+ module Activators
6
+ class ActiveJob < Activator
7
+ def can_instrument?
8
+ defined?(::ActiveJob::Base)
9
+ end
10
+
11
+ def instrument
12
+ require 'instana/instrumentation/active_job'
13
+
14
+ ::ActiveJob::Base
15
+ .prepend(Instana::Instrumentation::ActiveJob)
16
+
17
+ true
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ module Instana
5
+ module Activators
6
+ class AwsSdkLambda < Activator
7
+ def can_instrument?
8
+ defined?(::Aws::Lambda::Client) && ::Aws::Lambda::Client.respond_to?(:add_plugin)
9
+ end
10
+
11
+ def instrument
12
+ require 'instana/instrumentation/aws_sdk_lambda'
13
+
14
+ ::Aws::Lambda::Client.add_plugin(Instana::Instrumentation::Lambda)
15
+
16
+ true
17
+ end
18
+ end
19
+ end
20
+ end
@@ -49,11 +49,10 @@ module Instana
49
49
  response = @client.send_request('POST', path, spans)
50
50
 
51
51
  unless response.ok?
52
+ @logger.debug("Sent `#{spans.count}` spans to `#{path}` and got `#{response.code}`.")
52
53
  @discovery.swap { nil }
53
54
  break
54
55
  end
55
-
56
- @logger.debug("Sent `#{spans.count}` spans to `#{path}` and got `#{response.code}`.")
57
56
  end
58
57
  end
59
58
 
@@ -68,10 +67,9 @@ module Instana
68
67
  if response.ok?
69
68
  handle_agent_tasks(response, discovery) unless response.body.empty?
70
69
  else
70
+ @logger.debug("Sent `#{payload}` to `#{path}` and got `#{response.code}`.")
71
71
  @discovery.swap { nil }
72
72
  end
73
-
74
- @logger.debug("Sent `#{payload}` to `#{path}` and got `#{response.code}`.")
75
73
  end
76
74
 
77
75
  def handle_agent_tasks(response, discovery)
@@ -27,6 +27,9 @@ module Instana
27
27
  # Enable/disable tracing (default: enabled)
28
28
  @config[:tracing] = { :enabled => true }
29
29
 
30
+ # Enable/Disable logging
31
+ @config[:logging] = { :enabled => true }
32
+
30
33
  # Collector interval
31
34
  @config[:collector] = { :enabled => true, :interval => 1 }
32
35
 
@@ -64,7 +67,7 @@ module Instana
64
67
  @config[:graphql] = { :enabled => true }
65
68
  @config[:nethttp] = { :enabled => true }
66
69
  @config[:redis] = { :enabled => true }
67
- @config[:'resque-client'] = { :enabled => true }
70
+ @config[:'resque-client'] = { :enabled => true, :propagate => true }
68
71
  @config[:'resque-worker'] = { :enabled => true, :'setup-fork' => true }
69
72
  @config[:'rest-client'] = { :enabled => true }
70
73
  @config[:'sidekiq-client'] = { :enabled => true }
@@ -3,9 +3,6 @@
3
3
 
4
4
  if ::Rails::VERSION::MAJOR < 3
5
5
  ::Rails.configuration.after_initialize do
6
- # In Rails, let's use the Rails logger
7
- ::Instana.logger = ::Rails.logger if ::Rails.logger
8
-
9
6
  if ::Instana.config[:tracing][:enabled]
10
7
  ::Instana.logger.debug "Instrumenting Rack"
11
8
  ::Rails.configuration.middleware.insert 0, ::Instana::Rack
@@ -17,8 +14,11 @@ else
17
14
  module ::Instana
18
15
  class Railtie < ::Rails::Railtie
19
16
  initializer 'instana.rack' do |app|
20
- # In Rails, let's use the Rails logger
21
- ::Instana.logger = ::Rails.logger if ::Rails.logger
17
+ # Configure the Instrumented Logger
18
+ if ::Instana.config[:logging][:enabled] && !ENV.key?('INSTANA_TEST')
19
+ logger = ::Instana::InstrumentedLogger.new('/dev/null')
20
+ Rails.logger.extend(ActiveSupport::Logger.broadcast(logger))
21
+ end
22
22
 
23
23
  if ::Instana.config[:tracing][:enabled]
24
24
  ::Instana.logger.debug "Instrumenting Rack"
@@ -0,0 +1,22 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ module Instana
5
+ module Instrumentation
6
+ module ActionMailer
7
+ def method_missing(method_name, *args) # rubocop:disable Style/MissingRespondToMissing
8
+ if action_methods.include?(method_name.to_s)
9
+ tags = {
10
+ actionmailer: {
11
+ class: to_s,
12
+ method: method_name.to_s
13
+ }
14
+ }
15
+ Instana::Tracer.trace(:'mail.actionmailer', tags) { super }
16
+ else
17
+ super
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,52 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ module Instana
5
+ module Instrumentation
6
+ module ActiveJob
7
+ def self.prepended(target)
8
+ target.around_enqueue do |job, block|
9
+ tags = {
10
+ activejob: {
11
+ queue: job.queue_name,
12
+ job: job.class.to_s,
13
+ action: :enqueue,
14
+ job_id: job.job_id
15
+ }
16
+ }
17
+
18
+ ::Instana::Tracer.trace(:activejob, tags) do
19
+ context = ::Instana.tracer.context
20
+ job.arguments = [{
21
+ given_arguments: job.arguments,
22
+ instana_context: context ? context.to_hash : nil
23
+ }]
24
+
25
+ block.call
26
+ end
27
+ end
28
+
29
+ target.around_perform do |job, block|
30
+ tags = {
31
+ activejob: {
32
+ queue: job.queue_name,
33
+ job: job.class.to_s,
34
+ action: :perform,
35
+ job_id: job.job_id
36
+ }
37
+ }
38
+
39
+ incoming_context = if job.arguments.is_a?(Array) && job.arguments.first.is_a?(Hash)
40
+ instana_context = job.arguments.first[:instana_context]
41
+ job.arguments = job.arguments.first[:given_arguments]
42
+ instana_context ? ::Instana::SpanContext.new(instana_context[:trace_id], instana_context[:span_id]) : nil
43
+ end
44
+
45
+ ::Instana::Tracer.start_or_continue_trace(:activejob, tags, incoming_context) do
46
+ block.call
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,37 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+ require 'base64'
4
+
5
+ module Instana
6
+ module Instrumentation
7
+ class Lambda < Seahorse::Client::Plugin
8
+ class Handler < Seahorse::Client::Handler
9
+ def call(context)
10
+ return @handler.call(context) unless [:invoke_async, :invoke].include?(context.operation_name)
11
+
12
+ if context.params[:client_context].nil? && ::Instana.tracer.tracing? && context.operation_name == :invoke
13
+ span_context = ::Instana.tracer.context
14
+ payload = {
15
+ 'X-INSTANA-T' => span_context.trace_id,
16
+ 'X-INSTANA-S' => span_context.span_id,
17
+ 'X-INSTANA-L' => span_context.level.to_s
18
+ }
19
+
20
+ context.params[:client_context] = JSON.dump(payload)
21
+ end
22
+
23
+ tags = {
24
+ function: context.params[:function_name],
25
+ type: context.params[:invocation_type]
26
+ }.reject { |_, v| v.nil? }
27
+
28
+ ::Instana.tracer.trace(:"aws.lambda.invoke", {aws: {lambda: {invoke: tags}}}) { @handler.call(context) }
29
+ end
30
+ end
31
+
32
+ def add_handlers(handlers, _config)
33
+ handlers.add(Handler, step: :initialize)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -28,6 +28,7 @@ module Instana
28
28
  kvs = collect_kvs(:enqueue, klass, args)
29
29
 
30
30
  Instana.tracer.trace(:'resque-client', kvs) do
31
+ args.push(::Instana.tracer.context.to_hash) if ::Instana.config[:'resque-client'][:propagate]
31
32
  super(klass, *args)
32
33
  end
33
34
  else
@@ -41,6 +42,7 @@ module Instana
41
42
  kvs[:Queue] = queue.to_s if queue
42
43
 
43
44
  Instana.tracer.trace(:'resque-client', kvs) do
45
+ args.push(::Instana.tracer.context.to_hash) if ::Instana.config[:'resque-client'][:propagate]
44
46
  super(queue, klass, *args)
45
47
  end
46
48
  else
@@ -76,7 +78,15 @@ module Instana
76
78
  ::Instana.logger.debug { "#{__method__}:#{File.basename(__FILE__)}:#{__LINE__}: #{e.message}" } if Instana::Config[:verbose]
77
79
  end
78
80
 
79
- Instana.tracer.start_or_continue_trace(:'resque-worker', kvs) do
81
+ trace_context = if ::Instana.config[:'resque-client'][:propagate] && job.payload['args'][-1].is_a?(Hash) && job.payload['args'][-1].keys.include?('trace_id')
82
+ context_from_wire = job.payload['args'].pop
83
+ ::Instana::SpanContext.new(
84
+ context_from_wire['trace_id'],
85
+ context_from_wire['span_id']
86
+ )
87
+ end
88
+
89
+ Instana.tracer.start_or_continue_trace(:'resque-worker', kvs, trace_context) do
80
90
  super(job)
81
91
  end
82
92
  end
@@ -0,0 +1,26 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ module Instana
5
+ class InstrumentedLogger < Logger
6
+ LEVEL_LABELS = %w[Debug Info Warn Error Fatal Any].freeze
7
+
8
+ def instana_log_level
9
+ WARN
10
+ end
11
+
12
+ def add(severity, message = nil, progname = nil)
13
+ severity ||= UNKNOWN
14
+
15
+ if severity >= instana_log_level && ::Instana.tracer.tracing?
16
+ tags = {
17
+ level: LEVEL_LABELS[severity],
18
+ message: "#{message} #{progname}".strip
19
+ }
20
+ Instana::Tracer.trace(:log, {log: tags}) {}
21
+ end
22
+
23
+ super(severity, message, progname)
24
+ end
25
+ end
26
+ end
@@ -23,7 +23,7 @@ module Instana
23
23
 
24
24
  def wrap_aws(event, context, &block)
25
25
  Thread.current[:instana_function_arn] = [context.invoked_function_arn, context.function_version].join(':')
26
- trigger, event_tags, span_context = trigger_from_event(event)
26
+ trigger, event_tags, span_context = trigger_from_event(event, context)
27
27
 
28
28
  tags = {
29
29
  lambda: {
@@ -53,7 +53,7 @@ module Instana
53
53
 
54
54
  private
55
55
 
56
- def trigger_from_event(event) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
56
+ def trigger_from_event(event, context) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
57
57
  case event
58
58
  when ->(e) { defined?(::Instana::InstrumentedRequest) && e.is_a?(Hash) && e.key?('requestContext') && e['requestContext'].key?('elb') }
59
59
  request = InstrumentedRequest.new(event_to_rack(event))
@@ -74,7 +74,28 @@ module Instana
74
74
  tags = decode_sqs(event)
75
75
  ['aws:sqs', {sqs: tags}, {}]
76
76
  else
77
- ['aws:api.gateway.noproxy', {}, {}]
77
+ ctx = context_from_lambda_context(context)
78
+ if ctx.empty?
79
+ ['aws:api.gateway.noproxy', {}, {}]
80
+ else
81
+ ['aws.lambda.invoke', {}, ctx]
82
+ end
83
+ end
84
+ end
85
+
86
+ def context_from_lambda_context(context)
87
+ return {} unless context.client_context
88
+
89
+ begin
90
+ context = JSON.parse(Base64.decode64(context.client_context))
91
+
92
+ {
93
+ trace_id: context['X-INSTANA-T'],
94
+ span_id: context['X-INSTANA-S'],
95
+ level: Integer(context['X-INSTANA-L'])
96
+ }
97
+ rescue TypeError, JSON::ParserError, NoMethodError => _e
98
+ {}
78
99
  end
79
100
  end
80
101
 
data/lib/instana/setup.rb CHANGED
@@ -1,10 +1,12 @@
1
1
  # (c) Copyright IBM Corp. 2021
2
2
  # (c) Copyright Instana Inc. 2016
3
3
 
4
+ require 'logger'
4
5
  require 'concurrent'
5
6
  require 'sys-proctable'
6
7
 
7
8
  require 'instana/logger_delegator'
9
+ require 'instana/instrumented_logger'
8
10
 
9
11
  require "instana/base"
10
12
  require "instana/config"
@@ -2,6 +2,7 @@
2
2
  # (c) Copyright Instana Inc. 2016
3
3
 
4
4
  require 'thread'
5
+ require 'forwardable'
5
6
 
6
7
  module Instana
7
8
  class Processor
@@ -6,10 +6,13 @@ 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, :'aws.lambda.entry' ].freeze
10
- ENTRY_SPANS = [ :rack, :'resque-worker', :'rpc-server', :'sidekiq-worker', :'graphql.server', :sqs, :'aws.lambda.entry' ].freeze
9
+ :redis, :'resque-client', :'resque-worker', :'graphql.server', :dynamodb, :s3, :sns, :sqs, :'aws.lambda.entry', :activejob, :log, :"mail.actionmailer",
10
+ :"aws.lambda.invoke" ].freeze
11
+ ENTRY_SPANS = [ :rack, :'resque-worker', :'rpc-server', :'sidekiq-worker', :'graphql.server', :sqs,
12
+ :'aws.lambda.entry' ].freeze
11
13
  EXIT_SPANS = [ :activerecord, :excon, :'net-http', :'resque-client',
12
- :'rpc-client', :'sidekiq-client', :redis, :dynamodb, :s3, :sns, :sqs ].freeze
14
+ :'rpc-client', :'sidekiq-client', :redis, :dynamodb, :s3, :sns, :sqs, :log, :"mail.actionmailer",
15
+ :"aws.lambda.invoke" ].freeze
13
16
  HTTP_SPANS = [ :rack, :excon, :'net-http' ].freeze
14
17
 
15
18
  attr_accessor :parent
@@ -2,6 +2,6 @@
2
2
  # (c) Copyright Instana Inc. 2016
3
3
 
4
4
  module Instana
5
- VERSION = "1.201.0.pre1"
5
+ VERSION = "1.203.2"
6
6
  VERSION_FULL = "instana-#{VERSION}"
7
7
  end
@@ -158,4 +158,39 @@ class AwsTest < Minitest::Test
158
158
  assert_equal send_span[:s], message.message_attributes['X_INSTANA_S'].string_value
159
159
  assert_equal 'Sample', message.body
160
160
  end
161
+
162
+ def test_lambda
163
+ stub_request(:post, "https://lambda.local.amazonaws.com/2015-03-31/functions/Test/invocations")
164
+ .with(
165
+ body: "data",
166
+ headers: {
167
+ 'X-Amz-Client-Context' => /.+/
168
+ }
169
+ )
170
+ .to_return(status: 200, body: "", headers: {})
171
+
172
+ lambda = Aws::Lambda::Client.new(
173
+ endpoint: 'https://lambda.local.amazonaws.com',
174
+ region: 'local',
175
+ access_key_id: "test",
176
+ secret_access_key: "test"
177
+ )
178
+
179
+ Instana::Tracer.start_or_continue_trace(:lambda_test, {}) do
180
+ lambda.invoke(
181
+ function_name: 'Test',
182
+ invocation_type: 'Event',
183
+ payload: 'data'
184
+ )
185
+ end
186
+
187
+ spans = ::Instana.processor.queued_spans
188
+ lambda_span, _entry_span, *rest = spans
189
+
190
+ assert rest.empty?
191
+
192
+ assert_equal :"aws.lambda.invoke", lambda_span[:n]
193
+ assert_equal 'Test', lambda_span[:data][:aws][:lambda][:invoke][:function]
194
+ assert_equal 'Event', lambda_span[:data][:aws][:lambda][:invoke][:type]
195
+ end
161
196
  end
@@ -0,0 +1,37 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ require 'test_helper'
5
+ require 'action_mailer'
6
+
7
+ class RailsActionMailerTest < Minitest::Test
8
+ class TestMailer < ActionMailer::Base
9
+ def sample_email
10
+ mail(
11
+ from: 'test@example.com',
12
+ to: 'test@example.com',
13
+ subject: 'Test Email',
14
+ body: 'Hello',
15
+ content_type: "text/html"
16
+ )
17
+ end
18
+ end
19
+
20
+ def setup
21
+ TestMailer.delivery_method = :sendmail
22
+
23
+ clear_all!
24
+ end
25
+
26
+ def test_mailer
27
+ Instana.tracer.start_or_continue_trace(:test) do
28
+ TestMailer.sample_email.deliver_now
29
+ end
30
+
31
+ mail_span, = *::Instana.processor.queued_spans
32
+
33
+ assert_equal :"mail.actionmailer", mail_span[:n]
34
+ assert_equal 'RailsActionMailerTest::TestMailer', mail_span[:data][:actionmailer][:class]
35
+ assert_equal 'sample_email', mail_span[:data][:actionmailer][:method]
36
+ end
37
+ end
@@ -0,0 +1,65 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ require 'test_helper'
5
+
6
+ require 'rails'
7
+ require 'active_job'
8
+
9
+ class RailsActiveJobTest < Minitest::Test
10
+ class SampleJob < ActiveJob::Base
11
+ queue_as :test_queue
12
+
13
+ def perform(*args); end
14
+ end
15
+
16
+ def setup
17
+ @test_adapter = ActiveJob::Base.queue_adapter = ActiveJob::QueueAdapters::TestAdapter.new
18
+ ActiveJob::Base.logger = Logger.new('/dev/null')
19
+
20
+ clear_all!
21
+ end
22
+
23
+ def test_perform_now
24
+ SampleJob.perform_now("test_perform_now")
25
+ spans = ::Instana.processor.queued_spans
26
+
27
+ server_span, *rest = spans
28
+ assert_equal [], rest
29
+
30
+ assert_equal :activejob, server_span[:n]
31
+ assert_equal 'RailsActiveJobTest::SampleJob', server_span[:data][:activejob][:job]
32
+ assert_equal :perform, server_span[:data][:activejob][:action]
33
+ assert_equal 'test_queue', server_span[:data][:activejob][:queue]
34
+ end
35
+
36
+ def test_enqueue_perform
37
+ # ActiveJob::QueueAdapters::TestAdapter.new doesn't work for this test on any version less than 6
38
+ skip unless Rails::VERSION::MAJOR >= 6
39
+
40
+ Instana.tracer.start_or_continue_trace(:peform_test) do
41
+ SampleJob.perform_later("test_enqueue_perform")
42
+ end
43
+
44
+ job, *rest_jobs = @test_adapter.enqueued_jobs
45
+ assert_equal [], rest_jobs
46
+
47
+ ActiveJob::Base.execute(job)
48
+
49
+ spans = ::Instana.processor.queued_spans
50
+ client_span, _test_span, server_span, *rest = spans
51
+ assert_equal [], rest
52
+
53
+ assert_equal :activejob, server_span[:n]
54
+ assert_equal 'RailsActiveJobTest::SampleJob', server_span[:data][:activejob][:job]
55
+ assert_equal :perform, server_span[:data][:activejob][:action]
56
+
57
+ assert_equal :activejob, client_span[:n]
58
+ assert_equal 'RailsActiveJobTest::SampleJob', client_span[:data][:activejob][:job]
59
+ assert_equal :enqueue, client_span[:data][:activejob][:action]
60
+ assert_equal 'test_queue', server_span[:data][:activejob][:queue]
61
+
62
+ assert_equal client_span[:t], server_span[:t]
63
+ assert_equal client_span[:s], server_span[:p]
64
+ end
65
+ end
@@ -0,0 +1,43 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ require 'test_helper'
5
+ require 'support/apps/active_record/active_record'
6
+ require 'fileutils'
7
+
8
+ class RailsActiveRecordDatabaseMissingTest < Minitest::Test
9
+ def setup
10
+ skip unless ENV['DATABASE_URL']
11
+
12
+ @old_url = ENV['DATABASE_URL']
13
+ SQLite3::Database.new('/tmp/test.db')
14
+ ENV['DATABASE_URL'] = 'sqlite3:///tmp/test.db'
15
+
16
+ @connection = ActiveRecord::Base.establish_connection(ENV['DATABASE_URL'])
17
+ ActiveRecord::Migration.suppress_messages do
18
+ ActiveRecord::Migration.run(CreateBlocks, direction: :up)
19
+ end
20
+ end
21
+
22
+ def teardown
23
+ ActiveRecord::Base.remove_connection(@connection)
24
+ ENV['DATABASE_URL'] = @old_url
25
+ end
26
+
27
+ def test_error_on_missing_database
28
+ assert_raises(ActiveRecord::StatementInvalid) do
29
+ Instana::Tracer.start_or_continue_trace(:ar_test, {}) do
30
+ b = Block.new
31
+ FileUtils.rm('/tmp/test.db')
32
+ b.save!
33
+ end
34
+ end
35
+
36
+ spans = ::Instana.processor.queued_spans
37
+ assert_equal 3, spans.length
38
+ span = find_first_span_by_name(spans, :activerecord)
39
+
40
+ assert_equal 1, span[:ec]
41
+ assert span[:data][:activerecord][:error].include?("SQLite3::ReadOnlyException: attempt to write a readonly database")
42
+ end
43
+ end
@@ -22,6 +22,7 @@ class ResqueClientTest < Minitest::Test
22
22
  ::Resque.enqueue(FastJob)
23
23
  end
24
24
 
25
+ resque_job = Resque.reserve('critical')
25
26
  spans = ::Instana.processor.queued_spans
26
27
  assert_equal 2, spans.length
27
28
 
@@ -34,6 +35,9 @@ class ResqueClientTest < Minitest::Test
34
35
  assert_equal "FastJob", resque_span[:data][:'resque-client'][:job]
35
36
  assert_equal :critical, resque_span[:data][:'resque-client'][:queue]
36
37
  assert_equal false, resque_span[:data][:'resque-client'].key?(:error)
38
+
39
+ assert_equal resque_job.args.first['trace_id'], resque_span[:t]
40
+ assert_equal resque_job.args.first['span_id'], resque_span[:s]
37
41
  end
38
42
 
39
43
  def test_enqueue_to
@@ -41,6 +45,7 @@ class ResqueClientTest < Minitest::Test
41
45
  ::Resque.enqueue_to(:critical, FastJob)
42
46
  end
43
47
 
48
+ resque_job = Resque.reserve('critical')
44
49
  spans = ::Instana.processor.queued_spans
45
50
  assert_equal 2, spans.length
46
51
 
@@ -52,6 +57,9 @@ class ResqueClientTest < Minitest::Test
52
57
  assert_equal "FastJob", resque_span[:data][:'resque-client'][:job]
53
58
  assert_equal :critical, resque_span[:data][:'resque-client'][:queue]
54
59
  assert_equal false, resque_span[:data][:'resque-client'].key?(:error)
60
+
61
+ assert_equal resque_job.args.first['trace_id'], resque_span[:t]
62
+ assert_equal resque_job.args.first['span_id'], resque_span[:s]
55
63
  end
56
64
 
57
65
  def test_dequeue
@@ -73,17 +81,58 @@ class ResqueClientTest < Minitest::Test
73
81
  end
74
82
 
75
83
  def test_worker_job
76
- Resque::Job.create(:critical, FastJob)
77
- @worker.work(0)
84
+ ::Instana.tracer.start_or_continue_trace(:'resque-client_test') do
85
+ ::Resque.enqueue_to(:critical, FastJob)
86
+ end
87
+
88
+ resque_job = Resque.reserve('critical')
89
+ @worker.work_one_job(resque_job)
90
+
91
+ spans = ::Instana.processor.queued_spans
92
+ assert_equal 5, spans.length
93
+
94
+ client_span = spans[0]
95
+ resque_span = spans[4]
96
+ redis1_span = spans[3]
97
+ redis2_span = spans[2]
98
+
99
+ assert_equal :'resque-client', client_span[:n]
100
+
101
+ assert_equal :'resque-worker', resque_span[:n]
102
+ assert_equal client_span[:s], resque_span[:p]
103
+ assert_equal false, resque_span.key?(:error)
104
+ assert_equal false, resque_span.key?(:ec)
105
+ assert_equal "FastJob", resque_span[:data][:'resque-worker'][:job]
106
+ assert_equal "critical", resque_span[:data][:'resque-worker'][:queue]
107
+ assert_equal false, resque_span[:data][:'resque-worker'].key?(:error)
108
+
109
+ assert_equal :redis, redis1_span[:n]
110
+ assert_equal "SET", redis1_span[:data][:redis][:command]
111
+ assert_equal :redis, redis2_span[:n]
112
+ assert_equal "SET", redis2_span[:data][:redis][:command]
113
+ end
114
+
115
+ def test_worker_job_no_propagate
116
+ ::Instana.config[:'resque-client'][:propagate] = false
117
+ ::Instana.tracer.start_or_continue_trace(:'resque-client_test') do
118
+ ::Resque.enqueue_to(:critical, FastJob)
119
+ end
120
+
121
+ resque_job = Resque.reserve('critical')
122
+ @worker.work_one_job(resque_job)
78
123
 
79
124
  spans = ::Instana.processor.queued_spans
80
- assert_equal 3, spans.length
125
+ assert_equal 5, spans.length
126
+
127
+ client_span = spans[0]
128
+ resque_span = spans[4]
129
+ redis1_span = spans[3]
130
+ redis2_span = spans[2]
81
131
 
82
- resque_span = spans[2]
83
- redis1_span = spans[1]
84
- redis2_span = spans[0]
132
+ assert_equal :'resque-client', client_span[:n]
85
133
 
86
134
  assert_equal :'resque-worker', resque_span[:n]
135
+ refute_equal client_span[:s], resque_span[:p]
87
136
  assert_equal false, resque_span.key?(:error)
88
137
  assert_equal false, resque_span.key?(:ec)
89
138
  assert_equal "FastJob", resque_span[:data][:'resque-worker'][:job]
@@ -94,6 +143,8 @@ class ResqueClientTest < Minitest::Test
94
143
  assert_equal "SET", redis1_span[:data][:redis][:command]
95
144
  assert_equal :redis, redis2_span[:n]
96
145
  assert_equal "SET", redis2_span[:data][:redis][:command]
146
+ ensure
147
+ ::Instana.config[:'resque-client'][:propagate] = true
97
148
  end
98
149
 
99
150
  def test_worker_error_job
@@ -320,4 +320,50 @@ class ServerlessTest < Minitest::Test
320
320
 
321
321
  assert_equal 'test_arn', data[:messages].first[:queue]
322
322
  end
323
+
324
+ def test_lambda_client_context
325
+ clear_all!
326
+
327
+ mock_context = OpenStruct.new(
328
+ invoked_function_arn: 'test_arn',
329
+ function_name: 'test_function',
330
+ function_version: '$TEST',
331
+ client_context: "eyJYLUlOU1RBTkEtVCI6IjEyMyIsIlgtSU5TVEFOQS1TIjoiNDU2IiwiWC1J\nTlNUQU5BLUwiOiIxIn0=\n"
332
+ )
333
+ mock_event = {
334
+ "Invoked" => true
335
+ }
336
+
337
+ @subject.wrap_aws(mock_event, mock_context) { 0 }
338
+
339
+ lambda_span, *rest = Instana.processor.queued_spans
340
+ assert rest.empty?
341
+
342
+ assert_equal 'aws.lambda.invoke', lambda_span[:data][:lambda][:trigger]
343
+ assert_equal '123', lambda_span[:t]
344
+ assert_equal '456', lambda_span[:p]
345
+ end
346
+
347
+ def test_lambda_client_context_error
348
+ clear_all!
349
+
350
+ mock_context = OpenStruct.new(
351
+ invoked_function_arn: 'test_arn',
352
+ function_name: 'test_function',
353
+ function_version: '$TEST',
354
+ client_context: "eyJYLUlOU1RBkEtVCI6IjEyMyIsIlgtSU5TVEFOQS1TIjoiNDU2IiwiWC1J\nTlNUQU5BLUwiOiIxIn0=\n"
355
+ )
356
+ mock_event = {
357
+ "Invoked" => true
358
+ }
359
+
360
+ @subject.wrap_aws(mock_event, mock_context) { 0 }
361
+
362
+ lambda_span, *rest = Instana.processor.queued_spans
363
+ assert rest.empty?
364
+
365
+ refute_equal 'aws.lambda.invoke', lambda_span[:data][:lambda][:trigger]
366
+ refute_equal '123', lambda_span[:t]
367
+ refute_equal '456', lambda_span[:p]
368
+ end
323
369
  end
@@ -7,7 +7,9 @@ require "net/http"
7
7
  class FastJob
8
8
  @queue = :critical
9
9
 
10
- def self.perform
10
+ def self.perform(*args)
11
+ raise 'Invalid Args' unless args.empty?
12
+
11
13
  if ENV.key?('REDIS_URL')
12
14
  redis = Redis.new(:url => ENV['REDIS_URL'])
13
15
  elsif ENV.key?('REDIS_URL')
data/test/test_helper.rb CHANGED
@@ -50,5 +50,14 @@ WebMock.disable_net_connect!(
50
50
 
51
51
  Dir['test/support/*.rb'].each { |f| load(f) }
52
52
 
53
- Minitest::Reporters.use! MiniTest::Reporters::SpecReporter.new
53
+ if ENV['CI']
54
+ Minitest::Reporters.use!([
55
+ Minitest::Reporters::JUnitReporter.new('_junit', false),
56
+ Minitest::Reporters::SpecReporter.new
57
+ ])
58
+ else
59
+ Minitest::Reporters.use!([
60
+ MiniTest::Reporters::SpecReporter.new
61
+ ])
62
+ end
54
63
  Minitest::Test.include(Instana::TestHelpers)
@@ -0,0 +1,39 @@
1
+ # (c) Copyright IBM Corp. 2021
2
+ # (c) Copyright Instana Inc. 2021
3
+
4
+ require 'test_helper'
5
+
6
+ class InstrumentedLoggerTest < Minitest::Test
7
+ def setup
8
+ clear_all!
9
+ end
10
+
11
+ def test_log_warn_error
12
+ subject = Instana::InstrumentedLogger.new('/dev/null')
13
+
14
+ Instana::Tracer.start_or_continue_trace(:test_logging) do
15
+ subject.warn('warn')
16
+ subject.debug('test')
17
+ subject.error('error')
18
+ end
19
+
20
+ spans = ::Instana.processor.queued_spans
21
+
22
+ warn_span, error_span, = *spans
23
+
24
+ assert_equal :log, warn_span[:n]
25
+ assert_equal 'warn', warn_span[:data][:log][:message]
26
+ assert_equal 'Warn', warn_span[:data][:log][:level]
27
+
28
+ assert_equal :log, error_span[:n]
29
+ assert_equal 'error', error_span[:data][:log][:message]
30
+ assert_equal 'Error', error_span[:data][:log][:level]
31
+ end
32
+
33
+ def test_no_trace
34
+ subject = Instana::InstrumentedLogger.new('/dev/null')
35
+ subject.warn('warn')
36
+
37
+ assert_equal [], ::Instana.processor.queued_spans
38
+ end
39
+ 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.201.0.pre1
4
+ version: 1.203.2
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-06-08 00:00:00.000000000 Z
11
+ date: 2021-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -135,6 +135,8 @@ files:
135
135
  - ".codeclimate.yml"
136
136
  - ".editorconfig"
137
137
  - ".fasterer.yml"
138
+ - ".github/ISSUE_TEMPLATE/bug.yml"
139
+ - ".github/ISSUE_TEMPLATE/config.yml"
138
140
  - ".gitignore"
139
141
  - ".rubocop.yml"
140
142
  - ".rubocop_todo.yml"
@@ -182,9 +184,12 @@ files:
182
184
  - lib/instana/activators/action_cable.rb
183
185
  - lib/instana/activators/action_controller_api.rb
184
186
  - lib/instana/activators/action_controller_base.rb
187
+ - lib/instana/activators/action_mailer.rb
185
188
  - lib/instana/activators/action_view.rb
189
+ - lib/instana/activators/active_job.rb
186
190
  - lib/instana/activators/active_record.rb
187
191
  - lib/instana/activators/aws_sdk_dynamodb.rb
192
+ - lib/instana/activators/aws_sdk_lambda.rb
188
193
  - lib/instana/activators/aws_sdk_s3.rb
189
194
  - lib/instana/activators/aws_sdk_sns.rb
190
195
  - lib/instana/activators/aws_sdk_sqs.rb
@@ -223,9 +228,12 @@ files:
223
228
  - lib/instana/frameworks/sinatra.rb
224
229
  - lib/instana/instrumentation/action_cable.rb
225
230
  - lib/instana/instrumentation/action_controller.rb
231
+ - lib/instana/instrumentation/action_mailer.rb
226
232
  - lib/instana/instrumentation/action_view.rb
233
+ - lib/instana/instrumentation/active_job.rb
227
234
  - lib/instana/instrumentation/active_record.rb
228
235
  - lib/instana/instrumentation/aws_sdk_dynamodb.rb
236
+ - lib/instana/instrumentation/aws_sdk_lambda.rb
229
237
  - lib/instana/instrumentation/aws_sdk_s3.rb
230
238
  - lib/instana/instrumentation/aws_sdk_sns.rb
231
239
  - lib/instana/instrumentation/aws_sdk_sqs.rb
@@ -242,6 +250,7 @@ files:
242
250
  - lib/instana/instrumentation/shoryuken.rb
243
251
  - lib/instana/instrumentation/sidekiq-client.rb
244
252
  - lib/instana/instrumentation/sidekiq-worker.rb
253
+ - lib/instana/instrumented_logger.rb
245
254
  - lib/instana/logger_delegator.rb
246
255
  - lib/instana/open_tracing/carrier.rb
247
256
  - lib/instana/open_tracing/instana_tracer.rb
@@ -293,7 +302,10 @@ files:
293
302
  - test/instrumentation/rack_test.rb
294
303
  - test/instrumentation/rails_action_cable_test.rb
295
304
  - test/instrumentation/rails_action_controller_test.rb
305
+ - test/instrumentation/rails_action_mailer_test.rb
296
306
  - test/instrumentation/rails_action_view_test.rb
307
+ - test/instrumentation/rails_active_job_test.rb
308
+ - test/instrumentation/rails_active_record_database_missing_test.rb
297
309
  - test/instrumentation/rails_active_record_test.rb
298
310
  - test/instrumentation/redis_test.rb
299
311
  - test/instrumentation/resque_test.rb
@@ -331,6 +343,7 @@ files:
331
343
  - test/test_helper.rb
332
344
  - test/tracing/custom_test.rb
333
345
  - test/tracing/id_management_test.rb
346
+ - test/tracing/instrumented_logger_test.rb
334
347
  - test/tracing/opentracing_test.rb
335
348
  - test/tracing/processor_test.rb
336
349
  - test/tracing/span_context_test.rb
@@ -357,9 +370,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
357
370
  version: '2.1'
358
371
  required_rubygems_version: !ruby/object:Gem::Requirement
359
372
  requirements:
360
- - - ">"
373
+ - - ">="
361
374
  - !ruby/object:Gem::Version
362
- version: 1.3.1
375
+ version: '0'
363
376
  requirements: []
364
377
  rubygems_version: 3.1.6
365
378
  signing_key:
@@ -393,7 +406,10 @@ test_files:
393
406
  - test/instrumentation/rack_test.rb
394
407
  - test/instrumentation/rails_action_cable_test.rb
395
408
  - test/instrumentation/rails_action_controller_test.rb
409
+ - test/instrumentation/rails_action_mailer_test.rb
396
410
  - test/instrumentation/rails_action_view_test.rb
411
+ - test/instrumentation/rails_active_job_test.rb
412
+ - test/instrumentation/rails_active_record_database_missing_test.rb
397
413
  - test/instrumentation/rails_active_record_test.rb
398
414
  - test/instrumentation/redis_test.rb
399
415
  - test/instrumentation/resque_test.rb
@@ -431,6 +447,7 @@ test_files:
431
447
  - test/test_helper.rb
432
448
  - test/tracing/custom_test.rb
433
449
  - test/tracing/id_management_test.rb
450
+ - test/tracing/instrumented_logger_test.rb
434
451
  - test/tracing/opentracing_test.rb
435
452
  - test/tracing/processor_test.rb
436
453
  - test/tracing/span_context_test.rb