twiglet 3.0.2 → 3.0.8

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 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"