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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a9ade685a2af887a257340ed2dab29d09abceb8a
4
- data.tar.gz: 1b5671acbe54ce055156a496a481ce524270a3b1
3
+ metadata.gz: 56e3d511b8873dffb529444790ec2c111f2e06ce
4
+ data.tar.gz: 26ae968b0af65670a1fe9db8801b69748f6d6c96
5
5
  SHA512:
6
- metadata.gz: d5a206ab30b603af225468e52195c9ef3e87b42d2bf71cd7794ebe98b3eabe952fe9df666d1a1618915a379e7ac0559fba7e5543d6dbf5d1de1574157fb3ce83
7
- data.tar.gz: b363d87991efde13a6ea82b82e673536aa83179ad1f103f1d8098fe00222bf2b9e321b5a9bc59cf3ce0b9fbf451ec53eeb11c5ebfd8b3f11c21265d9a363d88e
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
@@ -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
- require_relative "adapters/#{type.to_s}_adapter"
7
- adapter = const_get(Inflecto.camelize(type.to_s) + 'Adapter')
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
- 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
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 = "#{parent_pointer}/#{key}"
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
- mask value
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.5.2'
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 file logger' do
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: '******'}, 1)
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 one asterisk' do
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 one asterisk' do
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 one asterisk' do
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: '******'}, depth)
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: '*******'}, {field: 'data2', 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 single asteriks' do
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.5.2
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-01 00:00:00.000000000 Z
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