appoptics_apm_mnfst 4.5.2

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.
Files changed (104) hide show
  1. checksums.yaml +7 -0
  2. data/.dockerignore +5 -0
  3. data/.github/ISSUE_TEMPLATE/bug-or-feature-request.md +16 -0
  4. data/.gitignore +29 -0
  5. data/.rubocop.yml +8 -0
  6. data/.travis.yml +121 -0
  7. data/.yardopts +4 -0
  8. data/CHANGELOG.md +769 -0
  9. data/CONFIG.md +33 -0
  10. data/Gemfile +29 -0
  11. data/LICENSE +193 -0
  12. data/README.md +393 -0
  13. data/Rakefile +230 -0
  14. data/appoptics_apm.gemspec +61 -0
  15. data/bin/appoptics_apm_config +15 -0
  16. data/build_gem.sh +15 -0
  17. data/build_gem_upload_to_packagecloud.sh +20 -0
  18. data/examples/SDK/01_basic_tracing.rb +67 -0
  19. data/examples/carrying_context.rb +220 -0
  20. data/ext/oboe_metal/extconf.rb +114 -0
  21. data/ext/oboe_metal/lib/.keep +0 -0
  22. data/ext/oboe_metal/noop/noop.c +7 -0
  23. data/ext/oboe_metal/src/VERSION +1 -0
  24. data/init.rb +4 -0
  25. data/lib/appoptics_apm.rb +76 -0
  26. data/lib/appoptics_apm/api.rb +20 -0
  27. data/lib/appoptics_apm/api/layerinit.rb +41 -0
  28. data/lib/appoptics_apm/api/logging.rb +375 -0
  29. data/lib/appoptics_apm/api/memcache.rb +37 -0
  30. data/lib/appoptics_apm/api/metrics.rb +55 -0
  31. data/lib/appoptics_apm/api/profiling.rb +203 -0
  32. data/lib/appoptics_apm/api/tracing.rb +53 -0
  33. data/lib/appoptics_apm/api/util.rb +122 -0
  34. data/lib/appoptics_apm/base.rb +230 -0
  35. data/lib/appoptics_apm/config.rb +254 -0
  36. data/lib/appoptics_apm/frameworks/grape.rb +97 -0
  37. data/lib/appoptics_apm/frameworks/padrino.rb +108 -0
  38. data/lib/appoptics_apm/frameworks/rails.rb +94 -0
  39. data/lib/appoptics_apm/frameworks/rails/inst/action_controller.rb +104 -0
  40. data/lib/appoptics_apm/frameworks/rails/inst/action_controller3.rb +55 -0
  41. data/lib/appoptics_apm/frameworks/rails/inst/action_controller4.rb +48 -0
  42. data/lib/appoptics_apm/frameworks/rails/inst/action_controller5.rb +50 -0
  43. data/lib/appoptics_apm/frameworks/rails/inst/action_controller_api.rb +50 -0
  44. data/lib/appoptics_apm/frameworks/rails/inst/action_view.rb +58 -0
  45. data/lib/appoptics_apm/frameworks/rails/inst/action_view_30.rb +50 -0
  46. data/lib/appoptics_apm/frameworks/rails/inst/active_record.rb +27 -0
  47. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
  48. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +29 -0
  49. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +31 -0
  50. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils.rb +119 -0
  51. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +108 -0
  52. data/lib/appoptics_apm/frameworks/sinatra.rb +125 -0
  53. data/lib/appoptics_apm/inst/bunny-client.rb +148 -0
  54. data/lib/appoptics_apm/inst/bunny-consumer.rb +89 -0
  55. data/lib/appoptics_apm/inst/curb.rb +330 -0
  56. data/lib/appoptics_apm/inst/dalli.rb +85 -0
  57. data/lib/appoptics_apm/inst/delayed_job.rb +92 -0
  58. data/lib/appoptics_apm/inst/em-http-request.rb +101 -0
  59. data/lib/appoptics_apm/inst/excon.rb +125 -0
  60. data/lib/appoptics_apm/inst/faraday.rb +94 -0
  61. data/lib/appoptics_apm/inst/grpc_client.rb +162 -0
  62. data/lib/appoptics_apm/inst/grpc_server.rb +120 -0
  63. data/lib/appoptics_apm/inst/http.rb +73 -0
  64. data/lib/appoptics_apm/inst/httpclient.rb +174 -0
  65. data/lib/appoptics_apm/inst/memcached.rb +86 -0
  66. data/lib/appoptics_apm/inst/mongo.rb +246 -0
  67. data/lib/appoptics_apm/inst/mongo2.rb +225 -0
  68. data/lib/appoptics_apm/inst/moped.rb +466 -0
  69. data/lib/appoptics_apm/inst/rack.rb +199 -0
  70. data/lib/appoptics_apm/inst/redis.rb +275 -0
  71. data/lib/appoptics_apm/inst/resque.rb +151 -0
  72. data/lib/appoptics_apm/inst/rest-client.rb +48 -0
  73. data/lib/appoptics_apm/inst/sequel.rb +178 -0
  74. data/lib/appoptics_apm/inst/sidekiq-client.rb +55 -0
  75. data/lib/appoptics_apm/inst/sidekiq-worker.rb +65 -0
  76. data/lib/appoptics_apm/inst/twitter-cassandra.rb +294 -0
  77. data/lib/appoptics_apm/inst/typhoeus.rb +108 -0
  78. data/lib/appoptics_apm/instrumentation.rb +22 -0
  79. data/lib/appoptics_apm/legacy_method_profiling.rb +90 -0
  80. data/lib/appoptics_apm/loading.rb +65 -0
  81. data/lib/appoptics_apm/logger.rb +42 -0
  82. data/lib/appoptics_apm/method_profiling.rb +33 -0
  83. data/lib/appoptics_apm/noop/README.md +9 -0
  84. data/lib/appoptics_apm/noop/context.rb +26 -0
  85. data/lib/appoptics_apm/noop/metadata.rb +22 -0
  86. data/lib/appoptics_apm/ruby.rb +35 -0
  87. data/lib/appoptics_apm/sdk/custom_metrics.rb +92 -0
  88. data/lib/appoptics_apm/sdk/tracing.rb +315 -0
  89. data/lib/appoptics_apm/support.rb +119 -0
  90. data/lib/appoptics_apm/test.rb +94 -0
  91. data/lib/appoptics_apm/thread_local.rb +26 -0
  92. data/lib/appoptics_apm/util.rb +319 -0
  93. data/lib/appoptics_apm/version.rb +15 -0
  94. data/lib/appoptics_apm/xtrace.rb +103 -0
  95. data/lib/joboe_metal.rb +212 -0
  96. data/lib/oboe.rb +7 -0
  97. data/lib/oboe/README +2 -0
  98. data/lib/oboe/backward_compatibility.rb +80 -0
  99. data/lib/oboe/inst/rack.rb +11 -0
  100. data/lib/oboe_metal.rb +198 -0
  101. data/lib/rails/generators/appoptics_apm/install_generator.rb +45 -0
  102. data/lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb +265 -0
  103. data/yardoc_frontpage.md +26 -0
  104. metadata +266 -0
