logbrew-sdk 0.1.0 → 0.1.2
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/README.md +425 -21
- data/examples/Makefile +21 -1
- data/examples/automatic_delivery.rb +32 -0
- data/examples/first_useful_telemetry.rb +118 -0
- data/examples/http_trace_correlation.rb +99 -0
- data/examples/persistent_worker_delivery.rb +33 -0
- data/examples/real_user_smoke.rb +15 -0
- data/examples/sidekiq_tracing.rb +22 -0
- data/lib/logbrew/automatic_delivery.rb +493 -0
- data/lib/logbrew/bounded_event_queue.rb +196 -0
- data/lib/logbrew/event_batcher.rb +67 -0
- data/lib/logbrew/faraday_tracing.rb +55 -0
- data/lib/logbrew/http_client_tracing.rb +282 -0
- data/lib/logbrew/operation_tracing.rb +194 -0
- data/lib/logbrew/persistent_event_store.rb +403 -0
- data/lib/logbrew/product_timeline.rb +153 -0
- data/lib/logbrew/sidekiq.rb +466 -0
- data/lib/logbrew/span_events.rb +34 -0
- data/lib/logbrew/support_ticket.rb +187 -0
- data/lib/logbrew/trace.rb +298 -0
- data/lib/logbrew/traceparent.rb +145 -0
- data/lib/logbrew/worker_lifecycle.rb +211 -0
- data/lib/logbrew.rb +427 -40
- metadata +21 -2
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "logbrew"
|
|
5
|
+
|
|
6
|
+
incoming_traceparent = "00-4BF92F3577B34DA6A3CE929D0E0E4736-00F067AA0BA902B7-01"
|
|
7
|
+
trace_context = LogBrew::Traceparent.parse(incoming_traceparent)
|
|
8
|
+
child_span_id = "b7ad6b7169203331"
|
|
9
|
+
outgoing_headers = LogBrew::Traceparent.create_headers(
|
|
10
|
+
trace_id: trace_context.trace_id,
|
|
11
|
+
span_id: child_span_id,
|
|
12
|
+
trace_flags: trace_context.trace_flags
|
|
13
|
+
)
|
|
14
|
+
session_id = "sess_checkout_123"
|
|
15
|
+
route_template = "/checkout/:cart_id"
|
|
16
|
+
|
|
17
|
+
client = LogBrew::Client.create(
|
|
18
|
+
api_key: "LOGBREW_API_KEY",
|
|
19
|
+
sdk_name: "checkout-service",
|
|
20
|
+
sdk_version: "1.2.3"
|
|
21
|
+
)
|
|
22
|
+
client.release(
|
|
23
|
+
"evt_release_checkout",
|
|
24
|
+
"2026-06-02T10:00:00Z",
|
|
25
|
+
version: "1.2.3",
|
|
26
|
+
commit: "abc123def456",
|
|
27
|
+
metadata: { service: "checkout-service" }
|
|
28
|
+
)
|
|
29
|
+
client.environment(
|
|
30
|
+
"evt_environment_checkout",
|
|
31
|
+
"2026-06-02T10:00:01Z",
|
|
32
|
+
name: "production",
|
|
33
|
+
region: "global",
|
|
34
|
+
metadata: { service: "checkout-service" }
|
|
35
|
+
)
|
|
36
|
+
client.log(
|
|
37
|
+
"evt_log_checkout_started",
|
|
38
|
+
"2026-06-02T10:00:02Z",
|
|
39
|
+
message: "checkout request started",
|
|
40
|
+
level: "info",
|
|
41
|
+
logger: "checkout",
|
|
42
|
+
metadata: {
|
|
43
|
+
traceId: trace_context.trace_id,
|
|
44
|
+
sessionId: session_id,
|
|
45
|
+
routeTemplate: route_template
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
client.action(
|
|
49
|
+
"evt_action_checkout_submit",
|
|
50
|
+
"2026-06-02T10:00:03Z",
|
|
51
|
+
LogBrew::ProductTimeline.product_action(
|
|
52
|
+
name: "checkout.submit",
|
|
53
|
+
route_template: "https://shop.example/checkout/:cart_id?coupon=sample#review",
|
|
54
|
+
session_id: session_id,
|
|
55
|
+
trace_id: trace_context.trace_id,
|
|
56
|
+
screen: "Checkout",
|
|
57
|
+
funnel: "checkout",
|
|
58
|
+
step: "submit",
|
|
59
|
+
metadata: { cartTier: "gold" }
|
|
60
|
+
)
|
|
61
|
+
)
|
|
62
|
+
client.action(
|
|
63
|
+
"evt_action_payment_api",
|
|
64
|
+
"2026-06-02T10:00:04Z",
|
|
65
|
+
LogBrew::ProductTimeline.network_milestone(
|
|
66
|
+
route_template: "https://api.example/payments/:payment_id?card=sample",
|
|
67
|
+
method: "post",
|
|
68
|
+
status_code: 202,
|
|
69
|
+
duration_ms: 183.4,
|
|
70
|
+
session_id: session_id,
|
|
71
|
+
trace_id: trace_context.trace_id,
|
|
72
|
+
metadata: { dependency: "payments" }
|
|
73
|
+
)
|
|
74
|
+
)
|
|
75
|
+
client.metric(
|
|
76
|
+
"evt_metric_http_server_duration",
|
|
77
|
+
"2026-06-02T10:00:05Z",
|
|
78
|
+
name: "http.server.duration",
|
|
79
|
+
kind: "histogram",
|
|
80
|
+
value: 183.4,
|
|
81
|
+
unit: "ms",
|
|
82
|
+
temporality: "delta",
|
|
83
|
+
metadata: {
|
|
84
|
+
method: "POST",
|
|
85
|
+
routeTemplate: route_template,
|
|
86
|
+
statusCode: 202,
|
|
87
|
+
traceId: trace_context.trace_id
|
|
88
|
+
}
|
|
89
|
+
)
|
|
90
|
+
client.span(
|
|
91
|
+
"evt_span_checkout_request",
|
|
92
|
+
"2026-06-02T10:00:06Z",
|
|
93
|
+
LogBrew::Traceparent.span_attributes_from_traceparent(
|
|
94
|
+
trace_context,
|
|
95
|
+
LogBrew::TraceparentSpanInput.new(
|
|
96
|
+
name: "POST /checkout/:cart_id",
|
|
97
|
+
span_id: child_span_id,
|
|
98
|
+
duration_ms: 183.4,
|
|
99
|
+
metadata: {
|
|
100
|
+
sampled: trace_context.sampled,
|
|
101
|
+
routeTemplate: route_template,
|
|
102
|
+
sessionId: session_id
|
|
103
|
+
}
|
|
104
|
+
)
|
|
105
|
+
)
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
puts client.preview_json
|
|
109
|
+
|
|
110
|
+
transport = LogBrew::RecordingTransport.always_accept
|
|
111
|
+
response = client.shutdown(transport)
|
|
112
|
+
warn JSON.generate(
|
|
113
|
+
ok: true,
|
|
114
|
+
status: response.status_code,
|
|
115
|
+
attempts: response.attempts,
|
|
116
|
+
events: 7,
|
|
117
|
+
outgoingTraceparent: outgoing_headers.fetch("traceparent")
|
|
118
|
+
)
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "logbrew"
|
|
5
|
+
|
|
6
|
+
incoming_traceparent = "00-4BF92F3577B34DA6A3CE929D0E0E4736-00F067AA0BA902B7-01"
|
|
7
|
+
route_template = "/checkout/:cart_id"
|
|
8
|
+
|
|
9
|
+
client = LogBrew::Client.create(
|
|
10
|
+
api_key: "LOGBREW_API_KEY",
|
|
11
|
+
sdk_name: "checkout-rack-app",
|
|
12
|
+
sdk_version: "1.2.3"
|
|
13
|
+
)
|
|
14
|
+
client.release(
|
|
15
|
+
"evt_release_checkout_trace",
|
|
16
|
+
"2026-06-02T10:00:00Z",
|
|
17
|
+
version: "1.2.3",
|
|
18
|
+
commit: "abc123def456",
|
|
19
|
+
metadata: { service: "checkout" }
|
|
20
|
+
)
|
|
21
|
+
client.environment(
|
|
22
|
+
"evt_environment_checkout_trace",
|
|
23
|
+
"2026-06-02T10:00:01Z",
|
|
24
|
+
name: "production",
|
|
25
|
+
region: "global",
|
|
26
|
+
metadata: { service: "checkout" }
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
logger = LogBrew::Logger.new(
|
|
30
|
+
client: client,
|
|
31
|
+
logger_name: "checkout",
|
|
32
|
+
event_id_prefix: "ruby_http_trace",
|
|
33
|
+
metadata: { service: "checkout", ignored: [] },
|
|
34
|
+
timestamp_provider: -> { Time.utc(2026, 6, 2, 10, 0, 2) }
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
app = lambda do |env|
|
|
38
|
+
trace = LogBrew::Trace.current
|
|
39
|
+
raise "missing active trace" unless trace
|
|
40
|
+
|
|
41
|
+
logger.warn("checkout request is slow")
|
|
42
|
+
client.issue(
|
|
43
|
+
"evt_issue_checkout_trace",
|
|
44
|
+
"2026-06-02T10:00:03Z",
|
|
45
|
+
title: "PaymentProviderWarning",
|
|
46
|
+
level: "warning",
|
|
47
|
+
message: "payment provider latency crossed threshold",
|
|
48
|
+
metadata: { routeTemplate: route_template }
|
|
49
|
+
)
|
|
50
|
+
client.action(
|
|
51
|
+
"evt_action_checkout_trace",
|
|
52
|
+
"2026-06-02T10:00:04Z",
|
|
53
|
+
LogBrew::ProductTimeline.product_action(
|
|
54
|
+
name: "checkout.submit",
|
|
55
|
+
status: "running",
|
|
56
|
+
route_template: "https://shop.example/checkout/:cart_id?coupon=sample#review",
|
|
57
|
+
metadata: { cartTier: "gold" }
|
|
58
|
+
)
|
|
59
|
+
)
|
|
60
|
+
client.metric(
|
|
61
|
+
"evt_metric_checkout_trace",
|
|
62
|
+
"2026-06-02T10:00:05Z",
|
|
63
|
+
name: "http.server.duration",
|
|
64
|
+
kind: "histogram",
|
|
65
|
+
value: 183.4,
|
|
66
|
+
unit: "ms",
|
|
67
|
+
temporality: "delta",
|
|
68
|
+
metadata: { routeTemplate: route_template, statusCode: 202 }
|
|
69
|
+
)
|
|
70
|
+
env["logbrew.outgoing_traceparent"] = LogBrew::Trace.create_headers(trace).fetch("traceparent")
|
|
71
|
+
[202, { "content-type" => "text/plain" }, ["accepted"]]
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
rack = LogBrew::RackMiddleware.new(
|
|
75
|
+
app,
|
|
76
|
+
client: client,
|
|
77
|
+
event_id_prefix: "ruby_http_trace",
|
|
78
|
+
metadata: { service: "checkout", ignored: [] },
|
|
79
|
+
timestamp_provider: -> { Time.utc(2026, 6, 2, 10, 0, 6) }
|
|
80
|
+
)
|
|
81
|
+
env = {
|
|
82
|
+
"REQUEST_METHOD" => "POST",
|
|
83
|
+
"PATH_INFO" => route_template,
|
|
84
|
+
"QUERY_STRING" => "coupon=sample",
|
|
85
|
+
"HTTP_TRACEPARENT" => incoming_traceparent
|
|
86
|
+
}
|
|
87
|
+
response = rack.call(env)
|
|
88
|
+
raise "unexpected Rack response" unless response[0] == 202
|
|
89
|
+
|
|
90
|
+
puts client.preview_json
|
|
91
|
+
transport = LogBrew::RecordingTransport.always_accept
|
|
92
|
+
flush_response = client.shutdown(transport)
|
|
93
|
+
warn JSON.generate(
|
|
94
|
+
ok: true,
|
|
95
|
+
status: flush_response.status_code,
|
|
96
|
+
attempts: flush_response.attempts,
|
|
97
|
+
events: 7,
|
|
98
|
+
outgoingTraceparent: env.fetch("logbrew.outgoing_traceparent")
|
|
99
|
+
)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "logbrew"
|
|
5
|
+
|
|
6
|
+
queue_path = ENV.fetch("LOGBREW_PERSISTENT_QUEUE_PATH")
|
|
7
|
+
dropped = 0
|
|
8
|
+
last_drop_reason = nil
|
|
9
|
+
loaded_spec = Gem.loaded_specs["logbrew-sdk"]
|
|
10
|
+
client = LogBrew::Client.create(
|
|
11
|
+
api_key: "LOGBREW_API_KEY",
|
|
12
|
+
sdk_name: "logbrew-ruby-persistent-worker",
|
|
13
|
+
sdk_version: loaded_spec ? loaded_spec.version.to_s : "0.1.0",
|
|
14
|
+
persistent_queue_path: queue_path,
|
|
15
|
+
on_event_dropped: lambda do |notice|
|
|
16
|
+
dropped = notice.dropped_events
|
|
17
|
+
last_drop_reason = notice.reason
|
|
18
|
+
end
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
client.release("evt_worker_release", "2026-07-13T18:00:00Z", version: "2.0.0")
|
|
22
|
+
client.environment("evt_worker_environment", "2026-07-13T18:00:01Z", name: "production")
|
|
23
|
+
client.log("evt_worker_started", "2026-07-13T18:00:02Z", message: "worker started", level: "info")
|
|
24
|
+
|
|
25
|
+
response = client.shutdown(LogBrew::RecordingTransport.always_accept)
|
|
26
|
+
puts JSON.generate(
|
|
27
|
+
ok: response.status_code == 202,
|
|
28
|
+
status: response.status_code,
|
|
29
|
+
attempts: response.attempts,
|
|
30
|
+
batches: response.batches,
|
|
31
|
+
dropped: dropped,
|
|
32
|
+
lastDropReason: last_drop_reason
|
|
33
|
+
)
|
data/examples/real_user_smoke.rb
CHANGED
|
@@ -29,6 +29,19 @@ retry_response = retry_client.flush(
|
|
|
29
29
|
LogBrew::RecordingTransport.new([LogBrew::TransportError.network("temporary outage"), 202])
|
|
30
30
|
)
|
|
31
31
|
|
|
32
|
+
support_draft = LogBrew::SupportTicketDraft.create(
|
|
33
|
+
source: "sdk",
|
|
34
|
+
category: "ingest_failure",
|
|
35
|
+
title: "Telemetry flush failed",
|
|
36
|
+
description: "Flush returned usage_limit_exceeded",
|
|
37
|
+
trace_id: "4BF92F3577B34DA6A3CE929D0E0E4736",
|
|
38
|
+
diagnostics: {
|
|
39
|
+
apiKey: "lbw_ingest_hidden",
|
|
40
|
+
endpoint: "https://api.example/ingest?debug=true#frag",
|
|
41
|
+
error: RuntimeError.new("contains hidden token")
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
|
|
32
45
|
rejected_after_shutdown = false
|
|
33
46
|
begin
|
|
34
47
|
client.action("evt_action_002", "2026-06-02T10:00:06Z", name: "deploy", status: "success")
|
|
@@ -41,5 +54,7 @@ $stderr.puts JSON.generate(
|
|
|
41
54
|
status: response.status_code,
|
|
42
55
|
attempts: response.attempts,
|
|
43
56
|
retryAttempts: retry_response.attempts,
|
|
57
|
+
supportDraftRedacted: support_draft.dig("diagnostics", "apiKey") == "[redacted]",
|
|
58
|
+
supportDraftTrace: support_draft.fetch("trace_id"),
|
|
44
59
|
events: 6
|
|
45
60
|
)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "logbrew"
|
|
4
|
+
require "logbrew/sidekiq"
|
|
5
|
+
require "sidekiq"
|
|
6
|
+
|
|
7
|
+
transport = LogBrew::HttpTransport.new(timeout: 10)
|
|
8
|
+
client = LogBrew::Client.create_automatic(
|
|
9
|
+
api_key: ENV.fetch("LOGBREW_API_KEY"),
|
|
10
|
+
sdk_name: "checkout-worker",
|
|
11
|
+
sdk_version: "1.0.0",
|
|
12
|
+
transport: transport
|
|
13
|
+
)
|
|
14
|
+
instrumentation = LogBrew::Sidekiq::Instrumentation.create(client: client, max_retries: 25)
|
|
15
|
+
|
|
16
|
+
Sidekiq.configure_client { |config| instrumentation.register_client(config) }
|
|
17
|
+
Sidekiq.configure_server do |config|
|
|
18
|
+
instrumentation.register_client(config)
|
|
19
|
+
instrumentation.register_server(config)
|
|
20
|
+
config.on(:quiet) { instrumentation.quiet }
|
|
21
|
+
config.on(:shutdown) { instrumentation.shutdown }
|
|
22
|
+
end
|