plugin

package
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Jun 2, 2026 License: MIT Imports: 3 Imported by: 0

Documentation

Overview

Package plugin defines the Phase A observe-class plugin surface (ObserveOnFinalize / ObserveAfterWrite) used by the path-filter plugin to drop traces before they reach the writer. Plugins are registered in-process at startup from the operator's enabled list; there is no hot-load. Hook-class plugins (request/response mutation) live under internal/plugin/v2.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ObserveAfterWrite

type ObserveAfterWrite interface {
	Plugin
	AfterWrite(ctx context.Context, tr trace.Trace)
}

ObserveAfterWrite is the observe-class hook called AFTER the writer chain has finished. It fires after the JSONL line is on disk and the SQLite row has been upserted — i.e. the trace is durable and queryable.

AfterWrite is the natural home for side-effecting observation: counter exports, downstream notification sinks, and operator dashboards. The in-tree project does not ship an alerting plugin; operators who want webhooks can register one.

Hook contract:

  • Runs after writer enqueue; delivery is best-effort because TrySend is non-blocking.
  • Runs in registration order, sequentially per trace. Phase A does NOT fan out to a worker pool; that is Phase B territory if the observed plugins prove load-bearing.
  • Errors are logged. There is no way for an AfterWrite plugin to un-write an already-recorded trace; the filesystem is the source of truth and append-only. Operators learn about plugin errors via /healthz counters.

Renamed from ObserveAfterRecord per plugin-b-c-spec §7.3 (Phase A migration); the "AfterWrite" name keeps the side-effecting-only semantics distinct from the hook-class AFTER (which can mutate the response before the client sees it).

type ObserveOnFinalize

type ObserveOnFinalize interface {
	Plugin
	OnFinalize(ctx context.Context, tr trace.Trace) (shouldRecord bool, err error)
}

ObserveOnFinalize is the observe-class hook called BEFORE the writer chain runs. It fires inside the trace finalize block, after buildTrace has produced a *trace.Trace but before the writer goroutine has been notified.

Returning shouldRecord=false drops the trace: no JSONL line is appended, no SQLite row is inserted, no downstream observation fires. This is the path-filter plugin's mechanism for honoring operator-configured noise filters at capture time (the capture-time skip path).

Returning a non-nil err is LOGGED and surfaced via /healthz counters but does NOT block forwarding and does NOT change shouldRecord on its own — fail-open for capture. A plugin that wants to drop on error returns shouldRecord=false alongside its err; a plugin that wants to record on error returns shouldRecord=true.

The trace value is passed BY VALUE to communicate read-only intent. Plugins MUST NOT retain references to req/resp body bytes past the call; the underlying buffers may be reused by the parser.

Hook contract:

  • Runs after the response has been fully delivered to the client. Cannot affect forwarding.
  • Runs synchronously on the finalize goroutine; the writer is not notified until every OnFinalize plugin has returned.
  • Runs in registration order. Returning shouldRecord=false from any plugin SHORT-CIRCUITS the iteration: subsequent plugins do not see the dropped trace.

Renamed from ObserveBeforeRecord per plugin-b-c-spec §7.3 (Phase A migration) to reflect that this fires inside the finalize block, not the writer pipeline. Observer-class plugins decide whether the trace is recorded; hook-class plugins (v2.BeforePlugin / v2.AfterPlugin) shape what flows to the client.

type Plugin

type Plugin interface {
	// Name returns the stable identifier used in config and telemetry.
	// MUST be a compile-time constant string and MUST match the key
	// the registry knows the plugin by. Two plugins with the same Name
	// are a configuration error.
	Name() string

	// Init is called once at process startup with the plugin's parsed
	// config subtree (the value at plugins.config.<name> in YAML, or
	// the equivalent struct field). Returning a non-nil error fails
	// process start; the caller logs and exits.
	//
	// Plugins MUST NOT perform background work, open files, or start
	// goroutines from Init unless those resources are owned and closed
	// in Close. Init should be cheap and synchronous.
	Init(cfg map[string]any) error

	// Close is called at process shutdown after the writer has drained.
	// Plugins SHOULD flush any buffered state here. Errors are logged
	// but do not block shutdown.
	Close() error
}

Plugin is the base contract every observe-class plugin satisfies.

A plugin opts into individual hooks by also implementing one of the hook interfaces (ObserveOnFinalize, ObserveAfterWrite). The base contract here is only "I am a named, configurable, closable thing."

type Registry

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

Registry holds the operator's enabled plugins in registration order.

