alephant-logger-json 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +32 -1
- data/lib/alephant/logger/json/version.rb +1 -1
- data/lib/alephant/logger/json.rb +12 -3
- data/lib/alephant/logger/json_to_io.rb +1 -0
- data/lib/alephant/logger/levels_controller.rb +41 -0
- data/spec/alephant/logger/json_spec.rb +80 -94
- data/spec/alephant/logger/json_to_io_spec.rb +77 -90
- data/spec/alephant/logger/levels_controller_spec.rb +145 -0
- data/spec/alephant/logger/support/json_shared_examples.rb +119 -0
- data/spec/alephant/logger/support/levels_controller_shared_examples.rb +11 -0
- metadata +10 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6716c8a5d3446d582752238b022fe71cb1af5574
|
4
|
+
data.tar.gz: eddc2df5fa9deb630a92fecc546d575bbf62ea64
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 36f9a992d64486a1152cc6ef974e4e634d78dee69e5918b7eee6382fcd052280ec86e2db677926bb2851369f2a950a0895c8847c530d16fe685030321eed9bf9
|
7
|
+
data.tar.gz: 573d6232f79aa04207fb8eb7c1525cc5004ec7728a9c8aa2638798addc1596b6af58c5a703e430571ddc5459c0fd803c7956f7a2a033853b07cc65a4f2cdcbca
|
data/README.md
CHANGED
@@ -51,7 +51,7 @@ There are two methods available to help you:
|
|
51
51
|
|
52
52
|
When using tracing, you'll need to provide a binding context as the first argument to your log level method calls.
|
53
53
|
|
54
|
-
This is to resolve issues with lambda's scope availability. See `Kernal#binding` for more details.
|
54
|
+
This is to resolve issues with lambda's scope availability. See `Kernal#binding` for more details.
|
55
55
|
|
56
56
|
Example usage:
|
57
57
|
|
@@ -63,6 +63,37 @@ If no `binding` is provided then tracing is ignored and the logger falls back to
|
|
63
63
|
|
64
64
|
> Note: you can hide the binding necessity behind an abstraction layer if you prefer
|
65
65
|
|
66
|
+
### Logging Levels
|
67
|
+
|
68
|
+
The logger includes an option to define a desired logging level. Only log levels that are equal to or higher than the desired level will be logged.
|
69
|
+
The logger defaults to the _lowest_ level `0` i.e. `:debug` when a desired level is undefined.
|
70
|
+
|
71
|
+
Example
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
# Hierarchical Log levels
|
75
|
+
# 0 => debug
|
76
|
+
# 1 => info
|
77
|
+
# 2 => warn
|
78
|
+
# 3 => error
|
79
|
+
|
80
|
+
# When Default level :debug
|
81
|
+
json_logger = Alephant::Logger::JSON.new("path/to/logfile.log")
|
82
|
+
|
83
|
+
# Log all levels >= 0
|
84
|
+
json_logger.info "This will log"
|
85
|
+
|
86
|
+
# When log level is defined
|
87
|
+
json_logger = Alephant::Logger::JSON.new("path/to/logfile.log", level: :info)
|
88
|
+
|
89
|
+
# log all levels >= 1
|
90
|
+
|
91
|
+
json_logger.debug "This will NOT log"
|
92
|
+
json_logger.info "This will log"
|
93
|
+
```
|
94
|
+
|
95
|
+
> Note: The logger expects the desired level to be defined as a Symbol, String or Integer type.
|
96
|
+
|
66
97
|
## Contributing
|
67
98
|
|
68
99
|
1. Fork it ( https://github.com/BBC-News/alephant-logger-json/fork )
|
data/lib/alephant/logger/json.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
require_relative './dynamic_binding.rb'
|
2
1
|
require 'json'
|
2
|
+
require_relative 'dynamic_binding'
|
3
|
+
require_relative 'levels_controller'
|
3
4
|
|
4
5
|
module Alephant
|
5
6
|
module Logger
|
@@ -8,10 +9,11 @@ module Alephant
|
|
8
9
|
@log_file = File.open(log_path, 'a+')
|
9
10
|
@log_file.sync = true
|
10
11
|
@nesting = options.fetch(:nesting, false)
|
12
|
+
@write_level = options.fetch(:level, :debug)
|
11
13
|
self.class.session = -> { 'n/a' } unless self.class.session?
|
12
14
|
end
|
13
15
|
|
14
|
-
|
16
|
+
LevelsController::LEVELS.each do |level|
|
15
17
|
define_method(level) do |b = nil, hash|
|
16
18
|
return if hash.is_a? String
|
17
19
|
|
@@ -23,7 +25,7 @@ module Alephant
|
|
23
25
|
|
24
26
|
hash = flatten_values_to_s(h) unless @nesting
|
25
27
|
|
26
|
-
write(hash)
|
28
|
+
write(hash) if writeable?(level)
|
27
29
|
end
|
28
30
|
end
|
29
31
|
|
@@ -41,6 +43,13 @@ module Alephant
|
|
41
43
|
@log_file.write(::JSON.generate(hash) + "\n")
|
42
44
|
end
|
43
45
|
|
46
|
+
def writeable?(message_level)
|
47
|
+
LevelsController.should_log?(
|
48
|
+
message_level: message_level,
|
49
|
+
desired_level: @write_level
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
44
53
|
def flatten_values_to_s(hash)
|
45
54
|
Hash[hash.map { |k, v| [k, v.to_s] }]
|
46
55
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Alephant
|
2
|
+
module Logger
|
3
|
+
class LevelsController
|
4
|
+
LEVELS = %i(debug info warn error).freeze
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def should_log?(message_level:, desired_level:)
|
8
|
+
message_level_index = level_index(message_level)
|
9
|
+
|
10
|
+
return false unless message_level_index
|
11
|
+
|
12
|
+
message_level_index >= desired_level_index(desired_level)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def desired_level_index(desired_level)
|
18
|
+
case desired_level
|
19
|
+
when Symbol then level_index_with_default(desired_level)
|
20
|
+
when String then level_index_with_default(desired_level.to_sym)
|
21
|
+
when Integer then desired_level
|
22
|
+
else
|
23
|
+
raise(
|
24
|
+
ArgumentError,
|
25
|
+
'wrong type of argument: expected Integer, Symbol or String. '\
|
26
|
+
"got #{desired_level.class}"
|
27
|
+
)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def level_index_with_default(desired_level)
|
32
|
+
level_index(desired_level) || 0
|
33
|
+
end
|
34
|
+
|
35
|
+
def level_index(level)
|
36
|
+
LEVELS.index(level)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -1,137 +1,123 @@
|
|
1
1
|
require 'date'
|
2
2
|
require 'spec_helper'
|
3
3
|
require 'alephant/logger/json'
|
4
|
+
require 'alephant/logger/levels_controller'
|
5
|
+
require_relative 'support/json_shared_examples'
|
4
6
|
|
5
7
|
describe Alephant::Logger::JSON do
|
6
|
-
subject { described_class.new(log_path) }
|
7
|
-
|
8
8
|
let(:fn) { -> { 'foo' } }
|
9
9
|
let(:log_path) { '/log/path.log' }
|
10
|
-
let(:
|
10
|
+
let(:log_output_obj) { instance_double(File) }
|
11
|
+
let(:msg) { :write }
|
11
12
|
|
12
13
|
before do
|
13
|
-
allow(File).to receive(:open) {
|
14
|
-
allow(
|
14
|
+
allow(File).to receive(:open) { log_output_obj }
|
15
|
+
allow(log_output_obj).to receive :sync=
|
15
16
|
end
|
16
17
|
|
17
|
-
|
18
|
-
let(:log_hash) do
|
19
|
-
{ 'foo' => 'bar', 'baz' => 'quux' }
|
20
|
-
end
|
18
|
+
logging_levels = Alephant::Logger::LevelsController::LEVELS
|
21
19
|
|
22
|
-
|
23
|
-
|
20
|
+
logging_levels.each_with_index do |level, i|
|
21
|
+
describe "##{level}" do
|
22
|
+
let(:level) { level }
|
23
|
+
let(:log_hash) { { 'foo' => 'bar', 'baz' => 'quux' } }
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
context 'when write level is specified' do
|
26
|
+
subject(:logger) do
|
27
|
+
described_class.new(log_path, level: write_level)
|
28
|
+
end
|
29
29
|
|
30
|
-
|
31
|
-
|
30
|
+
context 'when message level is same as write level' do
|
31
|
+
context 'Symbol' do
|
32
|
+
let(:write_level) { level }
|
32
33
|
|
33
|
-
|
34
|
-
expect(log_file).to receive(:write) do |json_dump|
|
35
|
-
t = JSON.parse(json_dump)['timestamp']
|
36
|
-
expect { DateTime.parse(t) }.to_not raise_error
|
37
|
-
end
|
34
|
+
it_behaves_like 'a JSON log writer'
|
38
35
|
|
39
|
-
|
40
|
-
end
|
36
|
+
it_behaves_like 'nested JSON message flattened to strings'
|
41
37
|
|
42
|
-
|
43
|
-
|
44
|
-
h = JSON.parse(json_dump)
|
45
|
-
expect(h.first[0].to_sym).to be :timestamp
|
46
|
-
end
|
38
|
+
it_behaves_like 'gracefully fails with string message'
|
39
|
+
end
|
47
40
|
|
48
|
-
|
49
|
-
|
41
|
+
context 'String' do
|
42
|
+
let(:write_level) { level.to_s }
|
50
43
|
|
51
|
-
|
52
|
-
expect(log_file).to receive(:write) do |json_dump|
|
53
|
-
h = JSON.parse(json_dump)
|
54
|
-
expect(h['uuid']).to eq 'n/a'
|
55
|
-
end
|
44
|
+
it_behaves_like 'a JSON log writer'
|
56
45
|
|
57
|
-
|
58
|
-
end
|
46
|
+
it_behaves_like 'nested JSON message flattened to strings'
|
59
47
|
|
60
|
-
|
61
|
-
|
62
|
-
h = JSON.parse(json_dump)
|
63
|
-
expect(h['uuid']).to eq 'foo'
|
64
|
-
end
|
48
|
+
it_behaves_like 'gracefully fails with string message'
|
49
|
+
end
|
65
50
|
|
66
|
-
|
67
|
-
|
68
|
-
described_class.session = -> { 'n/a' }
|
69
|
-
end
|
51
|
+
context 'Integer' do
|
52
|
+
let(:write_level) { logging_levels.index(level) }
|
70
53
|
|
71
|
-
|
72
|
-
described_class.session = fn
|
73
|
-
expect(described_class.session?).to eq 'instance-variable'
|
54
|
+
it_behaves_like 'a JSON log writer'
|
74
55
|
|
75
|
-
|
76
|
-
expect(described_class.session?).to eq nil
|
77
|
-
end
|
78
|
-
end
|
56
|
+
it_behaves_like 'nested JSON message flattened to strings'
|
79
57
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
end
|
58
|
+
it_behaves_like 'gracefully fails with string message'
|
59
|
+
end
|
60
|
+
end
|
84
61
|
|
85
|
-
|
86
|
-
|
62
|
+
context 'when message level is lower than write level' do
|
63
|
+
context 'Integer' do
|
64
|
+
let(:write_level) { logging_levels.index(level) + 1 }
|
87
65
|
|
88
|
-
|
89
|
-
include_context 'nested log hash'
|
66
|
+
it_behaves_like 'a JSON log non writer'
|
90
67
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
end
|
68
|
+
it_behaves_like 'gracefully fails with string message'
|
69
|
+
end
|
70
|
+
end
|
95
71
|
|
96
|
-
|
97
|
-
|
98
|
-
|
72
|
+
context 'when message level is higher than write level' do
|
73
|
+
let(:write_level_index) do
|
74
|
+
i > 0 ? logging_levels.index(level) - 1 : 0
|
75
|
+
end
|
99
76
|
|
100
|
-
|
101
|
-
|
77
|
+
context 'Symbol' do
|
78
|
+
let(:write_level) { logging_levels[write_level_index] }
|
102
79
|
|
103
|
-
|
104
|
-
expect(log_file).to receive(:write) do |json_dump|
|
105
|
-
expect(JSON.parse(json_dump)).to eq log_hash
|
106
|
-
end
|
80
|
+
it_behaves_like 'a JSON log writer'
|
107
81
|
|
108
|
-
|
109
|
-
end
|
110
|
-
end
|
82
|
+
it_behaves_like 'nested JSON message flattened to strings'
|
111
83
|
|
112
|
-
|
113
|
-
|
84
|
+
it_behaves_like 'gracefully fails with string message'
|
85
|
+
end
|
114
86
|
|
115
|
-
|
116
|
-
|
117
|
-
expect { subject.debug log_message }.not_to raise_error
|
118
|
-
end
|
119
|
-
end
|
87
|
+
context 'String' do
|
88
|
+
let(:write_level) { logging_levels[write_level_index].to_s }
|
120
89
|
|
121
|
-
|
122
|
-
describe "##{level}" do
|
123
|
-
let(:level) { level }
|
90
|
+
it_behaves_like 'a JSON log writer'
|
124
91
|
|
125
|
-
|
92
|
+
it_behaves_like 'nested JSON message flattened to strings'
|
126
93
|
|
127
|
-
|
94
|
+
it_behaves_like 'gracefully fails with string message'
|
95
|
+
end
|
128
96
|
|
129
|
-
|
97
|
+
context 'Integer' do
|
98
|
+
let(:write_level) { write_level_index }
|
130
99
|
|
131
|
-
|
132
|
-
|
133
|
-
|
100
|
+
it_behaves_like 'a JSON log writer'
|
101
|
+
|
102
|
+
it_behaves_like 'nested JSON message flattened to strings'
|
103
|
+
|
104
|
+
it_behaves_like 'gracefully fails with string message'
|
105
|
+
end
|
134
106
|
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'when write level is not specified' do
|
110
|
+
subject(:logger) { described_class.new(log_path) }
|
111
|
+
|
112
|
+
it_behaves_like 'a JSON log writer'
|
113
|
+
|
114
|
+
it_behaves_like 'nested JSON message flattened to strings'
|
115
|
+
|
116
|
+
it_behaves_like 'gracefully fails with string message'
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'with nesting allowed' do
|
120
|
+
subject(:logger) { described_class.new(log_path, nesting: true) }
|
135
121
|
|
136
122
|
it_behaves_like 'nesting allowed'
|
137
123
|
end
|
@@ -1,129 +1,116 @@
|
|
1
1
|
require 'date'
|
2
2
|
require 'spec_helper'
|
3
3
|
require 'alephant/logger/json_to_io'
|
4
|
+
require_relative 'support/json_shared_examples'
|
4
5
|
|
5
6
|
describe Alephant::Logger::JSONtoIO do
|
6
|
-
|
7
|
+
let(:fn) { -> { 'foo' } }
|
8
|
+
let(:log_output_obj) { spy }
|
9
|
+
let(:msg) { :puts }
|
7
10
|
|
8
|
-
|
9
|
-
let(:logger_io) { spy }
|
11
|
+
logging_levels = Alephant::Logger::LevelsController::LEVELS
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
{
|
14
|
-
|
13
|
+
logging_levels.each_with_index do |level, i|
|
14
|
+
describe "##{level}" do
|
15
|
+
let(:level) { level }
|
16
|
+
let(:log_hash) { { 'foo' => 'bar', 'baz' => 'quux' } }
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
+
context 'when write level is specified' do
|
19
|
+
subject(:logger) do
|
20
|
+
described_class.new(log_output_obj, level: write_level)
|
21
|
+
end
|
18
22
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
+
context 'when message level is same as write level' do
|
24
|
+
context 'Symbol' do
|
25
|
+
let(:write_level) { level }
|
23
26
|
|
24
|
-
|
25
|
-
end
|
27
|
+
it_behaves_like 'a JSON log writer'
|
26
28
|
|
27
|
-
|
28
|
-
expect(logger_io).to receive(:puts) do |json_dump|
|
29
|
-
t = JSON.parse(json_dump)['timestamp']
|
30
|
-
expect { DateTime.parse(t) }.to_not raise_error
|
31
|
-
end
|
29
|
+
it_behaves_like 'nested JSON message flattened to strings'
|
32
30
|
|
33
|
-
|
34
|
-
|
31
|
+
it_behaves_like 'gracefully fails with string message'
|
32
|
+
end
|
35
33
|
|
36
|
-
|
37
|
-
|
38
|
-
h = JSON.parse(json_dump)
|
39
|
-
expect(h.first[0].to_sym).to be :timestamp
|
40
|
-
end
|
34
|
+
context 'String' do
|
35
|
+
let(:write_level) { level.to_s }
|
41
36
|
|
42
|
-
|
43
|
-
end
|
37
|
+
it_behaves_like 'a JSON log writer'
|
44
38
|
|
45
|
-
|
46
|
-
expect(logger_io).to receive(:puts) do |json_dump|
|
47
|
-
h = JSON.parse(json_dump)
|
48
|
-
expect(h['uuid']).to eq 'n/a'
|
49
|
-
end
|
39
|
+
it_behaves_like 'nested JSON message flattened to strings'
|
50
40
|
|
51
|
-
|
52
|
-
|
41
|
+
it_behaves_like 'gracefully fails with string message'
|
42
|
+
end
|
53
43
|
|
54
|
-
|
55
|
-
|
56
|
-
h = JSON.parse(json_dump)
|
57
|
-
expect(h['uuid']).to eq 'foo'
|
58
|
-
end
|
44
|
+
context 'Integer' do
|
45
|
+
let(:write_level) { logging_levels.index(level) }
|
59
46
|
|
60
|
-
|
61
|
-
subject.send(level, binding, log_hash)
|
62
|
-
described_class.session = -> { 'n/a' }
|
63
|
-
end
|
47
|
+
it_behaves_like 'a JSON log writer'
|
64
48
|
|
65
|
-
|
66
|
-
described_class.session = fn
|
67
|
-
expect(described_class.session?).to eq 'instance-variable'
|
49
|
+
it_behaves_like 'nested JSON message flattened to strings'
|
68
50
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
end
|
51
|
+
it_behaves_like 'gracefully fails with string message'
|
52
|
+
end
|
53
|
+
end
|
73
54
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
end
|
55
|
+
context 'when message level is lower than write level' do
|
56
|
+
context 'Integer' do
|
57
|
+
let(:write_level) { logging_levels.index(level) + 1 }
|
78
58
|
|
79
|
-
|
80
|
-
end
|
59
|
+
it_behaves_like 'a JSON log non writer'
|
81
60
|
|
82
|
-
|
83
|
-
|
61
|
+
it_behaves_like 'gracefully fails with string message'
|
62
|
+
end
|
63
|
+
end
|
84
64
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
65
|
+
context 'when message level is higher than write level' do
|
66
|
+
let(:write_level_index) do
|
67
|
+
i > 0 ? logging_levels.index(level) - 1 : 0
|
68
|
+
end
|
89
69
|
|
90
|
-
|
91
|
-
|
92
|
-
end
|
70
|
+
context 'Symbol' do
|
71
|
+
let(:write_level) { logging_levels[write_level_index] }
|
93
72
|
|
94
|
-
|
95
|
-
include_context 'nested log hash'
|
73
|
+
it_behaves_like 'a JSON log writer'
|
96
74
|
|
97
|
-
|
98
|
-
expect(logger_io).to receive(:puts) do |json_dump|
|
99
|
-
expect(JSON.parse(json_dump)).to eq log_hash
|
100
|
-
end
|
75
|
+
it_behaves_like 'nested JSON message flattened to strings'
|
101
76
|
|
102
|
-
|
103
|
-
|
104
|
-
end
|
77
|
+
it_behaves_like 'gracefully fails with string message'
|
78
|
+
end
|
105
79
|
|
106
|
-
|
107
|
-
|
80
|
+
context 'String' do
|
81
|
+
let(:write_level) { logging_levels[write_level_index].to_s }
|
108
82
|
|
109
|
-
|
110
|
-
specify do
|
111
|
-
expect { subject.debug log_message }.not_to raise_error
|
112
|
-
end
|
113
|
-
end
|
83
|
+
it_behaves_like 'a JSON log writer'
|
114
84
|
|
115
|
-
|
116
|
-
describe "##{level}" do
|
117
|
-
let(:level) { level }
|
85
|
+
it_behaves_like 'nested JSON message flattened to strings'
|
118
86
|
|
119
|
-
|
87
|
+
it_behaves_like 'gracefully fails with string message'
|
88
|
+
end
|
120
89
|
|
121
|
-
|
90
|
+
context 'Symbol' do
|
91
|
+
let(:write_level) { write_level_index }
|
122
92
|
|
123
|
-
|
93
|
+
it_behaves_like 'a JSON log writer'
|
94
|
+
|
95
|
+
it_behaves_like 'nested JSON message flattened to strings'
|
96
|
+
|
97
|
+
it_behaves_like 'gracefully fails with string message'
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'when write level is not specified' do
|
103
|
+
subject(:logger) { described_class.new(log_output_obj) }
|
104
|
+
|
105
|
+
it_behaves_like 'a JSON log writer'
|
106
|
+
|
107
|
+
it_behaves_like 'nested JSON message flattened to strings'
|
108
|
+
|
109
|
+
it_behaves_like 'gracefully fails with string message'
|
110
|
+
end
|
124
111
|
|
125
112
|
context 'with nesting allowed' do
|
126
|
-
subject { described_class.new(
|
113
|
+
subject(:logger) { described_class.new(log_output_obj, nesting: true) }
|
127
114
|
|
128
115
|
it_behaves_like 'nesting allowed'
|
129
116
|
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'alephant/logger/levels_controller'
|
3
|
+
require_relative 'support/levels_controller_shared_examples'
|
4
|
+
|
5
|
+
RSpec.describe Alephant::Logger::LevelsController do
|
6
|
+
describe '.should_log?' do
|
7
|
+
subject(:loggable?) do
|
8
|
+
described_class.should_log?(
|
9
|
+
message_level: message_level,
|
10
|
+
desired_level: desired_level
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'Message level' do
|
15
|
+
let(:message_level) { :info }
|
16
|
+
|
17
|
+
context 'when message level is higher than desired level' do
|
18
|
+
context 'Symbol' do
|
19
|
+
let(:desired_level) { :debug }
|
20
|
+
|
21
|
+
it_behaves_like 'a loggable level'
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'String' do
|
25
|
+
let(:desired_level) { 'debug' }
|
26
|
+
|
27
|
+
it_behaves_like 'a loggable level'
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'Integer' do
|
31
|
+
let(:desired_level) { 0 }
|
32
|
+
|
33
|
+
it_behaves_like 'a loggable level'
|
34
|
+
|
35
|
+
context 'when out of range' do
|
36
|
+
let(:desired_level) { -200 }
|
37
|
+
|
38
|
+
it_behaves_like 'a loggable level'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when message level is lower than desired level' do
|
44
|
+
context 'Symbol' do
|
45
|
+
let(:desired_level) { :warn }
|
46
|
+
|
47
|
+
it_behaves_like 'a non loggable level'
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'String' do
|
51
|
+
let(:desired_level) { 'warn' }
|
52
|
+
|
53
|
+
it_behaves_like 'a non loggable level'
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'Integer' do
|
57
|
+
let(:desired_level) { 3 }
|
58
|
+
|
59
|
+
it_behaves_like 'a non loggable level'
|
60
|
+
|
61
|
+
context 'when out of range' do
|
62
|
+
let(:desired_level) { 100 }
|
63
|
+
|
64
|
+
it_behaves_like 'a non loggable level'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'when message level is equal to desired level' do
|
70
|
+
context 'Symbol' do
|
71
|
+
let(:desired_level) { message_level }
|
72
|
+
|
73
|
+
it_behaves_like 'a loggable level'
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'String' do
|
77
|
+
let(:desired_level) { message_level.to_s }
|
78
|
+
|
79
|
+
it_behaves_like 'a loggable level'
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'Integer' do
|
83
|
+
let(:desired_level) { 1 }
|
84
|
+
|
85
|
+
it_behaves_like 'a loggable level'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'when message level is invalid' do
|
90
|
+
let(:desired_level) { :debug }
|
91
|
+
|
92
|
+
context 'when message level is not in LEVELS' do
|
93
|
+
let(:message_level) { :foobar }
|
94
|
+
|
95
|
+
it_behaves_like 'a non loggable level'
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'when message level is nil' do
|
99
|
+
let(:message_level) { nil }
|
100
|
+
|
101
|
+
it_behaves_like 'a non loggable level'
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe 'Desired level' do
|
107
|
+
context 'when desired level is not in LEVELS' do
|
108
|
+
let(:message_level) { :error }
|
109
|
+
let(:desired_level) { :foobar }
|
110
|
+
|
111
|
+
it 'defaults to debug' do
|
112
|
+
expect(loggable?).to be(true)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'when desired level is an unsupported type' do
|
117
|
+
context 'Hash' do
|
118
|
+
let(:message_level) { :error }
|
119
|
+
let(:desired_level) { {} }
|
120
|
+
|
121
|
+
it 'raises an argument error' do
|
122
|
+
expect { loggable? }.to raise_error(
|
123
|
+
ArgumentError,
|
124
|
+
'wrong type of argument: expected Integer, '\
|
125
|
+
'Symbol or String. got Hash'
|
126
|
+
)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context 'Nil' do
|
131
|
+
let(:message_level) { :error }
|
132
|
+
let(:desired_level) { nil }
|
133
|
+
|
134
|
+
it 'raises an argument error' do
|
135
|
+
expect { loggable? }.to raise_error(
|
136
|
+
ArgumentError,
|
137
|
+
'wrong type of argument: expected Integer, '\
|
138
|
+
'Symbol or String. got NilClass'
|
139
|
+
)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
shared_examples 'a JSON log writer' do
|
2
|
+
let(:log_hash) do
|
3
|
+
{ 'foo' => 'bar', 'baz' => 'quux' }
|
4
|
+
end
|
5
|
+
|
6
|
+
it 'writes JSON dump of hash to log with corresponding level key' do
|
7
|
+
allow(Time).to receive(:now).and_return('foobar')
|
8
|
+
|
9
|
+
expect(log_output_obj).to receive(msg) do |json_dump|
|
10
|
+
h = { 'timestamp' => 'foobar', 'uuid' => 'n/a', 'level' => level.to_s }
|
11
|
+
expect(JSON.parse(json_dump)).to eq(h.merge(log_hash))
|
12
|
+
end
|
13
|
+
|
14
|
+
logger.send(level, log_hash)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'automatically includes a timestamp' do
|
18
|
+
expect(log_output_obj).to receive(msg) do |json_dump|
|
19
|
+
t = JSON.parse(json_dump)['timestamp']
|
20
|
+
expect { DateTime.parse(t) }.not_to raise_error
|
21
|
+
end
|
22
|
+
|
23
|
+
logger.send(level, log_hash)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'outputs the timestamp first' do
|
27
|
+
expect(log_output_obj).to receive(msg) do |json_dump|
|
28
|
+
h = JSON.parse(json_dump)
|
29
|
+
expect(h.first[0].to_sym).to be(:timestamp)
|
30
|
+
end
|
31
|
+
|
32
|
+
logger.send(level, log_hash)
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'when a session is set' do
|
36
|
+
it 'provides a static reader method' do
|
37
|
+
described_class.session = fn
|
38
|
+
expect(described_class.session?).to eq('instance-variable')
|
39
|
+
|
40
|
+
described_class.send(:remove_instance_variable, :@session)
|
41
|
+
expect(described_class.session?).to be(nil)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when a user defined function is provided' do
|
46
|
+
it 'displays a custom session value' do
|
47
|
+
expect(log_output_obj).to receive(msg) do |json_dump|
|
48
|
+
h = JSON.parse(json_dump)
|
49
|
+
expect(h['uuid']).to eq('foo')
|
50
|
+
end
|
51
|
+
|
52
|
+
described_class.session = fn
|
53
|
+
logger.send(level, binding, log_hash)
|
54
|
+
described_class.session = -> { 'n/a' }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'when a user defined function is not provided' do
|
59
|
+
it 'displays a default session value' do
|
60
|
+
expect(log_output_obj).to receive(msg) do |json_dump|
|
61
|
+
h = JSON.parse(json_dump)
|
62
|
+
expect(h['uuid']).to eq('n/a')
|
63
|
+
end
|
64
|
+
|
65
|
+
logger.send(level, log_hash)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
shared_examples 'a JSON log non writer' do
|
71
|
+
before do
|
72
|
+
allow(Time).to receive(:now).and_return('foobar')
|
73
|
+
logger.send(level, log_hash)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'does not write' do
|
77
|
+
expect(log_output_obj).not_to receive(msg)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
shared_context 'nested log hash' do
|
82
|
+
let(:log_hash) { { 'nest' => nest } }
|
83
|
+
|
84
|
+
let(:nest) { { 'bird' => 'eggs' } }
|
85
|
+
end
|
86
|
+
|
87
|
+
shared_examples 'nested JSON message flattened to strings' do
|
88
|
+
include_context 'nested log hash'
|
89
|
+
|
90
|
+
specify do
|
91
|
+
expect(log_output_obj).to receive(msg) do |json_dump|
|
92
|
+
expect(JSON.parse(json_dump)['nest']).to eq(nest.to_s)
|
93
|
+
end
|
94
|
+
|
95
|
+
logger.send(level, log_hash)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
shared_examples 'nesting allowed' do
|
100
|
+
include_context 'nested log hash'
|
101
|
+
|
102
|
+
specify do
|
103
|
+
expect(log_output_obj).to receive(msg) do |json_dump|
|
104
|
+
expect(JSON.parse(json_dump)).to eq(log_hash)
|
105
|
+
end
|
106
|
+
|
107
|
+
logger.send(level, log_hash)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
shared_examples 'gracefully fails with string message' do
|
112
|
+
let(:log_message) { 'Unable to connect to server' }
|
113
|
+
|
114
|
+
specify { expect(log_output_obj).not_to receive(msg) }
|
115
|
+
|
116
|
+
specify do
|
117
|
+
expect { logger.debug(log_message) }.not_to raise_error
|
118
|
+
end
|
119
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alephant-logger-json
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Arnould
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-09-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -112,8 +112,12 @@ files:
|
|
112
112
|
- lib/alephant/logger/json.rb
|
113
113
|
- lib/alephant/logger/json/version.rb
|
114
114
|
- lib/alephant/logger/json_to_io.rb
|
115
|
+
- lib/alephant/logger/levels_controller.rb
|
115
116
|
- spec/alephant/logger/json_spec.rb
|
116
117
|
- spec/alephant/logger/json_to_io_spec.rb
|
118
|
+
- spec/alephant/logger/levels_controller_spec.rb
|
119
|
+
- spec/alephant/logger/support/json_shared_examples.rb
|
120
|
+
- spec/alephant/logger/support/levels_controller_shared_examples.rb
|
117
121
|
- spec/spec_helper.rb
|
118
122
|
homepage: ''
|
119
123
|
licenses:
|
@@ -135,11 +139,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
135
139
|
version: '0'
|
136
140
|
requirements: []
|
137
141
|
rubyforge_project:
|
138
|
-
rubygems_version: 2.
|
142
|
+
rubygems_version: 2.6.8
|
139
143
|
signing_key:
|
140
144
|
specification_version: 4
|
141
145
|
summary: alephant-logger driver enabling structured logging in JSON
|
142
146
|
test_files:
|
143
147
|
- spec/alephant/logger/json_spec.rb
|
144
148
|
- spec/alephant/logger/json_to_io_spec.rb
|
149
|
+
- spec/alephant/logger/levels_controller_spec.rb
|
150
|
+
- spec/alephant/logger/support/json_shared_examples.rb
|
151
|
+
- spec/alephant/logger/support/levels_controller_shared_examples.rb
|
145
152
|
- spec/spec_helper.rb
|