Skip to content

Commit ae272b9

Browse files
committed
initial commit
0 parents  commit ae272b9

12 files changed

+240
-0
lines changed

.gitignore

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
*.gem
2+
*.rbc
3+
.bundle
4+
.config
5+
.yardoc
6+
Gemfile.lock
7+
InstalledFiles
8+
_yardoc
9+
coverage
10+
doc/
11+
lib/bundler/man
12+
pkg
13+
rdoc
14+
spec/reports
15+
test/tmp
16+
test/version_tmp
17+
tmp

.rspec

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
--color
2+
--format progress

Gemfile

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
source 'https://rubygems.org'
2+
3+
# Specify your gem's dependencies in rails-dtrace.gemspec
4+
gemspec

LICENSE

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Copyright (c) 2012 Eric Saxby
2+
3+
MIT License
4+
5+
Permission is hereby granted, free of charge, to any person obtaining
6+
a copy of this software and associated documentation files (the
7+
"Software"), to deal in the Software without restriction, including
8+
without limitation the rights to use, copy, modify, merge, publish,
9+
distribute, sublicense, and/or sell copies of the Software, and to
10+
permit persons to whom the Software is furnished to do so, subject to
11+
the following conditions:
12+
13+
The above copyright notice and this permission notice shall be
14+
included in all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# rails-dtrace
2+
3+
The rails-dtrace gem hooks into the ActiveSupport::Notifications
4+
instruments in Rails, turning them into DTrace probes.
5+
6+
## Requirements
7+
8+
An OS that supports DTrace. For example:
9+
* MacOS X
10+
* Illumos
11+
* SmartOS
12+
* Solaris
13+
14+
## Installation
15+
16+
Add this line to your application's Gemfile:
17+
18+
```ruby
19+
gem 'ruby-usdt', :git => 'https://github.com/chrisa/ruby-usdt.git',
20+
:submodules => true, :branch => 'disable_provider'
21+
gem 'rails-dtrace'
22+
```
23+
24+
And then execute:
25+
26+
```bash
27+
$ bundle
28+
```
29+
30+
## Warning
31+
32+
This gem in an experiment in progress. The code does not have automated
33+
tests, and the performance impact of ActiveSupport::Notifications
34+
combined with ruby-usdt and libusdt are unknown. **DO NOT USE THIS IN
35+
PRODUCTION** unless you love risk.
36+
37+
Also, this gem requires experimental behavior in libusdt/ruby-usdt.
38+
Core behavior may drastically change between releases/commits of this
39+
gem. When this is no longer the case (and I figure out how to write
40+
tests around this gem) these warnings will disappear.
41+
42+
## Usage
43+
44+
Once you add the gem to your Rails application, it will automatically
45+
subscribe to all notifications, turning them into DTrace probes. The
46+
arguments to the probes will be:
47+
48+
* `arg0` - Start time of notification - Integer
49+
* `arg1` - End time of notification - Integer
50+
* `arg2` - Unique identifier of notification - String
51+
* `arg3` - Stringified hash of notification payload - String
52+
53+
The following dtrace command can be used, as an example:
54+
55+
```bash
56+
sudo dtrace -n 'ruby*:rails:: { printf("%d %d %s %s", arg0, arg1,
57+
copyinstr(arg2), copyinstr(arg3)) }'
58+
```
59+
60+
Notifications are lazy-loaded, so even though rails-dtrace subscribes to
61+
all available instruments, they will only be converted to probes as
62+
they fire in Rails code. For this reason, in order to get a full picture
63+
of what is happening in a Rails process, enough load should be generated
64+
to ensure that all important probes are registered before tracing.
65+
66+
## Contributing
67+
68+
1. Fork it
69+
2. Create your feature branch (`git checkout -b my-new-feature`)
70+
3. Commit your changes (`git commit -am 'Added some feature'`)
71+
4. Push to the branch (`git push origin my-new-feature`)
72+
5. Create new Pull Request
73+
74+
## Suggestions for Contributions
75+
76+
* How the F do you test this thing?
77+
* Can Rails instruments be detected at initialization time?
78+
* Notifications do start/end in one instrument. DTrace probes tend to
79+
fire multiple probes, on entry and exit. This lets you write scripts
80+
to do neat analytics on event timing. Can Notifications be hacked to
81+
do this?
82+
* The Responder turns the Notification payload (a hash) into a string.
83+
This can surely be better.
84+
85+
## License
86+
87+
Copyright 2012 Eric Saxby
88+
89+
Licensed under the Apache License, Version 2.0 (the "License");
90+
you may not use this file except in compliance with the License.
91+
You may obtain a copy of the License at
92+
93+
http://www.apache.org/licenses/LICENSE-2.0
94+
95+
Unless required by applicable law or agreed to in writing, software
96+
distributed under the License is distributed on an "AS IS" BASIS,
97+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
98+
See the License for the specific language governing permissions and
99+
limitations under the License.

