logbrew

package module
v0.1.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 23, 2026 License: MIT Imports: 34 Imported by: 0

README

logbrew

LogBrew logo

Public Go SDK for creating LogBrew event batches, validating them locally, and flushing them through a transport.

Install

The current public module declares Go 1.24.0. If an existing application's go.mod declares an older Go version, review its compiler and deployment support policy and upgrade intentionally before installing LogBrew. Automated setup must not silently raise an application's Go version.

go get github.com/LogBrewCo/sdk/go/logbrew@latest

The explicit @latest query keeps copied setup snippets on the current public module release. Run the same command to upgrade an existing requirement before debugging an endpoint or transport failure.

Set LOGBREW_SERVER_API_KEY to a project-scoped server ingest key before starting the app.

If you are automating setup, follow the same safe path as a person. Do not ask a person to paste an ingest key, and do not treat a missing environment variable as a reason to stop setup. First run logbrew status --json. When it reports approved authentication, create a temporary project and key with the commands below, continue without a dashboard handoff, and confirm authenticated readback. Only stop for account authentication when the status command reports that no approved authentication is available.

Create a Project and Confirm Hosted Delivery

Use LogBrew CLI 0.1.32 or newer with approved account authentication to create the project. This requires no dashboard sign-in. The destination key file must not already exist. The CLI creates it with owner-only permissions and never prints the one-time key or its file path. The shell flow below targets macOS and Linux; the CLI stops before creating a project when it cannot confirm owner-only storage for the one-time key.

logbrew status --json
install -d -m 700 "$HOME/.logbrew"

project_result="$(
  logbrew projects create go-service \
    --runtime go \
    --environment development \
    --ingest-key-file "$HOME/.logbrew/go-service.ingest" \
    --json
)"
export LOGBREW_PROJECT_ID="$(jq -er '.project.id' <<<"$project_result")"
unset project_result
export LOGBREW_SERVER_API_KEY="$(< "$HOME/.logbrew/go-service.ingest")"

Send one safe application-owned log through the hosted HTTP transport:

package main

import (
  "fmt"
  "os"
  "strings"
  "time"

  "github.com/LogBrewCo/sdk/go/logbrew"
)

func main() {
  apiKey := strings.TrimSpace(os.Getenv("LOGBREW_SERVER_API_KEY"))
  if apiKey == "" {
    panic("LOGBREW_SERVER_API_KEY is required")
  }

  transport, err := logbrew.NewHTTPTransport(logbrew.HTTPTransportConfig{})
  must(err)
  client, err := logbrew.NewClient(logbrew.Config{
    APIKey:     apiKey,
    SDKName:    "go-service",
    SDKVersion: "1.0.0",
  })
  must(err)

  must(client.Log("evt_go_first_event", time.Now().UTC().Format(time.RFC3339Nano), logbrew.LogAttributes{
    Message: "go first event",
    Level:   "info",
    Logger:  "go-service",
  }))
  response, err := client.Shutdown(transport)
  must(err)
  fmt.Printf("hosted delivery accepted: %d\n", response.StatusCode)
}

func must(err error) {
  if err != nil {
    panic(err)
  }
}

Run the app, then check setup and read the same project through the authenticated CLI session:

logbrew doctor --project "$LOGBREW_PROJECT_ID" --json
logbrew read logs --project "$LOGBREW_PROJECT_ID" \
  --search "go first event" \
  --since 1h \
  --json

A successful ingest response confirms submission. The authenticated read confirms that the event is indexed for the same project. If you no longer need the temporary project, archive it and remove its revoked one-time key file:

unset LOGBREW_SERVER_API_KEY
logbrew projects archive "$LOGBREW_PROJECT_ID" --yes --json
rm -f "$HOME/.logbrew/go-service.ingest"
unset LOGBREW_PROJECT_ID

Local Preview Example

package main

import (
  "encoding/json"
  "fmt"
  "os"

  "github.com/LogBrewCo/sdk/go/logbrew"
)

func main() {
  client, err := logbrew.NewClient(logbrew.Config{
    APIKey:               "LOGBREW_API_KEY",
    SDKName:              "logbrew-go",
    SDKVersion:           "0.1.0",
    DisableRuntimeContext: true, // Keep this language-neutral parity preview minimal.
  })
  if err != nil {
    panic(err)
  }

  must(client.Release("evt_release_001", "2026-06-02T10:00:00Z", logbrew.ReleaseAttributes{
    Version: "1.2.3",
    Commit:  "abc123def456",
    Notes:   "Public release marker",
  }))
  must(client.Environment("evt_environment_001", "2026-06-02T10:00:01Z", logbrew.EnvironmentAttributes{
    Name:   "production",
    Region: "global",
  }))
  must(client.Issue("evt_issue_001", "2026-06-02T10:00:02Z", logbrew.IssueAttributes{
    Title:   "Checkout timeout",
    Level:   "error",
    Message: "Request timed out after retry budget",
  }))
  must(client.Log("evt_log_001", "2026-06-02T10:00:03Z", logbrew.LogAttributes{
    Message: "worker started",
    Level:   "info",
    Logger:  "job-runner",
  }))
  duration := 12.5
  must(client.Span("evt_span_001", "2026-06-02T10:00:04Z", logbrew.SpanAttributes{
    Name:       "GET /health",
    TraceID:    "trace_001",
    SpanID:     "span_001",
    Status:     "ok",
    DurationMs: &duration,
  }))
  must(client.Action("evt_action_001", "2026-06-02T10:00:05Z", logbrew.ActionAttributes{
    Name:   "deploy",
    Status: "success",
  }))

  payload, err := client.PreviewJSON()
  must(err)
  fmt.Println(payload)

  response, err := client.Shutdown(logbrew.AlwaysAcceptTransport())
  must(err)
  _ = json.NewEncoder(os.Stderr).Encode(map[string]any{
    "ok": true,
    "status": response.StatusCode,
    "attempts": response.Attempts,
    "events": 6,
  })
}

func must(err error) {
  if err != nil {
    panic(err)
  }
}

This example intentionally uses the in-memory AlwaysAcceptTransport. It makes no network request and never proves hosted delivery or event visibility. Use a clearly fake placeholder like LOGBREW_API_KEY only in local examples. Call Flush or Shutdown to send queued events through a transport, and use PreviewJSON when you want a stable local JSON preview before sending anything. For production delivery and authenticated readback, use the hosted flow above.

Shared Telemetry Context

Config.Context adds one versioned, typed context to every event. Event-level Context fields merge on top: resource sections and tags merge by field, while an event trace, session, or subject replaces the corresponding client section. Inputs are validated and detached before queueing, so later caller mutation cannot rewrite evidence that was already accepted. Use ValidateTelemetryContext to preflight one value or MergeTelemetryContexts to apply the client/event rules without queueing an event.

client, err := logbrew.NewClient(logbrew.Config{
  APIKey:     "LOGBREW_API_KEY",
  SDKName:    "checkout-service",
  SDKVersion: "1.2.3",
  Context: &logbrew.TelemetryContext{
    SchemaVersion: 1,
    Resource: &logbrew.TelemetryResource{
      Service:    &logbrew.TelemetryNamedVersion{Name: "checkout-service", Version: "1.2.3"},
      Deployment: &logbrew.TelemetryDeployment{Environment: "production", Release: "checkout@1.2.3"},
      Application: &logbrew.TelemetryApplication{
        Name: "checkout-api", Version: "1.2.3", Build: "20260803.1",
      },
    },
    Tags: map[string]string{"region": "eu", "plan": "team"},
  },
})
must(err)

sampled := true
requestContext := &logbrew.TelemetryContext{
  SchemaVersion: 1,
  Trace: &logbrew.TelemetryTraceContext{
    TraceID: "4bf92f3577b34da6a3ce929d0e0e4736",
    SpanID:  "00f067aa0ba902b7",
    Sampled: &sampled,
  },
  Session: &logbrew.TelemetrySessionContext{ID: "session_01"},
  Subject: &logbrew.TelemetrySubjectContext{ID: "user_42", Kind: "user"},
  Tags:    map[string]string{"operation": "checkout"},
}
must(client.Log("evt_checkout", "2026-08-03T08:15:30Z", logbrew.LogAttributes{
  Message: "checkout started",
  Level:   "info",
  Context: requestContext,
}))

By default the core client adds only runtime (go plus runtime.Version()), the compiled OS family, and the compiled architecture beneath explicit caller context. Set DisableRuntimeContext: true to disable those defaults without dropping explicit context. The runtime probe does not inspect process environment, machine names, network addresses, local account names, startup arguments, working directories, files, cloud metadata, or application configuration.

Session and subject IDs are app-owned opaque correlation values. Do not put names, email addresses, authentication material, network addresses, or other direct PII in them. Tags are capped at 32 low-cardinality string dimensions. Every context string and ID is bounded, control characters are rejected, W3C IDs are normalized, all-zero IDs are rejected, and empty resource sections fail before queueing.

Structured Issue Diagnostics

IssueAttributes accepts a typed exception identity, mechanism/handled state, up to 32 structured frames, and up to 64 application-owned breadcrumbs. This keeps issue details useful without embedding a raw Go stack string or an error value:

inApp := true
must(client.Issue("evt_checkout_failure", "2026-08-02T08:15:31Z", logbrew.IssueAttributes{
  Title:   "Checkout failed",
  Level:   "error",
  Message: "Inventory did not accept the reservation",
  Exception: &logbrew.IssueException{
    Type: "InventoryError",
    Mechanism: &logbrew.IssueExceptionMechanism{
      Type:    "checkout.reserve",
      Handled: true,
    },
  },
  StackFrames: []logbrew.IssueStackFrame{{
    Filename: "checkout.go",
    Line:     84,
    Column:   1,
    Function: "reserveInventory",
    Module:   "example.com/store/checkout",
    InApp:    &inApp,
  }},
  Breadcrumbs: []logbrew.IssueBreadcrumb{{
    Timestamp: "2026-08-02T08:15:30Z",
    Type:      "http",
    Category:  "inventory.request",
    Level:     "warning",
    Message:   "Inventory request completed",
    Data:      map[string]any{"status_code": 503, "attempt": 2},
  }},
  Evidence: &logbrew.IssueDiagnosticEvidence{
    LikelyRootCause: "The inventory provider exhausted its retry budget.",
    LikelyFixArea: &logbrew.IssueLikelyFixArea{
      File: "internal/inventory/reservation.go",
      Line: 84,
    },
    Impact: &logbrew.IssueImpactEvidence{
      FailedAction:       "checkout.submit",
      UserVisibleOutcome: "The order was not confirmed.",
    },
    RedactedFields: []string{"provider.message"},
  },
}))

Breadcrumbs are explicit and request-local; the core client does not keep a process-global breadcrumb ring that could mix concurrent users or requests. Attach oldest-to-newest history and set BreadcrumbsTruncated when older entries were intentionally omitted. Data is limited to eight flat finite primitive fields, and caller-owned slices/maps are detached before queueing.

