twiglet 3.0.2 → 3.0.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: caa9b2047bc7a8ca268f0ba1b84a983b110234769db49c549f1d61fb21bbc730
4
- data.tar.gz: c3eaa4009b34d4d01b4b0b7a90fc5ba1b2e760abb7b137fd92f4679c22de57ae
3
+ metadata.gz: aadbe159aee695cfd454e0f006ab5eab2b3c06d01ecaa80d3f6b1b69c0d21d5e
4
+ data.tar.gz: 53907b03fb29af1fe41d8262619a6d5c84dab554b4e309d7336d969c11600a44
5
5
  SHA512:
6
- metadata.gz: d3ab7e57c1e99ac93349dcc2e75787e08d5f5c5fc6e242a03f286f17ae892ff38f759eacff900bbec46508fe559c5172958e1b94452e6af807e239ae195e29f2
7
- data.tar.gz: 4c57202266f609af726de4cc9a60b38f9bcc414dbcdfb5ce26e7f39bb18ebb07f8292310a9fa6a853a49ab9a2f18d53837d77f2321c5046224884aa0b72c5f99
6
+ metadata.gz: d5e68a4b343c861c7236e4a301365d738221bbe5eb0b23426e3cba84fad2358046d1b868bef5248c1c3398f4c2cfd132445259b7db976937024f73663699c2d4
7
+ data.tar.gz: 28b619fd981103d5baea53d07e032e52e21cf88e84b5229d1ca1ff61cedc284d6825ebf26fb977f060d3af4c34f276b8a69c733e66321952a726d452dc82164b
@@ -0,0 +1,22 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: bundler
4
+ directory: "/"
5
+ schedule:
6
+ interval: daily
7
+ time: "07:00"
8
+ open-pull-requests-limit: 99
9
+ labels:
10
+ - dependencies
11
+ ignore:
12
+ - dependency-name: simplecov
13
+ versions:
14
+ - ">= 0.18"
15
+ - package-ecosystem: github-actions
16
+ directory: "/"
17
+ schedule:
18
+ interval: daily
19
+ time: "07:00"
20
+ open-pull-requests-limit: 99
21
+ labels:
22
+ - dependencies
@@ -16,7 +16,7 @@ jobs:
16
16
 
17
17
  strategy:
18
18
  matrix:
19
- ruby-version: [2.6, 2.7]
19
+ ruby-version: [2.6, 2.7, 3.0]
20
20
 
21
21
  steps:
22
22
  - uses: actions/checkout@v2
@@ -10,7 +10,7 @@ jobs:
10
10
  runs-on: ubuntu-18.04
11
11
 
12
12
  steps:
13
- - uses: simplybusiness/version-forget-me-not@v1
13
+ - uses: simplybusiness/version-forget-me-not@v2
14
14
  env:
15
15
  ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
16
16
  VERSION_FILE_PATH: "lib/twiglet/version.rb"
@@ -0,0 +1,15 @@
1
+ name: "version update action"
2
+ on:
3
+ issue_comment:
4
+ types: [created]
5
+ jobs:
6
+ pr_commented:
7
+ runs-on: ubuntu-20.04
8
+ if: startsWith(github.event.comment.body, '/dobby')
9
+
10
+ steps:
11
+ - name: 'bump version'
12
+ uses: simplybusiness/dobby@v1.0.0
13
+ env:
14
+ ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
15
+ VERSION_FILE_PATH: lib/twiglet/version.rb
data/README.md CHANGED
@@ -110,7 +110,7 @@ This writes:
110
110
  It may be that when making a series of logs that write information about a single event, you may want to avoid duplication by creating an event specific logger that includes the context:
111
111
 
112
112
  ```ruby
113
- request_log = logger.with({ event: { action: 'HTTP request'}, trace: { id: '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb' }})
113
+ request_logger = logger.with({ event: { action: 'HTTP request'}, trace: { id: '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb' }})
114
114
  ```
115
115
 
116
116
  This can be used like any other Logger instance:
@@ -140,6 +140,10 @@ To access the formatter:
140
140
  logger.formatter
