Skip to content

Commit 498a0c7

Browse files
authored
Merge pull request #21 from on-strum/develop
OnStrum::Logs v0.3.0
2 parents 22c157d + 93d9412 commit 498a0c7

File tree

15 files changed

+276
-40
lines changed

15 files changed

+276
-40
lines changed

.reek.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ detectors:
1313
exclude:
1414
- OnStrum::Logs::Configuration#valid_argument_type?
1515
- OnStrum::Logs::Logger::Default#configuration
16+
- OnStrum::Logs::Configuration#instance_initializer
1617

1718
FeatureEnvy:
1819
exclude:
@@ -22,5 +23,9 @@ detectors:
2223
exclude:
2324
- OnStrum::Logs::Configuration#detailed_formatter
2425

26+
TooManyStatements:
27+
exclude:
28+
- OnStrum::Logs::Logger::Default#hash_normalizer
29+
2530
exclude_paths:
2631
- spec/support/helpers

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,22 @@
22

33
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
44

5+
## [0.3.0] - 2024-03-10
6+
7+
### Added
8+
9+
- Added ability to configure builtin attribute key names
10+
11+
### Updated
12+
13+
- Updated `OnStrum::Logs::Configuration`, tests
14+
- Updated `OnStrum::Logs::Logger::Default`, tests
15+
- Updated `OnStrum::Logs::Formatter::Base`, tests
16+
- Updated `OnStrum::Logs::Formatter::Json`, tests
17+
- Updated `OnStrum::Logs::RspecHelper::Configuration`, tests
18+
- Updated `OnStrum::Logs::RspecHelper::ContextGenerator`, tests
19+
- Updated gem documentation
20+
521
## [0.2.0] - 2024-03-05
622

723
### Added

README.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ Simple configurable structured logger with `JSON` formatter out of the box.
3434

3535
- Structured `JSON` log
3636
- Built-in detailed (debug) formatter
37-
- Ability to configure required parameters
37+
- Ability to configure builtin attribute key names
38+
- Ability to configure required attributes
3839
- Ability to configure formatters
3940
- Ability to serialize an exceptions into structured log
4041

