julewire-semantic_logger 1.0.1 → 1.1.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
- data/CHANGELOG.md +6 -0
- data/docs/advanced-configuration.md +12 -0
- data/docs/configuration.md +6 -0
- data/docs/health.md +3 -1
- data/docs/transport.md +3 -15
- data/julewire-semantic_logger.gemspec +1 -1
- data/lib/julewire/semantic_logger/appender_health.rb +2 -0
- data/lib/julewire/semantic_logger/async_options.rb +127 -0
- data/lib/julewire/semantic_logger/destination.rb +23 -24
- data/lib/julewire/semantic_logger/transport.rb +31 -54
- data/lib/julewire/semantic_logger/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: beb5d40e08c5450bacaf2612a33be872a901a65720e7f45ca3e1ef6f3c5ba079
|
|
4
|
+
data.tar.gz: 732c33f8c3084b1910e2811bf46b22e4eb830251e03603d08f220d7806ed7e49
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bf6b5a29645f9c18c6a7b7b50a752835679e1d70c4b9832ba5150568a3ecd0ecee1e9b48a61eb5b92ab44238c8685f99e511cd7ee43c7df7b54f05416e449412
|
|
7
|
+
data.tar.gz: c5622b13c0ffebf510ecd7a11192ea4083d5f94fb0b8a0ae9ccc8ff79283794dbd390d6ee22d09e16c44d53458c82252f59a230debc365554e4ab60e75253f0d
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
## Unreleased
|
|
2
2
|
|
|
3
|
+
## 1.1.0 - 2026-07-20
|
|
4
|
+
|
|
5
|
+
- Support Semantic Logger 4 and 5 async option shapes.
|
|
6
|
+
- Keep destination health and callback failure reporting aligned with core.
|
|
7
|
+
- Require julewire-core 1.1.0.
|
|
8
|
+
|
|
3
9
|
## 1.0.1 - 2026-06-25
|
|
4
10
|
|
|
5
11
|
- Report destination callback failures in health, matching core destinations.
|
|
@@ -36,6 +36,18 @@ These options are passed to `SemanticLogger::Appender::Async` when
|
|
|
36
36
|
| `lag_check_interval:` | `1_000` |
|
|
37
37
|
| `lag_threshold_s:` | `30` |
|
|
38
38
|
|
|
39
|
+
## Async Queue Options
|
|
40
|
+
|
|
41
|
+
Transport-level async options are passed to the Semantic Logger async proxy
|
|
42
|
+
when the installed Semantic Logger version supports them. Semantic Logger 4.18
|
|
43
|
+
supports queue size and lag options. Semantic Logger 5 also supports
|
|
44
|
+
`non_blocking:`, `dropped_message_report_seconds:`, and `async_max_retries:`.
|
|
45
|
+
Setting a non-default unsupported async option raises a configuration error.
|
|
46
|
+
|
|
47
|
+
`batch: true` uses `SemanticLogger::Appender::AsyncBatch` on Semantic Logger 4
|
|
48
|
+
and `SemanticLogger::Appender::Async` batch mode on Semantic Logger 5. Batch
|
|
49
|
+
mode implies async output.
|
|
50
|
+
|
|
39
51
|
## Appender Defaults
|
|
40
52
|
|
|
41
53
|
Unknown transport options are merged into each appender spec. This is useful for
|
data/docs/configuration.md
CHANGED
|
@@ -39,6 +39,12 @@ At least one appender target is required.
|
|
|
39
39
|
| `appenders:` | none | Array of appender specs. |
|
|
40
40
|
| `async:` | `false` | Wrap the sink in `SemanticLogger::Appender::Async`. |
|
|
41
41
|
| `max_queue_size:` | `10_000` | Async queue size. `-1` means unbounded in Semantic Logger. |
|
|
42
|
+
| `batch:` | `nil` | Use Semantic Logger batch async processing when supported by the appender. `true` implies async output. |
|
|
43
|
+
| `batch_size:` | `300` | Batch size for batch-capable async appenders. |
|
|
44
|
+
| `batch_seconds:` | `5` | Maximum seconds between batch writes. |
|
|
45
|
+
| `non_blocking:` | `false` | Semantic Logger 5+ async drop mode. Raises on older Semantic Logger when set to a non-default value. |
|
|
46
|
+
| `dropped_message_report_seconds:` | `30` | Semantic Logger 5+ dropped-message report interval. Raises on older Semantic Logger when set to a non-default value. |
|
|
47
|
+
| `async_max_retries:` | `100` | Semantic Logger 5+ async worker retry limit. Raises on older Semantic Logger when set to a non-default value. |
|
|
42
48
|
|
|
43
49
|
Unknown transport options are passed to Semantic Logger appender construction.
|
|
44
50
|
|
data/docs/health.md
CHANGED
|
@@ -11,7 +11,7 @@ Destination health includes:
|
|
|
11
11
|
- destination `status`
|
|
12
12
|
- destination write/failure counts
|
|
13
13
|
- transport write/failure counts
|
|
14
|
-
- async queue state
|
|
14
|
+
- async queue state and lag settings
|
|
15
15
|
- file appender metadata
|
|
16
16
|
- child appender shape for multi-appender output
|
|
17
17
|
- lifecycle warnings
|
|
@@ -38,6 +38,8 @@ One practical mapping is:
|
|
|
38
38
|
| `destinations.*.transport.counts.*` | `julewire_semantic_logger_transport_total{destination,event}` |
|
|
39
39
|
| `destinations.*.transport.appender.queue_size` | `julewire_semantic_logger_queue_size{destination}` |
|
|
40
40
|
| `destinations.*.transport.appender.max_queue_size` | `julewire_semantic_logger_queue_capacity{destination}` |
|
|
41
|
+
| `destinations.*.transport.appender.lag_check_interval` | `julewire_semantic_logger_lag_check_interval{destination}` |
|
|
42
|
+
| `destinations.*.transport.appender.lag_threshold_s` | `julewire_semantic_logger_lag_threshold_seconds{destination}` |
|
|
41
43
|
| `destinations.*.transport.warnings.*` | `julewire_semantic_logger_warning{destination,reason}` |
|
|
42
44
|
|
|
43
45
|
Treat core health paths as inputs, not as a global metrics schema.
|
data/docs/transport.md
CHANGED
|
@@ -64,21 +64,9 @@ Verified paths:
|
|
|
64
64
|
## Metric Mapping
|
|
65
65
|
|
|
66
66
|
The adapter owns metric names because queue, file, and appender behavior is
|
|
67
|
-
transport-specific.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
| --- | --- |
|
|
71
|
-
| `counts.*` | `julewire_runtime_total{event}` |
|
|
72
|
-
| `pipeline.counts.*` | `julewire_pipeline_total{event}` |
|
|
73
|
-
| `destinations.*.counts.*` | `julewire_destination_total{destination,event}` |
|
|
74
|
-
| `destinations.*.last_loss.reason` | `julewire_destination_last_loss{destination,reason}` |
|
|
75
|
-
| `destinations.*.transport.counts.*` | `julewire_semantic_logger_transport_total{destination,event}` |
|
|
76
|
-
| `destinations.*.transport.appender.queue_size` | `julewire_semantic_logger_queue_size{destination}` |
|
|
77
|
-
| `destinations.*.transport.appender.max_queue_size` | `julewire_semantic_logger_queue_capacity{destination}` |
|
|
78
|
-
| `destinations.*.transport.warnings.*` | `julewire_semantic_logger_warning{destination,reason}` |
|
|
79
|
-
|
|
80
|
-
Extensions should treat core health paths as inputs, not as a global metrics
|
|
81
|
-
schema.
|
|
67
|
+
transport-specific. The [health guide](health.md#metric-mapping) is the
|
|
68
|
+
canonical mapping; extensions should treat core health paths as inputs, not as
|
|
69
|
+
a global metrics schema.
|
|
82
70
|
|
|
83
71
|
Observed behavior:
|
|
84
72
|
|
|
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
|
|
|
32
32
|
spec.executables = []
|
|
33
33
|
spec.require_paths = ["lib"]
|
|
34
34
|
|
|
35
|
-
spec.add_dependency "julewire-core", ">= 1.0
|
|
35
|
+
spec.add_dependency "julewire-core", ">= 1.1.0"
|
|
36
36
|
spec.add_dependency "logger", ">= 1.7"
|
|
37
37
|
spec.add_dependency "semantic_logger", ">= 4.18"
|
|
38
38
|
spec.add_dependency "zeitwerk", ">= 2.8.1"
|
|
@@ -36,6 +36,8 @@ module Julewire
|
|
|
36
36
|
{
|
|
37
37
|
active: value.active?,
|
|
38
38
|
capped: value.capped?,
|
|
39
|
+
lag_check_interval: value.lag_check_interval,
|
|
40
|
+
lag_threshold_s: value.lag_threshold_s,
|
|
39
41
|
max_queue_size: value.max_queue_size,
|
|
40
42
|
queue_size: value.queue.size,
|
|
41
43
|
wrapped: call(value.appender)
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Julewire
|
|
4
|
+
module SemanticLogger
|
|
5
|
+
class AsyncOptions
|
|
6
|
+
DEFAULT_MAX_QUEUE_SIZE = 10_000
|
|
7
|
+
DEFAULTS = {
|
|
8
|
+
max_queue_size: DEFAULT_MAX_QUEUE_SIZE,
|
|
9
|
+
lag_check_interval: 1_000,
|
|
10
|
+
lag_threshold_s: 30,
|
|
11
|
+
batch: nil,
|
|
12
|
+
batch_size: 300,
|
|
13
|
+
batch_seconds: 5,
|
|
14
|
+
non_blocking: false,
|
|
15
|
+
dropped_message_report_seconds: 30,
|
|
16
|
+
async_max_retries: 100
|
|
17
|
+
}.freeze
|
|
18
|
+
BATCH_OPTIONS = { batch_size: true, batch_seconds: true }.freeze
|
|
19
|
+
KEYWORD_PARAMETER_KINDS = { key: true, keyreq: true }.freeze
|
|
20
|
+
SUPPORTED_DEFAULTS = DEFAULTS.keys.to_h { [it, true] }.freeze
|
|
21
|
+
ASYNC_APPENDER = ::SemanticLogger::Appender::Async
|
|
22
|
+
ASYNC_APPENDER_ACCEPTS_ANY_KEYWORD =
|
|
23
|
+
ASYNC_APPENDER.instance_method(:initialize).parameters.any? { |kind, _name| kind == :keyrest }
|
|
24
|
+
ASYNC_BATCH_APPENDER = if ::SemanticLogger::Appender.const_defined?(:AsyncBatch, false)
|
|
25
|
+
::SemanticLogger::Appender.const_get(:AsyncBatch, false)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class << self
|
|
29
|
+
def extract(options)
|
|
30
|
+
configured = []
|
|
31
|
+
values = DEFAULTS.to_h do |name, default|
|
|
32
|
+
if options.key?(name)
|
|
33
|
+
configured << name
|
|
34
|
+
[name, options.delete(name)]
|
|
35
|
+
else
|
|
36
|
+
[name, default]
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
new(values: values, configured: configured)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def initialize(values:, configured:)
|
|
45
|
+
@values = values
|
|
46
|
+
@configured = configured
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def async?(base_async)
|
|
50
|
+
base_async || batch_enabled?
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def max_queue_size
|
|
54
|
+
@values.fetch(:max_queue_size)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def build_appender(sink)
|
|
58
|
+
klass = appender_class
|
|
59
|
+
klass.new(appender: sink, **constructor_options(klass))
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
if ASYNC_APPENDER_ACCEPTS_ANY_KEYWORD
|
|
65
|
+
def appender_class
|
|
66
|
+
ASYNC_APPENDER
|
|
67
|
+
end
|
|
68
|
+
else
|
|
69
|
+
def appender_class
|
|
70
|
+
return ASYNC_APPENDER unless batch_enabled?
|
|
71
|
+
|
|
72
|
+
ASYNC_BATCH_APPENDER
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def constructor_options(klass)
|
|
77
|
+
supported = supported_options(klass)
|
|
78
|
+
unsupported = unsupported_configured_options(supported)
|
|
79
|
+
unless unsupported.empty?
|
|
80
|
+
raise ArgumentError, "#{klass} does not support async option(s): #{unsupported.join(", ")}"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
DEFAULTS.each_with_object({}) do |(name, _default), kwargs|
|
|
84
|
+
next unless supported.fetch(name, false)
|
|
85
|
+
|
|
86
|
+
value = @values.fetch(name)
|
|
87
|
+
kwargs[name] = value unless value.nil?
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def supported_options(klass)
|
|
92
|
+
parameters = klass.instance_method(:initialize).parameters
|
|
93
|
+
return SUPPORTED_DEFAULTS if keyrest_constructor?(parameters)
|
|
94
|
+
|
|
95
|
+
parameters.each_with_object({}) do |(kind, name), supported|
|
|
96
|
+
supported[name] = true if KEYWORD_PARAMETER_KINDS.key?(kind)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def keyrest_constructor?(parameters)
|
|
101
|
+
parameters.any? { |kind, _name| kind == :keyrest }
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def unsupported_configured_options(supported)
|
|
105
|
+
@configured.reject do |name|
|
|
106
|
+
mode_selector?(name) || supported.fetch(name, false) || default_value?(name) || inactive_batch_option?(name)
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def mode_selector?(name)
|
|
111
|
+
name == :batch
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def default_value?(name)
|
|
115
|
+
@values.fetch(name) == DEFAULTS.fetch(name)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def inactive_batch_option?(name)
|
|
119
|
+
BATCH_OPTIONS.key?(name) && !batch_enabled?
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def batch_enabled?
|
|
123
|
+
@values.fetch(:batch).equal?(true)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -21,16 +21,16 @@ module Julewire
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def emit(record)
|
|
24
|
+
degradation_marker = @health.degradation_marker
|
|
24
25
|
formatted = false
|
|
25
26
|
increment(:received)
|
|
26
27
|
payload = @formatter.call(record)
|
|
27
28
|
formatted = true
|
|
28
29
|
@transport.write(encoded_payload(payload), severity: record.fetch(:severity))
|
|
29
|
-
record_written
|
|
30
|
+
record_written(degradation_marker)
|
|
30
31
|
nil
|
|
31
32
|
rescue StandardError => e
|
|
32
33
|
record_failure(e, formatted: formatted, record: record)
|
|
33
|
-
nil
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
def flush(*) = call_lifecycle(:flush) { @transport.flush }
|
|
@@ -46,7 +46,7 @@ module Julewire
|
|
|
46
46
|
def health
|
|
47
47
|
transport = @transport.health
|
|
48
48
|
@health.snapshot(
|
|
49
|
-
status: status(
|
|
49
|
+
status: status(transport),
|
|
50
50
|
type: "semantic_logger_destination",
|
|
51
51
|
transport: transport
|
|
52
52
|
)
|
|
@@ -71,14 +71,14 @@ module Julewire
|
|
|
71
71
|
@health.increment(name)
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
-
def record_written
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
@health.
|
|
74
|
+
def record_written(degradation_marker)
|
|
75
|
+
increment(:formatted)
|
|
76
|
+
increment(:written)
|
|
77
|
+
@health.clear_degradation_if_unchanged(degradation_marker)
|
|
78
78
|
end
|
|
79
79
|
|
|
80
|
-
def record_failure(error, formatted
|
|
81
|
-
|
|
80
|
+
def record_failure(error, formatted:, record:)
|
|
81
|
+
increment(:formatted) if formatted
|
|
82
82
|
@health.record_failure(error, destination: name, phase: :destination, record_metadata: record_metadata(record))
|
|
83
83
|
notify_failure(error, phase: :destination, record_metadata: record_metadata(record))
|
|
84
84
|
record_drop(:destination_exception, record)
|
|
@@ -90,8 +90,9 @@ module Julewire
|
|
|
90
90
|
end
|
|
91
91
|
|
|
92
92
|
def call_lifecycle(action)
|
|
93
|
+
degradation_marker = @health.degradation_marker
|
|
93
94
|
yield
|
|
94
|
-
|
|
95
|
+
@health.clear_degradation_if_unchanged(degradation_marker)
|
|
95
96
|
true
|
|
96
97
|
rescue StandardError => e
|
|
97
98
|
record_lifecycle_failure(e, action: action)
|
|
@@ -126,20 +127,18 @@ module Julewire
|
|
|
126
127
|
end
|
|
127
128
|
|
|
128
129
|
def record_metadata(record)
|
|
129
|
-
Core::Records::Metadata.call(record)
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
def status(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
def clear_degraded
|
|
142
|
-
@health.clear_degraded!
|
|
130
|
+
Core::Records::Metadata.call(record)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def status(transport)
|
|
134
|
+
case transport[:status]
|
|
135
|
+
when :closed
|
|
136
|
+
:closed
|
|
137
|
+
when nil, :ok
|
|
138
|
+
nil
|
|
139
|
+
else
|
|
140
|
+
:degraded
|
|
141
|
+
end
|
|
143
142
|
end
|
|
144
143
|
end
|
|
145
144
|
end
|
|
@@ -6,7 +6,7 @@ module Julewire
|
|
|
6
6
|
module SemanticLogger
|
|
7
7
|
class Transport
|
|
8
8
|
LOGGER_NAME = "julewire"
|
|
9
|
-
DEFAULT_MAX_QUEUE_SIZE =
|
|
9
|
+
DEFAULT_MAX_QUEUE_SIZE = AsyncOptions::DEFAULT_MAX_QUEUE_SIZE
|
|
10
10
|
LEVEL_MAP = {
|
|
11
11
|
# SemanticLogger has no unknown level; fatal keeps unknown core records visible.
|
|
12
12
|
unknown: :fatal
|
|
@@ -15,14 +15,11 @@ module Julewire
|
|
|
15
15
|
|
|
16
16
|
def initialize(**options)
|
|
17
17
|
@mutex = Mutex.new
|
|
18
|
-
@async = options.delete(:async)
|
|
19
|
-
@
|
|
20
|
-
@
|
|
21
|
-
@
|
|
22
|
-
@
|
|
23
|
-
@failure_count = 0
|
|
24
|
-
@degraded = false
|
|
25
|
-
@closed = false
|
|
18
|
+
@async = options.delete(:async)
|
|
19
|
+
@async_options = AsyncOptions.extract(options)
|
|
20
|
+
@async = @async_options.async?(@async)
|
|
21
|
+
@max_queue_size = @async_options.max_queue_size
|
|
22
|
+
@health = Core::Integration::DestinationHealth.new(counter_keys: %i[writes])
|
|
26
23
|
@appenders = build_appenders(
|
|
27
24
|
appenders: options.delete(:appenders),
|
|
28
25
|
appender: options.delete(:appender),
|
|
@@ -35,62 +32,50 @@ module Julewire
|
|
|
35
32
|
end
|
|
36
33
|
|
|
37
34
|
def write(value, severity:)
|
|
35
|
+
degradation_marker = @health.degradation_marker
|
|
38
36
|
log = log_for(value, severity: severity)
|
|
39
|
-
@
|
|
40
|
-
|
|
41
|
-
# Synchronous appenders write under our mutex; async appenders own
|
|
42
|
-
# queue synchronization and may block on bounded queues.
|
|
43
|
-
appender.log(log) unless @async
|
|
44
|
-
end
|
|
37
|
+
@health.increment(:writes)
|
|
38
|
+
@mutex.synchronize { appender.log(log) } unless @async
|
|
45
39
|
appender.log(log) if @async
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
@mutex.synchronize do
|
|
50
|
-
@failure_count += 1
|
|
51
|
-
@degraded = true
|
|
52
|
-
end
|
|
40
|
+
@health.clear_degradation_if_unchanged(degradation_marker)
|
|
41
|
+
rescue StandardError => e
|
|
42
|
+
@health.record_failure(e)
|
|
53
43
|
raise
|
|
54
44
|
end
|
|
55
45
|
|
|
56
46
|
def flush
|
|
57
|
-
|
|
58
|
-
|
|
47
|
+
degradation_marker = @health.degradation_marker
|
|
48
|
+
appender.flush
|
|
49
|
+
@health.clear_degradation_if_unchanged(degradation_marker)
|
|
59
50
|
nil
|
|
60
51
|
end
|
|
61
52
|
|
|
62
53
|
def close
|
|
63
|
-
appender.close
|
|
64
|
-
@
|
|
54
|
+
appender.close
|
|
55
|
+
@closed = true
|
|
65
56
|
nil
|
|
66
57
|
end
|
|
67
58
|
|
|
68
59
|
def reopen
|
|
60
|
+
degradation_marker = @health.degradation_marker
|
|
69
61
|
appender.reopen if appender.respond_to?(:reopen)
|
|
70
|
-
@
|
|
71
|
-
|
|
72
|
-
@degraded = false
|
|
73
|
-
end
|
|
62
|
+
@closed = false
|
|
63
|
+
@health.clear_degradation_if_unchanged(degradation_marker)
|
|
74
64
|
nil
|
|
75
65
|
end
|
|
76
66
|
|
|
77
67
|
def after_fork! = reopen
|
|
78
68
|
|
|
79
69
|
def health
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
closed: @closed,
|
|
83
|
-
degraded: @degraded,
|
|
84
|
-
failures: @failure_count,
|
|
85
|
-
writes: @write_count
|
|
86
|
-
}
|
|
87
|
-
end
|
|
70
|
+
snapshot = @health.snapshot(status: status)
|
|
71
|
+
counts = snapshot.fetch(:counts)
|
|
88
72
|
|
|
89
73
|
{
|
|
90
74
|
type: "semantic_logger",
|
|
91
|
-
status: status
|
|
75
|
+
status: snapshot.fetch(:status),
|
|
92
76
|
async: @async,
|
|
93
77
|
warnings: lifecycle_warnings,
|
|
78
|
+
last_failure: snapshot[:last_failure],
|
|
94
79
|
counts: {
|
|
95
80
|
writes: counts.fetch(:writes),
|
|
96
81
|
failures: counts.fetch(:failures)
|
|
@@ -140,12 +125,7 @@ module Julewire
|
|
|
140
125
|
def build_transport_appender(sink)
|
|
141
126
|
return sink unless @async
|
|
142
127
|
|
|
143
|
-
|
|
144
|
-
appender: sink,
|
|
145
|
-
lag_check_interval: @lag_check_interval,
|
|
146
|
-
lag_threshold_s: @lag_threshold_s,
|
|
147
|
-
max_queue_size: @max_queue_size
|
|
148
|
-
)
|
|
128
|
+
@async_options.build_appender(sink)
|
|
149
129
|
end
|
|
150
130
|
|
|
151
131
|
def log_for(value, severity:)
|
|
@@ -159,23 +139,20 @@ module Julewire
|
|
|
159
139
|
end
|
|
160
140
|
|
|
161
141
|
def semantic_level(value)
|
|
162
|
-
level =
|
|
163
|
-
level = LEVEL_MAP.fetch(level, level)
|
|
142
|
+
level = LEVEL_MAP.fetch(value, value)
|
|
164
143
|
return level if LEVEL_SET.key?(level)
|
|
165
144
|
|
|
166
145
|
:info
|
|
167
146
|
end
|
|
168
147
|
|
|
169
|
-
def status
|
|
170
|
-
return :closed if
|
|
171
|
-
return :degraded if appender.is_a?(::SemanticLogger::Appender::Async) && !appender.active?
|
|
172
|
-
return :degraded if counts.fetch(:degraded)
|
|
148
|
+
def status
|
|
149
|
+
return :closed if @closed
|
|
173
150
|
|
|
174
|
-
:
|
|
151
|
+
:degraded if async_appender_inactive?
|
|
175
152
|
end
|
|
176
153
|
|
|
177
|
-
def
|
|
178
|
-
@
|
|
154
|
+
def async_appender_inactive?
|
|
155
|
+
@async && !appender.active?
|
|
179
156
|
end
|
|
180
157
|
|
|
181
158
|
def lifecycle_warnings
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: julewire-semantic_logger
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0
|
|
4
|
+
version: 1.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alexander Grebennik
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 1.0
|
|
18
|
+
version: 1.1.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 1.0
|
|
25
|
+
version: 1.1.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: logger
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -84,6 +84,7 @@ files:
|
|
|
84
84
|
- lib/julewire-semantic_logger.rb
|
|
85
85
|
- lib/julewire/semantic_logger.rb
|
|
86
86
|
- lib/julewire/semantic_logger/appender_health.rb
|
|
87
|
+
- lib/julewire/semantic_logger/async_options.rb
|
|
87
88
|
- lib/julewire/semantic_logger/destination.rb
|
|
88
89
|
- lib/julewire/semantic_logger/exact_formatter.rb
|
|
89
90
|
- lib/julewire/semantic_logger/lifecycle_warnings.rb
|
|
@@ -111,7 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
111
112
|
- !ruby/object:Gem::Version
|
|
112
113
|
version: '0'
|
|
113
114
|
requirements: []
|
|
114
|
-
rubygems_version: 4.0.
|
|
115
|
+
rubygems_version: 4.0.16
|
|
115
116
|
specification_version: 4
|
|
116
117
|
summary: Semantic Logger transport adapter for Julewire.
|
|
117
118
|
test_files: []
|