Evidence carries only explicit application knowledge; the SDK does not infer a root cause from errors or stack frames. LogBrew keeps the reported hypothesis and likely fix area separate from observed runtime facts, while field-state lists preserve missing, redacted, and truncated evidence for API, CLI, dashboard, and agent consumers. Use repository-relative paths and do not place authentication material, request bodies, personal data, or raw user input in these fields. See the shared issue evidence contract.

CaptureIssueStackFrames() snapshots the current goroutine in newest-first order with basename-only filenames and bounded function/module identities. Call it at the failure boundary (including inside a recovery defer) when the current call stack is meaningful. It never captures source lines, locals, panic/error values, or raw stack text. Explicit frames receive the same validation and absolute filenames are reduced to basenames before queueing.

CreateIssueExceptionChain() follows standard Unwrap() error and Unwrap() []error relationships without formatting either value. It emits a bounded parent-first cause or aggregate graph, records redacted/missing message and stack states, detects cycles, and validates entry zero against the legacy exception and frames. Panic, Gin, and net/http helpers use this same contract instead of emitting a weaker wrapper-only shape. See the shared exception-chain contract.

High-Load Behavior

NewClient keeps the in-memory event queue bounded to 1,000 events by default. Set Config.MaxQueueSize when your service needs a larger or smaller local buffer. When the queue is full, LogBrew drops new events instead of blocking app logging or discarding already-buffered release/environment/request context. Use DroppedEvents() for a local counter and OnEventDropped for an advisory callback:

client, err := logbrew.NewClient(logbrew.Config{
  APIKey:       "LOGBREW_API_KEY",
  SDKName:      "go-worker",
  SDKVersion:   "0.1.0",
  MaxRetries:   1,
  MaxQueueSize: 1000,
  OnEventDropped: func(drop logbrew.EventDrop) {
    fmt.Printf("dropped %s %s after %d total drops\n", drop.EventType, drop.EventID, drop.DroppedEvents)
  },
})
must(err)

EventDrop contains only eventId, eventType, reason, and the cumulative dropped count; it never includes event attributes, payloads, API keys, headers, or transport details. The advisory callback is panic-safe and cannot interrupt capture. Flush and Shutdown still preserve accepted events across retryable transport failures, and DroppedEvents() is not reset by a successful flush.

Automatic Delivery

Keep the existing manual behavior by using NewClient. To let a client own delivery, use NewAutomaticClient with one app-scoped transport:

transport, err := logbrew.NewHTTPTransport(logbrew.HTTPTransportConfig{})
must(err)

client, err := logbrew.NewAutomaticClient(logbrew.Config{
  APIKey:     "LOGBREW_API_KEY",
  SDKName:    "checkout-api",
  SDKVersion: "0.1.0",
}, logbrew.AutomaticDeliveryConfig{
  Transport: transport,
})
must(err)
defer func() {
  _, _ = client.Shutdown(nil)
}()

Automatic delivery starts lazily after the first accepted event. It flushes every two seconds or at 100 queued events by default, whichever happens first, while reusing the same bounded queue and serialized flush path. Override FlushInterval and FlushThreshold when needed. Retryable failures preserve one immutable failed prefix. Without a server directive, automatic delivery uses the existing immediate retry budget before capped equal-jitter scheduling from 100 milliseconds to five seconds. Later captures remain queued separately. For 408 and 5xx responses, the standard HTTP transport honors one unambiguous RFC Retry-After delta-seconds or IMF-fixdate value without bypassing the client backoff floor, and clamps it to RetryMaxDelay. Malformed, duplicate, unsupported, or past values use the jittered client fallback instead of an immediate retry. Authentication (401/403), quota (402/429), and other non-retryable responses pause automatic delivery until the application fixes the cause and calls ResumeDelivery.

DeliveryHealth() returns only fixed lifecycle state, queue/drop counts, in-flight/coalesced state, bounded backoff source/outcome/delay fields, and counters. Backoff diagnostics distinguish the selected client or server delay and invalid server directives, but never retain the header value or clock input. The snapshot never contains event content or identifiers, API keys, endpoints, headers, paths, hosts, response text, or arbitrary metadata. Shutdown(nil) stops scheduling and drains through the owned transport. If that final send fails, queued work remains available for a later explicit Shutdown(nil) retry, while new captures stay rejected. The client installs no signal, process, or exit hooks; the application remains responsible for calling shutdown and for configuring an HTTP timeout appropriate to its runtime.

Encrypted restart persistence

NewPersistentAutomaticClient is an opt-in extension of the same automatic client. It durably encrypts the existing queue before capture returns, recovers events oldest first after restart, and stores the exact failed request prefix so a retry after restart uses byte-identical request data. Ordinary NewClient and NewAutomaticClient behavior remains memory-only.

// Load the same 32-byte key from your application's secure configuration on every
// restart. Do not generate a new key for an existing directory.
persistenceKey := loadApplicationPersistenceKey()

client, err := logbrew.NewPersistentAutomaticClient(logbrew.Config{
  APIKey:       "LOGBREW_API_KEY",
  SDKName:      "checkout-api",
  SDKVersion:   "0.1.0",
  MaxQueueSize: 1000,
}, logbrew.AutomaticDeliveryConfig{
  Transport: transport,
}, logbrew.PersistentDeliveryConfig{
  Directory:      "/var/lib/checkout-api/logbrew",
  EncryptionKey:  persistenceKey,
  MaxStoredBytes: 4 * 1024 * 1024,
})
must(err)

Persistence uses standard-library AES-256-GCM with a fresh nonce for every rewrite. The 32-byte key stays caller-owned and is never persisted or logged. Event count remains bounded by Config.MaxQueueSize; serialized event bytes default to 4 MiB and can be configured up to 16 MiB. Queue state, failed request bytes, event IDs, and the SDK identity inside a frozen request are authenticated, encrypted, and bound to the dedicated store's ownership marker. Outside that ciphertext, only fixed filenames, the content-free ownership marker, and a content-free transaction digest remain visible. API keys, transport authentication values, endpoints, headers, PIDs, hosts, and configured paths are not stored.

The configured directory is canonicalized to a dedicated leaf and must support verifiable owner-only POSIX modes, regular-file identity, single-link checks, advisory exclusive locking, file sync, and directory sync. Unsupported filesystems fail with persistence_unsupported; there is no plaintext or weak-permission fallback. Symlinked store leaves, unexpected files, unsafe links, unauthenticated corruption, the wrong key, concurrent ownership, inherited post-fork ownership, and file replacement while a process owns the store fail closed before delivery. A clean Shutdown(nil) releases ownership. The client adds no process hooks, shutdown hooks, or extra delivery queue.

Event content remains application-controlled sensitive data even when encrypted. Keep the directory private, protect and rotate the key using an app-owned migration, and use a different dedicated directory per logical client. PurgePersistentDelivery is an explicit destructive recovery operation: it acquires exclusive ownership, rejects unknown paths, removes only recognized persistence files, resets the content-free ownership marker, and synchronizes the directory. It accepts any valid 32-byte key value because purge must remain possible after the old key is lost.

An accepted prefix is removed from restart recovery only after its replacement queue snapshot and parent directory are durable. A crash after the remote service accepts a request but before that local acknowledgement completes can still resend the encrypted prefix after restart; transports and event processing should therefore remain idempotent. No local design can atomically commit a remote response and a filesystem update.

The app and its local filesystem owner remain inside the trust boundary. Without an external monotonic authority, the SDK cannot distinguish restoration of an entire older but internally valid persistence directory from a normal restart. Protect or back up the directory as one unit, and purge it if owner-driven rollback is suspected.

First Useful Telemetry

For a production Go service, the first useful LogBrew payload is usually a release marker, environment marker, one service log, one product action, one network milestone, one request duration metric, and one W3C-linked request span. That gives developers and AI assistants enough context to answer "what changed?", "where did this happen?", "what did the user do?", "which API call mattered?", and "which trace links the signals?" without installing a large instrumentation stack.

go run ./examples/first_useful_telemetry

The example uses a fake API key, emits a local PreviewJSON payload, and then flushes to AlwaysAcceptTransport. It keeps the SDK dependency-free, app-owned, and explicit: no global net/http patching, no request or response payload capture, no arbitrary header capture, and no query or hash text in route metadata. Use NewHTTPTransport only when you are ready to send to the hosted LogBrew intake.

Support Ticket Drafts

Use CreateSupportTicketDraft when a developer or support agent explicitly asks for a local JSON payload for the planned LogBrew support-ticket routes. The helper validates the public source/category contract, normalizes W3C trace IDs, redacts diagnostics, and returns a SupportTicketDraft. It does not send data, open a ticket, call backend support-ticket routes, use account/session API credentials, or infer backend ownership.

draft, err := logbrew.CreateSupportTicketDraft(logbrew.SupportTicketDraftInput{
  Source:      "sdk",
  Category:    "ingest_failure",
  Title:       "Telemetry flush failed",
  Description: "Flush returned usage_limit_exceeded",
  ProjectID:   "proj_123",
  Environment: "production",
  Runtime:     "go1.25",
  Framework:   "net/http",
  SDKPackage:  "github.com/LogBrewCo/sdk/go/logbrew",
  SDKVersion:  "0.1.0",
  Release:     "checkout@1.2.3",
  TraceID:     "4bf92f3577b34da6a3ce929d0e0e4736",
  EventID:     "evt_checkout_flush",
  Diagnostics: map[string]any{
    "attemptCount": 2,
    "endpoint":    "https://api.example/ingest?debug=true",
    "localPath":   "<local-app-path>",
  },
})
if err != nil {
  panic(err)
}
_ = draft

Diagnostics are bounded to JSON-like values. Auth-like keys, cookies, tokens, URL origins, local paths, unsupported objects, and raw error messages are redacted or omitted before the draft is returned. Network ticket creation should remain a separate explicit user or agent action only after backend reports deployed support-ticket storage and routes.

Metrics

Use Metric for explicit, application-owned measurements. LogBrew validates the metric name, kind, value, unit, temporality, and optional metadata before queueing the event:

must(client.Metric("evt_metric_queue_depth", "2026-06-02T10:00:06Z", logbrew.MetricAttributes{
  Name:        "queue.depth",
  Description: "Number of items waiting in the checkout queue.",
  Kind:        "gauge",
  Value:       42,
  Unit:        "{items}",
  Temporality: "instant",
  Metadata:    map[string]any{"service": "worker"},
}))

Supported metric kinds are counter, gauge, and histogram. Counters and histograms require delta or cumulative temporality and non-negative values; gauges require instant temporality and may be negative. An optional Description gives people and investigation tools the stable meaning of the measurement. Keep it generic, single-line, between 1 and 1,024 Unicode scalar values, and free of identifiers, personal data, or changing values. It is not a query dimension. Keep metadata low-cardinality and primitive. This SDK does not automatically collect runtime or framework metrics yet.

