x-ray-machine 1.0.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.
@@ -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