The order matters: OnFinalize plugins fire in registration order, and a shouldRecord=false return SHORT-CIRCUITS the chain. Operators who care about ordering (e.g. "tag-by-path runs before path-filter so dropped traces still carry the tag in logs") control it via the order of the enabled list in config.

Registry is constructed once at startup and treated as immutable thereafter. There is no hot-reload; restart the process.

func NewRegistry

func NewRegistry() *Registry

NewRegistry returns an empty Registry. Use Register to add plugins in the order the operator's config lists them.

func (*Registry) Close

func (r *Registry) Close() error

Close calls Close on every registered plugin in registration order. Errors are returned joined into a single error; close attempts continue past failures (graceful shutdown is best-effort across all plugins).

func (*Registry) Init

func (r *Registry) Init(cfgs map[string]map[string]any) error

Init calls Init on every registered plugin with the plugin's own config subtree. The cfgs map is keyed by Plugin.Name(); missing entries are passed as nil (plugins MUST treat nil as "use defaults").

Returns on the first plugin whose Init fails. Caller (main) logs and exits the process — a misconfigured plugin should not silently degrade.

func (*Registry) IterateAfterWrite

func (r *Registry) IterateAfterWrite(ctx context.Context, tr trace.Trace)

IterateAfterWrite runs the AfterWrite chain in registration order.

Plugins that do NOT implement ObserveAfterWrite are skipped. There is no short-circuit semantic here — the trace is already durable, and every interested plugin gets a chance to observe it. Plugin errors are NOT returned because AfterWrite has no return value; plugins that need to surface errors do so via their own logging / counter mechanism. Phase A.1's wiring layer will be the place that adds shared telemetry on top of this iterator.

func (*Registry) IterateOnFinalize

func (r *Registry) IterateOnFinalize(ctx context.Context, tr trace.Trace) (shouldRecord bool, errs []error)

IterateOnFinalize runs the OnFinalize chain in registration order.

Semantics:

  • Plugins that do NOT implement ObserveOnFinalize are skipped (a plugin can opt out of this hook entirely).
  • Returning shouldRecord=false from any plugin causes iteration to STOP and the caller receives (false, nil). Subsequent plugins do not see the trace.
  • Errors are collected in the returned errs slice (one entry per erroring plugin) but do NOT stop iteration on their own. Per-plugin behavior: if a plugin returns shouldRecord=false AND err != nil, the err is recorded and iteration stops. If a plugin returns shouldRecord=true AND err != nil, the err is recorded and iteration continues to the next plugin.

A plugin failure does not by itself drop a trace; the plugin must explicitly return shouldRecord=false.

The caller (the writer dispatch path) uses shouldRecord to gate the TrySend call and logs errs for telemetry.

func (*Registry) Plugins

func (r *Registry) Plugins() []Plugin

Plugins returns the registered plugins in registration order. Exposed for diagnostics (e.g. /healthz "enabled plugins" list); the returned slice is a copy, safe for the caller to mutate.

func (*Registry) Register

func (r *Registry) Register(p Plugin) error

Register appends p to the registry. The registration order is the invocation order for every hook. Returns an error if a plugin with the same Name() is already registered (operator config bug).

Directories

Path Synopsis
builtin
capturefilter
Package capturefilter implements the v0.1.2 "capture-filter" path gate: BEFORE the recording pipeline allocates a trace ID or wires the per-trace capture sinks, the proxy handler asks this filter whether the request path is in the operator-configured drop list.
Package capturefilter implements the v0.1.2 "capture-filter" path gate: BEFORE the recording pipeline allocates a trace ID or wires the per-trace capture sinks, the proxy handler asks this filter whether the request path is in the operator-configured drop list.
pathfilter
Package pathfilter implements the Phase A "path-filter" plugin: an ObserveOnFinalize plugin that drops traces whose Path matches any operator-configured pattern.
Package pathfilter implements the Phase A "path-filter" plugin: an ObserveOnFinalize plugin that drops traces whose Path matches any operator-configured pattern.
v2
Package v2 implements the hot-path BEFORE / AFTER plugin contract.
Package v2 implements the hot-path BEFORE / AFTER plugin contract.
builtin/textappend
Package textappend implements the text-append plugin described in docs/specs/plugin-b-c-spec.md, using append-to-last-delta for streaming responses.
Package textappend implements the text-append plugin described in docs/specs/plugin-b-c-spec.md, using append-to-last-delta for streaming responses.
builtin/textreplace
Package textreplace implements the text-replace plugin described in docs/specs/plugin-b-c-spec.md.
Package textreplace implements the text-replace plugin described in docs/specs/plugin-b-c-spec.md.

Jump to

Keyboard shortcuts

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