logasm 0.5.2 → 0.7.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 +4 -4
- data/README.md +1 -1
- data/lib/logasm/adapters/stdout_json_adapter.rb +43 -0
- data/lib/logasm/adapters.rb +18 -2
- data/lib/logasm/preprocessors/blacklist.rb +2 -9
- data/lib/logasm/preprocessors/whitelist.rb +9 -14
- data/logasm.gemspec +1 -1
- data/spec/adapters/stdout_json_adapter_spec.rb +41 -0
- data/spec/logasm_spec.rb +10 -1
- data/spec/preprocessors/blacklist_spec.rb +11 -11
- data/spec/preprocessors/whitelist_spec.rb +34 -16
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 56e3d511b8873dffb529444790ec2c111f2e06ce
|
4
|
+
data.tar.gz: 26ae968b0af65670a1fe9db8801b69748f6d6c96
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f71ce0380318847e9fe3eafd4cd4f9ab26b4175e2cd796dd575d9cf2f4192ca298d0b801b5e9464ccdc649c7dc0b0071b4f29fce2514bd099f8342806123de89
|
7
|
+
data.tar.gz: 38cf576d4f1e8f2961cbf8416373de2a06f6960bb83e13dc692940a56cd1554ca5537eac9be9650aba935030ea0dbd4b83d4e396f826dfac1178d6205b9303ef
|
data/README.md
CHANGED
@@ -108,7 +108,7 @@ Received request {"info":{"phone":"************"}}
|
|
108
108
|
|
109
109
|
Masks all the fields except those whitelisted in the configuration using [JSON Pointer](https://tools.ietf.org/html/rfc6901).
|
110
110
|
Only simple values(`string`, `number`, `boolean`) can be whitelisted.
|
111
|
-
Whitelisting array elements can be done using wildcard symbol `~`.
|
111
|
+
Whitelisting array and hash elements can be done using wildcard symbol `~`.
|
112
112
|
|
113
113
|
#### Configuration
|
114
114
|
|
@@ -0,0 +1,43 @@
|
|
1
|
+
class Logasm
|
2
|
+
module Adapters
|
3
|
+
class StdoutJsonAdapter
|
4
|
+
def initialize(level, service_name, *)
|
5
|
+
@level = level
|
6
|
+
@service_name = service_name
|
7
|
+
end
|
8
|
+
|
9
|
+
def log(level, metadata = {})
|
10
|
+
if meets_threshold?(level)
|
11
|
+
message = Utils.build_event(metadata, level, @service_name)
|
12
|
+
STDOUT.puts(JSON.dump(message))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def debug?
|
17
|
+
meets_threshold?(:debug)
|
18
|
+
end
|
19
|
+
|
20
|
+
def info?
|
21
|
+
meets_threshold?(:info)
|
22
|
+
end
|
23
|
+
|
24
|
+
def warn?
|
25
|
+
meets_threshold?(:warn)
|
26
|
+
end
|
27
|
+
|
28
|
+
def error?
|
29
|
+
meets_threshold?(:error)
|
30
|
+
end
|
31
|
+
|
32
|
+
def fatal?
|
33
|
+
meets_threshold?(:fatal)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def meets_threshold?(level)
|
39
|
+
LOG_LEVELS.index(level.to_s) >= @level
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/logasm/adapters.rb
CHANGED
@@ -3,8 +3,24 @@ class Logasm
|
|
3
3
|
LOG_LEVELS = %w(debug info warn error fatal unknown).freeze
|
4
4
|
|
5
5
|
def self.get(type, service_name, arguments)
|
6
|
-
|
7
|
-
|
6
|
+
adapter =
|
7
|
+
if type == 'rabbitmq'
|
8
|
+
require_relative 'adapters/rabbitmq_adapter'
|
9
|
+
RabbitmqAdapter
|
10
|
+
elsif type == 'logstash'
|
11
|
+
require_relative 'adapters/logstash_adapter'
|
12
|
+
LogstashAdapter
|
13
|
+
elsif type == 'stdout'
|
14
|
+
if arguments.fetch(:json, false)
|
15
|
+
require_relative 'adapters/stdout_json_adapter'
|
16
|
+
StdoutJsonAdapter
|
17
|
+
else
|
18
|
+
require_relative 'adapters/stdout_adapter'
|
19
|
+
StdoutAdapter
|
20
|
+
end
|
21
|
+
else
|
22
|
+
raise "Unsupported logger: #{type}"
|
23
|
+
end
|
8
24
|
level = LOG_LEVELS.index(arguments.fetch(:level, 'debug'))
|
9
25
|
adapter.new(level, service_name, arguments)
|
10
26
|
end
|
@@ -4,6 +4,7 @@ class Logasm
|
|
4
4
|
|
5
5
|
DEFAULT_ACTION = 'exclude'
|
6
6
|
MASK_SYMBOL = '*'
|
7
|
+
MASKED_VALUE = MASK_SYMBOL * 5
|
7
8
|
|
8
9
|
class UnsupportedActionException < Exception
|
9
10
|
end
|
@@ -48,20 +49,12 @@ class Logasm
|
|
48
49
|
end
|
49
50
|
|
50
51
|
def mask_field(data, key, val)
|
51
|
-
|
52
|
-
data.merge(key => MASK_SYMBOL)
|
53
|
-
else
|
54
|
-
data.merge(key => MASK_SYMBOL * val.to_s.length)
|
55
|
-
end
|
52
|
+
data.merge(key => MASKED_VALUE)
|
56
53
|
end
|
57
54
|
|
58
55
|
def exclude_field(data, *)
|
59
56
|
data
|
60
57
|
end
|
61
|
-
|
62
|
-
def is_boolean?(val)
|
63
|
-
val.is_a?(TrueClass) || val.is_a?(FalseClass)
|
64
|
-
end
|
65
58
|
end
|
66
59
|
end
|
67
60
|
end
|
@@ -4,6 +4,7 @@ class Logasm
|
|
4
4
|
|
5
5
|
DEFAULT_WHITELIST = %w(/id /message /correlation_id /queue)
|
6
6
|
MASK_SYMBOL = '*'
|
7
|
+
MASKED_VALUE = MASK_SYMBOL * 5
|
7
8
|
WILDCARD = '~'
|
8
9
|
|
9
10
|
class InvalidPointerFormatException < Exception
|
@@ -85,8 +86,14 @@ class Logasm
|
|
85
86
|
end
|
86
87
|
|
87
88
|
def process_hash(parent_pointer, hash)
|
89
|
+
create_child_pointer =
|
90
|
+
if @wildcards["#{parent_pointer}/~"]
|
91
|
+
lambda { |_| "#{parent_pointer}/~" }
|
92
|
+
else
|
93
|
+
lambda { |key| "#{parent_pointer}/#{key}" }
|
94
|
+
end
|
88
95
|
hash.inject({}) do |mem, (key, value)|
|
89
|
-
pointer =
|
96
|
+
pointer = create_child_pointer.call(key)
|
90
97
|
processed_value = process_data(pointer, value)
|
91
98
|
mem.merge(key => processed_value)
|
92
99
|
end
|
@@ -110,21 +117,9 @@ class Logasm
|
|
110
117
|
if @fields_to_include[parent_pointer]
|
111
118
|
value
|
112
119
|
else
|
113
|
-
|
120
|
+
MASKED_VALUE
|
114
121
|
end
|
115
122
|
end
|
116
|
-
|
117
|
-
def mask(value)
|
118
|
-
if value && value.respond_to?(:to_s) && !is_boolean?(value)
|
119
|
-
MASK_SYMBOL * value.to_s.length
|
120
|
-
else
|
121
|
-
MASK_SYMBOL
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
def is_boolean?(value)
|
126
|
-
value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
127
|
-
end
|
128
123
|
end
|
129
124
|
end
|
130
125
|
end
|
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.7.0'
|
8
8
|
gem.authors = ["Salemove"]
|
9
9
|
gem.email = ["support@salemove.com"]
|
10
10
|
gem.description = %q{It's logasmic}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative '../../lib/logasm/adapters/stdout_json_adapter'
|
3
|
+
|
4
|
+
describe Logasm::Adapters::StdoutJsonAdapter do
|
5
|
+
let(:debug_level_code) { 0 }
|
6
|
+
let(:debug_level) { Logasm::Adapters::LOG_LEVELS[debug_level_code] }
|
7
|
+
let(:info_level_code) { 1 }
|
8
|
+
let(:info_level) { Logasm::Adapters::LOG_LEVELS[info_level_code] }
|
9
|
+
|
10
|
+
describe '#log' do
|
11
|
+
context 'when below threshold' do
|
12
|
+
let(:adapter) { described_class.new(debug_level_code, service_name) }
|
13
|
+
let(:metadata) { {x: 'y'} }
|
14
|
+
let(:event) { {a: 'b', x: 'y'} }
|
15
|
+
let(:serialized_event) { JSON.dump(event) }
|
16
|
+
let(:service_name) { 'my-service' }
|
17
|
+
|
18
|
+
before do
|
19
|
+
allow(Logasm::Utils).to receive(:build_event)
|
20
|
+
.with(metadata, info_level, service_name)
|
21
|
+
.and_return(event)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'sends serialized event to STDOUT' do
|
25
|
+
expect(STDOUT).to receive(:puts).with(serialized_event)
|
26
|
+
adapter.log(info_level, metadata)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when above threshold' do
|
31
|
+
let(:adapter) { described_class.new(info_level_code, service_name) }
|
32
|
+
let(:metadata) { {x: 'y'} }
|
33
|
+
let(:service_name) { 'my-service' }
|
34
|
+
|
35
|
+
it 'does not log the event' do
|
36
|
+
expect(STDOUT).to_not receive(:puts)
|
37
|
+
adapter.log(debug_level, metadata)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/spec/logasm_spec.rb
CHANGED
@@ -2,7 +2,7 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Logasm do
|
4
4
|
describe '.build' do
|
5
|
-
it 'creates
|
5
|
+
it 'creates stdout logger' do
|
6
6
|
expect(described_class).to receive(:new) do |adapters|
|
7
7
|
expect(adapters.count).to be(1)
|
8
8
|
expect(adapters.first).to be_a(described_class::Adapters::StdoutAdapter)
|
@@ -11,6 +11,15 @@ describe Logasm do
|
|
11
11
|
described_class.build('test_service', stdout: nil)
|
12
12
|
end
|
13
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
|
+
|
14
23
|
it 'creates logstash logger' do
|
15
24
|
expect(described_class).to receive(:new) do |adapters|
|
16
25
|
expect(adapters.count).to be(1)
|
@@ -56,18 +56,18 @@ describe Logasm::Preprocessors::Blacklist do
|
|
56
56
|
let(:action) { 'mask' }
|
57
57
|
|
58
58
|
it 'masks nested field' do
|
59
|
-
expect(processed_data).to include_at_depth({field: '
|
59
|
+
expect(processed_data).to include_at_depth({field: '*****'}, 1)
|
60
60
|
end
|
61
61
|
|
62
62
|
it 'masks nested in array field' do
|
63
|
-
expect(processed_data[:array]).to include({field: '
|
63
|
+
expect(processed_data[:array]).to include({field: '*****'})
|
64
64
|
end
|
65
65
|
|
66
66
|
context 'when field is string' do
|
67
67
|
let(:value) { 'secret' }
|
68
68
|
|
69
69
|
it 'masks value with asterisks' do
|
70
|
-
expect(processed_data).to include(field: '
|
70
|
+
expect(processed_data).to include(field: '*****')
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
@@ -75,31 +75,31 @@ describe Logasm::Preprocessors::Blacklist do
|
|
75
75
|
let(:value) { 42 }
|
76
76
|
|
77
77
|
it 'masks number value' do
|
78
|
-
expect(processed_data).to include(field: '
|
78
|
+
expect(processed_data).to include(field: '*****')
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
82
|
context 'when field is boolean' do
|
83
83
|
let(:value) { true }
|
84
84
|
|
85
|
-
it 'masks value with
|
86
|
-
expect(processed_data).to include(field: '
|
85
|
+
it 'masks value with asterisks' do
|
86
|
+
expect(processed_data).to include(field: '*****')
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
90
|
context 'when field is array' do
|
91
91
|
let(:value) { [1,2,3,4] }
|
92
92
|
|
93
|
-
it 'masks value with
|
94
|
-
expect(processed_data).to include(field: '
|
93
|
+
it 'masks value with asterisks' do
|
94
|
+
expect(processed_data).to include(field: '*****')
|
95
95
|
end
|
96
96
|
end
|
97
97
|
|
98
98
|
context 'when field is hash' do
|
99
99
|
let(:value) { {data: {}} }
|
100
100
|
|
101
|
-
it 'masks value with
|
102
|
-
expect(processed_data).to include(field: '
|
101
|
+
it 'masks value with asterisks' do
|
102
|
+
expect(processed_data).to include(field: '*****')
|
103
103
|
end
|
104
104
|
end
|
105
105
|
|
@@ -108,7 +108,7 @@ describe Logasm::Preprocessors::Blacklist do
|
|
108
108
|
let(:data) { data_with_nested_field({field: 'secret'}, depth) }
|
109
109
|
|
110
110
|
it 'masks deeply nested field' do
|
111
|
-
expect(processed_data).to include_at_depth({field: '
|
111
|
+
expect(processed_data).to include_at_depth({field: '*****'}, depth)
|
112
112
|
end
|
113
113
|
end
|
114
114
|
end
|
@@ -16,11 +16,11 @@ describe Logasm::Preprocessors::Whitelist do
|
|
16
16
|
|
17
17
|
it 'masks all non-whitelisted fields' do
|
18
18
|
expect(processed_data).to eq({
|
19
|
-
field: '
|
19
|
+
field: '*****',
|
20
20
|
data: {
|
21
|
-
field: '
|
21
|
+
field: '*****'
|
22
22
|
},
|
23
|
-
array: [{field: '
|
23
|
+
array: [{field: '*****'}]
|
24
24
|
})
|
25
25
|
end
|
26
26
|
|
@@ -39,9 +39,9 @@ describe Logasm::Preprocessors::Whitelist do
|
|
39
39
|
expect(processed_data).to eq({
|
40
40
|
field: 'secret',
|
41
41
|
data: {
|
42
|
-
field: '
|
42
|
+
field: '*****'
|
43
43
|
},
|
44
|
-
array: [{field: '
|
44
|
+
array: [{field: '*****'}]
|
45
45
|
})
|
46
46
|
end
|
47
47
|
end
|
@@ -51,11 +51,11 @@ describe Logasm::Preprocessors::Whitelist do
|
|
51
51
|
|
52
52
|
it 'includes nested field' do
|
53
53
|
expect(processed_data).to eq({
|
54
|
-
field: '
|
54
|
+
field: '*****',
|
55
55
|
data: {
|
56
56
|
field: 'secret'
|
57
57
|
},
|
58
|
-
array: [{field: '
|
58
|
+
array: [{field: '*****'}]
|
59
59
|
})
|
60
60
|
end
|
61
61
|
end
|
@@ -65,15 +65,29 @@ describe Logasm::Preprocessors::Whitelist do
|
|
65
65
|
|
66
66
|
it 'includes array element' do
|
67
67
|
expect(processed_data).to eq({
|
68
|
-
field: '
|
68
|
+
field: '*****',
|
69
69
|
data: {
|
70
|
-
field: '
|
70
|
+
field: '*****'
|
71
71
|
},
|
72
72
|
array: [{field: 'secret'}]
|
73
73
|
})
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
+
context 'with whitelisted hash' do
|
78
|
+
it 'includes all whitelisted hash elements' do
|
79
|
+
source = {foo: {bar: 'baz'}}
|
80
|
+
target = {foo: {bar: 'baz'}}
|
81
|
+
expect(process(['/foo/~'], source)).to eq(target)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'does not include nested elements' do
|
85
|
+
source = {foo: {bar: {baz: 'asd'}}}
|
86
|
+
target = {foo: {bar: {baz: '***'}}}
|
87
|
+
expect(process(['/foo/~'], source)).to eq(target)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
77
91
|
context 'with whitelisted array elements field with wildcard' do
|
78
92
|
let(:data) {{
|
79
93
|
array: [{field: 'data1', secret: 'secret1'}, {field: 'data2', secret: 'secret2'}]
|
@@ -82,7 +96,7 @@ describe Logasm::Preprocessors::Whitelist do
|
|
82
96
|
|
83
97
|
it 'includes array elements field' do
|
84
98
|
expect(processed_data).to include(
|
85
|
-
array: [{field: 'data1', secret: '
|
99
|
+
array: [{field: 'data1', secret: '*****'}, {field: 'data2', secret: '*****'}]
|
86
100
|
)
|
87
101
|
end
|
88
102
|
end
|
@@ -102,7 +116,7 @@ describe Logasm::Preprocessors::Whitelist do
|
|
102
116
|
let(:pointers) { ['/array/0'] }
|
103
117
|
|
104
118
|
it 'masks array element' do
|
105
|
-
expect(processed_data).to include(array: [{field: '
|
119
|
+
expect(processed_data).to include(array: [{field: '*****'}])
|
106
120
|
end
|
107
121
|
end
|
108
122
|
|
@@ -110,7 +124,7 @@ describe Logasm::Preprocessors::Whitelist do
|
|
110
124
|
let(:pointers) { ['/array'] }
|
111
125
|
|
112
126
|
it 'masks array' do
|
113
|
-
expect(processed_data).to include(array: [{field: '
|
127
|
+
expect(processed_data).to include(array: [{field: '*****'}])
|
114
128
|
end
|
115
129
|
end
|
116
130
|
|
@@ -118,15 +132,15 @@ describe Logasm::Preprocessors::Whitelist do
|
|
118
132
|
let(:pointers) { ['/data'] }
|
119
133
|
|
120
134
|
it 'masks hash' do
|
121
|
-
expect(processed_data).to include(data: {field: '
|
135
|
+
expect(processed_data).to include(data: {field: '*****'})
|
122
136
|
end
|
123
137
|
end
|
124
138
|
|
125
139
|
context 'when boolean present' do
|
126
140
|
let(:data) { {bool: true} }
|
127
141
|
|
128
|
-
it 'masks it with
|
129
|
-
expect(processed_data).to eq(bool: '
|
142
|
+
it 'masks it with asteriks' do
|
143
|
+
expect(processed_data).to eq(bool: '*****')
|
130
144
|
end
|
131
145
|
end
|
132
146
|
|
@@ -173,7 +187,7 @@ describe Logasm::Preprocessors::Whitelist do
|
|
173
187
|
expect(processed_data).to include('field_with_~'=> 'secret')
|
174
188
|
end
|
175
189
|
end
|
176
|
-
|
190
|
+
|
177
191
|
context 'when field has tilde and 1' do
|
178
192
|
let(:data) {{
|
179
193
|
'field_with_~1' => 'secret'
|
@@ -184,4 +198,8 @@ describe Logasm::Preprocessors::Whitelist do
|
|
184
198
|
expect(processed_data).to include('field_with_~1'=> 'secret')
|
185
199
|
end
|
186
200
|
end
|
201
|
+
|
202
|
+
def process(pointers, data)
|
203
|
+
described_class.new(pointers: pointers).process(data)
|
204
|
+
end
|
187
205
|
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.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Salemove
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-04-
|
11
|
+
date: 2017-04-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: inflecto
|
@@ -86,6 +86,7 @@ files:
|
|
86
86
|
- lib/logasm/adapters/logstash_adapter/formatter.rb
|
87
87
|
- lib/logasm/adapters/rabbitmq_adapter.rb
|
88
88
|
- lib/logasm/adapters/stdout_adapter.rb
|
89
|
+
- lib/logasm/adapters/stdout_json_adapter.rb
|
89
90
|
- lib/logasm/null_logger.rb
|
90
91
|
- lib/logasm/preprocessors.rb
|
91
92
|
- lib/logasm/preprocessors/blacklist.rb
|
@@ -96,6 +97,7 @@ files:
|
|
96
97
|
- spec/adapters/logstash_adapter_spec.rb
|
97
98
|
- spec/adapters/rabbitmq_adapter_spec.rb
|
98
99
|
- spec/adapters/stdout_adapter_spec.rb
|
100
|
+
- spec/adapters/stdout_json_adapter_spec.rb
|
99
101
|
- spec/logasm_spec.rb
|
100
102
|
- spec/preprocessors/blacklist_spec.rb
|
101
103
|
- spec/preprocessors/whitelist_spec.rb
|
@@ -131,6 +133,7 @@ test_files:
|
|
131
133
|
- spec/adapters/logstash_adapter_spec.rb
|
132
134
|
- spec/adapters/rabbitmq_adapter_spec.rb
|
133
135
|
- spec/adapters/stdout_adapter_spec.rb
|
136
|
+
- spec/adapters/stdout_json_adapter_spec.rb
|
134
137
|
- spec/logasm_spec.rb
|
135
138
|
- spec/preprocessors/blacklist_spec.rb
|
136
139
|
- spec/preprocessors/whitelist_spec.rb
|