@@ -0,0 +1,15 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ ##
6
+ # The current version of the gem. Used mainly by
7
+ # appoptics_apm.gemspec during gem build process
8
+ module Version
9
+ MAJOR = 4
10
+ MINOR = 5
11
+ PATCH = 2
12
+
13
+ STRING = [MAJOR, MINOR, PATCH].compact.join('.')
14
+ end
15
+ end
@@ -0,0 +1,103 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ ##
6
+ # Methods to act on, manipulate or investigate an X-Trace
7
+ # value
8
+ module XTrace
9
+ class << self
10
+ ##
11
+ # AppOpticsAPM::XTrace.valid?
12
+ #
13
+ # Perform basic validation on a potential X-Trace ID
14
+ #
15
+ def valid?(xtrace)
16
+ # Shouldn't be nil
17
+ return false unless xtrace
18
+
19
+ # The X-Trace ID shouldn't be an initialized empty ID
20
+ return false if (xtrace =~ /^2b0000000/i) == 0
21
+
22
+ # Valid X-Trace IDs have a length of 60 bytes and start with '2b'
23
+ return false unless xtrace.length == 60 && (xtrace =~ /^2b/i) == 0
24
+
25
+ true
26
+ rescue StandardError => e
27
+ AppOpticsAPM.logger.debug "[appoptics_apm/xtrace] #{e.message}"
28
+ AppOpticsAPM.logger.debug e.backtrace
29
+ false
30
+ end
31
+
32
+ def sampled?(xtrace)
33
+ valid?(xtrace) && xtrace[59].to_i & 1 == 1
34
+ end
35
+
36
+ def set_sampled(xtrace)
37
+ xtrace[59] = (xtrace[59].hex | 1).to_s(16).upcase
38
+ end
39
+
40
+ def unset_sampled(xtrace)
41
+ xtrace[59] = (~(~xtrace[59].hex | 1)).to_s(16).upcase
42
+ end
43
+
44
+ ##
45
+ # AppOpticsAPM::XTrace.task_id
46
+ #
47
+ # Extract and return the task_id portion of an X-Trace ID
48
+ #
49
+ def task_id(xtrace)
50
+ return nil unless AppOpticsAPM::XTrace.valid?(xtrace)
51
+
52
+ xtrace[2..41]
53
+ rescue StandardError => e
54
+ AppOpticsAPM.logger.debug "[appoptics_apm/xtrace] #{e.message}"
55
+ AppOpticsAPM.logger.debug e.backtrace
56
+ return nil
57
+ end
58
+
59
+ ##
60
+ # AppOpticsAPM::XTrace.edge_id
61
+ #
62
+ # Extract and return the edge_id portion of an X-Trace ID
63
+ #
64
+ def edge_id(xtrace)
65
+ return nil unless AppOpticsAPM::XTrace.valid?(xtrace)
66
+
67
+ xtrace[42..57]
68
+ rescue StandardError => e
69
+ AppOpticsAPM.logger.debug "[appoptics_apm/xtrace] #{e.message}"
70
+ AppOpticsAPM.logger.debug e.backtrace
71
+ return nil
72
+ end
73
+
74
+ ##
75
+ # continue_service_context
76
+ #
77
+ # In the case of service calls such as external HTTP requests, we
78
+ # pass along X-Trace headers so that request context can be maintained
79
+ # across servers and applications.
80
+ #
81
+ # Remote requests can return a X-Trace header in which case we want
82
+ # to pickup on and continue the context in most cases.
83
+ #
84
+ # @start is the context just before the outgoing request
85
+ #
86
+ # @finish is the context returned to us (as an HTTP response header
87
+ # if that be the case)
88
+ #
89
+ def continue_service_context(start, finish)
90
+ if AppOpticsAPM::XTrace.valid?(finish) && AppOpticsAPM.tracing?
91
+
92
+ # Assure that we received back a valid X-Trace with the same task_id
93
+ # and the sampling bit is set, otherwise it is a response from a non-sampling service
94
+ if AppOpticsAPM::XTrace.task_id(start) == AppOpticsAPM::XTrace.task_id(finish) && AppOpticsAPM::XTrace.sampled?(finish)
95
+ AppOpticsAPM::Context.fromString(finish)
96
+ else
97
+ AppOpticsAPM.logger.debug "[XTrace] Sampling flag unset or mismatched start and finish ids:\n#{start}\n#{finish}"
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,212 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module Oboe_metal
5
+ include_package 'com.tracelytics.joboe'
6
+ java_import 'com.tracelytics.joboe.LayerUtil'
7
+ java_import 'com.tracelytics.joboe.SettingsReader'
8
+ java_import 'com.tracelytics.joboe.Context'
9
+ java_import 'com.tracelytics.joboe.Event'
10
+ java_import 'com.tracelytics.agent.Agent'
11
+
12
+ class Context
13
+ class << self
14
+ def toString
15
+ getMetadata.toHexString
16
+ end
17
+
18
+ def fromString(xtrace)
19
+ Context.setMetadata(xtrace)
20
+ end
21
+
22
+ def clear
23
+ clearMetadata
24
+ end
25
+
26
+ def get
27
+ getMetadata
28
+ end
29
+ end
30
+ end
31
+
32
+ module EventUtil
33
+ def self.metadataString(evt)
34
+ evt.getMetadata.toHexString
35
+ end
36
+ end
37
+
38
+ def UdpReporter
39
+ Java::ComTracelyticsJoboe
40
+ end
41
+
42
+ module Metadata
43
+ Java::ComTracelyticsJoboeMetaData
44
+ end
45
+
46
+ module Reporter
47
+ class << self
48
+ ##
49
+ # start
50
+ #
51
+ # Start the AppOpticsAPM Reporter
52
+ #
53
+ def start
54
+ return unless AppOpticsAPM.loaded
55
+
56
+ if ENV.key?('APPOPTICS_GEM_TEST')
57
+ AppOpticsAPM.reporter = Java::ComTracelyticsJoboe::ReporterFactory.getInstance.buildTestReporter(false)
58
+ else
59
+ AppOpticsAPM.reporter = Java::ComTracelyticsJoboe::ReporterFactory.getInstance.buildUdpReporter
60
+ end
61
+
62
+ begin
63
+ # Import the tracing mode and sample rate settings
64
+ # from the Java agent (user configured in
65
+ # /usr/local/tracelytics/javaagent.json when under JRuby)
66
+ cfg = LayerUtil.getLocalSampleRate(nil, nil)
67
+
68
+ if cfg.hasSampleStartFlag
69
+ AppOpticsAPM::Config.tracing_mode = :always
70
+ else
71
+ AppOpticsAPM::Config.tracing_mode = :never
72
+ end
73
+
74
+ AppOpticsAPM.sample_rate = cfg.getSampleRate
75
+ AppOpticsAPM::Config.sample_rate = cfg.sampleRate
76
+ AppOpticsAPM::Config.sample_source = cfg.sampleRateSourceValue
77
+ rescue => e
78
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] Couldn't retrieve/acces joboe sampleRateCfg"
79
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{e.message}"
80
+ end
81
+
82
+ # Only report __Init from here if we are not instrumenting a framework.
83
+ # Otherwise, frameworks will handle reporting __Init after full initialization
84
+ unless defined?(::Rails) || defined?(::Sinatra) || defined?(::Padrino) || defined?(::Grape)
85
+ AppOpticsAPM::API.report_init unless ENV.key?('APPOPTICS_GEM_TEST')
86
+ end
87
+ end
88
+
89
+ ##
90
+ # restart
91
+ #
92
+ # This is a nil method for AppOpticsAPM under Java. It is maintained only
93
+ # for compability across interfaces.
94
+ #
95
+ def restart
96
+ AppOpticsAPM.logger.warn "[appoptics_apm/reporter] Reporter.restart isn't supported under JRuby"
97
+ end
98
+
99
+ ##
100
+ # clear_all_traces
101
+ #
102
+ # Truncates the trace output file to zero
103
+ #
104
+ def clear_all_traces
105
+ AppOpticsAPM.reporter.reset if AppOpticsAPM.loaded
106
+ end
107
+
108
+ ##
109
+ # get_all_traces
110
+ #
111
+ # Retrieves all traces written to the trace file
112
+ #
113
+ def get_all_traces
114
+ return [] unless AppOpticsAPM.loaded
115
+
116
+ # Joboe TestReporter returns a Java::ComTracelyticsExtEbson::DefaultDocument
117
+ # document for traces which doesn't correctly support things like has_key? which
118
+ # raises an unhandled exception on non-existent key (duh). Here we convert
119
+ # the Java::ComTracelyticsExtEbson::DefaultDocument doc to a pure array of Ruby
120
+ # hashes
121
+ traces = []
122
+ AppOpticsAPM.reporter.getSentEventsAsBsonDocument.to_a.each do |e|
123
+ t = {}
124
+ e.each_pair { |k, v|
125
+ t[k] = v
126
+ }
127
+ traces << t
128
+ end
129
+ traces
130
+ end
131
+
132
+ def sendReport(evt)
133
+ evt.report(AppOpticsAPM.reporter)
134
+ end
135
+ end
136
+ end
137
+ end
138
+
139
+ module AppOpticsAPM
140
+ extend AppOpticsAPMBase
141
+ include Oboe_metal
142
+
143
+ class << self
144
+ def sample?(opts = {})
145
+ begin
146
+ # Return false if no-op mode
147
+ return false unless AppOpticsAPM.loaded
148
+
149
+ return true if ENV.key?('APPOPTICS_GEM_TEST')
150
+
151
+ # Validation to make Joboe happy. Assure that we have the KVs and that they
152
+ # are not empty strings.
153
+ opts[:xtrace] = nil if opts[:xtrace].is_a?(String) && opts[:xtrace].empty?
154
+
155
+ opts[:xtrace] ||= nil
156
+
157
+ sr_cfg = Java::ComTracelyticsJoboe::LayerUtil.shouldTraceRequest(APPOPTICS_STR_BLANK, { 'X-Trace' => opts[:xtrace] })
158
+
159
+ # Store the returned SampleRateConfig into AppOpticsAPM::Config
160
+ if sr_cfg
161
+ begin
162
+ AppOpticsAPM::Config.sample_rate = sr_cfg.sampleRate
163
+ AppOpticsAPM::Config.sample_source = sr_cfg.sampleRateSourceValue
164
+ # If we fail here, we do so quietly. This was we don't spam logs
165
+ # on every request
166
+ end
167
+ else
168
+ AppOpticsAPM.sample_rate = -1
169
+ AppOpticsAPM.sample_source = -1
170
+ end
171
+
172
+ sr_cfg ? true : false
173
+ rescue => e
174
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{e.message}"
175
+ false
176
+ end
177
+ end
178
+
179
+ def set_tracing_mode(_mode)
180
+ AppOpticsAPM.logger.warn '[appoptics_apm/joboe] When using JRuby set the tracing mode in /usr/local/tracelytics/javaagent.json instead'
181
+ end
182
+
183
+ def set_sample_rate(_rate)
184
+ # N/A
185
+ end
186
+ end
187
+ end
188
+
189
+ # Assure that the Joboe Java Agent was loaded via premain
190
+ case Java::ComTracelyticsAgent::Agent.getStatus
191
+ when Java::ComTracelyticsAgent::Agent::AgentStatus::INITIALIZED_SUCCESSFUL
192
+ AppOpticsAPM.loaded = true
193
+
194
+ when Java::ComTracelyticsAgent::Agent::AgentStatus::INITIALIZED_FAILED
195
+ AppOpticsAPM.loaded = false
196
+ $stderr.puts '=============================================================='
197
+ $stderr.puts 'AppOpticsAPM Java Agent not initialized properly.'
198
+ $stderr.puts 'Possibly misconfigured? Going into no-op mode.'
199
+ $stderr.puts 'http://docs.appoptics.solarwinds.com/Instrumentation/other-instrumentation-modules.html#jruby'
200
+ $stderr.puts '=============================================================='
201
+
202
+ when Java::ComTracelyticsAgent::Agent::AgentStatus::UNINITIALIZED
203
+ AppOpticsAPM.loaded = false
204
+ $stderr.puts '=============================================================='
205
+ $stderr.puts 'AppOpticsAPM Java Agent not loaded. Going into no-op mode.'
206
+ $stderr.puts 'To preload the AppOpticsAPM java agent see:'
207
+ $stderr.puts 'http://docs.appoptics.solarwinds.com/Instrumentation/other-instrumentation-modules.html#jruby'
208
+ $stderr.puts '=============================================================='
209
+
210
+ else
211
+ AppOpticsAPM.loaded = false
212
+ end
@@ -0,0 +1,7 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ # This module is provided for backward compatibility.
5
+ # It simply redirects to the appoptics_apm module which will
6
+ # also load backward compatibility support.
7
+ require 'appoptics_apm'
@@ -0,0 +1,2 @@
1
+ This directory is kept for backward compatibility for applications
2
+ making calls to Oboe modules.
@@ -0,0 +1,80 @@
1
+ require 'appoptics_apm/thread_local'
2
+
3
+ module Oboe
4
+ extend AppOpticsAPMBase
5
+ if AppOpticsAPM.loaded
6
+ include Oboe_metal
7
+ end
8
+
9
+ #
10
+ # Support for Oboe::API calls
11
+ #
12
+ module API
13
+ include AppOpticsAPM::API
14
+ extend AppOpticsAPM::ThreadLocal
15
+ thread_local :deprecation_notified
16
+
17
+ def self.method_missing(sym, *args, &blk)
18
+ # Notify of deprecation only once
19
+ unless @deprecated_notified
20
+ AppOpticsAPM.logger.warn "[appoptics_apm/warn] Note that Oboe::API has been renamed to AppOpticsAPM::API. (#{sym}:#{args})"
21
+ AppOpticsAPM.logger.warn '[appoptics_apm/warn] Oboe::API will be deprecated in a future version.'
22
+ AppOpticsAPM.logger.warn "[appoptics_apm/warn] Caller: #{Kernel.caller[0]}"
23
+ @deprecated_notified = true
24
+ end
25
+ AppOpticsAPM::API.send(sym, *args, &blk)
26
+ end
27
+ end
28
+
29
+
30
+ #
31
+ # Support for Oboe::Config calls
32
+ #
33
+ module Config
34
+ extend AppOpticsAPM::ThreadLocal
35
+ thread_local :deprecation_notified
36
+
37
+ def self.method_missing(sym, *args)
38
+ # Notify of deprecation only once
39
+ unless @deprecated_notified
40
+ AppOpticsAPM.logger.warn "[appoptics_apm/warn] Note that Oboe::Config has been renamed to AppOpticsAPM::Config. (#{sym}:#{args})"
41
+ AppOpticsAPM.logger.warn '[appoptics_apm/warn] Oboe::Config will be deprecated in a future version.'
42
+ AppOpticsAPM.logger.warn "[appoptics_apm/warn] Caller: #{Kernel.caller[0]}"
43
+ @deprecated_notified = true
44
+ end
45
+ AppOpticsAPM::Config.send(sym, *args)
46
+ end
47
+ end
48
+
49
+ #
50
+ # Support for legacy Oboe::Ruby.load calls
51
+ #
52
+ module Ruby
53
+ extend AppOpticsAPM::ThreadLocal
54
+ thread_local :deprecation_notified
55
+
56
+ def self.method_missing(sym, *args)
57
+ # Notify of deprecation only once
58
+ unless @deprecated_notified
59
+ AppOpticsAPM.logger.warn "[appoptics_apm/warn] Note that Oboe::Ruby has been renamed to AppOpticsAPM::Ruby. (#{sym}:#{args})"
60
+ AppOpticsAPM.logger.warn '[appoptics_apm/warn] Oboe::Ruby will be deprecated in a future version.'
61
+ AppOpticsAPM.logger.warn "[appoptics_apm/warn] Caller: #{Kernel.caller[0]}"
62
+ @deprecated_notified = true
63
+ end
64
+ AppOpticsAPM::Ruby.send(sym, *args)
65
+ end
66
+ end
67
+ end
68
+
69
+ #
70
+ # Support for OboeMethodProfiling
71
+ #
72
+ module OboeMethodProfiling
73
+ def self.included(klass)
74
+ klass.extend ClassMethods
75
+ end
76
+
77
+ module ClassMethods
78
+ include AppOpticsAPMMethodProfiling::ClassMethods
79
+ end
80
+ end
@@ -0,0 +1,11 @@
1
+ require 'appoptics_apm/inst/rack'
2
+
3
+ module Oboe
4
+ class Rack < AppOpticsAPM::Rack
5
+ # This simply makes Oboe::Rack available (and a clone of AppOpticsAPM::Rack) for
6
+ # backward compatibility
7
+ #
8
+ # Provided for pre-existing apps (sinatra, padrino, grape etc..) that may still
9
+ # call `use Oboe::Rack`
10
+ end
11
+ end
@@ -0,0 +1,198 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require 'thread'
5
+
6
+ # Disable docs and Camelcase warns since we're implementing
7
+ # an interface here. See OboeBase for details.
8
+ # rubocop:disable Style/Documentation, Style/MethodName
9
+ module AppOpticsAPM
10
+ extend AppOpticsAPMBase
11
+ include Oboe_metal
12
+
13
+ class Reporter
14
+ class << self
15
+ ##
16
+ # start
17
+ #
18
+ # Start the AppOpticsAPM Reporter
19
+ #
20
+ def start
21
+ return unless AppOpticsAPM.loaded
22
+
23
+ begin
24
+ options = []
25
+
26
+ ENV['APPOPTICS_REPORTER'] = 'file' if ENV.key?('APPOPTICS_GEM_TEST')
27
+
28
+ case ENV['APPOPTICS_REPORTER']
29
+ when 'file'
30
+ ENV['APPOPTICS_REPORTER_FILE'] = TRACE_FILE
31
+ when 'udp'
32
+ ENV['APPOPTICS_REPORTER_UDP'] = "#{AppOpticsAPM::Config[:reporter_host]}:#{AppOpticsAPM::Config[:reporter_port]}"
33
+ else # default is ssl, service_key is mandatory
34
+ return unless valid_service_key?
35
+ # Oboe will override these settings if there are env settings for them
36
+ options << AppOpticsAPM::Config[:service_key].to_s
37
+ options << AppOpticsAPM::Config[:hostname_alias].to_s
38
+ options << AppOpticsAPM::Config[:debug_level] unless AppOpticsAPM::Config[:debug_level].nil?
39
+ end
40
+ AppOpticsAPM.reporter = Oboe_metal::Reporter.new(*options)
41
+
42
+ # Only report __Init from here if we are not instrumenting a framework.
43
+ # Otherwise, frameworks will handle reporting __Init after full initialization
44
+ unless defined?(::Rails) || defined?(::Sinatra) || defined?(::Padrino) || defined?(::Grape)
45
+ AppOpticsAPM::API.report_init
46
+ end
47
+
48
+ rescue => e
49
+ $stderr.puts e.message
50
+ raise
51
+ end
52
+ end
53
+ alias :restart :start
54
+
55
+ def valid_service_key?
56
+ service_key = (ENV['APPOPTICS_SERVICE_KEY'] || AppOpticsAPM::Config[:service_key]).to_s
57
+ if service_key == ''
58
+ AppOpticsAPM.logger.warn '[appoptics_apm/warn] APPOPTICS_SERVICE_KEY not set. Cannot submit data.'
59
+ AppOpticsAPM.loaded = false
60
+ return false
61
+ elsif service_key !~ /^[0-9a-fA-F]{64}:[-.:_?\\\/\w ]{1,255}$/
62
+ AppOpticsAPM.logger.warn '[appoptics_apm/warn] APPOPTICS_SERVICE_KEY problem. No service name or api token in wrong format. Cannot submit data.'
63
+ AppOpticsAPM.loaded = false
64
+ return false
65
+ end
66
+ true
67
+ end
68
+ ##
69
+ # sendReport
70
+ #
71
+ # Send the report for the given event
72
+ #
73
+ def sendReport(evt)
74
+ AppOpticsAPM.reporter.sendReport(evt)
75
+ end
76
+
77
+ ##
78
+ # sendStatus
79
+ #
80
+ # Send the report for the given event
81
+ #
82
+ def sendStatus(evt, context = nil)
83
+ AppOpticsAPM.reporter.sendStatus(evt, context)
84
+ end
85
+
86
+ ##
87
+ # clear_all_traces
88
+ #
89
+ # Truncates the trace output file to zero
90
+ #
91
+ def clear_all_traces
92
+ File.truncate(TRACE_FILE, 0)
93
+ end
94
+
95
+ ##
96
+ # get_all_traces
97
+ #
98
+ # Retrieves all traces written to the trace file
99
+ #
100
+ def get_all_traces
101
+ io = File.open(TRACE_FILE, 'r')
102
+ contents = io.readlines(nil)
103
+
104
+ return contents if contents.empty?
105
+
106
+ traces = []
107
+
108
+ #
109
+ # We use Gem.loaded_spec because older versions of the bson
110
+ # gem didn't even have a version embedded in the gem. If the
111
+ # gem isn't in the bundle, it should rightfully error out
112
+ # anyways.
113
+ #
114
+ if Gem.loaded_specs['bson'].version.to_s < '4.0'
115
+ s = StringIO.new(contents[0])
116
+
117
+ until s.eof?
118
+ traces << if ::BSON.respond_to? :read_bson_document
119
+ BSON.read_bson_document(s)
120
+ else
121
+ BSON::Document.from_bson(s)
122
+ end
123
+ end
124
+ else
125
+ bbb = BSON::ByteBuffer.new(contents[0])
126
+ until bbb.length == 0
127
+ traces << Hash.from_bson(bbb)
128
+ end
129
+ end
130
+
131
+ traces
132
+ end
133
+ end
134
+ end
135
+
136
+ module EventUtil
137
+ def self.metadataString(evt)
138
+ evt.metadataString
139
+ end
140
+ end
141
+
142
+ class << self
143
+ def sample?(opts = {})
144
+ # Return false if no-op mode
145
+ return false unless AppOpticsAPM.loaded
146
+
147
+ # Assure defaults since SWIG enforces Strings
148
+ xtrace = opts[:xtrace] ? opts[:xtrace].to_s.strip : APPOPTICS_STR_BLANK
149
+
150
+ # the first arg has changed to be the service name, blank means to use the default (from the service key)
151
+ rv = AppOpticsAPM::Context.sampleRequest(APPOPTICS_STR_BLANK, xtrace)
152
+
153
+ if rv == 0
154
+ AppOpticsAPM.sample_rate = -1
155
+ AppOpticsAPM.sample_source = -1
156
+ false
157
+ else
158
+ # liboboe version > 1.3.1 returning a bit masked integer with SampleRate and
159
+ # source embedded
160
+ AppOpticsAPM.sample_rate = (rv & SAMPLE_RATE_MASK)
161
+ AppOpticsAPM.sample_source = (rv & SAMPLE_SOURCE_MASK) >> 24
162
+ true
163
+ end
164
+ rescue StandardError => e
165
+ AppOpticsAPM.logger.debug "[oboe/error] sample? error: #{e.inspect}"
166
+ false
167
+ end
168
+
169
+ def set_tracing_mode(mode)
170
+ return unless AppOpticsAPM.loaded
171
+
172
+ value = mode.to_sym
173
+
174
+ case value
175
+ when :never
176
+ AppOpticsAPM::Context.setTracingMode(APPOPTICS_TRACE_NEVER)
177
+
178
+ when :always
179
+ AppOpticsAPM::Context.setTracingMode(APPOPTICS_TRACE_ALWAYS)
180
+
181
+ else
182
+ AppOpticsAPM.logger.fatal "[oboe/error] Invalid tracing mode set: #{mode}"
183
+ AppOpticsAPM::Context.setTracingMode(APPOPTICS_TRACE_NEVER)
184
+ end
185
+ end
186
+
187
+ def set_sample_rate(rate)
188
+ return unless AppOpticsAPM.loaded
189
+
190
+ # Update liboboe with the new SampleRate value
191
+ AppOpticsAPM::Context.setDefaultSampleRate(rate.to_i)
192
+ end
193
+ end
194
+ end
195
+ # rubocop:enable Style/Documentation
196
+
197
+ AppOpticsAPM.loaded = true
198
+ AppOpticsAPM.config_lock = Mutex.new