Observability
Anvil emits mapped error events with route context.
app.OnError(func(ctx context.Context, event sdk.ErrorEvent) { logger.ErrorContext(ctx, "anvil error", "status", event.Failure.Status, "route", event.Failure.Context.Route, "endpoint", event.Failure.Context.Endpoint, "phase", event.Failure.Context.Phase, "expected", event.Expected, )})OnError receives the event after the selected driver has mapped the error
through app.ErrorPipeline(). The normalized sdk.Failure tells observers
whether the event came from validation, domain logic, panic recovery, or a
technical failure.
Reporter Plugins
Section titled “Reporter Plugins”Plugins attach Sentry, Datadog, Honeycomb, or company-owned telemetry without changing handler code:
app := anvil.New( httpstd.Driver(), anvil.Use(telemetry.New(telemetry.Options{ Logger: logger, })),)Expected vs Unexpected
Section titled “Expected vs Unexpected”Expected errors are domain or validation failures. Unexpected errors are technical failures such as database errors, panics, encode failures, and transport failures.
Report unexpected errors loudly. Track expected errors in metrics instead of exception reporting.
The default mapper treats *sdk.Failure returned by ctx.Errors() as already
classified. Other errors become 500 internal server error, Expected: false,
and include stack frames.
Observer Semantics
Section titled “Observer Semantics”Observers run synchronously in registration order on the goroutine that is handling the request, RPC, subscription, or queue delivery. Anvil does not recover observer panics and observers have no error return.
Keep observers small. If the observer calls an external system, use a short timeout, recover inside the observer, or hand work to a buffered reporter owned by your plugin.
Useful Fields
Section titled “Useful Fields”event.Failure.Context contains the stable route boundary Anvil knows:
ProtocolControllerEndpointMethodRoutePathPhase
event.Error and event.Failure.Cause are the technical error. Use them for
internal logs, exception reporting, and debugging; client responses should use
the normalized public failure message.
event.Recovered is true when the final failure context phase is
sdk.ErrorPhasePanic. The first-party HTTP drivers mark recovered route and
WebSocket panics that way. GraphQL, gRPC, and queue drivers recover panics into
handler-phase errors, so use both Recovered and Phase when building
dashboards.