feat: precise --changed via stack-trace source file tracking; OTel sink docs
This commit is contained in:
+66
-5
@@ -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
|
||||
|
||||
|
||||
+1
-1
@@ -83,7 +83,7 @@ apophis verify --profile ci --changed
|
||||
|
||||
If no routes changed, exits 2 with a message.
|
||||
|
||||
`--changed` is a heuristic: it maps changed file paths to routes by checking route path segments against file names. This is useful as a developer convenience, but for strict CI gating, prefer explicit `--routes` filters or full verification.
|
||||
`--changed` tracks which source file registered each route by capturing stack traces during route discovery. When a file changes, only routes registered from that file are verified. Falls back to a path-segment heuristic for routes discovered without source file metadata (e.g., `printRoutes()` fallback).
|
||||
|
||||
## Failure Output Format
|
||||
|
||||
|
||||
Reference in New Issue
Block a user