instana 1.11.4 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0b2f239d9d7286752e2650375e8096e9525db098a7e5b09486e36dbd89758eb1
4
- data.tar.gz: 14ebd785f5ef8333360214ad9731583976f96c62980b6d0b7927338d25a0ca90
3
+ metadata.gz: 7f4a95f79f6ce7a30fe5f54797a8a47637dd659345043155c13eec90a8fe221c
4
+ data.tar.gz: 8206b32f50dd0f80386854ec216414cb976f3045ba113e5a86f161cba87a4736
5
5
  SHA512:
6
- metadata.gz: f2e560309027517414f4358421b5e9f0579254e9479cbe263c7fdd89440d924ef416a90ef2b7ff25eb7cbb3bffb3f630338d590363451de877eb9d9c70a46c32
7
- data.tar.gz: 0e8612accc07577a4951fddde76e77789714b67ee2e749b167f18ae39f3b8e4947e65fa3f4d35cd7a9af350e9ce65fcec0119f8494760b5f8be855c792cbe229
6
+ metadata.gz: 9eada422ab4a40b7566fa1ae44614efc0ca2874ba0018fecd494ec01e31d1fa66c3a5ba18f86d6ded8089cbad85b196a21b57eaa79a17372ae954385c9ddfd7e
7
+ data.tar.gz: ffa1dd9e0eac0d0041945d1ddd10ecfcb813c82dcfa5aa241302838c02af17a015457af0344654bb77cc6ffb245958c8ab712c9eab450fbb627fa185ab591075
@@ -0,0 +1,168 @@
1
+ version: 2.1
2
+
3
+ # More about orbs: https://circleci.com/docs/2.0/using-orbs/
4
+ orbs:
5
+ ruby: circleci/ruby@1.1.2
6
+
7
+ commands:
8
+ prelim-deps:
9
+ steps:
10
+ - run:
11
+ name: Preliminary Dependencies
12
+ command: |
13
+ gem update --system
14
+ gem --version
15
+ gem install bundler
16
+ bundler --version
17
+ bundle config set path './vendor/bundle'
18
+
19
+ run-tests:
20
+ steps:
21
+ - run:
22
+ name: Run the Tests
23
+ command: |
24
+ bundle exec rake test
25
+
26
+ save-stan-cache:
27
+ parameters:
28
+ gemfile:
29
+ default: "Gemfile"
30
+ type: string
31
+ steps:
32
+ - save_cache:
33
+ key: gem-cache-v1-{{ arch }}-{{ .Branch }}-{{ checksum "<<parameters.gemfile>>" }}
34
+ paths:
35
+ - vendor/bundle
36
+
37
+ restore-stan-cache:
38
+ parameters:
39
+ gemfile:
40
+ default: "Gemfile"
41
+ type: string
42
+ steps:
43
+ - restore_cache:
44
+ keys:
45
+ - gem-cache-v1-{{ arch }}-{{ .Branch }}-{{ checksum "<<parameters.gemfile>>" }}
46
+ - gem-cache-v1-{{ arch }}-{{ .Branch }}
47
+ - gem-cache-v1
48
+
49
+ bundle-install:
50
+ parameters:
51
+ gemfile:
52
+ default: "Gemfile"
53
+ type: string
54
+ steps:
55
+ - restore-stan-cache:
56
+ gemfile: <<parameters.gemfile>>
57
+ - run:
58
+ name: Bundle Installation
59
+ command: |
60
+ bundle install
61
+ - save-stan-cache:
62
+ gemfile: <<parameters.gemfile>>
63
+
64
+ jobs:
65
+ ruby26:
66
+ parallelism: 3
67
+ docker:
68
+ - image: circleci/ruby:2.6.3-stretch-node
69
+ executor: ruby/default
70
+ environment:
71
+ BUNDLE_JOBS: "3"
72
+ BUNDLE_RETRY: "3"
73
+
74
+ steps:
75
+ - checkout
76
+ - prelim-deps
77
+ - bundle-install
78
+ - run-tests
79
+
80
+ rails50:
81
+ parallelism: 3
82
+ docker:
83
+ - image: circleci/ruby:2.6.3-stretch-node
84
+ - image: mariadb
85
+ environment:
86
+ MYSQL_DATABASE: 'travis_ci_test'
87
+ MYSQL_USER: 'root'
88
+ MYSQL_PASSWORD: ''
89
+ MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
90
+ MYSQL_ROOT_PASSWORD: ''
91
+ MYSQL_ROOT_HOST: '%'
92
+ executor: ruby/default
93
+ environment:
94
+ BUNDLE_JOBS: "3"
95
+ BUNDLE_RETRY: "3"
96
+ BUNDLE_GEMFILE: "./gemfiles/rails50.gemfile"
97
+
98
+ steps:
99
+ - checkout
100
+ - prelim-deps
101
+ - bundle-install:
102
+ gemfile: "./gemfiles/rails50.gemfile"
103
+ - run-tests
104
+
105
+ rails60:
106
+ parallelism: 3
107
+ docker:
108
+ - image: circleci/ruby:2.6.3-stretch-node
109
+ - image: mariadb
110
+ environment:
111
+ MYSQL_DATABASE: 'travis_ci_test'
112
+ MYSQL_USER: 'root'
113
+ MYSQL_PASSWORD: ''
114
+ MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
115
+ MYSQL_ROOT_PASSWORD: ''
116
+ MYSQL_ROOT_HOST: '%'
117
+ executor: ruby/default
118
+ environment:
119
+ BUNDLE_JOBS: "3"
120
+ BUNDLE_RETRY: "3"
121
+ BUNDLE_GEMFILE: "./gemfiles/rails60.gemfile"
122
+
123
+ steps:
124
+ - checkout
125
+ - prelim-deps
126
+ - bundle-install:
127
+ gemfile: "./gemfiles/rails60.gemfile"
128
+ - run-tests
129
+
130
+ libraries:
131
+ parallelism: 3
132
+ docker:
133
+ - image: circleci/ruby:2.6.3-stretch-node
134
+ - image: mariadb
135
+ environment:
136
+ MYSQL_DATABASE: 'travis_ci_test'
137
+ MYSQL_USER: 'root'
138
+ MYSQL_PASSWORD: ''
139
+ MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
140
+ MYSQL_ROOT_PASSWORD: ''
141
+ MYSQL_ROOT_HOST: '%'
142
+ - image: memcached
143
+ - image: postgres
144
+ environment:
145
+ POSTGRES_USER: 'stan'
146
+ POSTGRES_PASSWORD: 'stanlikesdata'
147
+ - image: redis
148
+ executor: ruby/default
149
+ environment:
150
+ BUNDLE_JOBS: "3"
151
+ BUNDLE_RETRY: "3"
152
+ BUNDLE_GEMFILE: "./gemfiles/libraries.gemfile"
153
+
154
+ steps:
155
+ - checkout
156
+ - prelim-deps
157
+ - bundle-install:
158
+ gemfile: "./gemfiles/libraries.gemfile"
159
+ - run-tests
160
+
161
+ workflows:
162
+ version: 2
163
+ whole-enchilada-MRI26:
164
+ jobs:
165
+ - ruby26
166
+ - rails50
167
+ - rails60
168
+ - libraries
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <div align="center">
2
- <img src="http://www.instana.com/wp-content/uploads/2016/11/Instana-Infrastructure-Map-1-1024x551.png"/>
2
+ <img src="https://disznc.s3.amazonaws.com/Ruby-Dashboard-2020-02-10-at-2.31.36-PM.png"/>
3
3
  </div>
