solarwinds_apm 5.0.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.
Files changed (142) 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/.github/workflows/build_and_release_gem.yml +112 -0
  5. data/.github/workflows/build_for_packagecloud.yml +70 -0
  6. data/.github/workflows/docker-images.yml +47 -0
  7. data/.github/workflows/run_cpluplus_tests.yml +73 -0
  8. data/.github/workflows/run_tests.yml +155 -0
  9. data/.github/workflows/scripts/test_install.rb +23 -0
  10. data/.github/workflows/swig/swig-v4.0.2.tar.gz +0 -0
  11. data/.github/workflows/test_on_4_linux.yml +161 -0
  12. data/.gitignore +39 -0
  13. data/.rubocop.yml +29 -0
  14. data/.yardopts +7 -0
  15. data/CHANGELOG.md +769 -0
  16. data/CONFIG.md +31 -0
  17. data/Gemfile +14 -0
  18. data/LICENSE +202 -0
  19. data/README.md +383 -0
  20. data/bin/solarwinds_apm_config +15 -0
  21. data/examples/prepend.rb +13 -0
  22. data/examples/sdk_examples.rb +158 -0
  23. data/ext/oboe_metal/README.md +69 -0
  24. data/ext/oboe_metal/extconf.rb +141 -0
  25. data/ext/oboe_metal/extconf_local.rb +75 -0
  26. data/ext/oboe_metal/lib/.keep +0 -0
  27. data/ext/oboe_metal/lib/liboboe-1.0-alpine-x86_64.so.0.0.0.sha256 +1 -0
  28. data/ext/oboe_metal/lib/liboboe-1.0-x86_64.so.0.0.0.sha256 +1 -0
  29. data/ext/oboe_metal/noop/noop.c +8 -0
  30. data/ext/oboe_metal/src/README.md +6 -0
  31. data/ext/oboe_metal/src/VERSION +2 -0
  32. data/ext/oboe_metal/src/bson/bson.h +220 -0
  33. data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
  34. data/ext/oboe_metal/src/frames.cc +247 -0
  35. data/ext/oboe_metal/src/frames.h +40 -0
  36. data/ext/oboe_metal/src/init_solarwinds_apm.cc +21 -0
  37. data/ext/oboe_metal/src/logging.cc +95 -0
  38. data/ext/oboe_metal/src/logging.h +35 -0
  39. data/ext/oboe_metal/src/oboe.h +1169 -0
  40. data/ext/oboe_metal/src/oboe_api.cpp +658 -0
  41. data/ext/oboe_metal/src/oboe_api.hpp +433 -0
  42. data/ext/oboe_metal/src/oboe_debug.h +59 -0
  43. data/ext/oboe_metal/src/oboe_swig_wrap.cc +7562 -0
  44. data/ext/oboe_metal/src/profiling.cc +435 -0
  45. data/ext/oboe_metal/src/profiling.h +78 -0
  46. data/ext/oboe_metal/test/CMakeLists.txt +53 -0
  47. data/ext/oboe_metal/test/FindGMock.cmake +43 -0
  48. data/ext/oboe_metal/test/README.md +56 -0
  49. data/ext/oboe_metal/test/frames_test.cc +164 -0
  50. data/ext/oboe_metal/test/profiling_test.cc +93 -0
  51. data/ext/oboe_metal/test/ruby_inc_dir.rb +8 -0
  52. data/ext/oboe_metal/test/ruby_prefix.rb +8 -0
  53. data/ext/oboe_metal/test/ruby_test_helper.rb +67 -0
  54. data/ext/oboe_metal/test/test.h +11 -0
  55. data/ext/oboe_metal/test/test_main.cc +32 -0
  56. data/init.rb +4 -0
  57. data/lib/oboe.rb +7 -0
  58. data/lib/oboe_metal.rb +172 -0
  59. data/lib/rails/generators/solarwinds_apm/install_generator.rb +47 -0
  60. data/lib/rails/generators/solarwinds_apm/templates/solarwinds_apm_initializer.rb +424 -0
  61. data/lib/solarwinds_apm/api/layerinit.rb +41 -0
  62. data/lib/solarwinds_apm/api/logging.rb +356 -0
  63. data/lib/solarwinds_apm/api/memcache.rb +37 -0
  64. data/lib/solarwinds_apm/api/metrics.rb +63 -0
  65. data/lib/solarwinds_apm/api/util.rb +98 -0
  66. data/lib/solarwinds_apm/api.rb +21 -0
  67. data/lib/solarwinds_apm/base.rb +160 -0
  68. data/lib/solarwinds_apm/config.rb +301 -0
  69. data/lib/solarwinds_apm/frameworks/grape.rb +96 -0
  70. data/lib/solarwinds_apm/frameworks/padrino.rb +78 -0
  71. data/lib/solarwinds_apm/frameworks/rails/inst/action_controller.rb +100 -0
  72. data/lib/solarwinds_apm/frameworks/rails/inst/action_controller5.rb +50 -0
  73. data/lib/solarwinds_apm/frameworks/rails/inst/action_controller_api.rb +50 -0
  74. data/lib/solarwinds_apm/frameworks/rails/inst/action_view.rb +88 -0
  75. data/lib/solarwinds_apm/frameworks/rails/inst/active_record.rb +26 -0
  76. data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +29 -0
  77. data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +22 -0
  78. data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +103 -0
  79. data/lib/solarwinds_apm/frameworks/rails/inst/logger_formatters.rb +14 -0
  80. data/lib/solarwinds_apm/frameworks/rails.rb +100 -0
  81. data/lib/solarwinds_apm/frameworks/sinatra.rb +96 -0
  82. data/lib/solarwinds_apm/inst/bunny-client.rb +157 -0
  83. data/lib/solarwinds_apm/inst/bunny-consumer.rb +102 -0
  84. data/lib/solarwinds_apm/inst/curb.rb +288 -0
  85. data/lib/solarwinds_apm/inst/dalli.rb +89 -0
  86. data/lib/solarwinds_apm/inst/delayed_job.rb +100 -0
  87. data/lib/solarwinds_apm/inst/excon.rb +113 -0
  88. data/lib/solarwinds_apm/inst/faraday.rb +96 -0
  89. data/lib/solarwinds_apm/inst/graphql.rb +206 -0
  90. data/lib/solarwinds_apm/inst/grpc_client.rb +147 -0
  91. data/lib/solarwinds_apm/inst/grpc_server.rb +119 -0
  92. data/lib/solarwinds_apm/inst/httpclient.rb +181 -0
  93. data/lib/solarwinds_apm/inst/logger_formatter.rb +46 -0
  94. data/lib/solarwinds_apm/inst/logging_log_event.rb +24 -0
  95. data/lib/solarwinds_apm/inst/lumberjack_formatter.rb +9 -0
  96. data/lib/solarwinds_apm/inst/memcached.rb +86 -0
  97. data/lib/solarwinds_apm/inst/mongo.rb +246 -0
  98. data/lib/solarwinds_apm/inst/mongo2.rb +225 -0
  99. data/lib/solarwinds_apm/inst/moped.rb +466 -0
  100. data/lib/solarwinds_apm/inst/net_http.rb +60 -0
  101. data/lib/solarwinds_apm/inst/rack.rb +217 -0
  102. data/lib/solarwinds_apm/inst/rack_cache.rb +35 -0
  103. data/lib/solarwinds_apm/inst/redis.rb +273 -0
  104. data/lib/solarwinds_apm/inst/resque.rb +129 -0
  105. data/lib/solarwinds_apm/inst/rest-client.rb +43 -0
  106. data/lib/solarwinds_apm/inst/sequel.rb +241 -0
  107. data/lib/solarwinds_apm/inst/sidekiq-client.rb +63 -0
  108. data/lib/solarwinds_apm/inst/sidekiq-worker.rb +64 -0
  109. data/lib/solarwinds_apm/inst/typhoeus.rb +90 -0
  110. data/lib/solarwinds_apm/instrumentation.rb +22 -0
  111. data/lib/solarwinds_apm/loading.rb +65 -0
  112. data/lib/solarwinds_apm/logger.rb +14 -0
  113. data/lib/solarwinds_apm/noop/README.md +9 -0
  114. data/lib/solarwinds_apm/noop/context.rb +26 -0
  115. data/lib/solarwinds_apm/noop/metadata.rb +25 -0
  116. data/lib/solarwinds_apm/noop/profiling.rb +21 -0
  117. data/lib/solarwinds_apm/oboe_init_options.rb +191 -0
  118. data/lib/solarwinds_apm/ruby.rb +35 -0
  119. data/lib/solarwinds_apm/sdk/current_trace_info.rb +123 -0
  120. data/lib/solarwinds_apm/sdk/custom_metrics.rb +94 -0
  121. data/lib/solarwinds_apm/sdk/logging.rb +37 -0
  122. data/lib/solarwinds_apm/sdk/trace_context_headers.rb +69 -0
  123. data/lib/solarwinds_apm/sdk/tracing.rb +432 -0
  124. data/lib/solarwinds_apm/support/profiling.rb +22 -0
  125. data/lib/solarwinds_apm/support/trace_context.rb +53 -0
  126. data/lib/solarwinds_apm/support/trace_state.rb +69 -0
  127. data/lib/solarwinds_apm/support/trace_string.rb +89 -0
  128. data/lib/solarwinds_apm/support/transaction_metrics.rb +67 -0
  129. data/lib/solarwinds_apm/support/transaction_settings.rb +233 -0
  130. data/lib/solarwinds_apm/support/x_trace_options.rb +113 -0
  131. data/lib/solarwinds_apm/support.rb +12 -0
  132. data/lib/solarwinds_apm/support_report.rb +113 -0
  133. data/lib/solarwinds_apm/test.rb +165 -0
  134. data/lib/solarwinds_apm/thread_local.rb +26 -0
  135. data/lib/solarwinds_apm/util.rb +334 -0
  136. data/lib/solarwinds_apm/version.rb +17 -0
  137. data/lib/solarwinds_apm.rb +72 -0
  138. data/log/.keep +0 -0
  139. data/log/postgresql/.keep +0 -0
  140. data/solarwinds_apm.gemspec +52 -0
  141. data/yardoc_frontpage.md +24 -0
  142. metadata +228 -0
