cogger 2.2.0 → 2.4.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
- checksums.yaml.gz.sig +0 -0
- data/README.adoc +91 -16
- data/cogger.gemspec +2 -2
- data/lib/cogger/entry.rb +1 -1
- data/lib/cogger/formatters/json.rb +2 -1
- data/lib/cogger/formatters/property.rb +2 -1
- data/lib/cogger/formatters/sanitizers/escape.rb +1 -1
- data/lib/cogger/hub.rb +9 -8
- data/lib/cogger/tag.rb +19 -9
- data.tar.gz.sig +0 -0
- metadata +4 -4
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d3dd4c51c4410b817ca889b3c06abf51fcab7e6e91f5746caed31d1bf45f3eb7
|
|
4
|
+
data.tar.gz: aa1f55995d710f2147071f4eaf9709e625c1fdd809d255860a3113ea6d742064
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 61b318f30b68581323296d09159df52721d5a4e7554ada7d7d6ac09416016d26dee20b83630aa708ddc1b02e43966ab0e1e98b3fb08c2243a769a840a7853f04
|
|
7
|
+
data.tar.gz: 4731b4c644c505603098c41b0f0ca5a3aa81b0d81c175dfe37c914cdbb5b06fb57619f4f1f154007dfafb331263262646ae50338db9eff930084b78072697209
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/README.adoc
CHANGED
|
@@ -142,6 +142,34 @@ logger = Cogger.new id: :demo,
|
|
|
142
142
|
suffix: "%Y"
|
|
143
143
|
----
|
|
144
144
|
|
|
145
|
+
=== Identity
|
|
146
|
+
|
|
147
|
+
Your logger's identity defaults to `$PROGRAM_NAME` -- as mentioned earlier -- but can be customized during initialization. Example:
|
|
148
|
+
|
|
149
|
+
[source,ruby]
|
|
150
|
+
----
|
|
151
|
+
logger = Cogger.new id: :demo
|
|
152
|
+
logger.info "A demonstration."
|
|
153
|
+
|
|
154
|
+
# 🟢 [demo] A demonstration.
|
|
155
|
+
----
|
|
156
|
+
|
|
157
|
+
You can also customize the identity by passing in an ID per log entry. Example:
|
|
158
|
+
|
|
159
|
+
[source,ruby]
|
|
160
|
+
----
|
|
161
|
+
logger = Cogger.new
|
|
162
|
+
|
|
163
|
+
logger.info "A demonstration.", id: :other
|
|
164
|
+
# 🟢 [other] A demonstration.
|
|
165
|
+
|
|
166
|
+
logger.info(id: :other) { "A demonstration." }
|
|
167
|
+
# 🟢 [other] A demonstration.
|
|
168
|
+
|
|
169
|
+
logger.info { {id: :other, message: "A demonstration."} }
|
|
170
|
+
# 🟢 [other] A demonstration.
|
|
171
|
+
----
|
|
172
|
+
|
|
145
173
|
=== Levels
|
|
146
174
|
|
|
147
175
|
Supported levels can be obtained via `Cogger::LEVELS`. Example:
|
|
@@ -165,7 +193,26 @@ The above adheres to {rfc_3339_link} and can be customized -- as mentioned earli
|
|
|
165
193
|
|
|
166
194
|
[source,ruby]
|
|
167
195
|
----
|
|
168
|
-
Cogger.new datetime_format: "%Y-%m-%d"
|
|
196
|
+
logger = Cogger.new formatter: :json, datetime_format: "%Y-%m-%d"
|
|
197
|
+
logger.info "A demonstration."
|
|
198
|
+
|
|
199
|
+
# {"id":"console","level":"INFO","at":"2026-06-28","message":"A demonstration."}
|
|
200
|
+
----
|
|
201
|
+
|
|
202
|
+
You can also customize the date/time format by passing in an date/time format per log entry. Example:
|
|
203
|
+
|
|
204
|
+
[source,ruby]
|
|
205
|
+
----
|
|
206
|
+
logger = Cogger.new formatter: :json
|
|
207
|
+
|
|
208
|
+
logger.info "A demonstration.", datetime_format: "%Y-%m-%d"
|
|
209
|
+
# {"id":"console","level":"INFO","at":"2026-06-28","message":"A demonstration."}
|
|
210
|
+
|
|
211
|
+
logger.info(datetime_format: "%Y-%m-%d") { "A demonstration." }
|
|
212
|
+
# {"id":"console","level":"INFO","at":"2026-06-28","message":"A demonstration."}
|
|
213
|
+
|
|
214
|
+
logger.info { {datetime_format: "%Y-%m-%d", message: "A demonstration."} }
|
|
215
|
+
# {"id":"console","level":"INFO","at":"2026-06-28","message":"A demonstration."}
|
|
169
216
|
----
|
|
170
217
|
|
|
171
218
|
=== Environment
|
|
@@ -182,7 +229,7 @@ export LOG_LEVEL=fatal
|
|
|
182
229
|
export LOG_LEVEL=unknown
|
|
183
230
|
----
|
|
184
231
|
|
|
185
|
-
While
|
|
232
|
+
While lower case is preferred for each log level value, you can use upper case values as well. If the `LOG_LEVEL` environment variable is not set, `Cogger` will fall back to `"info"` unless overwritten during initialization. Example: `Cogger.new level: :debug`. Otherwise, an invalid log level will result in an `ArgumentError`.
|
|
186
233
|
|
|
187
234
|
=== Mutations
|
|
188
235
|
|
|
@@ -457,7 +504,7 @@ Additional keys as provided by your message hash and/or tags can be customized a
|
|
|
457
504
|
Template keys, emojis, and elements do have a few restrictions:
|
|
458
505
|
|
|
459
506
|
* Use the special `emoji` key to provide dynamic or specific emoji logging.
|
|
460
|
-
* Use the special `tags` key to provide tagged logging.
|
|
507
|
+
* Use the special `tags` key to provide tagged logging. For more information, the _Tags_ section below.
|
|
461
508
|
* Avoid supplying the same keys as the default keys. Example: `logger.info id: :bad, at: Time.now, level: :bogus`. This is because these keys will be ignored. In other words, you can't _override_ the default keys.
|
|
462
509
|
* Avoid wrapping keys and/or emojis in elements because nesting isn't supported and can lead to strange output. Example: `<green>%<emoji:error>s %<id:dynamic>s</green>`.
|
|
463
510
|
* Avoid wrapping elements within elements because nesting isn't supported and can lead to strange output. Example: `<dynamic><cyan>%<message>s</cyan></dynamic>`.
|
|
@@ -757,8 +804,7 @@ logger.info "Demo", tags: ["WEB", "PRIMARY", {service: :api, demo: true}]
|
|
|
757
804
|
# "level":"INFO",
|
|
758
805
|
# "at":"2023-12-10T18:44:32.723+00:00",
|
|
759
806
|
# "message":"Demo",
|
|
760
|
-
# "tags":["WEB",
|
|
761
|
-
# "PRIMARY"],
|
|
807
|
+
# "tags":["WEB", "PRIMARY"],
|
|
762
808
|
# "service":"api",
|
|
763
809
|
# "demo":true
|
|
764
810
|
# }
|
|
@@ -877,7 +923,7 @@ Tags allow you to tag your messages at both a global and local (i.e. per message
|
|
|
877
923
|
logger = Cogger.new tags: %w[WEB]
|
|
878
924
|
logger.info "Demo"
|
|
879
925
|
|
|
880
|
-
# 🟢 [console] [WEB] Demo
|
|
926
|
+
# 🟢 [console] ["WEB"] Demo
|
|
881
927
|
----
|
|
882
928
|
|
|
883
929
|
You can use multiple tags as well:
|
|
@@ -887,7 +933,7 @@ You can use multiple tags as well:
|
|
|
887
933
|
logger = Cogger.new tags: %w[WEB EXAMPLE]
|
|
888
934
|
logger.info "Demo"
|
|
889
935
|
|
|
890
|
-
# 🟢 [console] [WEB] [EXAMPLE] Demo
|
|
936
|
+
# 🟢 [console] ["WEB"] ["EXAMPLE"] Demo
|
|
891
937
|
----
|
|
892
938
|
|
|
893
939
|
You are not limited to string-based tags. Any object will work:
|
|
@@ -897,7 +943,7 @@ You are not limited to string-based tags. Any object will work:
|
|
|
897
943
|
logger = Cogger.new tags: ["ONE", :two, 3, {four: "FOUR"}, proc { "FIVE" }]
|
|
898
944
|
logger.info "Demo"
|
|
899
945
|
|
|
900
|
-
# 🟢 [console] [ONE] [two] [3] [FIVE] [four=FOUR] Demo
|
|
946
|
+
# 🟢 [console] ["ONE"] [:two] [3] ["FIVE"] [four="FOUR"] Demo
|
|
901
947
|
----
|
|
902
948
|
|
|
903
949
|
With the above, we have string, symbol, integer, hash, and proc tags. With hashes, you'll always get a the key/value pair formatted as: `key=value`. Procs/lambdas allow you to lazy evaluate your tag at time of logging which provides a powerful way to acquire the current process ID, thread ID, and so forth.
|
|
@@ -909,7 +955,7 @@ In addition to global tags, you can use local tags per log message. Example:
|
|
|
909
955
|
logger = Cogger.new
|
|
910
956
|
logger.info "Demo", tags: ["ONE", :two, 3, {four: "FOUR"}, proc { "FIVE" }]
|
|
911
957
|
|
|
912
|
-
# 🟢 [console] [ONE] [two] [3] [FIVE] [four=FOUR] Demo
|
|
958
|
+
# 🟢 [console] ["ONE"] [:two] [3] ["FIVE"] [four="FOUR"] Demo
|
|
913
959
|
----
|
|
914
960
|
|
|
915
961
|
You can also combine global and local tags:
|
|
@@ -919,16 +965,34 @@ You can also combine global and local tags:
|
|
|
919
965
|
logger = Cogger.new tags: ["ONE", :two]
|
|
920
966
|
logger.info "Demo", tags: [3, proc { "FOUR" }]
|
|
921
967
|
|
|
922
|
-
# 🟢 [console] [ONE] [two] [3] [FOUR] Demo
|
|
968
|
+
# 🟢 [console] ["ONE"] [:two] [3] ["FOUR"] Demo
|
|
969
|
+
----
|
|
970
|
+
|
|
971
|
+
When using blocks, use a hash inside the block instead of supplying the tags before using the block. Example:
|
|
972
|
+
|
|
973
|
+
[source,ruby]
|
|
974
|
+
----
|
|
975
|
+
logger = Cogger.new level: :debug
|
|
976
|
+
|
|
977
|
+
# No
|
|
978
|
+
logger.debug(tags: ["ONE", :TWO]) { "Demo" }
|
|
979
|
+
🔎 [console] ["ONE"] [:TWO] Demo
|
|
980
|
+
|
|
981
|
+
# Yes
|
|
982
|
+
logger.debug { {tags: ["ONE", :TWO], message: "Demo"} }
|
|
983
|
+
🔎 [console] ["ONE"] [:TWO] Demo
|
|
923
984
|
----
|
|
924
985
|
|
|
986
|
+
This ensures your tags and associated message are only evaluated when the correct log level is accepted. This is especially important when dealing with tags that need additional evaluation like procs because you'll improve performance when the debug log level, in this example, isn't set.
|
|
987
|
+
|
|
925
988
|
As you can see, tags are highly versatile. That said, the following guidelines are worth consideration when using them:
|
|
926
989
|
|
|
927
|
-
* Prefer uppercase
|
|
928
|
-
* Prefer short
|
|
929
|
-
* Prefer consistent
|
|
930
|
-
* Prefer
|
|
931
|
-
* Prefer the JSON formatter for structured metadata instead of tags. Logging JSON formatted messages with tags will work but sticking with a traditional hash, instead of tags, will
|
|
990
|
+
* Prefer uppercase tags to make them visually stand out.
|
|
991
|
+
* Prefer short tags, ideally 1-4 characters since long tags defeat the purpose of brevity.
|
|
992
|
+
* Prefer consistent tags by using tags that are not synonymous or ambiguous.
|
|
993
|
+
* Prefer feature tags instead of environment tags. Examples: API, DB, MAILER.
|
|
994
|
+
* Prefer the JSON formatter for structured metadata instead of tags. Logging JSON formatted messages with tags will work but sticking with a traditional hash, instead of tags, will serve you better.
|
|
995
|
+
* Avoid using `id`, `level`, `at`, and/or `message` as hash keys since those are reserved keys and will be rejected if supplied.
|
|
932
996
|
|
|
933
997
|
=== Filters
|
|
934
998
|
|
|
@@ -970,14 +1034,25 @@ You can add multiple log streams (outputs) by using:
|
|
|
970
1034
|
|
|
971
1035
|
[source,ruby]
|
|
972
1036
|
----
|
|
1037
|
+
require "stringio"
|
|
1038
|
+
|
|
1039
|
+
buffer = StringIO.new
|
|
973
1040
|
logger = Cogger.new
|
|
1041
|
+
.add_stream(io: buffer)
|
|
974
1042
|
.add_stream(io: "tmp/demo.log")
|
|
975
1043
|
.add_stream(io: nil)
|
|
976
1044
|
|
|
977
1045
|
logger.info "Demo."
|
|
978
1046
|
----
|
|
979
1047
|
|
|
980
|
-
The above would log
|
|
1048
|
+
The above would log `"Demo."` to:
|
|
1049
|
+
|
|
1050
|
+
* To `$stdout` (the default stream which is your console).
|
|
1051
|
+
* To the StringIO `buffer` where you can use `buffer.string` to view content.
|
|
1052
|
+
* To the `tmp/demo.log` file where you can use `cat tmp/demo.log` to view content.
|
|
1053
|
+
* To `/dev/null` which immediately ignores all writes.
|
|
1054
|
+
|
|
1055
|
+
All attributes used to construct your default logger apply to all additional streams unless customized further. This means any custom template/formatter can be applied to your streams. Example:
|
|
981
1056
|
|
|
982
1057
|
[source,ruby]
|
|
983
1058
|
----
|
data/cogger.gemspec
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Gem::Specification.new do |spec|
|
|
4
4
|
spec.name = "cogger"
|
|
5
|
-
spec.version = "2.
|
|
5
|
+
spec.version = "2.4.0"
|
|
6
6
|
spec.authors = ["Brooke Kuhlmann"]
|
|
7
7
|
spec.email = ["brooke@alchemists.io"]
|
|
8
8
|
spec.homepage = "https://alchemists.io/projects/cogger"
|
|
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
|
|
|
28
28
|
spec.add_dependency "logger", "~> 1.7"
|
|
29
29
|
spec.add_dependency "refinements", "~> 14.0"
|
|
30
30
|
spec.add_dependency "tone", "~> 3.0"
|
|
31
|
-
spec.add_dependency "zeitwerk", "~> 2.
|
|
31
|
+
spec.add_dependency "zeitwerk", "~> 2.8"
|
|
32
32
|
|
|
33
33
|
spec.extra_rdoc_files = Dir["README*", "LICENSE*"]
|
|
34
34
|
spec.files = Dir["*.gemspec", "lib/**/*"]
|
data/lib/cogger/entry.rb
CHANGED
|
@@ -17,7 +17,8 @@ module Cogger
|
|
|
17
17
|
|
|
18
18
|
def call(*input)
|
|
19
19
|
*, entry = input
|
|
20
|
-
attributes = sanitize
|
|
20
|
+
attributes = sanitize entry, :tagged_attributes
|
|
21
|
+
attributes.delete :message unless attributes[:message]
|
|
21
22
|
|
|
22
23
|
parser.call(template, attributes).to_json << NEW_LINE
|
|
23
24
|
end
|
|
@@ -16,7 +16,8 @@ module Cogger
|
|
|
16
16
|
|
|
17
17
|
def call(*input)
|
|
18
18
|
*, entry = input
|
|
19
|
-
attributes = sanitize
|
|
19
|
+
attributes = sanitize entry, :tagged_attributes
|
|
20
|
+
attributes.delete :message unless attributes[:message]
|
|
20
21
|
|
|
21
22
|
concat(attributes).chop! << NEW_LINE
|
|
22
23
|
end
|
data/lib/cogger/hub.rb
CHANGED
|
@@ -101,22 +101,23 @@ module Cogger
|
|
|
101
101
|
crash message, error
|
|
102
102
|
end
|
|
103
103
|
|
|
104
|
-
# rubocop:todo Metrics/MethodLength
|
|
105
104
|
def dispatch(level, message, **payload, &)
|
|
106
|
-
entry =
|
|
105
|
+
entry = build_entry(level, message, payload, &)
|
|
106
|
+
configuration.mutex.synchronize { streams.each { |logger| logger.public_send level, entry } }
|
|
107
|
+
true
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def build_entry(level, message, payload, &)
|
|
111
|
+
configuration.entry.for(
|
|
107
112
|
message,
|
|
108
113
|
id: configuration.id,
|
|
109
114
|
level:,
|
|
110
|
-
tags: configuration.entag(payload
|
|
115
|
+
tags: configuration.entag(payload[:tags]),
|
|
111
116
|
datetime_format: configuration.datetime_format,
|
|
112
|
-
**payload,
|
|
117
|
+
**payload.except(:level, :at, :tags),
|
|
113
118
|
&
|
|
114
119
|
)
|
|
115
|
-
|
|
116
|
-
configuration.mutex.synchronize { streams.each { |logger| logger.public_send level, entry } }
|
|
117
|
-
true
|
|
118
120
|
end
|
|
119
|
-
# rubocop:enable Metrics/MethodLength
|
|
120
121
|
|
|
121
122
|
def crash message, error
|
|
122
123
|
configuration.with(id: :cogger, io: $stdout, formatter: Formatters::Crash.new)
|
data/lib/cogger/tag.rb
CHANGED
|
@@ -5,35 +5,45 @@ require "refinements/hash"
|
|
|
5
5
|
|
|
6
6
|
module Cogger
|
|
7
7
|
# Models a tag which may consist of an array and/or hash.
|
|
8
|
-
Tag = Data.define :singles, :pairs do
|
|
8
|
+
Tag = Data.define :singles, :pairs, :exclusions do
|
|
9
9
|
using Refinements::Hash
|
|
10
10
|
|
|
11
|
-
def self.for(*bag)
|
|
12
|
-
|
|
11
|
+
def self.for(*bag) = new(**reduce(bag))
|
|
12
|
+
|
|
13
|
+
def self.reduce bag
|
|
14
|
+
bag.each.with_object({singles: [], pairs: {}}) do |item, all|
|
|
13
15
|
value = item.is_a?(Proc) ? item.call : item
|
|
14
|
-
value.is_a?(Hash) ?
|
|
16
|
+
value.is_a?(Hash) ? all[:pairs].merge!(value) : all[:singles].append(value)
|
|
15
17
|
end
|
|
16
18
|
end
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
private_class_method :reduce
|
|
21
|
+
|
|
22
|
+
def initialize singles: [], pairs: {}, exclusions: %w[id level at message]
|
|
23
|
+
filtered_pairs = pairs.reject { |key, _| exclusions.include? key.to_s }
|
|
24
|
+
|
|
25
|
+
super singles:, pairs: filtered_pairs, exclusions:
|
|
20
26
|
end
|
|
21
27
|
|
|
22
28
|
def empty? = singles.empty? && pairs.empty?
|
|
23
29
|
|
|
24
|
-
def to_h
|
|
30
|
+
def to_h
|
|
31
|
+
return Core::EMPTY_HASH if empty?
|
|
32
|
+
|
|
33
|
+
singles.empty? ? pairs : {tags: singles.to_a, **pairs}
|
|
34
|
+
end
|
|
25
35
|
|
|
26
36
|
def to_s = empty? ? Core::EMPTY_STRING : "#{format_singles} #{format_pairs}".tap(&:strip!)
|
|
27
37
|
|
|
28
38
|
private
|
|
29
39
|
|
|
30
40
|
def format_singles
|
|
31
|
-
singles.map { |value| "[#{value}]" }
|
|
41
|
+
singles.map { |value| "[#{value.inspect}]" }
|
|
32
42
|
.join " "
|
|
33
43
|
end
|
|
34
44
|
|
|
35
45
|
def format_pairs
|
|
36
|
-
pairs.map { |key, value| "[#{key}=#{value}]" }
|
|
46
|
+
pairs.map { |key, value| "[#{key}=#{value.inspect}]" }
|
|
37
47
|
.join(" ")
|
|
38
48
|
end
|
|
39
49
|
end
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cogger
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Brooke Kuhlmann
|
|
@@ -97,14 +97,14 @@ dependencies:
|
|
|
97
97
|
requirements:
|
|
98
98
|
- - "~>"
|
|
99
99
|
- !ruby/object:Gem::Version
|
|
100
|
-
version: '2.
|
|
100
|
+
version: '2.8'
|
|
101
101
|
type: :runtime
|
|
102
102
|
prerelease: false
|
|
103
103
|
version_requirements: !ruby/object:Gem::Requirement
|
|
104
104
|
requirements:
|
|
105
105
|
- - "~>"
|
|
106
106
|
- !ruby/object:Gem::Version
|
|
107
|
-
version: '2.
|
|
107
|
+
version: '2.8'
|
|
108
108
|
email:
|
|
109
109
|
- brooke@alchemists.io
|
|
110
110
|
executables: []
|
|
@@ -175,7 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
175
175
|
- !ruby/object:Gem::Version
|
|
176
176
|
version: '0'
|
|
177
177
|
requirements: []
|
|
178
|
-
rubygems_version: 4.0.
|
|
178
|
+
rubygems_version: 4.0.15
|
|
179
179
|
specification_version: 4
|
|
180
180
|
summary: A customizable and feature rich logger.
|
|
181
181
|
test_files: []
|
metadata.gz.sig
CHANGED
|
Binary file
|