appoptics_apm_mnfst 4.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. checksums.yaml +7 -0
  2. data/.dockerignore +5 -0
  3. data/.github/ISSUE_TEMPLATE/bug-or-feature-request.md +16 -0
  4. data/.gitignore +29 -0
  5. data/.rubocop.yml +8 -0
  6. data/.travis.yml +121 -0
  7. data/.yardopts +4 -0
  8. data/CHANGELOG.md +769 -0
  9. data/CONFIG.md +33 -0
  10. data/Gemfile +29 -0
  11. data/LICENSE +193 -0
  12. data/README.md +393 -0
  13. data/Rakefile +230 -0
  14. data/appoptics_apm.gemspec +61 -0
  15. data/bin/appoptics_apm_config +15 -0
  16. data/build_gem.sh +15 -0
  17. data/build_gem_upload_to_packagecloud.sh +20 -0
  18. data/examples/SDK/01_basic_tracing.rb +67 -0
  19. data/examples/carrying_context.rb +220 -0
  20. data/ext/oboe_metal/extconf.rb +114 -0
  21. data/ext/oboe_metal/lib/.keep +0 -0
  22. data/ext/oboe_metal/noop/noop.c +7 -0
  23. data/ext/oboe_metal/src/VERSION +1 -0
  24. data/init.rb +4 -0
  25. data/lib/appoptics_apm.rb +76 -0
  26. data/lib/appoptics_apm/api.rb +20 -0
  27. data/lib/appoptics_apm/api/layerinit.rb +41 -0
  28. data/lib/appoptics_apm/api/logging.rb +375 -0
  29. data/lib/appoptics_apm/api/memcache.rb +37 -0
  30. data/lib/appoptics_apm/api/metrics.rb +55 -0
  31. data/lib/appoptics_apm/api/profiling.rb +203 -0
  32. data/lib/appoptics_apm/api/tracing.rb +53 -0
  33. data/lib/appoptics_apm/api/util.rb +122 -0
  34. data/lib/appoptics_apm/base.rb +230 -0
  35. data/lib/appoptics_apm/config.rb +254 -0
  36. data/lib/appoptics_apm/frameworks/grape.rb +97 -0
  37. data/lib/appoptics_apm/frameworks/padrino.rb +108 -0
  38. data/lib/appoptics_apm/frameworks/rails.rb +94 -0
  39. data/lib/appoptics_apm/frameworks/rails/inst/action_controller.rb +104 -0
  40. data/lib/appoptics_apm/frameworks/rails/inst/action_controller3.rb +55 -0
  41. data/lib/appoptics_apm/frameworks/rails/inst/action_controller4.rb +48 -0
  42. data/lib/appoptics_apm/frameworks/rails/inst/action_controller5.rb +50 -0
  43. data/lib/appoptics_apm/frameworks/rails/inst/action_controller_api.rb +50 -0
  44. data/lib/appoptics_apm/frameworks/rails/inst/action_view.rb +58 -0
  45. data/lib/appoptics_apm/frameworks/rails/inst/action_view_30.rb +50 -0
  46. data/lib/appoptics_apm/frameworks/rails/inst/active_record.rb +27 -0
  47. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
  48. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/mysql2.rb +29 -0
  49. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/postgresql.rb +31 -0
  50. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils.rb +119 -0
  51. data/lib/appoptics_apm/frameworks/rails/inst/connection_adapters/utils5x.rb +108 -0
  52. data/lib/appoptics_apm/frameworks/sinatra.rb +125 -0
  53. data/lib/appoptics_apm/inst/bunny-client.rb +148 -0
  54. data/lib/appoptics_apm/inst/bunny-consumer.rb +89 -0
  55. data/lib/appoptics_apm/inst/curb.rb +330 -0
  56. data/lib/appoptics_apm/inst/dalli.rb +85 -0
  57. data/lib/appoptics_apm/inst/delayed_job.rb +92 -0
  58. data/lib/appoptics_apm/inst/em-http-request.rb +101 -0
  59. data/lib/appoptics_apm/inst/excon.rb +125 -0
  60. data/lib/appoptics_apm/inst/faraday.rb +94 -0
  61. data/lib/appoptics_apm/inst/grpc_client.rb +162 -0
  62. data/lib/appoptics_apm/inst/grpc_server.rb +120 -0
  63. data/lib/appoptics_apm/inst/http.rb +73 -0
  64. data/lib/appoptics_apm/inst/httpclient.rb +174 -0
  65. data/lib/appoptics_apm/inst/memcached.rb +86 -0
  66. data/lib/appoptics_apm/inst/mongo.rb +246 -0
  67. data/lib/appoptics_apm/inst/mongo2.rb +225 -0
  68. data/lib/appoptics_apm/inst/moped.rb +466 -0
  69. data/lib/appoptics_apm/inst/rack.rb +199 -0
  70. data/lib/appoptics_apm/inst/redis.rb +275 -0
  71. data/lib/appoptics_apm/inst/resque.rb +151 -0
  72. data/lib/appoptics_apm/inst/rest-client.rb +48 -0
  73. data/lib/appoptics_apm/inst/sequel.rb +178 -0
  74. data/lib/appoptics_apm/inst/sidekiq-client.rb +55 -0
  75. data/lib/appoptics_apm/inst/sidekiq-worker.rb +65 -0
  76. data/lib/appoptics_apm/inst/twitter-cassandra.rb +294 -0
  77. data/lib/appoptics_apm/inst/typhoeus.rb +108 -0
  78. data/lib/appoptics_apm/instrumentation.rb +22 -0
  79. data/lib/appoptics_apm/legacy_method_profiling.rb +90 -0
  80. data/lib/appoptics_apm/loading.rb +65 -0
  81. data/lib/appoptics_apm/logger.rb +42 -0
  82. data/lib/appoptics_apm/method_profiling.rb +33 -0
  83. data/lib/appoptics_apm/noop/README.md +9 -0
  84. data/lib/appoptics_apm/noop/context.rb +26 -0
  85. data/lib/appoptics_apm/noop/metadata.rb +22 -0
  86. data/lib/appoptics_apm/ruby.rb +35 -0
  87. data/lib/appoptics_apm/sdk/custom_metrics.rb +92 -0
  88. data/lib/appoptics_apm/sdk/tracing.rb +315 -0
  89. data/lib/appoptics_apm/support.rb +119 -0
  90. data/lib/appoptics_apm/test.rb +94 -0
  91. data/lib/appoptics_apm/thread_local.rb +26 -0
  92. data/lib/appoptics_apm/util.rb +319 -0
  93. data/lib/appoptics_apm/version.rb +15 -0
  94. data/lib/appoptics_apm/xtrace.rb +103 -0
  95. data/lib/joboe_metal.rb +212 -0
  96. data/lib/oboe.rb +7 -0
  97. data/lib/oboe/README +2 -0
  98. data/lib/oboe/backward_compatibility.rb +80 -0
  99. data/lib/oboe/inst/rack.rb +11 -0
  100. data/lib/oboe_metal.rb +198 -0
  101. data/lib/rails/generators/appoptics_apm/install_generator.rb +45 -0
  102. data/lib/rails/generators/appoptics_apm/templates/appoptics_apm_initializer.rb +265 -0
  103. data/yardoc_frontpage.md +26 -0
  104. metadata +266 -0
