e-volv-logs 0.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 +7 -0
- data/LICENSE +21 -0
- data/README.md +230 -0
- data/lib/evolve_logs/carriers.rb +60 -0
- data/lib/evolve_logs/client.rb +383 -0
- data/lib/evolve_logs/context.rb +69 -0
- data/lib/evolve_logs/flags/cache.rb +87 -0
- data/lib/evolve_logs/flags/client.rb +316 -0
- data/lib/evolve_logs/flags/context.rb +128 -0
- data/lib/evolve_logs/flags/delivery.rb +391 -0
- data/lib/evolve_logs/flags/exposures.rb +128 -0
- data/lib/evolve_logs/flags/js_values.rb +228 -0
- data/lib/evolve_logs/flags/kernel.rb +334 -0
- data/lib/evolve_logs/flags/options.rb +64 -0
- data/lib/evolve_logs/flags/regex_cache.rb +72 -0
- data/lib/evolve_logs/flags/sse.rb +42 -0
- data/lib/evolve_logs/flags.rb +65 -0
- data/lib/evolve_logs/http.rb +48 -0
- data/lib/evolve_logs/logger.rb +51 -0
- data/lib/evolve_logs/rack_middleware.rb +33 -0
- data/lib/evolve_logs/redact.rb +40 -0
- data/lib/evolve_logs/version.rb +5 -0
- data/lib/evolve_logs.rb +179 -0
- metadata +95 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module EvolveLogs
|
|
4
|
+
module Flags
|
|
5
|
+
# Minimal text/event-stream parser: `event` and `data` fields, a blank
|
|
6
|
+
# line dispatches one event, `data` lines join with "\n". Port of
|
|
7
|
+
# logs-js/src/flags/sse.ts (and S2's Python).
|
|
8
|
+
class SseParser
|
|
9
|
+
def initialize(&on_event)
|
|
10
|
+
@on_event = on_event
|
|
11
|
+
@buffer = +""
|
|
12
|
+
@event = "message"
|
|
13
|
+
@data = []
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def push(text)
|
|
17
|
+
@buffer << text
|
|
18
|
+
while (idx = @buffer.index("\n"))
|
|
19
|
+
line = @buffer[0...idx]
|
|
20
|
+
@buffer = @buffer[(idx + 1)..-1] || +""
|
|
21
|
+
line = line.chomp("\r")
|
|
22
|
+
if line.empty?
|
|
23
|
+
@on_event.call(@event, @data.join("\n")) unless @data.empty?
|
|
24
|
+
@event = "message"
|
|
25
|
+
@data = []
|
|
26
|
+
next
|
|
27
|
+
end
|
|
28
|
+
next if line.start_with?(":")
|
|
29
|
+
|
|
30
|
+
field, colon, value = line.partition(":")
|
|
31
|
+
value = value[1..-1] if colon == ":" && value.start_with?(" ")
|
|
32
|
+
if field == "event"
|
|
33
|
+
@event = value
|
|
34
|
+
elsif field == "data"
|
|
35
|
+
@data << value
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
nil
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# e-volv Launch flags for the Ruby Observer SDK (docs/LAUNCH-SDK.md).
|
|
4
|
+
#
|
|
5
|
+
# One init and one key serve both logs and flags: the flags client binds to
|
|
6
|
+
# the Observer client's key and runs flag delivery on its own background
|
|
7
|
+
# thread, because a held-open stream would stall log flushing.
|
|
8
|
+
#
|
|
9
|
+
# Evaluation is synchronous, never raises and never performs I/O — the
|
|
10
|
+
# delivery state machine (PORTING.md "Delivery behaviour") owns the network
|
|
11
|
+
# on its own thread.
|
|
12
|
+
|
|
13
|
+
require "digest/sha1"
|
|
14
|
+
require "json"
|
|
15
|
+
require "net/http"
|
|
16
|
+
require "securerandom"
|
|
17
|
+
require "tempfile"
|
|
18
|
+
require "tmpdir"
|
|
19
|
+
require "uri"
|
|
20
|
+
|
|
21
|
+
module EvolveLogs
|
|
22
|
+
module Flags
|
|
23
|
+
# The production control plane (contract §2).
|
|
24
|
+
DEFAULT_FLAGS_BASE = "https://api.e-volv.io/api/public/v1/flags"
|
|
25
|
+
|
|
26
|
+
module_function
|
|
27
|
+
|
|
28
|
+
# base_url resolves the flags endpoint: an explicit flags url wins; else
|
|
29
|
+
# the origin of the Observer ingest url; else production. Never throws.
|
|
30
|
+
def base_url(observer_url, flags_url)
|
|
31
|
+
return flags_url.sub(%r{/+\z}, "") if flags_url.is_a?(String) && !flags_url.empty?
|
|
32
|
+
|
|
33
|
+
if observer_url.is_a?(String) && !observer_url.empty?
|
|
34
|
+
begin
|
|
35
|
+
uri = URI.parse(observer_url)
|
|
36
|
+
unless uri.scheme.nil? || uri.host.nil?
|
|
37
|
+
netloc = uri.host
|
|
38
|
+
netloc = "#{netloc}:#{uri.port}" if uri.port && uri.default_port != uri.port
|
|
39
|
+
return "#{uri.scheme}://#{netloc}/api/public/v1/flags"
|
|
40
|
+
end
|
|
41
|
+
rescue StandardError
|
|
42
|
+
# Fall through to production, like the JS URL() catch.
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
DEFAULT_FLAGS_BASE
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# full_jitter_seconds is the reconnect/retry sleep (contract §4):
|
|
49
|
+
# random(0, min(60, 2^attempt)) seconds.
|
|
50
|
+
def full_jitter_seconds(attempt, rng = Random)
|
|
51
|
+
rng.rand * [60, 2**[0, attempt].max].min
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
require "evolve_logs/flags/js_values"
|
|
57
|
+
require "evolve_logs/flags/context"
|
|
58
|
+
require "evolve_logs/flags/regex_cache"
|
|
59
|
+
require "evolve_logs/flags/kernel"
|
|
60
|
+
require "evolve_logs/flags/options"
|
|
61
|
+
require "evolve_logs/flags/cache"
|
|
62
|
+
require "evolve_logs/flags/exposures"
|
|
63
|
+
require "evolve_logs/flags/sse"
|
|
64
|
+
require "evolve_logs/flags/delivery"
|
|
65
|
+
require "evolve_logs/flags/client"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
|
|
5
|
+
module EvolveLogs
|
|
6
|
+
# Outbound traceparent injection, monkeypatch-free — helper modules you opt
|
|
7
|
+
# into per call site instead of patching Net::HTTP or Faraday globally.
|
|
8
|
+
module HTTP
|
|
9
|
+
# inject_traceparent sets the W3C traceparent header on a Net::HTTP
|
|
10
|
+
# request (or anything with Net::HTTPHeader-style #[]/#[]=) when called
|
|
11
|
+
# inside a trace. An existing traceparent header is never overwritten.
|
|
12
|
+
#
|
|
13
|
+
# request = Net::HTTP::Post.new(uri)
|
|
14
|
+
# EvolveLogs::HTTP.inject_traceparent(request)
|
|
15
|
+
# http.request(request)
|
|
16
|
+
def self.inject_traceparent(request)
|
|
17
|
+
tp = EvolveLogs.traceparent
|
|
18
|
+
if tp && (request["traceparent"].nil? || request["traceparent"].empty?)
|
|
19
|
+
request["traceparent"] = tp
|
|
20
|
+
end
|
|
21
|
+
request
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# FaradayMiddleware is a duck-typed Faraday middleware (no faraday require;
|
|
26
|
+
# any object with #call(env) works). Add it where the connection is built:
|
|
27
|
+
#
|
|
28
|
+
# conn = Faraday.new(url: "https://internal") do |builder|
|
|
29
|
+
# builder.use EvolveLogs::FaradayMiddleware
|
|
30
|
+
# builder.adapter Faraday.default_adapter
|
|
31
|
+
# end
|
|
32
|
+
#
|
|
33
|
+
# Outbound requests made inside a trace carry the traceparent header; an
|
|
34
|
+
# existing header is never overwritten.
|
|
35
|
+
class FaradayMiddleware
|
|
36
|
+
def initialize(app, _options = {})
|
|
37
|
+
@app = app
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def call(env)
|
|
41
|
+
headers = env.request_headers
|
|
42
|
+
tp = EvolveLogs.traceparent
|
|
43
|
+
existing = headers["traceparent"]
|
|
44
|
+
headers["traceparent"] = tp if tp && (existing.nil? || existing.empty?)
|
|
45
|
+
@app.call(env)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "logger"
|
|
4
|
+
|
|
5
|
+
module EvolveLogs
|
|
6
|
+
# Logger is a stdlib ::Logger subclass that ships every line to Observer in
|
|
7
|
+
# addition to the underlying log device, so
|
|
8
|
+
#
|
|
9
|
+
# Rails.logger = EvolveLogs::Logger.new($stdout)
|
|
10
|
+
#
|
|
11
|
+
# keeps the familiar Logger interface while every event reaches the ingest
|
|
12
|
+
# with its severity mapped to the OTel number. Logging an Exception as the
|
|
13
|
+
# message (`Rails.logger.error(err)`) becomes an exception.* error event.
|
|
14
|
+
class Logger < ::Logger
|
|
15
|
+
SEVERITY_TO_OTEL = {
|
|
16
|
+
::Logger::DEBUG => EvolveLogs::OTEL_DEBUG,
|
|
17
|
+
::Logger::INFO => EvolveLogs::OTEL_INFO,
|
|
18
|
+
::Logger::WARN => EvolveLogs::OTEL_WARN,
|
|
19
|
+
::Logger::ERROR => EvolveLogs::OTEL_ERROR,
|
|
20
|
+
::Logger::FATAL => EvolveLogs::OTEL_FATAL,
|
|
21
|
+
::Logger::UNKNOWN => EvolveLogs::OTEL_FATAL,
|
|
22
|
+
}.freeze
|
|
23
|
+
|
|
24
|
+
def initialize(logdev, client: nil)
|
|
25
|
+
@evolve_client = client
|
|
26
|
+
super(logdev)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def add(severity, message = nil, progname = nil, &block)
|
|
30
|
+
severity ||= ::Logger::UNKNOWN
|
|
31
|
+
raw = message.nil? ? (block ? block.call : progname) : message
|
|
32
|
+
emit_to_evolve(severity, raw)
|
|
33
|
+
super(severity, message, progname, &block)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def emit_to_evolve(severity, raw)
|
|
39
|
+
client = @evolve_client || EvolveLogs.get_client
|
|
40
|
+
return if client.nil? || !client.enabled?
|
|
41
|
+
if raw.is_a?(Exception)
|
|
42
|
+
client.exception(raw)
|
|
43
|
+
else
|
|
44
|
+
otel = SEVERITY_TO_OTEL[severity] || EvolveLogs::OTEL_INFO
|
|
45
|
+
client.log(otel, raw.nil? ? "" : raw.to_s)
|
|
46
|
+
end
|
|
47
|
+
rescue StandardError
|
|
48
|
+
nil
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module EvolveLogs
|
|
4
|
+
# RackMiddleware is plain Rack middleware: one root span per request,
|
|
5
|
+
# continuing an inbound traceparent header (or starting a fresh trace when
|
|
6
|
+
# there is none). Rack is a soft dependency — the middleware is duck-typed
|
|
7
|
+
# on #call and nothing requires "rack".
|
|
8
|
+
#
|
|
9
|
+
# use EvolveLogs::RackMiddleware
|
|
10
|
+
#
|
|
11
|
+
# An app that raises ends the "http.request" span as failed and is
|
|
12
|
+
# re-raised, so the server sees the crash exactly as it would without the
|
|
13
|
+
# SDK.
|
|
14
|
+
class RackMiddleware
|
|
15
|
+
def initialize(app, client: nil, span_name: "http.request")
|
|
16
|
+
@app = app
|
|
17
|
+
@client = client
|
|
18
|
+
@span_name = span_name
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def call(env)
|
|
22
|
+
client = @client || EvolveLogs.get_client
|
|
23
|
+
inbound = env["HTTP_TRACEPARENT"]
|
|
24
|
+
EvolveLogs.run_with_traceparent(inbound) do
|
|
25
|
+
attrs = {
|
|
26
|
+
"http.method" => env["REQUEST_METHOD"].to_s,
|
|
27
|
+
"http.path" => env["PATH_INFO"].to_s,
|
|
28
|
+
}
|
|
29
|
+
client.span(@span_name, attrs) { @app.call(env) }
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module EvolveLogs
|
|
4
|
+
# The backstop list: attribute keys matching this pattern are redacted
|
|
5
|
+
# before anything leaves the process. Pinned by the shared contract;
|
|
6
|
+
# redact_keys extends it (docs/OBSERVER-SDK.md).
|
|
7
|
+
BACKSTOP_PATTERN = /password|secret|token|authorization|cookie|set-cookie|api[-_]?key/i.freeze
|
|
8
|
+
REDACTED = "[redacted]"
|
|
9
|
+
|
|
10
|
+
# Redactor deep-walks hashes and arrays; values whose key matches the
|
|
11
|
+
# pattern (case-insensitive substring) are replaced with "[redacted]".
|
|
12
|
+
class Redactor
|
|
13
|
+
def initialize(extra_keys = nil)
|
|
14
|
+
sources = [BACKSTOP_PATTERN.source]
|
|
15
|
+
Array(extra_keys).each { |k| sources << Regexp.escape(k.to_s) }
|
|
16
|
+
@pattern = Regexp.new(sources.join("|"), Regexp::IGNORECASE)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def call(attrs)
|
|
20
|
+
walk(attrs || {})
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def walk(value)
|
|
26
|
+
case value
|
|
27
|
+
when Hash
|
|
28
|
+
out = {}
|
|
29
|
+
value.each do |key, val|
|
|
30
|
+
out[key] = @pattern.match?(key.to_s) ? REDACTED : walk(val)
|
|
31
|
+
end
|
|
32
|
+
out
|
|
33
|
+
when Array
|
|
34
|
+
value.map { |val| walk(val) }
|
|
35
|
+
else
|
|
36
|
+
value
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
data/lib/evolve_logs.rb
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# e-volv Observer SDK for Ruby (gem: e-volv-logs).
|
|
4
|
+
#
|
|
5
|
+
# Speaks the one wire contract documented in docs/OBSERVER-SDK.md: batches
|
|
6
|
+
# events (200 events / 2 s / 512 KB), gzips the payload, retries 429 with
|
|
7
|
+
# backoff and 413 by halving, redacts sensitive attribute keys before
|
|
8
|
+
# enqueue, and carries W3C traceparent in Thread/Fiber-local context.
|
|
9
|
+
# Everything is fail-silent: a logging SDK never raises into user code.
|
|
10
|
+
|
|
11
|
+
require "json"
|
|
12
|
+
require "zlib"
|
|
13
|
+
require "securerandom"
|
|
14
|
+
require "net/http"
|
|
15
|
+
require "uri"
|
|
16
|
+
|
|
17
|
+
module EvolveLogs
|
|
18
|
+
# Shared batching and retry numbers — identical in every SDK
|
|
19
|
+
# (docs/OBSERVER-SDK.md §"The contract every SDK speaks").
|
|
20
|
+
MAX_BATCH = 200
|
|
21
|
+
FLUSH_INTERVAL = 2.0
|
|
22
|
+
MAX_PAYLOAD_BYTES = 512 * 1024
|
|
23
|
+
MAX_BUFFER = MAX_BATCH * 2 # then the oldest events are dropped
|
|
24
|
+
MAX_ATTEMPTS = 3
|
|
25
|
+
BACKOFF_BASE = 0.5 # seconds, doubling
|
|
26
|
+
BACKOFF_MAX = 10.0
|
|
27
|
+
DELIVERY_TIMEOUT = 10 # seconds per request; matches the ingest's budget
|
|
28
|
+
|
|
29
|
+
# OTel severity numbers (trace 1 … fatal 21).
|
|
30
|
+
OTEL_TRACE = 1
|
|
31
|
+
OTEL_DEBUG = 5
|
|
32
|
+
OTEL_INFO = 9
|
|
33
|
+
OTEL_WARN = 13
|
|
34
|
+
OTEL_ERROR = 17
|
|
35
|
+
OTEL_FATAL = 21
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
require "evolve_logs/version"
|
|
39
|
+
require "evolve_logs/context"
|
|
40
|
+
require "evolve_logs/redact"
|
|
41
|
+
require "evolve_logs/flags"
|
|
42
|
+
require "evolve_logs/client"
|
|
43
|
+
require "evolve_logs/logger"
|
|
44
|
+
require "evolve_logs/rack_middleware"
|
|
45
|
+
require "evolve_logs/carriers"
|
|
46
|
+
require "evolve_logs/http"
|
|
47
|
+
|
|
48
|
+
module EvolveLogs
|
|
49
|
+
# Registry of live clients, flushed from the at_exit hook at the bottom of
|
|
50
|
+
# this file. A process that never calls init has nothing to flush.
|
|
51
|
+
module Registry
|
|
52
|
+
@clients = []
|
|
53
|
+
@mutex = Mutex.new
|
|
54
|
+
|
|
55
|
+
def self.register(client)
|
|
56
|
+
@mutex.synchronize { @clients << client }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def self.flush_all
|
|
60
|
+
clients = @mutex.synchronize { @clients.dup }
|
|
61
|
+
clients.each(&:flush)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
@default_mutex = Mutex.new
|
|
66
|
+
@default_client = nil
|
|
67
|
+
|
|
68
|
+
class << self
|
|
69
|
+
# init installs the module-level default client built from the keyword
|
|
70
|
+
# options and returns it. Module-level helpers (EvolveLogs.info,
|
|
71
|
+
# EvolveLogs.span, …) delegate to it; a later init replaces the previous
|
|
72
|
+
# default. With an empty key or url the client is a no-op and warns once
|
|
73
|
+
# on stderr. `flags:` carries the Launch flags options (a
|
|
74
|
+
# EvolveLogs::Flags::Options or an options Hash); the flags handle is
|
|
75
|
+
# available as client.flags / EvolveLogs.flags.
|
|
76
|
+
def init(key: nil, url: nil, service: nil, environment: nil, release: nil,
|
|
77
|
+
redact_keys: nil, sample_rate: 1.0, flags: nil, **opts)
|
|
78
|
+
install(Client.new(key: key, url: url, service: service,
|
|
79
|
+
environment: environment, release: release,
|
|
80
|
+
redact_keys: redact_keys, sample_rate: sample_rate,
|
|
81
|
+
flags: flags, **opts))
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# install replaces the module-level default client (used by tests and
|
|
85
|
+
# custom wiring) and returns it.
|
|
86
|
+
def install(client)
|
|
87
|
+
@default_mutex.synchronize { @default_client = client }
|
|
88
|
+
client
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# get_client returns the current default client, lazily a silent no-op —
|
|
92
|
+
# the one-warning contract belongs to init, not to the pre-init default.
|
|
93
|
+
def get_client
|
|
94
|
+
@default_mutex.synchronize { @default_client } ||
|
|
95
|
+
install(Client.new(key: nil, url: nil, silent: true))
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# log enqueues an event at the given OTel severity number.
|
|
99
|
+
def log(severity, message, attrs = nil)
|
|
100
|
+
get_client.log(severity, message, attrs)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def trace(message, attrs = nil)
|
|
104
|
+
log(OTEL_TRACE, message, attrs)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def debug(message, attrs = nil)
|
|
108
|
+
log(OTEL_DEBUG, message, attrs)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def info(message, attrs = nil)
|
|
112
|
+
log(OTEL_INFO, message, attrs)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def warn(message, attrs = nil)
|
|
116
|
+
log(OTEL_WARN, message, attrs)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def error(message, attrs = nil)
|
|
120
|
+
log(OTEL_ERROR, message, attrs)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def fatal(message, attrs = nil)
|
|
124
|
+
log(OTEL_FATAL, message, attrs)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# exception logs err as an error event: severity 17, err.message as the
|
|
128
|
+
# message, and exception.type / exception.message / exception.stack
|
|
129
|
+
# attributes, which make the event an error occurrence on the group page.
|
|
130
|
+
def exception(err, attrs = nil)
|
|
131
|
+
get_client.exception(err, attrs)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# span opens a child span of the current trace (or a new root trace) and
|
|
135
|
+
# runs the block inside it. A raised exception ends the span failed —
|
|
136
|
+
# exception.* attrs, severity 17 — and is re-raised, so the caller sees
|
|
137
|
+
# the failure exactly as before.
|
|
138
|
+
def span(name, attrs = nil, &block)
|
|
139
|
+
get_client.span(name, attrs, &block)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# traceparent returns the W3C traceparent of the current trace,
|
|
143
|
+
# "00-<traceId>-<spanId>-01", or nil outside a trace.
|
|
144
|
+
def traceparent
|
|
145
|
+
Context.traceparent
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# run_with_traceparent runs the block with the next hop of the trace
|
|
149
|
+
# named by a W3C traceparent header — the consumer side of a queue, the
|
|
150
|
+
# callee side of an inbound request. An absent or malformed header starts
|
|
151
|
+
# a fresh root trace.
|
|
152
|
+
def run_with_traceparent(header)
|
|
153
|
+
Context.with(Context.hop(header)) { yield }
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def current_context
|
|
157
|
+
Context.current
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# flush sends pending events on the default client; safe to call
|
|
161
|
+
# repeatedly (also from an at_exit hook).
|
|
162
|
+
def flush
|
|
163
|
+
get_client.flush
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# flags returns the default client's Launch flags handle
|
|
167
|
+
# (docs/LAUNCH-SDK.md §3).
|
|
168
|
+
def flags
|
|
169
|
+
get_client.flags
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# dropped returns the default client's dropped-event counter.
|
|
173
|
+
def dropped
|
|
174
|
+
get_client.dropped
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
at_exit { EvolveLogs::Registry.flush_all }
|
metadata
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: e-volv-logs
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- e-volv
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-09-14 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: minitest
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '5.0'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '5.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '12.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '12.0'
|
|
41
|
+
description: Batched log shipping, trace context and error capture for the e-volv
|
|
42
|
+
Observer ingest. Pure Ruby + stdlib; Rack middleware, Rails.logger bridge, ActiveJob
|
|
43
|
+
and Sidekiq carriers, Net::HTTP and Faraday injection.
|
|
44
|
+
email:
|
|
45
|
+
- support@e-volv.io
|
|
46
|
+
executables: []
|
|
47
|
+
extensions: []
|
|
48
|
+
extra_rdoc_files: []
|
|
49
|
+
files:
|
|
50
|
+
- LICENSE
|
|
51
|
+
- README.md
|
|
52
|
+
- lib/evolve_logs.rb
|
|
53
|
+
- lib/evolve_logs/carriers.rb
|
|
54
|
+
- lib/evolve_logs/client.rb
|
|
55
|
+
- lib/evolve_logs/context.rb
|
|
56
|
+
- lib/evolve_logs/flags.rb
|
|
57
|
+
- lib/evolve_logs/flags/cache.rb
|
|
58
|
+
- lib/evolve_logs/flags/client.rb
|
|
59
|
+
- lib/evolve_logs/flags/context.rb
|
|
60
|
+
- lib/evolve_logs/flags/delivery.rb
|
|
61
|
+
- lib/evolve_logs/flags/exposures.rb
|
|
62
|
+
- lib/evolve_logs/flags/js_values.rb
|
|
63
|
+
- lib/evolve_logs/flags/kernel.rb
|
|
64
|
+
- lib/evolve_logs/flags/options.rb
|
|
65
|
+
- lib/evolve_logs/flags/regex_cache.rb
|
|
66
|
+
- lib/evolve_logs/flags/sse.rb
|
|
67
|
+
- lib/evolve_logs/http.rb
|
|
68
|
+
- lib/evolve_logs/logger.rb
|
|
69
|
+
- lib/evolve_logs/rack_middleware.rb
|
|
70
|
+
- lib/evolve_logs/redact.rb
|
|
71
|
+
- lib/evolve_logs/version.rb
|
|
72
|
+
homepage: https://e-volv.io
|
|
73
|
+
licenses:
|
|
74
|
+
- MIT
|
|
75
|
+
metadata: {}
|
|
76
|
+
post_install_message:
|
|
77
|
+
rdoc_options: []
|
|
78
|
+
require_paths:
|
|
79
|
+
- lib
|
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
81
|
+
requirements:
|
|
82
|
+
- - ">="
|
|
83
|
+
- !ruby/object:Gem::Version
|
|
84
|
+
version: '2.6'
|
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0'
|
|
90
|
+
requirements: []
|
|
91
|
+
rubygems_version: 3.5.22
|
|
92
|
+
signing_key:
|
|
93
|
+
specification_version: 4
|
|
94
|
+
summary: e-volv Observer SDK for Ruby
|
|
95
|
+
test_files: []
|