Trace Context

Use the dependency-free W3C helpers when a Go service needs to continue incoming distributed trace context without taking an OpenTelemetry dependency:

traceparent := "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
context, err := logbrew.ParseTraceparent(traceparent)
if err != nil {
  panic(err)
}

duration := 8.5
attributes, err := logbrew.SpanAttributesFromTraceparent(logbrew.TraceparentSpanInput{
  Traceparent: traceparent,
  Name:        "GET /health",
  SpanID:      "b7ad6b7169203331",
  Status:      "ok",
  DurationMs:  &duration,
  Metadata: map[string]any{
    "framework": "net/http",
    "sampled":   context.Sampled,
  },
})
if err != nil {
  panic(err)
}

must(client.Span("evt_request_span", "2026-06-02T10:00:04Z", attributes))
outgoing, err := logbrew.CreateTraceparent(context.TraceID, attributes.SpanID, context.TraceFlags)
if err != nil {
  panic(err)
}
fmt.Println(outgoing)

ParseTraceparent validates W3C shape, rejects forbidden version ff, rejects all-zero trace/span IDs, normalizes IDs to lowercase, and exposes the sampled flag. SpanAttributesFromTraceparent returns LogBrew span attributes with TraceID from the incoming trace and ParentSpanID from the incoming parent span, while copying only primitive metadata values. CreateTraceparent emits a normalized outgoing traceparent from explicit IDs and defaults empty flags to sampled 01.

For request-local correlation, use NewTraceContext and attach it with ContextWithLogBrewTrace. LogBrewTraceFromContext returns the active request trace. LogAttributesWithTrace, IssueAttributesWithTrace, ActionAttributesWithTrace, and MetricAttributesWithTrace attach the exact trace/span as first-class shared context and retain primitive trace metadata for older readers:

trace, err := logbrew.NewTraceContext(logbrew.TraceContextInput{
  Traceparent: r.Header.Get("traceparent"),
})
if err != nil {
  // Treat malformed incoming propagation as non-fatal in request handlers.
  trace, err = logbrew.NewTraceContext(logbrew.TraceContextInput{})
}
if err != nil {
  panic(err)
}
r = r.WithContext(logbrew.ContextWithLogBrewTrace(r.Context(), trace))

must(client.Log("evt_handler_log", "2026-06-02T10:00:03Z", logbrew.LogAttributesWithTrace(r.Context(), logbrew.LogAttributes{
  Message: "checkout handler reached",
  Level:   "info",
  Logger:  "checkout-service",
})))

OpenTelemetry Bridge

If your Go app already installs OpenTelemetry, add the optional bridge module instead of changing the base SDK install:

go get github.com/LogBrewCo/sdk/go/logbrew/otel
import (
  logbrewotel "github.com/LogBrewCo/sdk/go/logbrew/otel"
  sdktrace "go.opentelemetry.io/otel/sdk/trace"
)

exporter, err := logbrewotel.NewSpanExporter(client, logbrewotel.SpanExporterConfig{
  EventIDPrefix: "checkout_otel",
  Metadata:      map[string]any{"service": "checkout-api"},
})
if err != nil {
  panic(err)
}
provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sdktrace.NewSimpleSpanProcessor(exporter)))
_ = provider

TraceContextFromContext and TraceContextFromSpanContext copy only valid OTel trace ID, span ID, and sampled flags into LogBrew child trace context. NewSpanExporter queues ended OTel spans as LogBrew span events with safe method/route/status, database, messaging, RPC, exception-type, span-kind, instrumentation-scope, and span-link summaries. It does not install global providers, own exporters/processors, retry, flush, capture full URLs, headers, payloads, SQL statements, exception messages, stacks, baggage, tracestate, or raw propagation values. Keep using client.Flush or client.Shutdown with your app-owned transport.

Gin Middleware

Gin applications can add the optional framework module without adding Gin to the dependency-free core package:

go get github.com/LogBrewCo/sdk/go/logbrew/gin@latest
import (
  logbrewgin "github.com/LogBrewCo/sdk/go/logbrew/gin"
  "github.com/gin-gonic/gin"
)

middleware, err := logbrewgin.NewMiddleware(logbrewgin.Config{
  Client:                   client,
  CaptureRequestMetrics:   true,
  CaptureServerErrorIssues: true,
  Metadata:                 map[string]any{"service": "checkout-api"},
})
if err != nil {
  panic(err)
}

router := gin.New()
router.Use(gin.Recovery(), middleware)

The middleware records matched Gin route templates, continues one valid W3C traceparent, and makes the LogBrew trace available through the request context.Context. It uses a fixed <unmatched> label instead of a concrete 404 path. Panics produce a generic type-only exception with mechanism/handled state and bounded structured call frames, then are re-panicked so Gin's existing recovery retains response ownership. Metrics and generic ordinary 5xx issues are opt-in. The adapter never captures bodies, concrete URLs, query strings, hosts, IPs, user identity, cookies, authorization values, arbitrary headers, raw propagation, error messages, panic values, raw stack text, source lines, locals, or absolute frame paths, and it never owns transport or flush behavior. See the Gin module guide for the complete setup and privacy contract.

NewHTTPHandler wraps an app-owned net/http handler, accepts exactly one valid W3C traceparent, creates one request span, optionally emits http.server.duration, and passes the active TraceContext to downstream code through context.Context. It uses the matched http.ServeMux pattern or an explicit RouteTemplate; when neither is available it records / instead of the raw request path. The outermost LogBrew wrapper owns nested instrumentation so the same request is emitted once. If the handler panics, LogBrew records one failed request span and one generic correlated issue with type-only exception identity, net_http.middleware mechanism, unhandled state, and bounded sanitized call frames, then re-panics with the original value. Ordinary 5xx responses remain span-only unless NewHTTPHandlerWithOptions receives WithHTTPServerErrorIssues(). NewSlogHandler wraps an app-owned slog.Handler, queues a LogBrew log, and adds traceId / spanId fields to the wrapped app log when the context contains a LogBrew trace:

slogHandler, err := logbrew.NewSlogHandler(logbrew.SlogHandlerConfig{
  Client:  client,
  Wrapped: slog.NewJSONHandler(os.Stdout, nil),
  Logger:  "checkout-service",
})
if err != nil {
  panic(err)
}
logger := slog.New(slogHandler)

handler, err := logbrew.NewHTTPHandlerWithOptions(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  logger.InfoContext(r.Context(), "checkout handler reached", slog.String("cartTier", "standard"))
  w.WriteHeader(http.StatusNoContent)
}), logbrew.HTTPHandlerConfig{
  Client:               client,
  RouteTemplate:        "/checkout/:cart_id",
  CaptureRequestMetric: true,
}, logbrew.WithHTTPServerErrorIssues())
if err != nil {
  panic(err)
}
http.Handle("/checkout/", handler)

The HTTP and slog helpers are dependency-free and explicit. The HTTP wrapper preserves cancellation/deadlines, http.Flusher, http.Hijacker, http.Pusher, io.ReaderFrom, and http.ResponseController unwrapping when the app writer supports them. It does not patch globals, add workers, buffer bodies, capture request or response bodies, capture arbitrary headers, capture panic messages or raw stack text, or use raw URLs, query strings, fragments, cookies, authentication values, IPs, user identity, hosts, or local paths. Structured panic frames contain basename, coordinates, and bounded code identity only; they exclude source, locals, values, and absolute paths. Custom or unknown HTTP methods are recorded as OTHER. Run go run ./examples/http_trace_correlation for a copyable local example where release, environment, slog, issue, request span, and request-duration metric events share the same W3C trace.

Outbound net/http Client Spans

Use NewHTTPClientTransport when you want one outbound client span around app-owned http.Client calls:

transport, err := logbrew.NewHTTPClientTransport(logbrew.HTTPClientTransportConfig{
  Client:        client,
  Base:          http.DefaultTransport,
  EventIDPrefix: "checkout_http",
  // Optional: finish successful spans when the response body reaches EOF or Close.
  // Always close response bodies in your app code.
  FinishSpanOnResponseBodyClose: true,
})
if err != nil {
  panic(err)
}

httpClient := &http.Client{Transport: transport}
request, err := http.NewRequestWithContext(
  r.Context(),
  http.MethodGet,
  "https://api.example.com/payments/123?coupon=summer",
  nil,
)
if err != nil {
  panic(err)
}
response, err := httpClient.Do(request)

The transport is an explicit app-owned wrapper; it never changes http.DefaultTransport or unrelated clients. A valid active LogBrew parent creates one child for each actual RoundTrip, and the request clone receives the matching W3C traceparent. With no valid parent, the original request goes directly to the selected transport without tracing work. Caller request headers and context remain unchanged, responses and errors keep their original identity, and capture failures are advisory. Direct duplicate registration returns the first wrapper; nested wrappers coalesce through the request context, and LogBrew delivery requests are excluded.

Place retry or redirect middleware outside this wrapper when each actual attempt should have its own child span. The fixed span metadata contains only method, normalized non-IP host when safe, status, duration, source, sampled state, real cancellation, and a bounded error class. It never stores scheme, port, path, query, fragment, full URL, headers, bodies or sizes, authentication material, cookies, baggage, tracestate, IP addresses, arbitrary metadata, error messages, stacks, or transport internals. RouteTemplate, Metadata, and CapturePhaseTimings remain in the config for source compatibility but are ignored and not retained. FinishSpanOnResponseBodyClose can defer capture while preserving body reads, writes, EOF, close, and errors. Run go run ./examples/http_client_trace for a local propagation and span-capture example.

Dependency Spans

Use DatabaseOperationWithLogBrewSpan, CacheOperationWithLogBrewSpan, and QueueOperationWithLogBrewSpan around app-owned database, cache, or queue calls when you want request-to-dependency timing without driver monkeypatching:

result, err := logbrew.DatabaseOperationWithLogBrewSpan(r.Context(), client, "select checkout", func(ctx context.Context) (string, error) {
  // Use ctx for your database call so logs inside the callback can share the child trace.
  return "order_123", nil
}, logbrew.DatabaseOperationConfig{
  System:            "postgresql",
  OperationKind:     "query",
  DatabaseName:      "orders",
  StatementTemplate: "SELECT * FROM orders WHERE id = ?",
  Metadata:          map[string]any{"service": "checkout"},
})

Each helper creates a child TraceContext, activates it for the callback, records one span, returns the original result, and re-raises the original error. If the callback panics, LogBrew records one failed span with type-only panic metadata, then re-panics with the original value. Metadata is primitive-only and intentionally drops SQL text, parameters, connection details, cache keys/values, commands, message bodies, broker URLs, headers, cookies, raw traceparent values, baggage, tracestate, panic messages, stacks, and auth-like fields. These helpers do not import or patch database/sql, Redis, Kafka, AMQP, or queue clients; future automatic coverage should live in explicit integration packages with separate dependency and privacy validation.

