traceview 3.1.0-java → 3.2.1-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7ab475ce550edae53924cbe72eaf7b93e337df71
4
- data.tar.gz: 12ee03213258aa59f4fd7641247db417833cde06
3
+ metadata.gz: 96c087aab94a58d443be7e150a674f72cffbf110
4
+ data.tar.gz: 08616ab412adefe991cc489aecb9c960c64dc8db
5
5
  SHA512:
6
- metadata.gz: c3f934605ce6a37c9e5b11d6d9490a01c279b104b6a4fe055bc8db4f76d63bf95df4591081b81534d8505d4c2fc2b5bffab4227bb1b6340253df5c03a6742943
7
- data.tar.gz: c4a2ea84c0a5e861f7878304fb59aa66d3f9f47165bc909dd25ff95c74f745cd72984473d6e5955f8f3ceb9357a16a2b9f48715bd461bbe3ea546e62a33e8a20
6
+ metadata.gz: 8f950a8ad1c44cf89064f94c4eb17b26020a74e2c1156af6e4cb8cfc1c80612e0e96aefb4576bcff8ffab3908e0358a0c2d3edd0338c69cc2fd44215e6b0100d
7
+ data.tar.gz: 311bb5d286c6eef95149a6807f81334117a727ab1d440c773442c6d7c6ce6e8e647bfad93742b2ac1e227245b6d2aba988533d279404eabbf9482c9c91b66690
data/.travis.yml CHANGED
@@ -63,8 +63,8 @@ before_install:
63
63
  - sudo service cassandra start
64
64
 
65
65
  install:
66
- - wget https://www.tracelytics.com/install_tracelytics.sh
67
- - sudo sh ./install_tracelytics.sh f51e2a43-0ee5-4851-8a54-825773b3218e
66
+ - wget https://files.appneta.com/install_appneta.sh
67
+ - sudo sh ./install_appneta.sh f51e2a43-0ee5-4851-8a54-825773b3218e
68
68
  - sudo apt-get install -y tracelytics-java-agent
69
69
 
70
70
  before_script:
data/CHANGELOG.md CHANGED
@@ -4,6 +4,18 @@ https://github.com/appneta/oboe-ruby/releases
4
4
 
5
5
  Dates in this file are in the format MM/DD/YYYY.
6
6
 
7
+ # traceview 3.2.0
8
+
9
+ This minor release adds the following:
10
+
11
+ * New and improved method profiling: #135
12
+ * Fix URL Query config: #136
13
+
14
+ Pushed to Rubygems:
15
+
16
+ https://rubygems.org/gems/traceview/versions/3.2.0
17
+ https://rubygems.org/gems/traceview/versions/3.2.0-java
18
+
7
19
  # traceview 3.1.0
8
20
 
9
21
  This minor release adds the following:
data/lib/traceview.rb CHANGED
@@ -40,6 +40,7 @@ begin
40
40
 
41
41
  require 'traceview/config'
42
42
  require 'traceview/loading'
43
+ require 'traceview/legacy_method_profiling'
43
44
  require 'traceview/method_profiling'
44
45
 
45
46
  if TraceView.loaded
@@ -45,6 +45,152 @@ module TraceView
45
45
  TraceView::API.log(nil, 'profile_exit', exit_kvs)
46
46
  end
47
47
  end
