twiglet 2.1.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4f97187804f27d00e7b8231880b43c50769b70a1598dcb3eedb42d2afad4fe0c
4
- data.tar.gz: 18f126aef6c1b43bde8b4e343d2c7595e4fc3f1c07608e02214b3bf7ab2e36e4
3
+ metadata.gz: 356d8c7fec6c41823029cc36bef1cc49bacae6157342b251e9b57f49dcb8151f
4
+ data.tar.gz: bd58a67b48daa9bf6108dc78098f46ad0204f98ca600c29bacd713f6cb54ea2e
5
5
  SHA512:
6
- metadata.gz: 2bf3104cbb1e9f4051f58d6969cf7a761f8aac44a50dfee5677ed52b8ddc0679692357b513b0c995f40fe29f9327f339c8491db326bff261e167e1e8bf6d61b1
7
- data.tar.gz: d1ee7cd4c20da132b3cfa8ca88ef117cc93bbb77773671274792cf67746f6b1947ff8c426099a2417ccbc291ff95853adaf1ded2be007f1deb85ebce265567ef
6
+ metadata.gz: 4bc443482b93b1bba853fbe67605d9b0673830726cf1ef89e941860bc7f832d1efb5f82d5890197ae279b9edf97bf19edf8dc2d8bf61d56d082d6e641f94a245
7
+ data.tar.gz: 8d5e178fca01957147dca807aab4117958b18514d568440e72f53cfc8931aad62035a71633646776368f4409d9be48ab8598c66aad4347edd59f79a0bfc281ae
@@ -0,0 +1,68 @@
1
+ require 'logger'
2
+ require_relative '../hash_extensions'
3
+
4
+ module Twiglet
5
+ class Formatter < ::Logger::Formatter
6
+ Hash.include HashExtensions
7
+
8
+ def initialize(service_name,
9
+ default_properties: {},
10
+ now: -> { Time.now.utc })
11
+ @service_name = service_name
12
+ @now = now
13
+ @default_properties = default_properties
14
+
15
+ super()
16
+ end
17
+
18
+ def call(severity, _time, _progname, msg)
19
+ level = severity.downcase
20
+ log(level: level, message: msg)
21
+ end
22
+
23
+ private
24
+
25
+ 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
+ base_message = {
53
+ "@timestamp": @now.call.iso8601(3),
54
+ service: {
55
+ name: @service_name
56
+ },
57
+ log: {
58
+ level: level
59
+ }
60
+ }
61
+
62
+ base_message
63
+ .deep_merge(@default_properties.to_nested)
64
+ .deep_merge(message.to_nested)
65
+ .to_json
66
+ end
67
+ end
68
+ end
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'logger'
3
4
  require 'time'
4
5
  require 'json'
6
+ require 'twiglet/formatter'
5
7
  require_relative '../hash_extensions'
6
8
 
7
9
  module Twiglet
8
- class Logger
10
+ class Logger < ::Logger
9
11
  Hash.include HashExtensions
10
12
 