For app-owned queue clients, use TraceparentSetter to write exactly one outgoing W3C traceparent, IncomingTraceparent to continue one valid message trace while processing, and LinkedTraceparents or SpanLinkSummary values to summarize batch/fan-in relationships. Use SpanLinkSummaryFromTraceparent for message-carrier traceparents or NewSpanLinkSummary for explicit W3C trace/span IDs:

headers := map[string]string{}
_, err = logbrew.QueueOperationWithLogBrewSpan(r.Context(), client, "publish checkout", func(ctx context.Context) (string, error) {
  // Send your Kafka/SQS/Pub/Sub/AMQP message here with headers["traceparent"].
  return "published", nil
}, logbrew.QueueOperationConfig{
  System:        "kafka",
  OperationKind: "publish",
  QueueName:     "checkout-events",
  TaskName:      "checkout.completed",
  TraceparentSetter: func(traceparent string) error {
    headers["traceparent"] = traceparent
    return nil
  },
})
if err != nil {
  panic(err)
}

messageCount := 2
_, err = logbrew.QueueOperationWithLogBrewSpan(context.Background(), client, "process checkout batch", func(ctx context.Context) (int, error) {
  // Logs emitted with ctx correlate to the message-processing child span.
  return 2, nil
}, logbrew.QueueOperationConfig{
  System:              "kafka",
  OperationKind:       "process",
  QueueName:           "checkout-events",
  MessageCount:        &messageCount,
  IncomingTraceparent: headers["traceparent"],
  LinkedTraceparents:  []string{headers["traceparent"]},
  LinkMetadata:        map[string]any{"relation": "batch_item"},
})

Malformed incoming or linked propagation is reported through OnError as a redacted diagnostic and skipped without interrupting app work. Span links are capped at eight and store only normalized trace ID, span ID, sampled flag, and primitive safe metadata.

For common database/sql calls, use SQLQueryContextWithLogBrewSpan and SQLExecContextWithLogBrewSpan with an app-owned *sql.DB, *sql.Tx, *sql.Conn, or prepared *sql.Stmt:

rows, err := logbrew.SQLQueryContextWithLogBrewSpan(
  r.Context(),
  client,
  db,
  "lookup checkout order",
  "SELECT * FROM orders WHERE account_ref = ?",
  logbrew.DatabaseOperationConfig{
    System:       "postgresql",
    DatabaseName: "orders",
    Metadata:     map[string]any{"service": "checkout"},
  },
  accountRef,
)
_ = rows
_ = err

The SQL helpers keep the same explicit boundary as the generic database helper. LogBrew passes query text and args only to query-text runners such as *sql.DB, *sql.Tx, and *sql.Conn; prepared statement runners such as *sql.Stmt receive args only. The exported runner interfaces are SQLQueryContextRunner, SQLExecContextRunner, SQLStatementQueryContextRunner, and SQLStatementExecContextRunner. In both cases LogBrew activates a child trace for logs inside that call, records safe operation metadata, and captures RowsAffected() for successful exec results when the driver exposes it. It does not wrap or register drivers, does not alter app connection inputs, and does not capture query text, parameters, connection details, user names, result rows, exception messages, stacks, baggage, or tracestate. If you want a sanitized statement template in telemetry, pass your own placeholder-only StatementTemplate; LogBrew will not derive one from query text.

For transaction-level hierarchy, use SQLTransactionWithLogBrewSpan with an app-owned *sql.DB or *sql.Conn, then pass the callback context to SQL query/exec helpers so those child spans sit under the transaction span:

result, err := logbrew.SQLTransactionWithLogBrewSpan(
  r.Context(),
  client,
  db,
  "checkout transaction",
  nil,
  func(txCtx context.Context, tx *sql.Tx) (string, error) {
    _, err := logbrew.SQLExecContextWithLogBrewSpan(
      txCtx,
      client,
      tx,
      "insert checkout order",
      "INSERT INTO orders(account_ref) VALUES (?)",
      logbrew.DatabaseOperationConfig{System: "postgresql", DatabaseName: "orders"},
      accountRef,
    )
    if err != nil {
      return "", err
    }
    return "committed", nil
  },
  logbrew.DatabaseOperationConfig{System: "postgresql", DatabaseName: "orders"},
)
_ = result
_ = err

The transaction helper begins through the app-owned SQLBeginTxRunner, commits when the callback succeeds, rolls back when the callback returns an error, rolls back before re-panicking when the callback panics, records a safe dbTransactionOutcome, and preserves the original callback, commit error, or panic. Rollback failures are reported through OnError with a redacted SDK diagnostic. It does not wrap drivers, register global SQL drivers, patch pools, capture SQL text, parameters, DSNs, connection details, result rows, exception messages, stacks, baggage, or tracestate.

Agent-Readable Timelines

Use CreateProductActionAttributes and CreateNetworkMilestoneAttributes when your Go service already knows important product steps or API milestones. The helpers create normal action event attributes with primitive metadata that AI assistants can analyze across sessions without visual replay, global HTTP patching, payload capture, or header capture.

context, err := logbrew.ParseTraceparent("00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01")
if err != nil {
  panic(err)
}

action, err := logbrew.CreateProductActionAttributes(logbrew.ProductActionInput{
  Name:          "checkout.started",
  SessionID:     "sess_checkout_123",
  TraceID:       context.TraceID,
  RouteTemplate: "/checkout/:step?email=user@example.com#pay",
  Screen:        "Checkout",
  Funnel:        "checkout",
  Step:          "started",
})
if err != nil {
  panic(err)
}
must(client.Action("evt_checkout_started", "2026-06-02T10:00:00Z", action))

statusCode := 202
durationMs := 64.5
network, err := logbrew.CreateNetworkMilestoneAttributes(logbrew.NetworkMilestoneInput{
  RouteTemplate: "https://api.example.com/v1/payments/:id?debug=true#trace",
  Method:        "post",
  StatusCode:    &statusCode,
  DurationMs:    &durationMs,
  SessionID:     "sess_checkout_123",
  TraceID:       context.TraceID,
  Metadata:      map[string]any{"region": "global"},
})
if err != nil {
  panic(err)
}
must(client.Action("evt_payment_api", "2026-06-02T10:00:01Z", network))

Route templates are stripped to path-only values before queueing, nested metadata is dropped, HTTP methods are normalized, and 4xx/5xx status codes default network milestone status to failure. The examples/agent_timeline package contains a focused preview of product and network milestones correlated by sessionId and W3C traceId; examples/first_useful_telemetry shows the same timeline signals alongside release, environment, log, metric, and span events; examples/http_trace_correlation shows request-local trace, slog, issue, request span, and duration metric correlation in a local net/http app.

HTTP Delivery

Use NewHTTPTransport for real outbound delivery from server-side Go apps:

transport, err := logbrew.NewHTTPTransport(logbrew.HTTPTransportConfig{
  Endpoint: logbrew.DefaultHTTPEndpoint,
  Headers: map[string]string{"x-logbrew-source": "go-worker"},
})
if err != nil {
  panic(err)
}

response, err := client.Flush(transport)
if err != nil {
  panic(err)
}
fmt.Println(response.StatusCode)

HTTPTransport uses Go's standard net/http client, posts JSON, passes the SDK key through the authorization header, supports custom endpoint/header/client/timeout settings, drains and closes response bodies, and maps client delivery failures into retryable NetworkError(...) values so Client.Flush can preserve queued events and retry. Inject a custom *http.Client when a service already owns proxy, TLS, or timeout settings.

The examples directory contains copyable snippets for creating a client, previewing queued JSON, sending through HTTPTransport, producing a first-useful telemetry payload, correlating net/http + slog signals, and using W3C trace propagation in your own Go service.

Documentation

Overview

Package logbrew provides a small public client for building, validating, previewing, and flushing LogBrew event batches from Go applications.

Index

Constants

View Source
const (
	DeliveryStateManual         = "manual"
	DeliveryStateRunning        = "running"
	DeliveryStatePaused         = "paused"
	DeliveryStateShuttingDown   = "shutting_down"
	DeliveryStateShutdownFailed = "shutdown_failed"
	DeliveryStateShutdown       = "shutdown"
)
View Source
const (
	DeliveryOutcomeNone                = "none"
	DeliveryOutcomeAccepted            = "accepted"
	DeliveryOutcomeRetryableFailure    = "retryable_failure"
	DeliveryOutcomeAuthenticationPause = "authentication_paused"
	DeliveryOutcomeQuotaPause          = "quota_paused"
	DeliveryOutcomeNonRetryablePause   = "nonretryable_paused"
	DeliveryOutcomePersistencePause    = "persistence_paused"
	DeliveryOutcomeShutdownFailed      = "shutdown_failed"
)
View Source
const (
	DeliveryBackoffSourceNone   = "none"
	DeliveryBackoffSourceClient = "client"
	DeliveryBackoffSourceServer = "server"
)
View Source
const (
	DeliveryBackoffOutcomeNone      = "none"
	DeliveryBackoffOutcomeScheduled = "scheduled"
	DeliveryBackoffOutcomeHonored   = "honored"
	DeliveryBackoffOutcomeClamped   = "clamped"
	DeliveryBackoffOutcomeFallback  = "fallback"
)
View Source
const (
	// DefaultHTTPEndpoint is the production LogBrew event intake URL used by
	// NewHTTPTransport when no endpoint is supplied.
	DefaultHTTPEndpoint = "https://api.logbrew.co/v1/events"
)

Variables

This section is empty.

Functions

func AsTransportError

func AsTransportError(err error, target **TransportError) bool

AsTransportError extracts a public transport failure for retry-aware callers.

func CacheOperationWithLogBrewSpan added in v0.1.2

func CacheOperationWithLogBrewSpan[T any](
	ctx context.Context,
	client *Client,
	operationName string,
	operation func(context.Context) (T, error),
	config CacheOperationConfig,
) (T, error)

CacheOperationWithLogBrewSpan runs operation under a child trace context and queues one privacy-bounded cache span.

func ContextWithLogBrewTrace added in v0.1.2

func ContextWithLogBrewTrace(parent context.Context, trace TraceContext) context.Context

ContextWithLogBrewTrace attaches trace context to a Go context.

func CreateTraceparent

func CreateTraceparent(traceID, spanID, traceFlags string) (string, error)

CreateTraceparent creates a normalized W3C traceparent header from explicit trace, span, and flags values. Empty traceFlags defaults to sampled "01".

func DatabaseOperationWithLogBrewSpan added in v0.1.2

func DatabaseOperationWithLogBrewSpan[T any](
	ctx context.Context,
	client *Client,
	operationName string,
	operation func(context.Context) (T, error),
	config DatabaseOperationConfig,
) (T, error)