48
+
49
+ ##
50
+ # Public: Profile a method on a class or module. That method can be of any (accessible)
51
+ # type (instance, singleton, private, protected etc.).
52
+ #
53
+ # klass - the class or module that has the method to profile
54
+ # method - the method to profile. Can be singleton, instance, private etc...
55
+ # opts - a hash specifying the one or more of the following options:
56
+ # * :arguments - report the arguments passed to <tt>method</tt> on each profile (default: false)
57
+ # * :result - report the return value of <tt>method</tt> on each profile (default: false)
58
+ # * :backtrace - report the return value of <tt>method</tt> on each profile (default: false)
59
+ # * :name - alternate name for the profile reported in the dashboard (default: method name)
60
+ # extra_kvs - a hash containing any additional KVs you would like reported with the profile
61
+ #
62
+ # Example
63
+ #
64
+ # opts = {}
65
+ # opts[:backtrace] = true
66
+ # opts[:arguments] = false
67
+ # opts[:name] = :array_sort
68
+ #
69
+ # TraceView::API.profile_method(Array, :sort, opts)
70
+ #
71
+ def profile_method(klass, method, opts = {}, extra_kvs = {})
72
+
73
+ # If we're on an unsupported platform (ahem Mac), just act
74
+ # like we did something to nicely play the no-op part.
75
+ return true unless TraceView.loaded
76
+
77
+ if RUBY_VERSION < '1.9.3'
78
+ TraceView.logger.warn "[traceview/error] profile_method: Use the legacy method profiling for Ruby versions before 1.9.3"
79
+ return false
80
+
81
+ elsif !klass.is_a?(Module)
82
+ TraceView.logger.warn "[traceview/error] profile_method: Not sure what to do with #{klass}. Send a class or module."
83
+ return false
84
+
85
+ elsif !method.is_a?(Symbol)
86
+ if method.is_a?(String)
87
+ method = method.to_sym
88
+ else
89
+ TraceView.logger.warn "[traceview/error] profile_method: Not sure what to do with #{method}. Send a string or symbol for method."
90
+ return false
91
+ end
92
+ end
93
+
94
+ instance_method = klass.instance_methods.include?(method) || klass.private_instance_methods.include?(method)
95
+ class_method = klass.singleton_methods.include?(method)
96
+
97
+ # Make sure the request klass::method exists
98
+ if !instance_method && !class_method
99
+ TraceView.logger.warn "[traceview/error] profile_method: Can't instrument #{klass}.#{method} as it doesn't seem to exist."
100
+ TraceView.logger.warn "[traceview/error] #{__FILE__}:#{__LINE__}"
101
+ return false
102
+ end
103
+
104
+ # Strip '!' or '?' from method if present
105
+ safe_method_name = method.to_s.chop if method.to_s =~ /\?$|\!$/
106
+ safe_method_name ||= method
107
+
108
+ without_traceview = "#{safe_method_name}_without_traceview"
109
+ with_traceview = "#{safe_method_name}_with_traceview"
110
+
111
+ # Check if already profiled
112
+ if klass.instance_methods.include?(with_traceview.to_sym) ||
113
+ klass.singleton_methods.include?(with_traceview.to_sym)
114
+ TraceView.logger.warn "[traceview/error] profile_method: #{klass}::#{method} already profiled."
115
+ TraceView.logger.warn "[traceview/error] profile_method: #{__FILE__}:#{__LINE__}"
116
+ return false
117
+ end
118
+
119
+ source_location = []
120
+ if instance_method
121
+ ::TraceView::Util.send_include(klass, ::TraceView::MethodProfiling)
122
+ source_location = klass.instance_method(method).source_location
123
+ elsif class_method
124
+ ::TraceView::Util.send_extend(klass, ::TraceView::MethodProfiling)
125
+ source_location = klass.method(method).source_location
126
+ end
127
+
128
+ report_kvs = collect_profile_kvs(klass, method, opts, extra_kvs, source_location)
129
+ report_kvs[:MethodName] = safe_method_name
130
+
131
+ if instance_method
132
+ klass.class_eval do
133
+ define_method(with_traceview) { | *args, &block |
134
+ profile_wrapper(without_traceview, report_kvs, opts, *args, &block)
135
+ }
136
+
137
+ alias_method without_traceview, "#{method}"
138
+ alias_method "#{method}", with_traceview
139
+ end
140
+ elsif class_method
141
+ klass.define_singleton_method(with_traceview) { | *args, &block |
142
+ profile_wrapper(without_traceview, report_kvs, opts, *args, &block)
143
+ }
144
+
145
+ klass.singleton_class.class_eval do
146
+ alias_method without_traceview, "#{method}"
147
+ alias_method "#{method}", with_traceview
148
+ end
149
+ end
150
+ true
151
+ end
152
+
153
+ private
154
+
155
+ ##
156
+ # Private: Helper method to aggregate KVs to report
157
+ #
158
+ # klass - the class or module that has the method to profile
159
+ # method - the method to profile. Can be singleton, instance, private etc...
160
+ # opts - a hash specifying the one or more of the following options:
161
+ # * :arguments - report the arguments passed to <tt>method</tt> on each profile (default: false)
162
+ # * :result - report the return value of <tt>method</tt> on each profile (default: false)
163
+ # * :backtrace - report the return value of <tt>method</tt> on each profile (default: false)
164
+ # * :name - alternate name for the profile reported in the dashboard (default: method name)
165
+ # extra_kvs - a hash containing any additional KVs you would like reported with the profile
166
+ # source_location - array returned from klass.method(:name).source_location
167
+ #
168
+ def collect_profile_kvs(klass, method, opts, extra_kvs, source_location)
169
+ report_kvs = {}
170
+ report_kvs[:Language] ||= :ruby
171
+ report_kvs[:ProfileName] ||= opts[:name] ? opts[:name] : method
172
+
173
+ if klass.is_a?(Class)
174
+ report_kvs[:Class] = klass.to_s
175
+ else
176
+ report_kvs[:Module] = klass.to_s
177
+ end
178
+
179
+ # If this is a Rails Controller, report the KVs
180
+ if defined?(::AbstractController::Base) && klass.ancestors.include?(::AbstractController::Base)
181
+ report_kvs[:Controller] = klass.to_s
182
+ report_kvs[:Action] = method.to_s
183
+ end
184
+
185
+ # We won't have access to this info for native methods (those not defined in Ruby).
186
+ if source_location.is_a?(Array) && source_location.length == 2
187
+ report_kvs[:File] = source_location[0]
188
+ report_kvs[:LineNumber] = source_location[1]
189
+ end
190
+
191
+ # Merge in any extra_kvs requested
192
+ report_kvs.merge!(extra_kvs)
193
+ end
48
194
  end
