twiglet 2.3.9 → 3.0.1

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: bd37b7e4eb03587c77c448d986a57dea2db5c119208c9588d400614785c9ab00
4
- data.tar.gz: 2087e6acf11a7944083c81a493f8dc1608f8789ea5e5fb09cdbe8fbad7391456
3
+ metadata.gz: 65c3f0028e0ac918736f63a2475fb45231586d51256a8778d4730ebd7792675c
4
+ data.tar.gz: 98d3607d5e1aad68f00d0ced7ccce24f0dba0c8b3eede84620a4a37a102a9849
5
5
  SHA512:
6
- metadata.gz: 15599c765672e0bcbdbd03f717dde89ccb99ac2142bbb9aad56337466f31c0e9355aa18cd07b4f6cbe9cf53768d9e8efc59042c98aa66aacf82a3ce4e1296993
7
- data.tar.gz: 67c1dae018c5fa57e4bffc0144b58ae5e9316faf4a1190d919d5828a44240955d246a12e6dde07b34b459694eb4808ac81d02fe2b08bc0187dce3562c8d94e6f
6
+ metadata.gz: '0418346dbb4f5d486062caa13b7d1859a96309d00061b3e818563c9c399601f73035e2c89c64888e168d2a040fbb96c18a47e150c505859a58c067cfe46fe76f'
7
+ data.tar.gz: 9437cae3f2662746cd059a660f9e0884c5c0edd7e56de77771d81678c01f6e55006e048b50bd44f7a99d240b9a5d3527b70a15528d0f4e8711ca2e0954c73235
@@ -16,7 +16,7 @@ jobs:
16
16
 
17
17
  strategy:
18
18
  matrix:
19
- ruby-version: [2.5, 2.6, 2.7]
19
+ ruby-version: [2.6, 2.7]
20
20
 
21
21
  steps:
22
22
  - uses: actions/checkout@v2
@@ -2,7 +2,7 @@ inherit_gem:
2
2
  simplycop: .simplycop.yml
3
3
 
4
4
  AllCops:
5
- TargetRubyVersion: 2.5
5
+ TargetRubyVersion: 2.6
6
6
  Rails:
7
7
  Enabled: false
8
8
  Documentation:
data/Gemfile CHANGED
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  source 'https://rubygems.org'
4
- gem 'simplycop', git: 'https://github.com/simplybusiness/simplycop.git'
5
4
  group :development, :test do
6
5
  gem 'minitest'
7
6
  gem 'rake'
8
7
  gem 'simplecov', '0.17.1'
8
+ gem 'simplycop'
9
9
  end
data/Makefile CHANGED
@@ -1,9 +1,21 @@
1
- .PHONY: all build test
1
+ .PHONY: all build clean shell test
2
2
 
3
- all: build test
3
+ all: clean build test
4
4
 
5
5
  build:
6
6
  docker build -t simplybusiness/ruby-dev:2.6.5 .
7
7
 
8
+ clean:
9
+ rm -f *~
10
+
11
+ shell:
12
+ docker run -it \
13
+ -v `pwd`:/var/app \
14
+ simplybusiness/ruby-dev:2.6.5 \
15
+ bash
16
+
8
17
  test:
9
- docker run -it -v `pwd`:/var/app simplybusiness/ruby-dev:2.6.5 bundle exec rake test
18
+ docker run -it \
19
+ -v `pwd`:/var/app \
20
+ simplybusiness/ruby-dev:2.6.5 \
21
+ bundle exec rake test
data/README.md CHANGED
@@ -11,13 +11,13 @@ gem install twiglet
11
11
 
12
12
  ## How to use
13
13
 
14
- Create a new logger like so:
14
+ ### Instantiate the logger
15
15
 
16
16
  ```ruby
17
17
  require 'twiglet/logger'
18
18
  logger = Twiglet::Logger.new('service name')
19
19
  ```
20
-
20
+ #### Optional initialization parameters
21
21
  A hash can optionally be passed in as a keyword argument for `default_properties`. This hash must be in the Elastic Common Schema format and will be present in every log message created by this Twiglet logger object.
22
22
 
23
23
  You may also provide an optional `output` keyword argument which should be an object with a `puts` method - like `$stdout`.
