XRay 1.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.
data/README ADDED
@@ -0,0 +1,34 @@
1
+ XRay provides a lightweight yet powerful toolbox for troubleshooting Ruby
2
+ applications when things stop making sense. Includes GDB and DTrace tooling.
3
+
4
+ *** GDB ***
5
+
6
+
7
+ Copy +gdb_macros+ file provided in the gem as your ~/.gdbinit file.
8
+
9
+ *** Fire DTrace Application Probes ***
10
+
11
+ See XRay::DTrace::Tracer
12
+
13
+ *** Out-of-the-box Rails DTrace Instrumentation ***
14
+
15
+ You are one require away from triggering automatically DTrace events for
16
+ Rails requests, database access and template rendering. As simple as
17
+
18
+ # environment.rb
19
+ Rails::Initializer.run do |config|
20
+
21
+ ...
22
+
23
+ config.after_initialize do
24
+ require "xray/dtrace/rails/enable_tracing"
25
+ end
26
+ end
27
+
28
+ See
29
+ * lib/xray/dtrace/railsenable_tracing.rb
30
+ * lib/xray/dtrace/action_controller_tracing_extension.rb
31
+ * lib/xray/dtrace/active_record_tracing_extension.rb
32
+
33
+
34
+
@@ -0,0 +1,22 @@
1
+ #
2
+ # Decorate ActionController::Base with request tracing
3
+ #
4
+ ActionController::Base.class_eval do
5
+ include XRay::DTrace::Tracer
6
+
7
+ def perform_action_with_tracing
8
+ firing('request', "#{self.class.to_s}##{action_name.to_s}") do
9
+ perform_action_without_tracing
10
+ end
11
+ end
12
+
13
+ def render_with_tracing(options = nil, deprecated_status = nil, &block)
14
+ firing('render', options.to_s) do
15
+ render_without_tracing options, deprecated_status
16
+ end
17
+ end
18
+
19
+ alias_method_chain :perform_action, :tracing
20
+ alias_method_chain :render, :tracing
21
+
22
+ end
@@ -0,0 +1,15 @@
1
+ #
2
+ # Decorate ActiveRecord connection with DB tracing
3
+ #
4
+ ActiveRecord::Base.connection.class.class_eval do
5
+ include XRay::DTrace::Tracer
6
+
7
+ def execute_with_tracing(sql, name=nil)
8
+ firing('db', sql) do
9
+ execute_without_tracing sql, name
10
+ end
11
+ end
12
+
13
+ alias_method_chain :execute, :tracing
14
+
15
+ end
@@ -0,0 +1,25 @@
1
+ # Require this file to enable out the box DTrace tracing
2
+ # for your Rails application
3
+ #
4
+ # You typically change your environment.rb to require it after config
5
+ # initialization:
6
+ #
7
+ # Rails::Initializer.run do |config|
8
+ #
9
+ # ...
10
+ #
11
+ # config.after_initialize do
12
+ # require "xray/dtrace/rails/enable_tracing"
13
+ # end
14
+ # end
15
+
16
+ require 'xray/dtrace/tracer'
17
+ if Object.const_defined? :ActionController
18
+ puts "Enabling controller tracing"
19
+ require "xray/dtrace/rails/action_controller_tracing_extension"
20
+ end
21
+
22
+ if Object.const_defined? :ActiveRecord
23
+ puts "Enabling DB tracing"
24
+ require "xray/dtrace/rails/active_record_connection_tracing_extension"
25
+ end
@@ -0,0 +1,111 @@
1
+ module XRay
2
+ module DTrace
3
+
4
+ # Ruby module to fire application-level Dtrace events (using ruby-probe).
5
+ #
6
+ # This module provide a convenient and unified API abstracting
7
+ # different tracing implementations in Leopard Ruby VM (by Apple)
8
+ # and in the one provided by Joyent (https://dev.joyent.com/projects/ruby-dtrace).
9
+ # This module also provides a NOOP implementation for Ruby VMs with
10
+ # no DTrace support: So you can use the exact same code while developing
11
+ # on Linux and deploying on Solaris for instance.
12
+ module Tracer
13
+
14
+ if Object.const_defined?(:DTracer) ### Leopard tracer ###
15
+
16
+ # Fire an application-level probe using ruby-probe.
17
+ #
18
+ # The first argument passed will be passed to the D script as arg0 for
19
+ # the ruby-probe probe. This is conventionally a probe name.
20
+ #
21
+ # The second argument is optional and can be used to pass additional
22
+ # data into the D script as arg1.
23
+ #
24
+ # Example:
25
+ #
26
+ # XRay::DTrace::Tracer.fire('service-start', "order processing")
27
+ #
28
+ # XRay::DTrace::Tracer.fire('service-stop')
29
+ #
30
+ def fire(name, data = nil)
31
+ DTracer.fire(name, data)
32
+ end
33
+
34
+ # Use ruby-probe to fire 2 application-level probes before and after
35
+ # evaling a block .
36
+ #
37
+ # The first argument passed will be passed to the D script as arg0 for
38
+ # the ruby-probe probe. This is conventionally a probe base name. The
39
+ # probes which fire before and after the block runs will have
40
+ # "-start" and "-end" appended, respectively.
41
+ #
42
+ # The second argument is optional and can be used to pass additional
43
+ # data into the D script as arg1.
44
+ #
45
+ # Example:
46
+ #
47
+ # XRay::DTrace::Tracer.fire('service-start', "order processing")
48
+ #
49
+ # XRay::DTrace::Tracer.firing('db-query', "select * from dual;") do
50
+ # ActiveRecord::Base.execute("select * from dual;")
51
+ #
52
+ # end
53
+ #
54
+ # Will:
55
+ # 1. Fire a probe with arg0 set to "db-query-start", and arg1 set
56
+ # to the sql query.
57
+ #
58
+ # 2. Run the block and execute the SQL.
59
+ #
60
+ # 3. Fire a probe with arg0 set to "db-query-start".
61
+ def firing(name, data = nil)
62
+ fire(name + "-start", data)
63
+ result = yield
64
+ fire(name + "-end", data)
65
+ result
66
+ end
67
+
68
+ # Returns true if ruby-probe probes are enables
69
+ # (application-level probes for Ruby).
70
+ def enabled?
71
+ DTracer.enabled?
72
+ end
73
+
74
+
75
+ elsif Object.const_defined?(:Tracer) && Tracer.methods.include?(:fire) ### Joyent Tracer ##
76
+
77
+ raise "got here"
78
+
79
+ def fire(name, data = nil) #:nodoc: all
80
+
81
+ ::Tracer.fire(name, data)
82
+ end
83
+
84
+ def firing(name, data = nil) #:nodoc: all
85
+ ::Tracer.fire(name, data)
86
+ end
87
+
88
+ def enabled? #:nodoc: all
89
+ STDERR.puts "WARNING: XRay::DTrace.Tracer.enabled? does not work with Joyent Tracer"
90
+ false
91
+ end
92
+
93
+ else ### No ruby-probe support ###
94
+
95
+ def fire(name, data = nil) #:nodoc: all
96
+ end
97
+
98
+ def firing(name, data = nil) #:nodoc: all
99
+ yield
100
+ end
101
+
102
+ def enabled? #:nodoc: all
103
+ false
104
+ end
105
+
106
+ end
107
+
108
+ end
109
+
110
+ end
111
+ end
@@ -0,0 +1 @@
1
+ Dispatcher.send :include, XRay::ThreadAwareDispatcher
@@ -0,0 +1,15 @@
1
+ #
2
+ # Install a signal handler dumping Rails stack by raising an exception
3
+ #
4
+ # Trigger it with: kill -QUIT <pid>
5
+ #
6
+
7
+ trap "QUIT" do
8
+ STDERR.puts "=============== XRay - Raising exception in Rails thread ==============="
9
+ if Dispatcher.thread_in_dispatch
10
+ Dispatcher.thread_in_dispatch.raise "XRay - Forced exception to Rails stack trace"
11
+ else
12
+ STDERR.puts "No Rails thread in dispatch"
13
+ end
14
+ STDERR.puts "=============== XRay - Done ==============="
15
+ end
@@ -0,0 +1,26 @@
1
+ #
2
+ # Install a signal handler dumping current thread stack
3
+ #
4
+ # Trigger it with: kill -QUIT <pid>
5
+ #
6
+ module XRay
7
+
8
+ def self.dump_threads
9
+ STDERR.puts "=============== XRay Inspector ==============="
10
+ STDERR.puts "Current Thread\n "
11
+ STDERR.puts caller.join("\n \_ ")
12
+ STDERR.puts Thread.current.xray_backtrace.join("\n \_ ")
13
+ # STDERR.puts "----------------------------------------------"
14
+ # Thread.list.each_with_index do |t,i|
15
+ # STDERR.puts "Dumping Thread #{i}\n "
16
+ # t.xray_backtrace.join("\n \_ ")
17
+ # end
18
+ STDERR.puts "=============================================="
19
+ STDERR.flush
20
+ end
21
+
22
+ end
23
+
24
+ trap "QUIT" do
25
+ XRay.dump_threads
26
+ end
@@ -0,0 +1,27 @@
1
+ module XRay
2
+
3
+ module ThreadAwareDispatcher
4
+
5
+ # Intercept dispatch with our own method when the module is included.
6
+ def self.included(target)
7
+ class << target
8
+ attr_reader :thread_in_dispatch
9
+
10
+ alias actual_dispatch dispatch
11
+
12
+ # Capture as an instance variable the current
13
+ # thread -- which is processing current Rails request --
14
+ # and do the actual dispatch.
15
+ def dispatch(*args)
16
+ @thread_in_dispatch = Thread.current
17
+ actual_dispatch *args
18
+ ensure
19
+ @thread_in_dispatch = nil
20
+ end
21
+
22
+ end
23
+ end
24
+
25
+ end
26
+
27
+ end
data/lib/xray/xray.rb ADDED
@@ -0,0 +1 @@
1
+ require 'xray/thread_aware_dispatcher'
data/test/all_tests.rb ADDED
@@ -0,0 +1 @@
1
+ Dir["#{File.dirname __FILE__}/**/*_test.rb"].each { |test_case| require test_case }
@@ -0,0 +1,54 @@
1
+ require File.expand_path(__FILE__ + '/../../../test_helper')
2
+
3
+ functional_tests do
4
+
5
+ test "fire a probe with no data and no block" do
6
+ aClass = Class.new do
7
+ include XRay::DTrace::Tracer
8
+ end
9
+
10
+ aClass.new.fire "a name"
11
+ end
12
+
13
+ test "fire a probe with data and no block" do
14
+ aClass = Class.new do
15
+ include XRay::DTrace::Tracer
16
+ end
17
+
18
+ aClass.new.fire "a name", "some data"
19
+ end
20
+
21
+ test "Can check whether ruby-probe is enabled" do
22
+ aClass = Class.new do
23
+ include XRay::DTrace::Tracer
24
+ end
25
+
26
+ assert [true, false].include?(aClass.new.enabled?)
27
+ end
28
+
29
+ test "fire a probe with block and no data" do
30
+ anObject = Class.new do
31
+ include XRay::DTrace::Tracer
32
+ end.new
33
+
34
+ result = anObject.firing("a-name") do
35
+ :expected_result
36
+ end
37
+
38
+ assert_equal :expected_result, result
39
+ end
40
+
41
+ test "fire a probe with block and data" do
42
+ anObject = Class.new do
43
+ include XRay::DTrace::Tracer
44
+ end.new
45
+
46
+ result = anObject.firing("a-name", "some data") do
47
+ :expected_result
48
+ end
49
+
50
+ assert_equal :expected_result, result
51
+ end
52
+
53
+ end
54
+
@@ -0,0 +1,18 @@
1
+ $: << File.dirname(__FILE__) + '/../../lib'
2
+ require 'xray/dtrace/tracer'
3
+
4
+ class Service
5
+ include XRay::DTrace::Tracer
6
+
7
+ def process
8
+ puts "Processing new request"
9
+ firing "my-service", "a sql query" do
10
+ sleep 2
11
+ end
12
+ end
13
+
14
+ end
15
+
16
+ loop do
17
+ Service.new.process
18
+ end
@@ -0,0 +1,10 @@
1
+ $: << File.dirname(__FILE__) + '/../ext/xray'
2
+ $: << File.dirname(__FILE__) + '/../lib'
3
+ require 'xray/xray'
4
+ require 'xray/dtrace/tracer'
5
+
6
+ require 'test/unit'
7
+ require 'rubygems'
8
+ require 'mocha'
9
+ require 'dust'
10
+
@@ -0,0 +1,51 @@
1
+ require File.expand_path(__FILE__ + '/../../test_helper')
2
+
3
+ unit_tests do
4
+
5
+ test "thread aware dispatcher returns original dispath result" do
6
+ dispatcher = Class.new
7
+ dispatcher.expects(:dispatch).with(:the_args).returns(:the_result)
8
+ dispatcher.send :include, XRay::ThreadAwareDispatcher
9
+ dispatcher.dispatch(:the_args)
10
+ end
11
+
12
+ test "thread aware dispatcher adds accessor for thread in dispatch" do
13
+ dispatcher = Class.new
14
+ dispatcher.stubs(:dispatch)
15
+ dispatcher.send :include, XRay::ThreadAwareDispatcher
16
+ dispatcher.thread_in_dispatch
17
+ end
18
+
19
+ test "thread in dispatch is nil when not in dispatch" do
20
+ dispatcher = Class.new
21
+ dispatcher.stubs(:dispatch)
22
+ dispatcher.send :include, XRay::ThreadAwareDispatcher
23
+ assert_nil dispatcher.thread_in_dispatch
24
+ end
25
+
26
+ test "thread in dispatch is nil when dispatch raises" do
27
+ begin
28
+ dispatcher = Class.new
29
+ dispatcher.expects(:dispatch).raises(StandardError.new("Fake Problem"))
30
+ dispatcher.send :include, XRay::ThreadAwareDispatcher
31
+ dispatcher.dispatch
32
+ flunk "Should relay exception"
33
+ rescue StandardError
34
+ assert_nil dispatcher.thread_in_dispatch
35
+ end
36
+ end
37
+
38
+ test "thread in dispatch is set to current thread when in dispatch" do
39
+ dispatcher = Class.new do
40
+ extend Test::Unit::Assertions
41
+
42
+ def self.dispatch(*args)
43
+ assert_equal Thread.current, thread_in_dispatch
44
+ end
45
+
46
+ include XRay::ThreadAwareDispatcher
47
+ end
48
+ dispatcher.dispatch
49
+ end
50
+
51
+ end
@@ -0,0 +1,54 @@
1
+ require File.expand_path(__FILE__ + '/../../../../test_helper')
2
+
3
+ unit_tests do
4
+
5
+ test "fire a probe with no data and no block" do
6
+ aClass = Class.new do
7
+ include XRay::DTrace::Tracer
8
+ end
9
+
10
+ aClass.new.fire "a name"
11
+ end
12
+
13
+ test "fire a probe with data and no block" do
14
+ aClass = Class.new do
15
+ include XRay::DTrace::Tracer
16
+ end
17
+
18
+ aClass.new.fire "a name", "some data"
19
+ end
20
+
21
+ test "Can check whether ruby-probe is enabled" do
22
+ aClass = Class.new do
23
+ include XRay::DTrace::Tracer
24
+ end
25
+
26
+ assert [true, false].include?(aClass.new.enabled?)
27
+ end
28
+
29
+ test "fire a probe with block and no data" do
30
+ anObject = Class.new do
31
+ include XRay::DTrace::Tracer
32
+ end.new
33
+
34
+ result = anObject.firing("a-name") do
35
+ :expected_result
36
+ end
37
+
38
+ assert_equal :expected_result, result
39
+ end
40
+
41
+ test "fire a probe with block and data" do
42
+ anObject = Class.new do
43
+ include XRay::DTrace::Tracer
44
+ end.new
45
+
46
+ result = anObject.firing("a-name", "some data") do
47
+ :expected_result
48
+ end
49
+
50
+ assert_equal :expected_result, result
51
+ end
52
+
53
+ end
54
+
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: XRay
3
+ version: !ruby/object:Gem::Version
4
+ version: "1.0"
5
+ platform: ruby
6
+ authors:
7
+ - Philippe Hanrigou
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-03-28 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: xray-developer@rubyforge.org
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ files:
25
+ - lib/xray/dtrace/rails/action_controller_tracing_extension.rb
26
+ - lib/xray/dtrace/rails/active_record_connection_tracing_extension.rb
27
+ - lib/xray/dtrace/rails/enable_tracing.rb
28
+ - lib/xray/dtrace/tracer.rb
29
+ - lib/xray/enable_thread_aware_dispatcher.rb
30
+ - lib/xray/rails_stack_signal_handler.rb
31
+ - lib/xray/signal_handler.rb
32
+ - lib/xray/thread_aware_dispatcher.rb
33
+ - lib/xray/xray.rb
34
+ - test/all_tests.rb
35
+ - test/functional/dtrace/tracer_test.rb
36
+ - test/functional/tracer_script.rb
37
+ - test/test_helper.rb
38
+ - test/unit/thread_aware_dispatcher_test.rb
39
+ - test/unit/xray/dtrace/tracer_test.rb
40
+ - README
41
+ has_rdoc: true
42
+ homepage: http://xray.rubyforge.com
43
+ post_install_message:
44
+ rdoc_options:
45
+ - --title
46
+ - XRay
47
+ - --main
48
+ - README
49
+ - --line-numbers
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ requirements: []
65
+
66
+ rubyforge_project: xray
67
+ rubygems_version: 1.0.1
68
+ signing_key:
69
+ specification_version: 2
70
+ summary: Dump backtrace for all threads.
71
+ test_files:
72
+ - test/all_tests.rb