4
4
 
5
5
  # Instana
@@ -1,6 +1,39 @@
1
1
  require "instana/rack"
2
2
 
3
+ module Instana
4
+ module CubaPathTemplateExtractor
5
+ REPLACE_TARGET = /:(?<term>[^\/]+)/i
6
+
7
+ def self.prepended(base)
8
+ ::Instana.logger.debug "#{base} prepended #{self}"
9
+ end
10
+
11
+ def on(*args, &blk)
12
+ wrapper = lambda do |*caputres|
13
+ env['INSTANA_PATH_TEMPLATE_FRAGMENTS'] << args
14
+ .select { |a| a.is_a?(String) }
15
+ .join('/')
16
+
17
+ blk.call(*captures)
18
+ end
19
+
20
+ super(*args, &wrapper)
21
+ end
22
+
23
+ def call!(env)
24
+ env['INSTANA_PATH_TEMPLATE_FRAGMENTS'] = []
25
+ response = super(env)
26
+ env['INSTANA_HTTP_PATH_TEMPLATE'] = env['INSTANA_PATH_TEMPLATE_FRAGMENTS']
27
+ .join('/')
28
+ .gsub(REPLACE_TARGET, '{\k<term>}')
29
+ response
30
+ end
31
+ end
32
+ end
33
+
34
+
3
35
  if defined?(::Cuba)