DatabaseOperationWithLogBrewSpan runs operation under a child trace context and queues one privacy-bounded database span.

func GenerateSpanID added in v0.1.2

func GenerateSpanID() (string, error)

GenerateSpanID returns a fresh non-zero W3C-compatible span ID.

func GenerateTraceID added in v0.1.2

func GenerateTraceID() (string, error)

GenerateTraceID returns a fresh non-zero W3C-compatible trace ID.

func IssueExceptionType added in v0.1.7

func IssueExceptionType(value any) string

IssueExceptionType returns a bounded type identity for an error or recovered panic value without formatting or reading that value.

func NewHTTPClientTransport added in v0.1.2

func NewHTTPClientTransport(config HTTPClientTransportConfig) (http.RoundTripper, error)

NewHTTPClientTransport wraps an app-owned RoundTripper with privacy-safe outbound spans.

func NewHTTPHandler added in v0.1.2

func NewHTTPHandler(next http.Handler, config HTTPHandlerConfig) (http.Handler, error)

NewHTTPHandler wraps an app-owned net/http handler with privacy-safe request span telemetry and request-local trace context.

func NewHTTPHandlerFunc added in v0.1.2

func NewHTTPHandlerFunc(next http.HandlerFunc, config HTTPHandlerConfig) (http.Handler, error)

NewHTTPHandlerFunc wraps an app-owned net/http handler function.

func NewHTTPHandlerFuncWithOptions added in v0.1.4

func NewHTTPHandlerFuncWithOptions(
	next http.HandlerFunc,
	config HTTPHandlerConfig,
	options ...HTTPHandlerOption,
) (http.Handler, error)

NewHTTPHandlerFuncWithOptions wraps an app-owned handler function with explicit additive behavior.

func NewHTTPHandlerWithOptions added in v0.1.4

func NewHTTPHandlerWithOptions(
	next http.Handler,
	config HTTPHandlerConfig,
	options ...HTTPHandlerOption,
) (http.Handler, error)

NewHTTPHandlerWithOptions wraps an app-owned handler with explicit additive behavior while preserving the stable HTTPHandlerConfig layout.

func NewSlogHandler added in v0.1.2

func NewSlogHandler(config SlogHandlerConfig) (slog.Handler, error)

NewSlogHandler wraps an app-owned slog.Handler and correlates logs with the LogBrew trace context stored on the provided context.

func PurgePersistentDelivery added in v0.1.4

func PurgePersistentDelivery(config PersistentDeliveryConfig) error

PurgePersistentDelivery removes only recognized LogBrew persistence files while holding exclusive ownership. It intentionally does not require the previous encryption key, allowing recovery from a lost caller-owned key.

func QueueOperationWithLogBrewSpan added in v0.1.2

func QueueOperationWithLogBrewSpan[T any](
	ctx context.Context,
	client *Client,
	operationName string,
	operation func(context.Context) (T, error),
	config QueueOperationConfig,
) (T, error)

QueueOperationWithLogBrewSpan runs operation under a child trace context and queues one privacy-bounded queue span.

func SQLExecContextWithLogBrewSpan added in v0.1.3

func SQLExecContextWithLogBrewSpan(
	ctx context.Context,
	client *Client,
	execer any,
	operationName string,
	query string,
	config DatabaseOperationConfig,
	args ...any,
) (sql.Result, error)

SQLExecContextWithLogBrewSpan runs an app-owned database/sql ExecContext call under a child trace and queues one privacy-bounded database span. Query-text runners receive query text and args; prepared statement runners receive args only. Neither query text nor args are copied into telemetry by this helper.

func SQLQueryContextWithLogBrewSpan added in v0.1.3

func SQLQueryContextWithLogBrewSpan(
	ctx context.Context,
	client *Client,
	queryer any,
	operationName string,
	query string,
	config DatabaseOperationConfig,
	args ...any,
) (*sql.Rows, error)

SQLQueryContextWithLogBrewSpan runs an app-owned database/sql QueryContext call under a child trace and queues one privacy-bounded database span. Query-text runners receive query text and args; prepared statement runners receive args only. Neither query text nor args are copied into telemetry by this helper.

func SQLTransactionWithLogBrewSpan added in v0.1.3

func SQLTransactionWithLogBrewSpan[T any](
	ctx context.Context,
	client *Client,
	beginner SQLBeginTxRunner,
	operationName string,
	opts *sql.TxOptions,
	operation func(context.Context, *sql.Tx) (T, error),
	config DatabaseOperationConfig,
) (T, error)

SQLTransactionWithLogBrewSpan runs an app-owned database/sql transaction callback under a child transaction span. LogBrew starts the transaction through the app-owned runner, passes the active transaction context to the callback, commits on callback success, and rolls back on callback error. Query and exec helpers called with the callback context become children of this transaction span. SQL text, args, connection details, and rollback error messages are not copied into telemetry.

func TraceMetadataFromContext added in v0.1.2

func TraceMetadataFromContext(ctx context.Context) map[string]any

TraceMetadataFromContext returns primitive trace metadata from ctx, when a LogBrew trace context is active.

Types

type ActionAttributes

type ActionAttributes struct {
	Name     string            `json:"name"`
	Status   string            `json:"status"`
	Metadata map[string]any    `json:"metadata,omitempty"`
	Context  *TelemetryContext `json:"context,omitempty"`
}

ActionAttributes describes the public payload fields for an action event.

func ActionAttributesWithTrace added in v0.1.6

func ActionAttributesWithTrace(ctx context.Context, attributes ActionAttributes) ActionAttributes

ActionAttributesWithTrace adds exact active trace/span context while keeping legacy primitive metadata for compatible readers.

func CreateNetworkMilestoneAttributes added in v0.1.1

func CreateNetworkMilestoneAttributes(input NetworkMilestoneInput) (ActionAttributes, error)

CreateNetworkMilestoneAttributes builds privacy-safe action attributes for an API milestone without patching HTTP clients or capturing payloads/headers.

func CreateProductActionAttributes added in v0.1.1

func CreateProductActionAttributes(input ProductActionInput) (ActionAttributes, error)

CreateProductActionAttributes builds privacy-safe action attributes for a product milestone without automatic click capture or global app mutation.

type AutomaticDeliveryConfig added in v0.1.4

type AutomaticDeliveryConfig struct {
	Transport      Transport
	FlushInterval  time.Duration
	FlushThreshold int
	RetryBaseDelay time.Duration
	RetryMaxDelay  time.Duration
}

AutomaticDeliveryConfig configures client-owned delivery through one transport. NewClient remains fully manual; NewAutomaticClient opts in.

type CacheOperationConfig added in v0.1.2

type CacheOperationConfig struct {
	System        string
	OperationKind string
	CacheName     string
	Hit           *bool
	ItemSizeBytes *int
	ItemCount     *int
	EventIDPrefix string
	Metadata      map[string]any
	SpanIDFactory func() string
	Now           func() time.Time
	OnError       func(error)
}

CacheOperationConfig configures an explicit app-owned cache span.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client buffers validated LogBrew events until they are previewed, flushed, or shut down through a transport.

func NewAutomaticClient added in v0.1.4

func NewAutomaticClient(config Config, delivery AutomaticDeliveryConfig) (*Client, error)

NewAutomaticClient creates a client that owns interval and threshold delivery through the supplied app-scoped transport.

func NewClient

func NewClient(config Config) (*Client, error)

NewClient creates a public LogBrew client from user-supplied SDK identity and API key configuration.

func NewPersistentAutomaticClient added in v0.1.4

func NewPersistentAutomaticClient(
	config Config,
	delivery AutomaticDeliveryConfig,
	persistence PersistentDeliveryConfig,
) (*Client, error)

NewPersistentAutomaticClient creates an owned automatic client whose one delivery queue is durably encrypted before capture returns.

func (*Client) Action

func (c *Client) Action(id, timestamp string, attributes ActionAttributes) error

func (*Client) DeliveryHealth added in v0.1.4

func (c *Client) DeliveryHealth() DeliveryHealth

DeliveryHealth returns a fixed local snapshot with no event content, identifiers, keys, endpoint data, headers, or raw transport errors.

func (*Client) DroppedEvents added in v0.1.3

func (c *Client) DroppedEvents() int

DroppedEvents returns the number of locally dropped events since the client was created. Flush does not reset this diagnostic counter.

func (*Client) Environment

func (c *Client) Environment(id, timestamp string, attributes EnvironmentAttributes) error

func (*Client) Flush

func (c *Client) Flush(transport Transport) (*TransportResponse, error)

Flush sends queued events through a transport while preserving retry semantics. It freezes one snapshot, and a nil transport uses an owned automatic transport when configured.

func (*Client) Issue

func (c *Client) Issue(id, timestamp string, attributes IssueAttributes) error

func (*Client) Log

func (c *Client) Log(id, timestamp string, attributes LogAttributes) error

func (*Client) Metric added in v0.1.1

func (c *Client) Metric(id, timestamp string, attributes MetricAttributes) error

Metric queues an explicit, application-owned metric event after validating name, optional description, kind, value, unit, temporality, and optional metadata.

func (*Client) PendingEvents

func (c *Client) PendingEvents() int

PendingEvents returns the number of validated events currently buffered in memory.

func (*Client) PreviewJSON

func (c *Client) PreviewJSON() (string, error)

PreviewJSON returns the queued event batch as stable, pretty-printed JSON.

func (*Client) Release

func (c *Client) Release(id, timestamp string, attributes ReleaseAttributes) error

func (*Client) ResumeDelivery added in v0.1.4

func (c *Client) ResumeDelivery() error

ResumeDelivery resumes an automatically managed client after a terminal authentication, quota, or non-retryable pause.

func (*Client) Shutdown

func (c *Client) Shutdown(transport Transport) (*TransportResponse, error)

Shutdown flushes queued events, then marks the client closed so later writes fail. It first stops automatic scheduling, and a nil transport uses the owned automatic transport when configured.

func (*Client) Span

func (c *Client) Span(id, timestamp string, attributes SpanAttributes) error

type Config

type Config struct {
	// APIKey is the public LogBrew API key sent to the transport.
	APIKey string
	// SDKName identifies the calling SDK or application in emitted payloads.
	SDKName string
	// SDKVersion identifies the calling SDK or application version.
	SDKVersion string
	// Context is explicit privacy-bounded resource, correlation, session,
	// subject, and tag context merged into every event.
	Context *TelemetryContext
	// DisableRuntimeContext turns off the default Go version, OS family, and
	// architecture context without changing explicit Context.
	DisableRuntimeContext bool
	// MaxRetries sets the retry budget for retryable transport failures.
	MaxRetries int
	// MaxQueueSize bounds the in-memory event queue. Zero defaults to 1000.
	MaxQueueSize int
	// OnEventDropped is an advisory callback for local queue overflow. It must
	// not be used for critical app control flow because panics are recovered.
	OnEventDropped func(EventDrop)
}

