logasm-jruby 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|