@@ -28,7 +28,7 @@ Lastly, you may provide the optional keyword argument `level` to initialize the
28
28
 
29
29
  The defaults for both `output` and `now` should serve for most uses, though you may want to override them for testing as we have done [here](test/logger_test.rb).
30
30
 
31
- To use, simply invoke like most other loggers:
31
+ ### Invoke the Logger
32
32
 
33
33
  ```ruby
34
34
  logger.error({ event: { action: 'startup' }, message: "Emergency! There's an Emergency going on" })
@@ -42,9 +42,10 @@ This will write to STDOUT a JSON string:
42
42
 
43
43
  Obviously the timestamp will be different.
44
44
 
45
- Alternatively, if you just want to log some error message in text format
45
+ Alternatively, if you just want to log some error string:
46
+
46
47
  ```ruby
47
- logger.error( "Emergency! There's an Emergency going on")
48
+ logger.error("Emergency! There's an Emergency going on")
48
49
  ```
49
50
 
50
51
  This will write to STDOUT a JSON string:
@@ -53,14 +54,27 @@ This will write to STDOUT a JSON string:
53
54
  {"service":{"name":"service name"},"@timestamp":"2020-05-14T10:54:59.164+01:00","log":{"level":"error"}, "message":"Emergency! There's an Emergency going on"}
54
55
  ```
55
56
 
56
- Errors can be logged as well, and this will log the error message and backtrace in the relevant ECS compliant fields:
57
+ A message is always required unless a block is provided. The message can be an object or a string.
58
+
59
+ #### Error logging
60
+ An optional error can also be provided, in which case the error message and backtrace will be logged in the relevant ECS compliant fields:
57
61
 
58
62
  ```ruby
59
63
  db_err = StandardError.new('Connection timed-out')
60
64
  logger.error({ message: 'DB connection failed.' }, db_err)
65
+
66
+ # this is also valid
67
+ logger.error('DB connection failed.', db_err)
68
+ ```
69
+
70
+ These will both result in the same JSON string written to STDOUT:
71
+
72
+ ```json
73
+ {"ecs":{"version":"1.5.0"},"@timestamp":"2020-08-21T15:44:37.890Z","service":{"name":"service name"},"log":{"level":"error"},"message":"DB connection failed.","error":{"message":"Connection timed-out"}}
61
74
  ```
62
75
 
63
- Add log event specific information simply as attributes in a hash:
76
+ #### Custom fields
77
+ Log custom event-specific information simply as attributes in a hash:
64
78
 
65
79
  ```ruby
66
80
  logger.info({
@@ -81,18 +95,18 @@ This writes:
81
95
  {"service":{"name":"service name"},"@timestamp":"2020-05-14T10:56:49.527+01:00","log":{"level":"info"},"event":{"action":"HTTP request"},"message":"GET /pets success","trace":{"id":"1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb"},"http":{"request":{"method":"get"},"response":{"status_code":200}},"url":{"path":"/pets"}}
82
96
  ```
83
97
 
84
- Similar to error you can use text logging here as:
98
+ Similar to error you can use string logging here as:
85
99
 
86
100
  ```
87
101
  logger.info('GET /pets success')
88
102
  ```
103
+
89
104
  This writes:
90
105
 
91
106
  ```json
92
107
  {"service":{"name":"service name"},"@timestamp":"2020-05-14T10:56:49.527+01:00","log":{"level":"info"}}
93
108
  ```
94
109
 
95
-
96
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:
97
111
 
98
112
  ```ruby
@@ -117,6 +131,15 @@ which will print:
117
131
  {"service":{"name":"service name"},"@timestamp":"2020-05-14T10:58:30.780+01:00","log":{"level":"error"},"event":{"action":"HTTP request"},"trace":{"id":"126bb6fa-28a2-470f-b013-eefbf9182b2d"},"message":"Error 500 in /pets/buy","http":{"request":{"method":"post","url.path":"/pet/buy"},"response":{"status_code":500}}}
118
132
  ```
119
133
 
