traceview 3.0.0-java

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 (137) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rubocop.yml +5 -0
  4. data/.travis.yml +58 -0
  5. data/Appraisals +10 -0
  6. data/CHANGELOG.md +490 -0
  7. data/CONFIG.md +16 -0
  8. data/Gemfile +95 -0
  9. data/LICENSE +199 -0
  10. data/README.md +380 -0
  11. data/Rakefile +109 -0
  12. data/examples/DNT.md +35 -0
  13. data/examples/carrying_context.rb +225 -0
  14. data/examples/instrumenting_metal_controller.rb +8 -0
  15. data/examples/puma_on_heroku_config.rb +17 -0
  16. data/examples/tracing_async_threads.rb +125 -0
  17. data/examples/tracing_background_jobs.rb +52 -0
  18. data/examples/tracing_forked_processes.rb +100 -0
  19. data/examples/unicorn_on_heroku_config.rb +28 -0
  20. data/ext/oboe_metal/extconf.rb +61 -0
  21. data/ext/oboe_metal/noop/noop.c +7 -0
  22. data/ext/oboe_metal/src/bson/bson.h +221 -0
  23. data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
  24. data/ext/oboe_metal/src/oboe.h +275 -0
  25. data/ext/oboe_metal/src/oboe.hpp +352 -0
  26. data/ext/oboe_metal/src/oboe_wrap.cxx +3886 -0
  27. data/ext/oboe_metal/tests/test.rb +11 -0
  28. data/gemfiles/mongo.gemfile +33 -0
  29. data/gemfiles/moped.gemfile +33 -0
  30. data/get_version.rb +5 -0
  31. data/init.rb +4 -0
  32. data/lib/joboe_metal.rb +206 -0
  33. data/lib/oboe/README +2 -0
  34. data/lib/oboe/backward_compatibility.rb +59 -0
  35. data/lib/oboe/inst/rack.rb +11 -0
  36. data/lib/oboe.rb +7 -0
  37. data/lib/oboe_metal.rb +151 -0
  38. data/lib/rails/generators/traceview/install_generator.rb +76 -0
  39. data/lib/rails/generators/traceview/templates/traceview_initializer.rb +159 -0
  40. data/lib/traceview/api/layerinit.rb +51 -0
  41. data/lib/traceview/api/logging.rb +209 -0
  42. data/lib/traceview/api/memcache.rb +31 -0
  43. data/lib/traceview/api/profiling.rb +50 -0
  44. data/lib/traceview/api/tracing.rb +135 -0
  45. data/lib/traceview/api/util.rb +121 -0
  46. data/lib/traceview/api.rb +18 -0
  47. data/lib/traceview/base.rb +225 -0
  48. data/lib/traceview/config.rb +238 -0
  49. data/lib/traceview/frameworks/grape.rb +97 -0
  50. data/lib/traceview/frameworks/padrino/templates.rb +58 -0
  51. data/lib/traceview/frameworks/padrino.rb +64 -0
  52. data/lib/traceview/frameworks/rails/helpers/rum/rum_ajax_header.js.erb +5 -0
  53. data/lib/traceview/frameworks/rails/helpers/rum/rum_footer.js.erb +1 -0
  54. data/lib/traceview/frameworks/rails/helpers/rum/rum_header.js.erb +3 -0
  55. data/lib/traceview/frameworks/rails/inst/action_controller.rb +216 -0
  56. data/lib/traceview/frameworks/rails/inst/action_view.rb +56 -0
  57. data/lib/traceview/frameworks/rails/inst/action_view_2x.rb +54 -0
  58. data/lib/traceview/frameworks/rails/inst/action_view_30.rb +48 -0
  59. data/lib/traceview/frameworks/rails/inst/active_record.rb +24 -0
  60. data/lib/traceview/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
  61. data/lib/traceview/frameworks/rails/inst/connection_adapters/mysql2.rb +28 -0
  62. data/lib/traceview/frameworks/rails/inst/connection_adapters/oracle.rb +18 -0
  63. data/lib/traceview/frameworks/rails/inst/connection_adapters/postgresql.rb +30 -0
  64. data/lib/traceview/frameworks/rails/inst/connection_adapters/utils.rb +117 -0
  65. data/lib/traceview/frameworks/rails.rb +145 -0
  66. data/lib/traceview/frameworks/sinatra/templates.rb +56 -0
  67. data/lib/traceview/frameworks/sinatra.rb +95 -0
  68. data/lib/traceview/inst/cassandra.rb +279 -0
  69. data/lib/traceview/inst/dalli.rb +86 -0
  70. data/lib/traceview/inst/em-http-request.rb +99 -0
  71. data/lib/traceview/inst/excon.rb +111 -0
  72. data/lib/traceview/inst/faraday.rb +73 -0
  73. data/lib/traceview/inst/http.rb +87 -0
  74. data/lib/traceview/inst/httpclient.rb +173 -0
  75. data/lib/traceview/inst/memcache.rb +102 -0
  76. data/lib/traceview/inst/memcached.rb +94 -0
  77. data/lib/traceview/inst/mongo.rb +238 -0
  78. data/lib/traceview/inst/moped.rb +474 -0
  79. data/lib/traceview/inst/rack.rb +122 -0
  80. data/lib/traceview/inst/redis.rb +271 -0
  81. data/lib/traceview/inst/resque.rb +192 -0
  82. data/lib/traceview/inst/rest-client.rb +38 -0
  83. data/lib/traceview/inst/sequel.rb +162 -0
  84. data/lib/traceview/inst/typhoeus.rb +102 -0
  85. data/lib/traceview/instrumentation.rb +21 -0
  86. data/lib/traceview/loading.rb +94 -0
  87. data/lib/traceview/logger.rb +41 -0
  88. data/lib/traceview/method_profiling.rb +84 -0
  89. data/lib/traceview/ruby.rb +36 -0
  90. data/lib/traceview/support.rb +113 -0
  91. data/lib/traceview/thread_local.rb +26 -0
  92. data/lib/traceview/util.rb +250 -0
  93. data/lib/traceview/version.rb +16 -0
  94. data/lib/traceview/xtrace.rb +90 -0
  95. data/lib/traceview.rb +62 -0
  96. data/test/frameworks/apps/grape_nested.rb +30 -0
  97. data/test/frameworks/apps/grape_simple.rb +24 -0
  98. data/test/frameworks/apps/padrino_simple.rb +45 -0
  99. data/test/frameworks/apps/sinatra_simple.rb +24 -0
  100. data/test/frameworks/grape_test.rb +142 -0
  101. data/test/frameworks/padrino_test.rb +30 -0
  102. data/test/frameworks/sinatra_test.rb +30 -0
  103. data/test/instrumentation/cassandra_test.rb +380 -0
  104. data/test/instrumentation/dalli_test.rb +171 -0
  105. data/test/instrumentation/em_http_request_test.rb +86 -0
  106. data/test/instrumentation/excon_test.rb +207 -0
  107. data/test/instrumentation/faraday_test.rb +235 -0
  108. data/test/instrumentation/http_test.rb +140 -0
  109. data/test/instrumentation/httpclient_test.rb +296 -0
  110. data/test/instrumentation/memcache_test.rb +251 -0
  111. data/test/instrumentation/memcached_test.rb +226 -0
  112. data/test/instrumentation/mongo_test.rb +462 -0
  113. data/test/instrumentation/moped_test.rb +496 -0
  114. data/test/instrumentation/rack_test.rb +116 -0
  115. data/test/instrumentation/redis_hashes_test.rb +265 -0
  116. data/test/instrumentation/redis_keys_test.rb +318 -0
  117. data/test/instrumentation/redis_lists_test.rb +310 -0
  118. data/test/instrumentation/redis_misc_test.rb +160 -0
  119. data/test/instrumentation/redis_sets_test.rb +293 -0
  120. data/test/instrumentation/redis_sortedsets_test.rb +325 -0
  121. data/test/instrumentation/redis_strings_test.rb +333 -0
  122. data/test/instrumentation/resque_test.rb +62 -0
  123. data/test/instrumentation/rest-client_test.rb +294 -0
  124. data/test/instrumentation/sequel_mysql2_test.rb +326 -0
  125. data/test/instrumentation/sequel_mysql_test.rb +326 -0
  126. data/test/instrumentation/sequel_pg_test.rb +330 -0
  127. data/test/instrumentation/typhoeus_test.rb +285 -0
  128. data/test/minitest_helper.rb +187 -0
  129. data/test/profiling/method_test.rb +198 -0
  130. data/test/servers/rackapp_8101.rb +22 -0
  131. data/test/support/backcompat_test.rb +269 -0
  132. data/test/support/config_test.rb +128 -0
  133. data/test/support/dnt_test.rb +73 -0
  134. data/test/support/liboboe_settings_test.rb +104 -0
  135. data/test/support/xtrace_test.rb +35 -0
  136. data/traceview.gemspec +29 -0
  137. metadata +248 -0
