instana 1.11.4 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
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