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.
- checksums.yaml +7 -0
- data/.dockerignore +5 -0
- data/.github/ISSUE_TEMPLATE/bug-or-feature-request.md +16 -0
- data/.github/workflows/build_and_release_gem.yml +112 -0
- data/.github/workflows/build_for_packagecloud.yml +70 -0
- data/.github/workflows/docker-images.yml +47 -0
- data/.github/workflows/run_cpluplus_tests.yml +73 -0
- data/.github/workflows/run_tests.yml +155 -0
- data/.github/workflows/scripts/test_install.rb +23 -0
- data/.github/workflows/swig/swig-v4.0.2.tar.gz +0 -0
- data/.github/workflows/test_on_4_linux.yml +161 -0
- data/.gitignore +39 -0
- data/.rubocop.yml +29 -0
- data/.yardopts +7 -0
- data/CHANGELOG.md +769 -0
- data/CONFIG.md +31 -0
- data/Gemfile +14 -0
- data/LICENSE +202 -0
- data/README.md +383 -0
- data/bin/solarwinds_apm_config +15 -0
- data/examples/prepend.rb +13 -0
- data/examples/sdk_examples.rb +158 -0
- data/ext/oboe_metal/README.md +69 -0
- data/ext/oboe_metal/extconf.rb +141 -0
- data/ext/oboe_metal/extconf_local.rb +75 -0
- data/ext/oboe_metal/lib/.keep +0 -0
- data/ext/oboe_metal/lib/liboboe-1.0-alpine-x86_64.so.0.0.0.sha256 +1 -0
- data/ext/oboe_metal/lib/liboboe-1.0-x86_64.so.0.0.0.sha256 +1 -0
- data/ext/oboe_metal/noop/noop.c +8 -0
- data/ext/oboe_metal/src/README.md +6 -0
- data/ext/oboe_metal/src/VERSION +2 -0
- data/ext/oboe_metal/src/bson/bson.h +220 -0
- data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
- data/ext/oboe_metal/src/frames.cc +247 -0
- data/ext/oboe_metal/src/frames.h +40 -0
- data/ext/oboe_metal/src/init_solarwinds_apm.cc +21 -0
- data/ext/oboe_metal/src/logging.cc +95 -0
- data/ext/oboe_metal/src/logging.h +35 -0
- data/ext/oboe_metal/src/oboe.h +1169 -0
- data/ext/oboe_metal/src/oboe_api.cpp +658 -0
- data/ext/oboe_metal/src/oboe_api.hpp +433 -0
- data/ext/oboe_metal/src/oboe_debug.h +59 -0
- data/ext/oboe_metal/src/oboe_swig_wrap.cc +7562 -0
- data/ext/oboe_metal/src/profiling.cc +435 -0
- data/ext/oboe_metal/src/profiling.h +78 -0
- data/ext/oboe_metal/test/CMakeLists.txt +53 -0
- data/ext/oboe_metal/test/FindGMock.cmake +43 -0
- data/ext/oboe_metal/test/README.md +56 -0
- data/ext/oboe_metal/test/frames_test.cc +164 -0
- data/ext/oboe_metal/test/profiling_test.cc +93 -0
- data/ext/oboe_metal/test/ruby_inc_dir.rb +8 -0
- data/ext/oboe_metal/test/ruby_prefix.rb +8 -0
- data/ext/oboe_metal/test/ruby_test_helper.rb +67 -0
- data/ext/oboe_metal/test/test.h +11 -0
- data/ext/oboe_metal/test/test_main.cc +32 -0
- data/init.rb +4 -0
- data/lib/oboe.rb +7 -0
- data/lib/oboe_metal.rb +172 -0
- data/lib/rails/generators/solarwinds_apm/install_generator.rb +47 -0
- data/lib/rails/generators/solarwinds_apm/templates/solarwinds_apm_initializer.rb +424 -0
- data/lib/solarwinds_apm/api/layerinit.rb +41 -0
- data/lib/solarwinds_apm/api/logging.rb +356 -0
- data/lib/solarwinds_apm/api/memcache.rb +37 -0
- data/lib/solarwinds_apm/api/metrics.rb +63 -0
- data/lib/solarwinds_apm/api/util.rb +98 -0
- data/lib/solarwinds_apm/api.rb +21 -0
- data/lib/solarwinds_apm/base.rb +160 -0
- data/lib/solarwinds_apm/config.rb +301 -0
- data/lib/solarwinds_apm/frameworks/grape.rb +96 -0
- data/lib/solarwinds_apm/frameworks/padrino.rb +78 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/action_controller.rb +100 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/action_controller5.rb +50 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/action_controller_api.rb +50 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/action_view.rb +88 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/active_record.rb +26 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +29 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +22 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +103 -0
- data/lib/solarwinds_apm/frameworks/rails/inst/logger_formatters.rb +14 -0
- data/lib/solarwinds_apm/frameworks/rails.rb +100 -0
- data/lib/solarwinds_apm/frameworks/sinatra.rb +96 -0
- data/lib/solarwinds_apm/inst/bunny-client.rb +157 -0
- data/lib/solarwinds_apm/inst/bunny-consumer.rb +102 -0
- data/lib/solarwinds_apm/inst/curb.rb +288 -0
- data/lib/solarwinds_apm/inst/dalli.rb +89 -0
- data/lib/solarwinds_apm/inst/delayed_job.rb +100 -0
- data/lib/solarwinds_apm/inst/excon.rb +113 -0
- data/lib/solarwinds_apm/inst/faraday.rb +96 -0
- data/lib/solarwinds_apm/inst/graphql.rb +206 -0
- data/lib/solarwinds_apm/inst/grpc_client.rb +147 -0
- data/lib/solarwinds_apm/inst/grpc_server.rb +119 -0
- data/lib/solarwinds_apm/inst/httpclient.rb +181 -0
- data/lib/solarwinds_apm/inst/logger_formatter.rb +46 -0
- data/lib/solarwinds_apm/inst/logging_log_event.rb +24 -0
- data/lib/solarwinds_apm/inst/lumberjack_formatter.rb +9 -0
- data/lib/solarwinds_apm/inst/memcached.rb +86 -0
- data/lib/solarwinds_apm/inst/mongo.rb +246 -0
- data/lib/solarwinds_apm/inst/mongo2.rb +225 -0
- data/lib/solarwinds_apm/inst/moped.rb +466 -0
- data/lib/solarwinds_apm/inst/net_http.rb +60 -0
- data/lib/solarwinds_apm/inst/rack.rb +217 -0
- data/lib/solarwinds_apm/inst/rack_cache.rb +35 -0
- data/lib/solarwinds_apm/inst/redis.rb +273 -0
- data/lib/solarwinds_apm/inst/resque.rb +129 -0
- data/lib/solarwinds_apm/inst/rest-client.rb +43 -0
- data/lib/solarwinds_apm/inst/sequel.rb +241 -0
- data/lib/solarwinds_apm/inst/sidekiq-client.rb +63 -0
- data/lib/solarwinds_apm/inst/sidekiq-worker.rb +64 -0
- data/lib/solarwinds_apm/inst/typhoeus.rb +90 -0
- data/lib/solarwinds_apm/instrumentation.rb +22 -0
- data/lib/solarwinds_apm/loading.rb +65 -0
- data/lib/solarwinds_apm/logger.rb +14 -0
- data/lib/solarwinds_apm/noop/README.md +9 -0
- data/lib/solarwinds_apm/noop/context.rb +26 -0
- data/lib/solarwinds_apm/noop/metadata.rb +25 -0
- data/lib/solarwinds_apm/noop/profiling.rb +21 -0
- data/lib/solarwinds_apm/oboe_init_options.rb +191 -0
- data/lib/solarwinds_apm/ruby.rb +35 -0
- data/lib/solarwinds_apm/sdk/current_trace_info.rb +123 -0
- data/lib/solarwinds_apm/sdk/custom_metrics.rb +94 -0
- data/lib/solarwinds_apm/sdk/logging.rb +37 -0
- data/lib/solarwinds_apm/sdk/trace_context_headers.rb +69 -0
- data/lib/solarwinds_apm/sdk/tracing.rb +432 -0
- data/lib/solarwinds_apm/support/profiling.rb +22 -0
- data/lib/solarwinds_apm/support/trace_context.rb +53 -0
- data/lib/solarwinds_apm/support/trace_state.rb +69 -0
- data/lib/solarwinds_apm/support/trace_string.rb +89 -0
- data/lib/solarwinds_apm/support/transaction_metrics.rb +67 -0
- data/lib/solarwinds_apm/support/transaction_settings.rb +233 -0
- data/lib/solarwinds_apm/support/x_trace_options.rb +113 -0
- data/lib/solarwinds_apm/support.rb +12 -0
- data/lib/solarwinds_apm/support_report.rb +113 -0
- data/lib/solarwinds_apm/test.rb +165 -0
- data/lib/solarwinds_apm/thread_local.rb +26 -0
- data/lib/solarwinds_apm/util.rb +334 -0
- data/lib/solarwinds_apm/version.rb +17 -0
- data/lib/solarwinds_apm.rb +72 -0
- data/log/.keep +0 -0
- data/log/postgresql/.keep +0 -0
- data/solarwinds_apm.gemspec +52 -0
- data/yardoc_frontpage.md +24 -0
- 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,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
|