logasm-jruby 1.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 +7 -0
- data/.gitignore +4 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +8 -0
- data/README.md +121 -0
- data/Rakefile +7 -0
- data/benchmark/whitelisting.rb +53 -0
- data/lib/logasm.rb +74 -0
- data/lib/logasm/adapters.rb +22 -0
- data/lib/logasm/adapters/stdout_adapter.rb +29 -0
- data/lib/logasm/adapters/stdout_json_adapter.rb +44 -0
- data/lib/logasm/null_logger.rb +18 -0
- data/lib/logasm/preprocessors.rb +18 -0
- data/lib/logasm/preprocessors/blacklist.rb +61 -0
- data/lib/logasm/preprocessors/json_pointer_trie.rb +40 -0
- data/lib/logasm/preprocessors/strategies/mask.rb +43 -0
- data/lib/logasm/preprocessors/strategies/prune.rb +44 -0
- data/lib/logasm/preprocessors/whitelist.rb +56 -0
- data/lib/logasm/utils.rb +91 -0
- data/logasm.gemspec +36 -0
- data/spec/adapters/stdout_adapter_spec.rb +48 -0
- data/spec/adapters/stdout_json_adapter_spec.rb +43 -0
- data/spec/logasm_spec.rb +142 -0
- data/spec/preprocessors/blacklist_spec.rb +131 -0
- data/spec/preprocessors/json_pointer_trie.rb +36 -0
- data/spec/preprocessors/whitelist_spec.rb +335 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/support/implement_interface.rb +11 -0
- data/spec/utils_spec.rb +84 -0
- metadata +168 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'lru_redux'
|
2
|
+
|
3
|
+
class Logasm
|
4
|
+
module Preprocessors
|
5
|
+
class JSONPointerTrie
|
6
|
+
SEPARATOR = '/'.freeze
|
7
|
+
WILDCARD = '~'.freeze
|
8
|
+
DEFAULT_CACHE_SIZE = 100
|
9
|
+
|
10
|
+
def initialize(cache_size: DEFAULT_CACHE_SIZE, **)
|
11
|
+
@root_node = {}
|
12
|
+
@cache = LruRedux::Cache.new(cache_size)
|
13
|
+
end
|
14
|
+
|
15
|
+
def insert(pointer)
|
16
|
+
split_path(pointer).reduce(@root_node) do |tree, key|
|
17
|
+
tree[key] ||= {}
|
18
|
+
end
|
19
|
+
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def include?(path)
|
24
|
+
@cache.getset(path) { traverse_path(path) }
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def traverse_path(path)
|
30
|
+
split_path(path).reduce(@root_node) do |node, key|
|
31
|
+
node[key] || node[WILDCARD] || (break false)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def split_path(path)
|
36
|
+
path.split(SEPARATOR).reject(&:empty?)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
class Logasm
|
2
|
+
module Preprocessors
|
3
|
+
module Strategies
|
4
|
+
class Mask
|
5
|
+
MASK_SYMBOL = '*'.freeze
|
6
|
+
MASKED_VALUE = MASK_SYMBOL * 5
|
7
|
+
|
8
|
+
def initialize(trie)
|
9
|
+
@trie = trie
|
10
|
+
end
|
11
|
+
|
12
|
+
def process(data, pointer = '')
|
13
|
+
return MASKED_VALUE unless @trie.include?(pointer)
|
14
|
+
|
15
|
+
case data
|
16
|
+
when Hash
|
17
|
+
process_hash(data, pointer)
|
18
|
+
|
19
|
+
when Array
|
20
|
+
process_array(data, pointer)
|
21
|
+
|
22
|
+
else
|
23
|
+
data
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def process_hash(data, parent_pointer)
|
30
|
+
data.each_with_object({}) do |(key, value), result|
|
31
|
+
result[key] = process(value, "#{parent_pointer}/#{key}")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def process_array(data, parent_pointer)
|
36
|
+
data.each_with_index.map do |value, index|
|
37
|
+
process(value, "#{parent_pointer}/#{index}")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class Logasm
|
2
|
+
module Preprocessors
|
3
|
+
module Strategies
|
4
|
+
class Prune
|
5
|
+
def initialize(trie)
|
6
|
+
@trie = trie
|
7
|
+
end
|
8
|
+
|
9
|
+
def process(data, pointer = '')
|
10
|
+
return nil unless @trie.include?(pointer)
|
11
|
+
|
12
|
+
case data
|
13
|
+
when Hash
|
14
|
+
process_hash(data, pointer)
|
15
|
+
|
16
|
+
when Array
|
17
|
+
process_array(data, pointer)
|
18
|
+
|
19
|
+
else
|
20
|
+
data
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def process_hash(data, parent_pointer)
|
27
|
+
data.each_with_object({}) do |(key, value), result|
|
28
|
+
path = "#{parent_pointer}/#{key}"
|
29
|
+
|
30
|
+
result[key] = process(value, path) if @trie.include?(path)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def process_array(data, parent_pointer)
|
35
|
+
data.each_with_index.each_with_object([]) do |(value, index), result|
|
36
|
+
path = "#{parent_pointer}/#{index}"
|
37
|
+
|
38
|
+
result << process(value, path) if @trie.include?(path)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'logasm/preprocessors/json_pointer_trie'
|
2
|
+
require 'logasm/preprocessors/strategies/mask'
|
3
|
+
require 'logasm/preprocessors/strategies/prune'
|
4
|
+
|
5
|
+
class Logasm
|
6
|
+
module Preprocessors
|
7
|
+
class Whitelist
|
8
|
+
DEFAULT_WHITELIST = %w[/id /message /correlation_id /queue].freeze
|
9
|
+
MASK_SYMBOL = '*'.freeze
|
10
|
+
MASKED_VALUE = MASK_SYMBOL * 5
|
11
|
+
|
12
|
+
PRUNE_ACTION_NAMES = %w[prune exclude].freeze
|
13
|
+
|
14
|
+
class InvalidPointerFormatException < Exception
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(config = {})
|
18
|
+
trie = build_trie(config)
|
19
|
+
|
20
|
+
@strategy = if PRUNE_ACTION_NAMES.include?(config[:action].to_s)
|
21
|
+
Strategies::Prune.new(trie)
|
22
|
+
else
|
23
|
+
Strategies::Mask.new(trie)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def process(data)
|
28
|
+
@strategy.process(data)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def validate_pointer(pointer)
|
34
|
+
if pointer.slice(-1) == '/'
|
35
|
+
raise InvalidPointerFormatException, 'Pointer should not contain trailing slash'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def decode(pointer)
|
40
|
+
pointer
|
41
|
+
.gsub('~1', '/')
|
42
|
+
.gsub('~0', '~')
|
43
|
+
end
|
44
|
+
|
45
|
+
def build_trie(config)
|
46
|
+
pointers = (config[:pointers] || []) + DEFAULT_WHITELIST
|
47
|
+
|
48
|
+
pointers.reduce(JSONPointerTrie.new(config)) do |trie, pointer|
|
49
|
+
validate_pointer(pointer)
|
50
|
+
|
51
|
+
trie.insert(decode(pointer))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/logasm/utils.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'time'
|
2
|
+
|
3
|
+
class Logasm
|
4
|
+
module Utils
|
5
|
+
DECIMAL_FRACTION_OF_SECOND = 3
|
6
|
+
|
7
|
+
# Build logstash json compatible event
|
8
|
+
#
|
9
|
+
# @param [Hash] metadata
|
10
|
+
# @param [#to_s] level
|
11
|
+
# @param [String] service_name
|
12
|
+
#
|
13
|
+
# @return [Hash]
|
14
|
+
def self.build_event(metadata, level, application_name)
|
15
|
+
overwritable_params
|
16
|
+
.merge(metadata)
|
17
|
+
.merge(
|
18
|
+
application: application_name,
|
19
|
+
level: level
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Return application name
|
24
|
+
#
|
25
|
+
# Returns lower snake case application name. This allows the
|
26
|
+
# application value to be used in the elasticsearch index name.
|
27
|
+
#
|
28
|
+
# @param [String] service_name
|
29
|
+
#
|
30
|
+
# @return [String]
|
31
|
+
def self.application_name(service_name)
|
32
|
+
underscore(service_name)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.overwritable_params
|
36
|
+
{
|
37
|
+
:@timestamp => Time.now.utc.iso8601(DECIMAL_FRACTION_OF_SECOND)
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.serialize_time_objects!(object)
|
42
|
+
if object.is_a?(Hash)
|
43
|
+
object.each do |key, value|
|
44
|
+
object[key] = serialize_time_objects!(value)
|
45
|
+
end
|
46
|
+
elsif object.is_a?(Array)
|
47
|
+
object.each_index do |index|
|
48
|
+
object[index] = serialize_time_objects!(object[index])
|
49
|
+
end
|
50
|
+
elsif object.is_a?(Time) || object.is_a?(Date)
|
51
|
+
object.iso8601
|
52
|
+
else
|
53
|
+
object
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
if RUBY_PLATFORM =~ /java/
|
58
|
+
require 'jrjackson'
|
59
|
+
|
60
|
+
DUMP_OPTIONS = {
|
61
|
+
timezone: 'utc',
|
62
|
+
date_format: "YYYY-MM-dd'T'HH:mm:ss.SSSX"
|
63
|
+
}.freeze
|
64
|
+
|
65
|
+
def self.generate_json(obj)
|
66
|
+
JrJackson::Json.dump(obj, DUMP_OPTIONS)
|
67
|
+
end
|
68
|
+
else
|
69
|
+
require 'oj'
|
70
|
+
DUMP_OPTIONS = { mode: :compat, time_format: :ruby }.freeze
|
71
|
+
|
72
|
+
def self.generate_json(obj)
|
73
|
+
serialize_time_objects!(obj)
|
74
|
+
|
75
|
+
Oj.dump(obj, DUMP_OPTIONS)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.underscore(input)
|
80
|
+
word = input.to_s.dup
|
81
|
+
word.gsub!(/::/, '/')
|
82
|
+
word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
83
|
+
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
84
|
+
word.tr!("-", "_")
|
85
|
+
word.downcase!
|
86
|
+
word
|
87
|
+
end
|
88
|
+
|
89
|
+
private_class_method :overwritable_params
|
90
|
+
end
|
91
|
+
end
|
data/logasm.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
if RUBY_PLATFORM =~ /java/
|
7
|
+
gem.name = 'logasm-jruby'
|
8
|
+
else
|
9
|
+
gem.name = 'logasm'
|
10
|
+
end
|
11
|
+
|
12
|
+
gem.version = '1.2.0'
|
13
|
+
gem.authors = ["Salemove"]
|
14
|
+
gem.email = ["support@salemove.com"]
|
15
|
+
gem.description = %q{It's logasmic}
|
16
|
+
gem.summary = %q{What description said}
|
17
|
+
gem.license = "MIT"
|
18
|
+
|
19
|
+
gem.files = `git ls-files`.split($/)
|
20
|
+
gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
21
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
22
|
+
gem.require_paths = ["lib"]
|
23
|
+
|
24
|
+
gem.add_dependency 'lru_redux'
|
25
|
+
|
26
|
+
if RUBY_PLATFORM =~ /java/
|
27
|
+
gem.add_dependency 'jrjackson'
|
28
|
+
else
|
29
|
+
gem.add_dependency 'oj'
|
30
|
+
end
|
31
|
+
|
32
|
+
gem.add_development_dependency "bundler", "~> 1.3"
|
33
|
+
gem.add_development_dependency "rake"
|
34
|
+
gem.add_development_dependency "bunny"
|
35
|
+
gem.add_development_dependency "benchmark-ips"
|
36
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative '../../lib/logasm/adapters/stdout_adapter'
|
3
|
+
|
4
|
+
describe Logasm::Adapters::StdoutAdapter do
|
5
|
+
it 'creates a stdout logger' do
|
6
|
+
io_logger = described_class.new(0)
|
7
|
+
|
8
|
+
logger = io_logger.instance_variable_get(:@logger)
|
9
|
+
expect(logger).to be_a Logger
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#log' do
|
13
|
+
let(:adapter) { described_class.new(0) }
|
14
|
+
let(:logger) { adapter.logger }
|
15
|
+
|
16
|
+
context 'with only a message' do
|
17
|
+
it 'stringifies it correctly' do
|
18
|
+
expect(logger).to receive(:info).with('test')
|
19
|
+
|
20
|
+
adapter.log :info, message: 'test'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'with an empty message' do
|
25
|
+
it 'stringifies it correctly' do
|
26
|
+
expect(logger).to receive(:info).with(' {"a":"b"}')
|
27
|
+
|
28
|
+
adapter.log :info, message: '', a: 'b'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'with no message' do
|
33
|
+
it 'stringifies it correctly' do
|
34
|
+
expect(logger).to receive(:info).with('{"a":"b"}')
|
35
|
+
|
36
|
+
adapter.log :info, a: 'b'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'with a message and metadata' do
|
41
|
+
it 'stringifies it correctly' do
|
42
|
+
expect(logger).to receive(:info).with('test {"a":"b"}')
|
43
|
+
|
44
|
+
adapter.log :info, message: 'test', a: 'b'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'json'
|
3
|
+
require_relative '../../lib/logasm/adapters/stdout_json_adapter'
|
4
|
+
|
5
|
+
describe Logasm::Adapters::StdoutJsonAdapter do
|
6
|
+
let(:debug_level_code) { 0 }
|
7
|
+
let(:debug_level) { Logasm::Adapters::LOG_LEVELS[debug_level_code] }
|
8
|
+
let(:info_level_code) { 1 }
|
9
|
+
let(:info_level) { Logasm::Adapters::LOG_LEVELS[info_level_code] }
|
10
|
+
|
11
|
+
describe '#log' do
|
12
|
+
context 'when below threshold' do
|
13
|
+
let(:adapter) { described_class.new(debug_level_code, service_name) }
|
14
|
+
let(:metadata) { {x: 'y'} }
|
15
|
+
let(:event) { {a: 'b', x: 'y'} }
|
16
|
+
let(:serialized_event) { JSON.dump(event) }
|
17
|
+
let(:service_name) { 'my-service' }
|
18
|
+
let(:application_name) { 'my_service' }
|
19
|
+
|
20
|
+
before do
|
21
|
+
allow(Logasm::Utils).to receive(:build_event)
|
22
|
+
.with(metadata, info_level, application_name)
|
23
|
+
.and_return(event)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'sends serialized event to STDOUT' do
|
27
|
+
expect(STDOUT).to receive(:puts).with(serialized_event)
|
28
|
+
adapter.log(info_level, metadata)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'when above threshold' do
|
33
|
+
let(:adapter) { described_class.new(info_level_code, service_name) }
|
34
|
+
let(:metadata) { {x: 'y'} }
|
35
|
+
let(:service_name) { 'my-service' }
|
36
|
+
|
37
|
+
it 'does not log the event' do
|
38
|
+
expect(STDOUT).to_not receive(:puts)
|
39
|
+
adapter.log(debug_level, metadata)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/spec/logasm_spec.rb
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Logasm do
|
4
|
+
describe '.build' do
|
5
|
+
it 'creates stdout logger' do
|
6
|
+
expect(described_class).to receive(:new) do |adapters|
|
7
|
+
expect(adapters.count).to be(1)
|
8
|
+
expect(adapters.first).to be_a(described_class::Adapters::StdoutAdapter)
|
9
|
+
end
|
10
|
+
|
11
|
+
described_class.build('test_service', stdout: nil)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'creates stdout json logger' do
|
15
|
+
expect(described_class).to receive(:new) do |adapters|
|
16
|
+
expect(adapters.count).to be(1)
|
17
|
+
expect(adapters.first).to be_a(described_class::Adapters::StdoutJsonAdapter)
|
18
|
+
end
|
19
|
+
|
20
|
+
described_class.build('test_service', stdout: {json: true})
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'creates stdout logger when no loggers are specified' do
|
24
|
+
expect(described_class).to receive(:new) do |adapters|
|
25
|
+
expect(adapters.count).to be(1)
|
26
|
+
expect(adapters.first).to be_a(described_class::Adapters::StdoutAdapter)
|
27
|
+
end
|
28
|
+
|
29
|
+
described_class.build('test_service', nil)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'creates preprocessor when preprocessor defined' do
|
33
|
+
expect(described_class).to receive(:new) do |adapters, preprocessors|
|
34
|
+
expect(preprocessors.count).to be(1)
|
35
|
+
expect(preprocessors.first).to be_a(described_class::Preprocessors::Blacklist)
|
36
|
+
end
|
37
|
+
|
38
|
+
preprocessors = {blacklist: {fields: []}}
|
39
|
+
described_class.build('test_service', nil, preprocessors)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when preprocessor defined' do
|
44
|
+
let(:logasm) { described_class.new([adapter], [preprocessor]) }
|
45
|
+
let(:adapter) { double }
|
46
|
+
let(:preprocessor) { double }
|
47
|
+
let(:data) { {data: 'data'} }
|
48
|
+
|
49
|
+
it 'preprocesses data before logging' do
|
50
|
+
expect(preprocessor).to receive(:process).with(data).and_return(data.merge(processed: true)).ordered
|
51
|
+
expect(adapter).to receive(:log).with(:info, data.merge(processed: true)).ordered
|
52
|
+
|
53
|
+
logasm.info(data)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when parsing log data' do
|
58
|
+
let(:logasm) { described_class.new([adapter], preprocessors) }
|
59
|
+
let(:adapter) { double }
|
60
|
+
let(:preprocessors) { [] }
|
61
|
+
|
62
|
+
it 'parses empty string with nil metadata' do
|
63
|
+
expect(adapter).to receive(:log).with(:info, message: '')
|
64
|
+
|
65
|
+
logasm.info('', nil)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'parses nil as metadata' do
|
69
|
+
expect(adapter).to receive(:log).with(:info, message: nil)
|
70
|
+
|
71
|
+
logasm.info(nil)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'parses only message' do
|
75
|
+
expect(adapter).to receive(:log).with(:info, message: 'test message')
|
76
|
+
|
77
|
+
logasm.info 'test message'
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'parses only metadata' do
|
81
|
+
expect(adapter).to receive(:log).with(:info, test: 'data')
|
82
|
+
|
83
|
+
logasm.info test: 'data'
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'parses message and metadata' do
|
87
|
+
expect(adapter).to receive(:log).with(:info, message: 'test message', test: 'data')
|
88
|
+
|
89
|
+
logasm.info 'test message', test: 'data'
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'parses block as a message' do
|
93
|
+
message = 'test message'
|
94
|
+
expect(adapter).to receive(:log).with(:info, message: message)
|
95
|
+
|
96
|
+
logasm.info { message }
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'ignores progname on block syntax' do
|
100
|
+
message = 'test message'
|
101
|
+
expect(adapter).to receive(:log).with(:info, message: message)
|
102
|
+
|
103
|
+
logasm.info('progname') { message }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'log level queries' do
|
108
|
+
context 'when adapter has debug level' do
|
109
|
+
let(:logger) do
|
110
|
+
described_class.build('test_service', stdout: {level: 'debug'})
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'responds true to debug? and higher levels' do
|
114
|
+
expect(logger.debug?).to be(true)
|
115
|
+
expect(logger.info?).to be(true)
|
116
|
+
expect(logger.warn?).to be(true)
|
117
|
+
expect(logger.error?).to be(true)
|
118
|
+
expect(logger.fatal?).to be(true)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context 'when adapter has info level' do
|
123
|
+
let(:logger) do
|
124
|
+
described_class.build('test_service', stdout: {level: 'info'})
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'responds true to info? and higher levels' do
|
128
|
+
expect(logger.debug?).to be(false)
|
129
|
+
expect(logger.info?).to be(true)
|
130
|
+
expect(logger.warn?).to be(true)
|
131
|
+
expect(logger.error?).to be(true)
|
132
|
+
expect(logger.fatal?).to be(true)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'has the same interface as Ruby logger' do
|
138
|
+
skip "https://salemove.atlassian.net/browse/INF-464"
|
139
|
+
logger = described_class.build('test_service', stdout: {level: 'debug'})
|
140
|
+
expect(logger).to implement_interface(Logger)
|
141
|
+
end
|
142
|
+
end
|