cogger 2.3.0 → 2.5.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
  SHA256:
3
- metadata.gz: 051cbeb63381e6680f86fd1b73a1e6648d6ecc1befc37824d0425cbb12d0fb63
4
- data.tar.gz: 8772b28a29157d2f023096eaf40ba28c252888e3430e5ddc673ade49888b7da2
3
+ metadata.gz: 394c25bd5359cd226784df811d32eca048dbef8aac78e886009259c3ceb5ab7c
4
+ data.tar.gz: 6f803583d161c300ac94ab8ca9b2d8187d17b2e389c23a9883cf3fe827cd5bbc
5
5
  SHA512:
6
- metadata.gz: 4b290ebea636e3744c68dd07c1cd37bd310fa3c99600a8b7a32ed93dcdcc651559ff718fcfe43446c7bad91772ba25eb4bb60bfe0ff9f2c6f85d8158dc58c9c1
7
- data.tar.gz: 163afc50ba9118ab76f2ff75f351b4d2b60992b29f317bbfab218e310ada42890fec1e5cfed6993bde0421d67126b65038adbe7b81791f062c07ae82e32c3143
6
+ metadata.gz: cab259078b7c9e07de8091cbe94a1f890a704dda85dedda0201293b9e2c3d50c357ceafb6d1d6723aae56e1923088fc1be7ae81ae5304f13d6723c6ffb5a8420
7
+ data.tar.gz: 1ecb68b40b4daa2e56ed50b43f1952cdcb5b4d99ffc7b3990809be0e86321baffb7cc30119afef60bcc373c9df086fc71e035a9bbeba598d0feb864d98c620ce
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
@@ -192,18 +239,25 @@ Each instance can be mutated using the following messages:
192
239
  ----
193
240
  logger = Cogger.new io: StringIO.new
194
241
 
195
- logger.close # nil
196
- logger.reopen # Logger
197
- logger.debug! # 0
198
- logger.info! # 1
199
- logger.warn! # 2
200
- logger.error! # 3
201
- logger.fatal! # 4
202
- logger.formatter = Cogger::Formatters::Simple.new # Cogger::Formatters::Simple
203
- logger.level = Logger::WARN # 2
242
+ logger.close # nil
243
+ logger.reopen # Logger
244
+ logger.debug! # 0
245
+ logger.info! # 1
246
+ logger.warn! # 2
247
+ logger.error! # 3
248
+ logger.fatal! # 4
249
+ logger.formatter = :simple # :simple
250
+ logger.level = Logger::WARN # 2
204
251
  ----
205
252
 
206
- Please see the {logger_link} documentation for more information.
253
+ When setting the formatter, you can use a string, symbol, or instance. For example, the following are identical:
254
+
255
+ [source,ruby]
256
+ ----
257
+ logger.formatter = "simple"
258
+ logger.formatter = :simple
259
+ logger.formatter = Cogger::Formatters::Simple.new
260
+ ----
207
261
 
208
262
  === Emojis
209
263
 