4
36
  ::Instana.logger.debug "Instrumenting Cuba"
5
37
  Cuba.use ::Instana::Rack
38
+ Cuba.prepend ::Instana::CubaPathTemplateExtractor
6
39
  end
@@ -64,6 +64,15 @@ module Instana
64
64
  end
65
65
  name
66
66
  end
67
+
68
+ def matched_path_template
69
+ Rails.application.routes.router.recognize(request) do |route, _, _|
70
+ path = route.path
71
+ return path.spec.to_s
72
+ end
73
+
74
+ nil
75
+ end
67
76
  end
68
77
 
69
78
  # Used in ActionPack versions 5 and beyond, this module provides
@@ -83,6 +92,7 @@ module Instana
83
92
  ::Instana.tracer.log_entry(:actioncontroller, kv_payload)
84
93
 
85
94
  super(*args)
95
+ request.env['INSTANA_HTTP_PATH_TEMPLATE'] = matched_path_template
86
96
  rescue Exception => e
87
97
  ::Instana.tracer.log_error(e) unless has_rails_handler?(e)
88
98
  raise
@@ -135,6 +145,7 @@ module Instana
135
145
  ::Instana.tracer.log_entry(:actioncontroller, kv_payload)
136
146
 
137
147
  process_action_without_instana(*args)
148
+ request.env['INSTANA_HTTP_PATH_TEMPLATE'] = matched_path_template
138
149
  rescue Exception => e
139
150
  ::Instana.tracer.log_error(e) unless has_rails_handler?(e)
140
151
  raise
@@ -1,6 +1,47 @@
1
1
  require "instana/rack"
2
2
 
3
+ module Instana
4
+ module RodaPathTemplateExtractor
5
+ module RequestMethods
6
+ TERM = defined?(::Roda) ? ::Roda::RodaPlugins::Base::RequestMethods::TERM : Object
7
+
8
+ def if_match(args, &blk)
9
+ path = @remaining_path
10
+ captures = @captures.clear
11
+
12
+ if match_all(args)
13
+ (env['INSTANA_PATH_TEMPLATE_FRAGMENTS'] ||= []).concat(named_args(args, blk))
14
+ block_result(blk.(*captures))
15
+ env['INSTANA_HTTP_PATH_TEMPLATE'] = env['INSTANA_PATH_TEMPLATE_FRAGMENTS']
16
+ .join('/')
17
+ .prepend('/')
18
+ throw :halt, response.finish
19
+ else
20
+ @remaining_path = path
21
+ false
22
+ end
23
+ end
24
+
25
+ def named_args(args, blk)
26
+ parameters = blk.parameters
27
+ args.map do |a|
28
+ case a
29
+ when String
30
+ a
31
+ when TERM
32
+ nil
33
+ else
34
+ _, name = parameters.pop
35
+ "{#{name}}"
36
+ end
37
+ end.compact
38
+ end
39
+ end
40
+ end
41
+ end
42
+
3
43
  if defined?(::Roda)
4
44
  ::Instana.logger.debug "Instrumenting Roda"
5
45
  Roda.use ::Instana::Rack
46
+ Roda.plugin ::Instana::RodaPathTemplateExtractor
6
47
  end
@@ -3,7 +3,24 @@ require "instana/rack"
3
3
  # This instrumentation will insert Rack into Sinatra _and_ Padrino since
4
4
  # the latter is based on Sinatra
5
5
 
6
+ module Instana
7
+ module SinatraPathTemplateExtractor
8
+ def self.extended(base)
9
+ ::Instana.logger.debug "#{base} extended #{self}"
10
+ base.store_path_template
11
+ end
12
+
13
+ def store_path_template
14
+ after do
15
+ @env["INSTANA_HTTP_PATH_TEMPLATE"] = @env["sinatra.route"]
16
+ .sub("#{@request.request_method} ", '')
17
+ end
18
+ end
19
+ end
20
+ end
21
+
6
22
  if defined?(::Sinatra)
