events

package
v0.0.0-...-94d7571 Latest Latest
Warning

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

Go to latest
Published: Aug 24, 2026 License: Apache-2.0 Imports: 20 Imported by: 0

Documentation

Index

Constants

View Source
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")
)
View Source
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.

View Source
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).

View Source
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.

View Source
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

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.

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

func TruncateCaptured(s string, maxBytes int) string

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 Envelope

type Envelope struct {
	Seq   uint64 `json:"seq"`
	Event Event  `json:"event"`
}

Envelope wraps an Event with pipeline-assigned metadata.

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).

func (*OTLPExportController) Stop

Stop drains and shuts down a running exporter, or is a no-op if stopped. ctx bounds shutdown time.

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.

func (*OTLPStorageWriter) Stop

func (w *OTLPStorageWriter) Stop(ctx context.Context) error

Stop waits for the Run goroutine to exit, drains remaining ring events, then flushes and shuts down the exporter. ctx bounds total shutdown time.

type ReadResult

type ReadResult struct {
	Envelope *Envelope
	Dropped  uint64
}

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 S2Config

type S2Config struct {
	// BatcherLinger is how long the batcher waits before flushing (default: 100ms).
	BatcherLinger time.Duration
	// BatcherMaxRecords is the max records per batch (default: 50).
	BatcherMaxRecords int
}

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.

func (*S2StorageWriter) Stop

func (w *S2StorageWriter) Stop(ctx context.Context) error

Stop waits for the Run goroutine to exit, drains any remaining ring events, then closes the S2 producer. ctx bounds the total shutdown time.

type Storage

type Storage interface {
	Append(ctx context.Context, env Envelope) error
	Close(ctx context.Context) error
}

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.

func (*StorageWriter) Drain

func (w *StorageWriter) Drain(ctx context.Context) error

Drain reads any events still in the ring non-blockingly until caught up or ctx expires. Call after all publishers have stopped and Run has returned to ensure no events are silently skipped on shutdown.

func (*StorageWriter) Run

func (w *StorageWriter) Run(ctx context.Context) error

Run reads from the ring buffer and appends each envelope to storage until ctx is cancelled. Returns the context error on clean shutdown. Must be called at most once; returns an error on a second call.

Jump to

Keyboard shortcuts

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