Rakefile

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/usr/bin/env rake
2+
require "bundler/gem_tasks"

lib/rails-dtrace.rb

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
require "rails-dtrace/version"
2+
require "rails-dtrace/responder"
3+
4+
require 'rails-dtrace/railtie' if defined?(Rails)

lib/rails-dtrace/railtie.rb

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module DTrace
2+
class Railtie < Rails::Railtie
3+
4+
initializer 'railtie.configure_rails.initialization' do
5+
DTrace::Responder.logger = Rails.logger
6+
ActiveSupport::Notifications.subscribe(/.*/, DTrace::Responder)
7+
end
8+
end
9+
end

lib/rails-dtrace/responder.rb

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
require 'usdt'
2+
3+
=begin
4+
5+
Problems:
6+
* How do you dynamically enable/disable probes?
7+
* Split name on '.' sucks
8+
* Notifications include entry AND exit. Can we fire our own entry/exit probes?
9+
10+
=end
11+
12+
module DTrace
13+
class Responder
14+
cattr_reader :probes, :provider
15+
cattr_writer :logger
16+
17+
@@provider = USDT::Provider.create :ruby, :rails
18+
@@probes = {}
19+
@@enabled = false
20+
21+
def self.logger
22+
@@logger || Logger.new
23+
end
24+
25+
def self.call(name, started, finished, unique_id, payload)
26+
unless probes.keys.include?(name)
27+
func_name, probe_name = name.split('.')
28+
p = @@provider.probe(func_name, probe_name, :integer, :integer, :string, :string)
29+
probes[name] = p
30+
logger.debug "Adding dtrace probe: #{name}"
31+
@@provider.disable if @@enabled
32+
@@provider.enable
33+
@@enabled = true
34+
end
35+
36+
if probes[name].enabled?
37+
probes[name].fire(started.to_i, finished.to_i, unique_id, payload.inspect)
38+
end
39+
end
40+
end
41+
end

lib/rails-dtrace/version.rb

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module Dtrace
2+
VERSION = "0.0.1"
3+
end

rails-dtrace.gemspec

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# -*- encoding: utf-8 -*-
2+
require File.expand_path('../lib/rails-dtrace/version', __FILE__)
3+
4+
Gem::Specification.new do |gem|
5+
gem.authors = ["Eric Saxby"]
6+
gem.email = ["[email protected]"]
7+
gem.description = %q{TODO: Write a gem description}
8+
gem.summary = %q{TODO: Write a gem summary}
9+
gem.homepage = ""
10+
11+
gem.files = `git ls-files`.split($\)
12+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| ::File.basename(f) }
13+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14+
gem.name = "rails-dtrace"
15+
gem.require_paths = ["lib"]
16+
gem.version = Dtrace::VERSION
17+
18+
gem.add_dependency 'ruby-usdt'
19+
gem.add_development_dependency 'rspec'
20+
end

spec/spec_helper.rb

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# This file was generated by the `rspec --init` command. Conventionally, all
2+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3+
# Require this file using `require "spec_helper"` to ensure that it is only
4+
# loaded once.
5+
#
6+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7+
RSpec.configure do |config|
8+
config.treat_symbols_as_metadata_keys_with_true_values = true
9+
config.run_all_when_everything_filtered = true
10+
config.filter_run :focus
11+
12+
# Run specs in random order to surface order dependencies. If you find an
13+
# order dependency and want to debug it, you can fix the order by providing
14+
# the seed, which is printed after each run.
15+
# --seed 1234
16+
config.order = 'random'
17+
end

0 commit comments

Comments
 (0)