@@ -0,0 +1,119 @@
1
+ # Copyright (c) 2018 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module SolarWindsAPM
5
+ module GRPC
6
+
7
+ if defined? ::GRPC
8
+ STATUSCODES = {}
9
+ ::GRPC::Core::StatusCodes.constants.each { |code| STATUSCODES[::GRPC::Core::StatusCodes.const_get(code)] = code }
10
+ end
11
+
12
+ module RpcDesc
13
+
14
+ def self.included(klass)
15
+ ::SolarWindsAPM::Util.method_alias(klass, :handle_request_response, ::GRPC::RpcDesc)
16
+ ::SolarWindsAPM::Util.method_alias(klass, :handle_client_streamer, ::GRPC::RpcDesc)
17
+ ::SolarWindsAPM::Util.method_alias(klass, :handle_server_streamer, ::GRPC::RpcDesc)
18
+ ::SolarWindsAPM::Util.method_alias(klass, :handle_bidi_streamer, ::GRPC::RpcDesc)
19
+ ::SolarWindsAPM::Util.method_alias(klass, :run_server_method, ::GRPC::RpcDesc)
20
+ end
21
+
22
+ def grpc_tags(active_call, mth)
23
+ tags = {
24
+ 'Spec' => 'grpc_server',
25
+ 'URL' => active_call.metadata['method'],
26
+ 'Controller' => mth.owner.to_s,
27
+ 'Action' => mth.name.to_s,
28
+ 'HTTP-Host' => active_call.peer
29
+ }
30
+
31
+ if request_response?
32
+ tags['GRPCMethodType'] = 'UNARY'
33
+ elsif client_streamer?
34
+ tags['GRPCMethodType'] = 'CLIENT_STREAMING'
35
+ elsif server_streamer?
36
+ tags['GRPCMethodType'] = 'SERVER_STREAMING'
37
+ else
38
+ # is a bidi_stream
39
+ tags['GRPCMethodType'] = 'BIDI_STREAMING'
40
+ end
41
+
42
+ tags
43
+ end
44
+
45
+ def handle_request_response_with_sw_apm(active_call, mth, inter_ctx)
46
+ handle_call('handle_request_response_without_sw_apm', active_call, mth, inter_ctx)
47
+ end
48
+
49
+ def handle_client_streamer_with_sw_apm(active_call, mth, inter_ctx)
50
+ handle_call('handle_client_streamer_without_sw_apm', active_call, mth, inter_ctx)
51
+ end
52
+
53
+ def handle_server_streamer_with_sw_apm(active_call, mth, inter_ctx)
54
+ handle_call('handle_server_streamer_without_sw_apm', active_call, mth, inter_ctx)
55
+ end
56
+
57
+ def handle_bidi_streamer_with_sw_apm(active_call, mth, inter_ctx)
58
+ handle_call('handle_bidi_streamer_without_sw_apm', active_call, mth, inter_ctx)
59
+ end
60
+
61
+ # status codes need to be determined in this lower method, because they may not get raised to the
62
+ # next instrumented method
63
+ def handle_call(without, active_call, mth, inter_ctx)
64
+ begin
65
+ send(without, active_call, mth, inter_ctx)
66
+ rescue ::GRPC::Core::CallError, ::GRPC::BadStatus, ::GRPC::Core::OutOfTime, StandardError, NotImplementedError => e
67
+ log_grpc_exception(active_call, e)
68
+ raise e
69
+ end
70
+ end
71
+
72
+ def run_server_method_with_sw_apm(active_call, mth, inter_ctx)
73
+ tags = grpc_tags(active_call, mth)
74
+
75
+ SolarWindsAPM::API.log_start('grpc-server', tags, active_call.metadata)
76
+
77
+ begin
78
+ SolarWindsAPM::API.send_metrics('grpc-server', tags) do
79
+ run_server_method_without_sw_apm(active_call, mth, inter_ctx)
80
+ end
81
+ rescue => e
82
+ log_grpc_exception(active_call, e)
83
+ raise e
84
+ ensure
85
+ tags['GRPCStatus'] = active_call.metadata_to_send.delete('grpc_status')
86
+ tags['GRPCStatus'] ||= active_call.status ? SolarWindsAPM::GRPC::STATUSCODES[active_call.status.code].to_s : 'OK'
87
+ tags['Backtrace'] = SolarWindsAPM::API.backtrace if SolarWindsAPM::Config[:grpc_server][:collect_backtraces]
88
+
89
+ SolarWindsAPM::API.log_end('grpc-server', tags)
90
+ end
91
+ end
92
+
93
+ private
94
+
95
+ def log_grpc_exception(active_call, e)
96
+ unless e.instance_variable_get(:@exn_logged)
97
+ SolarWindsAPM::API.log_exception('grpc-server', e)
98
+
99
+ unless active_call.metadata_sent
100
+ if e.class == ::GRPC::Core::OutOfTime
101
+ active_call.merge_metadata_to_send({ 'grpc_status' => 'DEADLINE_EXCEEDED' })
102
+ elsif e.respond_to?(:code)
103
+ active_call.merge_metadata_to_send({ 'grpc_status' => SolarWindsAPM::GRPC::STATUSCODES[e.code].to_s })
104
+ else
105
+ active_call.merge_metadata_to_send({ 'grpc_status' => 'UNKNOWN' })
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ end
112
+
113
+ end
114
+ end
115
+
116
+ if defined?(GRPC) && SolarWindsAPM::Config['grpc_server'][:enabled]
117
+ # server side is instrumented in RpcDesc
118
+ SolarWindsAPM::Util.send_include(GRPC::RpcDesc, SolarWindsAPM::GRPC::RpcDesc)
119
+ end
@@ -0,0 +1,181 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module SolarWindsAPM
5
+ module Inst
6
+ module HTTPClient
7
+
8
+ def sw_apm_collect(method, uri, query = nil)
9
+ kvs = {}
10
+ kvs[:Spec] = 'rsc'
11
+ kvs[:IsService] = 1
12
+
13
+ # Conditionally log URL query params
14
+ # Because of the hook points, the query arg can come in under <tt>query</tt>
15
+ # or as a part of <tt>uri</tt> (not both). Here we handle both cases.
16
+ if SolarWindsAPM::Config[:httpclient][:log_args]
17
+ if query
18
+ kvs[:RemoteURL] = uri.to_s + '?' + SolarWindsAPM::Util.to_query(query)
19
+ else
20
+ kvs[:RemoteURL] = uri.to_s
21
+ end
22
+ else
23
+ kvs[:RemoteURL] = uri.to_s.split('?').first
24
+ end
25
+
26
+ kvs[:HTTPMethod] = SolarWindsAPM::Util.upcase(method)
27
+ kvs
28
+ rescue => e
29
+ SolarWindsAPM.logger.debug "[solarwinds_apm/debug] Error capturing httpclient KVs: #{e.message}"
30
+ SolarWindsAPM.logger.debug e.backtrace.join('\n') if SolarWindsAPM::Config[:verbose]
31
+ ensure
32
+ return kvs
33
+ end
34
+
35
+ def do_request(method, uri, query, body, header, &block)
36
+ # If we're not tracing, just do a fast return.
37
+ unless SolarWindsAPM.tracing?
38
+ add_trace_header(header)
39
+ return super(method, uri, query, body, header, &block)
40
+ end
41
+
42
+ begin
43
+ kvs = sw_apm_collect(method, uri, query)
44
+
45
+ SolarWindsAPM::API.log_entry(:httpclient, kvs)
46
+ kvs.clear
47
+ kvs[:Backtrace] = SolarWindsAPM::API.backtrace if SolarWindsAPM::Config[:httpclient][:collect_backtraces]
48
+
49
+ add_trace_header(header)
50
+
51
+ # The core httpclient call
52
+ response = super(method, uri, query, body, header, &block)
53
+ kvs[:HTTPStatus] = response.status_code
54
+
55
+ # If we get a redirect, report the location header
56
+ if ((300..308).to_a.include? response.status.to_i) && response.headers.key?('Location')
57
+ kvs[:Location] = response.headers['Location']
58
+ end
59
+
60
+ response
61
+ rescue => e
62
+ SolarWindsAPM::API.log_exception(:httpclient, e)
63
+ raise e
64
+ ensure
65
+ SolarWindsAPM::API.log_exit(:httpclient, kvs)
66
+ end
67
+ end
68
+
69
+ def do_request_async(method, uri, query, body, header)
70
+ add_trace_header(header)
71
+ # added headers because this calls `do_get_stream` in a new thread
72
+ # threads do not inherit thread local variables like SolarWindsAPM.trace_context
73
+ super(method, uri, query, body, header)
74
+ end
75
+
76
+ def do_get_stream(req, proxy, conn)
77
+ # called from `do_request_async` in a new thread
78
+ # threads do not inherit thread local variables
79
+ # therefore we use headers to continue context
80
+ w3c_headers = get_trace_headers(req.headers)
81
+ SolarWindsAPM.trace_context = TraceContext.new(w3c_headers)
82
+ unless SolarWindsAPM::TraceString.sampled?(SolarWindsAPM.trace_context.tracestring)
83
+ # trace headers already included
84
+ return super(req, proxy, conn)
85
+ end
86
+
87
+ begin
88
+ method = req.http_header.request_method
89
+
90
+ uri = req.http_header.request_uri
91
+ kvs = sw_apm_collect(method, uri)
92
+ kvs[:Async] = 1
93
+
94
+ SolarWindsAPM::Context.fromString(SolarWindsAPM.trace_context.tracestring)
95
+ SolarWindsAPM::API.log_entry(:httpclient, kvs)
96
+ kvs.clear
97
+ kvs[:Backtrace] = SolarWindsAPM::API.backtrace if SolarWindsAPM::Config[:httpclient][:collect_backtraces]
98
+
99
+ add_trace_header(req.header)
100
+
101
+ # The core httpclient call
102
+ result = super(req, proxy, conn)
103
+
104
+ # Older HTTPClient < 2.6.0 returns HTTPClient::Connection
105
+ if result.is_a?(::HTTP::Message)
106
+ response = result
107
+ else
108
+ response = conn.pop
109
+ end
110
+
111
+ kvs[:HTTPStatus] = response.status_code
112
+
113
+ # If we get a redirect, report the location header
114
+ if ((300..308).to_a.include? response.status.to_i) && response.headers.key?('Location')
115
+ kvs[:Location] = response.headers['Location']
116
+ end
117
+
118
+ # Older HTTPClient < 2.6.0 returns HTTPClient::Connection
119
+ conn.push response if result.is_a?(::HTTPClient::Connection)
120
+ result
121
+ rescue => e
122
+ SolarWindsAPM::API.log_exception(:httpclient, e)
123
+ raise e
124
+ ensure
125
+ SolarWindsAPM::API.log_exit(:httpclient, kvs)
126
+ end
127
+ end
128
+
129
+ private
130
+
131
+ def get_trace_headers(headers)
132
+ if headers.is_a?(Array)
133
+ traceparent = headers.find { |ele| ele.first =~ /[Tt]raceparent/ }
134
+ tracestate = headers.find { |ele| ele.first =~ /[Tt]racestate/ }
135
+ return { traceparent: traceparent, tracestate: tracestate }
136
+ elsif headers.is_a?(Hash)
137
+ return { traceparent: headers['traceparent'], tracestate: headers['tracestate'] }
138
+ elsif headers.is_a? HTTP::Message::Headers
139
+ return { traceparent: headers['traceparent'].first,
140
+ tracestate: headers['tracestate'].first }
141
+ end
142
+ {}
143
+ end
144
+
145
+ def add_trace_header(headers)
146
+ tracestring, tracestate = w3c_context
147
+ # Be aware of various ways to call/use httpclient
148
+ if headers.is_a?(Array)
149
+ headers.delete_if { |kv| kv[0] =~ /^([Tt]raceparent|[Tt]racestate)$/ }
150
+ headers.push ['traceparent', tracestring] if tracestring
151
+ headers.push ['tracestate', tracestate] if tracestate
152
+ elsif headers.is_a?(Hash)
153
+ headers['traceparent'] = tracestring if tracestring
154
+ headers['tracestate'] = tracestate if tracestate
155
+ elsif headers.is_a? HTTP::Message::Headers
156
+ headers.set('traceparent', tracestring) if tracestring
157
+ headers.set('tracestate', tracestate) if tracestate
158
+ end
159
+ end
160
+
161
+ # !! this is a private method, only used in add_trace_header above
162
+ def w3c_context
163
+ tracestring = SolarWindsAPM::Context.toString
164
+
165
+ unless SolarWindsAPM::TraceString.valid?(tracestring)
166
+ return [SolarWindsAPM.trace_context&.traceparent, SolarWindsAPM.trace_context&.tracestate]
167
+ end
168
+
169
+ parent_id_flags = SolarWindsAPM::TraceString.span_id_flags(tracestring)
170
+ tracestate = SolarWindsAPM::TraceState.add_sw_member(SolarWindsAPM.trace_context&.tracestate, parent_id_flags)
171
+ [tracestring, tracestate]
172
+ end
173
+
174
+ end
175
+ end
176
+ end
177
+
178
+ if SolarWindsAPM::Config[:httpclient][:enabled] && defined?(HTTPClient)
179
+ SolarWindsAPM.logger.info '[solarwinds_apm/loading] Instrumenting httpclient' if SolarWindsAPM::Config[:verbose]
180
+ HTTPClient.prepend(SolarWindsAPM::Inst::HTTPClient)
181
+ end
@@ -0,0 +1,46 @@
1
+ # Copyright (c) 2019 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require 'logger'
5
+
6
+ module SolarWindsAPM
7
+ module Logger
8
+ module Formatter
9
+
10
+ def call(severity, time, progname, msg)
11
+ return super if SolarWindsAPM::Config[:log_traceId] == :never
12
+
13
+ msg = insert_trace_id(msg)
14
+ super
15
+ end
16
+
17
+ private
18
+
19
+ def insert_trace_id(msg)
20
+ return msg if msg =~ /trace_id=/
21
+
22
+ current_trace = SolarWindsAPM::SDK.current_trace_info
23
+ if current_trace.do_log
24
+ case msg
25
+ when ::String
26
+ msg = msg.strip.empty? ? msg : insert_before_empty_lines(msg, current_trace.for_log)
27
+ when ::Exception
28
+ # conversion to String copied from Logger::Formatter private method #msg2str
29
+ msg = ("#{msg.message} (#{msg.class}) #{current_trace.for_log}\n" <<
30
+ (msg.backtrace || []).join("\n"))
31
+ end
32
+ end
33
+ msg
34
+ end
35
+
36
+ def insert_before_empty_lines(msg, for_log)
37
+ stripped = msg.rstrip
38
+ "#{stripped} #{for_log}#{msg[stripped.length..-1]}"
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ if SolarWindsAPM.loaded
45
+ Logger::Formatter.send(:prepend, SolarWindsAPM::Logger::Formatter)
46
+ end
@@ -0,0 +1,24 @@
1
+ # Copyright (c) 2019 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require_relative 'logger_formatter'
5
+
6
+ module SolarWindsAPM
7
+ module Logging
8
+ module LogEvent
9
+ include SolarWindsAPM::Logger::Formatter # provides #insert_trace_id
10
+
11
+ def initialize(logger, level, data, caller_tracing )
12
+ return super if SolarWindsAPM::Config[:log_traceId] == :never
13
+
14
+ data = insert_trace_id(data)
15
+ super
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+
22
+ if SolarWindsAPM.loaded && defined?(Logging::LogEvent)
23
+ Logging::LogEvent.send(:prepend, SolarWindsAPM::Logging::LogEvent)
24
+ end
@@ -0,0 +1,9 @@
1
+ # Copyright (c) 2019 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require_relative 'logger_formatter'
5
+
6
+ if SolarWindsAPM.loaded && defined?(Lumberjack::Formatter)
7
+ Lumberjack::Formatter.send(:prepend, SolarWindsAPM::Logger::Formatter)
8
+ end
9
+
@@ -0,0 +1,86 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module SolarWindsAPM
5
+ module Inst
6
+ module Memcached
7
+ include SolarWindsAPM::API::Memcache
8
+
9
+ def self.included(cls)
10
+ SolarWindsAPM.logger.info '[solarwinds_apm/loading] Instrumenting memcached' if SolarWindsAPM::Config[:verbose]
11
+
12
+ cls.class_eval do
13
+ MEMCACHE_OPS.reject { |m| !method_defined?(m) }.each do |m|
14
+ define_method("#{m}_with_sw_apm") do |*args|
15
+ kvs = { :KVOp => m }
16
+
17
+ if args.length && !args[0].is_a?(Array)
18
+ kvs[:KVKey] = args[0].to_s
19
+ rhost = remote_host(args[0].to_s)
20
+ kvs[:RemoteHost] = rhost if rhost
21
+ end
22
+
23
+ SolarWindsAPM::SDK.trace(:memcache, kvs: kvs) do
24
+ result = send("#{m}_without_sw_apm", *args)
25
+
26
+ kvs[:KVHit] = memcache_hit?(result) if m == :get && args.length && args[0].class == String
27
+ kvs[:Backtrace] = SolarWindsAPM::API.backtrace if SolarWindsAPM::Config[:memcached][:collect_backtraces]
28
+
29
+ result
30
+ end
31
+ end
32
+
33
+ class_eval "alias #{m}_without_sw_apm #{m}"
34
+ class_eval "alias #{m} #{m}_with_sw_apm"
35
+ end
36
+ end
37
+ end
38
+
39
+ end # module Memcached
40
+
41
+ module MemcachedRails
42
+ def self.included(cls)
43
+ cls.class_eval do
44
+ if ::Memcached::Rails.method_defined? :get_multi
45
+ alias get_multi_without_sw_apm get_multi
46
+ alias get_multi get_multi_with_sw_apm
47
+ elsif SolarWindsAPM::Config[:verbose]
48
+ SolarWindsAPM.logger.warn '[solarwinds_apm/loading] Couldn\'t properly instrument Memcached. Partial traces may occur.'
49
+ end
50
+ end
51
+ end
52
+
53
+ def get_multi_with_sw_apm(keys, raw = false)
54
+ if SolarWindsAPM.tracing?
55
+ layer_kvs = {}
56
+ layer_kvs[:KVOp] = :get_multi
57
+
58
+ SolarWindsAPM::SDK.trace(:memcache, kvs: layer_kvs, protect_op: :get_multi) do
59
+ layer_kvs[:KVKeyCount] = keys.flatten.length
60
+
61
+ values = get_multi_without_sw_apm(keys, raw)
62
+
63
+ layer_kvs[:KVHitCount] = values.length
64
+ layer_kvs[:Backtrace] = SolarWindsAPM::API.backtrace if SolarWindsAPM::Config[:memcached][:collect_backtraces]
65
+
66
+ values
67
+ end
68
+ else
69
+ get_multi_without_sw_apm(keys, raw)
70
+ end
71
+ end
72
+ end # module MemcachedRails
73
+ end # module Inst
74
+ end # module SolarWindsAPM
75
+
76
+ if defined?(Memcached) && SolarWindsAPM::Config[:memcached][:enabled]
77
+ Memcached.class_eval do
78
+ include SolarWindsAPM::Inst::Memcached
79
+ end
80
+
81
+ if defined?(Memcached::Rails)
82
+ Memcached::Rails.class_eval do
83
+ include SolarWindsAPM::Inst::MemcachedRails
84
+ end
85
+ end
86
+ end