@@ -876,7 +930,7 @@ Tags allow you to tag your messages at both a global and local (i.e. per message
876
930
  logger = Cogger.new tags: %w[WEB]
877
931
  logger.info "Demo"
878
932
 
879
- # 🟢 [console] [WEB] Demo
933
+ # 🟢 [console] ["WEB"] Demo
880
934
  ----
881
935
 
882
936
  You can use multiple tags as well:
@@ -886,7 +940,7 @@ You can use multiple tags as well:
886
940
  logger = Cogger.new tags: %w[WEB EXAMPLE]
887
941
  logger.info "Demo"
888
942
 
889
- # 🟢 [console] [WEB] [EXAMPLE] Demo
943
+ # 🟢 [console] ["WEB"] ["EXAMPLE"] Demo
890
944
  ----
891
945
 
892
946
  You are not limited to string-based tags. Any object will work:
@@ -896,7 +950,7 @@ You are not limited to string-based tags. Any object will work:
896
950
  logger = Cogger.new tags: ["ONE", :two, 3, {four: "FOUR"}, proc { "FIVE" }]
897
951
  logger.info "Demo"
898
952
 
899
- # 🟢 [console] [ONE] [two] [3] [FIVE] [four=FOUR] Demo
953
+ # 🟢 [console] ["ONE"] [:two] [3] ["FIVE"] [four="FOUR"] Demo
900
954
  ----
901
955
 
902
956
  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.
@@ -908,7 +962,7 @@ In addition to global tags, you can use local tags per log message. Example:
908
962
  logger = Cogger.new
909
963
  logger.info "Demo", tags: ["ONE", :two, 3, {four: "FOUR"}, proc { "FIVE" }]
910
964
 
911
- # 🟢 [console] [ONE] [two] [3] [FIVE] [four=FOUR] Demo
965
+ # 🟢 [console] ["ONE"] [:two] [3] ["FIVE"] [four="FOUR"] Demo
912
966
  ----
913
967
 
914
968
  You can also combine global and local tags:
@@ -918,16 +972,33 @@ You can also combine global and local tags:
918
972
  logger = Cogger.new tags: ["ONE", :two]
919
973
  logger.info "Demo", tags: [3, proc { "FOUR" }]
920
974
 
921
- # 🟢 [console] [ONE] [two] [3] [FOUR] Demo
975
+ # 🟢 [console] ["ONE"] [:two] [3] ["FOUR"] Demo
922
976
  ----
923
977
 
978
+ When using blocks, use a hash inside the block instead of supplying the tags before using the block. Example:
979
+
980
+ [source,ruby]
981
+ ----
982
+ logger = Cogger.new level: :debug
983
+
984
+ # No
985
+ logger.debug(tags: ["ONE", :TWO]) { "Demo" }
986
+ 🔎 [console] ["ONE"] [:TWO] Demo
987
+
988
+ # Yes
989
+ logger.debug { {tags: ["ONE", :TWO], message: "Demo"} }
990
+ 🔎 [console] ["ONE"] [:TWO] Demo
991
+ ----
992
+
993
+ 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.
994
+
924
995
  As you can see, tags are highly versatile. That said, the following guidelines are worth consideration when using them:
925
996
 
926
- * Prefer uppercase tag names to make them visually stand out.
927
- * Prefer short names, ideally 1-4 characters since long tags defeat the purpose of brevity.
928
- * Prefer consistent tag names by using tags that are not synonymous or ambiguous.
929
- * Prefer using tags by feature rather than things like environments. Examples: API, DB, MAILER.
930
- * 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 probably serve you better.
997
+ * Prefer uppercase tags to make them visually stand out.
998
+ * Prefer short tags, ideally 1-4 characters since long tags defeat the purpose of brevity.
999
+ * Prefer consistent tags by using tags that are not synonymous or ambiguous.
1000
+ * Prefer feature tags instead of environment tags. Examples: API, DB, MAILER.
1001
+ * 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.
931
1002
  * Avoid using `id`, `level`, `at`, and/or `message` as hash keys since those are reserved keys and will be rejected if supplied.
932
1003
 
933
1004
  === Filters
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.3.0"
5
+ spec.version = "2.5.0"
6
6
  spec.authors = ["Brooke Kuhlmann"]
7
7
  spec.email = ["brooke@alchemists.io"]
8
8
  spec.homepage = "https://alchemists.io/projects/cogger"
data/lib/cogger/entry.rb CHANGED
@@ -30,7 +30,7 @@ module Cogger
30
30
 
31
31
  def self.sanitize! content, payload
32
32
  body = if content.is_a? Hash
33
- content.delete(:message).tap { payload.merge! content }
33
+ content.delete(:message).tap { payload.merge! content.except(:level, :at) }
34
34
  else
35
35
  content
36
36
  end
@@ -12,7 +12,7 @@ module Cogger
12
12
  @parser = parser
13
13
  end
14
14
 
15
- def call(*input)
15
+ def call *input
16
16
  *, entry = input
17
17
  attributes = sanitize entry, :tagged
18
18
 
@@ -17,7 +17,7 @@ module Cogger
17
17
  @parser = parser
18
18
  end
19
19
 
20
- def call(*input)
20
+ def call *input
21
21
  *, entry = input
22
22
  attributes = sanitize entry, :tagged
23
23
  attributes[:backtrace] = %( #{attributes[:backtrace].join "\n "})
@@ -15,9 +15,10 @@ module Cogger
15
15
  @parser = parser
16
16
  end
17
17
 
18
- def call(*input)
18
+ def call *input
19
19
  *, entry = input
20
- attributes = sanitize(entry, :tagged_attributes).tap(&:compact!)
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
@@ -14,9 +14,10 @@ module Cogger
14
14
  @parser = parser
15
15
  end
16
16
 
17
- def call(*input)
17
+ def call *input
18
18
  *, entry = input
19
- attributes = sanitize(entry, :tagged_attributes).tap(&:compact!)
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
@@ -35,7 +35,7 @@ module Cogger
35
35
 
36
36
  attr_reader :pattern
37
37
 
38
- def dump(value) = value.to_s.gsub(pattern, &:dump)
38
+ def dump(value) = value ? value.to_s.gsub(pattern, &:dump) : value.inspect
39
39
  end
40
40
  end
41
41
  end
@@ -11,7 +11,7 @@ module Cogger
11
11
  @template = template
12
12
  end
13
13
 
14
- def call(*input)
14
+ def call *input
15
15
  *, entry = input
16
16
  attributes = sanitize entry, :tagged
17
17
 
data/lib/cogger/hub.rb CHANGED
@@ -6,7 +6,6 @@ require "refinements/hash"
6
6
 
7
7
  module Cogger
8
8
  # Loads configuration and simultaneously sends messages to multiple streams.
9
- # :reek:TooManyMethods
10
9
  class Hub
11
10
  extend Forwardable
12
11
 
@@ -27,23 +26,22 @@ module Cogger
27
26
  fatal!
28
27
  fatal?
29
28
  formatter
30
- formatter=
31
29
  level
32
30
  level=
33
31
  ] => :primary
34
32
 
35
33
  delegate %i[id io tags mode age size suffix] => :configuration
36
34
 
37
- def initialize(registry: Cogger, model: Configuration, **attributes)
35
+ def initialize registry: Cogger, model: Configuration, **attributes
38
36
  @registry = registry
39
- @configuration = model[**find_formatter(attributes)]
37
+ @configuration = model[**resolve_formatter(attributes)]
40
38
  @primary = configuration.to_logger
41
39
  @streams = [@primary]
42
40
  end
43
41
 
44
42
  def add_stream **attributes
45
43
  attributes[:id] = configuration.id
46
- streams.append configuration.with(**find_formatter(attributes)).to_logger
44
+ streams.append configuration.with(**resolve_formatter(attributes)).to_logger
47
45
  self
48
46
  end
49
47
 
@@ -59,16 +57,20 @@ module Cogger
59
57
 
60
58
  def any(message = nil, **, &) = log(__method__, message, **, &)
61
59
 
62
- def abort(message = nil, **payload, &block)
60
+ def abort message = nil, **payload, &block
63
61
  error(message, **payload, &block) if message || !payload.empty? || block
64
62
  exit false
65
63
  end
66
64
 
67
- def panic(message = nil, **payload, &block)
65
+ def panic message = nil, **payload, &block
68
66
  fatal(message, **payload, &block) if message || !payload.empty? || block
69
67
  exit false
70
68
  end
71
69
 
70
+ def formatter= value
71
+ primary.formatter = find_or_use_formatter value
72
+ end
73
+
72
74
  def add(level, message = nil, **, &)
73
75
  log(Logger::SEV_LABEL.fetch(level, "ANY").downcase, message, **, &)
74
76
  end
@@ -85,13 +87,19 @@ module Cogger
85
87
 
86
88
  attr_reader :registry, :configuration, :primary, :streams
87
89
 
88
- # :reek:FeatureEnvy
89
- def find_formatter attributes
90
- attributes.transform_value! :formatter do |value|
91
- next value unless value.is_a?(Symbol) || value.is_a?(String)
90
+ def resolve_formatter attributes
91
+ attributes.transform_value!(:formatter) { |value| find_or_use_formatter value }
92
+ end
92
93
 
93
- formatter, template = registry.get_formatter value
94
- template ? formatter.new(template) : formatter.new
94
+ def find_or_use_formatter value
95
+ case value
96
+ when String, Symbol
97
+ formatter, template = registry.get_formatter value
98
+ template ? formatter.new(template) : formatter.new
99
+ when Formatters::Abstract then value
100
+ else fail TypeError,
101
+ "Invalid formatter. Must be a string, symbol, or " \
102
+ "subclass of Cogger::Formatters::Abstract."
95
103
  end
96
104
  end
97
105
 
@@ -101,22 +109,23 @@ module Cogger
101
109
  crash message, error
102
110
  end
103
111
 
104
- # rubocop:todo Metrics/MethodLength
105
112
  def dispatch(level, message, **payload, &)
106
- entry = configuration.entry.for(
113
+ entry = build_entry(level, message, payload, &)
114
+ configuration.mutex.synchronize { streams.each { |logger| logger.public_send level, entry } }
115
+ true
116
+ end
117
+
118
+ def build_entry(level, message, payload, &)
119
+ configuration.entry.for(
107
120
  message,
108
121
  id: configuration.id,
109
122
  level:,
110
- tags: configuration.entag(payload.delete(:tags)),
123
+ tags: configuration.entag(payload[:tags]),
111
124
  datetime_format: configuration.datetime_format,
112
- **payload,
125
+ **payload.except(:level, :at, :tags),
113
126
  &
114
127
  )
115
-
116
- configuration.mutex.synchronize { streams.each { |logger| logger.public_send level, entry } }
117
- true
118
128
  end
119
- # rubocop:enable Metrics/MethodLength
120
129
 
121
130
  def crash message, error
122
131
  configuration.with(id: :cogger, io: $stdout, formatter: Formatters::Crash.new)
@@ -39,14 +39,14 @@ module Cogger
39
39
  "%<duration>s %<ip>s %<path>s %<length>s %<params>s"
40
40
  end
41
41
 
42
- def add_alias(key, *styles)
42
+ def add_alias key, *styles
43
43
  color.add_alias(key, *styles)
44
44
  self
45
45
  end
46
46
 
47
47
  def aliases = color.aliases
48
48
 
49
- def add_emojis(**attributes)
49
+ def add_emojis **attributes
50
50
  emojis.merge! attributes.symbolize_keys!
51
51
  self
52
52
  end
@@ -57,7 +57,7 @@ module Cogger
57
57
 
58
58
  def emojis = @emojis ||= {}
59
59
 
60
- def add_filters(*keys)
60
+ def add_filters *keys
61
61
  filters.merge(keys.map(&:to_sym))
62
62
  self
63
63
  end
data/lib/cogger/tag.rb CHANGED
@@ -27,19 +27,23 @@ module Cogger
27
27
 
28
28
  def empty? = singles.empty? && pairs.empty?
29
29
 
30
- def to_h = empty? ? Core::EMPTY_HASH : {tags: singles.to_a, **pairs}.tap(&:compress!)
30
+ def to_h
31
+ return Core::EMPTY_HASH if empty?
32
+
33
+ singles.empty? ? pairs : {tags: singles.to_a, **pairs}
34
+ end
31
35
 
32
36
  def to_s = empty? ? Core::EMPTY_STRING : "#{format_singles} #{format_pairs}".tap(&:strip!)
33
37
 
34
38
  private
35
39
 
36
40
  def format_singles
37
- singles.map { |value| "[#{value}]" }
41
+ singles.map { |value| "[#{value.inspect}]" }
38
42
  .join " "
39
43
  end
40
44
 
41
45
  def format_pairs
42
- pairs.map { |key, value| "[#{key}=#{value}]" }
46
+ pairs.map { |key, value| "[#{key}=#{value.inspect}]" }
43
47
  .join(" ")
44
48
  end
45
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.3.0
4
+ version: 2.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brooke Kuhlmann
@@ -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.12
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