134
+ ### Log formatting
135
+ Some third party applications will allow you to optionally specify a [log formatter](https://ruby-doc.org/stdlib-2.4.0/libdoc/logger/rdoc/Logger/Formatter.html).
136
+ Supplying a Twiglet log formatter will format those third party logs so that they are ECS compliant and have the same default parameters as your application's internal logs.
137
+
138
+ To access the formatter:
139
+ ```ruby
140
+ logger.formatter
141
+ ```
142
+
120
143
  ## Use of dotted keys (DEPRECATED)
121
144
 
122
145
  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:
@@ -8,27 +8,27 @@ logger = Twiglet::Logger.new('petshop')
8
8
 
9
9
  # Start our petshop
10
10
  logger.info({
11
- event: {
12
- action: 'startup'
13
- },
14
- message: "Ready to go, listening on port #{PORT}",
15
- server: {
16
- port: PORT
17
- }
18
- })
11
+ event: {
12
+ action: 'startup'
13
+ },
14
+ message: "Ready to go, listening on port #{PORT}",
15
+ server: {
16
+ port: PORT
17
+ }
18
+ })
19
19
 
20
20
  # Use text logging
21
21
  logger.info("Ready to go, listening on port #{PORT}")
22
22
  #
23
23
  # We get a request
24
24
  request_logger = logger.with({
25
- event: {
26
- action: 'HTTP request'
27
- },
28
- trace: {
29
- id: '126bb6fa-28a2-470f-b013-eefbf9182b2d'
30
- }
31
- })
25
+ event: {
26
+ action: 'HTTP request'
27
+ },
28
+ trace: {
29
+ id: '126bb6fa-28a2-470f-b013-eefbf9182b2d'
30
+ }
31
+ })
32
32
 
33
33
  # Oh noes!
34
34
  db_err = StandardError.new('Connection timed-out')
@@ -37,16 +37,16 @@ request_logger.error({ message: 'DB connection failed.' }, db_err) if db_err
37
37
 
38
38
  # We return an error to the requester
39
39
  request_logger.info({
40
- message: 'Internal Server Error',
41
- http: {
42
- request: {
43
- method: 'get'
44
- },
45
- response: {
46
- status_code: 500
47
- }
48
- }
49
- })
40
+ message: 'Internal Server Error',
41
+ http: {
42
+ request: {
43
+ method: 'get'
44
+ },
45
+ response: {
46
+ status_code: 500
47
+ }
48
+ }
49
+ })
50
50
 
51
51
  # Logging with an empty message is an anti-pattern and is therefore forbidden
52
52
  # Both of the following lines would throw an error
@@ -22,8 +22,8 @@ module HashExtensions
22
22
 
23
23
  def build_nested_object(key, val)
24
24
  key.to_s
25
- .split('.')
26
- .reverse
27
- .reduce(val) { |nested, key_part| Hash[key_part.to_sym, nested] }
25
+ .split('.')
26
+ .reverse
27
+ .reduce(val) { |nested, key_part| Hash[key_part.to_sym, nested] }
28
28
  end
29
29
  end
@@ -1,5 +1,6 @@
1
1
  require 'logger'
2
2
  require_relative '../hash_extensions'
3
+ require_relative 'message'
3
4
 
4
5
  module Twiglet
5
6
  class Formatter < ::Logger::Formatter
@@ -17,38 +18,12 @@ module Twiglet
17
18
 
18
19
  def call(severity, _time, _progname, msg)
19
20
  level = severity.downcase
20
- log(level: level, message: msg)
21
+ log(level: level, message: Message.new(msg))
21
22
  end
22
23
 
23
24
  private
24
25
 
25
26
  def log(level:, message:)
