lograge 0.0.1
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/.gitignore +4 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/Guardfile +9 -0
- data/README.md +112 -0
- data/Rakefile +1 -0
- data/lib/lograge.rb +37 -0
- data/lib/lograge/log_subscriber.rb +35 -0
- data/lib/lograge/rails_ext/rack/logger.rb +23 -0
- data/lib/lograge/railtie.rb +12 -0
- data/lib/lograge/version.rb +3 -0
- data/lograge.gemspec +26 -0
- data/spec/lograge_logsubscriber_spec.rb +81 -0
- data/spec/lograge_spec.rb +40 -0
- data/spec/spec_helper.rb +11 -0
- metadata +109 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
Lograge - Taming Rails' Default Request Logging
|
2
|
+
=======
|
3
|
+
|
4
|
+
Lograge is an attempt to bring sanity to Rails' noisy and unusable, unparsable
|
5
|
+
and, in the context of running multiple processes and servers, unreadable
|
6
|
+
default logging output. Rails' default approach to log everything is great
|
7
|
+
during development, it's terrible when running it in production. It pretty much
|
8
|
+
renders Rails logs useless to me.
|
9
|
+
|
10
|
+
Instead of trying solving the problem of having multiple lines per request by
|
11
|
+
switching Rails' logger for something that outputs syslog lines or adds a
|
12
|
+
request token, Lograge replaces Rails' request logging entirely, reducing the
|
13
|
+
output per request to a single line with all the important information, removing
|
14
|
+
all that clutter Rails likes to include and that gets mingled up so nicely when
|
15
|
+
multiple processes dump their output into a single file.
|
16
|
+
|
17
|
+
Instead of having an unparsable amount of logging output like this:
|
18
|
+
|
19
|
+
```
|
20
|
+
Started GET "/" for 127.0.0.1 at 2012-03-10 14:28:14 +0100
|
21
|
+
Processing by HomeController#index as HTML
|
22
|
+
Rendered text template within layouts/application (0.0ms)
|
23
|
+
Rendered layouts/_assets.html.erb (2.0ms)
|
24
|
+
Rendered layouts/_top.html.erb (2.6ms)
|
25
|
+
Rendered layouts/_about.html.erb (0.3ms)
|
26
|
+
Rendered layouts/_google_analytics.html.erb (0.4ms)
|
27
|
+
Completed 200 OK in 79ms (Views: 78.8ms | ActiveRecord: 0.0ms)
|
28
|
+
```
|
29
|
+
|
30
|
+
you get a single line with all the important information, like this:
|
31
|
+
|
32
|
+
```
|
33
|
+
GET /jobs/833552.json format=json action=jobs#show status=200 duration=58.33 view=40.43 db=15.26
|
34
|
+
```
|
35
|
+
|
36
|
+
The second line is easy to grasp with a single glance and still includes all the
|
37
|
+
relevant information as simple key-value pairs. The syntax is heavily inspired
|
38
|
+
by the log output of the Heroku router. It doesn't include any timestamp by
|
39
|
+
default, instead it assumes you use a proper log formatter instead.
|
40
|
+
|
41
|
+
**Installation**
|
42
|
+
|
43
|
+
In your Gemfile
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
gem "lograge"
|
47
|
+
```
|
48
|
+
|
49
|
+
Enable it for the relevant environments, e.g. production:
|
50
|
+
|
51
|
+
```
|
52
|
+
# config/environments/production.rb
|
53
|
+
MyApp::Application.configure do
|
54
|
+
config.lograge.enabled = true
|
55
|
+
end
|
56
|
+
```
|
57
|
+
|
58
|
+
Done.
|
59
|
+
|
60
|
+
**Internals**
|
61
|
+
|
62
|
+
Thanks to the notification system that was introduced in Rails 3, replacing the
|
63
|
+
logging is easy. Lograge unhooks all subscriptions from
|
64
|
+
`ActionController::LogSubscriber` and `ActionView::LogSubscriber`, and hooks in
|
65
|
+
its own log subscription, but only listening for two events: `process_action`
|
66
|
+
and `redirect_to`. It makes sure that only subscriptions from those two classes
|
67
|
+
are removed. If you happened to hook in your own, they'll be safe.
|
68
|
+
|
69
|
+
Unfortunately, when a redirect is triggered by your application's code,
|
70
|
+
ActionController fires two events. One for the redirect itself, and another one
|
71
|
+
when the request is finished. Unfortunately the final event doesn't include the
|
72
|
+
redirect, so Lograge stores the redirect URL as a thread-local attribute and
|
73
|
+
refers to it in `process_action`.
|
74
|
+
|
75
|
+
The event itself contains most of the relevant information to build up the log
|
76
|
+
line, including view processing and database access times.
|
77
|
+
|
78
|
+
While the LogSubscribers encapsulate most logging pretty nicely, there are still
|
79
|
+
two lines that show up no matter what. The first line that's output for every
|
80
|
+
Rails request, you know, this one:
|
81
|
+
|
82
|
+
And the verbose output coming from rack-cache:
|
83
|
+
|
84
|
+
Both are independent of the LogSubscribers, and both need to be shut up using
|
85
|
+
different means.
|
86
|
+
|
87
|
+
For the first one, the starting line of every Rails request log, Lograge removes
|
88
|
+
the `Rails::Rack::Logger` middleware from the stack. This may look like a drastic
|
89
|
+
means, but all the middleware does is log that useless line, log exceptions, and
|
90
|
+
create a request transaction id (Rails 3.2). A future version may replace with
|
91
|
+
its own middleware, that simply removes the log line.
|
92
|
+
|
93
|
+
To remove rack-cache's output (which is only enabled if caching in Rails is
|
94
|
+
enabled), Lograge disables verbosity for rack-cache, which is unfortunately
|
95
|
+
enabled by default.
|
96
|
+
|
97
|
+
There, a single line per request. Beautiful.
|
98
|
+
|
99
|
+
**What it doesn't do**
|
100
|
+
|
101
|
+
Lograge removes ActionView logging, which also includes rendering times for
|
102
|
+
partials. If you're into those, Lograge is probably not for you. In my honest
|
103
|
+
opinion, those rendering times don't belong in the log file, they should be
|
104
|
+
collected in a system like New Relic, Librato Metrics or some other metrics
|
105
|
+
service that allows graphing rendering percentiles. I assume this for everything
|
106
|
+
that represents a moving target. That kind of data is better off being
|
107
|
+
visualized in graphs than dumped (and ignored) in a log file.
|
108
|
+
|
109
|
+
**License**
|
110
|
+
|
111
|
+
MIT. Code extracted from [Travis CI](http://travis-ci.org).
|
112
|
+
(c) 2012 Mathias Meyer
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/lograge.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'lograge/version'
|
2
|
+
require 'lograge/log_subscriber'
|
3
|
+
require 'active_support/core_ext/module/attribute_accessors'
|
4
|
+
require 'active_support/core_ext/string/inflections'
|
5
|
+
require 'active_support/ordered_options'
|
6
|
+
|
7
|
+
module Lograge
|
8
|
+
mattr_accessor :logger
|
9
|
+
|
10
|
+
def self.remove_existing_log_subscriptions
|
11
|
+
%w(redirect_to process_action start_processing send_data write_fragment exist_fragment? send_file).each do |event|
|
12
|
+
unsubscribe_from_event(:action_controller, event)
|
13
|
+
end
|
14
|
+
|
15
|
+
%w{render_template render_partial render_collection}.each do |event|
|
16
|
+
unsubscribe_from_event(:action_view, event)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.unsubscribe_from_event(component, event)
|
21
|
+
delegate_type = component.to_s.classify
|
22
|
+
ActiveSupport::Notifications.notifier.listeners_for("#{event}.#{component}").each do |listener|
|
23
|
+
if listener.inspect =~ /delegate[^a-z]+#{delegate_type}/
|
24
|
+
ActiveSupport::Notifications.unsubscribe listener
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.setup(app)
|
30
|
+
app.config.action_dispatch.rack_cache[:verbose] = false
|
31
|
+
require 'lograge/rails_ext/rack/logger'
|
32
|
+
Lograge.remove_existing_log_subscriptions
|
33
|
+
Lograge::RequestLogSubscriber.attach_to :action_controller
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
require 'lograge/railtie' if defined?(Rails)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'active_support/core_ext/class/attribute'
|
2
|
+
require 'active_support/log_subscriber'
|
3
|
+
|
4
|
+
module Lograge
|
5
|
+
class RequestLogSubscriber < ActiveSupport::LogSubscriber
|
6
|
+
def process_action(event)
|
7
|
+
payload = event.payload
|
8
|
+
message = "#{payload[:method]} #{payload[:path]} format=#{payload[:format]} action=#{payload[:params]['controller']}##{payload[:params]['action']}"
|
9
|
+
message << extract_status(payload)
|
10
|
+
message << runtimes(event)
|
11
|
+
logger.info(message)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def extract_status(payload)
|
17
|
+
if payload[:status]
|
18
|
+
" status=#{payload[:status]}"
|
19
|
+
elsif payload[:exception]
|
20
|
+
exception, message = payload[:exception]
|
21
|
+
" status=500 error='#{exception}:#{message}'"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def runtimes(event)
|
26
|
+
message = ""
|
27
|
+
{:duration => event.duration,
|
28
|
+
:view => event.payload[:view_runtime],
|
29
|
+
:db => event.payload[:db_runtime]}.each do |name, runtime|
|
30
|
+
message << " #{name}=%.2f" % runtime if runtime
|
31
|
+
end
|
32
|
+
message
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rails/rack/logger'
|
2
|
+
|
3
|
+
module Rails
|
4
|
+
module Rack
|
5
|
+
# Overwrites defaults of Rails::Rack::Logger that cause
|
6
|
+
# unnecessary logging.
|
7
|
+
# This effectively removes the log lines from the log
|
8
|
+
# that say:
|
9
|
+
# Started GET / for 192.168.2.1...
|
10
|
+
class Logger
|
11
|
+
# Overwrites Rails 3.2 code that logs new requests
|
12
|
+
def call_app(env)
|
13
|
+
@app.call(env)
|
14
|
+
ensure
|
15
|
+
ActiveSupport::LogSubscriber.flush_all!
|
16
|
+
end
|
17
|
+
|
18
|
+
# Overwrites Rails 3.0/3.1 code that logs new requests
|
19
|
+
def before_dispatch(env)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'rails/railtie'
|
2
|
+
|
3
|
+
module Lograge
|
4
|
+
class Railtie < Rails::Railtie
|
5
|
+
config.lograge = ActiveSupport::OrderedOptions.new
|
6
|
+
config.lograge.enabled = false
|
7
|
+
|
8
|
+
initializer :lograge do |app|
|
9
|
+
Lograge.setup(app) if app.config.lograge.enabled
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lograge.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "lograge/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "lograge"
|
7
|
+
s.version = Lograge::VERSION
|
8
|
+
s.authors = ["Mathias Meyer"]
|
9
|
+
s.email = ["meyer@paperplanes.de"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Tame Rails' multi-line logging into a single line per request}
|
12
|
+
s.description = %q{Tame Rails' multi-line logging into a single line per request}
|
13
|
+
|
14
|
+
s.rubyforge_project = "lograge"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
s.add_development_dependency "rspec"
|
23
|
+
s.add_development_dependency "guard-rspec"
|
24
|
+
s.add_runtime_dependency "activesupport"
|
25
|
+
s.add_runtime_dependency "actionpack"
|
26
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'lograge/log_subscriber'
|
3
|
+
require 'active_support/notifications'
|
4
|
+
require 'active_support/core_ext/string'
|
5
|
+
require 'logger'
|
6
|
+
|
7
|
+
describe Lograge::RequestLogSubscriber do
|
8
|
+
let(:log_output) {StringIO.new}
|
9
|
+
let(:logger) {
|
10
|
+
logger = Logger.new(log_output)
|
11
|
+
logger.formatter = ->(_, _, _, msg) {
|
12
|
+
msg
|
13
|
+
}
|
14
|
+
logger
|
15
|
+
}
|
16
|
+
before do
|
17
|
+
Lograge::RequestLogSubscriber.logger = logger
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:subscriber) {Lograge::RequestLogSubscriber.new}
|
21
|
+
let(:event) {
|
22
|
+
ActiveSupport::Notifications::Event.new(
|
23
|
+
'process_action.action_controller', Time.now, Time.now, 2, {
|
24
|
+
status: 200, format: 'application/json', method: 'GET', path: '/home', params: {
|
25
|
+
'controller' => 'home', 'action' => 'index'
|
26
|
+
}, db_runtime: 0.02, view_runtime: 0.01
|
27
|
+
}
|
28
|
+
)
|
29
|
+
}
|
30
|
+
|
31
|
+
let(:redirect) {
|
32
|
+
ActiveSupport::Notifications::Event.new(
|
33
|
+
'redirect_to.action_controller', Time.now, Time.now, 1, location: 'http://example.com', status: 302
|
34
|
+
)
|
35
|
+
}
|
36
|
+
|
37
|
+
describe "when processing an action" do
|
38
|
+
it "should include the URL in the log output" do
|
39
|
+
subscriber.process_action(event)
|
40
|
+
log_output.string.should include('/home')
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should start the log line with the HTTP method" do
|
44
|
+
subscriber.process_action(event)
|
45
|
+
log_output.string.starts_with?('GET').should == true
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should include the status code" do
|
49
|
+
subscriber.process_action(event)
|
50
|
+
log_output.string.should include('status=200')
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should include the controller and action" do
|
54
|
+
subscriber.process_action(event)
|
55
|
+
log_output.string.should include('action=home#index')
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should include the duration" do
|
59
|
+
subscriber.process_action(event)
|
60
|
+
log_output.string.should =~ /duration=[\.0-9]{4,4}/
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should include the view rendering time" do
|
64
|
+
subscriber.process_action(event)
|
65
|
+
log_output.string.should =~ /view=0.01/
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should include the database rendering time" do
|
69
|
+
subscriber.process_action(event)
|
70
|
+
log_output.string.should =~ /db=0.02/
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should add a 500 status when an exception occurred" do
|
74
|
+
event.payload[:status] = nil
|
75
|
+
event.payload[:exception] = ['AbstractController::ActionNotFound', 'Route not found']
|
76
|
+
subscriber.process_action(event)
|
77
|
+
log_output.string.should =~ /status=500/
|
78
|
+
log_output.string.should =~ /error='AbstractController::ActionNotFound:Route not found'/
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'lograge'
|
3
|
+
require 'active_support/notifications'
|
4
|
+
require 'active_support/core_ext/string'
|
5
|
+
require 'active_support/log_subscriber'
|
6
|
+
require 'action_controller/log_subscriber'
|
7
|
+
require 'action_view/log_subscriber'
|
8
|
+
|
9
|
+
describe Lograge do
|
10
|
+
describe "when removing Rails' log subscribers" do
|
11
|
+
after do
|
12
|
+
ActionController::LogSubscriber.attach_to :action_controller
|
13
|
+
ActionView::LogSubscriber.attach_to :action_view
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should remove subscribers for controller events" do
|
17
|
+
expect {
|
18
|
+
Lograge.remove_existing_log_subscriptions
|
19
|
+
}.to change {
|
20
|
+
ActiveSupport::Notifications.notifier.listeners_for('process_action.action_controller')
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should remove subscribers for all events" do
|
25
|
+
expect {
|
26
|
+
Lograge.remove_existing_log_subscriptions
|
27
|
+
}.to change {
|
28
|
+
ActiveSupport::Notifications.notifier.listeners_for('render_template.action_view')
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
it "shouldn't remove subscribers that aren't from Rails" do
|
33
|
+
blk = -> {}
|
34
|
+
ActiveSupport::Notifications.subscribe("process_action.action_controller", &blk)
|
35
|
+
Lograge.remove_existing_log_subscriptions
|
36
|
+
listeners = ActiveSupport::Notifications.notifier.listeners_for('process_action.action_controller')
|
37
|
+
listeners.size.should > 0
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,11 @@
|
|
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.rb"` 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
|
+
end
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lograge
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Mathias Meyer
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-03-11 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &70337094742500 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70337094742500
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: guard-rspec
|
27
|
+
requirement: &70337094741880 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70337094741880
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: activesupport
|
38
|
+
requirement: &70337094740860 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70337094740860
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: actionpack
|
49
|
+
requirement: &70337094739040 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70337094739040
|
58
|
+
description: Tame Rails' multi-line logging into a single line per request
|
59
|
+
email:
|
60
|
+
- meyer@paperplanes.de
|
61
|
+
executables: []
|
62
|
+
extensions: []
|
63
|
+
extra_rdoc_files: []
|
64
|
+
files:
|
65
|
+
- .gitignore
|
66
|
+
- .rspec
|
67
|
+
- .travis.yml
|
68
|
+
- Gemfile
|
69
|
+
- Guardfile
|
70
|
+
- README.md
|
71
|
+
- Rakefile
|
72
|
+
- lib/lograge.rb
|
73
|
+
- lib/lograge/log_subscriber.rb
|
74
|
+
- lib/lograge/rails_ext/rack/logger.rb
|
75
|
+
- lib/lograge/railtie.rb
|
76
|
+
- lib/lograge/version.rb
|
77
|
+
- lograge.gemspec
|
78
|
+
- spec/lograge_logsubscriber_spec.rb
|
79
|
+
- spec/lograge_spec.rb
|
80
|
+
- spec/spec_helper.rb
|
81
|
+
homepage: ''
|
82
|
+
licenses: []
|
83
|
+
post_install_message:
|
84
|
+
rdoc_options: []
|
85
|
+
require_paths:
|
86
|
+
- lib
|
87
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
88
|
+
none: false
|
89
|
+
requirements:
|
90
|
+
- - ! '>='
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
requirements: []
|
100
|
+
rubyforge_project: lograge
|
101
|
+
rubygems_version: 1.8.11
|
102
|
+
signing_key:
|
103
|
+
specification_version: 3
|
104
|
+
summary: Tame Rails' multi-line logging into a single line per request
|
105
|
+
test_files:
|
106
|
+
- spec/lograge_logsubscriber_spec.rb
|
107
|
+
- spec/lograge_spec.rb
|
108
|
+
- spec/spec_helper.rb
|
109
|
+
has_rdoc:
|