@@ -0,0 +1,250 @@
1
+ # Copyright (c) 2013 AppNeta, Inc.
2
+ # All rights reserved.
3
+
4
+ module TraceView
5
+ ##
6
+ # Provides utility methods for use while in the business
7
+ # of instrumenting code
8
+ module Util
9
+ class << self
10
+ def contextual_name(cls)
11
+ # Attempt to infer a contextual name if not indicated
12
+ #
13
+ # For example:
14
+ # ::ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.to_s.split(/::/).last
15
+ # => "AbstractMysqlAdapter"
16
+ #
17
+ cls.to_s.split(/::/).last
18
+ rescue
19
+ cls
20
+ end
21
+
22
+ ##
23
+ # method_alias
24
+ #
25
+ # Centralized utility method to alias a method on an arbitrary
26
+ # class or module.
27
+ #
28
+ def method_alias(cls, method, name = nil)
29
+ name ||= contextual_name(cls)
30
+
31
+ if cls.method_defined?(method.to_sym) || cls.private_method_defined?(method.to_sym)
32
+
33
+ # Strip '!' or '?' from method if present
34
+ safe_method_name = method.to_s.chop if method.to_s =~ /\?$|\!$/
35
+ safe_method_name ||= method
36
+
37
+ without_traceview = "#{safe_method_name}_without_traceview"
38
+ with_traceview = "#{safe_method_name}_with_traceview"
39
+
40
+ # Only alias if we haven't done so already
41
+ unless cls.method_defined?(without_traceview.to_sym) ||
42
+ cls.private_method_defined?(without_traceview.to_sym)
43
+
44
+ cls.class_eval do
45
+ alias_method without_traceview, "#{method}"
46
+ alias_method "#{method}", with_traceview
47
+ end
48
+ end
49
+ else
50
+ TraceView.logger.warn "[traceview/loading] Couldn't properly instrument #{name}.#{method}. Partial traces may occur."
51
+ end
52
+ end
53
+
54
+ ##
55
+ # class_method_alias
56
+ #
57
+ # Centralized utility method to alias a class method on an arbitrary
58
+ # class or module
59
+ #
60
+ def class_method_alias(cls, method, name = nil)
61
+ name ||= contextual_name(cls)
62
+
63
+ if cls.singleton_methods.include? method.to_sym
64
+
65
+ # Strip '!' or '?' from method if present
66
+ safe_method_name = method.to_s.chop if method.to_s =~ /\?$|\!$/
67
+ safe_method_name ||= method
68
+
69
+ without_traceview = "#{safe_method_name}_without_traceview"
70
+ with_traceview = "#{safe_method_name}_with_traceview"
71
+
72
+ # Only alias if we haven't done so already
73
+ unless cls.singleton_methods.include? without_traceview.to_sym
74
+ cls.singleton_class.send(:alias_method, without_traceview, "#{method}")
75
+ cls.singleton_class.send(:alias_method, "#{method}", with_traceview)
76
+ end
77
+ else TraceView.logger.warn "[traceview/loading] Couldn't properly instrument #{name}. Partial traces may occur."
78
+ end
79
+ end
80
+
81
+ ##
82
+ # send_extend
83
+ #
84
+ # Centralized utility method to send an extend call for an
85
+ # arbitrary class
86
+ def send_extend(target_cls, cls)
87
+ target_cls.send(:extend, cls) if defined?(target_cls)
88
+ end
89
+
90
+ ##
91
+ # send_include
92
+ #
93
+ # Centralized utility method to send a include call for an
94
+ # arbitrary class
95
+ def send_include(target_cls, cls)
96
+ target_cls.send(:include, cls) if defined?(target_cls)
97
+ end
98
+
99
+ ##
100
+ # static_asset?
101
+ #
102
+ # Given a path, this method determines whether it is a static asset or not (based
103
+ # solely on filename)
104
+ #
105
+ def static_asset?(path)
106
+ (path =~ Regexp.new(TraceView::Config[:dnt_regexp], TraceView::Config[:dnt_opts]))
107
+ end
108
+
109
+ ##
110
+ # prettify
111
+ #
112
+ # Even to my surprise, 'prettify' is a real word:
113
+ # transitive v. To make pretty or prettier, especially in a superficial or insubstantial way.
114
+ # from The American Heritage Dictionary of the English Language, 4th Edition
115
+ #
116
+ # This method makes things 'purty' for reporting.
117
+ def prettify(x)
118
+ if (x.to_s =~ /^#</) == 0
119
+ x.class.to_s
120
+ else
121
+ x.to_s
122
+ end
123
+ end
124
+
125
+ ##
126
+ # upcase
127
+ #
128
+ # Occasionally, we want to send some values in all caps. This is true
129
+ # for things like HTTP scheme or method. This takes anything and does
130
+ # it's best to safely convert it to a string (if needed) and convert it
131
+ # to all uppercase.
132
+ def upcase(o)
133
+ if o.is_a?(String) || o.respond_to?(:to_s)
134
+ o.to_s.upcase
135
+ else
136
+ TraceView.logger.debug "[traceview/debug] TraceView::Util.upcase: could not convert #{o.class}"
137
+ "UNKNOWN"
138
+ end
139
+ end
140
+
141
+
142
+ ##
143
+ # to_query
144
+ #
145
+ # Used under Ruby 1.8.7 to convert a hash into a URL
146
+ # query. A backport of Hash#to_query.
147
+ #
148
+ def to_query(h)
149
+ return "" unless h.is_a?(Hash)
150
+
151
+ # If called from a newer Ruby, use the builtin.
152
+ return h.to_query if RUBY_VERSION >= '1.9.3'
153
+
154
+ result = []
155
+
156
+ h.each { |k, v| result.push (k.to_s + '=' + v.to_s) }
157
+ return result.sort.join('&')
158
+ end
159
+
160
+ ##
161
+ # build_report
162
+ #
163
+ # Internal: Build a hash of KVs that reports on the status of the
164
+ # running environment. This is used on stack boot in __Init reporting
165
+ # and for TraceView.support_report.
166
+ def build_init_report
167
+ platform_info = { '__Init' => 1 }
168
+
169
+ begin
170
+ platform_info['Force'] = true
171
+ platform_info['Ruby.Platform.Version'] = RUBY_PLATFORM
172
+ platform_info['Ruby.Version'] = RUBY_VERSION
173
+ platform_info['Ruby.TraceView.Version'] = ::TraceView::Version::STRING
174
+ platform_info['RubyHeroku.TraceView.Version'] = ::TraceViewHeroku::Version::STRING if defined?(::TraceViewHeroku)
175
+ platform_info['Ruby.TraceMode.Version'] = ::TraceView::Config[:tracing_mode]
176
+
177
+ # Report the framework in use
178
+ if defined?(::RailsLts)
179
+ platform_info['Ruby.RailsLts.Version'] = "RailsLts-#{::RailsLts::VERSION}"
180
+ elsif defined?(::Rails)
181
+ platform_info['Ruby.Rails.Version'] = "Rails-#{::Rails.version}"
182
+ end
183
+ platform_info['Ruby.Grape.Version'] = "Grape-#{::Grape::VERSION}" if defined?(::Grape)
184
+ platform_info['Ruby.Cramp.Version'] = "Cramp-#{::Cramp::VERSION}" if defined?(::Cramp)
185
+
186
+ if defined?(::Padrino)
187
+ platform_info['Ruby.Padrino.Version'] = "Padrino-#{::Padrino::VERSION}"
188
+ elsif defined?(::Sinatra)
189
+ platform_info['Ruby.Sinatra.Version'] = "Sinatra-#{::Sinatra::VERSION}"
190
+ end
191
+
192
+ # Report the instrumented libraries
193
+ platform_info['Ruby.Cassandra.Version'] = "Cassandra-#{::Cassandra.VERSION}" if defined?(::Cassandra)
194
+ platform_info['Ruby.Dalli.Version'] = "Dalli-#{::Dalli::VERSION}" if defined?(::Dalli)
195
+ platform_info['Ruby.Excon.Version'] = "Excon-#{::Excon::VERSION}" if defined?(::Excon::VERSION)
196
+ platform_info['Ruby.Faraday.Version'] = "Faraday-#{::Faraday::VERSION}" if defined?(::Faraday)
197
+ platform_info['Ruby.HTTPClient.Version'] = "HTTPClient-#{::HTTPClient::VERSION}" if defined?(::HTTPClient::VERSION)
198
+ platform_info['Ruby.MemCache.Version'] = "MemCache-#{::MemCache::VERSION}" if defined?(::MemCache)
199
+ platform_info['Ruby.Moped.Version'] = "Moped-#{::Moped::VERSION}" if defined?(::Moped)
200
+ platform_info['Ruby.Redis.Version'] = "Redis-#{::Redis::VERSION}" if defined?(::Redis)
201
+ platform_info['Ruby.Resque.Version'] = "Resque-#{::Resque::VERSION}" if defined?(::Resque)
202
+ platform_info['Ruby.RestClient.Version'] = "RestClient-#{::RestClient::VERSION}" if defined?(::RestClient::VERSION)
203
+ platform_info['Ruby.Typhoeus.Version'] = "Typhoeus-#{::Typhoeus::VERSION}" if defined?(::Typhoeus::VERSION)
204
+
205
+ # Special case since the Mongo 1.x driver doesn't embed the version number in the gem directly
206
+ if ::Gem.loaded_specs.key?('mongo')
207
+ platform_info['Ruby.Mongo.Version'] = "Mongo-#{::Gem.loaded_specs['mongo'].version}"
208
+ end
209
+
210
+ # Report the DB adapter in use
211
+ platform_info['Ruby.Mysql.Version'] = Mysql::GemVersion::VERSION if defined?(Mysql::GemVersion::VERSION)
212
+ platform_info['Ruby.PG.Version'] = PG::VERSION if defined?(PG::VERSION)
213
+ platform_info['Ruby.Mysql2.Version'] = Mysql2::VERSION if defined?(Mysql2::VERSION)
214
+ platform_info['Ruby.Sequel.Version'] = ::Sequel::VERSION if defined?(::Sequel::VERSION)
215
+
216
+ # Report the server in use (if possible)
217
+ if defined?(::Unicorn)
218
+ platform_info['Ruby.AppContainer.Version'] = "Unicorn-#{::Unicorn::Const::UNICORN_VERSION}"
219
+ elsif defined?(::Puma)
220
+ platform_info['Ruby.AppContainer.Version'] = "Puma-#{::Puma::Const::PUMA_VERSION} (#{::Puma::Const::CODE_NAME})"
221
+ elsif defined?(::PhusionPassenger)
222
+ platform_info['Ruby.AppContainer.Version'] = "#{::PhusionPassenger::PACKAGE_NAME}-#{::PhusionPassenger::VERSION_STRING}"
223
+ elsif defined?(::Thin)
224
+ platform_info['Ruby.AppContainer.Version'] = "Thin-#{::Thin::VERSION::STRING} (#{::Thin::VERSION::CODENAME})"
225
+ elsif defined?(::Mongrel)
226
+ platform_info['Ruby.AppContainer.Version'] = "Mongrel-#{::Mongrel::Const::MONGREL_VERSION}"
227
+ elsif defined?(::Mongrel2)
228
+ platform_info['Ruby.AppContainer.Version'] = "Mongrel2-#{::Mongrel2::VERSION}"
229
+ elsif defined?(::Trinidad)
230
+ platform_info['Ruby.AppContainer.Version'] = "Trinidad-#{::Trinidad::VERSION}"
231
+ elsif defined?(::WEBrick::VERSION)
232
+ platform_info['Ruby.AppContainer.Version'] = "WEBrick-#{::WEBrick::VERSION}"
233
+ else
234
+ platform_info['Ruby.AppContainer.Version'] = File.basename($PROGRAM_NAME)
235
+ end
236
+
237
+ rescue StandardError, ScriptError => e
238
+ # Also rescue ScriptError (aka SyntaxError) in case one of the expected
239
+ # version defines don't exist
240
+
241
+ platform_info['Error'] = "Error in build_report: #{e.message}"
242
+
243
+ TraceView.logger.warn "[traceview/warn] Error in build_init_report: #{e.message}"
244
+ TraceView.logger.debug e.backtrace
245
+ end
246
+ platform_info
247
+ end
248
+ end
249
+ end
250
+ end
@@ -0,0 +1,16 @@
1
+ # Copyright (c) 2013 AppNeta, Inc.
2
+ # All rights reserved.
3
+
4
+ module TraceView
5
+ ##
6
+ # The current version of the gem. Used mainly by
7
+ # traceview.gemspec during gem build process
8
+ module Version
9
+ MAJOR = 3
10
+ MINOR = 0
11
+ PATCH = 0
12
+ BUILD = nil
13
+
14
+ STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.')
15
+ end
16
+ end
@@ -0,0 +1,90 @@
1
+ # Copyright (c) 2013 AppNeta, Inc.
2
+ # All rights reserved.
3
+
4
+ module TraceView
5
+ ##
6
+ # Methods to act on, manipulate or investigate an X-Trace
7
+ # value
8
+ module XTrace
9
+ class << self
10
+ ##
11
+ # TraceView::XTrace.valid?
12
+ #
13
+ # Perform basic validation on a potential X-Trace ID
14
+ #
15
+ def valid?(xtrace)
16
+ # Shouldn't be nil
17
+ return false unless xtrace
18
+
19
+ # The X-Trace ID shouldn't be an initialized empty ID
20
+ return false if (xtrace =~ /^1b0000000/i) == 0
21
+
22
+ # Valid X-Trace IDs have a length of 58 bytes and start with '1b'
23
+ return false unless xtrace.length == 58 && (xtrace =~ /^1b/i) == 0
24
+
25
+ true
26
+ rescue StandardError => e
27
+ TraceView.logger.debug e.message
28
+ TraceView.logger.debug e.backtrace
29
+ false
30
+ end
31
+
32
+ ##
33
+ # TraceView::XTrace.task_id
34
+ #
35
+ # Extract and return the task_id portion of an X-Trace ID
36
+ #
37
+ def task_id(xtrace)
38
+ return nil unless TraceView::XTrace.valid?(xtrace)
39
+
40
+ xtrace[2..41]
41
+ rescue StandardError => e
42
+ TraceView.logger.debug e.message
43
+ TraceView.logger.debug e.backtrace
44
+ return nil
45
+ end
46
+
47
+ ##
48
+ # TraceView::XTrace.edge_id
49
+ #
50
+ # Extract and return the edge_id portion of an X-Trace ID
51
+ #
52
+ def edge_id(xtrace)
53
+ return nil unless TraceView::XTrace.valid?(xtrace)
54
+
55
+ xtrace[42..57]
56
+ rescue StandardError => e
57
+ TraceView.logger.debug e.message
58
+ TraceView.logger.debug e.backtrace
59
+ return nil
60
+ end
61
+
62
+ ##
63
+ # continue_service_context
64
+ #
65
+ # In the case of service calls such as external HTTP requests, we
66
+ # pass along X-Trace headers so that request context can be maintained
67
+ # across servers and applications.
68
+ #
69
+ # Remote requests can return a X-Trace header in which case we want
70
+ # to pickup on and continue the context in most cases.
71
+ #
72
+ # @start is the context just before the outgoing request
73
+ #
74
+ # @finish is the context returned to us (as an HTTP response header
75
+ # if that be the case)
76
+ #
77
+ def continue_service_context(start, finish)
78
+ if TraceView::XTrace.valid?(finish) && TraceView.tracing?
79
+
80
+ # Assure that we received back a valid X-Trace with the same task_id
81
+ if TraceView::XTrace.task_id(start) == TraceView::XTrace.task_id(finish)
82
+ TraceView::Context.fromString(finish)
83
+ else
84
+ TraceView.logger.debug "Mismatched returned X-Trace ID: #{finish}"
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
data/lib/traceview.rb ADDED
@@ -0,0 +1,62 @@
1
+ # Copyright (c) 2013 AppNeta, Inc.
2
+ # All rights reserved.
3
+
4
+ # Backward compatibility for supported environment variables
5
+ ENV['TRACEVIEW_GEM_VERBOSE'] = ENV['OBOE_GEM_VERBOSE'] if ENV.key?('OBOE_GEM_VERBOSE')
6
+ ENV['TRACEVIEW_GEM_TEST'] = ENV['OBOE_GEM_TEST'] if ENV.key?('OBOE_GEM_TEST')
7
+
8
+ begin
9
+ require 'traceview/version'
10
+ require 'traceview/thread_local'
11
+ require 'traceview/logger'
12
+ require 'traceview/util'
13
+ require 'traceview/xtrace'
14
+ require 'traceview/support'
15
+
16
+ # If OboeHeroku is already defined then we are in a PaaS environment
17
+ # with an alternate metal (see the oboe-heroku gem)
18
+ unless defined?(OboeHeroku)
19
+ require 'traceview/base'
20
+
21
+ begin
22
+ if RUBY_PLATFORM == 'java'
23
+ require '/usr/local/tracelytics/tracelyticsagent.jar'
24
+ require 'joboe_metal'
25
+ else
26
+ require "oboe_metal.so"
27
+ require "oboe_metal.rb"
28
+ end
29
+ rescue LoadError
30
+ TraceView.loaded = false
31
+
32
+ unless ENV['RAILS_GROUP'] == 'assets' or ENV['IGNORE_TRACEVIEW_WARNING']
33
+ $stderr.puts '=============================================================='
34
+ $stderr.puts 'Missing TraceView libraries. Tracing disabled.'
35
+ $stderr.puts 'See: http://bit.ly/1DaNOjw'
36
+ $stderr.puts '=============================================================='
37
+ end
38
+ end
39
+ end
40
+
41
+ require 'traceview/config'
42
+ require 'traceview/loading'
43
+
44
+ if TraceView.loaded
45
+ require 'traceview/method_profiling'
46
+ require 'traceview/instrumentation'
47
+
48
+ # Frameworks
49
+ require 'traceview/frameworks/rails'
50
+ require 'traceview/frameworks/sinatra'
51
+ require 'traceview/frameworks/padrino'
52
+ require 'traceview/frameworks/grape'
53
+ end
54
+
55
+ # Load Ruby module last. If there is no framework detected,
56
+ # it will load all of the Ruby instrumentation
57
+ require 'traceview/ruby'
58
+ require 'oboe/backward_compatibility'
59
+ rescue => e
60
+ $stderr.puts "[traceview/error] Problem loading: #{e.inspect}"
61
+ $stderr.puts e.backtrace
62
+ end
@@ -0,0 +1,30 @@
1
+ require 'grape'
2
+
3
+ class Wrapper < Grape::API
4
+ class GrapeSimple < Grape::API
5
+ rescue_from :all do |e|
6
+ error_response({ message: "rescued from #{e.class.name}" })
7
+ end
8
+
9
+ get '/json_endpoint' do
10
+ present({ :test => true })
11
+ end
12
+
13
+ get "/break" do
14
+ raise Exception.new("This should have http status code 500!")
15
+ end
16
+
17
+ get "/error" do
18
+ error!("This is a error with 'error'!")
19
+ end
20
+
21
+ get "/breakstring" do
22
+ raise "This should have http status code 500!"
23
+ end
24
+ end
25
+ end
26
+
27
+ class GrapeNested < Grape::API
28
+ mount Wrapper::GrapeSimple
29
+ end
30
+
@@ -0,0 +1,24 @@
1
+ require 'grape'
2
+
3
+ class GrapeSimple < Grape::API
4
+ rescue_from :all do |e|
5
+ error_response({ message: "rescued from #{e.class.name}" })
6
+ end
7
+
8
+ get '/json_endpoint' do
9
+ present({ :test => true })
10
+ end
11
+
12
+ get "/break" do
13
+ raise Exception.new("This should have http status code 500!")
14
+ end
15
+
16
+ get "/error" do
17
+ error!("This is a error with 'error'!")
18
+ end
19
+
20
+ get "/breakstring" do
21
+ raise "This should have http status code 500!"
22
+ end
23
+ end
24
+
@@ -0,0 +1,45 @@
1
+ # This test Padrino stack file was taken from the padrino-core gem.
2
+ #
3
+ PADRINO_ROOT = File.dirname(__FILE__) unless defined? PADRINO_ROOT
4
+ # Remove this comment if you want do some like this: ruby PADRINO_ENV=test app.rb
5
+ #
6
+ # require 'rubygems'
7
+ # require 'padrino-core'
8
+ #
9
+
10
+ class SimpleDemo < Padrino::Application
11
+ set :public_folder, File.dirname(__FILE__)
12
+ set :reload, true
13
+ before { true }
14
+ after { true }
15
+ error(404) { "404" }
16
+ end
17
+
18
+ SimpleDemo.controllers do
19
+ get "/" do
20
+ 'The magick number is: 2767356926488785838763860464013972991031534522105386787489885890443740254365!' # Change only the number!!!
21
+ end
22
+
23
+ get "/rand" do
24
+ rand(2 ** 256).to_s
25
+ end
26
+
27
+ get "/render" do
28
+ render :erb, "This is an erb render"
29
+ end
30
+
31
+ get "/break" do
32
+ raise "This is a controller exception!"
33
+ end
34
+ end
35
+
36
+ ## If you want use this as a standalone app uncomment:
37
+ #
38
+ # Padrino.mount("SimpleDemo").to("/")
39
+ # Padrino.run! unless Padrino.loaded? # If you enable reloader prevent to re-run the app
40
+ #
41
+ # Then run it from your console: ruby -I"lib" test/fixtures/apps/simple.rb
42
+ #
43
+
44
+ Padrino.load!
45
+
@@ -0,0 +1,24 @@
1
+ require 'sinatra'
2
+
3
+ class SinatraSimple < Sinatra::Base
4
+ set :reload, true
5
+
6
+ get "/" do
7
+ 'The magick number is: 2767356926488785838763860464013972991031534522105386787489885890443740254365!' # Change only the number!!!
8
+ end
9
+
10
+ get "/rand" do
11
+ rand(2 ** 256).to_s
12
+ end
13
+
14
+ get "/render" do
15
+ render :erb, "This is an erb render"
16
+ end
17
+
18
+ get "/break" do
19
+ raise "This is a controller exception!"
20
+ end
21
+ end
22
+
23
+ use SinatraSimple
24
+
@@ -0,0 +1,142 @@
1
+ if RUBY_VERSION >= '1.9.3'
2
+ require 'minitest_helper'
3
+ require File.expand_path(File.dirname(__FILE__) + '/apps/grape_simple')
4
+ require File.expand_path(File.dirname(__FILE__) + '/apps/grape_nested')
5
+
6
+ describe Grape do
7
+ before do
8
+ clear_all_traces
9
+ end
10
+
11
+ it "should trace a request to a simple grape stack" do
12
+ @app = GrapeSimple
13
+
14
+ r = get "/json_endpoint"
15
+
16
+ r.status.must_equal 200
17
+ r.headers.key?('X-Trace').must_equal true
18
+
19
+ traces = get_all_traces
20
+ traces.count.must_equal 5
21
+
22
+ validate_outer_layers(traces, 'rack')
23
+
24
+ traces[2]['Layer'].must_equal "grape"
25
+ traces[3]['Layer'].must_equal "grape"
26
+ traces[3].has_key?('Controller').must_equal true
27
+ traces[3].has_key?('Action').must_equal true
28
+ traces[4]['Label'].must_equal "exit"
29
+
30
+ # Validate the existence of the response header
31
+ r.headers.key?('X-Trace').must_equal true
32
+ r.headers['X-Trace'].must_equal traces[4]['X-Trace']
33
+ end
34
+
35
+ it "should trace a request to a nested grape stack" do
36
+ @app = GrapeNested
37
+
38
+ r = get "/json_endpoint"
39
+
40
+ r.status.must_equal 200
41
+ r.headers.key?('X-Trace').must_equal true
42
+
43
+ traces = get_all_traces
44
+ traces.count.must_equal 5
45
+
46
+ validate_outer_layers(traces, 'rack')
47
+
48
+ traces[2]['Layer'].must_equal "grape"
49
+ traces[3]['Layer'].must_equal "grape"
50
+ traces[3].has_key?('Controller').must_equal true
51
+ traces[3].has_key?('Action').must_equal true
52
+ traces[4]['Label'].must_equal "exit"
53
+
54
+ # Validate the existence of the response header
55
+ r.headers.key?('X-Trace').must_equal true
56
+ r.headers['X-Trace'].must_equal traces[4]['X-Trace']
57
+ end
58
+
59
+ it "should trace a an error in a nested grape stack" do
60
+ @app = GrapeNested
61
+
62
+ r = get "/error"
63
+
64
+ r.status.must_equal 500
65
+ r.headers.key?('X-Trace').must_equal true
66
+
67
+ traces = get_all_traces
68
+ traces.count.must_equal 6
69
+
70
+ validate_outer_layers(traces, 'rack')
71
+
72
+ traces[2]['Layer'].must_equal "grape"
73
+ traces[2]['Label'].must_equal "entry"
74
+ traces[3]['Layer'].must_equal "grape"
75
+ traces[3]['Label'].must_equal "exit"
76
+ traces[3].has_key?('Controller').must_equal true
77
+ traces[3].has_key?('Action').must_equal true
78
+ traces[4]['Label'].must_equal "error"
79
+ traces[4]['ErrorClass'].must_equal "GrapeError"
80
+ traces[4]['ErrorMsg'].must_equal "This is a error with 'error'!"
81
+ traces[4].has_key?('Backtrace').must_equal true
82
+ traces[5]['Layer'].must_equal "rack"
83
+ traces[5]['Label'].must_equal "exit"
84
+
85
+ # Validate the existence of the response header
86
+ r.headers.key?('X-Trace').must_equal true
87
+ r.headers['X-Trace'].must_equal traces[5]['X-Trace']
88
+ end
89
+
90
+
91
+ it "should trace a request with an exception" do
92
+ @app = GrapeSimple
93
+
94
+ begin
95
+ r = get "/break"
96
+ rescue Exception => e
97
+ # Do not handle/raise this error so
98
+ # we can continue to test
99
+ end
100
+
101
+ traces = get_all_traces
102
+ traces.count.must_equal 6
103
+
104
+ validate_outer_layers(traces, 'rack')
105
+
106
+ traces[2]['Layer'].must_equal "grape"
107
+ traces[3]['Layer'].must_equal "grape"
108
+ traces[3].has_key?('Controller').must_equal true
109
+ traces[3].has_key?('Action').must_equal true
110
+ traces[4]['Label'].must_equal "error"
111
+ traces[4]['ErrorClass'].must_equal "Exception"
112
+ traces[4]['ErrorMsg'].must_equal "This should have http status code 500!"
113
+ traces[5]['Label'].must_equal "exit"
114
+ end
115
+
116
+ it "should trace a request with an error" do
117
+ @app = GrapeSimple
118
+
119
+ r = get "/error"
120
+
121
+ traces = get_all_traces
122
+ traces.count.must_equal 6
123
+
124
+ r.status.must_equal 500
125
+ r.headers.key?('X-Trace').must_equal true
126
+
127
+ validate_outer_layers(traces, 'rack')
128
+
129
+ traces[0]['Layer'].must_equal "rack"
130
+ traces[2]['Layer'].must_equal "grape"
131
+ traces[3]['Layer'].must_equal "grape"
132
+ traces[3].has_key?('Controller').must_equal true
133
+ traces[3].has_key?('Action').must_equal true
134
+ traces[4]['Label'].must_equal "error"
135
+ traces[4]['ErrorClass'].must_equal "GrapeError"
136
+ traces[4]['ErrorMsg'].must_equal "This is a error with 'error'!"
137
+ traces[5]['Layer'].must_equal "rack"
138
+ traces[5]['Label'].must_equal "exit"
139
+ traces[5]['Status'].must_equal 500
140
+ end
141
+ end
142
+ end