7
23
  ::Instana.logger.debug "Instrumenting Sinatra"
8
24
  ::Sinatra::Base.use ::Instana::Rack
25
+ ::Sinatra::Base.register ::Instana::SinatraPathTemplateExtractor
9
26
  end
@@ -8,8 +8,9 @@ module Instana
8
8
  @app = app
9
9
  end
10
10
 
11
- def call(env)
12
- kvs = { :http => {} }
11
+ def collect_kvs(env)
12
+ kvs = {}
13
+ kvs[:http] = {}
13
14
  kvs[:http][:method] = env['REQUEST_METHOD']
14
15
  kvs[:http][:url] = ::CGI.unescape(env['PATH_INFO'])
15
16
 
@@ -37,15 +38,27 @@ module Instana
37
38
  end
38
39
  }
39
40
  end
41
+ return kvs
42
+ end
40
43
 
44
+ def call(env)
41
45
  # Check incoming context
42
46
  incoming_context = {}
43
47
  if env.key?('HTTP_X_INSTANA_T')
44
48
  incoming_context[:trace_id] = ::Instana::Util.header_to_id(env['HTTP_X_INSTANA_T'])
45
49
  incoming_context[:span_id] = ::Instana::Util.header_to_id(env['HTTP_X_INSTANA_S']) if env.key?('HTTP_X_INSTANA_S')
46
50
  incoming_context[:level] = env['HTTP_X_INSTANA_L'] if env.key?('HTTP_X_INSTANA_L')
51
+
52
+ # Honor X-Instana-L
53
+ if incoming_context[:level] and incoming_context[:level].length > 0
54
+ if incoming_context[:level][0] == "0"
55
+ return @app.call(env)
56
+ end
57
+ end
47
58
  end
48
59
 
60
+ kvs = collect_kvs(env)
61
+
49
62
  ::Instana.tracer.log_start_or_continue(:rack, {}, incoming_context)
50
63
 
51
64
  status, headers, response = @app.call(env)
@@ -63,6 +76,11 @@ module Instana
63
76
  ::Instana.tracer.log_error(nil)
64
77
  end
65
78
 
79
+ # If the framework instrumentation provides a path template,
80
+ # pass it into the span here.
81
+ # See: https://www.instana.com/docs/tracing/custom-best-practices/#path-templates-visual-grouping-of-http-endpoints
82
+ kvs[:http][:path_tpl] = env['INSTANA_HTTP_PATH_TEMPLATE'] if env['INSTANA_HTTP_PATH_TEMPLATE']
83
+
66
84
  # Save the IDs before the trace ends so we can place
67
85
  # them in the response headers in the ensure block
68
86
  trace_id = ::Instana.tracer.current_span.trace_id
@@ -78,8 +96,10 @@ module Instana
78
96
  # Set reponse headers; encode as hex string
79
97
  headers['X-Instana-T'] = ::Instana::Util.id_to_header(trace_id)
80
98
  headers['X-Instana-S'] = ::Instana::Util.id_to_header(span_id)
99
+ headers['X-Instana-L'] = '1'
100
+ headers['Server-Timing'] = "intid;desc=#{::Instana::Util.id_to_header(trace_id)}"
101
+ ::Instana.tracer.log_end(:rack, kvs)
81
102
  end
82
- ::Instana.tracer.log_end(:rack, kvs)
83
103
  end
84
104
  end
85
105
  end
@@ -1,47 +1,32 @@
1
- module Instana
2
- module Instrumentation
3
- class Redis
4
- def self.get_host(client)
5
- client.host
6
- end
7
-
8
- def self.get_port(client)
9
- client.port
10
- end
11
-
12
- def self.pipeline_command(pipeline)
13
- pipeline.is_a?(::Redis::Pipeline::Multi) ? 'MULTI' : 'PIPELINE'
14
- end
15
- end
16
- end
17
- end
18
-
19
1
  if defined?(::Redis) && ::Instana.config[:redis][:enabled]
20
2
  ::Redis::Client.class_eval do
21
3
  def call_with_instana(*args, &block)