141
141
  ```
142
142
 
143
+ ### HTTP Request Logging
144
+ Take a look at this sample [Rack application](examples/rack/example_rack_app.rb#L15) with an ECS compliant
145
+ [request logger](/examples/rack/request_logger.rb) as a template when configuring your own request logging middleware with Twiglet.
146
+
143
147
  ## Use of dotted keys (DEPRECATED)
144
148
 
145
149
  Writing nested json objects could be confusing. This library has a built-in feature to convert dotted keys into nested objects, so if you log like this:
data/example_app.rb CHANGED
@@ -7,28 +7,32 @@ PORT = 8080
7
7
  logger = Twiglet::Logger.new('petshop')
8
8
 
9
9
  # Start our petshop
10
- logger.info({
11
- event: {
12
- action: 'startup'
13
- },
14
- message: "Ready to go, listening on port #{PORT}",
15
- server: {
16
- port: PORT
10
+ logger.info(
11
+ {
12
+ event: {
13
+ action: 'startup'
14
+ },
15
+ message: "Ready to go, listening on port #{PORT}",
16
+ server: {
17
+ port: PORT
18
+ }
17
19
  }
18
- })
20
+ )
19
21
 
20
22
  # Use text logging
21
23
  logger.info("Ready to go, listening on port #{PORT}")
22
24
  #
23
25
  # We get a request
24
- request_logger = logger.with({
25
- event: {
26
- action: 'HTTP request'
27
- },
28
- trace: {
29
- id: '126bb6fa-28a2-470f-b013-eefbf9182b2d'
26
+ request_logger = logger.with(
27
+ {
28
+ event: {
29
+ action: 'HTTP request'
30
+ },
31
+ trace: {
32
+ id: '126bb6fa-28a2-470f-b013-eefbf9182b2d'
33
+ }
30
34
  }
31
- })
35
+ )
32
36
 
33
37
  # Oh noes!
34
38
  db_err = StandardError.new('Connection timed-out')
@@ -36,17 +40,19 @@ db_err = StandardError.new('Connection timed-out')
36
40
  request_logger.error({ message: 'DB connection failed.' }, db_err) if db_err
37
41
 
38
42
  # We return an error to the requester
39
- request_logger.info({
40
- message: 'Internal Server Error',
41
- http: {
42
- request: {
43
- method: 'get'
44
- },
45
- response: {
46
- status_code: 500
43
+ request_logger.info(
44
+ {
45
+ message: 'Internal Server Error',
46
+ http: {
47
+ request: {
48
+ method: 'get'
49
+ },
50
+ response: {
51
+ status_code: 500
52
+ }
47
53
  }
48
54
  }
49
- })
55
+ )
50
56
 
51
57
  # Logging with an empty message is an anti-pattern and is therefore forbidden
52
58
  # Both of the following lines would throw an error
@@ -15,10 +15,12 @@ describe RequestLogger do
15
15
  end
16
16
 
17
17
  it 'logs the request data' do
18
- request.get("/some/path?some_var=1", 'HTTP_ACCEPT' => 'application/json',
19
- 'REMOTE_ADDR' => '0.0.0.0',
20
- 'HTTP_VERSION' => 'HTTP/1.1',
21
- 'HTTP_USER_AGENT' => 'Mozilla/5.0 (Macintosh)')
18
+ request.get(
19
+ "/some/path?some_var=1", 'HTTP_ACCEPT' => 'application/json',
20
+ 'REMOTE_ADDR' => '0.0.0.0',
21
+ 'HTTP_VERSION' => 'HTTP/1.1',
22
+ 'HTTP_USER_AGENT' => 'Mozilla/5.0 (Macintosh)'
23
+ )
22
24
  log = JSON.parse(output.string)
23
25
 
24
26
  expected_log = {
@@ -55,7 +57,7 @@ describe RequestLogger do
55
57
  end
56
58
 
57
59
  it 'does not log PII' do
58
- request.post("/user/info", input_data: {credit_card_no: '1234'})
60
+ request.post("/user/info", input_data: { credit_card_no: '1234' })
59
61
  log = output.string
60
62
  assert_includes log, "POST: /user/info"
61
63
  refute_includes log, 'credit_card_no'
@@ -33,9 +33,9 @@ module Twiglet
33
33
  def error(message = nil, error = nil, &block)
34
34
  if error
35
35
  error_fields = {
36
- 'error': {
37
- 'type': error.class,
38
- 'message': error.message
36
+ error: {
37
+ type: error.class,
38
+ message: error.message
39
39
  }
40
40
  }
41
41
  add_stack_trace(error_fields, error)
@@ -46,11 +46,13 @@ module Twiglet
46
46
  end
47
47
 
48
48
  def with(default_properties)
49
- Logger.new(@service_name,
50
- default_properties: default_properties,
51
- now: @now,
52
- output: @output,
53
- level: @level)
49
+ Logger.new(
50
+ @service_name,
51
+ default_properties: default_properties,
52
+ now: @now,
53
+ output: @output,
54
+ level: @level
55
+ )
54
56
  end
55
57
 
56
58
  alias_method :warning, :warn
@@ -1,11 +1,14 @@
1
1
  module Twiglet
2
2
  class Message < Hash
3
3
  def initialize(msg)
4
+ super
4
5
  case msg
5
6
  when String
6
7
  self[:message] = msg
7
8
  when Hash
8
9
  replace(msg.transform_keys!(&:to_sym))
10
+ else
11
+ super(msg)
9
12
  end
10
13
 
11
14
  validate!
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Twiglet
4
- VERSION = '3.0.2'
4
+ VERSION = '3.0.8'
5
5
  end
data/test/logger_test.rb CHANGED
@@ -18,9 +18,11 @@ describe Twiglet::Logger do
18
18
  before do
19
19
  @now = -> { Time.utc(2020, 5, 11, 15, 1, 1) }
20
20
  @buffer = StringIO.new
21
- @logger = Twiglet::Logger.new('petshop',
22
- now: @now,
23
- output: @buffer)
21
+ @logger = Twiglet::Logger.new(
22
+ 'petshop',
23
+ now: @now,
24
+ output: @buffer
25
+ )
24
26
  end
25
27
 
26
28
  it 'should throw an error with an empty service name' do
@@ -30,8 +32,10 @@ describe Twiglet::Logger do
30
32
  end
31
33
 
32
34
  it 'conforms to the standard Ruby Logger API' do
33
- [:debug, :debug?, :info, :info?, :warn, :warn?, :fatal, :fatal?, :error, :error?,
34
- :level, :level=, :sev_threshold=].each do |call|
35
+ [
36
+ :debug, :debug?, :info, :info?, :warn, :warn?, :fatal, :fatal?, :error, :error?,
37
+ :level, :level=, :sev_threshold=
38
+ ].each do |call|
35
39
  assert @logger.respond_to?(call), "Logger does not respond to #{call}"
36
40
  end
37
41
  end
@@ -39,12 +43,12 @@ describe Twiglet::Logger do
39
43
  describe 'JSON logging' do
40
44
  it 'should throw an error with an empty message' do
41
45
  assert_raises RuntimeError do
42
- @logger.info({message: ''})
46
+ @logger.info({ message: '' })
43
47
  end
44
48
  end
45
49
 
46
50
  it 'should log mandatory attributes' do
47
- @logger.error({message: 'Out of pets exception'})
51
+ @logger.error({ message: 'Out of pets exception' })
48
52
  actual_log = read_json(@buffer)
49
53
 
50
54
  expected_log = {
@@ -65,9 +69,13 @@ describe Twiglet::Logger do
65
69
  end
66
70
 
67
71
  it 'should log the provided message' do
68
- @logger.error({event:
69
- {action: 'exception'},
70
- message: 'Emergency! Emergency!'})
72
+ @logger.error(
73
+ {
74
+ event:
75
+ { action: 'exception' },
76
+ message: 'Emergency! Emergency!'
77
+ }
78
+ )
71
79
  log = read_json(@buffer)
72
80
 
73
81
  assert_equal 'exception', log[:event][:action]
@@ -82,17 +90,19 @@ describe Twiglet::Logger do
82
90
  service: {
83
91
  type: 'shop'
84
92
  },
85
- request: {method: 'get'},
86
- response: {status_code: 200}
93
+ request: { method: 'get' },
94
+ response: { status_code: 200 }
87
95
  }
88
96
 
89
97
  output = StringIO.new
90
- logger = Twiglet::Logger.new('petshop',
91
- now: @now,
92
- output: output,
93
- default_properties: extra_properties)
94
-
95
- logger.error({message: 'GET /cats'})
98
+ logger = Twiglet::Logger.new(
99
+ 'petshop',
100
+ now: @now,
101
+ output: output,
102
+ default_properties: extra_properties
103
+ )
104
+
105
+ logger.error({ message: 'GET /cats' })
96
106
  log = read_json output
97
107
 
98
108
  assert_equal '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb', log[:trace][:id]
@@ -104,17 +114,21 @@ describe Twiglet::Logger do
104
114
 
105
115
  it "should be able to add properties with '.with'" do
106
116
  # Let's add some context to this customer journey
107
- purchase_logger = @logger.with({
108
- trace: {id: '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb'},
109
- customer: {full_name: 'Freda Bloggs'},
110
- event: {action: 'pet purchase'}
111
- })
117
+ purchase_logger = @logger.with(
118
+ {
119
+ trace: { id: '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb' },
120
+ customer: { full_name: 'Freda Bloggs' },
121
+ event: { action: 'pet purchase' }
122
+ }
123
+ )
112
124
 
113
125
  # do stuff
114
- purchase_logger.info({
115
- message: 'customer bought a dog',
116
- pet: {name: 'Barker', species: 'dog', breed: 'Bitsa'}
117
- })
126
+ purchase_logger.info(
127
+ {
128
+ message: 'customer bought a dog',
129
+ pet: { name: 'Barker', species: 'dog', breed: 'Bitsa' }
130
+ }
131
+ )
118
132
 
119
133
  log = read_json @buffer
120
134
 
@@ -135,8 +149,8 @@ describe Twiglet::Logger do
135
149
  end
136
150
 
137
151
  it "should log multiple messages properly" do
138
- @logger.debug({message: 'hi'})
139
- @logger.info({message: 'there'})
152
+ @logger.debug({ message: 'hi' })
153
+ @logger.info({ message: 'there' })
140
154
 
141
155
  expected_output =
142
156
  '{"ecs":{"version":"1.5.0"},"@timestamp":"2020-05-11T15:01:01.000Z",'\
@@ -174,7 +188,7 @@ describe Twiglet::Logger do
174
188
 
175
189
  LEVELS.each do |attrs|
176
190
  it "should correctly log level when calling #{attrs[:method]}" do
177
- @logger.public_send(attrs[:method], {message: 'a log message'})
191
+ @logger.public_send(attrs[:method], { message: 'a log message' })
178
192
  actual_log = read_json(@buffer)
179
193
 
180
194
  assert_equal attrs[:level], actual_log[:log][:level]
@@ -188,7 +202,7 @@ describe Twiglet::Logger do
188
202
  begin
189
203
  1 / 0
190
204
  rescue StandardError => e
191
- @logger.error({message: 'Artificially raised exception'}, e)
205
+ @logger.error({ message: 'Artificially raised exception' }, e)
192
206
  end
193
207
 
194
208
  actual_log = read_json(@buffer)
@@ -201,7 +215,7 @@ describe Twiglet::Logger do
201
215
 
202
216
  it 'should log an error without backtrace' do
203
217
  e = StandardError.new('Connection timed-out')
204
- @logger.error({message: 'Artificially raised exception'}, e)
218
+ @logger.error({ message: 'Artificially raised exception' }, e)
205
219
 
206
220
  actual_log = read_json(@buffer)
207
221
 
@@ -284,13 +298,15 @@ describe Twiglet::Logger do
284
298
 
285
299
  describe 'dotted keys' do
286
300
  it 'should be able to convert dotted keys to nested objects' do
287
- @logger.debug({
288
- "trace.id": '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb',
289
- message: 'customer bought a dog',
290
- "pet.name": 'Barker',
291
- "pet.species": 'dog',
292
- "pet.breed": 'Bitsa'
293
- })
301
+ @logger.debug(
302
+ {
303
+ "trace.id": '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb',
304
+ message: 'customer bought a dog',
305
+ "pet.name": 'Barker',
306
+ "pet.species": 'dog',
307
+ "pet.breed": 'Bitsa'
308
+ }
309
+ )
294
310
  log = read_json(@buffer)
295
311
 
296
312
  assert_equal '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb', log[:trace][:id]
@@ -301,12 +317,14 @@ describe Twiglet::Logger do
301
317
  end
302
318
 
303
319
  it 'should be able to mix dotted keys and nested objects' do
304
- @logger.debug({
305
- "trace.id": '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb',
306
- message: 'customer bought a dog',
307
- pet: {name: 'Barker', breed: 'Bitsa'},
308
- "pet.species": 'dog'
309
- })
320
+ @logger.debug(
321
+ {
322
+ "trace.id": '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb',
323
+ message: 'customer bought a dog',
324
+ pet: { name: 'Barker', breed: 'Bitsa' },
325
+ "pet.species": 'dog'
326
+ }
327
+ )
310
328
  log = read_json(@buffer)
311
329
 
312
330
  assert_equal '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb', log[:trace][:id]
@@ -7,7 +7,11 @@ SimpleCov.start do
7
7
  if ENV['CI']
8
8
  formatter SimpleCov::Formatter::SimpleFormatter
9
9
  else
10
- formatter SimpleCov::Formatter::MultiFormatter.new([SimpleCov::Formatter::SimpleFormatter,
11
- SimpleCov::Formatter::HTMLFormatter])
10
+ formatter SimpleCov::Formatter::MultiFormatter.new(
11
+ [
12
+ SimpleCov::Formatter::SimpleFormatter,
13
+ SimpleCov::Formatter::HTMLFormatter
14
+ ]
15
+ )
12
16
  end
13
17
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twiglet
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.2
4
+ version: 3.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simply Business
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-15 00:00:00.000000000 Z
11
+ date: 2021-02-11 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Like a log, only smaller.
14
14
  email:
@@ -18,9 +18,11 @@ extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
20
  - ".github/CODEOWNERS"
21
+ - ".github/dependabot.yml"
21
22
  - ".github/workflows/gem-publish.yml"
22
23
  - ".github/workflows/ruby.yml"
23
24
  - ".github/workflows/version-forget-me-not.yml"
25
+ - ".github/workflows/version-update.yml"
24
26
  - ".gitignore"
25
27
  - ".rubocop.yml"
26
28
  - ".ruby-version"