twiglet 3.1.1 → 3.2.2

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: 56e2f49eb96f5f3f59c142dfb88df92ae14acc36f70ec3c9ab76e5ef2fc95797
4
- data.tar.gz: 2f75b68c03359a2c1f2fd6f2a01012ea317f1d1b5485d66225650ef2c295e417
3
+ metadata.gz: a18b325925f73f84865c9e55e4c06a61668434cc3cfa5f1abc55d661c3469084
4
+ data.tar.gz: 7fe0d1320ad5799335b9a44f32df02ddfeb64e9f882ecd2eb181710e80305d7e
5
5
  SHA512:
6
- metadata.gz: 8b5a5b66dfbe4af4f176375e9610725e1febe6517e1160d74a59337add91a80bc9d1e9bac21e7d37980898f8823a333a86c8a1787981a590c1f8130891822d8d
7
- data.tar.gz: 57db8b9451aae45abb024b18d33ca177d963abd19785b1bf4dca7e0bd7afa3999b2ed508e738cfce0f1905cb7173a14e4db6178dcfdcb1696548fc41ef90ea84
6
+ metadata.gz: cd922518bc1cd17c319c6e843289d340a24b7bd0ef647d6b2c55d23e777f1cf9ce4b54a2476b25254668bd8fec2608c24688d9e16b25a1aa0c2949f4163aedef
7
+ data.tar.gz: 472f81b779ef35fb597b4b8d4db98ab874f762b1c5fb30c9aa2b6bb8851e5f02cdfd8438470560af550653947496490f01abde3031eb1ad5fd74a68f2aac464b
@@ -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
@@ -2,11 +2,4 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
- gem 'json-schema'
6
-
7
- group :development, :test do
8
- gem 'minitest'
9
- gem 'rake'
10
- gem 'simplecov', '0.17.1'
11
- gem 'simplycop'
12
- end
5
+ gemspec
data/README.md CHANGED
@@ -144,7 +144,72 @@ logger.formatter
144
144
  Take a look at this sample [Rack application](examples/rack/example_rack_app.rb#L15) with an ECS compliant
145
145
  [request logger](/examples/rack/request_logger.rb) as a template when configuring your own request logging middleware with Twiglet.
146
146
 
147
- ## Use of dotted keys (DEPRECATED)
147
+ ### Log format validation
148
+ Twiglet allows for the configuration of a custom validation schema. The validation schema must be [JSON Schema](https://json-schema.org/) compliant. Any fields not explicitly included in the provided schema are permitted by default.
149
+
150
+ For example, given the following JSON Schema:
151
+ ```ruby
152
+ validation_schema = <<-JSON
153
+ {
154
+ "type": "object",
155
+ "required": ["pet"],
156
+ "properties": {
157
+ "pet": {
158
+ "type": "object",
159
+ "required": ["name", "best_boy_or_girl?"],
160
+ "properties": {
161
+ "name": {
162
+ "type": "string",
163
+ "minLength": 1
164
+ },
165
+ "good_boy?": {
166
+ "type": "boolean"
167
+ }
168
+ }
169
+ }
170
+ }
171
+ }
172
+ JSON
173
+ ```
174
+
175
+ The logger can be instantiated with the custom schema
176
+ ```ruby
177
+ custom_logger = Twiglet::Logger.new('service name', validation_schema: validation_schema)
178
+ ```
179
+
180
+ Compliant log messages will log as normal.
181
+ ```ruby
182
+ # this is compliant
183
+ custom_logger.debug(pet: { name: 'Davis', good_boy?: true })
184
+
185
+ # the result
186
+ {:ecs=>{:version=>"1.5.0"}, :@timestamp=>"2020-05-11T15:01:01.000Z", :service=>{:name=>"petshop"}, :log=>{:level=>"debug"}, :pet=>{:name=>"Davis", :good_boy?=>true}}
187
+ ```
188
+
189
+ Non compliant messages will raise an error.
190
+ ```ruby
191
+ begin
192
+ custom_logger.debug(pet: { name: 'Davis' })
193
+ rescue JSON::Schema::ValidationError
194
+ # we forgot to specify that he's a good boy!
195
+ puts 'uh-oh'
196
+ end
197
+ ```
198
+
199
+ #### Customizing error responses
200
+ Depending on the application, it may not be desirable for the logger to raise Runtime errors. Twiglet allows you to configure a custom response for handling validation errors.
201
+
202
+ Configure error handling by writing a block
203
+ ```ruby
204
+ logger.configure_validation_error_response do |error|
205
+ # validation error handling goes here
206
+ # for example:
207
+ {YOUR APPLICATION BUG TRACKING SERVICE}.notify_error(error)
208
+ end
209
+
210
+ ```
211
+
212
+ ### Use of dotted keys (DEPRECATED)
148
213
 
149
214
  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:
150
215
 
@@ -65,7 +65,7 @@ describe RequestLogger do
65
65
  end
66
66
 
67
67
  it 'logs an error message when a request is bad' do
68
- -> { bad_request.get("/some/path") }.must_raise StandardError
68
+ expect { bad_request.get("/some/path") }.must_raise StandardError
69
69
  log = JSON.parse(output.string)
70
70
  assert_equal log['log']['level'], 'error'
71
71
  assert_equal log['error']['message'], 'some exception'
@@ -1,7 +1,6 @@
1
1
  require 'logger'
2
2
  require_relative '../hash_extensions'
3
3
  require_relative 'message'
4
- require_relative 'validator'
5
4
 
6
5
  module Twiglet
7
6
  class Formatter < ::Logger::Formatter
@@ -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
@@ -13,28 +13,29 @@ module Twiglet
13
13
 
14
14
  def initialize(
15
15
  service_name,
16
- default_properties: {},
17
- now: -> { Time.now.utc },
18
- output: $stdout,
19
- level: Logger::DEBUG
16
+ **args
20
17
  )
21
18
  @service_name = service_name
22
- @now = now
23
- @output = output
24
- @level = level
19
+ default_properties = args.delete(:default_properties) || {}
20
+ @args = args
21
+
22
+ now = args.fetch(:now, -> { Time.now.utc })
23
+ output = args.fetch(:output, $stdout)
24
+ level = args.fetch(:level, DEBUG)
25
+ validation_schema = args.fetch(:validation_schema, File.read("#{__dir__}/validation_schema.json"))
25
26
 
26
27
  raise 'Service name is mandatory' \
27
28
  unless service_name.is_a?(String) && !service_name.strip.empty?
28
29
 
29
- @validator = Validator.from_file("#{__dir__}/validation_schema.json")
30
+ @validator = Validator.new(validation_schema)
30
31
 
31
- @formatter = Twiglet::Formatter.new(
32
+ formatter = Twiglet::Formatter.new(
32
33
  service_name,
33
34
  default_properties: default_properties,
34
35
  now: now,
35
36
  validator: @validator
36
37
  )
37
- super(output, formatter: @formatter, level: level)
38
+ super(output, formatter: formatter, level: level)
38
39
  end
39
40
 
40
41
  def configure_validation_error_response(&block)
@@ -59,10 +60,7 @@ module Twiglet
59
60
  def with(default_properties)
60
61
  Logger.new(
61
62
  @service_name,
62
- default_properties: default_properties,
63
- now: @now,
64
- output: @output,
65
- level: @level
63
+ **@args.merge(default_properties: default_properties)
66
64
  )
67
65
  end
68
66
 
@@ -8,14 +8,10 @@ module Twiglet
8
8
  attr_accessor :custom_error_handler
9
9
 
10
10
  def initialize(schema)
11
- @schema = schema
11
+ @schema = JSON.parse(schema)
12
12
  @custom_error_handler = ->(e) { raise e }
13
13
  end
14
14
 
15
- def self.from_file(file_path)
16
- new(JSON.parse(File.read(file_path)))
17
- end
18
-
19
15
  def validate(message)
20
16
  JSON::Validator.validate!(@schema, message)
21
17
  rescue JSON::Schema::ValidationError => e
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Twiglet
4
- VERSION = '3.1.1'
4
+ VERSION = '3.2.2'
5
5
  end
@@ -8,7 +8,7 @@ require_relative '../lib/twiglet/validator'
8
8
  describe Twiglet::Formatter do
9
9
  before do
10
10
  @now = -> { Time.utc(2020, 5, 11, 15, 1, 1) }
11
- @formatter = Twiglet::Formatter.new('petshop', now: @now, validator: Twiglet::Validator.new({}))
11
+ @formatter = Twiglet::Formatter.new('petshop', now: @now, validator: Twiglet::Validator.new({}.to_json))
12
12
  end
13
13
 
14
14
  it 'initializes an instance of a Ruby Logger Formatter' do
data/test/logger_test.rb CHANGED
@@ -357,6 +357,17 @@ describe Twiglet::Logger do
357
357
  it 'initializes the logger with the provided level' do
358
358
  assert_equal Logger::WARN, Twiglet::Logger.new('petshop', level: :warn).level
359
359
  end
360
+
361
+ it 'does not log lower level' do
362
+ logger = Twiglet::Logger.new(
363
+ 'petshop',
364
+ now: @now,
365
+ output: @buffer,
366
+ level: Logger::INFO
367
+ )
368
+ logger.debug({ name: 'Davis', best_boy_or_girl?: true, species: 'dog' })
369
+ assert_empty @buffer.read
370
+ end
360
371
  end
361
372
 
362
373
  describe 'configuring error response' do
@@ -380,6 +391,61 @@ describe Twiglet::Logger do
380
391
  end
381
392
  end
382
393
 
394
+ describe 'validation schema' do
395
+ before do
396
+ validation_schema = <<-JSON
397
+ {
398
+ "type": "object",
399
+ "required": ["pet"],
400
+ "properties": {
401
+ "pet": {
402
+ "type": "object",
403
+ "required": ["name", "best_boy_or_girl?"],
404
+ "properties": {
405
+ "name": {
406
+ "type": "string",
407
+ "minLength": 1
408
+ },
409
+ "best_boy_or_girl?": {
410
+ "type": "boolean"
411
+ }
412
+ }
413
+ }
414
+ }
415
+ }
416
+ JSON
417
+
418
+ @logger = Twiglet::Logger.new(
419
+ 'petshop',
420
+ now: @now,
421
+ output: @buffer,
422
+ validation_schema: validation_schema
423
+ )
424
+ end
425
+
426
+ it 'allows for the configuration of custom validation rules' do
427
+ @logger.debug(
428
+ {
429
+ pet: { name: 'Davis', best_boy_or_girl?: true, species: 'dog' }
430
+ }
431
+ )
432
+ log = read_json(@buffer)
433
+
434
+ assert_equal true, log[:pet][:best_boy_or_girl?]
435
+ end
436
+
437
+ it 'raises when custom validation rules are broken' do
438
+ nonconformant = {
439
+ pet: { name: 'Davis' }
440
+ }
441
+
442
+ assert_raises JSON::Schema::ValidationError,
443
+ "The property '#/pet' did not contain a required property of 'best_boy_or_girl?'" do
444
+ @logger.debug(nonconformant)
445
+ end
446
+ end
447
+ end
448
+
383
449
  private
384
450
 
385
451
  def read_json(buffer)
@@ -17,7 +17,7 @@ describe Twiglet::Validator do
17
17
  }
18
18
  }
19
19
 
20
- @validator = Twiglet::Validator.new(schema)
20
+ @validator = Twiglet::Validator.new(schema.to_json)
21
21
  end
22
22
 
23
23
  it 'does not raise when validation passes' do
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.1.1
4
+ version: 3.2.2
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-15 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2021-03-09 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"