49
195
  end
50
196
  end
@@ -22,15 +22,16 @@ module TraceView
22
22
 
23
23
  # Internal: Get the current backtrace.
24
24
  #
25
- # ignore - Number of frames to ignore at the end of the backtrace. Use
26
- # when you know how many layers deep in oboe the call is being
25
+ # ignore - Number of frames to ignore at the top of the backtrace. Use
26
+ # when you know how many layers deep in the key call is being
27
27
  # made.
28
28
  #
29
29
  # Returns a string with each frame of the backtrace separated by '\r\n'.
30
30
  #
31
- # FIXME: ignore is not currently used (see BACKTRACE_CUTOFF)
32
- def backtrace(_ignore = 1)
33
- trim_backtrace(Kernel.caller).join("\r\n")
31
+ def backtrace(ignore = 0)
32
+ bt = Kernel.caller
33
+ bt.slice!(0, ignore)
34
+ trim_backtrace(bt).join("\r\n")
34
35
  end
35
36
 
36
37
  # Internal: Trim a backtrace to a manageable size
@@ -168,9 +168,8 @@ module TraceViewBase
168
168
  # False otherwise
169
169
  #
170
170
  def tracing?
171
- return false unless TraceView.loaded
172
-
173
- TraceView::Context.isValid && !TraceView.never?
171
+ return false if !TraceView.loaded || TraceView.never?
172
+ TraceView::Context.isValid
174
173
  end
175
174
 
176
175
  def log(layer, label, options = {})
@@ -18,7 +18,7 @@ module TraceView
18
18
  :typhoeus]
19
19
 
20
20
  # Subgrouping of instrumentation
21
- @@http_clients = [:curb, :excon, :faraday, :httpclient, :nethttp, :rest_client, :typhoeus]
21
+ @@http_clients = [:curb, :excon, :em_http_request, :faraday, :httpclient, :nethttp, :rest_client, :typhoeus]
22
22
 
23
23
  ##
24
24
  # Return the raw nested hash.
@@ -217,14 +217,14 @@ module TraceView
217
217
  elsif key == :include_url_query_params
218
218
  # Obey the global flag and update all of the per instrumentation