26
- case message
27
- when String
28
- log_text(level, message: message)
29
- when Hash
30
- log_object(level, message: message)
31
- else
32
- raise('Message must be String or Hash')
33
- end
34
- end
35
-
36
- def log_text(level, message:)
37
- raise('The \'message\' property of log object must not be empty') if message.strip.empty?
38
-
39
- message = { message: message }
40
- log_message(level, message: message)
41
- end
42
-
43
- def log_object(level, message:)
44
- message = message.transform_keys(&:to_sym)
45
- message.key?(:message) || raise('Log object must have a \'message\' property')
46
- message[:message].strip.empty? && raise('The \'message\' property of log object must not be empty')
47
-
48
- log_message(level, message: message)
49
- end
50
-
51
- def log_message(level, message:)
52
27
  base_message = {
53
28
  ecs: {
54
29
  version: '1.5.0'
@@ -5,6 +5,7 @@ require 'time'
5
5
  require 'json'
6
6
  require_relative 'formatter'
7
7
  require_relative '../hash_extensions'
8
+ require_relative 'message'
8
9
 
9
10
  module Twiglet
10
11
  class Logger < ::Logger
@@ -29,15 +30,16 @@ module Twiglet
29
30
  super(output, formatter: formatter, level: level)
30
31
  end
31
32
 
32
- def error(message = {}, error = nil, &block)
33
+ def error(message = nil, error = nil, &block)
33
34
  if error
34
35
  error_fields = {
35
36
  'error': {
37
+ 'type': error.class,
36
38
  'message': error.message
37
39
  }
38
40
  }
39
41
  add_stack_trace(error_fields, error)
40
- message.is_a?(Hash) ? message.merge!(error_fields) : error_fields.merge!(message: message)
42
+ message = Message.new(message).merge(error_fields)
41
43
  end
42
44
 
43
45
  super(message, &block)
@@ -0,0 +1,24 @@
1
+ module Twiglet
2
+ class Message < Hash
3
+ def initialize(msg)
4
+ case msg
5
+ when String
6
+ self[:message] = msg
7
+ when Hash
8
+ replace(msg.transform_keys!(&:to_sym))
9
+ end
10
+
11
+ validate!
12
+ end
13
+
14
+ private
15
+
16
+ def validate!
17
+ raise 'Message must be initialized with a String or a non-empty Hash' if empty?
18
+
19
+ raise 'Log object must have a \'message\' property' unless self[:message]
20
+
21
+ raise 'The \'message\' property of the log object must not be empty' if self[:message].strip.empty?
22
+ end
23
+ end
24
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Twiglet
4
- VERSION = '2.3.9'
4
+ VERSION = '3.0.1'
5
5
  end
@@ -3,6 +3,16 @@
3
3
  require 'minitest/autorun'
4
4
  require_relative '../lib/twiglet/logger'
5
5
 
6
+ LEVELS = [
7
+ { method: :debug, level: 'debug' },
8
+ { method: :info, level: 'info' },
9
+ { method: :warning, level: 'warn' },
10
+ { method: :warn, level: 'warn' },
11
+ { method: :critical, level: 'fatal' },
12
+ { method: :fatal, level: 'fatal' },
13
+ { method: :error, level: 'error' }
14
+ ].freeze
15
+
6
16
  # rubocop:disable Metrics/BlockLength
7
17
  describe Twiglet::Logger do
8
18
  before do
@@ -13,16 +23,6 @@ describe Twiglet::Logger do
13
23
  output: @buffer)
14
24
  end
15
25
 
16
- LEVELS = [
17
- { method: :debug, level: 'debug' },
18
- { method: :info, level: 'info' },
19
- { method: :warning, level: 'warn' },
20
- { method: :warn, level: 'warn' },
21
- { method: :critical, level: 'fatal' },
22
- { method: :fatal, level: 'fatal' },
23
- { method: :error, level: 'error' }
24
- ].freeze
25
-
26
26
  it 'should throw an error with an empty service name' do
27
27
  assert_raises RuntimeError do
28
28
  Twiglet::Logger.new(' ')
@@ -105,16 +105,16 @@ describe Twiglet::Logger do
105
105
  it "should be able to add properties with '.with'" do
106
106
  # Let's add some context to this customer journey
107
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
- })
108
+ trace: {id: '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb'},
109
+ customer: {full_name: 'Freda Bloggs'},
110
+ event: {action: 'pet purchase'}
111
+ })
112
112
 
113
113
  # do stuff
114
114
  purchase_logger.info({
115
- message: 'customer bought a dog',
116
- pet: {name: 'Barker', species: 'dog', breed: 'Bitsa'}
117
- })
115
+ message: 'customer bought a dog',
116
+ pet: {name: 'Barker', species: 'dog', breed: 'Bitsa'}
117
+ })
118
118
 
119
119
  log = read_json @buffer