11
13
  def initialize(
@@ -19,26 +21,13 @@ module Twiglet
19
21
  @output = output
20
22
 
21
23
  raise 'Service name is mandatory' \
22
- unless @service_name.is_a?(String) && !@service_name.strip.empty?
24
+ unless service_name.is_a?(String) && !service_name.strip.empty?
23
25
 
24
- @default_properties = default_properties
26
+ formatter = Twiglet::Formatter.new(service_name, default_properties: default_properties, now: now)
27
+ super(output, formatter: formatter)
25
28
  end
26
29
 
27
- def debug(message)
28
- log(level: 'debug', message: message)
29
- end
30
-
31
- def info(message)
32
- log(level: 'info', message: message)
33
- end
34
-
35
- def warning(message)
36
- log(level: 'warning', message: message)
37
- end
38
-
39
- alias_method :warn, :warning
40
-
41
- def error(message, error = nil)
30
+ def error(message = {}, error = nil, &block)
42
31
  if error
43
32
  error_fields = {
44
33
  'error': {
@@ -46,18 +35,12 @@ module Twiglet
46
35
  }
47
36
  }
48
37
  add_stack_trace(error_fields, error)
49
- message = message.merge(error_fields)
38
+ message.is_a?(Hash) ? message.merge!(error_fields) : error_fields.merge!(message: message)
50
39
  end
51
40
 
52
- log(level: 'error', message: message)
53
- end
54
-
55
- def critical(message)
56
- log(level: 'critical', message: message)
41
+ super(message, &block)
57
42
  end
58
43
 
59
- alias_method :fatal, :critical
60
-
61
44
  def with(default_properties)
62
45
  Logger.new(@service_name,
63
46
  default_properties: default_properties,
@@ -65,50 +48,10 @@ module Twiglet
65
48
  output: @output)
66
49
  end
67
50
 
68
- private
69
-
70
- def log(level:, message:)
71
- case message
72
- when String
73
- log_text(level, message: message)
74
- when Hash
75
- log_object(level, message: message)
76
- else
77
- raise('Message must be String or Hash')
78
- end
79
- end
80
-
81
- def log_text(level, message:)
82
- raise('The \'message\' property of log object must not be empty') if message.strip.empty?
83
-
84
- message = { message: message }
85
- log_message(level, message: message)
86
- end
87
-
88
- def log_object(level, message:)
89
- message = message.transform_keys(&:to_sym)
90
- message.key?(:message) || raise('Log object must have a \'message\' property')
91
- message[:message].strip.empty? && raise('The \'message\' property of log object must not be empty')
51
+ alias_method :warning, :warn
52
+ alias_method :critical, :fatal
92
53
 
93
- log_message(level, message: message)
94
- end
95
-
96
- def log_message(level, message:)
97
- base_message = {
98
- "@timestamp": @now.call.iso8601(3),
99
- service: {
100
- name: @service_name
101
- },
102
- log: {
103
- level: level
104
- }
105
- }
106
-
107
- @output.puts base_message
108
- .deep_merge(@default_properties.to_nested)
109
- .deep_merge(message.to_nested)
110
- .to_json
111
- end
54
+ private
112
55
 
113
56
  def add_stack_trace(hash_to_add_to, error)
114
57
  hash_to_add_to[:error][:stack_trace] = error.backtrace.join("\n") if error.backtrace
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Twiglet
4
- VERSION = '2.1.1'
4
+ VERSION = '2.2.0'
5
5
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest/autorun'
4
+ require 'json'
5
+ require_relative '../lib/twiglet/formatter'
6
+
7
+ describe Twiglet::Formatter do
8
+ before do
9
+ @now = -> { Time.utc(2020, 5, 11, 15, 1, 1) }
10
+ @formatter = Twiglet::Formatter.new('petshop', now: @now)
11
+ end
12
+
13
+ it 'initializes an instance of a Ruby Logger Formatter' do
14
+ assert @formatter.is_a?(::Logger::Formatter)
15
+ end
16
+
17
+ it 'returns a formatted log from a string message' do
18
+ msg = @formatter.call('warn', nil, nil, 'shop is running low on dog food')
19
+ expected_log = {
20
+ "@timestamp" => '2020-05-11T15:01:01.000Z',
21
+ "service" => {
22
+ "name" => 'petshop'
23
+ },
24
+ "log" => {
25
+ "level" => 'warn'
26
+ },
27
+ "message" => 'shop is running low on dog food'
28
+ }
29
+ assert_equal JSON.parse(msg), expected_log
30
+ end
31
+ end
@@ -15,10 +15,10 @@ describe Twiglet::Logger do
15
15
  LEVELS = [
16
16
  { method: :debug, level: 'debug' },
17
17
  { method: :info, level: 'info' },
18
- { method: :warning, level: 'warning' },
19
- { method: :warn, level: 'warning' },
20
- { method: :critical, level: 'critical' },
21
- { method: :fatal, level: 'critical' },
18
+ { method: :warning, level: 'warn' },
19
+ { method: :warn, level: 'warn' },
20
+ { method: :critical, level: 'fatal' },
21
+ { method: :fatal, level: 'fatal' },
22
22
  { method: :error, level: 'error' }
23
23
  ].freeze
24
24
 
@@ -28,6 +28,13 @@ describe Twiglet::Logger do
28
28
  end
29
29
  end
30
30
 
31
+ it 'conforms to the standard Ruby Logger API' do
32
+ [:debug, :debug?, :info, :info?, :warn, :warn?, :fatal, :fatal?, :error, :error?,
33
+ :level, :level=, :sev_threshold=].each do |call|
34
+ assert @logger.respond_to?(call), "Logger does not respond to #{call}"
35
+ end
36
+ end
37
+
31
38
  describe 'JSON logging' do
32
39
  it 'should throw an error with an empty message' do
33
40
  assert_raises RuntimeError do
@@ -258,6 +265,32 @@ describe Twiglet::Logger do
258
265
  end
259
266
  end
260
267
 
268
+ describe 'logging with a block' do
269
+ LEVELS.each do |attrs|
270
+ it "should correctly log the block when calling #{attrs[:method]}" do
271
+ block = proc { 'a block log message' }
272
+ @logger.public_send(attrs[:method], &block)
273
+ actual_log = read_json(@buffer)
274
+
275
+ assert_equal attrs[:level], actual_log[:log][:level]
276
+ assert_equal 'a block log message', actual_log[:message]
277
+ end
278
+ end
279
+ end
280
+
281
+ describe 'logger level' do
282
+ [
283
+ { expression: :info, level: 1 },
284
+ { expression: 'warn', level: 2 },
285
+ { expression: Logger::DEBUG, level: 0 }
286
+ ].each do |args|
287
+ it "sets the severity threshold to level #{args[:level]}" do
288
+ @logger.level = args[:expression]
289
+ assert_equal args[:level], @logger.level
290
+ end
291
+ end
292
+ end
293
+
261
294
  private
262
295
 
263
296
  def read_json(buffer)
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.1.1
4
+ version: 2.2.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: 2020-06-11 00:00:00.000000000 Z
11
+ date: 2020-06-22 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Like a log, only smaller.
14
14
  email:
@@ -31,8 +31,10 @@ files:
31
31
  - Rakefile
32
32
  - example_app.rb
33
33
  - lib/hash_extensions.rb
34
+ - lib/twiglet/formatter.rb
34
35
  - lib/twiglet/logger.rb
35
36
  - lib/twiglet/version.rb
37
+ - test/formatter_test.rb
36
38
  - test/hash_extensions_test.rb
37
39
  - test/logger_test.rb
38
40
  - twiglet.gemspec
@@ -55,7 +57,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
55
57
  - !ruby/object:Gem::Version
56
58
  version: '0'
57
59
  requirements: []
58
- rubygems_version: 3.1.2
60
+ rubygems_version: 3.0.8
59
61
  signing_key:
60
62
  specification_version: 4
61
63
  summary: Twiglet