appoptics_apm-zearn 4.13.1

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 (145) 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 +103 -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 +168 -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 +159 -0
  12. data/.gitignore +36 -0
  13. data/.rubocop.yml +29 -0
  14. data/.travis.yml +130 -0
  15. data/.yardopts +6 -0
  16. data/CHANGELOG.md +769 -0
  17. data/CONFIG.md +33 -0
  18. data/Gemfile +14 -0
  19. data/LICENSE +202 -0
  20. data/README.md +393 -0
  21. data/appoptics_apm.gemspec +70 -0
  22. data/bin/appoptics_apm_config +15 -0
  23. data/examples/prepend.rb +13 -0
  24. data/examples/sdk_examples.rb +158 -0
  25. data/ext/oboe_metal/README.md +69 -0
  26. data/ext/oboe_metal/extconf.rb +151 -0
  27. data/ext/oboe_metal/lib/.keep +0 -0
  28. data/ext/oboe_metal/lib/liboboe-1.0-alpine-x86_64.so.0.0.0.sha256 +1 -0
  29. data/ext/oboe_metal/lib/liboboe-1.0-x86_64.so.0.0.0.sha256 +1 -0
  30. data/ext/oboe_metal/noop/noop.c +8 -0
  31. data/ext/oboe_metal/src/README.md +6 -0
  32. data/ext/oboe_metal/src/VERSION +2 -0
  33. data/ext/oboe_metal/src/bson/bson.h +220 -0
  34. data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
  35. data/ext/oboe_metal/src/frames.cc +246 -0
  36. data/ext/oboe_metal/src/frames.h +40 -0
  37. data/ext/oboe_metal/src/init_appoptics_apm.cc +21 -0
  38. data/ext/oboe_metal/src/logging.cc +95 -0
  39. data/ext/oboe_metal/src/logging.h +35 -0
  40. data/ext/oboe_metal/src/oboe.h +1156 -0
  41. data/ext/oboe_metal/src/oboe_api.cpp +652 -0
  42. data/ext/oboe_metal/src/oboe_api.hpp +431 -0
  43. data/ext/oboe_metal/src/oboe_debug.h +59 -0
  44. data/ext/oboe_metal/src/oboe_swig_wrap.cc +7329 -0
  45. data/ext/oboe_metal/src/profiling.cc +435 -0
  46. data/ext/oboe_metal/src/profiling.h +78 -0
  47. data/ext/oboe_metal/test/CMakeLists.txt +53 -0
  48. data/ext/oboe_metal/test/FindGMock.cmake +43 -0
  49. data/ext/oboe_metal/test/README.md +56 -0
  50. data/ext/oboe_metal/test/frames_test.cc +164 -0
  51. data/ext/oboe_metal/test/profiling_test.cc +93 -0
  52. data/ext/oboe_metal/test/ruby_inc_dir.rb +8 -0
  53. data/ext/oboe_metal/test/ruby_prefix.rb +8 -0
  54. data/ext/oboe_metal/test/ruby_test_helper.rb +67 -0
  55. data/ext/oboe_metal/test/test.h +11 -0
  56. data/ext/oboe_metal/test/test_main.cc +32 -0
  57. data/init.rb +4 -0
  58. data/lib/appoptics_apm/api/layerinit.rb +41 -0
  59. data/lib/appoptics_apm/api/logging.rb +381 -0
  60. data/lib/appoptics_apm/api/memcache.rb +37 -0
  61. data/lib/appoptics_apm/api/metrics.rb +63 -0
  62. data/lib/appoptics_apm/api/tracing.rb +57 -0
  63. data/lib/appoptics_apm/api/util.rb +120 -0
  64. data/lib/appoptics_apm/api.rb +21 -0
  65. data/lib/appoptics_apm/base.rb +231 -0
  66. data/lib/appoptics_apm/config.rb +299 -0
  67. data/lib/appoptics_apm/frameworks/grape.rb +98 -0
  68. data/lib/appoptics_apm/frameworks/padrino.rb +78 -0
  69. data/lib/appoptics_apm/frameworks/rails/inst/action_controller.rb +104 -0
  70. data/lib/appoptics_apm/frameworks/rails/inst/action_controller4.rb +48 -0
  71. data/lib/appoptics_apm/frameworks/rails/inst/action_controller5.rb +50 -0
  72. data/lib/appoptics_apm/frameworks/rails/inst/action_controller6.rb +50 -0
  73. data/lib/appoptics_apm/frameworks/rails/inst/action_controller_api.rb +50 -0
  74. data/lib/appoptics_apm/frameworks/rails/inst/action_view.rb +88 -0
  75. data/lib/appoptics_apm/frameworks/rails/inst/active_record.rb +27 -0
  76. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
  77. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +29 -0
  78. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +31 -0
  79. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils.rb +119 -0
  80. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +114 -0
  81. data/lib/appoptics_apm/frameworks/rails/inst/logger_formatters.rb +27 -0
  82. data/lib/appoptics_apm/frameworks/rails.rb +100 -0
  83. data/lib/appoptics_apm/frameworks/sinatra.rb +96 -0
  84. data/lib/appoptics_apm/inst/bunny-client.rb +148 -0
  85. data/lib/appoptics_apm/inst/bunny-consumer.rb +89 -0
  86. data/lib/appoptics_apm/inst/curb.rb +332 -0
  87. data/lib/appoptics_apm/inst/dalli.rb +85 -0
  88. data/lib/appoptics_apm/inst/delayed_job.rb +92 -0
  89. data/lib/appoptics_apm/inst/em-http-request.rb +101 -0
  90. data/lib/appoptics_apm/inst/excon.rb +125 -0
  91. data/lib/appoptics_apm/inst/faraday.rb +106 -0
  92. data/lib/appoptics_apm/inst/graphql.rb +240 -0
  93. data/lib/appoptics_apm/inst/grpc_client.rb +159 -0
  94. data/lib/appoptics_apm/inst/grpc_server.rb +120 -0
  95. data/lib/appoptics_apm/inst/http.rb +81 -0
  96. data/lib/appoptics_apm/inst/httpclient.rb +174 -0
  97. data/lib/appoptics_apm/inst/logger_formatter.rb +50 -0
  98. data/lib/appoptics_apm/inst/logging_log_event.rb +28 -0
  99. data/lib/appoptics_apm/inst/lumberjack_formatter.rb +13 -0
  100. data/lib/appoptics_apm/inst/memcached.rb +86 -0
  101. data/lib/appoptics_apm/inst/mongo.rb +246 -0
  102. data/lib/appoptics_apm/inst/mongo2.rb +225 -0
  103. data/lib/appoptics_apm/inst/moped.rb +466 -0
  104. data/lib/appoptics_apm/inst/rack.rb +182 -0
  105. data/lib/appoptics_apm/inst/rack_cache.rb +35 -0
  106. data/lib/appoptics_apm/inst/redis.rb +274 -0
  107. data/lib/appoptics_apm/inst/resque.rb +151 -0
  108. data/lib/appoptics_apm/inst/rest-client.rb +48 -0
  109. data/lib/appoptics_apm/inst/sequel.rb +178 -0
  110. data/lib/appoptics_apm/inst/sidekiq-client.rb +55 -0
  111. data/lib/appoptics_apm/inst/sidekiq-worker.rb +66 -0
  112. data/lib/appoptics_apm/inst/twitter-cassandra.rb +294 -0
  113. data/lib/appoptics_apm/inst/typhoeus.rb +108 -0
  114. data/lib/appoptics_apm/instrumentation.rb +22 -0
  115. data/lib/appoptics_apm/loading.rb +65 -0
  116. data/lib/appoptics_apm/logger.rb +14 -0
  117. data/lib/appoptics_apm/noop/README.md +9 -0
  118. data/lib/appoptics_apm/noop/context.rb +27 -0
  119. data/lib/appoptics_apm/noop/metadata.rb +25 -0
  120. data/lib/appoptics_apm/noop/profiling.rb +21 -0
  121. data/lib/appoptics_apm/oboe_init_options.rb +211 -0
  122. data/lib/appoptics_apm/ruby.rb +35 -0
  123. data/lib/appoptics_apm/sdk/current_trace.rb +77 -0
  124. data/lib/appoptics_apm/sdk/custom_metrics.rb +94 -0
  125. data/lib/appoptics_apm/sdk/logging.rb +37 -0
  126. data/lib/appoptics_apm/sdk/tracing.rb +434 -0
  127. data/lib/appoptics_apm/support/profiling.rb +18 -0
  128. data/lib/appoptics_apm/support/transaction_metrics.rb +67 -0
  129. data/lib/appoptics_apm/support/transaction_settings.rb +219 -0
  130. data/lib/appoptics_apm/support/x_trace_options.rb +110 -0
  131. data/lib/appoptics_apm/support_report.rb +119 -0
  132. data/lib/appoptics_apm/test.rb +95 -0
  133. data/lib/appoptics_apm/thread_local.rb +26 -0
  134. data/lib/appoptics_apm/util.rb +326 -0
  135. data/lib/appoptics_apm/version.rb +16 -0
  136. data/lib/appoptics_apm/xtrace.rb +115 -0
  137. data/lib/appoptics_apm.rb +77 -0
  138. data/lib/joboe_metal.rb +212 -0
  139. data/lib/oboe.rb +7 -0
  140. data/lib/oboe_metal.rb +172 -0
  141. data/lib/rails/generators/appoptics_apm/install_generator.rb +47 -0
  142. data/lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb +425 -0
  143. data/log/.keep +0 -0
  144. data/yardoc_frontpage.md +26 -0
  145. metadata +231 -0
