Skip to content

Commit d76d3d9

Browse files
committed
First implement
1 parent d7863c6 commit d76d3d9

File tree

11 files changed

+230
-48
lines changed

11 files changed

+230
-48
lines changed

README.md

Lines changed: 68 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
# TraceLocation
22

3-
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/trace_location`. To experiment with that code, run `bin/console` for an interactive prompt.
4-
5-
TODO: Delete this and the text above, and describe your gem
3+
TraceLocation gem provides logs a tracing result of `:call` and `:return`. It's useful for reading the huge codes (e.g. Ruby on Rails) and tracing its process.
64

75
## Installation
86

@@ -22,17 +20,76 @@ Or install it yourself as:
2220

2321
## Usage
2422

25-
TODO: Write usage instructions here
26-
27-
## Development
23+
You just surround the code which you want to track the process.
24+
For example, when you want to track the process of Rails application request/response:
2825

29-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30-
31-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
26+
```
27+
% bin/rails c
28+
Running via Spring preloader in process 40741
29+
Loading development environment (Rails 5.2.3)
30+
irb(main):001:0> env = Rack::MockRequest.env_for('http://localhost:3000/api/stories')
31+
irb(main):002:0> TraceLocation.trace { status, headers, body = Rails.application.call(env) }
32+
Created at /path/to/sampleapp/log/trace_location-2019050105051556706139.log
33+
=> true
34+
```
3235

33-
## Contributing
36+
Then you can get a log like this:
3437

35-
Bug reports and pull requests are welcome on GitHub at https://github.com/yhirano55/trace_location.
38+
```
39+
Logged by TraceLocation gem at 2019-05-01 05:22:19 -0500
40+
https://github.com/yhirano55/trace_location
41+
42+
[Tracing events] C: Call, R: Return
43+
44+
R <internal:prelude>:138#enable
45+
C /vendor/bundle/gems/railties-5.2.3/lib/rails.rb:39#application
46+
R /vendor/bundle/gems/railties-5.2.3/lib/rails.rb:41#application
47+
C /vendor/bundle/gems/railties-5.2.3/lib/rails/engine.rb:522#call
48+
C /vendor/bundle/gems/railties-5.2.3/lib/rails/application.rb:607#build_request
49+
C /vendor/bundle/gems/railties-5.2.3/lib/rails/engine.rb:705#build_request
50+
C /vendor/bundle/gems/railties-5.2.3/lib/rails/application.rb:247#env_config
51+
R /vendor/bundle/gems/railties-5.2.3/lib/rails/application.rb:275#env_config
52+
C /vendor/bundle/gems/actionpack-5.2.3/lib/action_dispatch/http/request.rb:59#initialize
53+
C /vendor/bundle/gems/rack-2.0.7/lib/rack/request.rb:40#initialize
54+
C /vendor/bundle/gems/actionpack-5.2.3/lib/action_dispatch/http/url.rb:186#initialize
55+
C /vendor/bundle/gems/actionpack-5.2.3/lib/action_dispatch/http/filter_parameters.rb:34#initialize
56+
R /vendor/bundle/gems/actionpack-5.2.3/lib/action_dispatch/http/filter_parameters.rb:39#initialize
57+
R /vendor/bundle/gems/actionpack-5.2.3/lib/action_dispatch/http/url.rb:190#initialize
58+
R /vendor/bundle/gems/rack-2.0.7/lib/rack/request.rb:43#initialize
59+
R /vendor/bundle/gems/actionpack-5.2.3/lib/action_dispatch/http/request.rb:67#initialize
60+
C /vendor/bundle/gems/railties-5.2.3/lib/rails/engine.rb:534#routes
61+
R /vendor/bundle/gems/railties-5.2.3/lib/rails/engine.rb:538#routes
62+
C /vendor/bundle/gems/actionpack-5.2.3/lib/action_dispatch/http/request.rb:142#routes=
63+
C /vendor/bundle/gems/rack-2.0.7/lib/rack/request.rb:68#set_header
64+
R /vendor/bundle/gems/rack-2.0.7/lib/rack/request.rb:70#set_header
65+
R /vendor/bundle/gems/actionpack-5.2.3/lib/action_dispatch/http/request.rb:144#routes=
66+
C /vendor/bundle/gems/rack-2.0.7/lib/rack/request.rb:129#script_name
67+
C /vendor/bundle/gems/rack-2.0.7/lib/rack/request.rb:52#get_header
68+
R /vendor/bundle/gems/rack-2.0.7/lib/rack/request.rb:54#get_header
69+
R /vendor/bundle/gems/rack-2.0.7/lib/rack/request.rb:129#script_name
70+
C /vendor/bundle/gems/actionpack-5.2.3/lib/action_dispatch/http/request.rb:150#engine_script_name=
71+
C /vendor/bundle/gems/actionpack-5.2.3/lib/action_dispatch/http/request.rb:138#routes
72+
C /vendor/bundle/gems/rack-2.0.7/lib/rack/request.rb:52#get_header
73+
R /vendor/bundle/gems/rack-2.0.7/lib/rack/request.rb:54#get_header
74+
..................
75+
(an omission)
76+
..................
77+
R /vendor/bundle/gems/actionpack-5.2.3/lib/action_dispatch/middleware/static.rb:128#call
78+
C /vendor/bundle/gems/rack-2.0.7/lib/rack/body_proxy.rb:9#respond_to?
79+
C /vendor/bundle/gems/rack-2.0.7/lib/rack/body_proxy.rb:9#respond_to?
80+
C /vendor/bundle/gems/rack-2.0.7/lib/rack/body_proxy.rb:9#respond_to?
81+
C /vendor/bundle/gems/rack-2.0.7/lib/rack/body_proxy.rb:9#respond_to?
82+
C /vendor/bundle/gems/rack-2.0.7/lib/rack/body_proxy.rb:9#respond_to?
83+
R /vendor/bundle/gems/rack-2.0.7/lib/rack/body_proxy.rb:15#respond_to?
84+
R /vendor/bundle/gems/rack-2.0.7/lib/rack/body_proxy.rb:15#respond_to?
85+
R /vendor/bundle/gems/rack-2.0.7/lib/rack/body_proxy.rb:15#respond_to?
86+
R /vendor/bundle/gems/rack-2.0.7/lib/rack/body_proxy.rb:15#respond_to?
87+
R /vendor/bundle/gems/rack-2.0.7/lib/rack/body_proxy.rb:15#respond_to?
88+
R /vendor/bundle/gems/rack-2.0.7/lib/rack/sendfile.rb:140#call
89+
R /vendor/bundle/gems/railties-5.2.3/lib/rails/engine.rb:525#call
90+
91+
Result: [200, {"Content-Type"=>"application/json; charset=utf-8", "ETag"=>"W/\"42334f8fba25471804e2cfa66fa989a7\"", "Cache-Control"=>"max-age=0, private, must-revalidate", "X-Request-Id"=>"f30153ff-3446-453a-a547-34c4b3766bfc", "X-Runtime"=>"0.455604"}, #<Rack::BodyProxy:0x00007f957960a430 @body=#<Rack::BodyProxy:0x00007f957f1c1f08 @body=#<Rack::BodyProxy:0x00007f957f1a8c10 @body=#<Rack::BodyProxy:0x00007f957f198040 @body=#<Rack::BodyProxy:0x00007f957f17bf58 @body=["[{\"id\":1,\"title\":\"The boy who cried 'wolf!'\",\"parentId\":1},{\"id\":2,\"title\":\"story 2\",\"parentId\":4},{\"id\":3,\"title\":\"story 3\",\"parentId\":null},{\"id\":4,\"title\":\"story 4\",\"parentId\":null},{\"id\":5,\"title\":\"story 1\",\"parentId\":null},{\"id\":6,\"title\":\"story 6\",\"parentId\":null},{\"id\":7,\"title\":\"story 7\",\"parentId\":null},{\"id\":8,\"title\":\"story 8\",\"parentId\":null},{\"id\":9,\"title\":\"story 9\",\"parentId\":null},{\"id\":10,\"title\":\"story 10\",\"parentId\":null},{\"id\":11,\"title\":\"story 11\",\"parentId\":null},{\"id\":12,\"title\":\"story 12\",\"parentId\":null},{\"id\":13,\"title\":\"story 13\",\"parentId\":null}]"], @block=#<Proc:0x00007f957f17ae78@/path/to/sampleapp/vendor/bundle/gems/rack-2.0.7/lib/rack/etag.rb:30>, @closed=false>, @block=#<Proc:0x00007f957f1a2d38@/path/to/sampleapp/vendor/bundle/gems/actionpack-5.2.3/lib/action_dispatch/middleware/executor.rb:15>, @closed=false>, @block=#<Proc:0x00007f957f1b3728@/path/to/sampleapp/vendor/bundle/gems/railties-5.2.3/lib/rails/rack/logger.rb:39>, @closed=false>, @block=#<Proc:0x00007f957f1c07c0@/path/to/sampleapp/vendor/bundle/gems/activesupport-5.2.3/lib/active_support/cache/strategy/local_cache_middleware.rb:30>, @closed=false>, @block=#<Proc:0x00007f95796096c0@/path/to/sampleapp/vendor/bundle/gems/actionpack-5.2.3/lib/action_dispatch/middleware/executor.rb:15>, @closed=false>]
92+
```
3693

3794
## License
3895

Rakefile

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
require "bundler/gem_tasks"
2-
require "rspec/core/rake_task"
1+
# frozen_string_literal: true
2+
3+
require 'bundler/gem_tasks'
4+
require 'rspec/core/rake_task'
35

46
RSpec::Core::RakeTask.new(:spec)
57

6-
task :default => :spec
8+
task default: :spec

bin/console

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#!/usr/bin/env ruby
2+
# frozen_string_literal: true
23

3-
require "bundler/setup"
4-
require "trace_location"
4+
require 'bundler/setup'
5+
require 'trace_location'
56

67
# You can add fixtures and/or initialization code here to make experimenting
78
# with your gem easier. You can also use a different console, if you like.
@@ -10,5 +11,5 @@ require "trace_location"
1011
# require "pry"
1112
# Pry.start
1213

13-
require "irb"
14+
require 'irb'
1415
IRB.start(__FILE__)

lib/trace_location.rb

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,26 @@
1-
require "trace_location/version"
1+
# frozen_string_literal: true
22

3-
module TraceLocation
4-
class Error < StandardError; end
5-
# Your code goes here...
3+
require_relative 'trace_location/version'
4+
require_relative 'trace_location/config'
5+
require_relative 'trace_location/tracer'
6+
7+
begin
8+
require 'rails'
9+
require_relative 'trace_location/railtie'
10+
rescue LoadError
11+
nil
12+
end
13+
14+
module TraceLocation # :nodoc:
15+
def self.trace(options = {}, &block)
16+
Tracer.new(options).call(&block)
17+
end
18+
19+
def self.configure
20+
yield config
21+
end
22+
23+
def self.config
24+
@config ||= Config.new
25+
end
626
end

lib/trace_location/config.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# frozen_string_literal: true
2+
3+
module TraceLocation
4+
class Config # :nodoc:
5+
attr_accessor :root_dir, :dest_dir
6+
7+
def initialize
8+
@root_dir = Dir.pwd
9+
@dest_dir = Dir.pwd
10+
end
11+
end
12+
end

lib/trace_location/railtie.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# frozen_string_literal: true
2+
3+
module TraceLocation
4+
class Railtie < ::Rails::Railtie # :nodoc:
5+
config.after_initialize do
6+
::TraceLocation.configure do |config|
7+
config.root_dir = Rails.root
8+
config.dest_dir = Rails.root.join('log')
9+
end
10+
end
11+
end
12+
end

lib/trace_location/tracer.rb

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# frozen_string_literal: true
2+
3+
module TraceLocation
4+
class Tracer # :nodoc:
5+
EVENTS = { call: 'C', return: 'R' }.freeze
6+
INDENT_SPACES = 2
7+
INDENT_STRING = ' '
8+
9+
def initialize(options = {})
10+
@root_dir = options.fetch(:root_dir) { TraceLocation.config.root_dir }
11+
@dest_dir = options.fetch(:dest_dir) { TraceLocation.config.dest_dir }
12+
end
13+
14+
def call(&block)
15+
logs = []
16+
nest = 0
17+
trace_point = TracePoint.new(:call, :return) do |tp|
18+
case tp.event
19+
when :call
20+
logs << build_log(trace_point: tp, nest: nest, root_dir: root_dir)
21+
nest += 1
22+
when :return
23+
nest = nest.positive? ? nest - 1 : 0
24+
logs << build_log(trace_point: tp, nest: nest, root_dir: root_dir)
25+
end
26+
end
27+
28+
trace_point.enable
29+
result = block.call
30+
trace_point.disable
31+
32+
current = Time.now
33+
filename = "trace_location-#{current.strftime('%Y%m%d%H%m%s')}.log"
34+
file_path = File.join(dest_dir, filename)
35+
File.open(file_path, 'w+') do |io|
36+
io.puts "Logged by TraceLocation gem at #{current}"
37+
io.puts 'https://github.com/yhirano55/trace_location'
38+
io.puts
39+
io.puts '[Tracing events] C: Call, R: Return'
40+
io.puts
41+
io.puts logs.join("\n")
42+
io.puts
43+
io.puts "Result: #{result.inspect}"
44+
end
45+
$stdout.puts "Created at #{file_path}"
46+
true
47+
rescue StandardError => e
48+
$stdout.puts "Failure: #{e.message}"
49+
false
50+
ensure
51+
trace_point.disable if trace_point.enabled?
52+
end
53+
54+
private
55+
56+
attr_reader :root_dir, :dest_dir, :block
57+
58+
def build_log(trace_point:, nest:, root_dir:)
59+
indent = indent(nest)
60+
event = EVENTS[trace_point.event]
61+
path = trace_point.path.to_s.gsub(/#{root_dir}/, '')
62+
lineno = trace_point.lineno
63+
method_id = trace_point.method_id
64+
65+
%(#{indent}#{event} #{path}:#{lineno}##{method_id})
66+
end
67+
68+
def indent(nest)
69+
INDENT_STRING * (nest * INDENT_SPACES)
70+
end
71+
end
72+
end

lib/trace_location/version.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# frozen_string_literal: true
2+
13
module TraceLocation
2-
VERSION = "0.1.0"
4+
VERSION = '0.1.0'
35
end

spec/spec_helper.rb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
require "bundler/setup"
2-
require "trace_location"
1+
# frozen_string_literal: true
2+
3+
require 'bundler/setup'
4+
require 'trace_location'
35

46
RSpec.configure do |config|
57
# Enable flags like --only-failures and --next-failure
6-
config.example_status_persistence_file_path = ".rspec_status"
8+
config.example_status_persistence_file_path = '.rspec_status'
79

810
# Disable RSpec exposing methods globally on `Module` and `main`
911
config.disable_monkey_patching!

spec/trace_location_spec.rb

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1+
# frozen_string_literal: true
2+
13
RSpec.describe TraceLocation do
2-
it "has a version number" do
4+
it 'has a version number' do
35
expect(TraceLocation::VERSION).not_to be nil
46
end
5-
6-
it "does something useful" do
7-
expect(false).to eq(true)
8-
end
97
end

0 commit comments

Comments
 (0)