Telemetry integration for LatticeStripe.
LatticeStripe emits :telemetry events for all
HTTP requests and webhook signature verification. Attach handlers to these events
to integrate with your observability stack (Prometheus, DataDog, OpenTelemetry, etc.).
HTTP Request Events
[:lattice_stripe, :request, :start]
Emitted before each HTTP request is dispatched.
Measurements:
| Key | Type | Description |
|---|---|---|
:system_time | integer | System time at span start (in native time units). See System.system_time/0. |
:monotonic_time | integer | Monotonic time at span start. See System.monotonic_time/0. |
Metadata:
| Key | Type | Description |
|---|---|---|
:method | atom | HTTP method atom: :get, :post, :delete |
:path | String.t() | Request path, e.g. "/v1/customers" |
:resource | String.t() | Parsed resource name, e.g. "customer", "payment_intent", "checkout.session" |
:operation | String.t() | Parsed operation name, e.g. "create", "retrieve", "list", "confirm" |
:api_version | String.t() | Stripe API version, e.g. "2026-03-25.dahlia" |
:stripe_account | String.t() | nil | Connected account ID from Stripe-Account header, or nil |
:telemetry_span_context | reference | Auto-injected by :telemetry.span/3 for correlating start/stop/exception events |
[:lattice_stripe, :request, :stop]
Emitted after each HTTP request completes (success or API error).
Measurements:
| Key | Type | Description |
|---|---|---|
:duration | integer | Elapsed time in native time units. Convert via System.convert_time_unit/3. |
:monotonic_time | integer | Monotonic time at span stop. |
Metadata (all start fields plus):
| Key | Type | Description |
|---|---|---|
:method | atom | HTTP method atom |
:path | String.t() | Request path |
:resource | String.t() | Parsed resource name |
:operation | String.t() | Parsed operation name |
:api_version | String.t() | Stripe API version |
:stripe_account | String.t() | nil | Connected account ID or nil |
:status | :ok | :error | Outcome of the request |
:http_status | integer | nil | HTTP status code (nil for connection errors) |
:request_id | String.t() | nil | Stripe request-id header value |
:attempts | integer | Total attempts made (1 = no retries, 2 = one retry, etc.) |
:retries | integer | Number of retries (attempts - 1) |
:error_type | atom | nil | Error type atom on failure: :connection_error, :card_error, etc. |
:idempotency_key | String.t() | nil | Idempotency key used (on error only) |
:telemetry_span_context | reference | Correlates with start event |
[:lattice_stripe, :request, :exception]
Emitted when an uncaught exception or throw escapes the request function. This covers
transport-level bugs, not API errors (which produce [:lattice_stripe, :request, :stop]
with status: :error). Handled automatically by :telemetry.span/3.
Measurements:
| Key | Type | Description |
|---|---|---|
:duration | integer | Elapsed time in native time units |
:monotonic_time | integer | Monotonic time at exception |
Metadata:
| Key | Type | Description |
|---|---|---|
:method | atom | HTTP method atom |
:path | String.t() | Request path |
:resource | String.t() | Parsed resource name |
:operation | String.t() | Parsed operation name |
:api_version | String.t() | Stripe API version |
:stripe_account | String.t() | nil | Connected account ID or nil |
:kind | :error | :exit | :throw | Exception kind |
:reason | any | Exception reason |
:stacktrace | list | Exception stacktrace |
:telemetry_span_context | reference | Correlates with start event |
[:lattice_stripe, :request, :retry]
Emitted for each retry attempt before the retry delay sleep.
Measurements:
| Key | Type | Description |
|---|---|---|
:attempt | integer | Retry attempt number (1 = first retry after initial failure) |
:delay_ms | integer | Delay in milliseconds before the retry |
Metadata:
| Key | Type | Description |
|---|---|---|
:method | atom | HTTP method atom |
:path | String.t() | Request path |
:error_type | atom | Error type that triggered the retry |
:status | integer | nil | HTTP status code (nil for connection errors) |
Webhook Verification Events
[:lattice_stripe, :webhook, :verify, :start]
Emitted before webhook signature verification begins.
Measurements:
| Key | Type | Description |
|---|---|---|
:system_time | integer | System time at span start |
:monotonic_time | integer | Monotonic time at span start |
Metadata:
| Key | Type | Description |
|---|---|---|
:path | String.t() | nil | Request path where webhook was received, if available |
:telemetry_span_context | reference | Auto-injected for span correlation |
[:lattice_stripe, :webhook, :verify, :stop]
Emitted after webhook signature verification completes.
Measurements:
| Key | Type | Description |
|---|---|---|
:duration | integer | Elapsed time in native time units |
:monotonic_time | integer | Monotonic time at span stop |
Metadata:
| Key | Type | Description |
|---|---|---|
:path | String.t() | nil | Request path where webhook was received |
:result | :ok | :error | Verification outcome |
:error_reason | atom | nil | Failure reason: :invalid_signature, :stale_timestamp, :missing_header, :no_valid_signature, or nil on success |
:telemetry_span_context | reference | Correlates with start event |
[:lattice_stripe, :webhook, :verify, :exception]
Emitted when an uncaught exception escapes webhook verification. Handled automatically by :telemetry.span/3.
Measurements:
| Key | Type | Description |
|---|---|---|
:duration | integer | Elapsed time in native time units |
:monotonic_time | integer | Monotonic time at exception |
Metadata:
| Key | Type | Description |
|---|---|---|
:path | String.t() | nil | Request path |
:kind | :error | :exit | :throw | Exception kind |
:reason | any | Exception reason |
:stacktrace | list | Exception stacktrace |
:telemetry_span_context | reference | Correlates with start event |
Usage with Telemetry.Metrics
If you're using telemetry_metrics with Prometheus or StatsD, here are ready-to-use metric
definitions:
[
# Request latency by resource and operation
Telemetry.Metrics.summary("lattice_stripe.request.stop.duration",
tags: [:resource, :operation, :status],
unit: {:native, :millisecond}
),
# Request throughput by outcome
Telemetry.Metrics.counter("lattice_stripe.request.stop",
tags: [:resource, :operation, :status]
),
# Latency distribution (p50/p95/p99)
Telemetry.Metrics.distribution("lattice_stripe.request.stop.duration",
tags: [:resource, :operation],
unit: {:native, :millisecond}
),
# Retry rate by error type
Telemetry.Metrics.counter("lattice_stripe.request.retry",
tags: [:error_type]
),
# Webhook verification outcomes
Telemetry.Metrics.counter("lattice_stripe.webhook.verify.stop",
tags: [:result, :error_reason]
)
]Invoice Auto-Advance Events
[:lattice_stripe, :invoice, :auto_advance_scheduled]
Emitted after a successful Invoice.create/3 when the returned invoice has
auto_advance: true. This signals that Stripe will automatically finalize the
draft invoice after approximately 1 hour. Attach a handler to log a warning or
trigger a monitoring alert when auto-advance invoices are created.
Measurements:
| Key | Type | Description |
|---|---|---|
:system_time | integer | System time at emission (in native time units). See System.system_time/0. |
Metadata:
| Key | Type | Description |
|---|---|---|
:invoice_id | String.t() | The created invoice ID (e.g. "in_123") |
:customer | String.t() | nil | Customer ID associated with the invoice, or nil |
Attaching a Default Logger
For instant visibility during development or to log all Stripe requests in production,
use attach_default_logger/1:
# In your application start/2:
LatticeStripe.Telemetry.attach_default_logger()
# Or with options:
LatticeStripe.Telemetry.attach_default_logger(level: :debug)This logs one line per request in the format:
[info] POST /v1/customers => 200 in 145ms (1 attempt, req_abc123)
[warn] GET /v1/payment_intents/pi_123 => :error in 301ms (3 attempts, connection_error)
[warning] Invoice in_123 (customer: cus_456) has auto_advance: true — Stripe will auto-finalize in ~1 hourConverting Duration
The :duration measurement is in native time units. Convert to milliseconds:
duration_ms = System.convert_time_unit(duration, :native, :millisecond)
Summary
Functions
Attaches a default structured logger for all LatticeStripe request events.
Functions
@spec attach_default_logger(keyword()) :: :ok
Attaches a default structured logger for all LatticeStripe request events.
Safe to call multiple times -- detaches any existing handler with the same ID first.
Options
:level-- log level (default::info)
Example
LatticeStripe.Telemetry.attach_default_logger(level: :info)Logs one line per completed request:
[info] POST /v1/customers => 200 in 145ms (1 attempt, req_abc123)
[warning] GET /v1/customers/cus_xxx => 404 in 12ms (1 attempt, req_yyy)Also logs a warning when an invoice is created with auto_advance: true:
[warning] Invoice in_123 (customer: cus_456) has auto_advance: true — Stripe will auto-finalize in ~1 hour