Config describes the public SDK identity, API key, and retry behavior for a Go LogBrew client.

type DatabaseOperationConfig added in v0.1.2

type DatabaseOperationConfig struct {
	System            string
	OperationKind     string
	DatabaseName      string
	StatementTemplate string
	RowCount          *int
	EventIDPrefix     string
	Metadata          map[string]any
	SpanIDFactory     func() string
	Now               func() time.Time
	OnError           func(error)
}

DatabaseOperationConfig configures an explicit app-owned database span.

type DeliveryHealth added in v0.1.4

type DeliveryHealth struct {
	State          string `json:"state"`
	PendingEvents  int    `json:"pendingEvents"`
	DroppedEvents  int    `json:"droppedEvents"`
	InFlight       bool   `json:"inFlight"`
	WakePending    bool   `json:"wakePending"`
	LastOutcome    string `json:"lastOutcome"`
	Flushes        uint64 `json:"flushes"`
	Attempts       uint64 `json:"attempts"`
	AcceptedEvents uint64 `json:"acceptedEvents"`
	FailedFlushes  uint64 `json:"failedFlushes"`
	RetrySchedules uint64 `json:"retrySchedules"`
	// BackoffSource and BackoffOutcome use the fixed DeliveryBackoff vocabulary.
	BackoffSource  string `json:"backoffSource"`
	BackoffOutcome string `json:"backoffOutcome"`
	// BackoffDelayMillis is the bounded delay selected for the latest retry.
	BackoffDelayMillis    uint64 `json:"backoffDelayMillis"`
	ServerBackoffs        uint64 `json:"serverBackoffs"`
	ClientBackoffs        uint64 `json:"clientBackoffs"`
	InvalidServerBackoffs uint64 `json:"invalidServerBackoffs"`
}

DeliveryHealth is a fixed, content-free snapshot of local delivery state.

type EnvironmentAttributes

type EnvironmentAttributes struct {
	Name     string            `json:"name"`
	Region   string            `json:"region,omitempty"`
	Metadata map[string]any    `json:"metadata,omitempty"`
	Context  *TelemetryContext `json:"context,omitempty"`
}

EnvironmentAttributes describes the public payload fields for an environment event.

type Event

type Event struct {
	// Type is the stable LogBrew event type such as release or span.
	Type string `json:"type"`
	// Timestamp is the RFC 3339 event timestamp with timezone information.
	Timestamp string `json:"timestamp"`
	// ID is the caller-supplied stable identifier for the event.
	ID string `json:"id"`
	// Attributes contains the event payload fields for the given event type.
	Attributes map[string]any `json:"attributes"`
}

Event is the public event shape buffered, previewed, and flushed by the client.

type EventDrop added in v0.1.3

type EventDrop struct {
	EventID       string `json:"eventId"`
	EventType     string `json:"eventType"`
	Reason        string `json:"reason"`
	DroppedEvents int    `json:"droppedEvents"`
}

EventDrop is a privacy-bounded advisory emitted when the client drops a local event before transport. It never includes event attributes, payloads, or keys.

type HTTPClientTransportConfig added in v0.1.2

type HTTPClientTransportConfig struct {
	Client *Client
	Base   http.RoundTripper
	// RouteTemplate is retained for source compatibility. Outbound tracing does not capture routes.
	RouteTemplate string
	// EventIDPrefix is a bounded local label used only to identify queued span events.
	EventIDPrefix string
	// Metadata is retained for source compatibility. Outbound tracing emits a fixed metadata allowlist.
	Metadata map[string]any
	// CapturePhaseTimings is retained for source compatibility. Transport internals are not captured.
	CapturePhaseTimings bool
	// FinishSpanOnResponseBodyClose defers span capture until the response body is read to EOF or closed.
	FinishSpanOnResponseBodyClose bool
	SpanIDFactory                 func() string
	Now                           func() time.Time
	OnError                       func(error)
}

HTTPClientTransportConfig configures dependency-free outbound net/http client spans.

type HTTPHandlerConfig added in v0.1.2

type HTTPHandlerConfig struct {
	Client               *Client
	RouteTemplate        string
	CaptureRequestMetric bool
	EventIDPrefix        string
	Metadata             map[string]any
	SpanIDFactory        func() string
	Now                  func() time.Time
	OnError              func(error)
}

HTTPHandlerConfig configures dependency-free net/http request telemetry.

type HTTPHandlerOption added in v0.1.4

type HTTPHandlerOption interface {
	// contains filtered or unexported methods
}

HTTPHandlerOption adds explicit behavior without changing the stable HTTPHandlerConfig layout.

func WithHTTPServerErrorIssues added in v0.1.4

func WithHTTPServerErrorIssues() HTTPHandlerOption

WithHTTPServerErrorIssues adds one generic correlated issue for ordinary 5xx responses. Panics always add a generic issue before being re-panicked.

type HTTPTransport

type HTTPTransport struct {
	// Endpoint is the URL that receives serialized LogBrew event batches.
	Endpoint string
	// Headers are added to every HTTP delivery request after default headers.
	Headers map[string]string
	// Client sends requests. When nil, a shared default client is used.
	Client *http.Client
}

HTTPTransport sends queued batches through Go's standard net/http client.

func NewHTTPTransport

func NewHTTPTransport(config HTTPTransportConfig) (*HTTPTransport, error)

NewHTTPTransport creates a dependency-free HTTP transport with safe defaults.

func (*HTTPTransport) Send

func (t *HTTPTransport) Send(apiKey string, body []byte) (*TransportResponse, error)

Send posts one serialized event batch and returns the HTTP status.

type HTTPTransportConfig

type HTTPTransportConfig struct {
	// Endpoint is the URL that receives serialized LogBrew event batches.
	Endpoint string
	// Headers are added to every HTTP delivery request after default headers.
	Headers map[string]string
	// Client sends requests. When nil, Send uses a shared default client unless
	// Timeout asks NewHTTPTransport to create one.
	Client *http.Client
	// Timeout is used for the default HTTP client when Client is nil.
	Timeout time.Duration
}

HTTPTransportConfig configures the dependency-free HTTP transport.

type IssueAttributes

type IssueAttributes struct {
	Title                string                   `json:"title"`
	Level                string                   `json:"level"`
	Message              string                   `json:"message,omitempty"`
	Exception            *IssueException          `json:"exception,omitempty"`
	ExceptionChain       *IssueExceptionChain     `json:"exceptionChain,omitempty"`
	StackFrames          []IssueStackFrame        `json:"stackFrames,omitempty"`
	Breadcrumbs          []IssueBreadcrumb        `json:"breadcrumbs,omitempty"`
	BreadcrumbsTruncated bool                     `json:"breadcrumbsTruncated,omitempty"`
	Evidence             *IssueDiagnosticEvidence `json:"evidence,omitempty"`
	Metadata             map[string]any           `json:"metadata,omitempty"`
	Context              *TelemetryContext        `json:"context,omitempty"`
}

IssueAttributes describes the public payload fields for an issue event.

func IssueAttributesFromError added in v0.1.7

func IssueAttributesFromError(err error, title string, mechanismType string, handled bool) (IssueAttributes, error)

IssueAttributesFromError creates error-level issue attributes from a Go error. The root capture stack is bounded; unwrap nodes explicitly report that Go did not provide a separate stack. Error text is redacted by default.

func IssueAttributesWithTrace added in v0.1.2

func IssueAttributesWithTrace(ctx context.Context, attributes IssueAttributes) IssueAttributes

IssueAttributesWithTrace merges active trace metadata into issue attributes.

type IssueBreadcrumb added in v0.1.6

type IssueBreadcrumb struct {
	Timestamp string         `json:"timestamp"`
	Type      string         `json:"type,omitempty"`
	Category  string         `json:"category"`
	Level     string         `json:"level,omitempty"`
	Message   string         `json:"message,omitempty"`
	Data      map[string]any `json:"data,omitempty"`
}

IssueBreadcrumb is one application-supplied, privacy-bounded step that happened before an issue. Data accepts at most eight flat finite primitive values.

type IssueDiagnosticEvidence added in v0.1.8

type IssueDiagnosticEvidence struct {
	LikelyRootCause string               `json:"likelyRootCause,omitempty"`
	LikelyFixArea   *IssueLikelyFixArea  `json:"likelyFixArea,omitempty"`
	Impact          *IssueImpactEvidence `json:"impact,omitempty"`
	CapturedFields  []string             `json:"capturedFields,omitempty"`
	MissingFields   []string             `json:"missingFields,omitempty"`
	RedactedFields  []string             `json:"redactedFields,omitempty"`
	TruncatedFields []string             `json:"truncatedFields,omitempty"`
}

IssueDiagnosticEvidence contains bounded application-reported cause, fix area, impact, and explicit field-state receipts.

type IssueException added in v0.1.6

type IssueException struct {
	Type      string                   `json:"type"`
	Mechanism *IssueExceptionMechanism `json:"mechanism,omitempty"`
}

IssueException is a privacy-bounded exception identity. It intentionally excludes the exception value; applications keep control of the issue Message field when a display-safe description is appropriate.

type IssueExceptionChain added in v0.1.7

type IssueExceptionChain struct {
	Entries   []IssueExceptionChainEntry `json:"entries"`
	Truncated bool                       `json:"truncated"`
}

IssueExceptionChain contains at most eight parent-first runtime exceptions.

func CreateIssueExceptionChain added in v0.1.7

func CreateIssueExceptionChain(input IssueExceptionChainInput) (*IssueExceptionChain, error)

CreateIssueExceptionChain builds a bounded parent-first chain from a Go error or recovered panic value without reading or serializing its text.

type IssueExceptionChainEntry added in v0.1.7

type IssueExceptionChainEntry struct {
	ID               int                            `json:"id"`
	ParentID         *int                           `json:"parentId,omitempty"`
	Relationship     IssueExceptionRelationship     `json:"relationship"`
	Type             string                         `json:"type"`
	Message          string                         `json:"message,omitempty"`
	MessageState     IssueExceptionMessageState     `json:"messageState"`
	Module           string                         `json:"module,omitempty"`
	Mechanism        *IssueExceptionMechanism       `json:"mechanism,omitempty"`
	StackFrames      []IssueStackFrame              `json:"stackFrames,omitempty"`
	StackFramesState IssueExceptionStackFramesState `json:"stackFramesState"`
}

IssueExceptionChainEntry is one parent-first runtime exception with its own bounded evidence states.

type IssueExceptionChainInput added in v0.1.7

type IssueExceptionChainInput struct {
	Value                any
	Exception            *IssueException
	StackFrames          []IssueStackFrame
	StackFramesTruncated bool
}

IssueExceptionChainInput provides a runtime value and the matching legacy exception fields used to create one bounded chain.

