From 58869fefb21efb6ab1bd63140db3fbb0f2fd10a5 Mon Sep 17 00:00:00 2001 From: Egor Lynko Date: Tue, 16 Feb 2021 19:06:41 +0300 Subject: [PATCH] Merge hash fields recursively for additional fields and child logger --- README.md | 15 ++++++++++++++- lib/ougai/logging.rb | 2 ++ spec/child_logger_spec.rb | 36 +++++++++++++++++++++++------------- spec/logging_spec.rb | 9 +++++++++ 4 files changed, 48 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 8382436..77021ed 100644 --- a/README.md +++ b/README.md @@ -194,7 +194,18 @@ logger.info('Hello!', user: { name: 'Jiro' }, version: '2.3') ``` If any field of with_fields is specified in each log, the field is overridden. -But if the field's type is *Array*, both with_field value and logging value are merged with `concat` and `uniq`. +If the field's type is *Array*, both with_field value and logging value are merged with `concat` and `uniq`. + +If the field's type is *Hash*, then values are merged recursively. + +```ruby +logger.with_fields = { version: '1.1.0', user: { name: 'Taro' } } +logger.debug(user: { age: 19 }) +``` + +```json +{"name":"test","hostname":"mint","pid":30182,"level":20,"time":"2017-07-22T20:52:12.332+09:00","v":0,"version":"1.1.0","msg":"No message","user":{"name":"Taro","age":19}} +``` ### Create a child logger @@ -242,6 +253,8 @@ child_logger.debug('This is not outputted') If any field exists in both parent log and child log, the parent value is overridden or merged by child value. +If the field's type is *Hash*, then values are merged recursively. + ### Hook before logging Setting `before_log` of logger or child an *lambda* with `data` field, a process can be run before log each output. diff --git a/lib/ougai/logging.rb b/lib/ougai/logging.rb index 56a67dd..95bb395 100644 --- a/lib/ougai/logging.rb +++ b/lib/ougai/logging.rb @@ -120,6 +120,8 @@ def weak_merge!(base_data, inferior_data) base_data.merge!(inferior_data) do |_, base_v, inferior_v| if base_v.is_a?(Array) and inferior_v.is_a?(Array) (inferior_v + base_v).uniq + elsif base_v.is_a?(Hash) and inferior_v.is_a?(Hash) + weak_merge!(base_v, inferior_v) else base_v end diff --git a/spec/child_logger_spec.rb b/spec/child_logger_spec.rb index 34468f7..5ce8524 100644 --- a/spec/child_logger_spec.rb +++ b/spec/child_logger_spec.rb @@ -390,7 +390,7 @@ parent_logger.with_fields = { foo: 11 } logger.with_fields = { bar: '11' } end - + it 'outputs with child fields' do logger.info(log_msg) parent_logger.info(parent_log_msg) @@ -426,7 +426,7 @@ before do parent_logger.with_fields = { foo: 22 } end - + it 'output with new parent fields' do logger.info(log_msg) parent_logger.info(parent_log_msg) @@ -462,7 +462,7 @@ before do logger.with_fields = { bar: '33' } end - + it 'output valid' do logger.info(log_msg) parent_logger.info(parent_log_msg) @@ -478,35 +478,45 @@ context 'grandchild logger' do before do - parent_logger.with_fields = { tag: 'parent', tags: ['parent'] } + parent_logger.with_fields = { tag: 'parent', tags: ['parent'], event: { module: 'core' } } end - let(:logger) { parent_logger.child(tag: 'child', tags: ['child']) } - let(:grand_logger) { logger.child(tag: 'grandchild', tags: ['grandchild']) } + let(:logger) { parent_logger.child(tag: 'child', tags: ['child'], event: { dataset: 'core.child' }) } + let(:grand_logger) { logger.child(tag: 'grandchild', tags: ['grandchild'], event: { action: 'log-action' }) } it 'outputs with all merged fields' do grand_logger.info('Hi', foo: 3) logger.info(log_msg, foo: 2) - parent_logger.info(parent_log_msg, foo: 10) - parent_logger.info('Good evening!', foo: 11) + parent_logger.info(parent_log_msg, foo: 10, event: { module: 'service' }) + parent_logger.info('Good evening!', foo: 11, event: { duration: 150 }) expect(items[0]).to be_log_message('Hi', log_level) - expect(items[0]).to include(tag: 'grandchild', tags: ['parent', 'child', 'grandchild'], foo: 3) + expect(items[0]).to include( + tag: 'grandchild', + tags: ['parent', 'child', 'grandchild'], + foo: 3, + event: { module: 'core', dataset: 'core.child', action: 'log-action' } + ) expect(items[1]).to be_log_message(log_msg, log_level) - expect(items[1]).to include(tag: 'child', tags: ['parent', 'child'], foo: 2) + expect(items[1]).to include( + tag: 'child', + tags: ['parent', 'child'], + foo: 2, + event: { module: 'core', dataset: 'core.child' } + ) expect(items[2]).to be_log_message(parent_log_msg, log_level) - expect(items[2]).to include(tag: 'parent', tags: ['parent'], foo: 10) + expect(items[2]).to include(tag: 'parent', tags: ['parent'], foo: 10, event: { module: 'service' }) expect(items[3]).to be_log_message('Good evening!', log_level) - expect(items[3]).to include(tag: 'parent', tags: ['parent'], foo: 11) + expect(items[3]).to include(tag: 'parent', tags: ['parent'], foo: 11, event: { module: 'core', duration: 150 }) end context 'after updating child logger with_fields' do before do logger.with_fields = { bar: '33' } end - + it 'outputs with child fields' do logger.info(log_msg) expect(items[0]).to be_log_message(log_msg, log_level) diff --git a/spec/logging_spec.rb b/spec/logging_spec.rb index 3165333..5edc87b 100644 --- a/spec/logging_spec.rb +++ b/spec/logging_spec.rb @@ -24,6 +24,15 @@ def level expect(result[:bar]).to eq('base') expect(result[:baz]).to eq(['B', 'A']) end + + it 'merges hashes recursively' do + result = nil + subject.instance_eval do + result = weak_merge!({ foo: { bar: { baz: 15 } } }, + { foo: { bar: { extra: 10 }, nested: 'string' } }) + end + expect(result).to eq({ foo: { bar: { baz: 15, extra: 10 }, nested: 'string' } }) + end end describe '#chain' do