superlogger 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +82 -0
- data/Rakefile +34 -0
- data/lib/superlogger.rb +54 -0
- data/lib/superlogger/action_controller_log_subscriber.rb +35 -0
- data/lib/superlogger/action_dispatch_debug_exceptions.rb +11 -0
- data/lib/superlogger/action_view_log_subscriber.rb +13 -0
- data/lib/superlogger/active_record_log_subscriber.rb +29 -0
- data/lib/superlogger/logger.rb +79 -0
- data/lib/superlogger/middleware.rb +31 -0
- data/lib/superlogger/rails_rack_logger.rb +11 -0
- data/lib/superlogger/railtie.rb +7 -0
- data/lib/superlogger/version.rb +3 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/controllers/home_controller.rb +5 -0
- data/test/dummy/app/models/something.rb +2 -0
- data/test/dummy/app/views/home/_partial.html.erb +0 -0
- data/test/dummy/app/views/home/index.html.erb +3 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +25 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +41 -0
- data/test/dummy/config/environments/production.rb +79 -0
- data/test/dummy/config/environments/test.rb +42 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +3 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/migrate/20160120090718_create_somethings.rb +10 -0
- data/test/dummy/db/schema.rb +23 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +294 -0
- data/test/dummy/log/test.log +1672 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/5L/5Lly_CA8DZvPhQV2jDQx-Y6P_y3Ygra9t5jfSlGhHDA.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/7J/7JXLU3kClrFYffhxcnNaLGjYz8LFI700NBjNiBOifaU.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/C_/C_C8IqUQirTZx1bt5Ewm3QJvhVbwm66pxvcH0maphFY.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Ch/Ch2bQFHkYziI9Erdkuj8uoPJyw0W2aA5prtYAqlccww.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/DS/DSOLSc6A5RVSmvM415eEWAWG_AgOvZcLZOXQjsXyWQA.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Gy/Gyqn3Ja6WbUSqKnvWm9Xw7FIxFqJIPQ88IlgpguMo1s.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/H3/H3tvaQM-yTy-25oSLlfjToAa74LSJHBDUpji-8C-eLg.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Iv/IvDM1j8-H1H6kEjVCsyIW8N2zla-aIp9q_OE9PVZtVw.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/K9/K9ZheMi0hi4DNLzmDMRnv9A_lOVz33kNImc16Now42o.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/LH/LHgjtAV8kdldaJ_dX0RCznzjmWYRuLdhU29fZCJ0VmU.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Nn/NnUCa7jNYx9HCmEB7E7WPWT00DwaM4IYICy1Ju1jjcs.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/OI/OI6uxGcnsKavdWTtwDAasU3wPx8QXhzBgV0X2n1KjMQ.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Ol/OlBX9JIv9SAOmK2t35x1SYDx1sxCXF0yvqpna3WMyH0.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Yr/YrZ0OIHu42cExs1kqngMA6ShVDKhfGmhyW-E9haNo5Y.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/ZU/ZUokoeZcfmoTFE9YAHZRhTgceOUGJTDGH__SCqPfkqU.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/_I/_IocgQl8XVm84HohovEBj-GxsSeBkOpqN-94yHgY-K8.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/bJ/bJVgCoQDvMv4iocjEuC3z3WqSeK7LXgxDJ-eXaHl0l4.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/b_/b_-O1DwVvDk3vPJ-GHDgGWR9Zth9CYblcXbBe6aiTf0.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/br/brSVWTme0G1yzUMjrDpklxoQetdFLXdF8ZUkYXFX-sE.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/cI/cIaWfk6Nq6ZAr0fhtHGTBtsRITI5n8IJFZbClZ2tExw.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/g3/g3x0V2jnf5A31QMz4xGeQMouu2eChQRpoe0BEWWESeY.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/gV/gVVPZef0xfm7t9Jyesa7ZVdnpzMpw2QtOyYUoEXO7fk.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/gZ/gZp3uXMHuYQC4hzCr7bQfetKNdJAtbQmg3so2KpW1Dw.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/gp/gpiWtnqpufka8lRtMznM6Ko0aWJrcH_j8cfZwdYmzNI.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/hZ/hZi1k6tpxxCGYxRe7zY74ItcOI8gZrREOpGuA8JSpGg.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/i7/i7v4b6OSQUj-1r9vUWRiOHjAVksSTpUfilZTpk0ACLc.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/kz/kzdSvu57G4i6eTuarsZCAfbhbICnkRa0Xhi0b9ua6qk.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/pE/pEhaat2KBd5SrT7szC_8R1_6hK17FTpvoRFkmCRSD3M.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/rC/rCO5-bHVJ6Y_GsPBmOPUL23pfjvc2Gw2zt_ODmZsygw.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/rg/rghMLGUpm1Uy3OPgfILHnVwLCycV9Rd9kSpEbxdwVV4.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/vm/vm9zMjZUFULeJsYWRoDd3cvnEpLGK-E5XTk30_NQTEs.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/wD/wDDl7jzOUTDgFcG1JlpN6jVHavfzB8Smsjtl3d8WDx0.cache +1 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/-Z_pj4kfRj993e_ypawYQUIDIDKcRe569udVq_1drFs.cache +1 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/2G0Z7Q5fvf2xX8ygtwcD9vZq-kwEzoV2MFc1URegs7s.cache +1 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/5Lly_CA8DZvPhQV2jDQx-Y6P_y3Ygra9t5jfSlGhHDA.cache +2 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/66bWF3byFzdKpXZsrn5Vy9CJBaDlkJKkoyqeLRRbBZY.cache +0 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/9NtfUddiu2UU8sqL-bYq-NPAx8NGp5m5AYiAWAcKQQ4.cache +0 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/DSOLSc6A5RVSmvM415eEWAWG_AgOvZcLZOXQjsXyWQA.cache +2 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/GELqHyWyVR_UvkpZPDb5xjZrCgkKB5G067DYoMwTjEA.cache +0 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/Gyqn3Ja6WbUSqKnvWm9Xw7FIxFqJIPQ88IlgpguMo1s.cache +1 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/H5fHMceViwaxMKkefsdMmVpBN3rRYZI1obJX5Jn-4jw.cache +1 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/IEJfj4Zwfra6y7iF-BOVR9PPIQeL9L5IiZT8MRqpCXg.cache +0 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/IordxSS9mOh1mkt2VyfX7Iz4DhZhy73lccOYxcw5aVU.cache +1 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/KgQHhqXCaYHJSJEG6JweQVe1a2rC-mHfkrqD9p9taTU.cache +2 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/Ki_R5uSCGEm1Jn7TSbJOc3eBMn4Q3_IPLG0r_RRn9lA.cache +1 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/NBBjlBjfPdkZkp4G7VCEA9LAeGycMn10CxLbDAbNeHc.cache +0 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/OI6uxGcnsKavdWTtwDAasU3wPx8QXhzBgV0X2n1KjMQ.cache +2 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/V9m2At1eKJAvbGAFvFTUt8hcdNI-G8xW1AShyPYS4Ys.cache +1 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/XsDQ8X8Klh__7HZNZk8sjYzyFg5TmATqo-_UraArzN8.cache +1 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/ZtbyFLml01tdqcRh4Ocz6XOkbPpmHM6nFRRYY4Nphpc.cache +1 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/_ZNMI9IrCfXNcrwiRGttWiFPcLlCSpkdJSFoLhmUpyg.cache +0 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/brSVWTme0G1yzUMjrDpklxoQetdFLXdF8ZUkYXFX-sE.cache +1 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/gZp3uXMHuYQC4hzCr7bQfetKNdJAtbQmg3so2KpW1Dw.cache +2 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/hZi1k6tpxxCGYxRe7zY74ItcOI8gZrREOpGuA8JSpGg.cache +2 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/jqyQL40gGhkqnPg3IttXbq8JGHLONBjR0MlrN9HeIvU.cache +1 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/kqQAJDpBuiNJ3XEy8VjtVcyUB9BVlP02oDMdVnlL04w.cache +0 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/pEhaat2KBd5SrT7szC_8R1_6hK17FTpvoRFkmCRSD3M.cache +2 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/pnW3u_1AN48ig6ngefI89y96xoSlvnJurx-e3J-leoE.cache +2 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/q9kUTJTzJpwJJQ8CoWPFc_eCW76RZgB-R2sc4P84y6c.cache +0 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/qFlPbNZ3UJs9EnENWVEbNWnrTEcjZkAQUzH55y3Ymi0.cache +1 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/r86oWGkKGjcta2GtxqeESX1w_4FX1c_DWHxPWVKP28A.cache +1 -0
- data/test/dummy/tmp/cache/sprockets/v3.0/ssS2x0Wl67rwXHaVHsh6CO7ayn9fQ5saIwATKN6O-nI.cache +2 -0
- data/test/superlogger_test.rb +134 -0
- data/test/test_helper.rb +19 -0
- metadata +299 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a8233a0f1140b23ad1a79d954256e9f406e7dbf4
|
4
|
+
data.tar.gz: 7fc49063ae14c89e033a224dc619e878401d8f33
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5bf2ca0272093a2b54928be31590756f57ddb0fb959c0fc4fc37cdd074cdaf51adbc903bfd5d549705708b53269e312afeb20ac04af50dec472ff41e7c4082c8
|
7
|
+
data.tar.gz: 1b181052bfb35cc721824dde111d9d87b4aadc0b8605d944b7c1657e0afff478a1b2052c6033b8df04f64f262de53b84744c709c177bed20985f9799ae8cafef
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2016 Soh Yu Ming
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
Superlogger - Machine-readable logging for Rails [![Build Status](https://travis-ci.org/moexmen/superlogger.svg?branch=master)](https://travis-ci.org/moexmen/superlogger)
|
2
|
+
=======
|
3
|
+
|
4
|
+
Rails' default request logging is easy to read for humans but difficult for log aggregators such as Kibana, Graylog and Splunk. Superlogger transforms the logs into key-value pairs for easy parsing and adds useful details like Timestamp and Session ID for tracing purposes.
|
5
|
+
|
6
|
+
Default rails logging:
|
7
|
+
```sh
|
8
|
+
Started GET "/home/index" for ::1 at 2016-04-11 16:23:27 +0800
|
9
|
+
ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations".* FROM "schema_migrations"
|
10
|
+
Processing by HomeController#index as HTML
|
11
|
+
Something Load (0.2ms) SELECT "somethings".* FROM "somethings" WHERE "somethings"."paper" = ? AND "somethings"."stone" = ? ORDER BY "somethings"."id" ASC LIMIT 1 [["paper", "123"], ["stone", "456"]]
|
12
|
+
Rendered home/_partial.html.erb (0.2ms)
|
13
|
+
Rendered home/index.html.erb within layouts/application (5.2ms)
|
14
|
+
Completed 200 OK in 283ms (Views: 271.6ms | ActiveRecord: 0.6ms)
|
15
|
+
|
16
|
+
Started GET "/assets/application.self-e80e8f2318043e8af94dddc2adad5a4f09739a8ebb323b3ab31cd71d45fd9113.css?body=1" for ::1 at 2016-04-11 16:23:27 +0800
|
17
|
+
|
18
|
+
Started GET "/assets/application.self-8f06a73c35179188914ab50e057157639fce1401c1cdca640ac9cec33746fc5b.js?body=1" for ::1 at 2016-04-11 16:23:27 +0800
|
19
|
+
```
|
20
|
+
|
21
|
+
Machine-readable logging with Superlogger:
|
22
|
+
```sh
|
23
|
+
2016-04-11 16:18:22.279 | b48534ea049a | I | middleware:28 | method=GET | path=/home/index | ip=::1
|
24
|
+
2016-04-11 16:18:22.293 | b48534ea049a | D | action_controller_log_subscriber:9 | controller=HomeController | action=index | params={}
|
25
|
+
2016-04-11 16:18:22.305 | b48534ea049a | D | active_record_log_subscriber:24 | sql=SELECT "somethings".* FROM "somethings" WHERE "somethings"."paper" = ? AND "somethings"."stone" = ? ORDER BY "somethings"."id" ASC LIMIT 1 | params=["'123'", "'456'"] | duration=0.48
|
26
|
+
2016-04-11 16:18:22.316 | b48534ea049a | D | action_view_log_subscriber:6 | view=_partial.html.erb | duration=0.3
|
27
|
+
2016-04-11 16:18:22.316 | b48534ea049a | D | action_view_log_subscriber:6 | view=index.html.erb | duration=5.6
|
28
|
+
2016-04-11 16:18:22.541 | b48534ea049a | I | action_controller_log_subscriber:29 | status=200 | total_duration=247.16 | view_duration=235.25 | db_duration=0.78
|
29
|
+
```
|
30
|
+
|
31
|
+
## Features ##
|
32
|
+
- Timestamp (milliseconds)
|
33
|
+
- Session ID for logs across requests
|
34
|
+
- Key-value pairs for log data
|
35
|
+
- Muting of assets logging
|
36
|
+
- File and line numbers
|
37
|
+
- Recording of IP address
|
38
|
+
|
39
|
+
## Installation ##
|
40
|
+
|
41
|
+
Add superlogger to your application's Gemfile
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
gem "superlogger"
|
45
|
+
```
|
46
|
+
|
47
|
+
And then execute:
|
48
|
+
|
49
|
+
```sh
|
50
|
+
$ bundle
|
51
|
+
```
|
52
|
+
|
53
|
+
## Usage ##
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
require 'superlogger'
|
57
|
+
|
58
|
+
class SomeClass
|
59
|
+
include Superlogger
|
60
|
+
|
61
|
+
def some_method
|
62
|
+
Logger.debug name:'john', age: '21'
|
63
|
+
Logger.info name:'john', age: '21'
|
64
|
+
Logger.warn name:'john', age: '21'
|
65
|
+
Logger.error name:'john', age: '21'
|
66
|
+
Logger.fatal name:'john', age: '21'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
71
|
+
## Output Format ##
|
72
|
+
```sh
|
73
|
+
2015-03-26 23:37:38.086 | 970298669a40 | I | log_subscriber:24 | status:200 | total:858.35 | view:597.46 | db:34.96
|
74
|
+
< timestamp > | < session id > | < severity > | < file >:< line num > | < data you pass in ... >
|
75
|
+
```
|
76
|
+
|
77
|
+
### Severity Levels ###
|
78
|
+
- **D** - Debug
|
79
|
+
- **I** - Info
|
80
|
+
- **W** - Warn
|
81
|
+
- **E** - Error
|
82
|
+
- **F** - Fatal
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Superlogger'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
Bundler::GemHelper.install_tasks
|
23
|
+
|
24
|
+
require 'rake/testtask'
|
25
|
+
|
26
|
+
Rake::TestTask.new(:test) do |t|
|
27
|
+
t.libs << 'lib'
|
28
|
+
t.libs << 'test'
|
29
|
+
t.pattern = 'test/**/*_test.rb'
|
30
|
+
t.verbose = false
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
task default: :test
|
data/lib/superlogger.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'superlogger/version'
|
2
|
+
require 'superlogger/logger'
|
3
|
+
|
4
|
+
module Superlogger
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def setup(app)
|
8
|
+
overwrite_rails_rack_logger
|
9
|
+
overwrite_action_dispatch_debug_exceptions
|
10
|
+
insert_superlogger_middleware(app)
|
11
|
+
detach_all_existing_log_subscribers
|
12
|
+
attach_superlogger_log_subscribers
|
13
|
+
end
|
14
|
+
|
15
|
+
def overwrite_rails_rack_logger
|
16
|
+
require 'superlogger/rails_rack_logger'
|
17
|
+
end
|
18
|
+
|
19
|
+
def overwrite_action_dispatch_debug_exceptions
|
20
|
+
require 'superlogger/action_dispatch_debug_exceptions'
|
21
|
+
end
|
22
|
+
|
23
|
+
def insert_superlogger_middleware(app)
|
24
|
+
require 'superlogger/middleware'
|
25
|
+
|
26
|
+
# important to insert after session middleware so we can get the session id
|
27
|
+
app.middleware.use Superlogger::Middleware
|
28
|
+
end
|
29
|
+
|
30
|
+
def detach_all_existing_log_subscribers
|
31
|
+
# force log subscribers to attach first so we can remove them all
|
32
|
+
require 'action_controller/log_subscriber'
|
33
|
+
require 'active_record/log_subscriber'
|
34
|
+
require 'action_view/log_subscriber'
|
35
|
+
require 'action_mailer/log_subscriber'
|
36
|
+
|
37
|
+
# remove log subscribers
|
38
|
+
ActiveSupport::LogSubscriber.log_subscribers.each do |subscriber|
|
39
|
+
subscriber.patterns.each do |pattern|
|
40
|
+
ActiveSupport::Notifications.unsubscribe pattern
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
ActiveSupport::LogSubscriber.log_subscribers.clear
|
45
|
+
end
|
46
|
+
|
47
|
+
def attach_superlogger_log_subscribers
|
48
|
+
require 'superlogger/action_controller_log_subscriber'
|
49
|
+
require 'superlogger/action_view_log_subscriber'
|
50
|
+
require 'superlogger/active_record_log_subscriber'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
require 'superlogger/railtie' if defined?(Rails)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Superlogger
|
2
|
+
class ActionControllerLogSubscriber < ActiveSupport::LogSubscriber
|
3
|
+
INTERNAL_PARAMS = %w(controller action format _method only_path)
|
4
|
+
|
5
|
+
# start of controller action
|
6
|
+
def start_processing(event)
|
7
|
+
payload = event.payload
|
8
|
+
|
9
|
+
Logger.debug controller: payload[:controller], action: payload[:action], params: payload[:params].except(*INTERNAL_PARAMS)
|
10
|
+
end
|
11
|
+
|
12
|
+
# end of controller action
|
13
|
+
def process_action(event)
|
14
|
+
payload = event.payload
|
15
|
+
|
16
|
+
if payload[:exception]
|
17
|
+
status = ActionDispatch::ExceptionWrapper.status_code_for_exception(payload[:exception][0])
|
18
|
+
|
19
|
+
Logger.fatal status: status, exception: payload[:exception]
|
20
|
+
else
|
21
|
+
# Assume status 401 if action finishes without status code and no exception
|
22
|
+
# https://github.com/pcg79/devise/commit/1e2dab3c0ce49efe2b5940c15f47388c69d6731b
|
23
|
+
payload[:status] ||= 401
|
24
|
+
|
25
|
+
total_duration = event.duration.to_f.round(2)
|
26
|
+
view_duration = payload[:view_runtime].to_f.round(2) if payload.key?(:view_runtime)
|
27
|
+
db_duration = payload[:db_runtime].to_f.round(2) if payload.key?(:db_runtime)
|
28
|
+
|
29
|
+
Logger.info status: payload[:status], total_duration: total_duration, view_duration: view_duration, db_duration: db_duration
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
Superlogger::ActionControllerLogSubscriber.attach_to :action_controller
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class ActionDispatch::DebugExceptions
|
2
|
+
alias_method :old_log_error, :log_error
|
3
|
+
def log_error(request, wrapper)
|
4
|
+
if wrapper.exception.is_a? ActionController::RoutingError
|
5
|
+
# Change routing errors to warn instead
|
6
|
+
Superlogger::Logger.warn routing_error: request['PATH_INFO'].inspect
|
7
|
+
else
|
8
|
+
old_log_error request, wrapper
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Superlogger
|
2
|
+
class ActionViewLogSubscriber < ActiveSupport::LogSubscriber
|
3
|
+
def render_template(event)
|
4
|
+
payload = event.payload
|
5
|
+
|
6
|
+
Logger.debug view: payload[:identifier].split('/').last, duration: event.duration.round(1)
|
7
|
+
end
|
8
|
+
alias :render_partial :render_template
|
9
|
+
alias :render_collection :render_template
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
Superlogger::ActionViewLogSubscriber.attach_to :action_view
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Superlogger
|
2
|
+
class ActiveRecordLogSubscriber < ActiveSupport::LogSubscriber
|
3
|
+
IGNORE_PAYLOAD_NAMES = ["SCHEMA", "EXPLAIN", "ActiveRecord::SchemaMigration Load"]
|
4
|
+
|
5
|
+
def self.runtime=(value)
|
6
|
+
ActiveRecord::RuntimeRegistry.sql_runtime = value
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.runtime
|
10
|
+
ActiveRecord::RuntimeRegistry.sql_runtime ||= 0
|
11
|
+
end
|
12
|
+
|
13
|
+
def sql(event)
|
14
|
+
self.class.runtime += event.duration
|
15
|
+
|
16
|
+
return if Rails.env.production?
|
17
|
+
|
18
|
+
payload = event.payload
|
19
|
+
return if IGNORE_PAYLOAD_NAMES.include?(payload[:name])
|
20
|
+
|
21
|
+
sql = payload[:sql]
|
22
|
+
params = payload[:binds].map { |_, value| "'#{value}'"}
|
23
|
+
|
24
|
+
Logger.debug sql: sql, params: params, duration: event.duration.round(2)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
Superlogger::ActiveRecordLogSubscriber.attach_to :active_record
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'request_store'
|
2
|
+
|
3
|
+
module Superlogger
|
4
|
+
module Logger
|
5
|
+
def self.session_id=(session_id)
|
6
|
+
RequestStore.store[:superlogger_session_id] = session_id
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.session_id
|
10
|
+
RequestStore.store[:superlogger_session_id] || "NS-#{Thread.current.object_id}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.debug(*args)
|
14
|
+
Rails.logger.debug { format_msg(args) }
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.info(*args)
|
18
|
+
Rails.logger.info { format_msg(args) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.warn(*args)
|
22
|
+
Rails.logger.warn { format_msg(args) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.error(*args)
|
26
|
+
Rails.logger.error { format_msg(args) }
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.fatal(*args)
|
30
|
+
Rails.logger.fatal { format_msg(args) }
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def self.format_msg(args)
|
36
|
+
"#{get_caller_location} | #{format_args(args)}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.get_caller_location
|
40
|
+
# Find the last method call on Superlogger::Logger
|
41
|
+
count = 0
|
42
|
+
location_index = caller_locations(0).find_index do |location|
|
43
|
+
count += 1 if location && location.path.include?('superlogger/logger.rb')
|
44
|
+
count == 4
|
45
|
+
end
|
46
|
+
|
47
|
+
# Add 1 to get the caller of the logger
|
48
|
+
location = caller_locations(location_index + 1).first
|
49
|
+
|
50
|
+
# extract filename without file extension from location.path
|
51
|
+
# eg. superlogger/lib/superlogger/logger.rb
|
52
|
+
file = location.path.split('/').last.split('.').first
|
53
|
+
|
54
|
+
"#{file}:#{location.lineno}"
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.format_args(args)
|
58
|
+
# format args in key=value pair, separated by pipes
|
59
|
+
args.map do |arg|
|
60
|
+
arg = {nil: arg} unless arg.is_a?(Hash)
|
61
|
+
|
62
|
+
arg.map do |key, value|
|
63
|
+
"#{key}=#{value}"
|
64
|
+
end
|
65
|
+
end.flatten.join(' | ')
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# for overriding default Rails Logger format
|
71
|
+
class Logger
|
72
|
+
def format_message(severity, time, _progname, msg)
|
73
|
+
timestamp = time.strftime('%Y-%m-%d %H:%M:%S.%L')
|
74
|
+
session_id = Superlogger::Logger.session_id[0..11]
|
75
|
+
severity = severity.to_s.upcase[0]
|
76
|
+
|
77
|
+
"#{timestamp} | #{session_id} | #{severity} | #{msg}\n"
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Superlogger
|
2
|
+
class Middleware
|
3
|
+
def initialize(app)
|
4
|
+
@app = app
|
5
|
+
end
|
6
|
+
|
7
|
+
def call(env)
|
8
|
+
request = ActionDispatch::Request.new(env)
|
9
|
+
|
10
|
+
# only process the actual request, less the assets
|
11
|
+
if request.path.start_with?('/assets/') == false
|
12
|
+
process_request(request)
|
13
|
+
end
|
14
|
+
|
15
|
+
@app.call(env)
|
16
|
+
end
|
17
|
+
|
18
|
+
def process_request(request)
|
19
|
+
if request.env['rack.session']
|
20
|
+
# Session is lazy loaded. Force session to load if it is not already loaded.
|
21
|
+
request.env['rack.session'].send(:load!) unless request.env['rack.session'].id
|
22
|
+
|
23
|
+
# Store session id before any actual logging is done
|
24
|
+
Superlogger::Logger.session_id = request.env['rack.session'].id
|
25
|
+
end
|
26
|
+
|
27
|
+
# Start of request logging
|
28
|
+
Logger.info method: request.method, path: request.fullpath, ip: request.ip
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Rails::Rack::Logger
|
2
|
+
# Overwrite the default call_app method to mute the following line:
|
3
|
+
# Started GET “/session/new” for 127.0.0.1 at 2012-09-26 14:51:42 -0700
|
4
|
+
def call_app(_request, env)
|
5
|
+
@app.call(env)
|
6
|
+
ensure
|
7
|
+
ActiveSupport::LogSubscriber.flush_all!
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
== README
|
2
|
+
|
3
|
+
This README would normally document whatever steps are necessary to get the
|
4
|
+
application up and running.
|
5
|
+
|
6
|
+
Things you may want to cover:
|
7
|
+
|
8
|
+
* Ruby version
|
9
|
+
|
10
|
+
* System dependencies
|
11
|
+
|
12
|
+
* Configuration
|
13
|
+
|
14
|
+
* Database creation
|
15
|
+
|
16
|
+
* Database initialization
|
17
|
+
|
18
|
+
* How to run the test suite
|
19
|
+
|
20
|
+
* Services (job queues, cache servers, search engines, etc.)
|
21
|
+
|
22
|
+
* Deployment instructions
|
23
|
+
|
24
|
+
* ...
|
25
|
+
|
26
|
+
|
27
|
+
Please feel free to use a different markup language if you do not plan to run
|
28
|
+
<tt>rake doc:app</tt>.
|