type IssueExceptionMechanism added in v0.1.6

type IssueExceptionMechanism struct {
	Type    string `json:"type"`
	Handled bool   `json:"handled"`
}

IssueExceptionMechanism identifies the runtime path that observed an exception and whether the exception escaped that path.

type IssueExceptionMessageState added in v0.1.7

type IssueExceptionMessageState string

IssueExceptionMessageState reports whether one exception message was captured, truncated, redacted, or unavailable.

const (
	IssueExceptionMessageCaptured    IssueExceptionMessageState = "captured"
	IssueExceptionMessageTruncated   IssueExceptionMessageState = "truncated"
	IssueExceptionMessageRedacted    IssueExceptionMessageState = "redacted"
	IssueExceptionMessageNotCaptured IssueExceptionMessageState = "not_captured"
)

type IssueExceptionRelationship added in v0.1.7

type IssueExceptionRelationship string

IssueExceptionRelationship describes how a runtime exception relates to an earlier parent node.

const (
	IssueExceptionReported        IssueExceptionRelationship = "reported"
	IssueExceptionCause           IssueExceptionRelationship = "cause"
	IssueExceptionContext         IssueExceptionRelationship = "context"
	IssueExceptionAggregateMember IssueExceptionRelationship = "aggregate_member"
	IssueExceptionSuppressed      IssueExceptionRelationship = "suppressed"
)

type IssueExceptionStackFramesState added in v0.1.7

type IssueExceptionStackFramesState string

IssueExceptionStackFramesState reports whether one exception stack was captured, truncated, or unavailable.

const (
	IssueExceptionStackFramesCaptured    IssueExceptionStackFramesState = "captured"
	IssueExceptionStackFramesTruncated   IssueExceptionStackFramesState = "truncated"
	IssueExceptionStackFramesNotCaptured IssueExceptionStackFramesState = "not_captured"
)

type IssueImpactEvidence added in v0.1.8

type IssueImpactEvidence struct {
	AffectedUserSegment string `json:"affectedUserSegment,omitempty"`
	FailedAction        string `json:"failedAction,omitempty"`
	UserVisibleOutcome  string `json:"userVisibleOutcome,omitempty"`
}

IssueImpactEvidence describes application-reported user-visible impact without carrying user identities.

type IssueLikelyFixArea added in v0.1.8

type IssueLikelyFixArea struct {
	Component string `json:"component,omitempty"`
	Module    string `json:"module,omitempty"`
	Function  string `json:"function,omitempty"`
	File      string `json:"file,omitempty"`
	Line      int    `json:"line,omitempty"`
	Column    int    `json:"column,omitempty"`
	InApp     *bool  `json:"inApp,omitempty"`
}

IssueLikelyFixArea is an application-reported code location that may contain the fix. File paths are repository-relative.

type IssueStackFrame added in v0.1.6

type IssueStackFrame struct {
	Filename string `json:"filename"`
	Line     int    `json:"line"`
	Column   int    `json:"column"`
	Function string `json:"function,omitempty"`
	Module   string `json:"module,omitempty"`
	InApp    *bool  `json:"inApp,omitempty"`
	DebugID  string `json:"debugId,omitempty"`
}

IssueStackFrame is one structured code location. CaptureIssueStackFrames emits basename-only generated filenames and never includes source text, locals, or raw stack strings.

func CaptureIssueStackFrames added in v0.1.6

func CaptureIssueStackFrames() []IssueStackFrame

CaptureIssueStackFrames snapshots the current goroutine's call frames in newest-first order. It returns at most 32 validated frames with basename-only filenames and bounded function/module identities. It never captures source lines, local variables, raw stack text, or panic values.

type LogAttributes

type LogAttributes struct {
	Message  string            `json:"message"`
	Level    string            `json:"level"`
	Logger   string            `json:"logger,omitempty"`
	Metadata map[string]any    `json:"metadata,omitempty"`
	Context  *TelemetryContext `json:"context,omitempty"`
}

LogAttributes describes the public payload fields for a log event.

func LogAttributesWithTrace added in v0.1.2

func LogAttributesWithTrace(ctx context.Context, attributes LogAttributes) LogAttributes

LogAttributesWithTrace merges active trace metadata into log attributes.

type MetricAttributes added in v0.1.1

type MetricAttributes struct {
	Name        string            `json:"name"`
	Description string            `json:"description,omitempty"`
	Kind        string            `json:"kind"`
	Value       float64           `json:"value"`
	Unit        string            `json:"unit"`
	Temporality string            `json:"temporality"`
	Metadata    map[string]any    `json:"metadata,omitempty"`
	Context     *TelemetryContext `json:"context,omitempty"`
}

MetricAttributes describes the public payload fields for an explicit metric event.

func MetricAttributesWithTrace added in v0.1.6

func MetricAttributesWithTrace(ctx context.Context, attributes MetricAttributes) MetricAttributes

MetricAttributesWithTrace adds exact active trace/span context while keeping legacy primitive metadata for compatible readers.

type NetworkMilestoneInput added in v0.1.1

type NetworkMilestoneInput struct {
	Name          string
	RouteTemplate string
	Method        string
	Status        string
	StatusCode    *int
	DurationMs    *float64
	SessionID     string
	TraceID       string
	Metadata      map[string]any
}

NetworkMilestoneInput describes an app-owned API milestone that should be captured as an agent-readable action event.

type PersistentDeliveryConfig added in v0.1.4

type PersistentDeliveryConfig struct {
	// Directory is the dedicated owner-only storage leaf.
	Directory string
	// EncryptionKey is a stable caller-owned 32-byte AES-256 key.
	EncryptionKey []byte
	// MaxStoredBytes bounds canonical serialized event bytes. Zero uses 4 MiB.
	MaxStoredBytes int
}

PersistentDeliveryConfig opts an owned automatic client into encrypted restart persistence. EncryptionKey must contain exactly 32 caller-owned bytes and is never written to storage.

type ProductActionInput added in v0.1.1

type ProductActionInput struct {
	Name          string
	Status        string
	RouteTemplate string
	SessionID     string
	TraceID       string
	Screen        string
	Funnel        string
	Step          string
	Metadata      map[string]any
}

ProductActionInput describes an app-owned product step that should be captured as an agent-readable action event.

type QueueOperationConfig added in v0.1.2

type QueueOperationConfig struct {
	System              string
	OperationKind       string
	QueueName           string
	TaskName            string
	MessageCount        *int
	EventIDPrefix       string
	Metadata            map[string]any
	TraceparentSetter   func(string) error
	IncomingTraceparent string
	LinkedTraceparents  []string
	Links               []SpanLinkSummary
	LinkMetadata        map[string]any
	SpanIDFactory       func() string
	Now                 func() time.Time
	OnError             func(error)
}

QueueOperationConfig configures an explicit app-owned queue span.

type RecordingTransport

type RecordingTransport struct {

	// SentBodies records every request body sent through this transport.
	SentBodies [][]byte
	// contains filtered or unexported fields
}

RecordingTransport scripts transport outcomes for previewing, accepting, or failing queued event flushes in tests and local runs.

func AlwaysAcceptTransport

func AlwaysAcceptTransport() *RecordingTransport

AlwaysAcceptTransport creates a transport that accepts every queued flush request with a 202 response.

func NewRecordingTransport

func NewRecordingTransport(scripted []any) *RecordingTransport

NewRecordingTransport creates a scripted transport from public status codes or transport errors.

func (*RecordingTransport) LastBody

func (t *RecordingTransport) LastBody() []byte

LastBody returns the most recent request body sent through this transport.

func (*RecordingTransport) Send

func (t *RecordingTransport) Send(apiKey string, body []byte) (*TransportResponse, error)

type ReleaseAttributes

type ReleaseAttributes struct {
	Version  string            `json:"version"`
	Commit   string            `json:"commit,omitempty"`
	Notes    string            `json:"notes,omitempty"`
	Metadata map[string]any    `json:"metadata,omitempty"`
	Context  *TelemetryContext `json:"context,omitempty"`
}

ReleaseAttributes describes the public payload fields for a release event.

type SQLBeginTxRunner added in v0.1.3

type SQLBeginTxRunner interface {
	BeginTx(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, error)
}

SQLBeginTxRunner is implemented by app-owned *sql.DB and *sql.Conn values that can start database/sql transactions.

type SQLExecContextRunner added in v0.1.3

type SQLExecContextRunner interface {
	ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
}

SQLExecContextRunner is implemented by app-owned *sql.DB, *sql.Tx, and *sql.Conn values that can run exec operations from query text.

type SQLQueryContextRunner added in v0.1.3

type SQLQueryContextRunner interface {
	QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
}

SQLQueryContextRunner is implemented by app-owned *sql.DB, *sql.Tx, and *sql.Conn values that can run query operations from query text.

type SQLStatementExecContextRunner added in v0.1.3

type SQLStatementExecContextRunner interface {
	ExecContext(ctx context.Context, args ...any) (sql.Result, error)
}

SQLStatementExecContextRunner is implemented by app-owned *sql.Stmt values that can run prepared exec operations from args only.

type SQLStatementQueryContextRunner added in v0.1.3

type SQLStatementQueryContextRunner interface {
	QueryContext(ctx context.Context, args ...any) (*sql.Rows, error)
}

SQLStatementQueryContextRunner is implemented by app-owned *sql.Stmt values that can run prepared query operations from args only.

type SdkError

type SdkError struct {
	Code    string
	Message string
}

SdkError describes a stable public SDK failure with parseable code and message fields.

func (*SdkError) Error

func (e *SdkError) Error() string

type SlogHandlerConfig added in v0.1.2

type SlogHandlerConfig struct {
	Client        *Client
	Wrapped       slog.Handler
	Logger        string
	EventIDPrefix string
	Metadata      map[string]any
	Now           func() time.Time
	OnError       func(error)
}

SlogHandlerConfig configures a slog handler that preserves app-owned logging while also queueing LogBrew log events.

type SpanAttributes

type SpanAttributes struct {
	Name         string            `json:"name"`
	TraceID      string            `json:"traceId"`
	SpanID       string            `json:"spanId"`
	ParentSpanID string            `json:"parentSpanId,omitempty"`
	Status       string            `json:"status"`
	DurationMs   *float64          `json:"durationMs,omitempty"`
	Metadata     map[string]any    `json:"metadata,omitempty"`
	Links        []SpanLinkSummary `json:"links,omitempty"`
	Context      *TelemetryContext `json:"context,omitempty"`
}

SpanAttributes describes the public payload fields for a span event.

func SpanAttributesFromTraceContext added in v0.1.2

func SpanAttributesFromTraceContext(input TraceContextSpanInput) (SpanAttributes, error)

SpanAttributesFromTraceContext returns LogBrew span attributes from request-local trace context.

func SpanAttributesFromTraceparent

func SpanAttributesFromTraceparent(input TraceparentSpanInput) (SpanAttributes, error)

