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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aadbe159aee695cfd454e0f006ab5eab2b3c06d01ecaa80d3f6b1b69c0d21d5e
4
- data.tar.gz: 53907b03fb29af1fe41d8262619a6d5c84dab554b4e309d7336d969c11600a44
3
+ metadata.gz: 120d52bf23086d2db6f65f068aa087835914bcfe52c3ef1f8b6b886f946e9dcd
4
+ data.tar.gz: 8355c113e09882c4b1346111bba954b82f81d69c0290d1055dca4bb61174fc09
5
5
  SHA512:
6
- metadata.gz: d5e68a4b343c861c7236e4a301365d738221bbe5eb0b23426e3cba84fad2358046d1b868bef5248c1c3398f4c2cfd132445259b7db976937024f73663699c2d4
7
- data.tar.gz: 28b619fd981103d5baea53d07e032e52e21cf88e84b5229d1ca1ff61cedc284d6825ebf26fb977f060d3af4c34f276b8a69c733e66321952a726d452dc82164b
6
+ metadata.gz: 65ca30c0dcf26b8190b7840b70bd5a183b481333bc98af0abfed2835a5a25ec664e2b3c24f10d90f40a6a1d5a18fb90d9f97c2c2aae0ab49b123558049cc11da
7
+ data.tar.gz: 5936e07ac730cd18b39b5777a3fd1a7b8d805852726ad2732d46d6acdb1c7ef820f7dacf87ba68a85352dd3653c0e49b132a90ad71a40dd7ebdc3744ff9e68b8
data/Gemfile CHANGED
@@ -1,6 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  source 'https://rubygems.org'
4
+
5
+ gem 'json-schema'
6
+
4
7
  group :development, :test do
5
8
  gem 'minitest'
6
9
  gem 'rake'
@@ -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
- log(level: level, message: Message.new(msg))
23
+ message = Message.new(msg)
24
+ @validator.validate(message)
25
+ log(level: level, message: message)
22
26
  end
23
27
 
24
28
  private
@@ -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
- formatter = Twiglet::Formatter.new(service_name, default_properties: default_properties, now: now)
30
- super(output, formatter: formatter, level: level)
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)
@@ -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,10 @@
1
+ {
2
+ "type": "object",
3
+ "required": ["message"],
4
+ "properties": {
5
+ "message": {
6
+ "type": "string",
7
+ "minLength": 1
8
+ }
9
+ }
10
+ }
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Twiglet
4
- VERSION = '3.0.8'
4
+ VERSION = '3.1.0'
5
5
  end
@@ -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 RuntimeError do
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 RuntimeError do
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.8
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 00:00:00.000000000 Z
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: