traceview 3.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 (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.rb +7 -0
  34. data/lib/oboe/README +2 -0
  35. data/lib/oboe/backward_compatibility.rb +59 -0
  36. data/lib/oboe/inst/rack.rb +11 -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.rb +62 -0
  41. data/lib/traceview/api.rb +18 -0
  42. data/lib/traceview/api/layerinit.rb +51 -0
  43. data/lib/traceview/api/logging.rb +209 -0
  44. data/lib/traceview/api/memcache.rb +31 -0
  45. data/lib/traceview/api/profiling.rb +50 -0
  46. data/lib/traceview/api/tracing.rb +135 -0
  47. data/lib/traceview/api/util.rb +121 -0
  48. data/lib/traceview/base.rb +225 -0
  49. data/lib/traceview/config.rb +238 -0
  50. data/lib/traceview/frameworks/grape.rb +97 -0
  51. data/lib/traceview/frameworks/padrino.rb +64 -0
  52. data/lib/traceview/frameworks/padrino/templates.rb +58 -0
  53. data/lib/traceview/frameworks/rails.rb +145 -0
  54. data/lib/traceview/frameworks/rails/helpers/rum/rum_ajax_header.js.erb +5 -0
  55. data/lib/traceview/frameworks/rails/helpers/rum/rum_footer.js.erb +1 -0
  56. data/lib/traceview/frameworks/rails/helpers/rum/rum_header.js.erb +3 -0
  57. data/lib/traceview/frameworks/rails/inst/action_controller.rb +216 -0
  58. data/lib/traceview/frameworks/rails/inst/action_view.rb +56 -0
  59. data/lib/traceview/frameworks/rails/inst/action_view_2x.rb +54 -0
  60. data/lib/traceview/frameworks/rails/inst/action_view_30.rb +48 -0
  61. data/lib/traceview/frameworks/rails/inst/active_record.rb +24 -0
  62. data/lib/traceview/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
  63. data/lib/traceview/frameworks/rails/inst/connection_adapters/mysql2.rb +28 -0
  64. data/lib/traceview/frameworks/rails/inst/connection_adapters/oracle.rb +18 -0
  65. data/lib/traceview/frameworks/rails/inst/connection_adapters/postgresql.rb +30 -0
  66. data/lib/traceview/frameworks/rails/inst/connection_adapters/utils.rb +117 -0
  67. data/lib/traceview/frameworks/sinatra.rb +95 -0
  68. data/lib/traceview/frameworks/sinatra/templates.rb +56 -0
  69. data/lib/traceview/inst/cassandra.rb +279 -0
  70. data/lib/traceview/inst/dalli.rb +86 -0
  71. data/lib/traceview/inst/em-http-request.rb +99 -0
  72. data/lib/traceview/inst/excon.rb +111 -0
  73. data/lib/traceview/inst/faraday.rb +73 -0
  74. data/lib/traceview/inst/http.rb +87 -0
  75. data/lib/traceview/inst/httpclient.rb +173 -0
  76. data/lib/traceview/inst/memcache.rb +102 -0
  77. data/lib/traceview/inst/memcached.rb +94 -0
  78. data/lib/traceview/inst/mongo.rb +238 -0
  79. data/lib/traceview/inst/moped.rb +474 -0
  80. data/lib/traceview/inst/rack.rb +122 -0
  81. data/lib/traceview/inst/redis.rb +271 -0
  82. data/lib/traceview/inst/resque.rb +192 -0
  83. data/lib/traceview/inst/rest-client.rb +38 -0
  84. data/lib/traceview/inst/sequel.rb +162 -0
  85. data/lib/traceview/inst/typhoeus.rb +102 -0
  86. data/lib/traceview/instrumentation.rb +21 -0
  87. data/lib/traceview/loading.rb +94 -0
  88. data/lib/traceview/logger.rb +41 -0
  89. data/lib/traceview/method_profiling.rb +84 -0
  90. data/lib/traceview/ruby.rb +36 -0
  91. data/lib/traceview/support.rb +113 -0
  92. data/lib/traceview/thread_local.rb +26 -0
  93. data/lib/traceview/util.rb +250 -0
  94. data/lib/traceview/version.rb +16 -0
  95. data/lib/traceview/xtrace.rb +90 -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 +250 -0
@@ -0,0 +1,84 @@
1
+ # Copyright (c) 2013 AppNeta, Inc.
2
+ # All rights reserved.
3
+
4
+ ##
5
+ # Provides the methods necessary for method profiling. Profiling
6
+ # results are sent to the TraceView dashboard.
7
+ #
8
+ # Example usage:
9
+ # class MyApp
10
+ # include TraceViewMethodProfiling
11
+ #
12
+ # def process_request()
13
+ # # The hard work
14
+ # end
15
+ #
16
+ # # call syntax: profile_method <method>, <profile_name>
17
+ # profile_method :process_request, 'request_processor'
18
+ # end
19
+ module TraceViewMethodProfiling
20
+ def self.included(klass)
21
+ klass.extend ClassMethods
22
+ end
23
+
24
+ module ClassMethods
25
+ def profile_method(method_name, profile_name, store_args = false, store_return = false, *_)
26
+ begin
27
+ # this only gets file and line where profiling is turned on, presumably
28
+ # right after the function definition. ruby 1.9 and 2.0 has nice introspection (Method.source_location)
29
+ # but its appears no such luck for ruby 1.8
30
+ file = ''
31
+ line = ''
32
+ if RUBY_VERSION >= '1.9'
33
+ info = instance_method(method_name).source_location
34
+ unless info.nil?
35
+ file = info[0].to_s
36
+ line = info[1].to_s
37
+ end
38
+ else
39
+ info = Kernel.caller[0].split(':')
40
+ file = info.first.to_s
41
+ line = info.last.to_s
42
+ end
43
+
44
+ # Safety: Make sure there are no quotes or double quotes to break the class_eval
45
+ file = file.gsub(/[\'\"]/, '')
46
+ line = line.gsub(/[\'\"]/, '')
47
+
48
+ # profiling via ruby-prof, is it possible to get return value of profiled code?
49
+ code = "def _traceview_profiled_#{method_name}(*args, &block)
50
+ entry_kvs = {}
51
+ entry_kvs['Language'] = 'ruby'
52
+ entry_kvs['ProfileName'] = '#{TraceView::Util.prettify(profile_name)}'
53
+ entry_kvs['FunctionName'] = '#{TraceView::Util.prettify(method_name)}'
54
+ entry_kvs['File'] = '#{file}'
55
+ entry_kvs['LineNumber'] = '#{line}'
56
+ entry_kvs['Args'] = TraceView::API.pps(*args) if #{store_args}
57
+ entry_kvs.merge!(::TraceView::API.get_class_name(self))
58
+
59
+ TraceView::API.log(nil, 'profile_entry', entry_kvs)
60
+
61
+ ret = _traceview_orig_#{method_name}(*args, &block)
62
+
63
+ exit_kvs = {}
64
+ exit_kvs['Language'] = 'ruby'
65
+ exit_kvs['ProfileName'] = '#{TraceView::Util.prettify(profile_name)}'
66
+ exit_kvs['ReturnValue'] = TraceView::API.pps(ret) if #{store_return}
67
+
68
+ TraceView::API.log(nil, 'profile_exit', exit_kvs)
69
+ ret
70
+ end"
71
+ rescue => e
72
+ TraceView.logger.warn "[traceview/warn] profile_method: #{e.inspect}"
73
+ end
74
+
75
+ begin
76
+ class_eval code, __FILE__, __LINE__
77
+ alias_method "_traceview_orig_#{method_name}", method_name
78
+ alias_method method_name, "_traceview_profiled_#{method_name}"
79
+ rescue => e
80
+ TraceView.logger.warn "[traceview/warn] Fatal error profiling method (#{method_name}): #{e.inspect}" if TraceView::Config[:verbose]
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,36 @@
1
+ # Copyright (c) 2013 AppNeta, Inc.
2
+ # All rights reserved.
3
+
4
+ module TraceView
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 TraceView.loaded
26
+ TraceView::Loading.load_access_key
27
+ TraceView::Inst.load_instrumentation
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ if TraceView.loaded and !TraceView.framework?
35
+ ::TraceView::Ruby.load
36
+ end
@@ -0,0 +1,113 @@
1
+ # Copyright (c) 2014 AppNeta, Inc.
2
+ # All rights reserved.
3
+
4
+ require 'rbconfig'
5
+
6
+ module TraceView
7
+ ##
8
+ # This module is used to debug problematic setups and/or environments.
9
+ # Depending on the environment, output may be to stdout or the framework
10
+ # log file (e.g. log/production.log)
11
+
12
+ ##
13
+ # yesno
14
+ #
15
+ # Utility method to translate value/nil to "yes"/"no" strings
16
+ def self.yesno(x)
17
+ x ? "yes" : "no"
18
+ end
19
+
20
+ def self.support_report
21
+ TraceView.logger.warn "********************************************************"
22
+ TraceView.logger.warn "* BEGIN TraceView Support Report"
23
+ TraceView.logger.warn "* Please email the output of this report to traceviewsupport@appneta.com"
24
+ TraceView.logger.warn "********************************************************"
25
+ TraceView.logger.warn "Ruby: #{RUBY_DESCRIPTION}"
26
+ TraceView.logger.warn "$0: #{$0}"
27
+ TraceView.logger.warn "$1: #{$1}" unless $1.nil?
28
+ TraceView.logger.warn "$2: #{$2}" unless $2.nil?
29
+ TraceView.logger.warn "$3: #{$3}" unless $3.nil?
30
+ TraceView.logger.warn "$4: #{$4}" unless $4.nil?
31
+ TraceView.logger.warn "TraceView.loaded == #{TraceView.loaded}"
32
+
33
+ using_jruby = defined?(JRUBY_VERSION)
34
+ TraceView.logger.warn "Using JRuby?: #{yesno(using_jruby)}"
35
+ if using_jruby
36
+ TraceView.logger.warn "Jtraceview Agent Status: #{Java::ComTracelyticsAgent::Agent.getStatus}"
37
+ end
38
+
39
+ on_heroku = TraceView.heroku?
40
+ TraceView.logger.warn "On Heroku?: #{yesno(on_heroku)}"
41
+ if on_heroku
42
+ TraceView.logger.warn "TRACEVIEW_URL: #{ENV['TRACEVIEW_URL']}"
43
+ end
44
+
45
+ TraceView.logger.warn "TraceView::Ruby defined?: #{yesno(defined?(TraceView::Ruby))}"
46
+ TraceView.logger.warn "TraceView.reporter: #{TraceView.reporter}"
47
+
48
+ TraceView.logger.warn "********************************************************"
49
+ TraceView.logger.warn "* Frameworks"
50
+ TraceView.logger.warn "********************************************************"
51
+
52
+ using_rails = defined?(::Rails)
53
+ TraceView.logger.warn "Using Rails?: #{yesno(using_rails)}"
54
+ if using_rails
55
+ TraceView.logger.warn "TraceView::Rails loaded?: #{yesno(defined?(::TraceView::Rails))}"
56
+ end
57
+
58
+ using_sinatra = defined?(::Sinatra)
59
+ TraceView.logger.warn "Using Sinatra?: #{yesno(using_sinatra)}"
60
+
61
+ using_padrino = defined?(::Padrino)
62
+ TraceView.logger.warn "Using Padrino?: #{yesno(using_padrino)}"
63
+
64
+ using_grape = defined?(::Grape)
65
+ TraceView.logger.warn "Using Grape?: #{yesno(using_grape)}"
66
+
67
+ TraceView.logger.warn "********************************************************"
68
+ TraceView.logger.warn "* TraceView Libraries"
69
+ TraceView.logger.warn "********************************************************"
70
+ files = Dir.glob('/usr/lib/liboboe*')
71
+ if files.empty?
72
+ TraceView.logger.warn "Error: No liboboe libs!"
73
+ else
74
+ files.each { |f|
75
+ TraceView.logger.warn f
76
+ }
77
+ end
78
+
79
+ TraceView.logger.warn "********************************************************"
80
+ TraceView.logger.warn "* TraceView::Config Values"
81
+ TraceView.logger.warn "********************************************************"
82
+ TraceView::Config.show.each { |k,v|
83
+ TraceView.logger.warn "#{k}: #{v}"
84
+ }
85
+
86
+ TraceView.logger.warn "********************************************************"
87
+ TraceView.logger.warn "* OS, Platform + Env"
88
+ TraceView.logger.warn "********************************************************"
89
+ TraceView.logger.warn RbConfig::CONFIG['host_os']
90
+ TraceView.logger.warn RbConfig::CONFIG['sitearch']
91
+ TraceView.logger.warn RbConfig::CONFIG['arch']
92
+ TraceView.logger.warn RUBY_PLATFORM
93
+ TraceView.logger.warn "RACK_ENV: #{ENV['RACK_ENV']}"
94
+ TraceView.logger.warn "RAILS_ENV: #{ENV['RAILS_ENV']}" if using_rails
95
+
96
+ TraceView.logger.warn "********************************************************"
97
+ TraceView.logger.warn "* Raw __Init KVs"
98
+ TraceView.logger.warn "********************************************************"
99
+ platform_info = TraceView::Util.build_init_report
100
+ platform_info.each { |k,v|
101
+ TraceView.logger.warn "#{k}: #{v}"
102
+ }
103
+
104
+ TraceView.logger.warn "********************************************************"
105
+ TraceView.logger.warn "* END TraceView Support Report"
106
+ TraceView.logger.warn "* Support Email: traceviewsupport@appneta.com"
107
+ TraceView.logger.warn "* Support Portal: https://support.tv.appneta.com"
108
+ TraceView.logger.warn "* Freenode IRC: #appneta"
109
+ TraceView.logger.warn "* Github: https://github.com/appneta/traceview-ruby"
110
+ TraceView.logger.warn "********************************************************"
111
+ nil
112
+ end
113
+ end
@@ -0,0 +1,26 @@
1
+ # Copyright (c) 2014 AppNeta, Inc.
2
+ # All rights reserved.
3
+
4
+ module TraceView
5
+ ##
6
+ # Provides thread local storage for TraceView.
7
+ #
8
+ # Example usage:
9
+ # module TraceViewBase
10
+ # extend ::TraceView::ThreadLocal
11
+ # thread_local :layer_op
12
+ # end
13
+ module ThreadLocal
14
+ def thread_local(name)
15
+ key = "__#{self}_#{name}__".intern
16
+
17
+ define_method(name) do
18
+ Thread.current[key]
19
+ end
20
+
21
+ define_method(name.to_s + '=') do |value|
22
+ Thread.current[key] = value
23
+ end
24
+ end
25
+ end
26
+ end
@@ -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