SpanAttributesFromTraceparent returns LogBrew span attributes that continue an incoming W3C traceparent as a child span.

type SpanLinkSummary added in v0.1.3

type SpanLinkSummary struct {
	TraceID  string         `json:"traceId"`
	SpanID   string         `json:"spanId"`
	Sampled  bool           `json:"sampled"`
	Metadata map[string]any `json:"metadata,omitempty"`
}

SpanLinkSummary is a privacy-bounded link from one span to another W3C trace context, useful for queue batch/fan-in relationships.

func NewSpanLinkSummary added in v0.1.3

func NewSpanLinkSummary(traceID, spanID string, sampled bool) (SpanLinkSummary, error)

NewSpanLinkSummary validates explicit W3C trace and span IDs and returns a safe span-link summary.

func SpanLinkSummaryFromTraceparent added in v0.1.3

func SpanLinkSummaryFromTraceparent(traceparent string) (SpanLinkSummary, error)

SpanLinkSummaryFromTraceparent validates a W3C traceparent value and returns a safe span-link summary without retaining the raw propagation string.

type SupportTicketDraft added in v0.1.2

type SupportTicketDraft struct {
	ProjectID   string         `json:"project_id,omitempty"`
	Source      string         `json:"source"`
	Category    string         `json:"category"`
	Title       string         `json:"title"`
	Description string         `json:"description"`
	Environment string         `json:"environment,omitempty"`
	Runtime     string         `json:"runtime,omitempty"`
	Framework   string         `json:"framework,omitempty"`
	SDKPackage  string         `json:"sdk_package,omitempty"`
	SDKVersion  string         `json:"sdk_version,omitempty"`
	Release     string         `json:"release,omitempty"`
	TraceID     string         `json:"trace_id,omitempty"`
	EventID     string         `json:"event_id,omitempty"`
	Diagnostics map[string]any `json:"diagnostics,omitempty"`
}

SupportTicketDraft is the planned support-ticket create payload after local validation and diagnostics redaction.

func CreateSupportTicketDraft added in v0.1.2

func CreateSupportTicketDraft(input SupportTicketDraftInput) (SupportTicketDraft, error)

CreateSupportTicketDraft builds a local-only, token-free support-ticket create payload draft without calling backend support routes.

type SupportTicketDraftInput added in v0.1.2

type SupportTicketDraftInput struct {
	ProjectID   string
	Source      string
	Category    string
	Title       string
	Description string
	Environment string
	Runtime     string
	Framework   string
	SDKPackage  string
	SDKVersion  string
	Release     string
	TraceID     string
	EventID     string
	Diagnostics map[string]any
}

SupportTicketDraftInput describes an explicit local-only draft for planned backend support-ticket routes. It does not open a ticket or send telemetry.

type TelemetryApplication added in v0.1.6

type TelemetryApplication struct {
	Name    string `json:"name,omitempty"`
	Version string `json:"version,omitempty"`
	Build   string `json:"build,omitempty"`
}

TelemetryApplication identifies the instrumented application and build.

type TelemetryContext added in v0.1.6

type TelemetryContext struct {
	SchemaVersion int                      `json:"schemaVersion"`
	Resource      *TelemetryResource       `json:"resource,omitempty"`
	Trace         *TelemetryTraceContext   `json:"trace,omitempty"`
	Session       *TelemetrySessionContext `json:"session,omitempty"`
	Subject       *TelemetrySubjectContext `json:"subject,omitempty"`
	Tags          map[string]string        `json:"tags,omitempty"`
}

TelemetryContext is the versioned privacy-bounded context available on every LogBrew event type. Tags are limited to low-cardinality string dimensions.

func MergeTelemetryContexts added in v0.1.6

func MergeTelemetryContexts(base, override *TelemetryContext) (*TelemetryContext, error)

MergeTelemetryContexts applies the same client-base and event-override rules used by Client event capture and returns a detached result.

func ValidateTelemetryContext added in v0.1.6

func ValidateTelemetryContext(context *TelemetryContext) (*TelemetryContext, error)

ValidateTelemetryContext validates, normalizes, and detaches one shared context without queueing an event.

type TelemetryDeployment added in v0.1.6

type TelemetryDeployment struct {
	Environment string `json:"environment,omitempty"`
	Release     string `json:"release,omitempty"`
}

TelemetryDeployment identifies an application deployment without host data.

type TelemetryDevice added in v0.1.6

type TelemetryDevice struct {
	Family       string `json:"family,omitempty"`
	Model        string `json:"model,omitempty"`
	Architecture string `json:"architecture,omitempty"`
}

TelemetryDevice describes a broad device or runtime host class. Do not put unique device identifiers, machine names, network addresses, or local account names here.

type TelemetryNamedVersion added in v0.1.6

type TelemetryNamedVersion struct {
	Name    string `json:"name"`
	Version string `json:"version,omitempty"`
}

TelemetryNamedVersion is a bounded service, runtime, or framework identity.

type TelemetryOperatingSystem added in v0.1.6

type TelemetryOperatingSystem struct {
	Name    string `json:"name"`
	Version string `json:"version,omitempty"`
	Build   string `json:"build,omitempty"`
}

TelemetryOperatingSystem identifies an OS family and optional safe version.

type TelemetryResource added in v0.1.6

type TelemetryResource struct {
	Service         *TelemetryNamedVersion    `json:"service,omitempty"`
	Deployment      *TelemetryDeployment      `json:"deployment,omitempty"`
	Runtime         *TelemetryNamedVersion    `json:"runtime,omitempty"`
	Framework       *TelemetryNamedVersion    `json:"framework,omitempty"`
	OperatingSystem *TelemetryOperatingSystem `json:"operatingSystem,omitempty"`
	Device          *TelemetryDevice          `json:"device,omitempty"`
	Application     *TelemetryApplication     `json:"application,omitempty"`
}

TelemetryResource is the shared service, deployment, runtime, framework, OS, device, and application identity attached to telemetry signals.

type TelemetrySessionContext added in v0.1.6

type TelemetrySessionContext struct {
	ID         string `json:"id"`
	PreviousID string `json:"previousId,omitempty"`
}

TelemetrySessionContext is an opaque application-owned session identity. It must not contain an email address, authentication material, or other direct PII.

type TelemetrySubjectContext added in v0.1.6

type TelemetrySubjectContext struct {
	ID   string `json:"id"`
	Kind string `json:"kind"`
}

TelemetrySubjectContext is an explicit opaque user or anonymous identity. Applications should use their own irreversible or otherwise non-PII ID.

type TelemetryTraceContext added in v0.1.6

type TelemetryTraceContext struct {
	TraceID      string `json:"traceId"`
	SpanID       string `json:"spanId,omitempty"`
	ParentSpanID string `json:"parentSpanId,omitempty"`
	Sampled      *bool  `json:"sampled,omitempty"`
}

TelemetryTraceContext is exact W3C-compatible trace and span correlation for any telemetry signal.

type TraceContext added in v0.1.2

type TraceContext struct {
	TraceID      string
	SpanID       string
	ParentSpanID string
	TraceFlags   string
	Sampled      bool
}

TraceContext is the request-local LogBrew trace state safe to attach to logs, spans, issues, and callbacks.

func LogBrewTraceFromContext added in v0.1.2

func LogBrewTraceFromContext(ctx context.Context) (TraceContext, bool)

LogBrewTraceFromContext returns the active LogBrew trace context, when one is attached to ctx.

func NewTraceContext added in v0.1.2

func NewTraceContext(input TraceContextInput) (TraceContext, error)

NewTraceContext creates a request-local trace context. When Traceparent is empty it starts a fresh W3C-shaped local trace; malformed traceparent values are returned as validation errors so framework helpers can choose whether to fall back non-fatally.

func (TraceContext) Metadata added in v0.1.2

func (trace TraceContext) Metadata() map[string]any

Metadata returns primitive-only trace metadata for logs, issues, and metrics.

func (TraceContext) TelemetryContext added in v0.1.6

func (trace TraceContext) TelemetryContext() *TelemetryContext

TelemetryContext returns first-class W3C trace and exact span correlation suitable for an issue, log, action, or metric Context field.

type TraceContextInput added in v0.1.2

type TraceContextInput struct {
	Traceparent string
	SpanID      string
}

TraceContextInput creates request-local trace context from an optional W3C traceparent header and optional explicit child span ID.

type TraceContextSpanInput added in v0.1.2

type TraceContextSpanInput struct {
	Trace      TraceContext
	Name       string
	Status     string
	DurationMs *float64
	Metadata   map[string]any
	Links      []SpanLinkSummary
}

TraceContextSpanInput describes a LogBrew span derived from a request-local TraceContext.

type TraceparentContext

type TraceparentContext struct {
	// Version is the two-character W3C traceparent version.
	Version string
	// TraceID is the normalized 32-character trace identifier.
	TraceID string
	// ParentSpanID is the normalized 16-character upstream span identifier.
	ParentSpanID string
	// TraceFlags is the normalized two-character trace flags value.
	TraceFlags string
	// Sampled reports whether the W3C sampled flag is set.
	Sampled bool
}

TraceparentContext describes an incoming W3C traceparent header after validation and normalization.

func ParseTraceparent

func ParseTraceparent(traceparent string) (TraceparentContext, error)

ParseTraceparent validates and normalizes a W3C traceparent header.

type TraceparentSpanInput

type TraceparentSpanInput struct {
	// Traceparent is the incoming W3C traceparent header value.
	Traceparent string
	// Name is the LogBrew span name.
	Name string
	// SpanID is the fresh child span identifier created by this service.
	SpanID string
	// Status is the LogBrew span status, usually ok or error.
	Status string
	// DurationMs is the optional span duration in milliseconds.
	DurationMs *float64
	// Metadata is copied with primitive values only.
	Metadata map[string]any
}

TraceparentSpanInput describes a LogBrew span derived from an incoming W3C traceparent header.

type Transport

type Transport interface {
	Send(apiKey string, body []byte) (*TransportResponse, error)
}

Transport is the public interface used by Flush and Shutdown transport calls.

type TransportError

type TransportError struct {
	Code      string
	Message   string
	Retryable bool
}

TransportError describes a transport-layer failure with a stable public code and retry hint.

func NetworkError

func NetworkError(message string) *TransportError

NetworkError creates a retryable network failure that preserves queued events.

func (*TransportError) Error

func (e *TransportError) Error() string

type TransportResponse

type TransportResponse struct {
	// StatusCode is the final HTTP-like status returned by the transport.
	StatusCode int `json:"status"`
	// Attempts is the number of transport attempts used for the flush.
	Attempts int `json:"attempts"`
}

TransportResponse is returned after a transport accepts or skips a queued flush.

Directories

Path Synopsis
examples
agent_timeline command
readme_example command
real_user_smoke command
gin module
otel module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL