heavylog 0.0.16 → 0.0.21
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.
- checksums.yaml +4 -4
- data/.editorconfig +14 -0
- data/.github/workflows/test.yml +33 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +19 -17
- data/Gemfile.lock +113 -62
- data/README.md +78 -15
- data/heavylog.gemspec +6 -2
- data/lib/heavylog.rb +4 -1
- data/lib/heavylog/formatters/ecs.rb +65 -0
- data/lib/heavylog/log_subscriber.rb +9 -0
- data/lib/heavylog/railtie.rb +3 -0
- data/lib/heavylog/sidekiq_logger.rb +13 -10
- data/lib/heavylog/version.rb +1 -1
- metadata +64 -6
- data/.travis.yml +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e5698a7bfa3d9476d9b35f0a0da99a7faeeb230df8889599cf343b017745488
|
4
|
+
data.tar.gz: 74d24b9be2f75463929bc5de1cb076fca87cb7b707a7123474a95682b3899e4a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1dde2fc6a5912a2345729bd7150d1a6c39b55ab4f90800ee2cbe61acb3f351c978ecadea820981ba1cc94180140d8ddbab0f0f6890901c6251a906b2be9343a7
|
7
|
+
data.tar.gz: b7a5930b2cba4fa6501798ac200978a5c172cda4af2b0d1dd55dc23bf0373edde9c722b1b3cbf658f68163d03adee190814f3d342bf621bf5d11c7eeab03dbaa
|
data/.editorconfig
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# This file is for unifying the coding style for different editors and IDEs
|
2
|
+
# editorconfig.org
|
3
|
+
|
4
|
+
root = true
|
5
|
+
|
6
|
+
[*]
|
7
|
+
charset = utf-8
|
8
|
+
trim_trailing_whitespace = false
|
9
|
+
insert_final_newline = true
|
10
|
+
indent_style = space
|
11
|
+
indent_size = 2
|
12
|
+
|
13
|
+
[*.md]
|
14
|
+
trim_trailing_whitespace = true
|
@@ -0,0 +1,33 @@
|
|
1
|
+
name: Test
|
2
|
+
|
3
|
+
on: [push]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
test:
|
7
|
+
name: Build
|
8
|
+
runs-on: ubuntu-latest
|
9
|
+
|
10
|
+
steps:
|
11
|
+
- uses: actions/checkout@v1
|
12
|
+
- name: Set up Ruby
|
13
|
+
uses: ruby/setup-ruby@v1
|
14
|
+
with:
|
15
|
+
ruby-version: 3.0.1
|
16
|
+
|
17
|
+
- uses: actions/cache@v1
|
18
|
+
with:
|
19
|
+
path: vendor/bundle
|
20
|
+
key: ${{ runner.os }}-gem-${{ hashFiles('**/Gemfile.lock') }}
|
21
|
+
restore-keys: |
|
22
|
+
${{ runner.os }}-gem-
|
23
|
+
|
24
|
+
- name: Install dependencies
|
25
|
+
run: |
|
26
|
+
gem install bundler
|
27
|
+
bundle config path vendor/bundle
|
28
|
+
bundle install --jobs 4 --retry 3
|
29
|
+
|
30
|
+
- name: Run tests
|
31
|
+
env:
|
32
|
+
CI: true
|
33
|
+
run: bundle exec rspec
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -2,46 +2,42 @@ require:
|
|
2
2
|
- rubocop-performance
|
3
3
|
|
4
4
|
AllCops:
|
5
|
-
TargetRubyVersion:
|
5
|
+
TargetRubyVersion: 3.0
|
6
6
|
|
7
7
|
# # Commonly used screens these days easily fit more than 80 characters.
|
8
|
-
|
8
|
+
Layout/LineLength:
|
9
9
|
Max: 120
|
10
10
|
|
11
11
|
# Too short methods lead to extraction of single-use methods, which can make
|
12
12
|
# the code easier to read (by naming things), but can also clutter the class
|
13
13
|
Metrics/MethodLength:
|
14
|
-
|
14
|
+
Enabled: false
|
15
15
|
|
16
16
|
# The guiding principle of classes is SRP, SRP can't be accurately measured by LoC
|
17
17
|
Metrics/ClassLength:
|
18
|
-
|
18
|
+
Enabled: false
|
19
19
|
|
20
20
|
Metrics/AbcSize:
|
21
|
-
|
21
|
+
Enabled: false
|
22
22
|
|
23
23
|
Metrics/CyclomaticComplexity:
|
24
|
-
|
24
|
+
Enabled: false
|
25
25
|
|
26
26
|
Metrics/PerceivedComplexity:
|
27
|
-
|
27
|
+
Enabled: false
|
28
28
|
|
29
29
|
Metrics/ParameterLists:
|
30
|
-
|
30
|
+
Enabled: false
|
31
31
|
|
32
32
|
Metrics/ModuleLength:
|
33
|
-
|
33
|
+
Enabled: false
|
34
34
|
|
35
35
|
Metrics/BlockLength:
|
36
|
-
|
37
|
-
Exclude:
|
38
|
-
- 'spec/**/*'
|
36
|
+
Enabled: false
|
39
37
|
|
40
38
|
# Mixing the styles looks just silly.
|
41
39
|
Style/HashSyntax:
|
42
40
|
EnforcedStyle: ruby19_no_mixed_keys
|
43
|
-
Exclude:
|
44
|
-
- 'config/routes.rb'
|
45
41
|
|
46
42
|
# Single quotes being faster is hardly measurable and only affects parse time.
|
47
43
|
# Enforcing double quotes reduces the times where you need to change them
|
@@ -103,8 +99,11 @@ Style/ClassAndModuleChildren:
|
|
103
99
|
Style/DoubleNegation:
|
104
100
|
Enabled: false
|
105
101
|
|
102
|
+
Style/AsciiComments:
|
103
|
+
Enabled: false
|
104
|
+
|
106
105
|
# Most readable form.
|
107
|
-
Layout/
|
106
|
+
Layout/HashAlignment:
|
108
107
|
EnforcedHashRocketStyle: table
|
109
108
|
EnforcedColonStyle: table
|
110
109
|
|
@@ -125,14 +124,14 @@ Layout/MultilineMethodCallIndentation:
|
|
125
124
|
# Suppressing exceptions can be perfectly fine, and be it to avoid to
|
126
125
|
# explicitly type nil into the rescue since that's what you want to return,
|
127
126
|
# or suppressing LoadError for optional dependencies
|
128
|
-
Lint/
|
127
|
+
Lint/SuppressedException:
|
129
128
|
Enabled: false
|
130
129
|
|
131
130
|
# This is just silly. Calling the argument `other` in all cases makes no sense.
|
132
131
|
Naming/BinaryOperatorParameterName:
|
133
132
|
Enabled: false
|
134
133
|
|
135
|
-
Naming/
|
134
|
+
Naming/MethodParameterName:
|
136
135
|
AllowedNames:
|
137
136
|
- io
|
138
137
|
- id
|
@@ -148,3 +147,6 @@ Naming/UncommunicativeMethodParamName:
|
|
148
147
|
|
149
148
|
Bundler/OrderedGems:
|
150
149
|
Enabled: false
|
150
|
+
|
151
|
+
Gemspec/OrderedDependencies:
|
152
|
+
Enabled: false
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
heavylog (0.0.
|
4
|
+
heavylog (0.0.21)
|
5
5
|
actionpack (>= 5)
|
6
6
|
activesupport (>= 5)
|
7
7
|
railties (>= 5)
|
@@ -10,90 +10,137 @@ PATH
|
|
10
10
|
GEM
|
11
11
|
remote: https://rubygems.org/
|
12
12
|
specs:
|
13
|
-
actionpack (6.
|
14
|
-
actionview (= 6.
|
15
|
-
activesupport (= 6.
|
16
|
-
rack (~> 2.0)
|
13
|
+
actionpack (6.1.3.2)
|
14
|
+
actionview (= 6.1.3.2)
|
15
|
+
activesupport (= 6.1.3.2)
|
16
|
+
rack (~> 2.0, >= 2.0.9)
|
17
17
|
rack-test (>= 0.6.3)
|
18
18
|
rails-dom-testing (~> 2.0)
|
19
19
|
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
20
|
-
actionview (6.
|
21
|
-
activesupport (= 6.
|
20
|
+
actionview (6.1.3.2)
|
21
|
+
activesupport (= 6.1.3.2)
|
22
22
|
builder (~> 3.1)
|
23
23
|
erubi (~> 1.4)
|
24
24
|
rails-dom-testing (~> 2.0)
|
25
25
|
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
26
|
-
activesupport (6.
|
26
|
+
activesupport (6.1.3.2)
|
27
27
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
28
|
-
i18n (>=
|
29
|
-
minitest (
|
30
|
-
tzinfo (~>
|
31
|
-
zeitwerk (~> 2.
|
32
|
-
ast (2.4.
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
28
|
+
i18n (>= 1.6, < 2)
|
29
|
+
minitest (>= 5.1)
|
30
|
+
tzinfo (~> 2.0)
|
31
|
+
zeitwerk (~> 2.3)
|
32
|
+
ast (2.4.2)
|
33
|
+
backport (1.1.2)
|
34
|
+
benchmark (0.1.1)
|
35
|
+
builder (3.2.4)
|
36
|
+
concurrent-ruby (1.1.8)
|
37
|
+
connection_pool (2.2.5)
|
38
|
+
crass (1.0.6)
|
39
|
+
diff-lcs (1.4.4)
|
40
|
+
docile (1.3.5)
|
41
|
+
e2mmap (0.1.0)
|
42
|
+
erubi (1.10.0)
|
43
|
+
i18n (1.8.10)
|
39
44
|
concurrent-ruby (~> 1.0)
|
40
|
-
jaro_winkler (1.5.
|
41
|
-
|
45
|
+
jaro_winkler (1.5.4)
|
46
|
+
json (2.5.1)
|
47
|
+
kramdown (2.3.1)
|
48
|
+
rexml
|
49
|
+
kramdown-parser-gfm (1.1.0)
|
50
|
+
kramdown (~> 2.0)
|
51
|
+
loofah (2.9.1)
|
42
52
|
crass (~> 1.0.2)
|
43
53
|
nokogiri (>= 1.5.9)
|
44
|
-
method_source (0.
|
45
|
-
mini_portile2 (2.
|
46
|
-
minitest (5.
|
47
|
-
nokogiri (1.
|
48
|
-
mini_portile2 (~> 2.
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
54
|
+
method_source (1.0.0)
|
55
|
+
mini_portile2 (2.5.1)
|
56
|
+
minitest (5.14.4)
|
57
|
+
nokogiri (1.11.3)
|
58
|
+
mini_portile2 (~> 2.5.0)
|
59
|
+
racc (~> 1.4)
|
60
|
+
parallel (1.20.1)
|
61
|
+
parser (3.0.1.0)
|
62
|
+
ast (~> 2.4.1)
|
63
|
+
racc (1.5.2)
|
64
|
+
rack (2.2.3)
|
53
65
|
rack-test (1.1.0)
|
54
66
|
rack (>= 1.0, < 3)
|
55
67
|
rails-dom-testing (2.0.3)
|
56
68
|
activesupport (>= 4.2.0)
|
57
69
|
nokogiri (>= 1.6)
|
58
|
-
rails-html-sanitizer (1.
|
59
|
-
loofah (~> 2.
|
60
|
-
railties (6.
|
61
|
-
actionpack (= 6.
|
62
|
-
activesupport (= 6.
|
70
|
+
rails-html-sanitizer (1.3.0)
|
71
|
+
loofah (~> 2.3)
|
72
|
+
railties (6.1.3.2)
|
73
|
+
actionpack (= 6.1.3.2)
|
74
|
+
activesupport (= 6.1.3.2)
|
63
75
|
method_source
|
64
76
|
rake (>= 0.8.7)
|
65
|
-
thor (
|
77
|
+
thor (~> 1.0)
|
66
78
|
rainbow (3.0.0)
|
67
|
-
rake (
|
68
|
-
|
79
|
+
rake (13.0.3)
|
80
|
+
redis (4.2.5)
|
81
|
+
regexp_parser (2.1.1)
|
82
|
+
request_store (1.5.0)
|
69
83
|
rack (>= 1.4)
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
rspec-
|
76
|
-
|
84
|
+
reverse_markdown (2.0.0)
|
85
|
+
nokogiri
|
86
|
+
rexml (3.2.5)
|
87
|
+
rspec (3.10.0)
|
88
|
+
rspec-core (~> 3.10.0)
|
89
|
+
rspec-expectations (~> 3.10.0)
|
90
|
+
rspec-mocks (~> 3.10.0)
|
91
|
+
rspec-core (3.10.1)
|
92
|
+
rspec-support (~> 3.10.0)
|
93
|
+
rspec-expectations (3.10.1)
|
77
94
|
diff-lcs (>= 1.2.0, < 2.0)
|
78
|
-
rspec-support (~> 3.
|
79
|
-
rspec-mocks (3.
|
95
|
+
rspec-support (~> 3.10.0)
|
96
|
+
rspec-mocks (3.10.2)
|
80
97
|
diff-lcs (>= 1.2.0, < 2.0)
|
81
|
-
rspec-support (~> 3.
|
82
|
-
rspec-support (3.
|
83
|
-
rubocop (0.
|
84
|
-
jaro_winkler (~> 1.5.1)
|
98
|
+
rspec-support (~> 3.10.0)
|
99
|
+
rspec-support (3.10.2)
|
100
|
+
rubocop (0.93.1)
|
85
101
|
parallel (~> 1.10)
|
86
|
-
parser (>= 2.
|
102
|
+
parser (>= 2.7.1.5)
|
87
103
|
rainbow (>= 2.2.2, < 4.0)
|
104
|
+
regexp_parser (>= 1.8)
|
105
|
+
rexml
|
106
|
+
rubocop-ast (>= 0.6.0)
|
88
107
|
ruby-progressbar (~> 1.7)
|
89
|
-
unicode-display_width (>= 1.4.0, <
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
108
|
+
unicode-display_width (>= 1.4.0, < 2.0)
|
109
|
+
rubocop-ast (1.4.1)
|
110
|
+
parser (>= 2.7.1.5)
|
111
|
+
rubocop-performance (1.5.2)
|
112
|
+
rubocop (>= 0.71.0)
|
113
|
+
ruby-progressbar (1.11.0)
|
114
|
+
sidekiq (6.2.1)
|
115
|
+
connection_pool (>= 2.2.2)
|
116
|
+
rack (~> 2.0)
|
117
|
+
redis (>= 4.2.0)
|
118
|
+
simplecov (0.17.1)
|
119
|
+
docile (~> 1.1)
|
120
|
+
json (>= 1.8, < 3)
|
121
|
+
simplecov-html (~> 0.10.0)
|
122
|
+
simplecov-html (0.10.2)
|
123
|
+
solargraph (0.40.4)
|
124
|
+
backport (~> 1.1)
|
125
|
+
benchmark
|
126
|
+
bundler (>= 1.17.2)
|
127
|
+
e2mmap
|
128
|
+
jaro_winkler (~> 1.5)
|
129
|
+
kramdown (~> 2.3)
|
130
|
+
kramdown-parser-gfm (~> 1.1)
|
131
|
+
parser (~> 3.0)
|
132
|
+
reverse_markdown (>= 1.0.5, < 3)
|
133
|
+
rubocop (>= 0.52)
|
134
|
+
thor (~> 1.0)
|
135
|
+
tilt (~> 2.0)
|
136
|
+
yard (~> 0.9, >= 0.9.24)
|
137
|
+
thor (1.1.0)
|
138
|
+
tilt (2.0.10)
|
139
|
+
tzinfo (2.0.4)
|
140
|
+
concurrent-ruby (~> 1.0)
|
141
|
+
unicode-display_width (1.7.0)
|
142
|
+
yard (0.9.26)
|
143
|
+
zeitwerk (2.4.2)
|
97
144
|
|
98
145
|
PLATFORMS
|
99
146
|
ruby
|
@@ -101,9 +148,13 @@ PLATFORMS
|
|
101
148
|
DEPENDENCIES
|
102
149
|
bundler (~> 2.0)
|
103
150
|
heavylog!
|
104
|
-
rake (~>
|
151
|
+
rake (~> 13.0)
|
105
152
|
rspec (~> 3.0)
|
106
153
|
rubocop (~> 0.71)
|
154
|
+
rubocop-performance (~> 1.5.2)
|
155
|
+
sidekiq (>= 5.0)
|
156
|
+
simplecov (~> 0.17.1)
|
157
|
+
solargraph
|
107
158
|
|
108
159
|
BUNDLED WITH
|
109
|
-
2.
|
160
|
+
2.2.15
|
data/README.md
CHANGED
@@ -1,39 +1,102 @@
|
|
1
|
-
# Heavylog [](https://github.com/krisrang/heavylog/actions/workflows/test.yml) [](https://badge.fury.io/rb/heavylog)
|
2
2
|
|
3
|
-
|
3
|
+
Heavylog enables you to log all Rails requests to file as JSON or any other format you want.
|
4
4
|
|
5
|
-
|
5
|
+
Aside from metadata about requests full output is also included like SQL/Rails logging and `puts` statements.
|
6
|
+
Example request using the JSON formatter:
|
7
|
+
```
|
8
|
+
{"request_id":"e2cdef0a-9851-4aab-b58f-60e607b4d1a9","request_start":"2021-04-25T15:37:20+00:00","ip":"52.52.52.52","messages":"Started GET \"/admin/info/sidekiq\" for 52.52.52.52 at 2021-04-25 15:37:20 +0000\nProcessing by Admin::InfoController#sidekiq_stats as */*\nRequested via apphost.com as */*\n Snippet Load (1.8ms) SELECT \"snippets\".* FROM \"snippets\" WHERE (locale = 'sv-SE' AND tag = 'information_notice_contact') ORDER BY \"snippets\".\"id\" ASC LIMIT $1 [[\"LIMIT\", 1]]\n Snippet Load (1.5ms) SELECT \"snippets\".* FROM \"snippets\" WHERE (locale = 'sv-SE' AND tag = 'contact_us_frame') ORDER BY \"snippets\".\"id\" ASC LIMIT $1 [[\"LIMIT\", 1]]\n Rendering text template\n Rendered text template (Duration: 0.1ms | Allocations: 16)\nCompleted 200 OK in 41ms (Views: 0.6ms | ActiveRecord: 3.3ms | Allocations: 10734)\n","method":"GET","path":"/admin/info/sidekiq","format":"*/*","controller":"Admin::InfoController","action":"sidekiq_stats","status":200,"duration":40.74,"view_runtime":0.56,"db_runtime":3.28,"user_id":null,"admin_id":null,"request_host":"apphost.com","ua":"curl/7.58.0","operation":null}
|
9
|
+
```
|
6
10
|
|
11
|
+
Example use case is collecting the JSON files and shipping them to an Elastic/Kibana cluster for centralized logging.
|
7
12
|
## Installation
|
8
13
|
|
9
14
|
Add this line to your application's Gemfile:
|
10
15
|
|
11
16
|
```ruby
|
12
|
-
gem
|
17
|
+
gem "heavylog"
|
13
18
|
```
|
14
19
|
|
15
20
|
And then execute:
|
16
21
|
|
17
|
-
|
22
|
+
```bash
|
23
|
+
$ bundle
|
24
|
+
```
|
18
25
|
|
19
|
-
|
26
|
+
## Usage
|
20
27
|
|
21
|
-
|
28
|
+
Enable and configure in a Rails initializer `config/initializers/logger.rb`:
|
22
29
|
|
23
|
-
|
30
|
+
```rb
|
31
|
+
Rails.application.configure do
|
32
|
+
config.heavylog.enabled = true
|
33
|
+
config.heavylog.path = Rails.root.join("log/heavylog.log")
|
34
|
+
# Default formatter is Heavylog::Formatters::Raw which simply outputs the ruby hash as a string
|
35
|
+
config.heavylog.formatter = Heavylog::Formatters::Json.new
|
36
|
+
config.heavylog.log_sidekiq = true # Default is `false`, set to `true` to automatically log sidekiq job runs too.
|
37
|
+
end
|
38
|
+
```
|
24
39
|
|
25
|
-
|
40
|
+
## Configuration
|
41
|
+
|
42
|
+
| Option | Type | Description |
|
43
|
+
| :-------- | :------- | :------------------------- |
|
44
|
+
| `enabled` | `boolean` | Set to `true` to enable logging. Default: `false`. |
|
45
|
+
| `path` | `string` | Path to output file. Default: `log/heavylog.log`. |
|
46
|
+
| `message_limit` | `integer` | Request output will be truncated if longer than this limit. Default: `52428800` (50MB). |
|
47
|
+
| `log_sidekiq` | `boolean` | Set to `true` to automatically log sidekiq jobs too. Default: `false`. |
|
48
|
+
| `error_handler` | `lambda/proc` | Code to execute when formatter throws exception. Default: `->(e) { p "HeavyLog: Error writing to log: #{e.class}: #{e.message}\n #{e.backtrace.join("\n ")}" }`
|
49
|
+
| `custom_payload` | `block` | Block executed for every request that should return hash with extra fields you want to log. Default: `nil`. |
|
50
|
+
|
51
|
+
### Custom payload
|
52
|
+
|
53
|
+
`custom_payload` accepts a block with a single argument, `controller` you can use to access any methods you normally would in a controller action.
|
54
|
+
It should return a hash with the extra fields you want to log.
|
55
|
+
|
56
|
+
```rb
|
57
|
+
Rails.application.configure do
|
58
|
+
config.heavylog.custom_payload do |controller|
|
59
|
+
user_id = controller.respond_to?(:current_user) ? controller.current_user&.id : nil
|
60
|
+
|
61
|
+
{
|
62
|
+
user_id: user_id,
|
63
|
+
request_host: controller.request.host,
|
64
|
+
ua: controller.request.user_agent,
|
65
|
+
operation: controller.request.params[:operationName],
|
66
|
+
}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
```
|
26
70
|
|
27
|
-
|
71
|
+
### Sidekiq logging
|
28
72
|
|
29
|
-
|
73
|
+
Set `log_sidekiq` to `true` if you want to automatically log Sidekiq job runs to the same file. Example with JSON formatter:
|
74
|
+
```
|
75
|
+
{"request_id":"fb2c3798e2634011d670f753","request_start":"2021-04-25T16:00:53+00:00","ip":"127.0.0.1","messages":" Order Load (1.8ms) SELECT \"orders\".* FROM \"orders\" WHERE \"orders\".\"id\" = $1 LIMIT $2 [[\"id\", 109987473], [\"LIMIT\", 1]]\n Customer Load (1.7ms) SELECT \"customers\".* FROM \"customers\" WHERE \"customers\".\"id\" = $1 LIMIT $2 [[\"id\", 1027337], [\"LIMIT\", 1]]\n","controller":"SidekiqLogger","action":"MailPrepaidCheckupsJob","args":"[109987473]"}
|
76
|
+
```
|
77
|
+
|
78
|
+
Sidekiq job runs go into the same file as regular request logs but have controller set to `SidekiqLogger` and action to the name of the Job.
|
30
79
|
|
31
|
-
|
80
|
+
### JSON formatter
|
32
81
|
|
33
|
-
|
82
|
+
Every request results in a hash containing all info about the request. The default `Heavylog::Formatters::Raw` formatter simply outputs the hash as a string to the output file.
|
83
|
+
Use the `Heavylog::Formatters::Json` formatter to convert the hash to JSON. The resulting file will contain one JSON object per line for every request.
|
34
84
|
|
35
|
-
|
85
|
+
### Custom formatter
|
36
86
|
|
87
|
+
The formatter interface is simply a class with a `call` method that accepts a single argument which is the hash containing info about the request.
|
88
|
+
The method should return the final result you want to write to file. Heavylog writes one line per request.
|
89
|
+
|
90
|
+
JSON formatter for example:
|
91
|
+
```rb
|
92
|
+
class Json
|
93
|
+
def call(data)
|
94
|
+
::JSON.dump(data)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
```
|
37
98
|
## License
|
38
99
|
|
39
|
-
|
100
|
+
[MIT](https://choosealicense.com/licenses/mit/)
|
101
|
+
|
102
|
+
|
data/heavylog.gemspec
CHANGED
@@ -16,16 +16,20 @@ Gem::Specification.new do |spec|
|
|
16
16
|
spec.license = "MIT"
|
17
17
|
|
18
18
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
19
|
-
f.match(%r{^(test|spec|features)/})
|
19
|
+
f.match(%r{^(test|spec|features|.vscode)/})
|
20
20
|
end
|
21
21
|
spec.bindir = "exe"
|
22
22
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
23
|
spec.require_paths = ["lib"]
|
24
24
|
|
25
25
|
spec.add_development_dependency "bundler", "~> 2.0"
|
26
|
-
spec.add_development_dependency "rake", "~>
|
26
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
27
27
|
spec.add_development_dependency "rspec", "~> 3.0"
|
28
28
|
spec.add_development_dependency "rubocop", "~> 0.71"
|
29
|
+
spec.add_development_dependency "rubocop-performance", "~> 1.5.2"
|
30
|
+
spec.add_development_dependency "simplecov", "~> 0.17.1"
|
31
|
+
spec.add_development_dependency "sidekiq", ">= 5.0"
|
32
|
+
spec.add_development_dependency "solargraph"
|
29
33
|
|
30
34
|
spec.add_runtime_dependency "actionpack", ">= 5"
|
31
35
|
spec.add_runtime_dependency "activesupport", ">= 5"
|
data/lib/heavylog.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require "heavylog/version"
|
4
4
|
require "heavylog/formatters/raw"
|
5
5
|
require "heavylog/formatters/json"
|
6
|
+
require "heavylog/formatters/ecs"
|
6
7
|
require "heavylog/log_subscriber"
|
7
8
|
require "heavylog/middleware"
|
8
9
|
require "heavylog/ordered_options"
|
@@ -136,8 +137,10 @@ module Heavylog
|
|
136
137
|
messages: buffer.string.dup,
|
137
138
|
}.merge(RequestStore.store[:heavylog_request_data] || {})
|
138
139
|
|
139
|
-
formatted = Heavylog.formatter.call(request)
|
140
|
+
formatted = Heavylog.formatter.call(request.transform_keys(&:to_s))
|
140
141
|
Heavylog.logger.send(Heavylog.log_level, formatted)
|
142
|
+
rescue StandardError => e
|
143
|
+
config.error_handler&.(e)
|
141
144
|
end
|
142
145
|
|
143
146
|
def finish_sidekiq
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
module Heavylog
|
6
|
+
module Formatters
|
7
|
+
class ECS
|
8
|
+
# mapping from heavylog standard keys to ECS https://www.elastic.co/guide/en/ecs/current/ecs-reference.html
|
9
|
+
ECS_MAP = {
|
10
|
+
"request_start" => "@timestamp",
|
11
|
+
"messages" => "message",
|
12
|
+
"request_id" => "http.request.id",
|
13
|
+
"method" => "http.request.method",
|
14
|
+
"referrer" => "http.request.referrer",
|
15
|
+
"format" => "http.response.format",
|
16
|
+
"status" => "http.response.status_code",
|
17
|
+
"location" => "http.response.location",
|
18
|
+
"ip" => "source.address",
|
19
|
+
"path" => "url.original",
|
20
|
+
"controller" => "heavylog.controller",
|
21
|
+
"action" => "heavylog.action",
|
22
|
+
"unpermitted_params" => "heavylog.unpermitted_params",
|
23
|
+
"args" => "heavylog.args",
|
24
|
+
"duration" => "heavylog.duration",
|
25
|
+
"view_runtime" => "heavylog.view_runtime",
|
26
|
+
"db_runtime" => "heavylog.db_runtime",
|
27
|
+
}.freeze
|
28
|
+
|
29
|
+
def call(data)
|
30
|
+
ECS_MAP.each do |original, correct|
|
31
|
+
dig_set(data, correct.split("."), data.delete(original)) if data[original]
|
32
|
+
end
|
33
|
+
|
34
|
+
dig_set(data, %w[event module], "heavylog")
|
35
|
+
dig_set(data, %w[event category], "web")
|
36
|
+
|
37
|
+
unless data.dig("event", "dataset")
|
38
|
+
value = data.dig("heavylog", "controller") == "SidekiqLogger" ? "heavylog.sidekiq" : "heavylog.rails"
|
39
|
+
dig_set(data, %w[event dataset], value)
|
40
|
+
end
|
41
|
+
|
42
|
+
if (code = data.dig("http", "response", "status_code"))
|
43
|
+
dig_set(data, %w[event outcome], (200..399).cover?(code) ? "success" : "failure")
|
44
|
+
end
|
45
|
+
|
46
|
+
dig_set(data, %w[source ip], data.dig("source", "address")) unless data.dig("source", "ip")
|
47
|
+
dig_set(data, %w[url path], data.dig("url", "original")) unless data.dig("url", "path")
|
48
|
+
|
49
|
+
::JSON.dump(data)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def dig_set(obj, keys, value)
|
55
|
+
key = keys.first
|
56
|
+
if keys.length == 1
|
57
|
+
obj[key] = value
|
58
|
+
else
|
59
|
+
obj[key] = {} unless obj[key]
|
60
|
+
dig_set(obj[key], keys.slice(1..-1), value)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -31,6 +31,7 @@ module Heavylog
|
|
31
31
|
data.merge!(extract_runtimes(event, payload))
|
32
32
|
data.merge!(extract_location)
|
33
33
|
data.merge!(extract_unpermitted_params)
|
34
|
+
data.merge!(extract_referrer(payload))
|
34
35
|
data.merge!(custom_options(event))
|
35
36
|
end
|
36
37
|
|
@@ -101,5 +102,13 @@ module Heavylog
|
|
101
102
|
RequestStore.store[:heavylog_unpermitted_params] = nil
|
102
103
|
{ unpermitted_params: unpermitted_params }
|
103
104
|
end
|
105
|
+
|
106
|
+
def extract_referrer(payload)
|
107
|
+
if payload[:request].is_a?(ActionDispatch::Request) && payload[:request].referrer
|
108
|
+
return { referrer: payload[:request].referrer }
|
109
|
+
end
|
110
|
+
|
111
|
+
{}
|
112
|
+
end
|
104
113
|
end
|
105
114
|
end
|
data/lib/heavylog/railtie.rb
CHANGED
@@ -7,6 +7,9 @@ module Heavylog
|
|
7
7
|
config.heavylog.path = "log/heavylog.log"
|
8
8
|
config.heavylog.message_limit = 1024 * 1024 * 50 # 50MB
|
9
9
|
config.heavylog.log_sidekiq = false
|
10
|
+
config.heavylog.error_handler = lambda { |e|
|
11
|
+
Kernel.puts "HeavyLog: Error writing to log: #{e.class}: #{e.message}\n #{e.backtrace.join("\n ")}"
|
12
|
+
}
|
10
13
|
|
11
14
|
initializer "heavylog.insert_middleware" do |app|
|
12
15
|
app.config.middleware.insert_before Rails::Rack::Logger, Heavylog::Middleware
|
@@ -1,17 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
begin
|
4
|
+
require "sidekiq/job_logger"
|
4
5
|
|
5
|
-
module Heavylog
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
module Heavylog
|
7
|
+
class SidekiqLogger < Sidekiq::JobLogger
|
8
|
+
def call(item, _queue)
|
9
|
+
# item = {"class"=>"SuspiciousJob", "args"=>[12754545, [3858890], "invoice"], "retry"=>true, "queue"=>"default",
|
10
|
+
# "jid"=>"5ec968571e358497d70a3cf2", "created_at"=>1540484817.3950138, "enqueued_at"=>1540484817.395076}
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
Heavylog.log_sidekiq(item["jid"], item["class"], item["args"])
|
13
|
+
super
|
14
|
+
ensure
|
15
|
+
Heavylog.finish_sidekiq
|
16
|
+
end
|
15
17
|
end
|
16
18
|
end
|
19
|
+
rescue LoadError
|
17
20
|
end
|
data/lib/heavylog/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: heavylog
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.21
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kristjan Rang
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-05-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '13.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '13.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,6 +66,62 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0.71'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop-performance
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.5.2
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.5.2
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.17.1
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.17.1
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: sidekiq
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '5.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '5.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: solargraph
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
69
125
|
- !ruby/object:Gem::Dependency
|
70
126
|
name: actionpack
|
71
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -129,10 +185,11 @@ executables: []
|
|
129
185
|
extensions: []
|
130
186
|
extra_rdoc_files: []
|
131
187
|
files:
|
188
|
+
- ".editorconfig"
|
189
|
+
- ".github/workflows/test.yml"
|
132
190
|
- ".gitignore"
|
133
191
|
- ".rspec"
|
134
192
|
- ".rubocop.yml"
|
135
|
-
- ".travis.yml"
|
136
193
|
- Gemfile
|
137
194
|
- Gemfile.lock
|
138
195
|
- LICENSE.txt
|
@@ -142,6 +199,7 @@ files:
|
|
142
199
|
- bin/setup
|
143
200
|
- heavylog.gemspec
|
144
201
|
- lib/heavylog.rb
|
202
|
+
- lib/heavylog/formatters/ecs.rb
|
145
203
|
- lib/heavylog/formatters/json.rb
|
146
204
|
- lib/heavylog/formatters/raw.rb
|
147
205
|
- lib/heavylog/log_subscriber.rb
|
@@ -171,7 +229,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
171
229
|
- !ruby/object:Gem::Version
|
172
230
|
version: '0'
|
173
231
|
requirements: []
|
174
|
-
rubygems_version: 3.
|
232
|
+
rubygems_version: 3.2.15
|
175
233
|
signing_key:
|
176
234
|
specification_version: 4
|
177
235
|
summary: Format all Rails logging per request
|