logasm 0.2.6 → 0.3.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 +71 -0
- data/lib/logasm/preprocessors/blacklist.rb +67 -0
- data/lib/logasm/preprocessors/whitelist.rb +88 -0
- data/lib/logasm/preprocessors.rb +9 -0
- data/lib/logasm.rb +16 -4
- data/logasm.gemspec +1 -1
- data/spec/logasm_spec.rb +32 -1
- data/spec/preprocessors/blacklist_spec.rb +131 -0
- data/spec/preprocessors/whitelist_spec.rb +152 -0
- data/spec/support/implement_interface.rb +11 -0
- metadata +12 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 440665fe491c115f43c411822de433ead259e193
|
4
|
+
data.tar.gz: 06568509dacd084a9607ac545b3cfd03447947db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 380b1118c988bbf141b9c03a63ca3c68d33f1f8873709bd92d5e52188dfb3adf980edf7d040eca62c2bdbc66fb4a142e0906e2272aa278cceb4109d6c88e52a2
|
7
|
+
data.tar.gz: b93a280171c1123d5559ac630a5db52710cd429a7f5bbaddbb73885f7aa75d287d21b117ca3a8fe75b6a2399667c05bcb1631ce889795f2b493036f664742992
|
data/README.md
CHANGED
@@ -61,3 +61,74 @@ logasm = Logasm.build('myApp', { stdout: nil, logstash: { host: "localhost", por
|
|
61
61
|
```
|
62
62
|
|
63
63
|
When no loggers are specified, it creates a stdout logger by default.
|
64
|
+
|
65
|
+
## Preprocessors
|
66
|
+
|
67
|
+
Preprocessors allow modification of log messages, prior to sending of the message to the configured logger(s).
|
68
|
+
|
69
|
+
### Blacklist
|
70
|
+
|
71
|
+
Excludes or masks defined fields of the passed hash object.
|
72
|
+
You can specify the name of the field and which action to take on it.
|
73
|
+
Nested hashes of any level are preprocessed as well.
|
74
|
+
|
75
|
+
Available actions:
|
76
|
+
|
77
|
+
* exclude(`default`) - fully excludes the field and its value from the hash.
|
78
|
+
* mask - replaces every character from the original value with `*`. In case of `array`, `hash` or `boolean` value is replaced with one `*`.
|
79
|
+
|
80
|
+
#### Configuration
|
81
|
+
|
82
|
+
```yaml
|
83
|
+
preprocessors:
|
84
|
+
blacklist:
|
85
|
+
fields:
|
86
|
+
- key: password
|
87
|
+
- key: phone
|
88
|
+
action: mask
|
89
|
+
```
|
90
|
+
|
91
|
+
#### Usage
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
logger = Logasm.build(application_name, logger_config, preprocessors)
|
95
|
+
|
96
|
+
input = {password: 'password', info: {phone: '+12055555555'}}
|
97
|
+
|
98
|
+
logger.debug("Received request", input)
|
99
|
+
```
|
100
|
+
|
101
|
+
Logger output:
|
102
|
+
|
103
|
+
```
|
104
|
+
Received request {"info":{"phone":"************"}}
|
105
|
+
```
|
106
|
+
|
107
|
+
### Whitelist
|
108
|
+
|
109
|
+
Masks all the fields except those whitelisted in the configuration using [JSON Pointer](https://tools.ietf.org/html/rfc6901).
|
110
|
+
Only simple values(`string`, `number`, `boolean`) can be whitelisted.
|
111
|
+
|
112
|
+
#### Configuration
|
113
|
+
|
114
|
+
```yaml
|
115
|
+
preprocessors:
|
116
|
+
whitelist:
|
117
|
+
pointers: ['/info/phone']
|
118
|
+
```
|
119
|
+
|
120
|
+
#### Usage
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
logger = Logasm.build(application_name, logger_config, preprocessors)
|
124
|
+
|
125
|
+
input = {password: 'password', info: {phone: '+12055555555'}}
|
126
|
+
|
127
|
+
logger.debug("Received request", input)
|
128
|
+
```
|
129
|
+
|
130
|
+
Logger output:
|
131
|
+
|
132
|
+
```
|
133
|
+
Received request {password: "********", "info":{"phone":"+12055555555"}}
|
134
|
+
```
|
@@ -0,0 +1,67 @@
|
|
1
|
+
class Logasm
|
2
|
+
module Preprocessors
|
3
|
+
class Blacklist
|
4
|
+
|
5
|
+
DEFAULT_ACTION = 'exclude'
|
6
|
+
MASK_SYMBOL = '*'
|
7
|
+
|
8
|
+
class UnsupportedActionException < Exception
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(config = {})
|
12
|
+
@fields_to_process = config[:fields].inject({}) do |mem, field|
|
13
|
+
key = field.delete(:key)
|
14
|
+
options = {action: DEFAULT_ACTION}.merge(field)
|
15
|
+
validate_action_supported(options[:action])
|
16
|
+
mem.merge(key => options)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def process(data)
|
21
|
+
if data.is_a? Hash
|
22
|
+
data.inject({}) do |mem, (key, val)|
|
23
|
+
if (field = @fields_to_process[key.to_s])
|
24
|
+
self.send(action_method(field[:action]), mem, key, val)
|
25
|
+
else
|
26
|
+
mem.merge(key => process(val))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
elsif data.is_a? Array
|
30
|
+
data.inject([]) do |mem, val|
|
31
|
+
mem + [process(val)]
|
32
|
+
end
|
33
|
+
else
|
34
|
+
data
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def action_method(action)
|
41
|
+
"#{action}_field"
|
42
|
+
end
|
43
|
+
|
44
|
+
def validate_action_supported(action)
|
45
|
+
unless self.respond_to?(action_method(action).to_sym, true)
|
46
|
+
raise UnsupportedActionException.new("Action: #{action} is not supported")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def mask_field(data, key, val)
|
51
|
+
if val.is_a?(Hash) || val.is_a?(Array) || is_boolean?(val)
|
52
|
+
data.merge(key => MASK_SYMBOL)
|
53
|
+
else
|
54
|
+
data.merge(key => MASK_SYMBOL * val.to_s.length)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def exclude_field(data, *)
|
59
|
+
data
|
60
|
+
end
|
61
|
+
|
62
|
+
def is_boolean?(val)
|
63
|
+
val.is_a?(TrueClass) || val.is_a?(FalseClass)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
class Logasm
|
2
|
+
module Preprocessors
|
3
|
+
class Whitelist
|
4
|
+
|
5
|
+
DEFAULT_WHITELIST = %w(/id /message /correlation_id /queue)
|
6
|
+
MASK_SYMBOL = '*'
|
7
|
+
|
8
|
+
class InvalidPointerFormatException < Exception
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(config = {})
|
12
|
+
pointers = (config[:pointers] || []) + DEFAULT_WHITELIST
|
13
|
+
@fields_to_include = pointers.inject({}) do |mem, pointer|
|
14
|
+
validate_pointer(pointer)
|
15
|
+
mem.merge(decode(pointer) => true)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def process(data)
|
20
|
+
process_data('', data)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def validate_pointer(pointer)
|
26
|
+
if pointer.slice(-1) == '/'
|
27
|
+
raise InvalidPointerFormatException.new('Pointer should not contain trailing slash')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def decode(pointer)
|
32
|
+
pointer
|
33
|
+
.gsub('~0', '~')
|
34
|
+
.gsub('~1', '/')
|
35
|
+
end
|
36
|
+
|
37
|
+
def process_data(parent_pointer, data)
|
38
|
+
self.send("process_#{get_type(data)}", parent_pointer, data)
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_type(data)
|
42
|
+
if data.is_a? Hash
|
43
|
+
'hash'
|
44
|
+
elsif data.is_a? Array
|
45
|
+
'array'
|
46
|
+
else
|
47
|
+
'value'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def process_hash(parent_pointer, hash)
|
52
|
+
hash.inject({}) do |mem, (key, value)|
|
53
|
+
pointer = "#{parent_pointer}/#{key}"
|
54
|
+
processed_value = process_data(pointer, value)
|
55
|
+
mem.merge(key => processed_value)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def process_array(parent_pointer, array)
|
60
|
+
array.each_with_index.inject([]) do |mem, (value, index)|
|
61
|
+
pointer = "#{parent_pointer}/#{index}"
|
62
|
+
processed_value = process_data(pointer, value)
|
63
|
+
mem + [processed_value]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def process_value(parent_pointer, value)
|
68
|
+
if @fields_to_include[parent_pointer]
|
69
|
+
value
|
70
|
+
else
|
71
|
+
mask value
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def mask(value)
|
76
|
+
if value && value.respond_to?(:to_s) && !is_boolean?(value)
|
77
|
+
MASK_SYMBOL * value.to_s.length
|
78
|
+
else
|
79
|
+
MASK_SYMBOL
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def is_boolean?(value)
|
84
|
+
value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/logasm.rb
CHANGED
@@ -4,20 +4,25 @@ require 'json'
|
|
4
4
|
require_relative 'logasm/adapters'
|
5
5
|
require_relative 'logasm/utils'
|
6
6
|
require_relative 'logasm/null_logger'
|
7
|
+
require_relative 'logasm/preprocessors'
|
7
8
|
|
8
9
|
LOG_LEVEL_QUERY_METHODS = [:debug?, :info?, :warn?, :error?, :fatal?]
|
9
10
|
|
10
11
|
class Logasm
|
11
|
-
def self.build(service_name, loggers_config)
|
12
|
+
def self.build(service_name, loggers_config, preprocessors_config = {})
|
12
13
|
loggers_config ||= {stdout: nil}
|
14
|
+
preprocessors = preprocessors_config.map do |type, arguments|
|
15
|
+
Preprocessors.get(type.to_s, arguments || {})
|
16
|
+
end
|
13
17
|
adapters = loggers_config.map do |type, arguments|
|
14
18
|
Adapters.get(type.to_s, service_name, arguments || {})
|
15
19
|
end
|
16
|
-
new(adapters)
|
20
|
+
new(adapters, preprocessors)
|
17
21
|
end
|
18
22
|
|
19
|
-
def initialize(adapters)
|
23
|
+
def initialize(adapters, preprocessors)
|
20
24
|
@adapters = adapters
|
25
|
+
@preprocessors = preprocessors
|
21
26
|
end
|
22
27
|
|
23
28
|
def debug(*args)
|
@@ -50,9 +55,16 @@ class Logasm
|
|
50
55
|
|
51
56
|
def log(level, *args)
|
52
57
|
data = parse_log_data(*args)
|
58
|
+
processed_data = preprocess(data)
|
53
59
|
|
54
60
|
@adapters.each do |adapter|
|
55
|
-
adapter.log(level,
|
61
|
+
adapter.log(level, processed_data)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def preprocess(data)
|
66
|
+
@preprocessors.inject(data) do |data_to_process, preprocessor|
|
67
|
+
preprocessor.process(data_to_process)
|
56
68
|
end
|
57
69
|
end
|
58
70
|
|
data/logasm.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |gem|
|
6
6
|
gem.name = "logasm"
|
7
|
-
gem.version = '0.
|
7
|
+
gem.version = '0.3.0'
|
8
8
|
gem.authors = ["Salemove"]
|
9
9
|
gem.email = ["support@salemove.com"]
|
10
10
|
gem.description = %q{It's logasmic}
|
data/spec/logasm_spec.rb
CHANGED
@@ -38,11 +38,36 @@ describe Logasm do
|
|
38
38
|
|
39
39
|
described_class.build('test_service', nil)
|
40
40
|
end
|
41
|
+
|
42
|
+
it 'creates preprocessor when preprocessor defined' do
|
43
|
+
expect(described_class).to receive(:new) do |adapters, preprocessors|
|
44
|
+
expect(preprocessors.count).to be(1)
|
45
|
+
expect(preprocessors.first).to be_a(described_class::Preprocessors::Blacklist)
|
46
|
+
end
|
47
|
+
|
48
|
+
preprocessors = {blacklist: {fields: []}}
|
49
|
+
described_class.build('test_service', nil, preprocessors)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'when preprocessor defined' do
|
54
|
+
let(:logasm) { described_class.new([adapter], [preprocessor]) }
|
55
|
+
let(:adapter) { double }
|
56
|
+
let(:preprocessor) { double }
|
57
|
+
let(:data) { {data: 'data'} }
|
58
|
+
|
59
|
+
it 'preprocesses data before logging' do
|
60
|
+
expect(preprocessor).to receive(:process).with(data).and_return(data.merge(processed: true)).ordered
|
61
|
+
expect(adapter).to receive(:log).with(:info, data.merge(processed: true)).ordered
|
62
|
+
|
63
|
+
logasm.info(data)
|
64
|
+
end
|
41
65
|
end
|
42
66
|
|
43
67
|
context 'when parsing log data' do
|
44
|
-
let(:logasm) { described_class.new([adapter]) }
|
68
|
+
let(:logasm) { described_class.new([adapter], preprocessors) }
|
45
69
|
let(:adapter) { double }
|
70
|
+
let(:preprocessors) { [] }
|
46
71
|
|
47
72
|
it 'parses empty string with nil metadata' do
|
48
73
|
expect(adapter).to receive(:log).with(:info, message: '')
|
@@ -114,4 +139,10 @@ describe Logasm do
|
|
114
139
|
end
|
115
140
|
end
|
116
141
|
end
|
142
|
+
|
143
|
+
it 'has the same interface as Ruby logger' do
|
144
|
+
skip "https://salemove.atlassian.net/browse/INF-464"
|
145
|
+
logger = described_class.build('test_service', stdout: {level: 'debug'})
|
146
|
+
expect(logger).to implement_interface(Logger)
|
147
|
+
end
|
117
148
|
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative '../../lib/logasm/preprocessors/blacklist'
|
3
|
+
|
4
|
+
describe Logasm::Preprocessors::Blacklist do
|
5
|
+
subject(:processed_data) { described_class.new(config).process(data) }
|
6
|
+
|
7
|
+
let(:config) {{
|
8
|
+
fields: [{ key: 'field', action: action }]
|
9
|
+
}}
|
10
|
+
|
11
|
+
let(:action) {}
|
12
|
+
let(:data) {{
|
13
|
+
field: value,
|
14
|
+
data: {
|
15
|
+
field: 'secret'
|
16
|
+
},
|
17
|
+
array: [{field: 'secret'}]
|
18
|
+
}}
|
19
|
+
|
20
|
+
let(:value) { 'secret' }
|
21
|
+
|
22
|
+
context 'when action is unsupported' do
|
23
|
+
let(:action) { 'reverse' }
|
24
|
+
|
25
|
+
it 'throws exception' do
|
26
|
+
expect { processed_data }.to raise_exception(Logasm::Preprocessors::Blacklist::UnsupportedActionException)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when action is "exclude"' do
|
31
|
+
let(:action) { 'exclude' }
|
32
|
+
|
33
|
+
it 'removes the field' do
|
34
|
+
expect(processed_data).not_to include(:field)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'removes nested field' do
|
38
|
+
expect(processed_data).not_to include_at_depth({field: 'secret'}, 1)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'removes nested in array field' do
|
42
|
+
expect(processed_data[:array]).not_to include({field: 'secret'})
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when field is deeply nested' do
|
46
|
+
let(:depth) { 10 }
|
47
|
+
let(:data) { data_with_nested_field({field: 'secret'}, depth) }
|
48
|
+
|
49
|
+
it 'removes deeply nested field' do
|
50
|
+
expect(processed_data).not_to include_at_depth({field: 'secret'}, depth)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'when action is "mask"' do
|
56
|
+
let(:action) { 'mask' }
|
57
|
+
|
58
|
+
it 'masks nested field' do
|
59
|
+
expect(processed_data).to include_at_depth({field: '******'}, 1)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'masks nested in array field' do
|
63
|
+
expect(processed_data[:array]).to include({field: '******'})
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'when field is string' do
|
67
|
+
let(:value) { 'secret' }
|
68
|
+
|
69
|
+
it 'masks value with asterisks' do
|
70
|
+
expect(processed_data).to include(field: '******')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'when field is number' do
|
75
|
+
let(:value) { 42 }
|
76
|
+
|
77
|
+
it 'masks number value' do
|
78
|
+
expect(processed_data).to include(field: '**')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'when field is boolean' do
|
83
|
+
let(:value) { true }
|
84
|
+
|
85
|
+
it 'masks value with one asterisk' do
|
86
|
+
expect(processed_data).to include(field: '*')
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'when field is array' do
|
91
|
+
let(:value) { [1,2,3,4] }
|
92
|
+
|
93
|
+
it 'masks value with one asterisk' do
|
94
|
+
expect(processed_data).to include(field: '*')
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'when field is hash' do
|
99
|
+
let(:value) { {data: {}} }
|
100
|
+
|
101
|
+
it 'masks value with one asterisk' do
|
102
|
+
expect(processed_data).to include(field: '*')
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'when field is deeply nested' do
|
107
|
+
let(:depth) { 10 }
|
108
|
+
let(:data) { data_with_nested_field({field: 'secret'}, depth) }
|
109
|
+
|
110
|
+
it 'masks deeply nested field' do
|
111
|
+
expect(processed_data).to include_at_depth({field: '******'}, depth)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def data_with_nested_field(field, depth)
|
117
|
+
depth.times.inject(field) do |mem|
|
118
|
+
{}.merge(data: mem)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
RSpec::Matchers.define :include_at_depth do |expected_hash, depth|
|
123
|
+
match do |actual|
|
124
|
+
nested_data = depth.times.inject(actual) do |mem|
|
125
|
+
mem[:data]
|
126
|
+
end
|
127
|
+
|
128
|
+
expect(nested_data).to include(expected_hash)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative '../../lib/logasm/preprocessors/whitelist'
|
3
|
+
|
4
|
+
describe Logasm::Preprocessors::Whitelist do
|
5
|
+
subject(:processed_data) { described_class.new(config).process(data) }
|
6
|
+
|
7
|
+
let(:config) { {pointers: pointers} }
|
8
|
+
let(:pointers) { [] }
|
9
|
+
let(:data) {{
|
10
|
+
field: 'secret',
|
11
|
+
data: {
|
12
|
+
field: 'secret'
|
13
|
+
},
|
14
|
+
array: [{field: 'secret'}]
|
15
|
+
}}
|
16
|
+
|
17
|
+
it 'masks all non-whitelisted fields' do
|
18
|
+
expect(processed_data).to eq({
|
19
|
+
field: '******',
|
20
|
+
data: {
|
21
|
+
field: '******'
|
22
|
+
},
|
23
|
+
array: [{field: '******'}]
|
24
|
+
})
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'when pointer has trailing slash' do
|
28
|
+
let(:pointers) { ['/field/'] }
|
29
|
+
|
30
|
+
it 'throws exception' do
|
31
|
+
expect { processed_data }.to raise_exception(Logasm::Preprocessors::Whitelist::InvalidPointerFormatException)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'with whitelisted field' do
|
36
|
+
let(:pointers) { ['/field'] }
|
37
|
+
|
38
|
+
it 'includes the field' do
|
39
|
+
expect(processed_data).to eq({
|
40
|
+
field: 'secret',
|
41
|
+
data: {
|
42
|
+
field: '******'
|
43
|
+
},
|
44
|
+
array: [{field: '******'}]
|
45
|
+
})
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'with whitelisted nested field' do
|
50
|
+
let(:pointers) { ['/data/field'] }
|
51
|
+
|
52
|
+
it 'includes nested field' do
|
53
|
+
expect(processed_data).to eq({
|
54
|
+
field: '******',
|
55
|
+
data: {
|
56
|
+
field: 'secret'
|
57
|
+
},
|
58
|
+
array: [{field: '******'}]
|
59
|
+
})
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'with whitelisted array element field' do
|
64
|
+
let(:pointers) { ['/array/0/field'] }
|
65
|
+
|
66
|
+
it 'includes array element' do
|
67
|
+
expect(processed_data).to eq({
|
68
|
+
field: '******',
|
69
|
+
data: {
|
70
|
+
field: '******'
|
71
|
+
},
|
72
|
+
array: [{field: 'secret'}]
|
73
|
+
})
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'with whitelisted array element' do
|
78
|
+
let(:pointers) { ['/array/0'] }
|
79
|
+
|
80
|
+
it 'masks array element' do
|
81
|
+
expect(processed_data).to include(array: [{field: '******'}])
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'with whitelisted array' do
|
86
|
+
let(:pointers) { ['/array'] }
|
87
|
+
|
88
|
+
it 'masks array' do
|
89
|
+
expect(processed_data).to include(array: [{field: '******'}])
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'with whitelisted hash' do
|
94
|
+
let(:pointers) { ['/data'] }
|
95
|
+
|
96
|
+
it 'masks hash' do
|
97
|
+
expect(processed_data).to include(data: {field: '******'})
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'when boolean present' do
|
102
|
+
let(:data) { {bool: true} }
|
103
|
+
|
104
|
+
it 'masks it with single asteriks' do
|
105
|
+
expect(processed_data).to eq(bool: '*')
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'when field has slash in the name' do
|
110
|
+
let(:data) {{
|
111
|
+
'field_with_/' => 'secret'
|
112
|
+
}}
|
113
|
+
let(:pointers) { ['/field_with_~1'] }
|
114
|
+
|
115
|
+
it 'includes field' do
|
116
|
+
expect(processed_data).to include('field_with_/'=> 'secret')
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'when field has tilde in the name' do
|
121
|
+
let(:data) {{
|
122
|
+
'field_with_~' => 'secret'
|
123
|
+
}}
|
124
|
+
let(:pointers) { ['/field_with_~0'] }
|
125
|
+
|
126
|
+
it 'includes field' do
|
127
|
+
expect(processed_data).to include('field_with_~'=> 'secret')
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'when field has slash in the name' do
|
132
|
+
let(:data) {{
|
133
|
+
'field_with_/' => 'secret'
|
134
|
+
}}
|
135
|
+
let(:pointers) { ['/field_with_~1'] }
|
136
|
+
|
137
|
+
it 'includes field' do
|
138
|
+
expect(processed_data).to include('field_with_/'=> 'secret')
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context 'when field has tilde in the name' do
|
143
|
+
let(:data) {{
|
144
|
+
'field_with_~' => 'secret'
|
145
|
+
}}
|
146
|
+
let(:pointers) { ['/field_with_~0'] }
|
147
|
+
|
148
|
+
it 'includes field' do
|
149
|
+
expect(processed_data).to include('field_with_~'=> 'secret')
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
RSpec::Matchers.define :implement_interface do |expected|
|
2
|
+
required_methods = expected.instance_methods(false)
|
3
|
+
match do |actual|
|
4
|
+
required_methods - actual.methods == []
|
5
|
+
end
|
6
|
+
|
7
|
+
failure_message do |actual|
|
8
|
+
missing_methods = required_methods - actual.methods
|
9
|
+
"Expected instance methods #{missing_methods.inspect} to be implemented"
|
10
|
+
end
|
11
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logasm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Salemove
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-07-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: inflecto
|
@@ -88,6 +88,9 @@ files:
|
|
88
88
|
- lib/logasm/adapters/rabbitmq_adapter.rb
|
89
89
|
- lib/logasm/adapters/stdout_adapter.rb
|
90
90
|
- lib/logasm/null_logger.rb
|
91
|
+
- lib/logasm/preprocessors.rb
|
92
|
+
- lib/logasm/preprocessors/blacklist.rb
|
93
|
+
- lib/logasm/preprocessors/whitelist.rb
|
91
94
|
- lib/logasm/utils.rb
|
92
95
|
- logasm.gemspec
|
93
96
|
- spec/adapters/logstash_adapter/formatter_spec.rb
|
@@ -95,8 +98,11 @@ files:
|
|
95
98
|
- spec/adapters/rabbitmq_adapter_spec.rb
|
96
99
|
- spec/adapters/stdout_adapter_spec.rb
|
97
100
|
- spec/logasm_spec.rb
|
101
|
+
- spec/preprocessors/blacklist_spec.rb
|
102
|
+
- spec/preprocessors/whitelist_spec.rb
|
98
103
|
- spec/spec_helper.rb
|
99
104
|
- spec/support/freddy_mock.rb
|
105
|
+
- spec/support/implement_interface.rb
|
100
106
|
- spec/utils_spec.rb
|
101
107
|
homepage:
|
102
108
|
licenses:
|
@@ -118,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
118
124
|
version: '0'
|
119
125
|
requirements: []
|
120
126
|
rubyforge_project:
|
121
|
-
rubygems_version: 2.4.
|
127
|
+
rubygems_version: 2.4.8
|
122
128
|
signing_key:
|
123
129
|
specification_version: 4
|
124
130
|
summary: What description said
|
@@ -128,6 +134,9 @@ test_files:
|
|
128
134
|
- spec/adapters/rabbitmq_adapter_spec.rb
|
129
135
|
- spec/adapters/stdout_adapter_spec.rb
|
130
136
|
- spec/logasm_spec.rb
|
137
|
+
- spec/preprocessors/blacklist_spec.rb
|
138
|
+
- spec/preprocessors/whitelist_spec.rb
|
131
139
|
- spec/spec_helper.rb
|
132
140
|
- spec/support/freddy_mock.rb
|
141
|
+
- spec/support/implement_interface.rb
|
133
142
|
- spec/utils_spec.rb
|