Documentation
¶
Index ¶
- Constants
- Variables
- func CategoryForOperation(operationID string) (oapi.TelemetryEventCategory, bool)
- func CategoryForType(eventType string) (oapi.TelemetryEventCategory, bool)
- func HasCDPCategory(cats []oapi.TelemetryEventCategory) bool
- func NewDropCountingHandler(base slog.Handler, metrics *OTLPMetrics) slog.Handler
- func TruncateCaptured(s string, maxBytes int) string
- type Envelope
- type Event
- type EventStream
- type EventStreamConfig
- type OTLPConfig
- type OTLPExportController
- type OTLPMetrics
- type OTLPStorageWriter
- type ReadResult
- type Reader
- type S2Config
- type S2StorageWriter
- type Storage
- type StorageWriter
Constants ¶
const ( Console = oapi.TelemetryEventCategory("console") Network = oapi.TelemetryEventCategory("network") Page = oapi.TelemetryEventCategory("page") Interaction = oapi.TelemetryEventCategory("interaction") Control = oapi.TelemetryEventCategory("control") Platform = oapi.TelemetryEventCategory("platform") Connection = oapi.TelemetryEventCategory("connection") System = oapi.TelemetryEventCategory("system") Screenshot = oapi.TelemetryEventCategory("screenshot") Captcha = oapi.TelemetryEventCategory("captcha") Monitor = oapi.TelemetryEventCategory("monitor") )
const CapturedFieldCap = 8 * 1024
CapturedFieldCap is the ceiling for a single captured string on an event: response bodies of structured types, and the source submitted to Playwright execution. It sits two orders of magnitude below maxS2RecordBytes so no one field can push an envelope past the record limit, which would null the whole payload rather than clip the field.
const DefaultOTLPMaxBatchRecords = 200
DefaultOTLPMaxBatchRecords bounds how many records the SDK buffers per export cycle. The per-request byte size is bounded separately by the loggingExporter, which splits an export into sub-requests under maxOTLPExportBytes so a batch of large records can't exceed the target's HTTP body limit. Exported so the config layer can validate the queue size against it (the queue must hold at least one full batch).
const DefaultRingMaxBytes = 64 << 20
DefaultRingMaxBytes bounds the ring when a caller does not choose. Sized to hold a full ring of control events comfortably while keeping a run of screenshot-sized ones from costing capacity times the largest envelope.
const TruncatedSuffix = "...[truncated]"
TruncatedSuffix marks a captured string that was cut at its cap, so a consumer can tell a clipped value from a complete one.
Variables ¶
var DefaultCategories = []oapi.TelemetryEventCategory{ Control, Connection, System, Captcha, }
DefaultCategories is captured when the caller enables telemetry without per-category settings: the lightweight operational signals. CDP categories (console/network/page/interaction) and screenshot are excluded so the default never starts the CDP collector or emits high-volume streams; they are opt-in. Platform is excluded too: those calls are mostly platform-induced bookkeeping (recording, profile save) that drowns out the agent's own actions.
var UserCategories = []oapi.TelemetryEventCategory{ Console, Network, Page, Interaction, Control, Platform, Connection, System, Screenshot, Captcha, }
UserCategories are the categories a caller can configure via the telemetry config. Monitor is excluded: it is CDP-collector health metadata that flows automatically whenever a CDP category is captured, not a configurable knob.
Functions ¶
func CategoryForOperation ¶
func CategoryForOperation(operationID string) (oapi.TelemetryEventCategory, bool)
CategoryForOperation returns the category an api_call event carries for the given operation, keyed by the generated handler name the event reports. ok is false for an unknown operation.
func CategoryForType ¶
func CategoryForType(eventType string) (oapi.TelemetryEventCategory, bool)
CategoryForType returns the authoritative category for a known event type. ok is false for an unknown type.
func HasCDPCategory ¶
func HasCDPCategory(cats []oapi.TelemetryEventCategory) bool
HasCDPCategory reports whether the set contains any CDP-collector category. It is the single predicate gating both the collector start and Monitor inclusion, so the two can never diverge.
func NewDropCountingHandler ¶
func NewDropCountingHandler(base slog.Handler, metrics *OTLPMetrics) slog.Handler
NewDropCountingHandler wraps base so OTel batch-queue drop reports are summed into metrics before being logged as usual.
func TruncateCaptured ¶
TruncateCaptured caps s at maxBytes on a rune boundary, so the result never splits a multi-byte character, and appends TruncatedSuffix when it cuts.
Types ¶
type Event ¶
type Event struct {
// Ts is the event time in Unix microseconds. It must be wall-clock
// (time.Now()) captured at emit/observe, never a monotonic or other
// source-derived clock (e.g. a kmsg envelope timestamp), which skews
// on VM suspend. HTTP-published events are stamped by the API handler;
// in-process producers must set it themselves.
Ts int64 `json:"ts"`
Type string `json:"type"`
Category oapi.TelemetryEventCategory `json:"category"`
Source oapi.BrowserEventSource `json:"source"`
Data json.RawMessage `json:"data,omitempty"`
Truncated bool `json:"truncated,omitempty"`
}
Event is the portable event schema. It contains only producer-emitted content; pipeline metadata (seq) lives on the Envelope.
type EventStream ¶
type EventStream struct {
// contains filtered or unexported fields
}
EventStream is the process-lifetime event bus. It owns the ring buffer and sequence counter, which outlive individual capture sessions.
func NewEventStream ¶
func NewEventStream(cfg EventStreamConfig) (*EventStream, error)
func (*EventStream) DroppedEvents ¶
func (es *EventStream) DroppedEvents() uint64
DroppedEvents returns the cumulative gap count across consumers, so a reader can tell a quiet stream from one it is falling behind.
func (*EventStream) NewReader ¶
func (es *EventStream) NewReader(afterSeq uint64) *Reader
NewReader returns a Reader positioned after afterSeq. Pass 0 to start from the oldest buffered event.
func (*EventStream) Publish ¶
func (es *EventStream) Publish(env Envelope) Envelope
Publish assigns a monotonically increasing seq to env, truncates oversized payloads, and pushes it to the ring buffer.
func (*EventStream) RecordDropped ¶
func (es *EventStream) RecordDropped(n uint64)
RecordDropped notes that a consumer found a gap of n envelopes. Consumers report it rather than the ring detecting it, because only a consumer knows what it had already read.
func (*EventStream) Seq ¶
func (es *EventStream) Seq() uint64
Seq returns the sequence number of the last published event.
type EventStreamConfig ¶
type EventStreamConfig struct {
// RingCapacity is the number of envelopes the ring buffer holds.
RingCapacity int
// RingMaxBytes bounds the memory those envelopes may occupy. Zero uses
// DefaultRingMaxBytes. Capacity alone does not bound memory: a slot holds
// anything from a small control event to a base64 screenshot.
RingMaxBytes uint64
}
type OTLPConfig ¶
type OTLPConfig struct {
// Endpoint is the host[:port] of the OTLP/HTTP target: a collector in
// development, or a forwarding relay in production.
Endpoint string
// URLPath overrides the request path. Empty uses the exporter default of
// /v1/logs.
URLPath string
// Insecure sends over plaintext HTTP. Development only.
Insecure bool
// Headers are attached to every export request.
Headers map[string]string
// AuthTokenFunc, when set, is called on every export request to resolve the
// bearer credential, set as "Authorization: Bearer <token>". It is read per
// request (not captured once) so a credential that changes after start, e.g.
// the instance JWT refreshed from an applied fork-identity payload, takes
// effect without restarting the process. An empty return sends no header.
AuthTokenFunc func() string
// ServiceName, InstanceName, and Metro populate the OTLP Resource.
ServiceName string
InstanceName string
Metro string
// InstanceNameFunc and MetroFunc, when set, resolve the resource identity at
// exporter-build time and take precedence over the static InstanceName/Metro.
// Like AuthTokenFunc, this lets a forked VM stamp the fresh identity from its
// applied fork-identity payload instead of stale boot env. Since export is
// started per session after identity applies, build time sees the applied
// values.
InstanceNameFunc func() string
MetroFunc func() string
// Batch tuning. Zero values fall back to the SDK defaults.
MaxQueueSize int
ExportInterval time.Duration
ExportTimeout time.Duration
// Metrics accumulates export counters. When nil a throwaway is used so the
// sink still runs; callers that scrape metrics pass a shared instance.
Metrics *OTLPMetrics
}
OTLPConfig configures the OTLP telemetry sink.
type OTLPExportController ¶
type OTLPExportController struct {
// contains filtered or unexported fields
}
OTLPExportController starts and stops OTLP export on demand so it can be toggled at runtime via the telemetry API. The underlying writer is one-shot, so each enable builds a fresh one. Safe for concurrent use.
func NewOTLPExportController ¶
func NewOTLPExportController(es *EventStream, cfg OTLPConfig, log *slog.Logger) *OTLPExportController
func (*OTLPExportController) Running ¶
func (c *OTLPExportController) Running() bool
Running reports whether export is currently active.
func (*OTLPExportController) Start ¶
func (c *OTLPExportController) Start(parent context.Context) error
Start begins export, or is a no-op if already running. parent governs the read loop; the controller derives a cancelable child so Stop can halt the loop even when parent is still live (a runtime toggle-off).
type OTLPMetrics ¶
type OTLPMetrics struct {
// contains filtered or unexported fields
}
OTLPMetrics holds process-lifetime counters for the OTLP export sink. It is owned above the export writer so the counts stay monotonic across export enable/disable cycles (the writer is rebuilt on each enable). Safe for concurrent use.
func (*OTLPMetrics) Dropped ¶
func (m *OTLPMetrics) Dropped() uint64
Dropped returns records dropped from the batch queue under backpressure.
func (*OTLPMetrics) Exported ¶
func (m *OTLPMetrics) Exported() uint64
Exported returns records that were successfully exported.
func (*OTLPMetrics) Failures ¶
func (m *OTLPMetrics) Failures() uint64
Failures returns export requests that returned an error.
type OTLPStorageWriter ¶
type OTLPStorageWriter struct {
// contains filtered or unexported fields
}
OTLPStorageWriter reads from an EventStream and forwards each event to an OTLP endpoint. Construct with NewOTLPStorageWriter, call Start to begin and Stop to drain and shut down. Unlike S2StorageWriter it starts from the stream tail at Start, so a writer rebuilt on a runtime export re-enable forwards only new events rather than replaying the retained ring.
func NewOTLPStorageWriter ¶
func NewOTLPStorageWriter(es *EventStream, cfg OTLPConfig, log *slog.Logger) *OTLPStorageWriter
func (*OTLPStorageWriter) Start ¶
func (w *OTLPStorageWriter) Start(ctx context.Context) error
Start builds the exporter and begins reading from the event stream. ctx governs the Run loop; cancel it (e.g. on SIGTERM) to stop reading. The exporter outlives ctx and is torn down by Stop after flushing.
type ReadResult ¶
ReadResult is returned by Reader.Read. Exactly one of Envelope or Dropped is set: Envelope is non-nil for a normal read, Dropped is non-zero when the reader fell behind and events were lost.
type Reader ¶
type Reader struct {
// contains filtered or unexported fields
}
Reader tracks an independent read position in a ringBuffer.
func (*Reader) Read ¶
func (r *Reader) Read(ctx context.Context) (ReadResult, error)
Read blocks until the next envelope is available or ctx is cancelled.
func (*Reader) TryRead ¶
func (r *Reader) TryRead() (ReadResult, bool)
TryRead returns the next available result without blocking. Returns (result, true) if data is available, (ReadResult{}, false) if the reader has caught up to the latest published seq.
type S2StorageWriter ¶
type S2StorageWriter struct {
// contains filtered or unexported fields
}
S2StorageWriter reads from an EventStream and forwards each event to S2. Construct with NewS2StorageWriter, call Start to begin, Stop to drain and shut down.
func NewS2StorageWriter ¶
func NewS2StorageWriter(es *EventStream, basin, accessToken, streamName string, cfg S2Config, log *slog.Logger) *S2StorageWriter
func (*S2StorageWriter) Start ¶
func (w *S2StorageWriter) Start(ctx context.Context) error
Start opens the S2 append session and begins reading from the event stream. ctx governs the Run loop — cancel it (e.g. on SIGTERM) to stop reading. The session itself outlives ctx and is torn down by Stop after flushing.
type StorageWriter ¶
type StorageWriter struct {
// contains filtered or unexported fields
}
StorageWriter reads from the ring buffer and forwards each envelope to Storage. Single-use and not thread-safe: call Run once, then after it returns call Drain followed by Close. Reads start from the oldest available event in the ring, not the current tail. Delivery is at-least-once; consumers should dedupe by env.Seq.
func NewStorageWriter ¶
func NewStorageWriter(es *EventStream, storage Storage, log *slog.Logger) *StorageWriter
NewStorageWriter creates a writer that reads from es starting at the oldest buffered event (seq 0).
func NewStorageWriterAfter ¶
func NewStorageWriterAfter(es *EventStream, storage Storage, log *slog.Logger, afterSeq uint64) *StorageWriter
NewStorageWriterAfter creates a writer that reads from es starting after afterSeq. Pass 0 to start from the oldest buffered event; pass the stream's current seq to start from the tail (only future events), so a writer that is rebuilt on demand does not replay the ring.
func (*StorageWriter) Close ¶
func (w *StorageWriter) Close(ctx context.Context) error
Close drains in-flight writes and releases backend resources.