instana 0.12.1 → 0.13.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Configuration.md +73 -1
- data/Gemfile +6 -0
- data/README.md +7 -70
- data/lib/instana.rb +1 -1
- data/lib/instana/collectors.rb +1 -1
- data/lib/instana/config.rb +3 -0
- data/lib/instana/instrumentation/excon.rb +64 -0
- data/lib/instana/instrumentation/rack.rb +1 -1
- data/lib/instana/instrumentation/rest-client.rb +34 -0
- data/lib/instana/logger.rb +12 -1
- data/lib/instana/tracer.rb +138 -8
- data/lib/instana/tracing/processor.rb +114 -11
- data/lib/instana/tracing/span.rb +12 -0
- data/lib/instana/tracing/trace.rb +216 -43
- data/lib/instana/util.rb +59 -41
- data/lib/instana/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fff8c1b1ed4764301a7f1a45dec8973df279b2d8
|
4
|
+
data.tar.gz: 8947536ba2a71f9916712d55980f77f57af8fde7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1626e65166c81355c55105db86179e22c8cf9a1ae7ee7292e17574015f0acf2590eb0ed06b667d20d6d1294bd2d79eddaef584951119fc750880950401caa2ff
|
7
|
+
data.tar.gz: 18c6581dbaece4419c1fd6edb59e4fabd30efab3789c24bc0b006420c3bce83f774ae4a239a37dc47b7c8ea1d0e99bf2f981c59d692b39b0e4ac00870010820e
|
data/Configuration.md
CHANGED
@@ -1,5 +1,76 @@
|
|
1
1
|
# Configuration
|
2
2
|
|
3
|
+
## Enabling/Disabling Components
|
4
|
+
|
5
|
+
Individual components can be enabled and disabled with a local config.
|
6
|
+
|
7
|
+
To disable a single component in the gem, you can disable a single component with the following code:
|
8
|
+
|
9
|
+
```Ruby
|
10
|
+
::Instana.config[:metrics][:gc][:enabled] = false
|
11
|
+
```
|
12
|
+
Current metric components are `:gc`, `:memory` and `:thread`.
|
13
|
+
|
14
|
+
Instrumentation can be disabled as:
|
15
|
+
|
16
|
+
```Ruby
|
17
|
+
::Instana.config[:excon][:enabled] = false
|
18
|
+
::Instana.config[:rack][:enabled] = false
|
19
|
+
```
|
20
|
+
|
21
|
+
## Rack Middleware
|
22
|
+
|
23
|
+
This gem will detect and automagically insert the Instana Rack middleware into the middleware stack when a [supported framework](https://instana.atlassian.net/wiki/display/DOCS/Ruby) is present. We are currently adding support for more frameworks. If you are using a yet to be instrumented framework, you can insert the Instana Rack middleware with the following:
|
24
|
+
|
25
|
+
```Ruby
|
26
|
+
require "instana/rack"
|
27
|
+
config.middleware.use ::Instana::Rack
|
28
|
+
```
|
29
|
+
|
30
|
+
...or whatever specific middleware call is appropriate for your framework.
|
31
|
+
|
32
|
+
|
33
|
+
## Managing the Agent Background Thread
|
34
|
+
|
35
|
+
This agent spawns a lightweight background thread to periodically collect and report metrics and traces. Be default, this uses a standard Ruby thread. If you wish to have greater control and potentially boot the agent reporting manually in an alternative thread system (such as actor based threads), you can do so with the following:
|
36
|
+
|
37
|
+
```Ruby
|
38
|
+
gem "instana", :require => "instana/setup"
|
39
|
+
```
|
40
|
+
|
41
|
+
...then in the background thread of your choice simply call:
|
42
|
+
|
43
|
+
```Ruby
|
44
|
+
::Instana.agent.start
|
45
|
+
```
|
46
|
+
|
47
|
+
Note that this call is blocking. It kicks off a loop of timers that periodically collects and reports metrics and trace data. This should only be called from inside an already initialized background thread:
|
48
|
+
|
49
|
+
```Ruby
|
50
|
+
Thread.new do
|
51
|
+
::Instana.agent.start
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
### Caveat
|
56
|
+
|
57
|
+
In the case of forking webservers such as Unicorn or Puma in clustered mode, the agent detects the pid change and re-spawns the background thread. If you are managing the background thread yourself with the steps above _and_ you are using a forking webserver (or anything else that may fork the original process), you should also do the following.
|
58
|
+
|
59
|
+
When a fork is detected, the agent handles the re-initialization and then calls `::Agent.instana.spawn_background_thread`. This by default uses the standard `Thread.new`. If you wish to control this, you should override this method by re-defining that method. For example:
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
# This method can be overridden with the following:
|
63
|
+
#
|
64
|
+
module Instana
|
65
|
+
class Agent
|
66
|
+
def spawn_background_thread
|
67
|
+
# start/identify custom thread
|
68
|
+
::Instana.agent.start
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
3
74
|
## Logging
|
4
75
|
|
5
76
|
The Instana logger is a standard Ruby logger that logs debug, warn, info
|
@@ -16,6 +87,7 @@ what extra debug info it reports. It allows for:
|
|
16
87
|
* `:agent` - shows all agent state related debug messages
|
17
88
|
* `:agent_comm` - outputs all request/response pairs to and from the
|
18
89
|
host agent
|
90
|
+
* `:trace` - outputs debug messages related to tracing and trace management
|
19
91
|
|
20
92
|
Log messages can be generated for these channels using:
|
21
93
|
|
@@ -27,7 +99,7 @@ Log messages can be generated for these channels using:
|
|
27
99
|
To set the debug log level:
|
28
100
|
|
29
101
|
```Ruby
|
30
|
-
::Instana.logger.debug_level = [:agent, :agent_comm]
|
102
|
+
::Instana.logger.debug_level = [:agent, :agent_comm, :trace]
|
31
103
|
# or
|
32
104
|
::Instana.logger.debug_level = [:agent_comm]
|
33
105
|
# or
|
data/Gemfile
CHANGED
@@ -13,9 +13,15 @@ group :development, :test do
|
|
13
13
|
gem "cuba"
|
14
14
|
gem "roda"
|
15
15
|
|
16
|
+
# HTTP Clients
|
17
|
+
gem 'rest-client'
|
18
|
+
|
16
19
|
# Webservers
|
17
20
|
gem "puma"
|
18
21
|
|
22
|
+
# HTTP Clients
|
23
|
+
gem 'excon'
|
24
|
+
|
19
25
|
# Rack v2 dropped support for Ruby 2.2 and higher.
|
20
26
|
if RUBY_VERSION < '2.2'
|
21
27
|
gem 'rack', '< 2.0'
|
data/README.md
CHANGED
@@ -17,12 +17,12 @@ This gem supports Ruby versions 2.0 or greater.
|
|
17
17
|
|
18
18
|
Any and all feedback is welcome. Happy Ruby visibility.
|
19
19
|
|
20
|
-
![rails](https://s3.amazonaws.com/instana/rails-logo.jpg?1)
|
21
|
-
![roda](https://s3.amazonaws.com/instana/roda-logo.png?1)
|
22
|
-
![cuba](https://s3.amazonaws.com/instana/cuba-logo.png?1)
|
23
|
-
![sinatra](https://s3.amazonaws.com/instana/sinatra-logo.png?1)
|
24
|
-
![padrino](https://s3.amazonaws.com/instana/padrino-logo.png?1)
|
25
|
-
![rack](https://s3.amazonaws.com/instana/rack-logo.png?1)
|
20
|
+
[![rails](https://s3.amazonaws.com/instana/rails-logo.jpg?1)](http://rubyonrails.org/)
|
21
|
+
[![roda](https://s3.amazonaws.com/instana/roda-logo.png?1)](http://roda.jeremyevans.net/)
|
22
|
+
[![cuba](https://s3.amazonaws.com/instana/cuba-logo.png?1)](http://cuba.is/)
|
23
|
+
[![sinatra](https://s3.amazonaws.com/instana/sinatra-logo.png?1)](http://www.sinatrarb.com/)
|
24
|
+
[![padrino](https://s3.amazonaws.com/instana/padrino-logo.png?1)](http://padrinorb.com/)
|
25
|
+
[![rack](https://s3.amazonaws.com/instana/rack-logo.png?1)](https://rack.github.io/)
|
26
26
|
|
27
27
|
## Installation
|
28
28
|
|
@@ -46,70 +46,7 @@ The instana gem is a zero configuration tool that will automatically collect key
|
|
46
46
|
|
47
47
|
## Configuration
|
48
48
|
|
49
|
-
Although the gem has no configuration required for out of the box metrics and tracing, components can be configured if needed.
|
50
|
-
|
51
|
-
### Agent Reporting
|
52
|
-
|
53
|
-
This agent spawns a lightweight background thread to periodically collect and report metrics and traces. Be default, this uses a standard Ruby thread. If you wish to have greater control and potentially boot the agent reporting manually in an alternative thread system (such as actor based threads), you can do so with the following:
|
54
|
-
|
55
|
-
```Ruby
|
56
|
-
gem "instana", :require => "instana/setup"
|
57
|
-
```
|
58
|
-
|
59
|
-
...then in the background thread of your choice simply call:
|
60
|
-
|
61
|
-
```Ruby
|
62
|
-
::Instana.agent.start
|
63
|
-
```
|
64
|
-
|
65
|
-
Note that this call is blocking. It kicks off a loop of timers that periodically collects and reports metrics and trace data. This should only be called from inside an already initialized background thread:
|
66
|
-
|
67
|
-
```Ruby
|
68
|
-
Thread.new do
|
69
|
-
::Instana.agent.start
|
70
|
-
end
|
71
|
-
```
|
72
|
-
|
73
|
-
#### Caveat
|
74
|
-
|
75
|
-
In the case of forking webservers such as Unicorn or Puma in clustered mode, the agent detects the pid change and re-spawns the background thread. If you are managing the background thread yourself with the steps above _and_ you are using a forking webserver (or anything else that may fork the original process), you should also do the following.
|
76
|
-
|
77
|
-
When a fork is detected, the agent handles the re-initialization and then calls `::Agent.instana.spawn_background_thread`. This by default uses the standard `Thread.new`. If you wish to control this, you should override this method by re-defining that method. For example:
|
78
|
-
|
79
|
-
```ruby
|
80
|
-
# This method can be overridden with the following:
|
81
|
-
#
|
82
|
-
module Instana
|
83
|
-
class Agent
|
84
|
-
def spawn_background_thread
|
85
|
-
# start/identify custom thread
|
86
|
-
::Instana.agent.start
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
```
|
91
|
-
|
92
|
-
### Components
|
93
|
-
|
94
|
-
Individual components can be disabled with a local config.
|
95
|
-
|
96
|
-
To disable a single component in the gem, you can disable a single component with the following code:
|
97
|
-
|
98
|
-
```Ruby
|
99
|
-
::Instana.config[:metrics][:gc][:enabled] = false
|
100
|
-
```
|
101
|
-
Current components are `:gc`, `:memory` and `:thread`.
|
102
|
-
|
103
|
-
### Rack Middleware
|
104
|
-
|
105
|
-
This gem will detect and automagically insert the Instana Rack middleware into the middleware stack when a [supported framework](https://instana.atlassian.net/wiki/display/DOCS/Ruby) is present. We are currently adding support for more frameworks. If you are using a yet to be instrumented framework, you can insert the Instana Rack middleware with the following:
|
106
|
-
|
107
|
-
```Ruby
|
108
|
-
require "instana/rack"
|
109
|
-
config.middleware.use ::Instana::Rack
|
110
|
-
```
|
111
|
-
|
112
|
-
...or whatever specific middleware call is appropriate for your framework.
|
49
|
+
Although the gem has no configuration required for out of the box metrics and tracing, components can be configured if needed. See [Configuration.md](https://github.com/instana/ruby-sensor/blob/master/Configuration.md).
|
113
50
|
|
114
51
|
## Documentation
|
115
52
|
|
data/lib/instana.rb
CHANGED
@@ -3,7 +3,7 @@ require "instana/setup"
|
|
3
3
|
# Boot the instana agent background thread. If you wish to have greater
|
4
4
|
# control on the where and which thread this is run in, instead use
|
5
5
|
#
|
6
|
-
# gem "instana", :require "instana/setup"
|
6
|
+
# gem "instana", :require => "instana/setup"
|
7
7
|
#
|
8
8
|
# ...and manually call ::Instana.agent.start in the thread
|
9
9
|
# of your choice
|
data/lib/instana/collectors.rb
CHANGED
data/lib/instana/config.rb
CHANGED
@@ -0,0 +1,64 @@
|
|
1
|
+
if defined?(::Excon) && ::Instana.config[:excon][:enabled]
|
2
|
+
module Instana
|
3
|
+
module Instrumentation
|
4
|
+
class Excon < ::Excon::Middleware::Base
|
5
|
+
def request_call(datum)
|
6
|
+
return @stack.request_call(datum) unless ::Instana.tracer.tracing?
|
7
|
+
|
8
|
+
payload = { :http => {} }
|
9
|
+
path = datum[:path].split('?').first
|
10
|
+
payload[:http][:url] = "#{datum[:connection].instance_variable_get(:@socket_key)}#{path}"
|
11
|
+
payload[:http][:method] = datum[:method] if datum.key?(:method)
|
12
|
+
|
13
|
+
if datum[:pipeline] == true
|
14
|
+
# Pass the context along in the datum so we get back on response
|
15
|
+
# and can close out the async span
|
16
|
+
datum[:instana_context] = ::Instana.tracer.log_async_entry(:excon, payload)
|
17
|
+
else
|
18
|
+
::Instana.tracer.log_entry(:excon, payload)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Set request headers; encode IDs as hexadecimal strings
|
22
|
+
datum[:headers]['X-Instana-T'] = ::Instana.tracer.trace_id_header
|
23
|
+
datum[:headers]['X-Instana-S'] = ::Instana.tracer.span_id_header
|
24
|
+
|
25
|
+
@stack.request_call(datum)
|
26
|
+
end
|
27
|
+
|
28
|
+
def error_call(datum)
|
29
|
+
return @stack.error_call(datum) unless ::Instana.tracer.tracing?
|
30
|
+
|
31
|
+
if datum[:pipeline] == true
|
32
|
+
::Instana.tracer.log_async_error(datum[:error], datum[:instana_context])
|
33
|
+
else
|
34
|
+
::Instana.tracer.log_error(datum[:error])
|
35
|
+
end
|
36
|
+
@stack.error_call(datum)
|
37
|
+
end
|
38
|
+
|
39
|
+
def response_call(datum)
|
40
|
+
return @stack.response_call(datum) unless ::Instana.tracer.tracing?
|
41
|
+
|
42
|
+
result = @stack.response_call(datum)
|
43
|
+
|
44
|
+
status = datum[:status]
|
45
|
+
if !status && datum.key?(:response) && datum[:response].is_a?(Hash)
|
46
|
+
status = datum[:response][:status]
|
47
|
+
end
|
48
|
+
|
49
|
+
if datum[:pipeline] == true
|
50
|
+
# Pickup context of this async span from datum[:instana_id]
|
51
|
+
::Instana.tracer.log_async_exit(:excon, { :http => {:status => status } }, datum[:instana_context])
|
52
|
+
else
|
53
|
+
::Instana.tracer.log_exit(:excon, { :http => {:status => status } })
|
54
|
+
end
|
55
|
+
result
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
::Instana.logger.warn "Instrumenting excon"
|
62
|
+
::Excon.defaults[:middlewares].unshift(::Instana::Instrumentation::Excon)
|
63
|
+
end
|
64
|
+
|
@@ -19,7 +19,7 @@ module Instana
|
|
19
19
|
incoming_context = {}
|
20
20
|
if env.key?('HTTP_X_INSTANA_T')
|
21
21
|
incoming_context[:trace_id] = ::Instana.tracer.header_to_id(env['HTTP_X_INSTANA_T'])
|
22
|
-
incoming_context[:
|
22
|
+
incoming_context[:span_id] = ::Instana.tracer.header_to_id(env['HTTP_X_INSTANA_S']) if env.key?('HTTP_X_INSTANA_S')
|
23
23
|
incoming_context[:level] = env['HTTP_X_INSTANA_L'] if env.key?('HTTP_X_INSTANA_L')
|
24
24
|
end
|
25
25
|
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Instana
|
2
|
+
module Instrumentation
|
3
|
+
module RestClientRequest
|
4
|
+
def self.included(klass)
|
5
|
+
if klass.method_defined?(:execute)
|
6
|
+
klass.class_eval do
|
7
|
+
alias execute_without_instana execute
|
8
|
+
alias execute execute_with_instana
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute_with_instana & block
|
14
|
+
# Since RestClient uses net/http under the covers, we just
|
15
|
+
# provide span visibility here. HTTP related KVs are reported
|
16
|
+
# in the Net::HTTP instrumentation
|
17
|
+
::Instana.tracer.log_entry(:'rest-client')
|
18
|
+
|
19
|
+
execute_without_instana(&block)
|
20
|
+
rescue => e
|
21
|
+
::Instana.tracer.log_error(e)
|
22
|
+
raise
|
23
|
+
ensure
|
24
|
+
::Instana.tracer.log_exit(:'rest-client')
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
if defined?(::RestClient::Request)
|
32
|
+
::Instana.logger.warn "Instrumenting RestClient"
|
33
|
+
::RestClient::Request.send(:include, ::Instana::Instrumentation::RestClientRequest)
|
34
|
+
end
|
data/lib/instana/logger.rb
CHANGED
@@ -2,7 +2,7 @@ require "logger"
|
|
2
2
|
|
3
3
|
module Instana
|
4
4
|
class XLogger < Logger
|
5
|
-
LEVELS = [:agent, :agent_comm].freeze
|
5
|
+
LEVELS = [:agent, :agent_comm, :trace].freeze
|
6
6
|
STAMP = "Instana: ".freeze
|
7
7
|
|
8
8
|
def initialize(*args)
|
@@ -12,6 +12,12 @@ module Instana
|
|
12
12
|
super(*args)
|
13
13
|
end
|
14
14
|
|
15
|
+
# Sets the debug level for this logger. The debug level is broken up into various
|
16
|
+
# sub-levels as defined in LEVELS.
|
17
|
+
#
|
18
|
+
# To use:
|
19
|
+
# ::Instana.logger.debug_level = [:agent_comm, :trace]
|
20
|
+
#
|
15
21
|
def debug_level=(levels)
|
16
22
|
LEVELS.each do |l|
|
17
23
|
instance_variable_set("@level_#{l}", false)
|
@@ -34,6 +40,11 @@ module Instana
|
|
34
40
|
self.debug(msg)
|
35
41
|
end
|
36
42
|
|
43
|
+
def trace(msg)
|
44
|
+
return unless @level_trace
|
45
|
+
self.debug(msg)
|
46
|
+
end
|
47
|
+
|
37
48
|
def error(msg)
|
38
49
|
super(STAMP + msg)
|
39
50
|
end
|
data/lib/instana/tracer.rb
CHANGED
@@ -9,7 +9,7 @@ module Instana
|
|
9
9
|
thread_local :current_trace
|
10
10
|
|
11
11
|
#######################################
|
12
|
-
# Tracing blocks
|
12
|
+
# Tracing blocks API methods
|
13
13
|
#######################################
|
14
14
|
|
15
15
|
# Will start a new trace or continue an on-going one (such as
|
@@ -18,9 +18,9 @@ module Instana
|
|
18
18
|
# @param name [String] the name of the span to start
|
19
19
|
# @param kvs [Hash] list of key values to be reported in the span
|
20
20
|
# @param incoming_context [Hash] specifies the incoming context. At a
|
21
|
-
# minimum, it should specify :trace_id and :
|
21
|
+
# minimum, it should specify :trace_id and :span_id from the following:
|
22
22
|
# @:trace_id the trace ID (must be an unsigned hex-string)
|
23
|
-
# :
|
23
|
+
# :span_id the ID of the parent span (must be an unsigned hex-string)
|
24
24
|
# :level specifies data collection level (optional)
|
25
25
|
#
|
26
26
|
def start_or_continue_trace(name, kvs = {}, incoming_context = {}, &block)
|
@@ -35,6 +35,12 @@ module Instana
|
|
35
35
|
|
36
36
|
# Trace a block of code within the context of the exiting trace
|
37
37
|
#
|
38
|
+
# Example usage:
|
39
|
+
#
|
40
|
+
# ::Instana.tracer.trace(:dbwork, { :db_name => @db.name }) do
|
41
|
+
# @db.select(1)
|
42
|
+
# end
|
43
|
+
#
|
38
44
|
# @param name [String] the name of the span to start
|
39
45
|
# @param kvs [Hash] list of key values to be reported in this new span
|
40
46
|
#
|
@@ -50,7 +56,7 @@ module Instana
|
|
50
56
|
end
|
51
57
|
|
52
58
|
#######################################
|
53
|
-
# Lower level tracing methods
|
59
|
+
# Lower level tracing API methods
|
54
60
|
#######################################
|
55
61
|
|
56
62
|
# Will start a new trace or continue an on-going one (such as
|
@@ -59,9 +65,9 @@ module Instana
|
|
59
65
|
# @param name [String] the name of the span to start
|
60
66
|
# @param kvs [Hash] list of key values to be reported in the span
|
61
67
|
# @param incoming_context [Hash] specifies the incoming context. At a
|
62
|
-
# minimum, it should specify :trace_id and :
|
68
|
+
# minimum, it should specify :trace_id and :span_id from the following:
|
63
69
|
# :trace_id the trace ID (must be an unsigned hex-string)
|
64
|
-
# :
|
70
|
+
# :span_id the ID of the parent span (must be an unsigned hex-string)
|
65
71
|
# :level specifies data collection level (optional)
|
66
72
|
#
|
67
73
|
def log_start_or_continue(name, kvs = {}, incoming_context = {})
|
@@ -98,7 +104,7 @@ module Instana
|
|
98
104
|
self.current_trace.add_error(e)
|
99
105
|
end
|
100
106
|
|
101
|
-
#
|
107
|
+
# Closes out the current span
|
102
108
|
#
|
103
109
|
# @note `name` isn't really required but helps keep sanity that
|
104
110
|
# we're closing out the span that we really want to close out.
|
@@ -124,10 +130,109 @@ module Instana
|
|
124
130
|
return unless tracing?
|
125
131
|
|
126
132
|
self.current_trace.finish(kvs)
|
127
|
-
|
133
|
+
|
134
|
+
if !self.current_trace.has_async? ||
|
135
|
+
(self.current_trace.has_async? && self.current_trace.complete?)
|
136
|
+
Instana.processor.add(self.current_trace)
|
137
|
+
else
|
138
|
+
# This trace still has outstanding/uncompleted asynchronous spans.
|
139
|
+
# Put it in the staging queue until the async span closes out or
|
140
|
+
# 5 minutes has passed. Whichever comes first.
|
141
|
+
Instana.processor.stage(self.current_trace)
|
142
|
+
end
|
128
143
|
self.current_trace = nil
|
129
144
|
end
|
130
145
|
|
146
|
+
###########################################################################
|
147
|
+
# Asynchronous API methods
|
148
|
+
###########################################################################
|
149
|
+
|
150
|
+
# Starts a new asynchronous span on the current trace.
|
151
|
+
#
|
152
|
+
# @param name [String] the name of the span to create
|
153
|
+
# @param kvs [Hash] list of key values to be reported in the span
|
154
|
+
#
|
155
|
+
# @return [Hash] the context: Trace ID and Span ID in the form of
|
156
|
+
# :trace_id => 12345
|
157
|
+
# :span_id => 12345
|
158
|
+
#
|
159
|
+
def log_async_entry(name, kvs, incoming_context = nil)
|
160
|
+
return unless tracing?
|
161
|
+
self.current_trace.new_async_span(name, kvs)
|
162
|
+
end
|
163
|
+
|
164
|
+
# Add info to an asynchronous span
|
165
|
+
#
|
166
|
+
# @param kvs [Hash] list of key values to be reported in the span
|
167
|
+
# @param t_context [Hash] the Trace ID and Span ID in the form of
|
168
|
+
# :trace_id => 12345
|
169
|
+
# :span_id => 12345
|
170
|
+
# This can be retrieved by using ::Instana.tracer.context
|
171
|
+
#
|
172
|
+
def log_async_info(kvs, ids)
|
173
|
+
# Asynchronous spans can persist longer than the parent
|
174
|
+
# trace. With the trace ID, we check the current trace
|
175
|
+
# but otherwise, we search staged traces.
|
176
|
+
|
177
|
+
if tracing? && self.current_trace.id == ids[:trace_id]
|
178
|
+
self.current_trace.add_async_info(kvs, ids)
|
179
|
+
else
|
180
|
+
trace = ::Instana.processor.staged_trace(ids)
|
181
|
+
trace.add_async_info(kvs, ids)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# Add an error to an asynchronous span
|
186
|
+
#
|
187
|
+
# @param e [Exception] Add exception to the current span
|
188
|
+
# @param ids [Hash] the Trace ID and Span ID in the form of
|
189
|
+
# :trace_id => 12345
|
190
|
+
# :span_id => 12345
|
191
|
+
#
|
192
|
+
def log_async_error(e, ids)
|
193
|
+
# Asynchronous spans can persist longer than the parent
|
194
|
+
# trace. With the trace ID, we check the current trace
|
195
|
+
# but otherwise, we search staged traces.
|
196
|
+
|
197
|
+
if tracing? && self.current_trace.id == ids[:trace_id]
|
198
|
+
self.current_trace.add_async_error(e, ids)
|
199
|
+
else
|
200
|
+
trace = ::Instana.processor.staged_trace(ids)
|
201
|
+
trace.add_async_error(e, ids)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# Closes out an asynchronous span
|
206
|
+
#
|
207
|
+
# @param name [String] the name of the async span to exit (close out)
|
208
|
+
# @param kvs [Hash] list of key values to be reported in the span
|
209
|
+
# @param ids [Hash] the Trace ID and Span ID in the form of
|
210
|
+
# :trace_id => 12345
|
211
|
+
# :span_id => 12345
|
212
|
+
#
|
213
|
+
def log_async_exit(name, kvs, ids)
|
214
|
+
# An asynchronous span can end after the current trace has
|
215
|
+
# already completed so we make sure that we end the span
|
216
|
+
# on the right trace.
|
217
|
+
|
218
|
+
if tracing? && (self.current_trace.id == ids[:trace_id])
|
219
|
+
self.current_trace.end_async_span(kvs, ids)
|
220
|
+
else
|
221
|
+
# Different trace from current so find the staged trace
|
222
|
+
# and close out the span on it.
|
223
|
+
trace = ::Instana.processor.staged_trace(ids)
|
224
|
+
if trace
|
225
|
+
trace.end_async_span(kvs, ids)
|
226
|
+
else
|
227
|
+
::Instana.logger.debug "log_async_exit: Couldn't find staged trace. #{ids.inspect}"
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
###########################################################################
|
233
|
+
# Helper methods
|
234
|
+
###########################################################################
|
235
|
+
|
131
236
|
# Indicates if we're are currently in the process of
|
132
237
|
# collecting a trace. This is false when the host agent isn
|
133
238
|
# available.
|
@@ -141,6 +246,31 @@ module Instana
|
|
141
246
|
self.current_trace ? true : false
|
142
247
|
end
|
143
248
|
|
249
|
+
# Retrieve the current context of the tracer.
|
250
|
+
#
|
251
|
+
def context
|
252
|
+
{ :trace_id => self.current_trace.id,
|
253
|
+
:span_id => self.current_trace.current_span_id }
|
254
|
+
end
|
255
|
+
|
256
|
+
# Take the current trace_id and convert it to a header compatible
|
257
|
+
# format.
|
258
|
+
#
|
259
|
+
# @return [String] a hexadecimal representation of the current trace ID
|
260
|
+
#
|
261
|
+
def trace_id_header
|
262
|
+
id_to_header(trace_id)
|
263
|
+
end
|
264
|
+
|
265
|
+
# Take the current span_id and convert it to a header compatible
|
266
|
+
# formate.
|
267
|
+
#
|
268
|
+
# @return [String] a hexadecimal representation of the current span ID
|
269
|
+
#
|
270
|
+
def span_id_header
|
271
|
+
id_to_header(span_id)
|
272
|
+
end
|
273
|
+
|
144
274
|
# Convert an ID to a value appropriate to pass in a header.
|
145
275
|
#
|
146
276
|
# @param id [Integer] the id to be converted
|
@@ -4,7 +4,20 @@ module Instana
|
|
4
4
|
class Processor
|
5
5
|
|
6
6
|
def initialize
|
7
|
+
# The main queue before being reported to the
|
8
|
+
# host agent. Traces in this queue are complete
|
9
|
+
# and ready to be sent.
|
7
10
|
@queue = Queue.new
|
11
|
+
|
12
|
+
# The staging queue that holds traces that have completed
|
13
|
+
# but still have outstanding async spans.
|
14
|
+
# Traces that have been in this queue for more than
|
15
|
+
# 5 minutes are discarded.
|
16
|
+
@staging_queue = Set.new
|
17
|
+
|
18
|
+
# No access to the @staging_queue until this lock
|
19
|
+
# is taken.
|
20
|
+
@staging_lock = Mutex.new
|
8
21
|
end
|
9
22
|
|
10
23
|
# Adds a trace to the queue to be processed and
|
@@ -12,9 +25,41 @@ module Instana
|
|
12
25
|
#
|
13
26
|
# @param [Trace] the trace to be added to the queue
|
14
27
|
def add(trace)
|
28
|
+
::Instana.logger.trace("Queuing completed trace id: #{trace.id}")
|
15
29
|
@queue.push(trace)
|
16
30
|
end
|
17
31
|
|
32
|
+
# Adds a trace to the staging queue.
|
33
|
+
#
|
34
|
+
# @param [Trace] the trace to be added to the queue
|
35
|
+
def stage(trace)
|
36
|
+
::Instana.logger.trace("Staging incomplete trace id: #{trace.id}")
|
37
|
+
@staging_queue.add(trace)
|
38
|
+
end
|
39
|
+
|
40
|
+
# This will run through the staged traces (if any) to find
|
41
|
+
# completed or timed out incompleted traces. Completed traces will
|
42
|
+
# be added to the main @queue. Timed out traces will be discarded
|
43
|
+
#
|
44
|
+
def process_staged
|
45
|
+
@staging_lock.synchronize {
|
46
|
+
if @staging_queue.size > 0
|
47
|
+
@staging_queue.delete_if do |t|
|
48
|
+
if t.complete?
|
49
|
+
::Instana.logger.trace("Moving staged complete trace to main queue: #{t.id}")
|
50
|
+
add(t)
|
51
|
+
true
|
52
|
+
elsif t.discard?
|
53
|
+
::Instana.logger.debug("Discarding trace with uncompleted async spans over 5 mins old. id: #{t.id}")
|
54
|
+
true
|
55
|
+
else
|
56
|
+
false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
18
63
|
##
|
19
64
|
# send
|
20
65
|
#
|
@@ -27,20 +72,21 @@ module Instana
|
|
27
72
|
# - Prevent another run of the timer while this is running
|
28
73
|
#
|
29
74
|
def send
|
30
|
-
return if @queue.empty?
|
75
|
+
return if @queue.empty? || ENV['INSTANA_GEM_TEST']
|
31
76
|
|
32
77
|
size = @queue.size
|
33
78
|
if size > 100
|
34
79
|
Instana.logger.debug "Trace queue is #{size}"
|
35
80
|
end
|
36
81
|
|
37
|
-
|
38
|
-
|
82
|
+
# Scan for any staged but incomplete traces that have now
|
83
|
+
# completed.
|
84
|
+
process_staged
|
39
85
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
86
|
+
# Retrieve all spans for queued traces
|
87
|
+
spans = queued_spans
|
88
|
+
|
89
|
+
::Instana.agent.report_spans(spans)
|
44
90
|
end
|
45
91
|
|
46
92
|
# Retrieves all of the traces in @queue and returns
|
@@ -49,6 +95,8 @@ module Instana
|
|
49
95
|
# Note that traces retrieved with this method are removed
|
50
96
|
# entirely from the queue.
|
51
97
|
#
|
98
|
+
# @return [Array] An array of [Span] or empty
|
99
|
+
#
|
52
100
|
def queued_spans
|
53
101
|
return [] if @queue.empty?
|
54
102
|
|
@@ -67,6 +115,8 @@ module Instana
|
|
67
115
|
# Note that traces retrieved with this method are removed
|
68
116
|
# entirely from the queue.
|
69
117
|
#
|
118
|
+
# @return [Array] An array of [Trace] or empty
|
119
|
+
#
|
70
120
|
def queued_traces
|
71
121
|
return [] if @queue.empty?
|
72
122
|
|
@@ -78,16 +128,69 @@ module Instana
|
|
78
128
|
traces
|
79
129
|
end
|
80
130
|
|
81
|
-
#
|
82
|
-
#
|
131
|
+
# Retrieves a all staged traces from the staging queue. Staged traces
|
132
|
+
# are traces that have completed but may have outstanding
|
133
|
+
# asynchronous spans.
|
83
134
|
#
|
84
|
-
|
85
|
-
|
135
|
+
# @return [Array]
|
136
|
+
#
|
137
|
+
def staged_traces
|
138
|
+
traces = nil
|
139
|
+
@staging_lock.synchronize {
|
140
|
+
traces = @staging_queue.to_a
|
141
|
+
@staging_queue.clear
|
142
|
+
}
|
143
|
+
traces
|
144
|
+
end
|
86
145
|
|
146
|
+
# Retrieves a single staged trace from the staging queue. Staged traces
|
147
|
+
# are traces that have completed but may have outstanding
|
148
|
+
# asynchronous spans.
|
149
|
+
#
|
150
|
+
# @param ids [Hash] the Trace ID and Span ID in the form of
|
151
|
+
# :trace_id => 12345
|
152
|
+
# :span_id => 12345
|
153
|
+
#
|
154
|
+
def staged_trace(ids)
|
155
|
+
candidate = nil
|
156
|
+
@staging_lock.synchronize {
|
157
|
+
@staging_queue.each do |trace|
|
158
|
+
if trace.id == ids[:trace_id]
|
159
|
+
candidate = trace
|
160
|
+
end
|
161
|
+
end
|
162
|
+
}
|
163
|
+
unless candidate
|
164
|
+
::Instana.logger.trace("Couldn't find staged trace with trace_id: #{ids[:trace_id]}")
|
165
|
+
end
|
166
|
+
candidate
|
167
|
+
end
|
168
|
+
|
169
|
+
# Get the number traces currently in the queue
|
170
|
+
#
|
171
|
+
# @return [Integer] the queue size
|
172
|
+
#
|
173
|
+
def queue_count
|
174
|
+
@queue.size
|
175
|
+
end
|
176
|
+
|
177
|
+
# Get the number traces currently in the staging queue
|
178
|
+
#
|
179
|
+
# @return [Integer] the queue size
|
180
|
+
#
|
181
|
+
def staged_count
|
182
|
+
@staging_queue.size
|
183
|
+
end
|
184
|
+
|
185
|
+
# Removes all traces from the @queue and @staging_queue. Used in the
|
186
|
+
# test suite to reset state.
|
187
|
+
#
|
188
|
+
def clear!
|
87
189
|
until @queue.empty? do
|
88
190
|
# Non-blocking pop; ignore exception
|
89
191
|
@queue.pop(true) rescue nil
|
90
192
|
end
|
193
|
+
@staging_queue.clear
|
91
194
|
end
|
92
195
|
end
|
93
196
|
end
|
data/lib/instana/tracing/span.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Instana
|
2
2
|
class Trace
|
3
|
-
REGISTERED_SPANS = [ :rack, :'net-http' ]
|
3
|
+
REGISTERED_SPANS = [ :rack, :'net-http', :excon ]
|
4
4
|
|
5
5
|
# @return [Integer] the ID for this trace
|
6
6
|
attr_reader :id
|
@@ -14,9 +14,9 @@ module Instana
|
|
14
14
|
# @param name [String] the name of the span to start
|
15
15
|
# @param kvs [Hash] list of key values to be reported in the span
|
16
16
|
# @param incoming_context [Hash] specifies the incoming context. At a
|
17
|
-
# minimum, it should specify :trace_id and :
|
17
|
+
# minimum, it should specify :trace_id and :span_id from the following:
|
18
18
|
# :trace_id the trace ID (must be an unsigned hex-string)
|
19
|
-
# :
|
19
|
+
# :span_id the ID of the parent span (must be an unsigned hex-string)
|
20
20
|
# :level specifies data collection level (optional)
|
21
21
|
#
|
22
22
|
def initialize(name, kvs = {}, incoming_context = {})
|
@@ -30,6 +30,13 @@ module Instana
|
|
30
30
|
# Generate a random 64bit ID for this trace
|
31
31
|
@id = generate_id
|
32
32
|
|
33
|
+
# Indicates the time when this trace was started. Used to timeout
|
34
|
+
# traces that have asynchronous spans that never close out.
|
35
|
+
@started_at = Time.now
|
36
|
+
|
37
|
+
# Indicates if this trace has any asynchronous spans within it
|
38
|
+
@has_async = false
|
39
|
+
|
33
40
|
# This is a new trace so open the first span with the proper
|
34
41
|
# root span IDs.
|
35
42
|
@current_span = Span.new({
|
@@ -41,7 +48,7 @@ module Instana
|
|
41
48
|
|
42
49
|
# Check for custom tracing
|
43
50
|
if !REGISTERED_SPANS.include?(name.to_sym)
|
44
|
-
configure_custom_span(name, kvs)
|
51
|
+
configure_custom_span(nil, name, kvs)
|
45
52
|
else
|
46
53
|
@current_span[:n] = name.to_sym
|
47
54
|
@current_span[:data] = kvs
|
@@ -55,7 +62,7 @@ module Instana
|
|
55
62
|
else
|
56
63
|
@id = incoming_context[:trace_id]
|
57
64
|
@current_span[:t] = incoming_context[:trace_id]
|
58
|
-
@current_span[:p] = incoming_context[:
|
65
|
+
@current_span[:p] = incoming_context[:span_id]
|
59
66
|
end
|
60
67
|
|
61
68
|
@spans.add(@current_span)
|
@@ -72,7 +79,7 @@ module Instana
|
|
72
79
|
new_span = Span.new({
|
73
80
|
:s => generate_id, # Span ID
|
74
81
|
:t => @id, # Trace ID (same as :s for root span)
|
75
|
-
:p => @current_span
|
82
|
+
:p => @current_span.id, # Parent ID
|
76
83
|
:ts => ts_now, # Timestamp
|
77
84
|
:ta => :ruby, # Agent
|
78
85
|
:f => { :e => Process.pid, :h => :agent_id } # Entity Source
|
@@ -84,7 +91,7 @@ module Instana
|
|
84
91
|
|
85
92
|
# Check for custom tracing
|
86
93
|
if !REGISTERED_SPANS.include?(name.to_sym)
|
87
|
-
configure_custom_span(name, kvs)
|
94
|
+
configure_custom_span(nil, name, kvs)
|
88
95
|
else
|
89
96
|
@current_span[:n] = name.to_sym
|
90
97
|
@current_span[:data] = kvs
|
@@ -93,17 +100,28 @@ module Instana
|
|
93
100
|
|
94
101
|
# Add KVs to the current span
|
95
102
|
#
|
103
|
+
# @param span [Span] the span to add kvs to or otherwise the current span
|
96
104
|
# @param kvs [Hash] list of key values to be reported in the span
|
97
105
|
#
|
98
|
-
def add_info(kvs)
|
99
|
-
|
100
|
-
|
101
|
-
|
106
|
+
def add_info(kvs, span = nil)
|
107
|
+
span ||= @current_span
|
108
|
+
|
109
|
+
if span.custom?
|
110
|
+
if span[:data][:sdk].key?(:custom)
|
111
|
+
span[:data][:sdk][:custom].merge!(kvs)
|
102
112
|
else
|
103
|
-
|
113
|
+
span[:data][:sdk][:custom] = kvs
|
104
114
|
end
|
105
115
|
else
|
106
|
-
|
116
|
+
kvs.each_pair do |k,v|
|
117
|
+
if !span[:data].key?(k)
|
118
|
+
span[:data][k] = v
|
119
|
+
elsif v.is_a?(Hash) && span[:data][k].is_a?(Hash)
|
120
|
+
span[:data][k].merge!(v)
|
121
|
+
else
|
122
|
+
span[:data][k] = v
|
123
|
+
end
|
124
|
+
end
|
107
125
|
end
|
108
126
|
end
|
109
127
|
|
@@ -111,26 +129,16 @@ module Instana
|
|
111
129
|
#
|
112
130
|
# @param e [Exception] Add exception to the current span
|
113
131
|
#
|
114
|
-
def add_error(e)
|
115
|
-
@current_span
|
132
|
+
def add_error(e, span = nil)
|
133
|
+
span ||= @current_span
|
134
|
+
|
135
|
+
span[:error] = true
|
116
136
|
|
117
|
-
if
|
118
|
-
|
137
|
+
if span.key?(:ec)
|
138
|
+
span[:ec] = span[:ec] + 1
|
119
139
|
else
|
120
|
-
|
140
|
+
span[:ec] = 1
|
121
141
|
end
|
122
|
-
|
123
|
-
#if e.backtrace && e.backtrace.is_a?(Array)
|
124
|
-
# @current_span[:stack] = []
|
125
|
-
# e.backtrace.each do |x|
|
126
|
-
# file, line, method = x.split(':')
|
127
|
-
# @current_span[:stack] << {
|
128
|
-
# :f => file,
|
129
|
-
# :n => line
|
130
|
-
# #:m => method
|
131
|
-
# }
|
132
|
-
# end
|
133
|
-
#end
|
134
142
|
end
|
135
143
|
|
136
144
|
# Close out the current span and set the parent as
|
@@ -154,17 +162,124 @@ module Instana
|
|
154
162
|
end_span(kvs)
|
155
163
|
end
|
156
164
|
|
157
|
-
|
158
|
-
#
|
159
|
-
|
165
|
+
###########################################################################
|
166
|
+
# Asynchronous Methods
|
167
|
+
###########################################################################
|
168
|
+
|
169
|
+
# Start a new asynchronous span
|
170
|
+
#
|
171
|
+
# The major differentiator between this method and simple new_span is that
|
172
|
+
# this method doesn't affect @current_trace and instead returns an
|
173
|
+
# ID pair that can be used later to close out the created async span.
|
174
|
+
#
|
175
|
+
# @param name [String] the name of the span to start
|
176
|
+
# @param kvs [Hash] list of key values to be reported in the span
|
177
|
+
#
|
178
|
+
def new_async_span(name, kvs)
|
179
|
+
|
180
|
+
new_span = Span.new({
|
181
|
+
:s => generate_id, # Span ID
|
182
|
+
:t => @id, # Trace ID (same as :s for root span)
|
183
|
+
:p => @current_span.id, # Parent ID
|
184
|
+
:ts => ts_now, # Timestamp
|
185
|
+
:ta => :ruby, # Agent
|
186
|
+
:async => true, # Asynchonous
|
187
|
+
:f => { :e => Process.pid, :h => :agent_id } # Entity Source
|
188
|
+
})
|
189
|
+
|
190
|
+
new_span.parent = @current_span
|
191
|
+
@has_async = true
|
192
|
+
|
193
|
+
# Check for custom tracing
|
194
|
+
if !REGISTERED_SPANS.include?(name.to_sym)
|
195
|
+
configure_custom_span(new_span, name, kvs)
|
196
|
+
else
|
197
|
+
new_span[:n] = name.to_sym
|
198
|
+
new_span[:data] = kvs
|
199
|
+
end
|
200
|
+
|
201
|
+
# Add the new span to the span collection
|
202
|
+
@spans.add(new_span)
|
203
|
+
|
204
|
+
{ :trace_id => new_span[:t], :span_id => new_span.id }
|
205
|
+
end
|
206
|
+
|
207
|
+
# Log info into an asynchronous span
|
208
|
+
#
|
209
|
+
# @param kvs [Hash] list of key values to be reported in the span
|
210
|
+
# @param span [Span] the span to configure
|
211
|
+
#
|
212
|
+
def add_async_info(kvs, ids)
|
213
|
+
@spans.each do |span|
|
214
|
+
if span.id == ids[:span_id]
|
215
|
+
add_info(kvs, span)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# Log an error into an asynchronous span
|
221
|
+
#
|
222
|
+
# @param span [Span] the span to configure
|
223
|
+
# @param e [Exception] Add exception to the current span
|
224
|
+
#
|
225
|
+
def add_async_error(e, ids)
|
226
|
+
@spans.each do |span|
|
227
|
+
add_error(e, span) if span.id == ids[:span_id]
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
# End an asynchronous span
|
232
|
+
#
|
233
|
+
# @param name [Symbol] the name of the span
|
234
|
+
# @param kvs [Hash] list of key values to be reported in the span
|
235
|
+
# @param ids [Hash] the Trace ID and Span ID in the form of
|
236
|
+
# :trace_id => 12345
|
237
|
+
# :span_id => 12345
|
238
|
+
#
|
239
|
+
def end_async_span(kvs = {}, ids)
|
240
|
+
@spans.each do |span|
|
241
|
+
if span.id == ids[:span_id]
|
242
|
+
span[:d] = ts_now - span[:ts]
|
243
|
+
add_info(kvs, span) unless kvs.empty?
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
###########################################################################
|
249
|
+
# Validator and Helper Methods
|
250
|
+
###########################################################################
|
251
|
+
|
252
|
+
# Indicates whether all seems ok with this trace in it's current state.
|
253
|
+
# Should be only called on finished traces.
|
160
254
|
#
|
161
255
|
# @return [Boolean] true or false on whether this trace is valid
|
162
256
|
#
|
163
257
|
def valid?
|
164
|
-
|
258
|
+
@spans.each do |span|
|
259
|
+
unless span.key?(:d)
|
260
|
+
return false
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
# Indicates if every span of this trace has completed. Useful when
|
266
|
+
# asynchronous spans potentially could run longer than the parent trace.
|
267
|
+
#
|
268
|
+
def complete?
|
269
|
+
@spans.each do |span|
|
270
|
+
if !span.duration
|
271
|
+
return false
|
272
|
+
end
|
273
|
+
end
|
165
274
|
true
|
166
275
|
end
|
167
276
|
|
277
|
+
# Indicates whether this trace has any asynchronous spans.
|
278
|
+
#
|
279
|
+
def has_async?
|
280
|
+
@has_async
|
281
|
+
end
|
282
|
+
|
168
283
|
# Searches the set of spans and indicates if there
|
169
284
|
# is an error logged in one of them.
|
170
285
|
#
|
@@ -191,26 +306,84 @@ module Instana
|
|
191
306
|
@current_span.id
|
192
307
|
end
|
193
308
|
|
309
|
+
# Get the name of the current span. Supports both registered spans
|
310
|
+
# and custom sdk spans.
|
311
|
+
#
|
312
|
+
def current_span_name
|
313
|
+
@current_span.name
|
314
|
+
end
|
315
|
+
|
316
|
+
# Check if the current span has the name value of <name>
|
317
|
+
#
|
318
|
+
# @param name [Symbol] The name to be checked against.
|
319
|
+
#
|
320
|
+
# @return [Boolean]
|
321
|
+
#
|
322
|
+
def current_span_name?(name)
|
323
|
+
@current_span.name == name
|
324
|
+
end
|
325
|
+
|
326
|
+
# For traces that have asynchronous spans, this method indicates
|
327
|
+
# whether we have hit the timeout on waiting for those async
|
328
|
+
# spans to close out.
|
329
|
+
#
|
330
|
+
# @return [Boolean]
|
331
|
+
#
|
332
|
+
def discard?
|
333
|
+
# If this trace has async spans that have not closed
|
334
|
+
# out in 5 minutes, then it's discarded.
|
335
|
+
if has_async? && (Time.now.to_i - @started_at.to_i) > 601
|
336
|
+
return true
|
337
|
+
end
|
338
|
+
false
|
339
|
+
end
|
340
|
+
|
194
341
|
private
|
195
342
|
|
196
343
|
# Configure @current_span to be a custom span per the
|
197
344
|
# SDK generic span type.
|
198
345
|
#
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
346
|
+
# @param span [Span] the span to configure or nil
|
347
|
+
# @param name [String] name of the span
|
348
|
+
# @param kvs [Hash] list of key values to be reported in the span
|
349
|
+
#
|
350
|
+
def configure_custom_span(span, name, kvs = {})
|
351
|
+
span ||= @current_span
|
352
|
+
|
353
|
+
span[:n] = :sdk
|
354
|
+
span[:data] = { :sdk => { :name => name.to_sym } }
|
355
|
+
span[:data][:sdk][:type] = kvs.key?(:type) ? kvs[:type] : :local
|
203
356
|
|
204
357
|
if kvs.key?(:arguments)
|
205
|
-
|
358
|
+
span[:data][:sdk][:arguments] = kvs[:arguments]
|
206
359
|
end
|
207
360
|
|
208
361
|
if kvs.key?(:return)
|
209
|
-
|
362
|
+
span[:data][:sdk][:return] = kvs[:return]
|
363
|
+
end
|
364
|
+
span[:data][:sdk][:custom] = kvs unless kvs.empty?
|
365
|
+
#span[:data][:sdk][:custom][:tags] = {}
|
366
|
+
#span[:data][:sdk][:custom][:logs] = {}
|
367
|
+
end
|
368
|
+
|
369
|
+
# Locates the span in the current_trace or
|
370
|
+
# in the staging queue. This is generally used by async
|
371
|
+
# operations.
|
372
|
+
#
|
373
|
+
# @param ids [Hash] the Trace ID and Span ID in the form of
|
374
|
+
# :trace_id => 12345
|
375
|
+
# :span_id => 12345
|
376
|
+
#
|
377
|
+
# @return [Span]
|
378
|
+
#
|
379
|
+
def find_span(ids)
|
380
|
+
if ids[:trace_id] == @id
|
381
|
+
@spans.each do |s|
|
382
|
+
return s if s[:s] == ids[:span_id]
|
383
|
+
end
|
384
|
+
else
|
385
|
+
#::Instana.processor.staged_trace(
|
210
386
|
end
|
211
|
-
@current_span[:data][:sdk][:custom] = kvs unless kvs.empty?
|
212
|
-
#@current_span[:data][:sdk][:custom][:tags] = {}
|
213
|
-
#@current_span[:data][:sdk][:custom][:logs] = {}
|
214
387
|
end
|
215
388
|
|
216
389
|
# Get the current time in milliseconds
|
data/lib/instana/util.rb
CHANGED
@@ -1,52 +1,70 @@
|
|
1
1
|
module Instana
|
2
2
|
module Util
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
3
|
+
class << self
|
4
|
+
# An agnostic approach to method aliasing.
|
5
|
+
#
|
6
|
+
# @param klass [Object] The class or module that holds the method to be alias'd.
|
7
|
+
# @param method [Symbol] The name of the method to be aliased.
|
8
|
+
#
|
9
|
+
def method_alias(klass, method)
|
10
|
+
if klass.method_defined?(method.to_sym)
|
11
|
+
|
12
|
+
with = "#{method}_with_instana"
|
13
|
+
without = "#{method}_without_instana"
|
14
|
+
|
15
|
+
klass.class_eval do
|
16
|
+
alias_method without, method.to_s
|
17
|
+
alias_method method.to_s, with
|
18
|
+
end
|
19
|
+
else
|
20
|
+
::Instana.logger.debug "No such method (#{method}) to alias on #{klass}"
|
19
21
|
end
|
20
22
|
end
|
21
|
-
candidate
|
22
|
-
end
|
23
|
-
end
|
24
23
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
Pry.commands.alias_command 'n', 'next'
|
40
|
-
Pry.commands.alias_command 'f', 'finish'
|
41
|
-
|
42
|
-
Pry::Commands.command(/^$/, 'repeat last command') do
|
43
|
-
_pry_.run_command Pry.history.to_a.last
|
24
|
+
# Take two hashes, and make sure candidate does not have
|
25
|
+
# any of the same values as `last`. We only report
|
26
|
+
# when values change.
|
27
|
+
#
|
28
|
+
# Note this is not recursive, so only pass in the single
|
29
|
+
# hashes that you want delta reporting with.
|
30
|
+
#
|
31
|
+
def enforce_deltas(candidate, last)
|
32
|
+
return unless last.is_a?(Hash)
|
33
|
+
|
34
|
+
candidate.each do |k,v|
|
35
|
+
if candidate[k] == last[k]
|
36
|
+
candidate.delete(k)
|
37
|
+
end
|
44
38
|
end
|
39
|
+
candidate
|
45
40
|
end
|
46
41
|
|
47
|
-
|
48
|
-
|
49
|
-
|
42
|
+
# Debugging helper method
|
43
|
+
#
|
44
|
+
def pry!
|
45
|
+
# Only valid for development or test environments
|
46
|
+
#env = ENV['RACK_ENV'] || ENV['RAILS_ENV']
|
47
|
+
#return unless %w(development, test).include? env
|
48
|
+
|
49
|
+
if RUBY_VERSION > '1.8.7'
|
50
|
+
require 'pry-byebug'
|
51
|
+
|
52
|
+
if defined?(PryByebug)
|
53
|
+
Pry.commands.alias_command 'c', 'continue'
|
54
|
+
Pry.commands.alias_command 's', 'step'
|
55
|
+
Pry.commands.alias_command 'n', 'next'
|
56
|
+
Pry.commands.alias_command 'f', 'finish'
|
57
|
+
|
58
|
+
Pry::Commands.command(/^$/, 'repeat last command') do
|
59
|
+
_pry_.run_command Pry.history.to_a.last
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
binding.pry
|
64
|
+
else
|
65
|
+
require 'ruby-debug'; debugger
|
66
|
+
end
|
67
|
+
end
|
50
68
|
end
|
51
69
|
end
|
52
70
|
end
|
data/lib/instana/version.rb
CHANGED
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: 0.
|
4
|
+
version: 0.13.1
|
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: 2016-12-
|
11
|
+
date: 2016-12-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -140,8 +140,10 @@ files:
|
|
140
140
|
- lib/instana/frameworks/roda.rb
|
141
141
|
- lib/instana/frameworks/sinatra.rb
|
142
142
|
- lib/instana/instrumentation.rb
|
143
|
+
- lib/instana/instrumentation/excon.rb
|
143
144
|
- lib/instana/instrumentation/net-http.rb
|
144
145
|
- lib/instana/instrumentation/rack.rb
|
146
|
+
- lib/instana/instrumentation/rest-client.rb
|
145
147
|
- lib/instana/logger.rb
|
146
148
|
- lib/instana/rack.rb
|
147
149
|
- lib/instana/setup.rb
|