219
219
  # <tt>:log_args</tt> values.
220
- @@http_clients.each do |i|
221
- @@config[i][:log_args] = value
222
- end
220
+ @@config[:rack][:log_args] = value
223
221
 
224
222
  elsif key == :include_remote_url_params
225
223
  # Obey the global flag and update all of the per instrumentation
226
224
  # <tt>:log_args</tt> values.
227
- @@config[:rack][:log_args] = value
225
+ @@http_clients.each do |i|
226
+ @@config[i][:log_args] = value
227
+ end
228
228
  end
229
229
 
230
230
  # Update liboboe if updating :tracing_mode
@@ -0,0 +1,97 @@
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_noop(*args)
26
+ nil
27
+ end
28
+
29
+ def profile_method_real(method_name, profile_name, store_args = false, store_return = false, *_)
30
+ begin
31
+ # this only gets file and line where profiling is turned on, presumably
32
+ # right after the function definition. ruby 1.9 and 2.0 has nice introspection (Method.source_location)
33
+ # but its appears no such luck for ruby 1.8
34
+ file = ''
35
+ line = ''
36
+ if RUBY_VERSION >= '1.9'
37
+ info = instance_method(method_name).source_location
38
+ unless info.nil?
39
+ file = info[0].to_s
40
+ line = info[1].to_s
41
+ end
42
+ else
43
+ info = Kernel.caller[0].split(':')
44
+ file = info.first.to_s
45
+ line = info.last.to_s
46
+ end
47
+
48
+ # Safety: Make sure there are no quotes or double quotes to break the class_eval
49
+ file = file.gsub(/[\'\"]/, '')
50
+ line = line.gsub(/[\'\"]/, '')
51
+
52
+ # profiling via ruby-prof, is it possible to get return value of profiled code?
53
+ code = "def _traceview_profiled_#{method_name}(*args, &block)
54
+ entry_kvs = {}
55
+ entry_kvs['Language'] = 'ruby'
56
+ entry_kvs['ProfileName'] = '#{TraceView::Util.prettify(profile_name)}'
57
+ entry_kvs['FunctionName'] = '#{TraceView::Util.prettify(method_name)}'
58
+ entry_kvs['File'] = '#{file}'
59
+ entry_kvs['LineNumber'] = '#{line}'
60
+ entry_kvs['Args'] = TraceView::API.pps(*args) if #{store_args}
61
+ entry_kvs.merge!(::TraceView::API.get_class_name(self))
62
+
63
+ TraceView::API.log(nil, 'profile_entry', entry_kvs)
64
+
65
+ ret = _traceview_orig_#{method_name}(*args, &block)
66
+
67
+ exit_kvs = {}
68
+ exit_kvs['Language'] = 'ruby'
69
+ exit_kvs['ProfileName'] = '#{TraceView::Util.prettify(profile_name)}'
70
+ exit_kvs['ReturnValue'] = TraceView::API.pps(ret) if #{store_return}
71
+
72
+ TraceView::API.log(nil, 'profile_exit', exit_kvs)
73
+ ret
74
+ end"
75
+ rescue => e
76
+ TraceView.logger.warn "[traceview/warn] profile_method: #{e.inspect}"
77
+ end
78
+
79
+ begin
80
+ class_eval code, __FILE__, __LINE__
81
+ alias_method "_traceview_orig_#{method_name}", method_name
82
+ alias_method method_name, "_traceview_profiled_#{method_name}"
83
+ rescue => e
84
+ TraceView.logger.warn "[traceview/warn] Fatal error profiling method (#{method_name}): #{e.inspect}" if TraceView::Config[:verbose]
85
+ end
86
+ end
87
+
88
+ # This allows this module to be included and called even if the gem is in
89
+ # no-op mode (no base libraries).
90
+ if TraceView.loaded
91
+ alias :profile_method :profile_method_real
92
+ else
93
+ alias :profile_method :profile_method_noop
94
+ end
95
+
96
+ end
97
+ end
@@ -1,97 +1,25 @@
1
- # Copyright (c) 2013 AppNeta, Inc.
2
- # All rights reserved.
3
1
 
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
2
+ module TraceView
3
+ module MethodProfiling
4
+ def profile_wrapper(method, report_kvs, opts, *args, &block)
5
+ report_kvs[:Backtrace] = TraceView::API.backtrace(2) if opts[:backtrace]
6
+ report_kvs[:Arguments] = args if opts[:arguments]
23
7
 
24
- module ClassMethods
25
- def profile_method_noop(*args)
26
- nil
27
- end
8
+ TraceView::API.log(nil, 'profile_entry', report_kvs)
28
9
 
29
- def profile_method_real(method_name, profile_name, store_args = false, store_return = false, *_)
30
10
  begin
31
- # this only gets file and line where profiling is turned on, presumably
32
- # right after the function definition. ruby 1.9 and 2.0 has nice introspection (Method.source_location)
33
- # but its appears no such luck for ruby 1.8
34
- file = ''
35
- line = ''
36
- if RUBY_VERSION >= '1.9'
37
- info = instance_method(method_name).source_location
38
- unless info.nil?
39
- file = info[0].to_s
40
- line = info[1].to_s
41
- end
42
- else
43
- info = Kernel.caller[0].split(':')
44
- file = info.first.to_s
45
- line = info.last.to_s
46
- end
47
-
48
- # Safety: Make sure there are no quotes or double quotes to break the class_eval
49
- file = file.gsub(/[\'\"]/, '')
50
- line = line.gsub(/[\'\"]/, '')
51
-
52
- # profiling via ruby-prof, is it possible to get return value of profiled code?
53
- code = "def _traceview_profiled_#{method_name}(*args, &block)
54
- entry_kvs = {}
55
- entry_kvs['Language'] = 'ruby'
56
- entry_kvs['ProfileName'] = '#{TraceView::Util.prettify(profile_name)}'
57
- entry_kvs['FunctionName'] = '#{TraceView::Util.prettify(method_name)}'
58
- entry_kvs['File'] = '#{file}'
59
- entry_kvs['LineNumber'] = '#{line}'
60
- entry_kvs['Args'] = TraceView::API.pps(*args) if #{store_args}
61
- entry_kvs.merge!(::TraceView::API.get_class_name(self))
62
-
63
- TraceView::API.log(nil, 'profile_entry', entry_kvs)
64
-
65
- ret = _traceview_orig_#{method_name}(*args, &block)
66
-
67
- exit_kvs = {}
68
- exit_kvs['Language'] = 'ruby'
69
- exit_kvs['ProfileName'] = '#{TraceView::Util.prettify(profile_name)}'
70
- exit_kvs['ReturnValue'] = TraceView::API.pps(ret) if #{store_return}
71
-
72
- TraceView::API.log(nil, 'profile_exit', exit_kvs)
73
- ret
74
- end"
11
+ rv = self.send(method, *args, &block)
12
+ report_kvs[:ReturnValue] = rv if opts[:result]
13
+ rv
75
14
  rescue => e
76
- TraceView.logger.warn "[traceview/warn] profile_method: #{e.inspect}"
77
- end
78
-
79
- begin
80
- class_eval code, __FILE__, __LINE__
81
- alias_method "_traceview_orig_#{method_name}", method_name
82
- alias_method method_name, "_traceview_profiled_#{method_name}"
83
- rescue => e
84
- TraceView.logger.warn "[traceview/warn] Fatal error profiling method (#{method_name}): #{e.inspect}" if TraceView::Config[:verbose]
15
+ TraceView::API.log_exception(nil, e)
16
+ raise
17
+ ensure
18
+ report_kvs.delete(:Backtrace)
19
+ report_kvs.delete(:Controller)
20
+ report_kvs.delete(:Action)
21
+ TraceView::API.log(nil, 'profile_exit', report_kvs)
85
22
  end
86
23
  end
87
-
88
- # This allows this module to be included and called even if the gem is in
89
- # no-op mode (no base libraries).
90
- if TraceView.loaded
91
- alias :profile_method :profile_method_real
92
- else
93
- alias :profile_method :profile_method_noop
94
- end
95
-
96
24
  end
97
25
  end