@@ -0,0 +1,114 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require 'mkmf'
5
+ require 'rbconfig'
6
+ require 'open-uri'
7
+ require 'no_proxy_fix'
8
+
9
+ ext_dir = File.expand_path(File.dirname(__FILE__))
10
+
11
+ # Check if we're running in JRuby
12
+ jruby = defined?(JRUBY_VERSION) ? true : false
13
+
14
+ # Set the mkmf lib paths so we have no issues linking to
15
+ # the AppOpticsAPM libs.
16
+ ao_lib_dir = File.join(ext_dir, 'lib')
17
+ ao_include = File.join(ext_dir, 'src')
18
+
19
+ # Download the appropriate liboboe from S3(via rake for testing) or files.appoptics.com (production)
20
+ version = File.read(File.join(ao_include, 'VERSION')).chomp
21
+ if ENV['APPOPTICS_FROM_S3'].to_s.downcase == 'true'
22
+ ao_path = File.join('https://s3-us-west-2.amazonaws.com/rc-files-t2/c-lib/', version)
23
+ puts "Fetching c-lib from S3"
24
+ else
25
+ ao_path = File.join('https://files.appoptics.com/c-lib', version)
26
+ end
27
+ ao_arch = `ldd --version 2>&1` =~ /musl/ ? 'alpine-x86_64' : 'x86_64'
28
+ ao_clib = "liboboe-1.0-#{ao_arch}.so.0.0.0"
29
+ ao_item = File.join(ao_path, ao_clib)
30
+ ao_checksum_item = "#{ao_item}.sha256"
31
+ clib = File.join(ao_lib_dir, ao_clib)
32
+
33
+ retries = 3
34
+ success = false
35
+ while retries > 0
36
+ begin
37
+ # download
38
+ download = open(ao_item, 'rb')
39
+ IO.copy_stream(download, clib)
40
+
41
+ checksum = open(ao_checksum_item, 'r').read.chomp
42
+ clib_checksum = Digest::SHA256.file(clib).hexdigest
43
+
44
+ # verify_checksum
45
+ if clib_checksum != checksum
46
+ $stderr.puts '== ERROR ================================================================='
47
+ $stderr.puts 'Checksum Verification failed for the c-extension of the appoptics_apm gem.'
48
+ $stderr.puts 'appoptics_apm will not instrument the code. No tracing will occur.'
49
+ $stderr.puts 'Contact support@appoptics.com if the problem persists.'
50
+ $stderr.puts '=========================================================================='
51
+ create_makefile('oboe_noop', 'noop')
52
+ retries = 0
53
+ else
54
+ success = true
55
+ retries = 0
56
+ end
57
+ rescue => e
58
+ File.write(clib, '')
59
+ retries -= 1
60
+ if retries == 0
61
+ $stderr.puts '== ERROR =========================================================='
62
+ $stderr.puts 'Download of the c-extension for the appoptics_apm gem failed.'
63
+ $stderr.puts 'appoptics_apm will not instrument the code. No tracing will occur.'
64
+ $stderr.puts 'Contact support@appoptics.com if the problem persists.'
65
+ $stderr.puts "error:\n#{e.message}"
66
+ $stderr.puts '==================================================================='
67
+ create_makefile('oboe_noop', 'noop')
68
+ end
69
+ sleep 0.5
70
+ end
71
+ end
72
+
73
+ if success
74
+ # Create relative symlinks for the AppOpticsAPM library
75
+ Dir.chdir(ao_lib_dir) do
76
+ File.symlink(ao_clib, 'liboboe.so')
77
+ File.symlink(ao_clib, 'liboboe-1.0.so.0')
78
+ end
79
+
80
+ dir_config('oboe', 'src', 'lib')
81
+
82
+ # create Makefile
83
+ if jruby || ENV.key?('APPOPTICS_URL')
84
+ # Build the noop extension under JRuby and Heroku.
85
+ # The oboe-heroku gem builds it's own c extension which links to
86
+ # libs specific to a Heroku dyno
87
+ # FIXME: For JRuby we need to remove the c extension entirely
88
+ create_makefile('oboe_noop', 'noop')
89
+
90
+ elsif have_library('oboe', 'oboe_config_get_revision', 'oboe.h')
91
+
92
+ $libs = append_library($libs, 'oboe')
93
+ $libs = append_library($libs, 'stdc++')
94
+
95
+ $CFLAGS << " #{ENV['CFLAGS']}"
96
+ $CPPFLAGS << " #{ENV['CPPFLAGS']}"
97
+ $LIBS << " #{ENV['LIBS']}"
98
+ $LDFLAGS << " #{ENV['LDFLAGS']} '-Wl,-rpath=$$ORIGIN/../ext/oboe_metal/lib'"
99
+
100
+ create_makefile('oboe_metal', 'src')
101
+
102
+ else
103
+ $stderr.puts '== ERROR ========================================================='
104
+ if have_library('oboe')
105
+ $stderr.puts "The c-library either needs to be updated or doesn't match the OS."
106
+ $stderr.puts 'No tracing will occur.'
107
+ else
108
+ $stderr.puts 'Could not find a matching c-library. No tracing will occur.'
109
+ end
110
+ $stderr.puts 'Contact support@appoptics.com if the problem persists.'
111
+ $stderr.puts '=================================================================='
112
+ create_makefile('oboe_noop', 'noop')
113
+ end
114
+ end
File without changes
@@ -0,0 +1,7 @@
1
+ #include <ruby.h>
2
+
3
+ /* ruby calls this to load the extension */
4
+ void Init_oboe_noop(void) {
5
+ /* assume we haven't yet defined Hola */
6
+ VALUE klass = rb_define_class("OboeNoop", rb_cObject);
7
+ }
@@ -0,0 +1 @@
1
+ 4.0.0
data/init.rb ADDED
@@ -0,0 +1,4 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ require 'appoptics_apm'
@@ -0,0 +1,76 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ begin
5
+ require 'openssl'
6
+ require 'appoptics_apm/version'
7
+ require 'appoptics_apm/thread_local'
8
+ require 'appoptics_apm/logger'
9
+ require 'appoptics_apm/util'
10
+ require 'appoptics_apm/xtrace'
11
+ require 'appoptics_apm/support'
12
+ require 'appoptics_apm/base'
13
+ AppOpticsAPM.loaded = false
14
+
15
+ require 'appoptics_apm/config'
16
+ AppOpticsAPM::Config.load_config_file
17
+
18
+ begin
19
+ if RUBY_PLATFORM == 'java'
20
+ require '/usr/local/tracelytics/tracelyticsagent.jar'
21
+ require 'joboe_metal'
22
+ elsif RUBY_PLATFORM =~ /linux/
23
+ require_relative './oboe_metal.so'
24
+ require 'oboe_metal.rb' # sets AppOpticsAPM.loaded = true if successful
25
+ else
26
+ $stderr.puts '==================================================================='
27
+ $stderr.puts "AppOptics warning: Platform #{RUBY_PLATFORM} not yet supported."
28
+ $stderr.puts 'see: https://docs.appoptics.com/kb/apm_tracing/supported_platforms/'
29
+ $stderr.puts 'Tracing disabled.'
30
+ $stderr.puts 'Contact support@appoptics.com if this is unexpected.'
31
+ $stderr.puts '==================================================================='
32
+ end
33
+ rescue LoadError => e
34
+ unless ENV['RAILS_GROUP'] == 'assets' or ENV['IGNORE_APPOPTICS_WARNING']
35
+ $stderr.puts '=============================================================='
36
+ $stderr.puts 'Missing AppOpticsAPM libraries. Tracing disabled.'
37
+ $stderr.puts "Error: #{e.message}"
38
+ $stderr.puts 'See: https://docs.appoptics.com/kb/apm_tracing/ruby/'
39
+ $stderr.puts '=============================================================='
40
+ end
41
+ end
42
+
43
+ # appoptics_apm/loading can set AppOpticsAPM.loaded = false if the service key is not working
44
+ require 'appoptics_apm/loading'
45
+ require 'appoptics_apm/legacy_method_profiling'
46
+ require 'appoptics_apm/method_profiling'
47
+
48
+ if AppOpticsAPM.loaded
49
+ # tracing mode is configured via config file but can only be set once we have oboe_metal loaded
50
+ AppOpticsAPM.set_tracing_mode(AppOpticsAPM::Config[:tracing_mode].to_sym)
51
+ require 'appoptics_apm/instrumentation'
52
+
53
+ # Frameworks
54
+ require 'appoptics_apm/frameworks/rails'
55
+ require 'appoptics_apm/frameworks/sinatra'
56
+ require 'appoptics_apm/frameworks/padrino'
57
+ require 'appoptics_apm/frameworks/grape'
58
+ else
59
+ $stderr.puts '=============================================================='
60
+ $stderr.puts 'AppOpticsAPM not loaded. Tracing disabled.'
61
+ $stderr.puts 'Service Key may be wrong or missing.'
62
+ $stderr.puts '=============================================================='
63
+ require 'appoptics_apm/noop/context'
64
+ require 'appoptics_apm/noop/metadata'
65
+ end
66
+
67
+ # Load Ruby module last. If there is no framework detected,
68
+ # it will load all of the Ruby instrumentation
69
+ require 'appoptics_apm/ruby'
70
+ require 'oboe/backward_compatibility'
71
+
72
+ require 'appoptics_apm/test' if ENV['APPOPTICS_GEM_TEST']
73
+ rescue => e
74
+ $stderr.puts "[appoptics_apm/error] Problem loading: #{e.inspect}"
75
+ $stderr.puts e.backtrace
76
+ end
@@ -0,0 +1,20 @@
1
+ # Copyright (c) 2016 SolarWinds, LLC.
2
+ # All rights reserved.
3
+
4
+ module AppOpticsAPM
5
+
6
+ module API
7
+ extend AppOpticsAPM::API::Logging
8
+ extend AppOpticsAPM::API::Metrics
9
+ extend AppOpticsAPM::API::Profiling
10
+ extend AppOpticsAPM::API::LayerInit
11
+ extend AppOpticsAPM::API::Util
12
+
13
+ require_relative './sdk/tracing'
14
+ require_relative './sdk/custom_metrics'
15
+
16
+ extend AppOpticsAPM::SDK::Tracing
17
+ extend AppOpticsAPM::SDK::CustomMetrics
18
+ extend AppOpticsAPM::API::Tracing
19
+ end
20
+ end
@@ -0,0 +1,41 @@
1
+ #--
2
+ # Copyright (c) 2016 SolarWinds, LLC.
3
+ # All rights reserved.
4
+ #++
5
+
6
+ module AppOpticsAPM
7
+ module API
8
+ ##
9
+ # Provides methods related to layer initialization and reporting
10
+ module LayerInit #:nodoc:
11
+ # Internal: Report that instrumentation for the given layer has been
12
+ # installed, as well as the version of instrumentation and version of
13
+ # layer.
14
+ #
15
+ def report_init(layer = :rack) #:nodoc:
16
+ # Don't send __Init in test or if AppOpticsAPM
17
+ # isn't fully loaded (e.g. missing c-extension)
18
+ return if ENV.key?('APPOPTICS_GEM_TEST') || !AppOpticsAPM.loaded
19
+
20
+ platform_info = AppOpticsAPM::Util.build_init_report
21
+ log_init(layer, platform_info)
22
+ end
23
+
24
+ ##
25
+ # :nodoc:
26
+ # Deprecated:
27
+ # force_trace has been deprecated and will be removed in a subsequent version.
28
+ #
29
+ def force_trace
30
+ AppOpticsAPM.logger.warn '[appoptics_apm/api] AppOpticsAPM::API::LayerInit.force_trace has been deprecated and will be ' \
31
+ 'removed in a subsequent version.'
32
+
33
+ saved_mode = AppOpticsAPM::Config[:tracing_mode]
34
+ AppOpticsAPM::Config[:tracing_mode] = :always
35
+ yield
36
+ ensure
37
+ AppOpticsAPM::Config[:tracing_mode] = saved_mode
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,375 @@
1
+ #--
2
+ # Copyright (c) 2016 SolarWinds, LLC.
3
+ # All rights reserved.
4
+ #++
5
+
6
+ # Make sure Set is loaded if possible.
7
+ begin
8
+ require 'set'
9
+ rescue LoadError
10
+ class Set; end # :nodoc:
11
+ end
12
+
13
+
14
+ module AppOpticsAPM
15
+ module API
16
+ ##
17
+ # This modules provides the X-Trace logging facilities.
18
+ #
19
+ # These are the lower level methods, please see AppOpticsAPM::SDK
20
+ # for the higher level methods
21
+ #
22
+ # If using these directly make sure to always match a start/end and entry/exit to
23
+ # avoid broken traces.
24
+ module Logging
25
+ @@ints_or_nil = [Integer, Float, NilClass, String]
26
+ @@ints_or_nil << Fixnum unless RUBY_VERSION >= '2.4'
27
+
28
+ ##
29
+ # Public: Report an event in an active trace.
30
+ #
31
+ # ==== Arguments
32
+ #
33
+ # * +layer+ - The layer the reported event belongs to
34
+ # * +label+ - The label for the reported event. See SDK documentation for reserved labels and usage.
35
+ # * +opts+ - A hash containing key/value pairs that will be reported along with this event (optional).
36
+ # * +event+ - An event to be used instead of generating a new one (see also start_trace_with_target)
37
+ #
38
+ # ==== Example
39
+ #
40
+ # AppOpticsAPM::API.log('logical_layer', 'entry')
41
+ # AppOpticsAPM::API.log('logical_layer', 'info', { :list_length => 20 })
42
+ # AppOpticsAPM::API.log('logical_layer', 'exit')
43
+ #
44
+ # Returns nothing.
45
+ def log(layer, label, opts = {}, event = nil)
46
+ return AppOpticsAPM::Context.toString unless AppOpticsAPM.tracing?
47
+
48
+ event ||= AppOpticsAPM::Context.createEvent
49
+ log_event(layer, label, event, opts)
50
+ end
51
+
52
+ ##
53
+ # Public: Report an exception.
54
+ #
55
+ # ==== Arguments
56
+ #
57
+ # * +layer+ - The layer the reported event belongs to
58
+ # * +exception+ - The exception to report
59
+ # * +opts+ - Custom params if you want to log extra information
60
+ #
61
+ # ==== Example
62
+ #
63
+ # begin
64
+ # my_iffy_method
65
+ # rescue Exception => e
66
+ # AppOpticsAPM::API.log_exception('rails', e, { user: user_id })
67
+ # raise
68
+ # end
69
+ #
70
+ # Returns nothing.
71
+ def log_exception(layer, exception, opts = {})
72
+ return AppOpticsAPM::Context.toString if !AppOpticsAPM.tracing? || exception.instance_variable_get(:@exn_logged)
73
+
74
+ unless exception
75
+ AppOpticsAPM.logger.debug '[appoptics_apm/debug] log_exception called with nil exception'
76
+ return AppOpticsAPM::Context.toString
77
+ end
78
+
79
+ exception.message << exception.class.name if exception.message.length < 4
80
+ opts.merge!(:Spec => 'error',
81
+ :ErrorClass => exception.class.name,
82
+ :ErrorMsg => exception.message)
83
+ opts.merge!(:Backtrace => exception.backtrace.join("\r\n")) if exception.backtrace
84
+
85
+ exception.instance_variable_set(:@exn_logged, true)
86
+ log(layer, :error, opts)
87
+ end
88
+
89
+ ##
90
+ # Public: Decide whether or not to start a trace, and report an entry event
91
+ # appropriately.
92
+ #
93
+ # ==== Arguments
94
+ #
95
+ # * +layer+ - The layer the reported event belongs to
96
+ # * +xtrace+ - An xtrace metadata string, or nil. Used for cross-application tracing.
97
+ # * +opts+ - A hash containing key/value pairs that will be reported along with this event (optional).
98
+ #
99
+ # ==== Example
100
+ #
101
+ # AppOpticsAPM::API.log_start(:layer_name, nil, { :id => @user.id })
102
+ #
103
+ # Returns an xtrace metadata string if we are tracing
104
+ def log_start(layer, xtrace = nil, opts = {})
105
+ return if !AppOpticsAPM.loaded || (opts.key?(:URL) && AppOpticsAPM::Util.static_asset?(opts[:URL]))
106
+
107
+ #--
108
+ # Is the below necessary? Only on JRuby? Could there be an existing context but not x-trace header?
109
+ # See discussion at:
110
+ # https://github.com/librato/ruby-tracelytics/pull/6/files?diff=split#r131029135
111
+ #
112
+ # Used by JRuby/Java webservers such as Tomcat
113
+ # AppOpticsAPM::Context.fromString(xtrace) if AppOpticsAPM.pickup_context?(xtrace)
114
+
115
+ # if AppOpticsAPM.tracing?
116
+ # # Pre-existing context. Either we inherited context from an
117
+ # # incoming X-Trace request header or under JRuby, Joboe started
118
+ # # tracing before the JRuby code was called (e.g. Tomcat)
119
+ # AppOpticsAPM.is_continued_trace = true
120
+
121
+ # if AppOpticsAPM.has_xtrace_header
122
+ # opts[:TraceOrigin] = :continued_header
123
+ # elsif AppOpticsAPM.has_incoming_context
124
+ # opts[:TraceOrigin] = :continued_context
125
+ # else
126
+ # opts[:TraceOrigin] = :continued
127
+ # end
128
+
129
+ # return log_entry(layer, opts)
130
+ # end
131
+ #++
132
+
133
+ # This is a bit ugly, but here is the best place to reset the layer_op thread local var.
134
+ AppOpticsAPM.layer_op = nil unless AppOpticsAPM::Context.isValid
135
+
136
+ if AppOpticsAPM.sample?(opts.merge(:xtrace => xtrace))
137
+ # Yes, we're sampling this request
138
+ # Probablistic tracing of a subset of requests based off of
139
+ # sample rate and sample source
140
+ opts[:SampleRate] = AppOpticsAPM.sample_rate
141
+ opts[:SampleSource] = AppOpticsAPM.sample_source
142
+ opts[:TraceOrigin] = :always_sampled
143
+
144
+ if xtrace_v2?(xtrace)
145
+ # continue valid incoming xtrace
146
+ # use it for current context, ensuring sample bit is set
147
+ AppOpticsAPM::XTrace.set_sampled(xtrace)
148
+
149
+ md = AppOpticsAPM::Metadata.fromString(xtrace)
150
+ AppOpticsAPM::Context.fromString(xtrace)
151
+ log_event(layer, :entry, md.createEvent, opts)
152
+ else
153
+ # discard invalid incoming xtrace
154
+ # create a new context, ensuring sample bit set
155
+ md = AppOpticsAPM::Metadata.makeRandom(true)
156
+ AppOpticsAPM::Context.set(md)
157
+ log_event(layer, :entry, AppOpticsAPM::Event.startTrace(md), opts)
158
+ end
159
+ else
160
+ # No, we're not sampling this request
161
+ # set the context but don't log the event
162
+ if xtrace_v2?(xtrace)
163
+ # continue valid incoming xtrace
164
+ # use it for current context, ensuring sample bit is not set
165
+ AppOpticsAPM::XTrace.unset_sampled(xtrace)
166
+ AppOpticsAPM::Context.fromString(xtrace)
167
+ else
168
+ # discard invalid incoming xtrace
169
+ # create a new context, ensuring sample bit not set
170
+ md = AppOpticsAPM::Metadata.makeRandom(false)
171
+ AppOpticsAPM::Context.fromString(md.toString)
172
+ end
173
+ end
174
+ AppOpticsAPM::Context.toString
175
+ end
176
+
177
+ ##
178
+ # Public: Report an exit event and potentially clear the tracing context.
179
+ #
180
+ # ==== Arguments
181
+ #
182
+ # * +layer+ - The layer the reported event belongs to
183
+ # * +opts+ - A hash containing key/value pairs that will be reported along with this event (optional).
184
+ #
185
+ # ==== Example
186
+ #
187
+ # AppOpticsAPM::API.log_end(:layer_name, { :id => @user.id })
188
+ #
189
+ # Returns an xtrace metadata string if we are tracing
190
+ def log_end(layer, opts = {}, event = nil)
191
+ return AppOpticsAPM::Context.toString unless AppOpticsAPM.tracing?
192
+
193
+ event ||= AppOpticsAPM::Context.createEvent
194
+ log_event(layer, :exit, event, opts)
195
+ ensure
196
+ # FIXME has_incoming_context commented out, it has importance for JRuby only but breaks Ruby tests
197
+ AppOpticsAPM::Context.clear # unless AppOpticsAPM.has_incoming_context?
198
+ AppOpticsAPM.transaction_name = nil
199
+ end
200
+
201
+ ##
202
+ # Public: Log an entry event
203
+ #
204
+ # A helper method to create and log an entry event
205
+ #
206
+ # ==== Arguments
207
+ #
208
+ # * +layer+ - The layer the reported event belongs to
209
+ # * +opts+ - A hash containing key/value pairs that will be reported along with this event (optional).
210
+ # * +op+ - To identify the current operation being traced. Used to avoid double tracing recursive calls.
211
+ #
212
+ # ==== Example
213
+ #
214
+ # AppOpticsAPM::API.log_entry(:layer_name, { :id => @user.id })
215
+ #
216
+ # Returns an xtrace metadata string if we are tracing
217
+ def log_entry(layer, opts = {}, op = nil)
218
+ return AppOpticsAPM::Context.toString unless AppOpticsAPM.tracing?
219
+
220
+ AppOpticsAPM.layer_op = (AppOpticsAPM.layer_op || []) << op.to_sym if op
221
+ log_event(layer, :entry, AppOpticsAPM::Context.createEvent, opts)
222
+ end
223
+
224
+ ##
225
+ # Public: Log an info event
226
+ #
227
+ # A helper method to create and log an info event
228
+ #
229
+ # ==== Arguments
230
+ #
231
+ # * +layer+ - The layer the reported event belongs to
232
+ # * +opts+ - A hash containing key/value pairs that will be reported along with this event (optional).
233
+ #
234
+ # ==== Example
235
+ #
236
+ # AppOpticsAPM::API.log_info(:layer_name, { :id => @user.id })
237
+ #
238
+ # Returns an xtrace metadata string if we are tracing
239
+ def log_info(layer, opts = {})
240
+ return AppOpticsAPM::Context.toString unless AppOpticsAPM.tracing?
241
+
242
+ log_event(layer, :info, AppOpticsAPM::Context.createEvent, opts)
243
+ end
244
+
245
+ ##
246
+ # Public: Log an exit event
247
+ #
248
+ # A helper method to create and log an exit event
249
+ #
250
+ # ==== Arguments
251
+ #
252
+ # * +layer+ - The layer the reported event belongs to
253
+ # * +opts+ - A hash containing key/value pairs that will be reported along with this event (optional).
254
+ # * +op+ - Used to avoid double tracing recursive calls, needs to be true in +log_exit+ that corresponds to a
255
+ # +log_entry+
256
+ #
257
+ # ==== Example
258
+ #
259
+ # AppOpticsAPM::API.log_exit(:layer_name, { :id => @user.id })
260
+ #
261
+ # Returns an xtrace metadata string if we are tracing
262
+ def log_exit(layer, opts = {}, op = nil)
263
+ return AppOpticsAPM::Context.toString unless AppOpticsAPM.tracing?
264
+
265
+ AppOpticsAPM.layer_op.pop if op && AppOpticsAPM.layer_op.is_a?(Array) && AppOpticsAPM.layer_op.last == op.to_sym
266
+
267
+ log_event(layer, :exit, AppOpticsAPM::Context.createEvent, opts)
268
+ end
269
+
270
+ ##
271
+ # Public: Log an exit event from multiple requests
272
+ #
273
+ # A helper method to create and log an info event
274
+ # If we return from a request that faned out multiple requests
275
+ # we can add the collected X-Traces to the exit event
276
+ #
277
+ # ==== Arguments
278
+ #
279
+ # * +layer+ - The layer the reported event belongs to
280
+ # * +traces+ - An array with X-Trace strings returned from the requests
281
+ #
282
+ def log_multi_exit(layer, traces)
283
+ return AppOpticsAPM::Context.toString unless AppOpticsAPM.tracing?
284
+ task_id = AppOpticsAPM::XTrace.task_id(AppOpticsAPM::Context.toString)
285
+ event = AppOpticsAPM::Context.createEvent
286
+ traces.each do |trace|
287
+ event.addEdgeStr(trace) if AppOpticsAPM::XTrace.task_id(trace) == task_id
288
+ end
289
+ log_event(layer, :exit, event)
290
+ end
291
+
292
+ ##
293
+ #:nodoc:
294
+ # Internal: Reports agent init to the collector
295
+ #
296
+ # ==== Arguments
297
+ #
298
+ # * +layer+ - The layer the reported event belongs to
299
+ # * +opts+ - A hash containing key/value pairs that will be reported along with this event
300
+ def log_init(layer = :rack, opts = {})
301
+ context = AppOpticsAPM::Metadata.makeRandom
302
+ return AppOpticsAPM::Context.toString unless context.isValid
303
+
304
+ event = context.createEvent
305
+ event.addInfo(APPOPTICS_STR_LAYER, layer.to_s)
306
+ event.addInfo(APPOPTICS_STR_LABEL, 'single')
307
+ opts.each do |k, v|
308
+ event.addInfo(k, v.to_s)
309
+ end
310
+
311
+ AppOpticsAPM::Reporter.sendStatus(event, context)
312
+ AppOpticsAPM::Context.toString
313
+ end
314
+
315
+ private
316
+
317
+ ##
318
+ #:nodoc:
319
+ # @private
320
+ # Internal: Report an event.
321
+ #
322
+ # ==== Arguments
323
+ #
324
+ # * +layer+ - The layer the reported event belongs to
325
+ # * +label+ - The label for the reported event. See API documentation for reserved labels and usage.
326
+ # * +event+ - The pre-existing AppOpticsAPM context event. See AppOpticsAPM::Context.createEvent
327
+ # * +opts+ - A hash containing key/value pairs that will be reported along with this event (optional).
328
+ #
329
+ # ==== Example
330
+ #
331
+ # entry = AppOpticsAPM::Context.createEvent
332
+ # AppOpticsAPM::API.log_event(:layer_name, 'entry', entry_event, { :id => @user.id })
333
+ #
334
+ # exit_event = AppOpticsAPM::Context.createEvent
335
+ # exit_event.addEdge(entry.getMetadata)
336
+ # AppOpticsAPM::API.log_event(:layer_name, 'exit', exit_event, { :id => @user.id })
337
+ #
338
+ def log_event(layer, label, event, opts = {})
339
+ event.addInfo(APPOPTICS_STR_LAYER, layer.to_s.freeze) if layer
340
+ event.addInfo(APPOPTICS_STR_LABEL, label.to_s.freeze)
341
+
342
+ AppOpticsAPM.layer = layer.to_sym if label == :entry
343
+ AppOpticsAPM.layer = nil if label == :exit
344
+
345
+ opts.each do |k, v|
346
+ value = nil
347
+
348
+ next unless valid_key? k
349
+
350
+ if @@ints_or_nil.include?(v.class)
351
+ value = v
352
+ elsif v.class == Set
353
+ value = v.to_a.to_s
354
+ else
355
+ value = v.to_s if v.respond_to?(:to_s)
356
+ end
357
+
358
+ begin
359
+ event.addInfo(k.to_s, value)
360
+ rescue ArgumentError => e
361
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] Couldn't add event KV: #{k} => #{v.class}"
362
+ AppOpticsAPM.logger.debug "[appoptics_apm/debug] #{e.message}"
363
+ end
364
+ end if !opts.nil? && opts.any?
365
+
366
+ AppOpticsAPM::Reporter.sendReport(event)
367
+ AppOpticsAPM::Context.toString
368
+ end
369
+
370
+ # need to set the context to public, otherwise the following `extends` will be private in api.rb
371
+ public
372
+
373
+ end
374
+ end
375
+ end