twiglet 3.0.8 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +3 -0
- data/lib/twiglet/formatter.rb +6 -2
- data/lib/twiglet/logger.rb +13 -2
- data/lib/twiglet/message.rb +0 -12
- data/lib/twiglet/validation_schema.json +10 -0
- data/lib/twiglet/validator.rb +25 -0
- data/lib/twiglet/version.rb +1 -1
- data/test/formatter_test.rb +2 -1
- data/test/logger_test.rb +30 -2
- data/test/message_test.rb +0 -18
- data/test/validator_test.rb +38 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 120d52bf23086d2db6f65f068aa087835914bcfe52c3ef1f8b6b886f946e9dcd
|
4
|
+
data.tar.gz: 8355c113e09882c4b1346111bba954b82f81d69c0290d1055dca4bb61174fc09
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65ca30c0dcf26b8190b7840b70bd5a183b481333bc98af0abfed2835a5a25ec664e2b3c24f10d90f40a6a1d5a18fb90d9f97c2c2aae0ab49b123558049cc11da
|
7
|
+
data.tar.gz: 5936e07ac730cd18b39b5777a3fd1a7b8d805852726ad2732d46d6acdb1c7ef820f7dacf87ba68a85352dd3653c0e49b132a90ad71a40dd7ebdc3744ff9e68b8
|
data/Gemfile
CHANGED
data/lib/twiglet/formatter.rb
CHANGED
@@ -1,24 +1,28 @@
|
|
1
1
|
require 'logger'
|
2
2
|
require_relative '../hash_extensions'
|
3
3
|
require_relative 'message'
|
4
|
+
require_relative 'validator'
|
4
5
|
|
5
6
|
module Twiglet
|
6
7
|
class Formatter < ::Logger::Formatter
|
7
8
|
Hash.include HashExtensions
|
8
9
|
|
9
10
|
def initialize(service_name,
|
10
|
-
default_properties: {},
|
11
|
+
validator:, default_properties: {},
|
11
12
|
now: -> { Time.now.utc })
|
12
13
|
@service_name = service_name
|
13
14
|
@now = now
|
14
15
|
@default_properties = default_properties
|
16
|
+
@validator = validator
|
15
17
|
|
16
18
|
super()
|
17
19
|
end
|
18
20
|
|
19
21
|
def call(severity, _time, _progname, msg)
|
20
22
|
level = severity.downcase
|
21
|
-
|
23
|
+
message = Message.new(msg)
|
24
|
+
@validator.validate(message)
|
25
|
+
log(level: level, message: message)
|
22
26
|
end
|
23
27
|
|
24
28
|
private
|
data/lib/twiglet/logger.rb
CHANGED
@@ -26,8 +26,19 @@ module Twiglet
|
|
26
26
|
raise 'Service name is mandatory' \
|
27
27
|
unless service_name.is_a?(String) && !service_name.strip.empty?
|
28
28
|
|
29
|
-
|
30
|
-
|
29
|
+
@validator = Validator.from_file('lib/twiglet/validation_schema.json')
|
30
|
+
|
31
|
+
@formatter = Twiglet::Formatter.new(
|
32
|
+
service_name,
|
33
|
+
default_properties: default_properties,
|
34
|
+
now: now,
|
35
|
+
validator: @validator
|
36
|
+
)
|
37
|
+
super(output, formatter: @formatter, level: level)
|
38
|
+
end
|
39
|
+
|
40
|
+
def configure_validation_error_response(&block)
|
41
|
+
@validator.custom_error_handler = block
|
31
42
|
end
|
32
43
|
|
33
44
|
def error(message = nil, error = nil, &block)
|
data/lib/twiglet/message.rb
CHANGED
@@ -10,18 +10,6 @@ module Twiglet
|
|
10
10
|
else
|
11
11
|
super(msg)
|
12
12
|
end
|
13
|
-
|
14
|
-
validate!
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def validate!
|
20
|
-
raise 'Message must be initialized with a String or a non-empty Hash' if empty?
|
21
|
-
|
22
|
-
raise 'Log object must have a \'message\' property' unless self[:message]
|
23
|
-
|
24
|
-
raise 'The \'message\' property of the log object must not be empty' if self[:message].strip.empty?
|
25
13
|
end
|
26
14
|
end
|
27
15
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json-schema'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module Twiglet
|
7
|
+
class Validator
|
8
|
+
attr_accessor :custom_error_handler
|
9
|
+
|
10
|
+
def initialize(schema)
|
11
|
+
@schema = schema
|
12
|
+
@custom_error_handler = ->(e) { raise e }
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.from_file(file_path)
|
16
|
+
new(JSON.parse(File.read(file_path)))
|
17
|
+
end
|
18
|
+
|
19
|
+
def validate(message)
|
20
|
+
JSON::Validator.validate!(@schema, message)
|
21
|
+
rescue JSON::Schema::ValidationError => e
|
22
|
+
custom_error_handler.call(e)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/twiglet/version.rb
CHANGED
data/test/formatter_test.rb
CHANGED
@@ -3,11 +3,12 @@
|
|
3
3
|
require 'minitest/autorun'
|
4
4
|
require 'json'
|
5
5
|
require_relative '../lib/twiglet/formatter'
|
6
|
+
require_relative '../lib/twiglet/validator'
|
6
7
|
|
7
8
|
describe Twiglet::Formatter do
|
8
9
|
before do
|
9
10
|
@now = -> { Time.utc(2020, 5, 11, 15, 1, 1) }
|
10
|
-
@formatter = Twiglet::Formatter.new('petshop', now: @now)
|
11
|
+
@formatter = Twiglet::Formatter.new('petshop', now: @now, validator: Twiglet::Validator.new({}))
|
11
12
|
end
|
12
13
|
|
13
14
|
it 'initializes an instance of a Ruby Logger Formatter' do
|
data/test/logger_test.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'minitest/autorun'
|
4
|
+
require 'minitest/mock'
|
4
5
|
require_relative '../lib/twiglet/logger'
|
5
6
|
|
6
7
|
LEVELS = [
|
@@ -42,11 +43,17 @@ describe Twiglet::Logger do
|
|
42
43
|
|
43
44
|
describe 'JSON logging' do
|
44
45
|
it 'should throw an error with an empty message' do
|
45
|
-
assert_raises
|
46
|
+
assert_raises JSON::Schema::ValidationError, "The property '#/message' was not of a minimum string length of 1" do
|
46
47
|
@logger.info({ message: '' })
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
51
|
+
it 'should throw an error if message is missing' do
|
52
|
+
assert_raises JSON::Schema::ValidationError, "The property '#/message' was not of a minimum string length of 1" do
|
53
|
+
@logger.info({ foo: 'bar' })
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
50
57
|
it 'should log mandatory attributes' do
|
51
58
|
@logger.error({ message: 'Out of pets exception' })
|
52
59
|
actual_log = read_json(@buffer)
|
@@ -239,7 +246,7 @@ describe Twiglet::Logger do
|
|
239
246
|
|
240
247
|
describe 'text logging' do
|
241
248
|
it 'should throw an error with an empty message' do
|
242
|
-
assert_raises
|
249
|
+
assert_raises JSON::Schema::ValidationError, "The property '#/message' was not of a minimum string length of 1" do
|
243
250
|
@logger.info('')
|
244
251
|
end
|
245
252
|
end
|
@@ -352,6 +359,27 @@ describe Twiglet::Logger do
|
|
352
359
|
end
|
353
360
|
end
|
354
361
|
|
362
|
+
describe 'configuring error response' do
|
363
|
+
it 'blows up by default' do
|
364
|
+
assert_raises JSON::Schema::ValidationError,
|
365
|
+
"The property '#/message' of type boolean did not match the following type: string" do
|
366
|
+
@logger.debug(message: true)
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
it 'silently swallows errors when configured to do so' do
|
371
|
+
mock = Minitest::Mock.new
|
372
|
+
|
373
|
+
@logger.configure_validation_error_response do |_e|
|
374
|
+
mock.notify_error("Logging schema validation error")
|
375
|
+
end
|
376
|
+
|
377
|
+
mock.expect(:notify_error, nil, ["Logging schema validation error"])
|
378
|
+
nonconformant_log = { message: true }
|
379
|
+
@logger.debug(nonconformant_log)
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
355
383
|
private
|
356
384
|
|
357
385
|
def read_json(buffer)
|
data/test/message_test.rb
CHANGED
@@ -2,24 +2,6 @@ require 'minitest/autorun'
|
|
2
2
|
require_relative '../lib/twiglet/message'
|
3
3
|
|
4
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
5
|
it 'returns a message hash from a string' do
|
24
6
|
assert_equal Twiglet::Message.new('hello, world'), { message: 'hello, world' }
|
25
7
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require_relative '../lib/twiglet/validator'
|
5
|
+
|
6
|
+
describe Twiglet::Validator do
|
7
|
+
let(:valid)
|
8
|
+
|
9
|
+
before do
|
10
|
+
schema = {
|
11
|
+
"type" => "object",
|
12
|
+
"required" => ["message"],
|
13
|
+
"properties" => {
|
14
|
+
"message" => {
|
15
|
+
"type" => "string"
|
16
|
+
}
|
17
|
+
}
|
18
|
+
}
|
19
|
+
|
20
|
+
@validator = Twiglet::Validator.new(schema)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'does not raise when validation passes' do
|
24
|
+
assert_equal(@validator.validate({ message: 'this is my message', foo: 'bar' }), true)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'raises when validation fails' do
|
28
|
+
assert_raises JSON::Schema::ValidationError do
|
29
|
+
@validator.validate({ message: true })
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'is a no-op when validator is configured to swallow errors' do
|
34
|
+
@validator.custom_error_handler = ->(e) { puts e }
|
35
|
+
|
36
|
+
assert_nil(@validator.validate({ message: true }))
|
37
|
+
end
|
38
|
+
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
|
4
|
+
version: 3.1.0
|
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-02-
|
11
|
+
date: 2021-02-15 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Like a log, only smaller.
|
14
14
|
email:
|
@@ -42,12 +42,15 @@ files:
|
|
42
42
|
- lib/twiglet/formatter.rb
|
43
43
|
- lib/twiglet/logger.rb
|
44
44
|
- lib/twiglet/message.rb
|
45
|
+
- lib/twiglet/validation_schema.json
|
46
|
+
- lib/twiglet/validator.rb
|
45
47
|
- lib/twiglet/version.rb
|
46
48
|
- test/formatter_test.rb
|
47
49
|
- test/hash_extensions_test.rb
|
48
50
|
- test/logger_test.rb
|
49
51
|
- test/message_test.rb
|
50
52
|
- test/test_coverage.rb
|
53
|
+
- test/validator_test.rb
|
51
54
|
- twiglet.gemspec
|
52
55
|
homepage: https://github.com/simplybusiness/twiglet-ruby
|
53
56
|
licenses:
|