120
120
 
@@ -149,39 +149,6 @@ describe Twiglet::Logger do
149
149
  assert_equal expected_output, @buffer.string
150
150
  end
151
151
 
152
- it 'should be able to convert dotted keys to nested objects' do
153
- @logger.debug({
154
- "trace.id": '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb',
155
- message: 'customer bought a dog',
156
- "pet.name": 'Barker',
157
- "pet.species": 'dog',
158
- "pet.breed": 'Bitsa'
159
- })
160
- log = read_json(@buffer)
161
-
162
- assert_equal '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb', log[:trace][:id]
163
- assert_equal 'customer bought a dog', log[:message]
164
- assert_equal 'Barker', log[:pet][:name]
165
- assert_equal 'dog', log[:pet][:species]
166
- assert_equal 'Bitsa', log[:pet][:breed]
167
- end
168
-
169
- it 'should be able to mix dotted keys and nested objects' do
170
- @logger.debug({
171
- "trace.id": '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb',
172
- message: 'customer bought a dog',
173
- pet: {name: 'Barker', breed: 'Bitsa'},
174
- "pet.species": 'dog'
175
- })
176
- log = read_json(@buffer)
177
-
178
- assert_equal '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb', log[:trace][:id]
179
- assert_equal 'customer bought a dog', log[:message]
180
- assert_equal 'Barker', log[:pet][:name]
181
- assert_equal 'dog', log[:pet][:species]
182
- assert_equal 'Bitsa', log[:pet][:breed]
183
- end
184
-
185
152
  it 'should work with mixed string and symbol properties' do
186
153
  log = {
187
154
  "trace.id": '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb'
@@ -205,6 +172,18 @@ describe Twiglet::Logger do
205
172
  assert_equal 'Bitsa', actual_log[:pet][:breed]
206
173
  end
207
174
 
175
+ LEVELS.each do |attrs|
176
+ it "should correctly log level when calling #{attrs[:method]}" do
177
+ @logger.public_send(attrs[:method], {message: 'a log message'})
178
+ actual_log = read_json(@buffer)
179
+
180
+ assert_equal attrs[:level], actual_log[:log][:level]
181
+ assert_equal 'a log message', actual_log[:message]
182
+ end
183
+ end
184
+ end
185
+
186
+ describe 'logging an exception' do
208
187
  it 'should log an error with backtrace' do
209
188
  begin
210
189
  1 / 0
@@ -216,6 +195,7 @@ describe Twiglet::Logger do
216
195
 
217
196
  assert_equal 'Artificially raised exception', actual_log[:message]
218
197
  assert_equal 'divided by 0', actual_log[:error][:message]
198
+ assert_equal 'ZeroDivisionError', actual_log[:error][:type]
219
199
  assert_match 'logger_test.rb', actual_log[:error][:stack_trace].lines.first
220
200
  end
221
201
 
@@ -226,18 +206,20 @@ describe Twiglet::Logger do
226
206
  actual_log = read_json(@buffer)
227
207
 
228
208
  assert_equal 'Artificially raised exception', actual_log[:message]
209
+ assert_equal 'StandardError', actual_log[:error][:type]
229
210
  assert_equal 'Connection timed-out', actual_log[:error][:message]
230
211
  refute actual_log[:error].key?(:stack_trace)
231
212
  end
232
213
 
233
- LEVELS.each do |attrs|
234
- it "should correctly log level when calling #{attrs[:method]}" do
235
- @logger.public_send(attrs[:method], {message: 'a log message'})
236
- actual_log = read_json(@buffer)
214
+ it 'should log an error with string message' do
215
+ e = StandardError.new('Unknown error')
216
+ @logger.error('Artificially raised exception with string message', e)
237
217
 
238
- assert_equal attrs[:level], actual_log[:log][:level]
239
- assert_equal 'a log message', actual_log[:message]
240
- end
218
+ actual_log = read_json(@buffer)
219
+
220
+ assert_equal 'Artificially raised exception with string message', actual_log[:message]
221
+ assert_equal 'StandardError', actual_log[:error][:type]
222
+ assert_equal 'Unknown error', actual_log[:error][:message]
241
223
  end
242
224
  end
243
225
 
@@ -300,6 +282,41 @@ describe Twiglet::Logger do
300
282
  end
301
283
  end
302
284
 
285
+ describe 'dotted keys' do
286
+ 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
+ })
294
+ log = read_json(@buffer)
295
+
296
+ assert_equal '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb', log[:trace][:id]
297
+ assert_equal 'customer bought a dog', log[:message]
298
+ assert_equal 'Barker', log[:pet][:name]
299
+ assert_equal 'dog', log[:pet][:species]
300
+ assert_equal 'Bitsa', log[:pet][:breed]
301
+ end
302
+
303
+ 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
+ })
310
+ log = read_json(@buffer)
311
+
312
+ assert_equal '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb', log[:trace][:id]
313
+ assert_equal 'customer bought a dog', log[:message]
314
+ assert_equal 'Barker', log[:pet][:name]
315
+ assert_equal 'dog', log[:pet][:species]
316
+ assert_equal 'Bitsa', log[:pet][:breed]
317
+ end
318
+ end
319
+
303
320
  describe 'logger level' do
