x-ray-machine 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0a96ac18783ffbb5d0c77256f0cdb11e3cf7c2ce
4
+ data.tar.gz: a8b664e63e6450c3f0cb3012c397a9d65af50802
5
+ SHA512:
6
+ metadata.gz: 3dec83fd88b356ae3fe723dd451537fdd483d2555dd3f63d888af90e476bd6adaa1c4c4aa1d25e5da3490313a4c1c53bafa6369756b5d6ec2d1731d5fd9522a5
7
+ data.tar.gz: 4542b55289dcaa18d99aadca5f3ba18475b0bc8a663ede503bb02baa2d4297dc093bf2134f66fdf656775a80851aa010897749c0bfda6f7b1bdea33a8aa03799
@@ -0,0 +1,2 @@
1
+ .bundle
2
+ *.gem
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ -c -f p -r spec_helper
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ninefold.gemspec
4
+ gemspec
@@ -0,0 +1,132 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ x-ray-machine (0.0.0)
5
+ rails (~> 4.0, >= 4.0.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ actionmailer (4.1.8)
11
+ actionpack (= 4.1.8)
12
+ actionview (= 4.1.8)
13
+ mail (~> 2.5, >= 2.5.4)
14
+ actionpack (4.1.8)
15
+ actionview (= 4.1.8)
16
+ activesupport (= 4.1.8)
17
+ rack (~> 1.5.2)
18
+ rack-test (~> 0.6.2)
19
+ actionview (4.1.8)
20
+ activesupport (= 4.1.8)
21
+ builder (~> 3.1)
22
+ erubis (~> 2.7.0)
23
+ activemodel (4.1.8)
24
+ activesupport (= 4.1.8)
25
+ builder (~> 3.1)
26
+ activerecord (4.1.8)
27
+ activemodel (= 4.1.8)
28
+ activesupport (= 4.1.8)
29
+ arel (~> 5.0.0)
30
+ activesupport (4.1.8)
31
+ i18n (~> 0.6, >= 0.6.9)
32
+ json (~> 1.7, >= 1.7.7)
33
+ minitest (~> 5.1)
34
+ thread_safe (~> 0.1)
35
+ tzinfo (~> 1.1)
36
+ arel (5.0.1.20140414130214)
37
+ builder (3.2.2)
38
+ celluloid (0.16.0)
39
+ timers (~> 4.0.0)
40
+ coderay (1.1.0)
41
+ diff-lcs (1.2.5)
42
+ erubis (2.7.0)
43
+ ffi (1.9.6)
44
+ formatador (0.2.5)
45
+ guard (2.10.1)
46
+ formatador (>= 0.2.4)
47
+ listen (~> 2.7)
48
+ lumberjack (~> 1.0)
49
+ pry (>= 0.9.12)
50
+ thor (>= 0.18.1)
51
+ guard-rspec (4.3.1)
52
+ guard (~> 2.1)
53
+ rspec (>= 2.14, < 4.0)
54
+ hike (1.2.3)
55
+ hitimes (1.2.2)
56
+ i18n (0.6.11)
57
+ json (1.8.1)
58
+ listen (2.8.3)
59
+ celluloid (>= 0.15.2)
60
+ rb-fsevent (>= 0.9.3)
61
+ rb-inotify (>= 0.9)
62
+ lumberjack (1.0.9)
63
+ mail (2.6.3)
64
+ mime-types (>= 1.16, < 3)
65
+ method_source (0.8.2)
66
+ mime-types (2.4.3)
67
+ minitest (5.4.3)
68
+ multi_json (1.10.1)
69
+ pry (0.10.1)
70
+ coderay (~> 1.1.0)
71
+ method_source (~> 0.8.1)
72
+ slop (~> 3.4)
73
+ rack (1.5.2)
74
+ rack-test (0.6.2)
75
+ rack (>= 1.0)
76
+ rails (4.1.8)
77
+ actionmailer (= 4.1.8)
78
+ actionpack (= 4.1.8)
79
+ actionview (= 4.1.8)
80
+ activemodel (= 4.1.8)
81
+ activerecord (= 4.1.8)
82
+ activesupport (= 4.1.8)
83
+ bundler (>= 1.3.0, < 2.0)
84
+ railties (= 4.1.8)
85
+ sprockets-rails (~> 2.0)
86
+ railties (4.1.8)
87
+ actionpack (= 4.1.8)
88
+ activesupport (= 4.1.8)
89
+ rake (>= 0.8.7)
90
+ thor (>= 0.18.1, < 2.0)
91
+ rake (10.3.2)
92
+ rb-fsevent (0.9.4)
93
+ rb-inotify (0.9.5)
94
+ ffi (>= 0.5.0)
95
+ rspec (3.1.0)
96
+ rspec-core (~> 3.1.0)
97
+ rspec-expectations (~> 3.1.0)
98
+ rspec-mocks (~> 3.1.0)
99
+ rspec-core (3.1.7)
100
+ rspec-support (~> 3.1.0)
101
+ rspec-expectations (3.1.2)
102
+ diff-lcs (>= 1.2.0, < 2.0)
103
+ rspec-support (~> 3.1.0)
104
+ rspec-mocks (3.1.3)
105
+ rspec-support (~> 3.1.0)
106
+ rspec-support (3.1.2)
107
+ slop (3.6.0)
108
+ sprockets (2.11.3)
109
+ hike (~> 1.2)
110
+ multi_json (~> 1.0)
111
+ rack (~> 1.0)
112
+ tilt (~> 1.1, != 1.3.0)
113
+ sprockets-rails (2.2.0)
114
+ actionpack (>= 3.0)
115
+ activesupport (>= 3.0)
116
+ sprockets (>= 2.8, < 4.0)
117
+ thor (0.19.1)
118
+ thread_safe (0.3.4)
119
+ tilt (1.4.1)
120
+ timers (4.0.1)
121
+ hitimes
122
+ tzinfo (1.2.2)
123
+ thread_safe (~> 0.1)
124
+
125
+ PLATFORMS
126
+ ruby
127
+
128
+ DEPENDENCIES
129
+ bundler (~> 1.7)
130
+ guard-rspec (~> 4.3)
131
+ rspec (~> 3.1)
132
+ x-ray-machine!
@@ -0,0 +1,8 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
@@ -0,0 +1,100 @@
1
+ # X Ray Machine
2
+
3
+ ![X-Ray](./x-ray.jpg)
4
+
5
+ Ever wanted to log and profile your external API calls in a Rails app the
6
+ same way Rails does with active record? Look no further, as the `x-ray-machine`
7
+ is the thing that will enable you to do that!
8
+
9
+ ## Usage
10
+
11
+ As per usual add this to your `Gemfile`
12
+
13
+ ```ruby
14
+ gem 'x-ray-machine'
15
+ ```
16
+
17
+ Then just call `XRay.whatevers` with some marker you wanna see in the logs
18
+ (it can be an url or anything stringy) and then give it a block to measure.
19
+
20
+ ```ruby
21
+ class MyThing
22
+ def talk_to_elastic_search
23
+ url = figure_the_url
24
+
25
+ XRay.elastic_search url do
26
+ make_the_actual_request url
27
+ end
28
+ end
29
+
30
+ def talk_to_twitter_api
31
+ XRay.twitter "loading recent tweets" do
32
+ load_some_tweets_for_fun_and_profit
33
+ end
34
+ end
35
+
36
+ def craaaazy_stuff
37
+ XRay.baaacooon "fat acids hitting the brain" do
38
+ i_wonder_if_spacemen_eat_bacon
39
+ end
40
+ end
41
+ end
42
+ ```
43
+
44
+ This will show something like this in your rails console
45
+
46
+ ```log
47
+ ElasticSearch (5.1ms) /url?bla=bla&bla
48
+ Twitter (100.2ms) loading recent tweets
49
+ Baaacooon (10.1ms) fat acids hitting the brain
50
+ ```
51
+
52
+ ## Marking Cached Results
53
+
54
+ In case you want to mark a query as cached, you can use the `ray`
55
+ object that is passed down the block, and mark it as cached
56
+
57
+ ```ruby
58
+ url = "some/url.thing"
59
+
60
+ XRay.heavy_request url do |ray|
61
+ if result = find_in_cache(url)
62
+ ray.cached = true
63
+ else
64
+ result = make_the_actual_request(url)
65
+ end
66
+ end
67
+ ```
68
+
69
+ After that your log entry will look like so
70
+
71
+ ```log
72
+ HeavyRequest CACHE (0.1ms) /url?bla=bla&bla
73
+ ```
74
+
75
+
76
+ ## Customization & Configuration
77
+
78
+ Normally, the `XRay` object will use `method_missing` and automatically
79
+ guess the name for the entry and use a random color for it, but you can
80
+ customize things
81
+
82
+ ```ruby
83
+ XRayMachine.config do |config|
84
+ config.elastic_search = {
85
+ color: :yellow, # color for the line
86
+ title: "ES", # title for the entries
87
+ show_in_summary: false # show/hide the results in the summary
88
+ }
89
+ end
90
+ ```
91
+
92
+ __NOTE__: the name you use with the `config` should match the one
93
+ that you use on the `XRay` class to track your queries.
94
+
95
+
96
+ ## Copyright & License
97
+
98
+ All code in this repository is released under the terms of the MIT License
99
+
100
+ Copyright (C) 2014 Nikolay Nemshilov
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'bundler' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('bundler', 'bundler')
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'coderay' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('coderay', 'coderay')
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'erubis' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('erubis', 'erubis')
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'guard' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('guard', 'guard')
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'htmldiff' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('diff-lcs', 'htmldiff')
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'ldiff' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('diff-lcs', 'ldiff')
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'listen' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('listen', 'listen')
data/bin/pry ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'pry' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('pry', 'pry')
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rackup' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('rack', 'rackup')
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rails' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('railties', 'rails')
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rake' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('rake', 'rake')
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rspec' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('rspec-core', 'rspec')
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'sprockets' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('sprockets', 'sprockets')
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'thor' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('thor', 'thor')
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'tilt' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('tilt', 'tilt')
@@ -0,0 +1,2 @@
1
+ # just a gem hook
2
+ require_relative "./x_ray_machine"
@@ -0,0 +1,12 @@
1
+ module XRayMachine
2
+ # x-ray all everything!
3
+ end
4
+
5
+ require_relative "./x_ray_machine/version"
6
+ require_relative "./x_ray_machine/x_ray"
7
+ require_relative "./x_ray_machine/config"
8
+ require_relative "./x_ray_machine/log_subscriber"
9
+ require_relative "./x_ray_machine/summary"
10
+ require_relative "./x_ray_machine/railtie"
11
+
12
+ XRay = XRayMachine::XRay
@@ -0,0 +1,79 @@
1
+ module XRayMachine
2
+
3
+ def self.config(&block)
4
+ yield options
5
+ end
6
+
7
+ def self.options
8
+ @options ||= Options.new
9
+ end
10
+
11
+ class Options
12
+ COLORS = {
13
+ red: "\e[31m",
14
+ green: "\e[32m",
15
+ yellow: "\e[33m",
16
+ blue: "\e[34m",
17
+ magenta: "\e[35m",
18
+ cyan: "\e[36m"
19
+ }
20
+
21
+ def initialize
22
+ @streams = {}
23
+ end
24
+
25
+ def method_missing(name, config=nil)
26
+ name = name[0, name.size - 1] if name[name.size - 1] == "="
27
+ name = name.to_sym
28
+
29
+ if config
30
+ @streams[name] = fill_defaults_for(config)
31
+ else
32
+ @streams[name] ||= generate_options_for(name)
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def generate_options_for(name)
39
+ fill_defaults_for title: name.to_s.gsub(/(^|_)([a-z])/) { |m| $2.upcase }
40
+ end
41
+
42
+ def fill_defaults_for(config)
43
+ {
44
+ color: available_colors[0],
45
+ show_in_summary: true
46
+ }.merge config
47
+ end
48
+
49
+ def available_colors
50
+ used_colors = @streams.map{|_,o| o[:color] }.compact
51
+ COLORS.keys - used_colors
52
+ end
53
+ end
54
+
55
+ class Config
56
+ attr_reader :title, :color, :show_in_summary
57
+
58
+ def self.for(stream)
59
+ options = XRayMachine.options.__send__ stream
60
+ title = options[:title]
61
+ color = options[:color]
62
+ show_in_summary = options[:show_in_summary]
63
+
64
+ new title, color, show_in_summary
65
+ end
66
+
67
+ def initialize(title, color, show_in_summary)
68
+ @title = title
69
+ @color = XRayMachine::Options::COLORS[color] || XRayMachine::Options::COLORS[:red]
70
+ @show_in_summary = show_in_summary
71
+ end
72
+
73
+ alias :show_in_summary? :show_in_summary
74
+
75
+ def to_h
76
+ {title: title, color: color, show_in_summary: show_in_summary}
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,23 @@
1
+ module XRayMachine
2
+ class LogSubscriber < ActiveSupport::LogSubscriber
3
+ def self.runtimes
4
+ Thread.current["x_ray_machine_runtimes"] ||= Hash.new{|k,_| 0}
5
+ end
6
+
7
+ def self.reset_runtimes
8
+ Thread.current["x_ray_machine_runtimes"] = nil
9
+ end
10
+
11
+ def request(event)
12
+ group = event.payload[:group]
13
+ config = XRayMachine::Config.for(group)
14
+
15
+ self.class.runtimes[group] += event.duration
16
+
17
+ name = config.title
18
+ name += " CACHE" if event.payload[:cache]
19
+ name = '%s (%.1fms)' % [name, event.duration]
20
+ debug " #{color(name, config.color, true)} #{event.payload[:query]}"
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,13 @@
1
+ module XRayMachine
2
+ class Railtie < Rails::Railtie
3
+ railtie_name :x_ray_machine
4
+
5
+ config.before_initialize do |app|
6
+ XRayMachine::LogSubscriber.attach_to :xraymachine
7
+
8
+ ActiveSupport.on_load(:action_controller) do
9
+ include XRayMachine::Summary::Runtime
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,41 @@
1
+ module XRayMachine
2
+ class Summary
3
+ def self.add(payload)
4
+ payload_sum = XRayMachine::LogSubscriber.runtimes.map{|k,v| v}.inject(0){|a,b| a+b}
5
+
6
+ # most of the times things are lazyloaded
7
+ if payload[:view_runtime] && payload[:view_runtime] > payload_sum
8
+ payload[:view_runtime] -= payload_sum
9
+ end
10
+ end
11
+
12
+ def self.messages
13
+ XRayMachine::LogSubscriber.runtimes.map do |stream_name, duration|
14
+ stream = XRayMachine::Config.for(stream_name)
15
+ if stream.show_in_summary?
16
+ "%s: %.1fms" % [stream.title, duration]
17
+ end
18
+ end.compact
19
+ end
20
+
21
+ module Runtime
22
+ extend ActiveSupport::Concern
23
+
24
+ protected
25
+
26
+ def append_info_to_payload(payload)
27
+ super.tap do
28
+ XRayMachine::Summary.add(payload)
29
+ end
30
+ end
31
+
32
+ module ClassMethods
33
+ def log_process_action(payload)
34
+ super.tap do |messages|
35
+ messages += XRayMachine::Summary.messages
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ module XRayMachine
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,25 @@
1
+ module XRayMachine
2
+ class XRay
3
+ def cached
4
+ @cached || false
5
+ end
6
+
7
+ def cached=(val)
8
+ @cached = val
9
+ end
10
+
11
+ alias :cached? :cached
12
+
13
+ def self.method_missing(name, query, &block)
14
+ options = {group: name, query: query, cache: false}
15
+
16
+ ActiveSupport::Notifications.instrument "request.xraymachine", options do
17
+ ray = XRayMachine::XRay.new
18
+
19
+ block.call(ray).tap do |result|
20
+ options[:cache] = true if ray.cached?
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,55 @@
1
+ require "spec_helper"
2
+
3
+ describe XRayMachine::Config do
4
+
5
+ before { XRayMachine.instance_eval{ @options = nil } }
6
+
7
+ describe ".config" do
8
+
9
+ it "allows to config things" do
10
+ XRayMachine.config do |config|
11
+ config.thing = {title: "Thingy"}
12
+ end
13
+
14
+ expect(XRayMachine.options.instance_variable_get("@streams")).to eq({
15
+ thing: {title: "Thingy", color: :red, show_in_summary: true}
16
+ })
17
+ end
18
+
19
+ it "allows to override colors and the summary settings" do
20
+ XRayMachine.config do |config|
21
+ config.thing = {title: "Thingy", color: :yellow, show_in_summary: false}
22
+ end
23
+
24
+ expect(XRayMachine.options.instance_variable_get("@streams")).to eq({
25
+ thing: {title: "Thingy", color: :yellow, show_in_summary: false}
26
+ })
27
+ end
28
+
29
+ end
30
+
31
+ describe ".for" do
32
+ subject { XRayMachine::Config.for("some_thing").to_h }
33
+
34
+ it "generates a new config if the settings are missing" do
35
+ is_expected.to eq({title: "SomeThing", color: "\e[31m", show_in_summary: true})
36
+ end
37
+
38
+ it "uses the user settings when it configured" do
39
+ XRayMachine.config { |c| c.some_thing = {title: "ST", color: :yellow} }
40
+
41
+ is_expected.to eq({title: "ST", color: "\e[33m", show_in_summary: true})
42
+ end
43
+
44
+ it "returns the same object every time" do
45
+ is_expected.to eq(XRayMachine::Config.for("some_thing").to_h)
46
+ end
47
+
48
+ it "picks different colors for different things" do
49
+ colors = (1..3).to_a.map{|i| XRayMachine::Config.for("thing_#{i}").color }
50
+ expect(colors).to eq ["\e[31m", "\e[32m", "\e[33m"]
51
+ end
52
+
53
+ end
54
+
55
+ end
@@ -0,0 +1,48 @@
1
+ require "spec_helper"
2
+
3
+ describe XRayMachine::LogSubscriber do
4
+ before { XRayMachine::LogSubscriber.reset_runtimes }
5
+
6
+ describe ".runtimes" do
7
+ subject { XRayMachine::LogSubscriber.runtimes }
8
+
9
+ it { is_expected.to be_a Hash }
10
+ it { is_expected.to eq({}) }
11
+
12
+ it "returns the same object all the time" do
13
+ other_object = XRayMachine::LogSubscriber.runtimes
14
+
15
+ is_expected.to be other_object
16
+ end
17
+ end
18
+
19
+ describe "#request" do
20
+ let(:subscriber) { XRayMachine::LogSubscriber.new }
21
+ let(:event) { double("Event", duration: 11, payload: payload) }
22
+ let(:payload) { {query: "some/query/data", cache: false, group: "external_api"} }
23
+
24
+ subject { subscriber.request(event) }
25
+
26
+ before do
27
+ def subscriber.debug(string=nil)
28
+ @debug ||= string
29
+ end
30
+ end
31
+
32
+ it "saves the duration in the runtimes list" do
33
+ expect{ subject }.to change{ XRayMachine::LogSubscriber.runtimes }.to({"external_api" => 11})
34
+ end
35
+
36
+ it "dumps the data in the debugging stream" do
37
+ expect{ subject }.to change{ subscriber.debug }
38
+ .to(" \e[1m\e[34mExternalApi (11.0ms)\e[0m some/query/data")
39
+ end
40
+
41
+ it "marks things cached when the payload have a cache:true option" do
42
+ payload[:cache] = true
43
+
44
+ expect{ subject }.to change{ subscriber.debug }
45
+ .to(" \e[1m\e[34mExternalApi CACHE (11.0ms)\e[0m some/query/data")
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,55 @@
1
+ require "spec_helper"
2
+
3
+ describe XRayMachine::Summary do
4
+
5
+ before do
6
+ XRayMachine.instance_eval { @options = nil }
7
+ XRayMachine::LogSubscriber.reset_runtimes
8
+ XRayMachine::LogSubscriber.runtimes.merge!({
9
+ one: 11, two: 22, three: 33
10
+ })
11
+ end
12
+
13
+ describe ".add" do
14
+ let(:payload) { {view_runtime: 123} }
15
+
16
+ subject { XRayMachine::Summary.add(payload) }
17
+
18
+ it "substracts the custom runtime from the views runtime" do
19
+ expect{ subject }.to change{ payload }.to({view_runtime: 57})
20
+ end
21
+
22
+ it "doesn't change the view runtime when it's less than the recorded rintimes" do
23
+ payload[:view_runtime] = 10
24
+
25
+ expect{ subject }.not_to change{ payload }
26
+ end
27
+
28
+ it "doesn't explode when the view data is missing" do
29
+ payload.delete :view_runtime
30
+
31
+ expect{ subject }.not_to raise_error
32
+ end
33
+ end
34
+
35
+ describe ".messages" do
36
+ subject { XRayMachine::Summary.messages }
37
+
38
+ it "generates a list of summary messages from the recorded runtimes" do
39
+ is_expected.to eq ["One: 11.0ms", "Two: 22.0ms", "Three: 33.0ms"]
40
+ end
41
+
42
+ it "respect the title settings" do
43
+ XRayMachine.config{ |c| c.one = {title: "Custom One"} }
44
+
45
+ is_expected.to eq ["Custom One: 11.0ms", "Two: 22.0ms", "Three: 33.0ms"]
46
+ end
47
+
48
+ it "hides runtimes that are configured to be hidden from the summary" do
49
+ XRayMachine.config{ |c| c.one = {show_in_summary: false} }
50
+
51
+ is_expected.to eq ["Two: 22.0ms", "Three: 33.0ms"]
52
+ end
53
+ end
54
+
55
+ end
@@ -0,0 +1,44 @@
1
+ require "spec_helper"
2
+
3
+ describe XRay do
4
+
5
+ before do
6
+ ActiveSupport::Notifications.instance_eval do
7
+ def self.instrument(*args, &block)
8
+ @args = args
9
+ yield
10
+ end
11
+ end
12
+ end
13
+
14
+ def active_support_args
15
+ ActiveSupport::Notifications.instance_eval { @args }
16
+ end
17
+
18
+ describe ".method_missing" do
19
+ it "runs whatevers" do
20
+ XRay.whatevers "query/data" do
21
+ end
22
+
23
+ expect(active_support_args).to eq [
24
+ "request.xraymachine", {group: :whatevers, query: "query/data", cache: false}
25
+ ]
26
+ end
27
+
28
+ it "returns whatever the block yields" do
29
+ result = XRay.whatevers("query/data") { "yielded result" }
30
+ expect(result).to eq "yielded result"
31
+ end
32
+
33
+ it "sends a ray in and allows to mark it as cached" do
34
+ XRay.whatevers "query/data" do |ray|
35
+ ray.cached = true
36
+ end
37
+
38
+ expect(active_support_args).to eq [
39
+ "request.xraymachine", {group: :whatevers, query: "query/data", cache: true}
40
+ ]
41
+ end
42
+ end
43
+
44
+ end
@@ -0,0 +1,10 @@
1
+ require "rails"
2
+ require File.dirname(__FILE__)+ "/../lib/x_ray_machine"
3
+
4
+ RSpec.configure do |config|
5
+ config.raise_errors_for_deprecations!
6
+
7
+ config.expect_with :rspec do |c|
8
+ c.syntax = :expect
9
+ end
10
+ end
@@ -0,0 +1,23 @@
1
+ require File.dirname(__FILE__)+ '/lib/x_ray_machine/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "x-ray-machine"
5
+ spec.version = XRayMachine::VERSION
6
+ spec.authors = ["Nikolay Nemshilov"]
7
+ spec.email = ["nemshilov@gmail.com"]
8
+ spec.description = "Better instrumentation/logging utility for Rails"
9
+ spec.summary = "Better instrumentation/logging utility for Rails. Seriously"
10
+ spec.homepage = "https://github.com/MadRabbit/x-ray-machine"
11
+ spec.license = "MIT"
12
+
13
+ spec.files = `git ls-files`.split($/)
14
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
15
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
16
+ spec.require_paths = ["lib"]
17
+
18
+ spec.add_runtime_dependency 'rails', '~> 4.0', '>= 4.0.0'
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.7"
21
+ spec.add_development_dependency "rspec", "~> 3.1"
22
+ spec.add_development_dependency "guard-rspec", "~> 4.3"
23
+ end
Binary file
metadata ADDED
@@ -0,0 +1,162 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: x-ray-machine
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Nikolay Nemshilov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-12-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 4.0.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '4.0'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 4.0.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: bundler
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.7'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.7'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rspec
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '3.1'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '3.1'
61
+ - !ruby/object:Gem::Dependency
62
+ name: guard-rspec
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '4.3'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '4.3'
75
+ description: Better instrumentation/logging utility for Rails
76
+ email:
77
+ - nemshilov@gmail.com
78
+ executables:
79
+ - bundler
80
+ - coderay
81
+ - erubis
82
+ - guard
83
+ - htmldiff
84
+ - ldiff
85
+ - listen
86
+ - pry
87
+ - rackup
88
+ - rails
89
+ - rake
90
+ - rspec
91
+ - sprockets
92
+ - thor
93
+ - tilt
94
+ extensions: []
95
+ extra_rdoc_files: []
96
+ files:
97
+ - ".gitignore"
98
+ - ".rspec"
99
+ - Gemfile
100
+ - Gemfile.lock
101
+ - Guardfile
102
+ - README.md
103
+ - bin/bundler
104
+ - bin/coderay
105
+ - bin/erubis
106
+ - bin/guard
107
+ - bin/htmldiff
108
+ - bin/ldiff
109
+ - bin/listen
110
+ - bin/pry
111
+ - bin/rackup
112
+ - bin/rails
113
+ - bin/rake
114
+ - bin/rspec
115
+ - bin/sprockets
116
+ - bin/thor
117
+ - bin/tilt
118
+ - lib/x-ray-machine.rb
119
+ - lib/x_ray_machine.rb
120
+ - lib/x_ray_machine/config.rb
121
+ - lib/x_ray_machine/log_subscriber.rb
122
+ - lib/x_ray_machine/railtie.rb
123
+ - lib/x_ray_machine/summary.rb
124
+ - lib/x_ray_machine/version.rb
125
+ - lib/x_ray_machine/x_ray.rb
126
+ - spec/lib/x_ray_machine/config_spec.rb
127
+ - spec/lib/x_ray_machine/log_subscriber_spec.rb
128
+ - spec/lib/x_ray_machine/summary_spec.rb
129
+ - spec/lib/x_ray_machine/x_ray_spec.rb
130
+ - spec/spec_helper.rb
131
+ - x-ray-machine.gemspec
132
+ - x-ray.jpg
133
+ homepage: https://github.com/MadRabbit/x-ray-machine
134
+ licenses:
135
+ - MIT
136
+ metadata: {}
137
+ post_install_message:
138
+ rdoc_options: []
139
+ require_paths:
140
+ - lib
141
+ required_ruby_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ required_rubygems_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ requirements: []
152
+ rubyforge_project:
153
+ rubygems_version: 2.2.2
154
+ signing_key:
155
+ specification_version: 4
156
+ summary: Better instrumentation/logging utility for Rails. Seriously
157
+ test_files:
158
+ - spec/lib/x_ray_machine/config_spec.rb
159
+ - spec/lib/x_ray_machine/log_subscriber_spec.rb
160
+ - spec/lib/x_ray_machine/summary_spec.rb
161
+ - spec/lib/x_ray_machine/x_ray_spec.rb
162
+ - spec/spec_helper.rb