twiglet 3.0.6 → 3.1.3

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: f5cdde3c0d71c1d9749653946057baea5d50178d32c3345aaec2969da0a08b81
4
- data.tar.gz: cbf3b20dadb27002fbfe6f9448d515f086b59c9b6d9321e01090860edf6aad3e
3
+ metadata.gz: 9cace8decdc47857c5ce0bec8ae85b92fe93f866521bc6872371db38999b25c3
4
+ data.tar.gz: dc9bf4d673968a4c718af21c117584f7770a3f2d50cc704ff5d39da1bec26626
5
5
  SHA512:
6
- metadata.gz: 47fbf4941a54d8fc6acf5b52f6b0cc3bbf68a0ecc6cb0f7739c595c47b78dd23d1a1bf3cfb692c79d915248b1bc9de6b9c45f8f43c902f5bc22675a43256af85
7
- data.tar.gz: f65764ec68e251d38ba49eafe44f1b04a62695bc94411f5c1ebb524c3fab498916b65f6905768fbb1c7bdad5dce7124f8e38fa219266cd0a300aadfae84c1162
6
+ metadata.gz: 12c4455ae13471d0ebf0899966c9dbd32bf17841c468beaddb0a912a234033921a1694c2007d6a9d1732bdb69dbabc21f88cf98a195b9eea9a9be52d51cc07db
7
+ data.tar.gz: 91fab7466ae13a05de15fe66c2b8e4b78b28e2ee31220cd0f427d3928bfd59b15dbec2facc444f5c3a10a29bade3ee568e369fb921360fd6ddbb4c76f80bafd0
@@ -1,4 +1,4 @@
1
- name: "version update action"
1
+ name: "dobby action"
2
2
  on:
3
3
  issue_comment:
4
4
  types: [created]
@@ -8,8 +8,9 @@ jobs:
8
8
  if: startsWith(github.event.comment.body, '/dobby')
9
9
 
10
10
  steps:
11
- - name: 'bump version'
12
- uses: simplybusiness/dobby@v1.0.0
11
+ - name: bump version
12
+ uses: simplybusiness/dobby@v2.0.0
13
13
  env:
14
- ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
14
+ DOBBY_APP_ID: ${{ secrets.DOBBY_APP_ID }}
15
+ DOBBY_PRIVATE_KEY: ${{ secrets.DOBBY_PRIVATE_KEY }}
15
16
  VERSION_FILE_PATH: lib/twiglet/version.rb
data/Gemfile CHANGED
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  source 'https://rubygems.org'
4
- group :development, :test do
5
- gem 'minitest'
6
- gem 'rake'
7
- gem 'simplecov', '0.17.1'
8
- gem 'simplycop'
9
- end
4
+
5
+ gemspec
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:
@@ -7,18 +7,21 @@ module Twiglet
7
7
  Hash.include HashExtensions
8
8
 
9
9
  def initialize(service_name,
10
- default_properties: {},
10
+ validator:, default_properties: {},
11
11
  now: -> { Time.now.utc })
12
12
  @service_name = service_name
13
13
  @now = now
14
14
  @default_properties = default_properties
15
+ @validator = validator
15
16
 
16
17
  super()
17
18
  end
18
19
 
19
20
  def call(severity, _time, _progname, msg)
20
21
  level = severity.downcase
21
- log(level: level, message: Message.new(msg))
22
+ message = Message.new(msg)
23
+ @validator.validate(message)
24
+ log(level: level, message: message)
22
25
  end
23
26
 
24
27
  private
@@ -2,10 +2,10 @@
2
2
 
3
3
  require 'logger'
4
4
  require 'time'
5
- require 'json'
6
5
  require_relative 'formatter'
7
6
  require_relative '../hash_extensions'
8
7
  require_relative 'message'
8
+ require_relative 'validator'
9
9
 
10
10
  module Twiglet
11
11
  class Logger < ::Logger
@@ -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("#{__dir__}/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)
@@ -1,6 +1,7 @@
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
@@ -9,18 +10,6 @@ module Twiglet
9
10
  else
10
11
  super(msg)
11
12
  end
12
-
13
- validate!
14
- end
15
-
16
- private
17
-
18
- def validate!
19
- raise 'Message must be initialized with a String or a non-empty Hash' if empty?
20
-
21
- raise 'Log object must have a \'message\' property' unless self[:message]
22
-
23
- raise 'The \'message\' property of the log object must not be empty' if self[:message].strip.empty?
24
13
  end
25
14
  end
26
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.6'
4
+ VERSION = '3.1.3'
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
data/twiglet.gemspec CHANGED
@@ -21,4 +21,10 @@ Gem::Specification.new do |gem|
21
21
  gem.required_ruby_version = '>= 2.6'
22
22
 
23
23
  gem.license = 'Copyright SimplyBusiness'
24
+
25
+ gem.add_runtime_dependency 'json-schema'
26
+ gem.add_development_dependency 'minitest'
27
+ gem.add_development_dependency 'rake'
28
+ gem.add_development_dependency 'simplecov', '0.17.1'
29
+ gem.add_development_dependency 'simplycop'
24
30
  end
metadata CHANGED
@@ -1,15 +1,85 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twiglet
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.6
4
+ version: 3.1.3
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-10 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2021-02-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: json-schema
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 0.17.1
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 0.17.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplycop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
13
83
  description: Like a log, only smaller.
14
84
  email:
15
85
  - tech@simplybusiness.co.uk
@@ -19,10 +89,10 @@ extra_rdoc_files: []
19
89
  files:
20
90
  - ".github/CODEOWNERS"
21
91
  - ".github/dependabot.yml"
92
+ - ".github/workflows/dobby-actions.yml"
22
93
  - ".github/workflows/gem-publish.yml"
23
94
  - ".github/workflows/ruby.yml"
24
95
  - ".github/workflows/version-forget-me-not.yml"
25
- - ".github/workflows/version-update.yml"
26
96
  - ".gitignore"
27
97
  - ".rubocop.yml"
28
98
  - ".ruby-version"
@@ -42,12 +112,15 @@ files:
42
112
  - lib/twiglet/formatter.rb
43
113
  - lib/twiglet/logger.rb
44
114
  - lib/twiglet/message.rb
115
+ - lib/twiglet/validation_schema.json
116
+ - lib/twiglet/validator.rb
45
117
  - lib/twiglet/version.rb
46
118
  - test/formatter_test.rb
47
119
  - test/hash_extensions_test.rb
48
120
  - test/logger_test.rb
49
121
  - test/message_test.rb
50
122
  - test/test_coverage.rb
123
+ - test/validator_test.rb
51
124
  - twiglet.gemspec
52
125
  homepage: https://github.com/simplybusiness/twiglet-ruby
53
126
  licenses: