feat: precise --changed via stack-trace source file tracking; OTel sink docs

This commit is contained in:
John Dvorak
2026-05-22 15:00:04 -07:00
parent dab14ef77d
commit 6331933388
5 changed files with 111 additions and 18 deletions
+66 -5
View File
@@ -228,12 +228,73 @@ Key constraints:
## Sink Implementations
APOPHIS does not ship with built-in sinks. The `ObserveSink` interface lets you
plug in any backend. Common patterns:
plug in any backend.
- **OpenTelemetry**: emit counters and histograms via `@opentelemetry/api`.
- **pino logger**: emit structured log records via `pino.info()` / `pino.warn()`.
- **Internal metrics service**: POST events to an internal collector endpoint.
- **In-memory ring buffer**: capture recent events for diagnostics endpoints.
### OpenTelemetry
Export contract evaluations as OTel custom metrics alongside your existing spans and traces:
```typescript
import type { ObserveSink, ObserveEvent } from '@apophis/fastify'
import { metrics } from '@opentelemetry/api'
const meter = metrics.getMeter('apophis')
const contractCounter = meter.createCounter('apophis.contract.evaluations', {
description: 'Number of contract evaluations',
})
const violationCounter = meter.createCounter('apophis.contract.violations', {
description: 'Number of contract violations',
})
const durationHistogram = meter.createHistogram('apophis.contract.duration_ms', {
description: 'Contract evaluation duration',
})
export const otelSink: ObserveSink = {
emit(event: ObserveEvent) {
const labels = { route: event.route, formula: event.formula }
contractCounter.add(1, labels)
if (event.type === 'contract.violation') {
violationCounter.add(1, labels)
}
durationHistogram.record(event.durationMs, labels)
},
}
```
Register it with your Fastify app:
```typescript
await app.register(apophisPlugin, {
observe: { enabled: true, sinks: [otelSink] },
})
```
APOPHIS violations now appear in your OTel metrics backend (Prometheus, Datadog, New Relic, etc.) alongside latency and error data — no custom collector needed.
### Console (development / debugging)
```typescript
export const consoleSink: ObserveSink = {
emit(event: ObserveEvent) {
if (event.type === 'contract.violation') {
console.warn('[apophis]', event.route, event.formula, event.observed)
}
},
}
```
### pino logger
```typescript
export function createPinoSink(logger: pino.Logger): ObserveSink {
return {
emit(event: ObserveEvent) {
logger[event.type === 'contract.violation' ? 'warn' : 'info'](event)
},
}
}
```
## Monorepo Validation