@@ -0,0 +1,120 @@
1
+ # Copyright (c) 2018 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
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
+ ::AppOpticsAPM::Util.method_alias(klass, :handle_request_response, ::GRPC::RpcDesc)
16
+ ::AppOpticsAPM::Util.method_alias(klass, :handle_client_streamer, ::GRPC::RpcDesc)
17
+ ::AppOpticsAPM::Util.method_alias(klass, :handle_server_streamer, ::GRPC::RpcDesc)
18
+ ::AppOpticsAPM::Util.method_alias(klass, :handle_bidi_streamer, ::GRPC::RpcDesc)
19
+ ::AppOpticsAPM::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 # is a bidi_stream
38
+ tags['GRPCMethodType'] = 'BIDI_STREAMING'
39
+ end
40
+
41
+ tags
42
+ end
43
+
44
+ def handle_request_response_with_appoptics(active_call, mth, inter_ctx)
45
+ handle_call('handle_request_response_without_appoptics', active_call, mth, inter_ctx)
46
+ end
47
+
48
+ def handle_client_streamer_with_appoptics(active_call, mth, inter_ctx)
49
+ handle_call('handle_client_streamer_without_appoptics', active_call, mth, inter_ctx)
50
+ end
51
+
52
+ def handle_server_streamer_with_appoptics(active_call, mth, inter_ctx)
53
+ handle_call('handle_server_streamer_without_appoptics', active_call, mth, inter_ctx)
54
+ end
55
+
56
+ def handle_bidi_streamer_with_appoptics(active_call, mth, inter_ctx)
57
+ handle_call('handle_bidi_streamer_without_appoptics', active_call, mth, inter_ctx)
58
+ end
59
+
60
+ # status codes need to be determined in this lower method, because they may not get raised to the
61
+ # next instrumented method
62
+ def handle_call(without, active_call, mth, inter_ctx)
63
+ begin
64
+ send(without, active_call, mth, inter_ctx)
65
+ rescue ::GRPC::Core::CallError, ::GRPC::BadStatus, ::GRPC::Core::OutOfTime, StandardError, NotImplementedError => e
66
+ log_grpc_exception(active_call, e)
67
+ raise e
68
+ end
69
+ end
70
+
71
+ def run_server_method_with_appoptics(active_call, mth, inter_ctx)
72
+ tags = grpc_tags(active_call, mth)
73
+ AppOpticsAPM::API.log_start('grpc-server', active_call.metadata['x-trace'], tags)
74
+
75
+ exit_event = AppOpticsAPM::Event.startTrace(AppOpticsAPM::Context.get)
76
+ active_call.merge_metadata_to_send({ 'x-trace' => exit_event.metadataString })
77
+ begin
78
+ AppOpticsAPM::API.send_metrics('grpc-server', tags) do
79
+ run_server_method_without_appoptics(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 ? AppOpticsAPM::GRPC::STATUSCODES[active_call.status.code].to_s : 'OK'
87
+ tags['Backtrace'] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:grpc_server][:collect_backtraces]
88
+
89
+ exit_event.addEdge(AppOpticsAPM::Context.get)
90
+ AppOpticsAPM::API.log_end('grpc-server', tags, exit_event)
91
+ end
92
+ end
93
+
94
+ private
95
+
96
+ def log_grpc_exception(active_call, e)
97
+ unless e.instance_variable_get(:@exn_logged)
98
+ AppOpticsAPM::API.log_exception('grpc-server', e)
99
+
100
+ unless active_call.metadata_sent
101
+ if e.class == ::GRPC::Core::OutOfTime
102
+ active_call.merge_metadata_to_send({ 'grpc_status' => 'DEADLINE_EXCEEDED' })
103
+ elsif e.respond_to?(:code)
104
+ active_call.merge_metadata_to_send({ 'grpc_status' => AppOpticsAPM::GRPC::STATUSCODES[e.code].to_s })
105
+ else
106
+ active_call.merge_metadata_to_send({ 'grpc_status' => 'UNKNOWN' })
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ end
113
+
114
+ end
115
+ end
116
+
117
+ if defined?(GRPC) && AppOpticsAPM::Config['grpc_server'][:enabled]
118
+ # server side is instrumented in RpcDesc
119
+ AppOpticsAPM::Util.send_include(GRPC::RpcDesc, AppOpticsAPM::GRPC::RpcDesc)
120
+ end
@@ -0,0 +1,81 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require 'net/http'
5
+
6
+ if AppOpticsAPM::Config[:nethttp][:enabled]
7
+ module AppOpticsAPM
8
+ module Inst
9
+ module NetHttp
10
+ # Net::HTTP.class_eval do
11
+ # def request_with_appoptics(*args, &block)
12
+ def request(*args, &block)
13
+ # Avoid cross host tracing for blacklisted domains
14
+ blacklisted = AppOpticsAPM::API.blacklisted?(addr_port)
15
+
16
+ # If we're not tracing, just do a fast return. Since
17
+ # net/http.request calls itself, only trace
18
+ # once the http session has been started.
19
+ if !AppOpticsAPM.tracing? || !started?
20
+ if blacklisted # if the other site is blacklisted, we don't want to leak its X-trace
21
+ resp = super
22
+ resp.delete('X-Trace') # if resp['X-Trace']
23
+ return resp
24
+ else
25
+ xtrace = AppOpticsAPM::Context.toString
26
+ args[0]['X-Trace'] = xtrace if AppOpticsAPM::XTrace.valid?(xtrace)
27
+ return super
28
+ end
29
+ end
30
+
31
+ opts = {}
32
+ AppOpticsAPM::API.trace(:'net-http', opts) do
33
+ context = AppOpticsAPM::Context.toString
34
+
35
+ # Collect KVs to report in the exit event
36
+ if args.respond_to?(:first) && args.first
37
+ req = args.first
38
+
39
+ opts[:Spec] = 'rsc'
40
+ opts[:IsService] = 1
41
+ opts[:RemoteURL] = "#{use_ssl? ? 'https' : 'http'}://#{addr_port}"
42
+ opts[:RemoteURL] << (AppOpticsAPM::Config[:nethttp][:log_args] ? req.path : req.path.split('?').first)
43
+ opts[:HTTPMethod] = req.method
44
+ opts[:Blacklisted] = true if blacklisted
45
+ opts[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:nethttp][:collect_backtraces]
46
+
47
+ req['X-Trace'] = context unless blacklisted
48
+ end
49
+
50
+ begin
51
+ # The actual net::http call
52
+ resp = super
53
+ # Re-attach net::http edge unless blacklisted and is a valid X-Trace ID
54
+ xtrace = resp.get_fields('X-Trace')
55
+ if blacklisted
56
+ # we don't want the x-trace if it is from a blacklisted address
57
+ resp.delete('X-Trace') # if xtrace
58
+ else
59
+ xtrace = xtrace[0] if xtrace && xtrace.is_a?(Array)
60
+ AppOpticsAPM::XTrace.continue_service_context(context, xtrace)
61
+ end
62
+
63
+ opts[:HTTPStatus] = resp.code
64
+
65
+ # If we get a redirect, report the location header
66
+ if ((300..308).to_a.include? resp.code.to_i) && resp.header["Location"]
67
+ opts[:Location] = resp.header["Location"]
68
+ end
69
+
70
+ next resp
71
+ end
72
+ end
73
+ end
74
+
75
+ end
76
+ end
77
+ end
78
+
79
+ Net::HTTP.prepend(AppOpticsAPM::Inst::NetHttp)
80
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting net/http' if AppOpticsAPM::Config[:verbose]
81
+ end
@@ -0,0 +1,174 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ module Inst
6
+ module HTTPClient
7
+ def self.included(klass)
8
+ AppOpticsAPM::Util.method_alias(klass, :do_request, ::HTTPClient)
9
+ AppOpticsAPM::Util.method_alias(klass, :do_request_async, ::HTTPClient)
10
+ AppOpticsAPM::Util.method_alias(klass, :do_get_stream, ::HTTPClient)
11
+ end
12
+
13
+ def appoptics_collect(method, uri, query = nil)
14
+ kvs = {}
15
+ kvs[:Spec] = 'rsc'
16
+ kvs[:IsService] = 1
17
+
18
+ # Conditionally log URL query params
19
+ # Because of the hook points, the query arg can come in under <tt>query</tt>
20
+ # or as a part of <tt>uri</tt> (not both). Here we handle both cases.
21
+ if AppOpticsAPM::Config[:httpclient][:log_args]
22
+ if query
23
+ kvs[:RemoteURL] = uri.to_s + '?' + AppOpticsAPM::Util.to_query(query)
24
+ else
25
+ kvs[:RemoteURL] = uri.to_s
26
+ end
27
+ else
28
+ kvs[:RemoteURL] = uri.to_s.split('?').first
29
+ end
30
+
31
+ kvs[:HTTPMethod] = AppOpticsAPM::Util.upcase(method)
32
+ kvs
33
+ rescue => e
34
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] Error capturing httpclient KVs: #{e.message}"
35
+ AppOpticsAPM.logger.debug e.backtrace.join('\n') if AppOpticsAPM::Config[:verbose]
36
+ ensure
37
+ return kvs
38
+ end
39
+
40
+ def do_request_with_appoptics(method, uri, query, body, header, &block)
41
+ # Avoid cross host tracing for blacklisted domains
42
+ blacklisted = AppOpticsAPM::API.blacklisted?(uri.hostname)
43
+
44
+ # If we're not tracing, just do a fast return.
45
+ unless AppOpticsAPM.tracing?
46
+ add_xtrace_header(header) unless blacklisted
47
+ return do_request_without_appoptics(method, uri, query, body, header, &block)
48
+ end
49
+
50
+ begin
51
+ req_context = nil
52
+ response_context = nil
53
+
54
+ kvs = appoptics_collect(method, uri, query)
55
+ kvs[:Blacklisted] = true if blacklisted
56
+
57
+ AppOpticsAPM::API.log_entry(:httpclient, kvs)
58
+ kvs.clear
59
+ kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:httpclient][:collect_backtraces]
60
+
61
+ req_context = add_xtrace_header(header) unless blacklisted
62
+
63
+ # The core httpclient call
64
+ response = do_request_without_appoptics(method, uri, query, body, header, &block)
65
+
66
+ response_context = response.headers['X-Trace']
67
+ kvs[:HTTPStatus] = response.status_code
68
+
69
+ # If we get a redirect, report the location header
70
+ if ((300..308).to_a.include? response.status.to_i) && response.headers.key?('Location')
71
+ kvs[:Location] = response.headers['Location']
72
+ end
73
+
74
+ if response_context && !blacklisted
75
+ AppOpticsAPM::XTrace.continue_service_context(req_context, response_context)
76
+ end
77
+
78
+ response
79
+ rescue => e
80
+ AppOpticsAPM::API.log_exception(:httpclient, e)
81
+ raise e
82
+ ensure
83
+ AppOpticsAPM::API.log_exit(:httpclient, kvs)
84
+ end
85
+ end
86
+
87
+ def do_request_async_with_appoptics(method, uri, query, body, header)
88
+ add_xtrace_header(header)
89
+ do_request_async_without_appoptics(method, uri, query, body, header)
90
+ end
91
+
92
+ def do_get_stream_with_appoptics(req, proxy, conn)
93
+ AppOpticsAPM::Context.fromString(req.header['X-Trace'].first) unless req.header['X-Trace'].empty?
94
+ # Avoid cross host tracing for blacklisted domains
95
+ uri = req.http_header.request_uri
96
+ blacklisted = AppOpticsAPM::API.blacklisted?(uri.hostname)
97
+
98
+ unless AppOpticsAPM.tracing?
99
+ req.header.delete('X-Trace') if blacklisted
100
+ return do_get_stream_without_appoptics(req, proxy, conn)
101
+ end
102
+
103
+ begin
104
+ response = nil
105
+ req_context = nil
106
+ method = req.http_header.request_method
107
+
108
+ kvs = appoptics_collect(method, uri)
109
+ kvs[:Blacklisted] = true if blacklisted
110
+ kvs[:Async] = 1
111
+
112
+ AppOpticsAPM::API.log_entry(:httpclient, kvs)
113
+ kvs.clear
114
+ kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:httpclient][:collect_backtraces]
115
+
116
+ blacklisted ? req.header.delete('X-Trace') : req_context = add_xtrace_header(req.header)
117
+
118
+ # The core httpclient call
119
+ result = do_get_stream_without_appoptics(req, proxy, conn)
120
+
121
+ # Older HTTPClient < 2.6.0 returns HTTPClient::Connection
122
+ if result.is_a?(::HTTP::Message)
123
+ response = result
124
+ else
125
+ response = conn.pop
126
+ end
127
+
128
+ response_context = response.headers['X-Trace']
129
+ kvs[:HTTPStatus] = response.status_code
130
+
131
+ # If we get a redirect, report the location header
132
+ if ((300..308).to_a.include? response.status.to_i) && response.headers.key?('Location')
133
+ kvs[:Location] = response.headers['Location']
134
+ end
135
+
136
+ if response_context && !blacklisted
137
+ AppOpticsAPM::XTrace.continue_service_context(req_context, response_context)
138
+ end
139
+
140
+ # Older HTTPClient < 2.6.0 returns HTTPClient::Connection
141
+ conn.push response if result.is_a?(::HTTPClient::Connection)
142
+ result
143
+ rescue => e
144
+ AppOpticsAPM::API.log_exception(:httpclient, e)
145
+ raise e
146
+ ensure
147
+ AppOpticsAPM::API.log_exit(:httpclient, kvs)
148
+ end
149
+ end
150
+
151
+ private
152
+
153
+ def add_xtrace_header(headers)
154
+ req_context = AppOpticsAPM::Context.toString
155
+ return nil unless AppOpticsAPM::XTrace.valid?(req_context)
156
+ # Be aware of various ways to call/use httpclient
157
+ if headers.is_a?(Array)
158
+ headers.delete_if { |kv| kv[0] == 'X-Trace' }
159
+ headers.push ['X-Trace', req_context]
160
+ elsif headers.is_a?(Hash)
161
+ headers['X-Trace'] = req_context
162
+ elsif headers.is_a? HTTP::Message::Headers
163
+ headers.set('X-Trace', req_context)
164
+ end
165
+ req_context
166
+ end
167
+ end
168
+ end
169
+ end
170
+
171
+ if AppOpticsAPM::Config[:httpclient][:enabled] && defined?(HTTPClient)
172
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting httpclient' if AppOpticsAPM::Config[:verbose]
173
+ AppOpticsAPM::Util.send_include(HTTPClient, AppOpticsAPM::Inst::HTTPClient)
174
+ end
@@ -0,0 +1,50 @@
1
+ # Copyright (c) 2019 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require 'logger'
5
+
6
+ module AppOpticsAPM
7
+ module Logger
8
+ module Formatter
9
+
10
+ def call(severity, time, progname, msg)
11
+ return super if AppOpticsAPM::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 =~ /ao(=>{:|\.){1}traceId/
21
+
22
+ current_trace = AppOpticsAPM::SDK.current_trace
23
+ if current_trace.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 AppOpticsAPM.loaded
45
+ class Logger
46
+ class Formatter
47
+ prepend AppOpticsAPM::Logger::Formatter
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,28 @@
1
+ # Copyright (c) 2019 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require_relative 'logger_formatter'
5
+
6
+ module AppOpticsAPM
7
+ module Logging
8
+ module LogEvent
9
+ include AppOpticsAPM::Logger::Formatter # provides #insert_trace_id
10
+
11
+ def initialize(logger, level, data, caller_tracing )
12
+ return super if AppOpticsAPM::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 AppOpticsAPM.loaded && defined?(Logging::LogEvent)
23
+ module Logging
24
+ class LogEvent
25
+ prepend AppOpticsAPM::Logging::LogEvent
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,13 @@
1
+ # Copyright (c) 2019 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require_relative 'logger_formatter'
5
+
6
+ if AppOpticsAPM.loaded && defined?(Lumberjack::Formatter)
7
+ module Lumberjack
8
+ class Formatter
9
+ prepend AppOpticsAPM::Logger::Formatter
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,86 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+ module Inst
6
+ module Memcached
7
+ include AppOpticsAPM::API::Memcache
8
+
9
+ def self.included(cls)
10
+ AppOpticsAPM.logger.info '[appoptics_apm/loading] Instrumenting memcached' if AppOpticsAPM::Config[:verbose]
11
+
12
+ cls.class_eval do
13
+ MEMCACHE_OPS.reject { |m| !method_defined?(m) }.each do |m|
14
+ define_method("#{m}_with_appoptics") do |*args|
15
+ opts = { :KVOp => m }
16
+
17
+ if args.length && !args[0].is_a?(Array)
18
+ opts[:KVKey] = args[0].to_s
19
+ rhost = remote_host(args[0].to_s)
20
+ opts[:RemoteHost] = rhost if rhost
21
+ end
22
+
23
+ AppOpticsAPM::API.trace(:memcache, opts) do
24
+ result = send("#{m}_without_appoptics", *args)
25
+
26
+ opts[:KVHit] = memcache_hit?(result) if m == :get && args.length && args[0].class == String
27
+ opts[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:memcached][:collect_backtraces]
28
+
29
+ result
30
+ end
31
+ end
32
+
33
+ class_eval "alias #{m}_without_appoptics #{m}"
34
+ class_eval "alias #{m} #{m}_with_appoptics"
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_appoptics get_multi
46
+ alias get_multi get_multi_with_appoptics
47
+ elsif AppOpticsAPM::Config[:verbose]
48
+ AppOpticsAPM.logger.warn '[appoptics_apm/loading] Couldn\'t properly instrument Memcached. Partial traces may occur.'
49
+ end
50
+ end
51
+ end
52
+
53
+ def get_multi_with_appoptics(keys, raw = false)
54
+ if AppOpticsAPM.tracing?
55
+ layer_kvs = {}
56
+ layer_kvs[:KVOp] = :get_multi
57
+
58
+ AppOpticsAPM::API.trace(:memcache, layer_kvs || {}, :get_multi) do
59
+ layer_kvs[:KVKeyCount] = keys.flatten.length
60
+
61
+ values = get_multi_without_appoptics(keys, raw)
62
+
63
+ layer_kvs[:KVHitCount] = values.length
64
+ layer_kvs[:Backtrace] = AppOpticsAPM::API.backtrace if AppOpticsAPM::Config[:memcached][:collect_backtraces]
65
+
66
+ values
67
+ end
68
+ else
69
+ get_multi_without_appoptics(keys, raw)
70
+ end
71
+ end
72
+ end # module MemcachedRails
73
+ end # module Inst
74
+ end # module AppOpticsAPM
75
+
76
+ if defined?(Memcached) && AppOpticsAPM::Config[:memcached][:enabled]
77
+ Memcached.class_eval do
78
+ include AppOpticsAPM::Inst::Memcached
79
+ end
80
+
81
+ if defined?(Memcached::Rails)
82
+ Memcached::Rails.class_eval do
83
+ include AppOpticsAPM::Inst::MemcachedRails
84
+ end
85
+ end
86
+ end