22
4
  kv_payload = { redis: {} }
5
+ dnt_spans = [:redis, :'resque-client', :'sidekiq-client']
23
6
 
24
- if !Instana.tracer.tracing?
7
+ if !Instana.tracer.tracing? || dnt_spans.include?(::Instana.tracer.current_span.name)
25
8
  return call_without_instana(*args, &block)
26
9
  end
27
10
 
28
- host = ::Instana::Instrumentation::Redis.get_host(self)
29
- port = ::Instana::Instrumentation::Redis.get_port(self)
30
- kv_payload[:redis] = {
31
- connection: "#{host}:#{port}",
32
- db: db,
33
- command: args[0][0].to_s.upcase
34
- }
35
- ::Instana.tracer.log_entry(:redis, kv_payload)
11
+ begin
12
+ ::Instana.tracer.log_entry(:redis)
13
+
14
+ begin
15
+ kv_payload[:redis][:connection] = "#{self.host}:#{self.port}"
16
+ kv_payload[:redis][:db] = db.to_s
17
+ kv_payload[:redis][:command] = args[0][0].to_s.upcase
18
+ rescue
19
+ nil
20
+ end
36
21
 
37
- call_without_instana(*args, &block)
38
- rescue => e
39
- kv_payload[:redis][:error] = true
40
- ::Instana.tracer.log_info(kv_payload)
41
- ::Instana.tracer.log_error(e)
42
- raise
43
- ensure
44
- ::Instana.tracer.log_exit(:redis, {})
22
+ call_without_instana(*args, &block)
23
+ rescue => e
24
+ ::Instana.tracer.log_info({ redis: {error: true} })
25
+ ::Instana.tracer.log_error(e)
26
+ raise
27
+ ensure
28
+ ::Instana.tracer.log_exit(:redis, kv_payload)
29
+ end
45
30
  end
46
31
 
47
32
  ::Instana.logger.debug "Instrumenting Redis"
@@ -51,29 +36,32 @@ if defined?(::Redis) && ::Instana.config[:redis][:enabled]
51
36
 
52
37
  def call_pipeline_with_instana(*args, &block)
53
38
  kv_payload = { redis: {} }
39
+ dnt_spans = [:redis, :'resque-client', :'sidekiq-client']
54
40
 
55
- if !Instana.tracer.tracing?
41
+ if !Instana.tracer.tracing? || dnt_spans.include?(::Instana.tracer.current_span.name)
56
42
  return call_pipeline_without_instana(*args, &block)
57
43
  end
58
44
 
59
- pipeline = args.first
60
- host = ::Instana::Instrumentation::Redis.get_host(self)
61
- port = ::Instana::Instrumentation::Redis.get_port(self)
62
- kv_payload[:redis] = {
63
- connection: "#{host}:#{port}",
64
- db: db,
65
- command: ::Instana::Instrumentation::Redis.pipeline_command(pipeline)
66
- }
67
- ::Instana.tracer.log_entry(:redis, kv_payload)
45
+ begin
46
+ ::Instana.tracer.log_entry(:redis)
47
+
48
+ pipeline = args.first
49
+ begin
50
+ kv_payload[:redis][:connection] = "#{self.host}:#{self.port}"
51
+ kv_payload[:redis][:db] = db.to_s
52
+ kv_payload[:redis][:command] = pipeline.is_a?(::Redis::Pipeline::Multi) ? 'MULTI' : 'PIPELINE'
53
+ rescue
54
+ nil
55
+ end
68
56
 
69
- call_pipeline_without_instana(*args, &block)
70
- rescue => e
71
- kv_payload[:redis][:error] = true
72
- ::Instana.tracer.log_info(kv_payload)
73
- ::Instana.tracer.log_error(e)
74
- raise
75
- ensure
76
- ::Instana.tracer.log_exit(:redis, {})
57
+ call_pipeline_without_instana(*args, &block)
58
+ rescue => e
59
+ ::Instana.tracer.log_info({ redis: {error: true} })
60
+ ::Instana.tracer.log_error(e)
61
+ raise
62
+ ensure
63
+ ::Instana.tracer.log_exit(:redis, kv_payload)
64
+ end
77
65
  end
78
66
 
79
67
  alias call_pipeline_without_instana call_pipeline