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,191 @@
1
+ # Copyright (c) 2019 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require 'singleton'
5
+
6
+ module SolarWindsAPM
7
+
8
+ class OboeInitOptions
9
+ include Singleton
10
+
11
+ attr_reader :reporter, :host, :service_name, :ec2_md_timeout, :grpc_proxy # exposing these mainly for testing
12
+
13
+ def initialize
14
+ # optional hostname alias
15
+ @hostname_alias = ENV['SW_APM_HOSTNAME_ALIAS'] || SolarWindsAPM::Config[:hostname_alias] || ''
16
+ # level at which log messages will be written to log file (0-6)
17
+ @debug_level = (ENV['SW_APM_DEBUG_LEVEL'] || SolarWindsAPM::Config[:debug_level] || 3).to_i
18
+ # file name including path for log file
19
+ # TODO eventually find better way to combine ruby and oboe logs
20
+ @log_file_path = ENV['SW_APM_LOGFILE'] || ''
21
+ # maximum number of transaction names to track
22
+ @max_transactions = (ENV['SW_APM_MAX_TRANSACTIONS'] || -1).to_i
23
+ # maximum wait time for flushing data before terminating in milli seconds
24
+ @max_flush_wait_time = (ENV['SW_APM_FLUSH_MAX_WAIT_TIME'] || -1).to_i
25
+ # events flush timeout in seconds (threshold for batching messages before sending off)
26
+ @events_flush_interval = (ENV['SW_APM_EVENTS_FLUSH_INTERVAL'] || -1).to_i
27
+ # events flush batch size in KB (threshold for batching messages before sending off)
28
+ @event_flush_batch_size = (ENV['SW_APM_EVENTS_FLUSH_BATCH_SIZE'] || -1).to_i
29
+
30
+ # the reporter to be used (ssl, upd, file, null)
31
+ # collector endpoint (reporter=ssl), udp address (reporter=udp), or file path (reporter=file)
32
+ @reporter, @host = reporter_and_host
33
+
34
+ # the service key
35
+ @service_key = read_and_validate_service_key
36
+ # path to the SSL certificate (only for ssl)
37
+ @trusted_path = ENV['SW_APM_TRUSTEDPATH'] || ''
38
+ # size of the message buffer
39
+ @buffer_size = (ENV['SW_APM_BUFSIZE'] || -1).to_i
40
+ # flag indicating if trace metrics reporting should be enabled (default) or disabled
41
+ @trace_metrics = (ENV['SW_APM_TRACE_METRICS'] || -1).to_i
42
+ # the histogram precision (only for ssl)
43
+ @histogram_precision = (ENV['SW_APM_HISTOGRAM_PRECISION'] || -1).to_i
44
+ # custom token bucket capacity
45
+ @token_bucket_capacity = (ENV['SW_APM_TOKEN_BUCKET_CAPACITY'] || -1).to_i
46
+ # custom token bucket rate
47
+ @token_bucket_rate = (ENV['SW_APM_TOKEN_BUCKET_RATE'] || -1).to_i
48
+ # use single files in file reporter for each event
49
+ @file_single = (ENV['SW_APM_REPORTER_FILE_SINGLE'].to_s.downcase == 'true') ? 1 : 0
50
+ # timeout for ec2 metadata
51
+ @ec2_md_timeout = read_and_validate_ec2_md_timeout
52
+ @grpc_proxy = read_and_validate_proxy
53
+ # hardcoded arg for lambda (lambda not supported yet)
54
+ # hardcoded arg for grpc hack
55
+ # hardcoded arg for trace id format to use w3c format
56
+ end
57
+
58
+ def re_init # for testing with changed ENV vars
59
+ initialize
60
+ end
61
+
62
+ def array_for_oboe
63
+ [
64
+ @hostname_alias, # 0
65
+ @debug_level, # 1
66
+ @log_file_path, # 2
67
+ @max_transactions, # 3
68
+ @max_flush_wait_time, # 4
69
+ @events_flush_interval, # 5
70
+ @event_flush_batch_size, # 6
71
+
72
+ @reporter, # 7
73
+ @host, # 8
74
+ @service_key, # 9
75
+ @trusted_path, #10
76
+ @buffer_size, #11
77
+ @trace_metrics, #12
78
+ @histogram_precision, #13
79
+ @token_bucket_capacity, #14
80
+ @token_bucket_rate, #15
81
+ @file_single, #16
82
+ @ec2_md_timeout, #17
83
+ @grpc_proxy, #18
84
+ 0, #19 arg for lambda (no lambda for ruby yet)
85
+ 1, #20 arg for grpc hack, hardcoded to include hack
86
+ 1 #21 arg for trace id format to use w3c format
87
+ ]
88
+ end
89
+
90
+ def service_key_ok?
91
+ return !@service_key.empty? || @reporter != 'ssl'
92
+ end
93
+
94
+ private
95
+
96
+ def reporter_and_host
97
+
98
+ reporter = ENV['SW_APM_REPORTER'] || 'ssl'
99
+ # override with 'file', e.g. when running tests
100
+ # changed my mind => set the right reporter in the env when running tests !!!
101
+ # reporter = 'file' if ENV.key?('SW_APM_GEM_TEST')
102
+
103
+ host = ''
104
+ case reporter
105
+ when 'ssl', 'file'
106
+ host = ENV['SW_APM_COLLECTOR'] || ''
107
+ when 'udp'
108
+ host = ENV['SW_APM_COLLECTOR'] ||
109
+ "#{SolarWindsAPM::Config[:reporter_host]}:#{SolarWindsAPM::Config[:reporter_port]}"
110
+ # TODO decide what to do
111
+ # ____ SolarWindsAPM::Config[:reporter_host] and
112
+ # ____ SolarWindsAPM::Config[:reporter_port] were moved here from
113
+ # ____ oboe_metal.rb and are not documented anywhere
114
+ # ____ udp is for internal use only
115
+ when 'null'
116
+ host = ''
117
+ end
118
+
119
+ [reporter, host]
120
+ end
121
+
122
+ def read_and_validate_service_key
123
+ return '' unless @reporter == 'ssl'
124
+
125
+ service_key = ENV['SW_APM_SERVICE_KEY'] || SolarWindsAPM::Config[:service_key]
126
+ unless service_key
127
+ SolarWindsAPM.logger.error "[solarwinds_apm/oboe_options] SW_APM_SERVICE_KEY not configured."
128
+ return ''
129
+ end
130
+
131
+ match = service_key.match( /([^:]+)(:{0,1})(.*)/ )
132
+ token = match[1]
133
+ service_name = match[3]
134
+
135
+ return '' unless validate_token(token)
136
+ return '' unless validate_transform_service_name(service_name)
137
+
138
+ return "#{token}:#{service_name}"
139
+ end
140
+
141
+ def validate_token(token)
142
+ if (token !~ /^[0-9a-zA-Z_-]{71}$/) && ENV['SW_APM_COLLECTOR'] !~ /java-collector:1222/
143
+ masked = "#{token[0..3]}...#{token[-4..-1]}"
144
+ SolarWindsAPM.logger.error "[solarwinds_apm/oboe_options] SW_APM_SERVICE_KEY problem. API Token in wrong format. Masked token: #{masked}"
145
+ return false
146
+ end
147
+
148
+ true
149
+ end
150
+
151
+ def validate_transform_service_name(service_name)
152
+ service_name = 'test_ssl_collector' if ENV['SW_APM_COLLECTOR'] =~ /java-collector:1222/
153
+ if service_name.empty?
154
+ SolarWindsAPM.logger.error "[solarwinds_apm/oboe_options] SW_APM_SERVICE_KEY problem. Service Name is missing"
155
+ return false
156
+ end
157
+
158
+ name = service_name.dup
159
+ name.downcase!
160
+ name.gsub!(/[^a-z0-9.:_-]/, '')
161
+ name = name[0..254]
162
+
163
+ if name != service_name
164
+ SolarWindsAPM.logger.warn "[solarwinds_apm/oboe_options] SW_APM_SERVICE_KEY problem. Service Name transformed from #{service_name} to #{name}"
165
+ service_name = name
166
+ end
167
+ @service_name = service_name # instance variable used in testing
168
+ true
169
+ end
170
+
171
+ def read_and_validate_ec2_md_timeout
172
+ timeout = ENV['SW_APM_EC2_METADATA_TIMEOUT'] || SolarWindsAPM::Config[:ec2_metadata_timeout]
173
+ return 1000 unless timeout.is_a?(Integer) || timeout =~ /^\d+$/
174
+ timeout = timeout.to_i
175
+ return timeout.between?(0, 3000) ? timeout : 1000
176
+ end
177
+
178
+ def read_and_validate_proxy
179
+ proxy = ENV['SW_APM_PROXY'] || SolarWindsAPM::Config[:http_proxy] || ''
180
+ return proxy if proxy == ''
181
+
182
+ unless proxy =~ /http:\/\/.*:\d+$/
183
+ SolarWindsAPM.logger.error "[solarwinds_apm/oboe_options] SW_APM_PROXY/http_proxy doesn't start with 'http://', #{proxy}"
184
+ return '' # try without proxy, it may work, shouldn't crash but may not report
185
+ end
186
+
187
+ proxy
188
+ end
189
+ end
190
+ end
191
+
@@ -0,0 +1,35 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module SolarWindsAPM
5
+ ##
6
+ # This module provides a method to manually initialize the
7
+ # Ruby instrumentation. Normally this is done by detecting
8
+ # frameworks at load time and inserting initialization hooks.
9
+ module Ruby
10
+ class << self
11
+ def initialize
12
+ load
13
+ end
14
+
15
+ ##
16
+ # The core method to load Ruby instrumentation. Call this
17
+ # from raw Ruby scripts or in Ruby applications where a
18
+ # supported framework isn't being used. Supported frameworks
19
+ # will instead be detected at load time and initialization is
20
+ # automatic.
21
+ def load
22
+ # In case some apps call this manually, make sure
23
+ # that the gem is fully loaded and not in no-op
24
+ # mode (e.g. on unsupported platforms etc.)
25
+ if SolarWindsAPM.loaded
26
+ SolarWindsAPM::Inst.load_instrumentation
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ if SolarWindsAPM.loaded && !SolarWindsAPM.framework?
34
+ SolarWindsAPM::Ruby.load
35
+ end
@@ -0,0 +1,123 @@
1
+ #--
2
+ # Copyright (c) SolarWinds, LLC.
3
+ # All rights reserved.
4
+ #++
5
+
6
+ module SolarWindsAPM
7
+ module SDK
8
+
9
+ module CurrentTraceInfo
10
+ # Creates an instance of {TraceInfo} with instance methods {TraceInfo#trace_id},
11
+ # {TraceInfo#span_id}, {TraceInfo#trace_flags}, {TraceInfo#for_log},
12
+ # and {TraceInfo#hash_for_log}.
13
+ #
14
+ # === Example:
15
+ #
16
+ # trace = SolarWindsAPM::SDK.current_trace_info
17
+ # trace.for_log # 'trace_id=7435a9fe510ae4533414d425dadf4e18 span_id=49e60702469db05f trace_flags=01' or '' depends on Config
18
+ # trace.hash_for_log # { trace_id: '7435a9fe510ae4533414d425dadf4e18',
19
+ # span_id: '49e60702469db05f',
20
+ # trace_flags: ''} or {} depends on Config
21
+ #
22
+ # Configure trace info injection with lograge:
23
+ #
24
+ # Lograge.custom_options = lambda do |event|
25
+ # SolarWindsAPM::SDK.current_trace_info.hash_for_log
26
+ # end
27
+ #
28
+
29
+ def current_trace_info
30
+ TraceInfo.new
31
+ end
32
+
33
+ # @attr trace_id
34
+ # @attr span_id
35
+ # @attr trace_flags
36
+ class TraceInfo
37
+ attr_reader :tracestring, :trace_id, :span_id, :trace_flags, :do_log
38
+
39
+ SQL_REGEX=/\/\*\s*traceparent=.*\*\/\s*/.freeze
40
+
41
+ def initialize
42
+ tracestring = SolarWindsAPM::Context.toString
43
+ parts = SolarWindsAPM::TraceString.split(tracestring)
44
+
45
+ @tracestring = parts[:tracestring]
46
+ @trace_id = parts[:trace_id]
47
+ @span_id = parts[:span_id]
48
+ @trace_flags = parts[:flags]
49
+
50
+ @do_log = log? # true if the tracecontext should be added to logs
51
+ @do_sql = sql? # true if the tracecontext should be added to sql
52
+ end
53
+
54
+ # for_log returns a string in the format
55
+ # 'trace_id=<trace_id> span_id=<span_id> trace_flags=<trace_flags>' or ''.
56
+ #
57
+ # An empty string is returned depending on the setting for
58
+ # <tt>SolarWindsAPM::Config[:log_traceId]</tt>, which can be :never,
59
+ # :sampled, :traced, or :always.
60
+ #
61
+ def for_log
62
+ @for_log ||= @do_log ? "trace_id=#{@trace_id} span_id=#{@span_id} trace_flags=#{@trace_flags}" : ''
63
+ end
64
+
65
+ def hash_for_log
66
+ @hash_for_log ||= @do_log ? { trace_id: @trace_id,
67
+ span_id: @span_id,
68
+ trace_flags: @trace_flags } : {}
69
+ end
70
+
71
+ def for_sql
72
+ @for_sql ||= @do_sql ? "/*traceparent='#{@tracestring}'*/" : ''
73
+ end
74
+
75
+ ##
76
+ # add_traceparent_to_sql
77
+ #
78
+ # returns the sql with "/*traceparent='#{@tracestring}'*/" prepended
79
+ # and adds the QueryTag kv to kvs
80
+ #
81
+ def add_traceparent_to_sql(sql, kvs)
82
+ sql = sql.gsub(SQL_REGEX, '') # remove if it was added before
83
+
84
+ unless for_sql.empty?
85
+ kvs[:QueryTag] = for_sql
86
+ return "#{for_sql}#{sql}"
87
+ end
88
+
89
+ sql
90
+ end
91
+
92
+ private
93
+
94
+ # if true the trace info should be added to the log message
95
+ def log?
96
+ case SolarWindsAPM::Config[:log_traceId]
97
+ when :never, nil
98
+ false
99
+ when :always
100
+ # there is no way @tracestring is not ok
101
+ # it may be all 0s, but that is ok
102
+ # SolarWindsAPM::TraceString.ok?(@tracestring)
103
+ true
104
+ when :traced
105
+ SolarWindsAPM::TraceString.valid?(@tracestring)
106
+ when :sampled
107
+ SolarWindsAPM::TraceString.sampled?(@tracestring)
108
+ end
109
+ end
110
+
111
+ # if true the trace info should be added to the sql query
112
+ def sql?
113
+ SolarWindsAPM::Config[:tag_sql] &&
114
+ SolarWindsAPM::TraceString.sampled?(@tracestring)
115
+ end
116
+
117
+ end
118
+
119
+ end
120
+
121
+ extend CurrentTraceInfo
122
+ end
123
+ end
@@ -0,0 +1,94 @@
1
+ #--
2
+ # Copyright (c) 2016 SolarWinds, LLC.
3
+ # All rights reserved.
4
+ #++
5
+
6
+ module SolarWindsAPM
7
+ module SDK
8
+
9
+ module CustomMetrics
10
+
11
+ # Send counts
12
+ #
13
+ # Use this method to report the number of times an action occurs. The metric counts reported are summed and flushed every 60 seconds.
14
+ #
15
+ # === Arguments:
16
+ #
17
+ # * +name+ (String) Name to be used for the metric. Must be 255 or fewer characters and consist only of A-Za-z0-9.:-*
18
+ # * +count+ (Integer, optional, default = 1): Count of actions being reported
19
+ # * +with_hostname+ (Boolean, optional, default = false): Indicates if the host name should be included as a tag for the metric
20
+ # * +tags_kvs+ (Hash, optional): List of key/value pairs to describe the metric. The key must be <= 64 characters, the value must be <= 255 characters, allowed characters: A-Za-z0-9.:-_
21
+ #
22
+ # === Example:
23
+ #
24
+ # class WorkTracker
25
+ # def counting(name, tags = {})
26
+ # yield # yield to where work is done
27
+ # SolarWindsAPM::SDK.increment_metric(name, 1, false, tags)
28
+ # end
29
+ # end
30
+ #
31
+ # === Returns:
32
+ # * 0 on success, error code on failure
33
+ #
34
+ def increment_metric(name, count = 1, with_hostname = false, tags_kvs = {})
35
+ return true unless SolarWindsAPM.loaded
36
+ with_hostname = with_hostname ? 1 : 0
37
+ tags, tags_count = make_tags(tags_kvs)
38
+ SolarWindsAPM::CustomMetrics.increment(name.to_s, count, with_hostname, nil, tags, tags_count) == 1
39
+ end
40
+
41
+ # Send values with counts
42
+ #
43
+ # Use this method to report a value for each or multiple counts. The metric values reported are aggregated and flushed every 60 seconds. The dashboard displays the average value per count.
44
+ #
45
+ # === Arguments:
46
+ #
47
+ # * +name+ (String) Name to be used for the metric. Must be 255 or fewer characters and consist only of A-Za-z0-9.:-*
48
+ # * +value+ (Numeric) Value to be added to the current sum
49
+ # * +count+ (Integer, optional, default = 1): Count of actions being reported
50
+ # * +with_hostname+ (Boolean, optional, default = false): Indicates if the host name should be included as a tag for the metric
51
+ # * +tags_kvs+ (Hash, optional): List of key/value pairs to describe the metric. The key must be <= 64 characters, the value must be <= 255 characters, allowed characters: A-Za-z0-9.:-_
52
+ #
53
+ # === Example:
54
+ #
55
+ # class WorkTracker
56
+ # def timing(name, tags = {})
57
+ # start = Time.now
58
+ # yield # yield to where work is done
59
+ # duration = Time.now - start
60
+ # SolarWindsAPM::SDK.summary_metric(name, duration, 1, false, tags)
61
+ # end
62
+ # end
63
+ #
64
+ # === Returns:
65
+ # * 0 on success, error code on failure
66
+ #
67
+ def summary_metric(name, value, count = 1, with_hostname = false, tags_kvs = {})
68
+ return true unless SolarWindsAPM.loaded
69
+ with_hostname = with_hostname ? 1 : 0
70
+ tags, tags_count = make_tags(tags_kvs)
71
+ SolarWindsAPM::CustomMetrics.summary(name.to_s, value, count, with_hostname, nil, tags, tags_count) == 1
72
+ end
73
+
74
+ private
75
+
76
+ def make_tags(tags_kvs)
77
+ unless tags_kvs.is_a?(Hash)
78
+ SolarWindsAPM.logger.warn("[solarwinds_apm/metrics] CustomMetrics received tags_kvs that are not a Hash (found #{tags_kvs.class}), setting tags_kvs = {}")
79
+ tags_kvs = {}
80
+ end
81
+ count = tags_kvs.size
82
+ tags = SolarWindsAPM::MetricTags.new(count)
83
+
84
+ tags_kvs.each_with_index do |(k, v), i|
85
+ tags.add(i, k.to_s, v.to_s)
86
+ end
87
+
88
+ [tags, count]
89
+ end
90
+ end
91
+
92
+ extend CustomMetrics
93
+ end
94
+ end
@@ -0,0 +1,37 @@
1
+ # Copyright (c) 2019 SolarWinds, LLC.
2
+ # All rights reserved.
3
+ #
4
+
5
+ module SolarWindsAPM
6
+ module SDK
7
+ module Logging
8
+
9
+ # Log an information event in the current span
10
+ #
11
+ # a possible use-case is to collect extra information during the execution of a request
12
+ #
13
+ # === Arguments:
14
+ # * +kvs+ - (optional) hash containing key/value pairs that will be reported with this span.
15
+ #
16
+ def log_info(kvs)
17
+ SolarWindsAPM::API.log_info(SolarWindsAPM.layer, kvs)
18
+ end
19
+
20
+ # Log an exception/error event in the current span
21
+ #
22
+ # this may be helpful to track problems when an exception is rescued
23
+ #
24
+ # === Arguments:
25
+ # * +exception+ - an exception, must respond to :message and :backtrace
26
+ # * +kvs+ - (optional) hash containing key/value pairs that will be reported with this span.
27
+ #
28
+ def log_exception(exception, kvs = {})
29
+ SolarWindsAPM::API.log_exception(SolarWindsAPM.layer, exception, kvs)
30
+ end
31
+
32
+ end
33
+
34
+ extend Logging
35
+
36
+ end
37
+ end
@@ -0,0 +1,69 @@
1
+ #sh Copyright (c) SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module SolarWindsAPM
5
+ module SDK
6
+ ##
7
+ #
8
+ # Module to be included in classes with outbound calls
9
+ #
10
+ module TraceContextHeaders
11
+
12
+ ##
13
+ # Add w3c tracecontext to headers arg
14
+ #
15
+ # === Argument:
16
+ # * +:headers+ outbound headers, a Hash or other object that can have key/value assigned
17
+ #
18
+ # Internally it uses SolarWindsAPM.trace_context, which is a thread local
19
+ # variable containing verified and processed incoming w3c headers.
20
+ # It gets populated by requests processed by Rack or through the
21
+ # :headers arg in SolarWindsAPM::SDK.start_trace
22
+ #
23
+ # === Example:
24
+ # class OutboundCaller
25
+ # include SolarWindsAPM::SDK::TraceContextHeaders
26
+ #
27
+ # # create new headers
28
+ # def faraday_send
29
+ # conn = Faraday.new(:url => 'http://example.com')
30
+ # headers = add_tracecontext_headers
31
+ # conn.get('/', nil, headers)
32
+ # end
33
+ #
34
+ # # add to given headers
35
+ # def excon_send(headers)
36
+ # conn = Excon.new('http://example.com')
37
+ # add_tracecontext_headers(headers)
38
+ # conn.get(headers: headers)
39
+ # end
40
+ # end
41
+ #
42
+ # === Returns:
43
+ # * The headers with w3c tracecontext added, also modifies the headers arg if given
44
+ #
45
+ def add_tracecontext_headers(headers = {})
46
+ begin
47
+ if SolarWindsAPM::Context.isValid
48
+ headers['traceparent'] = SolarWindsAPM::Context.toString
49
+ parent_id_flags = SolarWindsAPM::TraceString.span_id_flags(headers['traceparent'])
50
+ tracestate = SolarWindsAPM.trace_context&.tracestate
51
+ headers['tracestate'] = SolarWindsAPM::TraceState.add_sw_member(tracestate, parent_id_flags)
52
+ else
53
+ # make sure we propagate an incoming trace_context even if we don't trace
54
+ if SolarWindsAPM.trace_context
55
+ headers['traceparent'] = SolarWindsAPM.trace_context.traceparent
56
+ headers['tracestate'] = SolarWindsAPM.trace_context.tracestate
57
+ end
58
+ end
59
+ rescue => e
60
+ # we don't know what the class of headers is and the obj may not
61
+ # be able to accept a key/value assignment
62
+ # unfortunately I could not find a method to check for that
63
+ # therefore we're catching the error and don't change the headers
64
+ end
65
+ headers
66
+ end
67
+ end
68
+ end
69
+ end