@@ -85,6 +86,30 @@ OnStrum::Logs.configure do |config|
8586
# Optional parameter. You can use your custom formatter insted of built-in.
8687
# Please note, using this option will override using detailed_formatter option.
8788
config.custom_formatter = YourCustomFormatter
89+
90+
# Optional parameter. You can override log level builtin attribute key.
91+
# It is equal to :level by default.
92+
config.field_name_level = :log_level
93+
94+
# Optional parameter. You can override log time builtin attribute key.
95+
# It is equal to :time by default.
96+
config.field_name_time = :log_time
97+
98+
# Optional parameter. You can override log message builtin attribute key.
99+
# It is equal to :message by default.
100+
config.field_name_message = :log_message
101+
102+
# Optional parameter. You can override log context builtin attribute key.
103+
# It is equal to :context by default.
104+
config.field_name_context = :log_context
105+
106+
# Optional parameter. You can override log exception message builtin attribute key.
107+
# It is equal to :message by default.
108+
config.field_name_exception_message = :log_exception_message
109+
110+
# Optional parameter. You can override log exception stack trace builtin attribute key.
111+
# It is equal to :stack_trace by default.
112+
config.field_name_exception_stack_trace = :log_exception_stack_trace
88113
end
89114
```
90115

lib/on_strum/logs/configuration.rb

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,24 @@ module OnStrum
44
module Logs
55
class Configuration
66
INCOMPLETE_CONFIG = 'service_name, service_version are required parameters'
7-
SETTERS = %i[custom_formatter service_name service_version].freeze
7+
SETTERS = %i[
8+
custom_formatter
9+
service_name
10+
service_version
11+
field_name_level
12+
field_name_time
13+
field_name_message
14+
field_name_context
15+
field_name_exception_message
16+
field_name_exception_stack_trace
17+
].freeze
18+
BUILTIN_FIELDS_DEFAULT_NAMES = %i[level time message context stack_trace].freeze
819

920
attr_reader(*OnStrum::Logs::Configuration::SETTERS)
1021
attr_accessor :detailed_formatter
1122

1223
def initialize(&block)
24+
instance_initializer.each { |instace_variable, value| instance_variable_set(:"@#{instace_variable}", value) }
1325
tap(&block) if block
1426
end
1527

@@ -28,12 +40,32 @@ def formatter
2840
custom_formatter || builded_formatter
2941
end
3042

43+
# TODO: hardcoded fields will be removed in next release
44+
def log_attributes_order
45+
@log_attributes_order ||= OnStrum::Logs::Configuration::SETTERS[3..6].map do |field_name_getter|
46+
public_send(field_name_getter)
47+
end + %i[service_name service_version]
48+
end
49+
3150
private
3251

52+
def instance_initializer
53+
message_key = OnStrum::Logs::Configuration::BUILTIN_FIELDS_DEFAULT_NAMES[2]
54+
{
55+
field_name_level: OnStrum::Logs::Configuration::BUILTIN_FIELDS_DEFAULT_NAMES[0],
56+
field_name_time: OnStrum::Logs::Configuration::BUILTIN_FIELDS_DEFAULT_NAMES[1],
57+
field_name_message: message_key,
58+
field_name_context: OnStrum::Logs::Configuration::BUILTIN_FIELDS_DEFAULT_NAMES[3],
59+
field_name_exception_message: message_key,
60+
field_name_exception_stack_trace: OnStrum::Logs::Configuration::BUILTIN_FIELDS_DEFAULT_NAMES[4]
61+
}
62+
end
63+
3364
def valid_argument_type?(method_name, argument)
3465
argument.is_a?(
3566
case method_name
3667
when :service_name, :service_version then ::String
68+
when *OnStrum::Logs::Configuration::SETTERS[3..-1] then ::Symbol
3769
when :custom_formatter then ::Class
3870
end
3971
)

lib/on_strum/logs/formatter/base.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@ module Logs
55
module Formatter
66
class Base
77
DATETIME_FORMAT = '%FT%T.%3N%:z'
8-
LOG_ATTRIBUTES_ORDER = %i[level time message context service_name service_version].freeze
98

109
def self.arrange_attrs(**log_data)
11-
OnStrum::Logs::Formatter::Base::LOG_ATTRIBUTES_ORDER.each_with_object({}) do |attribute, arranged_attrs|
10+
OnStrum::Logs.configuration.log_attributes_order.each_with_object({}) do |attribute, arranged_attrs|
1211
arranged_attrs[attribute] = log_data[attribute]
1312
end
1413
end

lib/on_strum/logs/formatter/json.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ module Formatter
66
class Json < Base
77
require 'json'
88

9-
def self.call(time:, **log_data)
9+
def self.call(**log_data)
10+
time_key = OnStrum::Logs.configuration.field_name_time
1011
json_log = arrange_attrs(
11-
time: time.strftime(OnStrum::Logs::Formatter::Base::DATETIME_FORMAT),
12-
**log_data
12+
**log_data,
13+
time_key => log_data[time_key].strftime(OnStrum::Logs::Formatter::Base::DATETIME_FORMAT)
1314
).to_json
1415

1516
"#{json_log}\n"

lib/on_strum/logs/logger/default.rb

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ def initialize
2020

2121
# TODO: we need to have ability to process log data before render it to STDOUT/STDERR
2222
# hash_normalizer(arg); after_callback.call(arg)
23-
logger.public_send(method_name, hash_normalizer(arg).merge(level: method_name.to_s.upcase))
23+
logger.public_send(
24+
method_name,
25+
hash_normalizer(arg).merge(configuration.field_name_level => method_name.to_s.upcase)
26+
)
2427
end
2528
end
2629

@@ -35,7 +38,7 @@ def configuration
3538
def formatter
3639
@formatter ||= proc do |_severity, datetime, _progname, log_data|
3740
configuration.formatter.call(
38-
time: datetime,
41+
configuration.field_name_time => datetime,
3942
service_name: configuration.service_name,
4043
service_version: configuration.service_version,
4144
**log_data
@@ -44,20 +47,22 @@ def formatter
4447
end
4548

4649
def hash_normalizer(object)
50+
message_key, context_key = configuration.field_name_message, configuration.field_name_context
51+
4752
case object
4853
when ::Hash
49-
raise OnStrum::Logs::Error::Logger unless object.key?(:message)
54+
raise OnStrum::Logs::Error::Logger unless object.key?(message_key)
5055

51-
{ message: object.delete(:message), context: (object.empty? ? nil : object) }
56+
{ message_key => object.delete(message_key), context_key => (object.empty? ? nil : object) }
5257
when ::Exception
5358
{
54-
message: "Exception: #{object.class}",
55-
context: {
56-
message: object.message,
57-
stack_trace: object.backtrace
59+
message_key => "Exception: #{object.class}",
60+
context_key => {
61+
configuration.field_name_exception_message => object.message,
62+
configuration.field_name_exception_stack_trace => object.backtrace
5863
}
5964
}
60-
else { message: object.to_s, context: nil }
65+
else { message_key => object.to_s, context_key => nil }
6166
end
6267
end
6368
end

lib/on_strum/logs/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
module OnStrum
44
module Logs
5-
VERSION = '0.2.0'
5+
VERSION = '0.3.0'
66
end
77
end

spec/on_strum/logs/configuration_spec.rb

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,34 @@
44
describe 'defined constants' do
55
it { expect(described_class).to be_const_defined(:INCOMPLETE_CONFIG) }
66
it { expect(described_class).to be_const_defined(:SETTERS) }
7+
it { expect(described_class).to be_const_defined(:BUILTIN_FIELDS_DEFAULT_NAMES) }
78
end
89

910
describe '.new' do
1011
let(:custom_formatter) { use_formatter(:custom) }
1112
let(:detailed_formatter) { true }
1213
let(:service_name) { random_service_name }
1314
let(:service_version) { random_semver }
15+
let(:field_name_level) { random_field_name }
16+
let(:field_name_time) { random_field_name }
17+
let(:field_name_message) { random_field_name }
18+
let(:field_name_context) { random_field_name }
19+
let(:field_name_exception_message) { random_field_name }
20+
let(:field_name_exception_stack_trace) { random_field_name }
1421

1522
context 'when valid configuration' do
1623
subject(:configuration) do
1724
create_configuration(
1825
custom_formatter: custom_formatter,
1926
detailed_formatter: detailed_formatter,
2027
service_name: service_name,
21-
service_version: service_version
28+
service_version: service_version,
29+
field_name_level: field_name_level,
30+
field_name_time: field_name_time,
31+
field_name_message: field_name_message,
32+
field_name_context: field_name_context,
33+
field_name_exception_message: field_name_exception_message,
34+
field_name_exception_stack_trace: field_name_exception_stack_trace
2235
)
2336
end
2437

@@ -27,6 +40,12 @@
2740
expect(configuration.detailed_formatter).to eq(detailed_formatter)
2841
expect(configuration.service_name).to eq(service_name)
2942
expect(configuration.service_version).to eq(service_version)
43+
expect(configuration.field_name_level).to eq(field_name_level)
44+
expect(configuration.field_name_time).to eq(field_name_time)
45+
expect(configuration.field_name_message).to eq(field_name_message)
46+
expect(configuration.field_name_context).to eq(field_name_context)
47+
expect(configuration.field_name_exception_message).to eq(field_name_exception_message)
48+
expect(configuration.field_name_exception_stack_trace).to eq(field_name_exception_stack_trace)
3049
expect(configuration).to be_complete
3150
end
3251
end
@@ -76,6 +95,22 @@
7695

7796
include_examples 'raies argument error'
7897
end
98+
99+
OnStrum::Logs::Configuration::SETTERS[3..-1].each do |field_name_setter|
100+
context "when argument #{field_name_setter}= invalid" do
101+
subject(:configuration) do
102+
create_configuration(
103+
service_name: random_service_name,
104+
service_version: random_semver,
105+
field_name_setter => invalid_argument
106+
)
107+
end
108+
109+
let(:expected_error_message) { "#{invalid_argument} is not a valid #{field_name_setter}=" }
110+
111+
include_examples 'raies argument error'
112+
end
113+
end
79114
end
80115

81116
context 'when configuration without block' do
@@ -85,6 +120,12 @@
85120
expect(configuration.service_name).to be_nil
86121
expect(configuration.service_version).to be_nil
87122
expect(configuration.custom_formatter).to be_nil
123+
expect(configuration.field_name_level).to eq(:level)
124+
expect(configuration.field_name_time).to eq(:time)
125+
expect(configuration.field_name_message).to eq(:message)
126+
expect(configuration.field_name_context).to eq(:context)
127+
expect(configuration.field_name_exception_message).to eq(:message)
128+
expect(configuration.field_name_exception_stack_trace).to eq(:stack_trace)
88129
expect(configuration.detailed_formatter).to be_nil
89130
expect(configuration).not_to be_complete
90131
end
@@ -156,4 +197,30 @@
156197
include_examples 'returns target formatter'
157198
end
158199
end
200+
201+
describe '#log_attributes_order' do
202+
subject(:log_attributes_order) { configuration_instance.log_attributes_order }
203+
204+
let(:configuration_instance) do
205+
create_configuration(
206+
field_name_level: random_field_name,
207+
field_name_time: random_field_name,
208+
field_name_message: random_field_name,
209+
field_name_context: random_field_name
210+
)
211+
end
212+
213+
it 'returns log attributes order' do
214+
expect(log_attributes_order).to eq(
215+
[
216+
configuration_instance.field_name_level,
217+
configuration_instance.field_name_time,
218+
configuration_instance.field_name_message,
219+
configuration_instance.field_name_context,
220+
:service_name,
221+
:service_version
222+
]
223+
)
224+
end
225+
end
159226
end

spec/on_strum/logs/formatter/base_spec.rb

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,24 @@
33
RSpec.describe OnStrum::Logs::Formatter::Base do
44
describe 'defined constants' do
55
it { expect(described_class).to be_const_defined(:DATETIME_FORMAT) }
6-
it { expect(described_class).to be_const_defined(:LOG_ATTRIBUTES_ORDER) }
76
end
87

98
describe '.arrange_attrs' do
109
subject(:arrange_attrs) { described_class.arrange_attrs(**log_data) }
1110

11+
let!(:configuration_instance) do
12+
init_configuration(
13+
field_name_level: field_name_level,
14+
field_name_time: field_name_time,
15+
field_name_message: field_name_message,
16+
field_name_context: field_name_context
17+
)
18+
end
19+
20+
let(:field_name_level) { :a }
21+
let(:field_name_time) { :b }
22+
let(:field_name_message) { :c }
23+
let(:field_name_context) { :d }
1224
let(:level) { random_log_level }
1325
let(:time) { random_datetime }
1426
let(:message) { random_message }
@@ -17,17 +29,17 @@
1729
let(:service_version) { random_semver }
1830
let(:log_data) do
1931
[
20-
[:level, level],
21-
[:time, time],
32+
[field_name_level, level],
33+
[field_name_time, time],
2234
[:service_name, service_name],
2335
[:service_version, service_version],
24-
[:message, message],
25-
[:context, context]
36+
[field_name_message, message],
37+
[field_name_context, context]
2638
].shuffle.to_h
2739
end
2840

2941
it 'arranges log data by predefined order' do
30-
expect(arrange_attrs.keys).to eq(described_class::LOG_ATTRIBUTES_ORDER)
42+
expect(arrange_attrs.keys).to eq(configuration_instance.log_attributes_order)
3143
end
3244
end
3345
end

0 commit comments

Comments
 (0)