appoptics_apm_mnfst 4.5.2

Sign up to get free protection for your applications and to get access to all the features.
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