304
321
  [
305
322
  { expression: :info, level: 1 },
@@ -0,0 +1,31 @@
1
+ require 'minitest/autorun'
2
+ require_relative '../lib/twiglet/message'
3
+
4
+ describe Twiglet::Message do
5
+ it 'raises if message is empty' do
6
+ assert_raises RuntimeError do
7
+ Twiglet::Message.new(' ')
8
+ end
9
+ end
10
+
11
+ it 'raises if message is not provided' do
12
+ assert_raises RuntimeError do
13
+ Twiglet::Message.new(foo: 'bar')
14
+ end
15
+ end
16
+
17
+ it 'raises on unrecognized inputs' do
18
+ assert_raises RuntimeError do
19
+ Twiglet::Message.new(OpenStruct.new(message: 'hello'))
20
+ end
21
+ end
22
+
23
+ it 'returns a message hash from a string' do
24
+ assert_equal Twiglet::Message.new('hello, world'), { message: 'hello, world' }
25
+ end
26
+
27
+ it 'returns a message hash with symbolized keys' do
28
+ input_message = { 'key' => 'value', 'message' => 'hello, world' }
29
+ assert_equal Twiglet::Message.new(input_message), { key: 'value', message: 'hello, world' }
30
+ end
31
+ end
@@ -18,7 +18,7 @@ Gem::Specification.new do |gem|
18
18
  gem.test_files = `git ls-files -- {test}/*`.split("\n")
19
19
 
20
20
  gem.require_paths = ['lib']
21
- gem.required_ruby_version = '>= 2.5'
21
+ gem.required_ruby_version = '>= 2.6'
22
22
 
23
23
  gem.license = 'Copyright SimplyBusiness'
24
24
  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: 2.3.9
4
+ version: 3.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simply Business
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-13 00:00:00.000000000 Z
11
+ date: 2020-12-22 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Like a log, only smaller.
14
14
  email:
@@ -39,10 +39,12 @@ files:
39
39
  - lib/hash_extensions.rb
40
40
  - lib/twiglet/formatter.rb
41
41
  - lib/twiglet/logger.rb
42
+ - lib/twiglet/message.rb
42
43
  - lib/twiglet/version.rb
43
44
  - test/formatter_test.rb
44
45
  - test/hash_extensions_test.rb
45
46
  - test/logger_test.rb
47
+ - test/message_test.rb
46
48
  - test/test_coverage.rb
47
49
  - twiglet.gemspec
48
50
  homepage: https://github.com/simplybusiness/twiglet-ruby
@@ -57,14 +59,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
57
59
  requirements:
58
60
  - - ">="
59
61
  - !ruby/object:Gem::Version
60
- version: '2.5'
62
+ version: '2.6'
61
63
  required_rubygems_version: !ruby/object:Gem::Requirement
62
64
  requirements:
63
65
  - - ">="
64
66
  - !ruby/object:Gem::Version
65
67
  version: '0'
66
68
  requirements: []
67
- rubygems_version: 3.0.3
69
+ rubygems_version: 3.1.4
68
70
  signing_key:
69
71
  specification_version: 4
70
72
  summary: Twiglet