cogger 0.13.1 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/README.adoc +164 -70
- data/cogger.gemspec +1 -1
- data/lib/cogger/configuration.rb +1 -1
- data/lib/cogger/entry.rb +3 -2
- data/lib/cogger/formatters/json.rb +6 -0
- data/lib/cogger/level.rb +17 -0
- data/lib/cogger/rack/logger.rb +51 -0
- data/lib/cogger/time/clock.rb +8 -0
- data/lib/cogger/time/range.rb +13 -0
- data/lib/cogger/time/span.rb +58 -0
- data/lib/cogger/time/unit.rb +18 -0
- data/lib/cogger.rb +3 -1
- data.tar.gz.sig +2 -4
- metadata +8 -2
- 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: e943adc7eaeab019242b860b3c66da64e24c52cfe756c242d3b92de480586503
|
4
|
+
data.tar.gz: ad0f47de612ca8fde2eff91593e32e5ed7cfaad13f77b62b6c3aebcbe18a9bc6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52c552fcb5ae45c4893bb84e427691504d49b987904734e81ce68b3dac889544f30c040e547d7a99d17c18429c732651a63b7628d11c00de6ba506985ea7c493
|
7
|
+
data.tar.gz: 4d7d3c410af6800bbcc6c2d35d969d06e5752c9a326010e55c8049ba91e5657aa808a04cb82cbaf294f077630a61c01ff4dcbed156abf54696a017cd59955a00
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/README.adoc
CHANGED
@@ -2,10 +2,11 @@
|
|
2
2
|
:toclevels: 5
|
3
3
|
:figure-caption!:
|
4
4
|
|
5
|
-
:
|
5
|
+
:format_link: link:https://ruby-doc.org/3.2.2/format_specifications_rdoc.html[String Format Specification]
|
6
6
|
:logger_link: link:https://rubyapi.org/o/s?q=Logger[Logger]
|
7
|
-
:format_link: link:https://ruby-doc.org/3.2.1/format_specifications_rdoc.html[Format Specification]
|
8
7
|
:pattern_matching_link: link:https://alchemists.io/articles/ruby_pattern_matching[pattern matching]
|
8
|
+
:rack_link: link:https://github.com/rack/rack[Rack]
|
9
|
+
:tone_link: link:https://alchemists.io/projects/tone[Tone]
|
9
10
|
|
10
11
|
= Cogger
|
11
12
|
|
@@ -23,6 +24,7 @@ toc::[]
|
|
23
24
|
* Provides multiple streams so you can log the same information to several outputs at once.
|
24
25
|
* Provides global and individual log entry tagging.
|
25
26
|
* Provides filtering of sensitive information.
|
27
|
+
* Provides {rack_link} middleware for HTTP request logging.
|
26
28
|
|
27
29
|
== Screenshots
|
28
30
|
|
@@ -44,7 +46,7 @@ image::https://alchemists.io/images/projects/cogger/screenshots/detail.png[Detai
|
|
44
46
|
|
45
47
|
*JSON*
|
46
48
|
|
47
|
-
image::https://alchemists.io/images/projects/cogger/screenshots/json.png[JSON,width=
|
49
|
+
image::https://alchemists.io/images/projects/cogger/screenshots/json.png[JSON,width=1002,height=290]
|
48
50
|
|
49
51
|
*Rack*
|
50
52
|
|
@@ -156,51 +158,32 @@ logger = Cogger.new id: :demo,
|
|
156
158
|
suffix: "%Y"
|
157
159
|
----
|
158
160
|
|
159
|
-
===
|
161
|
+
=== Levels
|
160
162
|
|
161
|
-
|
163
|
+
Supported levels can be obtained via `Cogger::LEVELS`. Example:
|
162
164
|
|
163
165
|
[source,ruby]
|
164
166
|
----
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
# "#<Cogger::Hub @id=console,
|
169
|
-
# @io=IO,
|
170
|
-
# @level=1,
|
171
|
-
# @formatter=Cogger::Formatters::Emoji,
|
172
|
-
# @tags=[],
|
173
|
-
# @mode=false,
|
174
|
-
# @age=0,
|
175
|
-
# @size=1048576,
|
176
|
-
# @suffix=\"%Y-%m-%d\",
|
177
|
-
# @entry=Cogger::Entry,
|
178
|
-
# @logger=Logger>"
|
167
|
+
Cogger::LEVELS
|
168
|
+
# ["debug", "info", "warn", "error", "fatal", "unknown"]
|
179
169
|
----
|
180
170
|
|
181
|
-
|
171
|
+
=== Environment
|
182
172
|
|
183
|
-
|
184
|
-
----
|
185
|
-
logger = Cogger.new
|
173
|
+
You can use your environment to define the desired default log level. The default log level is: `"info"`. Although, you can set the log level to any of the following:
|
186
174
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
logger.level # 1
|
196
|
-
logger.formatter # Cogger::Formatters::Emoji
|
197
|
-
logger.debug? # false
|
198
|
-
logger.info? # true
|
199
|
-
logger.warn? # true
|
200
|
-
logger.error? # true
|
201
|
-
logger.fatal? # true
|
175
|
+
[source,bash]
|
176
|
+
----
|
177
|
+
export LOG_LEVEL=debug
|
178
|
+
export LOG_LEVEL=info
|
179
|
+
export LOG_LEVEL=warn
|
180
|
+
export LOG_LEVEL=error
|
181
|
+
export LOG_LEVEL=fatal
|
182
|
+
export LOG_LEVEL=unknown
|
202
183
|
----
|
203
184
|
|
185
|
+
While downcase is preferred for the log level, you can use upcased 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
|
+
|
204
187
|
=== Mutations
|
205
188
|
|
206
189
|
Each instance can be mutated using the following messages:
|
@@ -222,26 +205,9 @@ logger.level = Logger::WARN # 2
|
|
222
205
|
|
223
206
|
Please see the {logger_link} documentation for more information.
|
224
207
|
|
225
|
-
=== Environment
|
226
|
-
|
227
|
-
The default log level is `INFO` but can be customized via your environment. For instance, you could
|
228
|
-
set the logging level to any of the following:
|
229
|
-
|
230
|
-
[source,bash]
|
231
|
-
----
|
232
|
-
export LOG_LEVEL=DEBUG
|
233
|
-
export LOG_LEVEL=INFO
|
234
|
-
export LOG_LEVEL=WARN
|
235
|
-
export LOG_LEVEL=ERROR
|
236
|
-
export LOG_LEVEL=FATAL
|
237
|
-
export LOG_LEVEL=UNKNOWN
|
238
|
-
----
|
239
|
-
|
240
|
-
By default, `Cogger` will automatically use whatever is set via the `LOG_LEVEL` environment variable unless overwritten during initialization.
|
241
|
-
|
242
208
|
=== Templates
|
243
209
|
|
244
|
-
Templates are used by all formatters and adhere to {format_link} as used by `Kernel#format`. All specifiers, flags, width, and precision are supported except for the following restrictions:
|
210
|
+
Templates are used by all formatters and adhere to the {format_link} as used by `Kernel#format`. All specifiers, flags, width, and precision are supported except for the following restrictions:
|
245
211
|
|
246
212
|
- Use of _reference by name_ is required which means `%<demo>s` is allowed but `%{demo}` is not. This is because _reference by name_ is required for regular expressions and/or {pattern_matching_link}.
|
247
213
|
- Use of the `n$` flag is prohibited because this isn't compatible with the above.
|
@@ -539,16 +505,16 @@ logger.warn "Demo"
|
|
539
505
|
|
540
506
|
==== JSON
|
541
507
|
|
542
|
-
This formatter is similar in behavior to the _simple_ formatter except the template allows you to _order_ the layout of your keys. All other template information is ignored, only the order of your template keys matters. Example:
|
508
|
+
This formatter is similar in behavior to the _simple_ formatter except that date/time defaults to UTC, is formattted according to link:https://datatracker.ietf.org/doc/html/rfc3339[RFC 3339] using millisecond precision, and the template allows you to _order_ the layout of your keys. All other template information is ignored, only the order of your template keys matters. Example:
|
543
509
|
|
544
510
|
*Default Order*
|
545
511
|
|
546
512
|
[source,ruby]
|
547
513
|
----
|
548
514
|
logger = Cogger.new formatter: :json
|
549
|
-
logger.info verb: "GET", path: "/"
|
550
515
|
|
551
|
-
|
516
|
+
logger.info verb: "GET", path: "/"
|
517
|
+
# {"id":"console","severity":"INFO","at":"2023-12-10T18:42:32.844+00:00","verb":"GET","path":"/"}
|
552
518
|
----
|
553
519
|
|
554
520
|
*Custom Order*
|
@@ -556,9 +522,9 @@ logger.info verb: "GET", path: "/"
|
|
556
522
|
[source,ruby]
|
557
523
|
----
|
558
524
|
logger = Cogger.new formatter: Cogger::Formatters::JSON.new("%<severity>s %<verb>s")
|
559
|
-
logger.info verb: "GET", path: "/"
|
560
525
|
|
561
|
-
|
526
|
+
logger.info verb: "GET", path: "/"
|
527
|
+
# {"severity":"INFO","verb":"GET","id":"console","at":"2023-12-10T18:43:03.805+00:00","path":"/"}
|
562
528
|
----
|
563
529
|
|
564
530
|
Your template can be a full or partial match of keys. If no keys match what is defined in the template, then the original order of the keys will be used instead.
|
@@ -567,29 +533,29 @@ You can always supply a message as your first argument -- or specify it by using
|
|
567
533
|
|
568
534
|
[source,ruby]
|
569
535
|
----
|
570
|
-
logger = Cogger.new formatter: json
|
536
|
+
logger = Cogger.new formatter: :json
|
571
537
|
|
572
538
|
logger.info "Demo"
|
573
|
-
# {"id":"console","severity":"INFO","at":"2023-
|
539
|
+
# {"id":"console","severity":"INFO","at":"2023-12-10T18:43:42.029+00:00","message":"Demo"}
|
574
540
|
|
575
|
-
logger.info
|
576
|
-
{"id":"console","severity":"INFO","at":"2023-
|
541
|
+
logger.info message: "Demo"
|
542
|
+
# {"id":"console","severity":"INFO","at":"2023-12-10T18:44:14.568+00:00","message":"Demo"}
|
577
543
|
----
|
578
544
|
|
579
|
-
When tags are provided, the `:tags` key will appear in the output depending on whether you are using _single tags_. If hash tags are used, they'll show up as additional attributes in the
|
545
|
+
When tags are provided, the `:tags` key will appear in the output depending on whether you are using _single tags_. If hash tags are used, they'll show up as additional attributes in the output. Here's an example where a mix of single and hash keys are used:
|
580
546
|
|
581
547
|
[source,ruby]
|
582
548
|
----
|
583
549
|
logger = Cogger.new formatter: :json
|
584
550
|
|
585
551
|
logger.info "Demo", tags: ["WEB", "PRIMARY", {service: :api, demo: true}]
|
586
|
-
|
587
552
|
# {
|
588
553
|
# "id":"console",
|
589
554
|
# "severity":"INFO",
|
590
|
-
# "at":"2023-
|
555
|
+
# "at":"2023-12-10T18:44:32.723+00:00",
|
591
556
|
# "message":"Demo",
|
592
|
-
# "tags":["WEB",
|
557
|
+
# "tags":["WEB",
|
558
|
+
# "PRIMARY"],
|
593
559
|
# "service":"api",
|
594
560
|
# "demo":true
|
595
561
|
# }
|
@@ -789,6 +755,89 @@ logger.info "Demo"
|
|
789
755
|
# Demo
|
790
756
|
----
|
791
757
|
|
758
|
+
=== Rack
|
759
|
+
|
760
|
+
{rack_link} is _implicitly_ supported which means your middleware _must be_ Rack-based and _must require_ the Rack gem since `Cogger::Rack::Logger` doesn't _explicitly_ require Rack by default. If these requirements are met then, to add HTTP request logging, you only need to use it. Example:
|
761
|
+
|
762
|
+
[source,ruby]
|
763
|
+
----
|
764
|
+
use Rails::Rack::Logger
|
765
|
+
----
|
766
|
+
|
767
|
+
Like any other {rack_link} middleware, `Rails::Rack::Logger` is initialized with your current application along with any custom options. Example:
|
768
|
+
|
769
|
+
[source,ruby]
|
770
|
+
----
|
771
|
+
middleware = Cogger::Rack::Logger.new application
|
772
|
+
middleware.call environment
|
773
|
+
----
|
774
|
+
|
775
|
+
The following defaults are supported:
|
776
|
+
|
777
|
+
[source,ruby]
|
778
|
+
----
|
779
|
+
Cogger::Rack::Logger::DEFAULTS
|
780
|
+
|
781
|
+
# {
|
782
|
+
# logger: Cogger.new(formatter: :json),
|
783
|
+
# timer: Cogger::Time::Span.new,
|
784
|
+
# :key_map => {
|
785
|
+
# :verb => "REQUEST_METHOD",
|
786
|
+
# :ip => "REMOTE_ADDR",
|
787
|
+
# :path => "PATH_INFO",
|
788
|
+
# :params => "QUERY_STRING",
|
789
|
+
# :length => "CONTENT_LENGTH"
|
790
|
+
# }
|
791
|
+
# }
|
792
|
+
----
|
793
|
+
|
794
|
+
The defaults can be customized. Example:
|
795
|
+
|
796
|
+
[source,]
|
797
|
+
----
|
798
|
+
Cogger::Rack::Logger.new application, {logger: Cogger.new}
|
799
|
+
----
|
800
|
+
|
801
|
+
In the above example, we see `Cogger.new` overrides the default `Cogger.new(formatter: :json)`. In practice, you'll want to customize the logger and key map. Here's how each default is configured to be used:
|
802
|
+
|
803
|
+
* `logger`: Defaults to JSON formatted logging but you'll want to pass in the same logger as globally configured for your application in order to reduce duplication and save on memory.
|
804
|
+
* `timer`: The timer calculates the total duration of the request and defaults to nanosecond precision but you can swap this out with your own timer if desired. When providing your own timer, the only requirement is that the timer respond to the `#call` message with a block.
|
805
|
+
* `key_map`: The key map is used to map the HTTP Headers to keys (i.e. tags) used in the log output. You can use the existing key map, provide your own, or use a hybrid.
|
806
|
+
|
807
|
+
Once this middleware is configured and used within your application, you'll start seeing the following kinds of log entries (depending on your specific settings and tags used):
|
808
|
+
|
809
|
+
[source,json]
|
810
|
+
----
|
811
|
+
{
|
812
|
+
"id":"demo",
|
813
|
+
"severity":"INFO",
|
814
|
+
"at":"2023-12-10T22:37:06.341+00:00",
|
815
|
+
"verb":"GET",
|
816
|
+
"ip":"127.0.0.1",
|
817
|
+
"path":"/dashboard",
|
818
|
+
"status":200,
|
819
|
+
"duration":83,
|
820
|
+
"unit":"ms"
|
821
|
+
}
|
822
|
+
----
|
823
|
+
|
824
|
+
*Rails*
|
825
|
+
|
826
|
+
To build upon the above -- and if using the Rails framework -- you could configure your application as follows:
|
827
|
+
|
828
|
+
[source,ruby]
|
829
|
+
----
|
830
|
+
# demo/config/application.rb
|
831
|
+
module Demo
|
832
|
+
class Application < Rails::Application
|
833
|
+
config.logger = Cogger.new id: "demo", formatter: :json,
|
834
|
+
config.middleware.swap Rails::Rack::Logger, Cogger::Rack::Logger, {logger: config.logger}
|
835
|
+
end
|
836
|
+
end
|
837
|
+
----
|
838
|
+
|
839
|
+
The above defines `Cogger` as the default logger for the entire application, ensures `Cogger::Rack::Logger` is configured to use it and swaps itself with the default `Rails::Rack::Logger` so you don't have two pieces of middleware logging the same HTTP requests.
|
840
|
+
|
792
841
|
=== Defaults
|
793
842
|
|
794
843
|
Should you ever need quick access to the defaults, you can use:
|
@@ -800,6 +849,51 @@ Cogger.defaults
|
|
800
849
|
|
801
850
|
This is primarily meant for display/inspection purposes, though.
|
802
851
|
|
852
|
+
=== Inspection
|
853
|
+
|
854
|
+
Each instance can be inspected via the `#inspect` message:
|
855
|
+
|
856
|
+
[source,ruby]
|
857
|
+
----
|
858
|
+
logger = Cogger.new
|
859
|
+
logger.inspect
|
860
|
+
|
861
|
+
# "#<Cogger::Hub @id=console,
|
862
|
+
# @io=IO,
|
863
|
+
# @level=1,
|
864
|
+
# @formatter=Cogger::Formatters::Emoji,
|
865
|
+
# @tags=[],
|
866
|
+
# @mode=false,
|
867
|
+
# @age=0,
|
868
|
+
# @size=1048576,
|
869
|
+
# @suffix=\"%Y-%m-%d\",
|
870
|
+
# @entry=Cogger::Entry,
|
871
|
+
# @logger=Logger>"
|
872
|
+
----
|
873
|
+
|
874
|
+
You can also look at individual attributes:
|
875
|
+
|
876
|
+
[source,ruby]
|
877
|
+
----
|
878
|
+
logger = Cogger.new
|
879
|
+
|
880
|
+
logger.id # "console"
|
881
|
+
logger.io # #<IO:<STDOUT>>
|
882
|
+
logger.tags # []
|
883
|
+
logger.mode # false
|
884
|
+
logger.age # 0
|
885
|
+
logger.size # 1048576
|
886
|
+
logger.suffix # "%Y-%m-%d"
|
887
|
+
|
888
|
+
logger.level # 1
|
889
|
+
logger.formatter # Cogger::Formatters::Emoji
|
890
|
+
logger.debug? # false
|
891
|
+
logger.info? # true
|
892
|
+
logger.warn? # true
|
893
|
+
logger.error? # true
|
894
|
+
logger.fatal? # true
|
895
|
+
----
|
896
|
+
|
803
897
|
=== Testing
|
804
898
|
|
805
899
|
When testing, you might find it convenient to rewind and read from the stream you are writing too (i.e. `IO`, `StringIO`, `File`). For instance, here is an example where I inject the default logger into my `Demo` class and then, for testing purposes, create a new logger to be injected which only logs to `StringIO` so I can buffer and read for test verification:
|
@@ -852,7 +946,7 @@ You can also use the IRB console for direct access to all objects:
|
|
852
946
|
bin/console
|
853
947
|
----
|
854
948
|
|
855
|
-
Lastly, there is a `bin/
|
949
|
+
Lastly, there is a `bin/demo` script which displays multiple log formats for quick visual reference. This is the same script used to generate the screenshots shown at the top of this document.
|
856
950
|
|
857
951
|
== Tests
|
858
952
|
|
data/cogger.gemspec
CHANGED
data/lib/cogger/configuration.rb
CHANGED
data/lib/cogger/entry.rb
CHANGED
@@ -6,8 +6,9 @@ module Cogger
|
|
6
6
|
# Defines a log entry which can be formatted for output.
|
7
7
|
Entry = Data.define :id, :severity, :at, :message, :tags, :payload do
|
8
8
|
def self.for(message = nil, **payload)
|
9
|
-
new id:
|
9
|
+
new id: payload.delete(:id) || Program.call,
|
10
10
|
severity: (payload.delete(:severity) || "INFO").upcase,
|
11
|
+
at: payload.delete(:at) || ::Time.now,
|
11
12
|
message: (block_given? ? yield : message),
|
12
13
|
tags: Array(payload.delete(:tags)),
|
13
14
|
payload:
|
@@ -26,7 +27,7 @@ module Cogger
|
|
26
27
|
|
27
28
|
def initialize id: Program.call,
|
28
29
|
severity: "INFO",
|
29
|
-
at: Time.now,
|
30
|
+
at: ::Time.now,
|
30
31
|
message: nil,
|
31
32
|
tags: [],
|
32
33
|
payload: Core::EMPTY_HASH
|
@@ -18,6 +18,7 @@ module Cogger
|
|
18
18
|
|
19
19
|
def call(*input)
|
20
20
|
attributes = sanitizer.call(*input).tagged_attributes.tap(&:compact!)
|
21
|
+
format_date_time attributes
|
21
22
|
|
22
23
|
return "#{attributes.to_json}\n" if positions.empty?
|
23
24
|
|
@@ -27,6 +28,11 @@ module Cogger
|
|
27
28
|
private
|
28
29
|
|
29
30
|
attr_reader :positions, :sanitizer
|
31
|
+
|
32
|
+
# :reek:UtilityFunction
|
33
|
+
def format_date_time attributes
|
34
|
+
attributes[:at] = attributes[:at].utc.strftime "%Y-%m-%dT%H:%M:%S.%L%:z"
|
35
|
+
end
|
30
36
|
end
|
31
37
|
end
|
32
38
|
end
|
data/lib/cogger/level.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "logger"
|
4
|
+
require "refinements/arrays"
|
5
|
+
|
6
|
+
# Loads log level from environment.
|
7
|
+
module Cogger
|
8
|
+
using Refinements::Arrays
|
9
|
+
|
10
|
+
Level = lambda do |logger = Logger, environment: ENV, allowed: LEVELS|
|
11
|
+
value = String environment.fetch("LOG_LEVEL", "INFO")
|
12
|
+
|
13
|
+
return logger.const_get value.upcase if allowed.include? value.downcase
|
14
|
+
|
15
|
+
fail ArgumentError, %(Invalid log level: #{value.inspect}. Use: #{allowed.to_usage "or"}.)
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "core"
|
4
|
+
|
5
|
+
module Cogger
|
6
|
+
module Rack
|
7
|
+
# Middlware for enriched logging based on the incoming request.
|
8
|
+
class Logger
|
9
|
+
DEFAULTS = {
|
10
|
+
logger: Cogger.new(formatter: :json),
|
11
|
+
timer: Cogger::Time::Span.new,
|
12
|
+
key_map: {
|
13
|
+
verb: "REQUEST_METHOD",
|
14
|
+
ip: "REMOTE_ADDR",
|
15
|
+
path: "PATH_INFO",
|
16
|
+
params: "QUERY_STRING",
|
17
|
+
length: "CONTENT_LENGTH"
|
18
|
+
}
|
19
|
+
}.freeze
|
20
|
+
|
21
|
+
def initialize application, options = Core::EMPTY_HASH, defaults: DEFAULTS
|
22
|
+
configuration = defaults.merge options
|
23
|
+
|
24
|
+
@application = application
|
25
|
+
@logger = configuration.fetch :logger
|
26
|
+
@timer = configuration.fetch :timer
|
27
|
+
@key_map = configuration.fetch :key_map
|
28
|
+
end
|
29
|
+
|
30
|
+
def call environment
|
31
|
+
request = ::Rack::Request.new environment
|
32
|
+
(status, headers, body), duration, unit = timer.call { application.call environment }
|
33
|
+
|
34
|
+
logger.info tags: [tags_for(request), {status:, duration:, unit:}]
|
35
|
+
|
36
|
+
[status, headers, body]
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
attr_reader :application, :logger, :timer, :key_map
|
42
|
+
|
43
|
+
def tags_for request
|
44
|
+
key_map.each_key.with_object({}) do |tag, collection|
|
45
|
+
key = key_map.fetch tag, tag
|
46
|
+
collection[String(tag).downcase] = request.get_header key
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cogger
|
4
|
+
module Time
|
5
|
+
RANGE = {
|
6
|
+
nanoseconds: ...1_000,
|
7
|
+
microseconds: 1_000...1_000_000,
|
8
|
+
milliseconds: 1_000_000...1_000_000_000,
|
9
|
+
seconds: 1_000_000_000...60_000_000_000,
|
10
|
+
minutes: 60_000_000_000...
|
11
|
+
}.freeze
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cogger
|
4
|
+
module Time
|
5
|
+
# Measures duration of a process with nanosecond precision.
|
6
|
+
class Span
|
7
|
+
def initialize clock = Clock, unit: Unit, range: RANGE
|
8
|
+
@clock = clock
|
9
|
+
@unit = unit
|
10
|
+
@range = range
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
start = current
|
15
|
+
result = yield
|
16
|
+
span = current - start
|
17
|
+
|
18
|
+
[result, duration(span), unit.call(span)]
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
attr_reader :clock, :unit, :range
|
24
|
+
|
25
|
+
def duration value
|
26
|
+
case value
|
27
|
+
when nanoseconds then value
|
28
|
+
when microseconds then value / microseconds.min
|
29
|
+
when milliseconds then value / milliseconds.min
|
30
|
+
when seconds then value / seconds.min
|
31
|
+
else value / minutes.min
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def current = clock.call
|
36
|
+
|
37
|
+
def nanoseconds
|
38
|
+
@nanoseconds ||= range.fetch __method__
|
39
|
+
end
|
40
|
+
|
41
|
+
def microseconds
|
42
|
+
@microseconds ||= range.fetch __method__
|
43
|
+
end
|
44
|
+
|
45
|
+
def milliseconds
|
46
|
+
@milliseconds ||= range.fetch __method__
|
47
|
+
end
|
48
|
+
|
49
|
+
def seconds
|
50
|
+
@seconds ||= range.fetch __method__
|
51
|
+
end
|
52
|
+
|
53
|
+
def minutes
|
54
|
+
@minutes ||= range.fetch __method__
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cogger
|
4
|
+
module Time
|
5
|
+
# Provides unit of measure for duration.
|
6
|
+
# rubocop:disable Style/MethodCallWithArgsParentheses
|
7
|
+
Unit = lambda do |duration, range: RANGE|
|
8
|
+
case duration
|
9
|
+
when range.fetch(:nanoseconds) then "ns"
|
10
|
+
when range.fetch(:microseconds) then "µs"
|
11
|
+
when range.fetch(:milliseconds) then "ms"
|
12
|
+
when range.fetch(:seconds) then "s"
|
13
|
+
else "m"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
# rubocop:enable Style/MethodCallWithArgsParentheses
|
17
|
+
end
|
18
|
+
end
|
data/lib/cogger.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
require "zeitwerk"
|
4
4
|
|
5
5
|
Zeitwerk::Loader.new.then do |loader|
|
6
|
-
loader.inflector.inflect "json" => "JSON"
|
6
|
+
loader.inflector.inflect "json" => "JSON", "range" => "RANGE"
|
7
7
|
loader.tag = File.basename __FILE__, ".rb"
|
8
8
|
loader.push_dir __dir__
|
9
9
|
loader.setup
|
@@ -13,6 +13,8 @@ end
|
|
13
13
|
module Cogger
|
14
14
|
extend Registry
|
15
15
|
|
16
|
+
LEVELS = %w[debug info warn error fatal unknown].freeze
|
17
|
+
|
16
18
|
def self.loader registry = Zeitwerk::Registry
|
17
19
|
@loader ||= registry.loaders.find { |loader| loader.tag == File.basename(__FILE__, ".rb") }
|
18
20
|
end
|
data.tar.gz.sig
CHANGED
@@ -1,4 +1,2 @@
|
|
1
|
-
�
|
2
|
-
|
3
|
-
0�ê�\�aFp��VO�R���;��$�2�ǚ��D��^6�Eh����O�/Gjx�B+enS`ڟ톦�,�K�a��IR�=<-����'\�f_�n��W^EL�H�
|
4
|
-
�qj��$Z%�
|
1
|
+
)�_��S����q�¦�=��r��B}u��<k8���Y�]גq��hnA��IY�1�^e�b�C4%�����-���ϣ�*
|
2
|
+
���
|
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: 0.
|
4
|
+
version: 0.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brooke Kuhlmann
|
@@ -35,7 +35,7 @@ cert_chain:
|
|
35
35
|
3n5C8/6Zh9DYTkpcwPSuIfAga6wf4nXc9m6JAw8AuMLaiWN/r/2s4zJsUHYERJEu
|
36
36
|
gZGm4JqtuSg8pYjPeIJxS960owq+SfuC+jxqmRA54BisFCv/0VOJi7tiJVY=
|
37
37
|
-----END CERTIFICATE-----
|
38
|
-
date: 2023-
|
38
|
+
date: 2023-12-10 00:00:00.000000000 Z
|
39
39
|
dependencies:
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
41
|
name: core
|
@@ -120,9 +120,15 @@ files:
|
|
120
120
|
- lib/cogger/formatters/processors/color.rb
|
121
121
|
- lib/cogger/formatters/simple.rb
|
122
122
|
- lib/cogger/hub.rb
|
123
|
+
- lib/cogger/level.rb
|
123
124
|
- lib/cogger/program.rb
|
125
|
+
- lib/cogger/rack/logger.rb
|
124
126
|
- lib/cogger/registry.rb
|
125
127
|
- lib/cogger/tag.rb
|
128
|
+
- lib/cogger/time/clock.rb
|
129
|
+
- lib/cogger/time/range.rb
|
130
|
+
- lib/cogger/time/span.rb
|
131
|
+
- lib/cogger/time/unit.rb
|
126
132
|
homepage: https://alchemists.io/projects/cogger
|
127
133
|
licenses:
|
128
134
|
- Hippocratic-2.1
|
metadata.gz.sig
CHANGED
Binary file
|