Package Exports
- @graphorin/observability
- @graphorin/observability/cost
- @graphorin/observability/eval
- @graphorin/observability/exporters
- @graphorin/observability/gen-ai
- @graphorin/observability/logger
- @graphorin/observability/openinference
- @graphorin/observability/package.json
- @graphorin/observability/redaction
- @graphorin/observability/redaction/imperative-patterns
- @graphorin/observability/redaction/patterns
- @graphorin/observability/replay
- @graphorin/observability/telemetry
- @graphorin/observability/tracer
Readme
@graphorin/observability
Observability primitives for the Graphorin framework.
@graphorin/observability ships every cross-cutting tracing,
redaction, replay, cost, and structured-logging primitive every other
@graphorin/* package builds on. The package is intentionally
opinionated: every exporter must be wrapped through
withValidation(...) before it can ship a single span, the validator
defaults to default-deny non-public, and the framework makes zero
outbound network calls without an explicit user action.
Highlights
- Typed
AISpan<T>tracer.createTracer({...})returns aGraphorinTracerthat emitsAISpan<SpanType>records compatible with OpenTelemetry. Sampling rules + per-event sampling cover noisy span kinds (memory.embed,tool.execute.partial, …). - Mandatory
withValidation(...)wrapper. Every exporter passed tocreateTracer({ exporters })is wrapped through the configuredRedactionValidator. Registering a raw exporter whilevalidation: 'off'triggersUnvalidatedExporterErrorat startup - there is no silent path. RedactionValidatorwith 14 built-in patterns. API key / JWT / PEM private key / GitHub PAT / AWS access key / Graphorin token / bearer header / basic-auth header / email / credit card / US SSN / E.164 phone / IBAN - all on by default. Three additional patterns (IPv4, IPv6, GCP service account) are opt-in.- OpenTelemetry GenAI semantic-conventions conformance.
emitGenAIAttributes(span, {...}),emitGenAIMessageEvents(span, [...]), andderiveGenAISystem(...)ship the canonicalgen_ai.*attribute family alongside the existinggraphorin.*attributes - additive, never replacing. - OpenInference span-kind layer.
emitOpenInferenceKind(span)emits theopeninference.span.kindattribute via the canonical per-SpanTypemapping (agent.*→AGENT,provider.*→LLM,tool.execute→TOOL,memory.*→RETRIEVER/EMBEDDING,workflow.*→CHAIN,agent.evaluator.iteration→EVALUATOR). ConsoleExporter,JSONLExporter,OTLPHttpExporter. The built-in exporters cover dev (console), replay (append-only JSONL with0700directories +0600files), and remote OTLP collectors (fetch-based reference implementation, swappablefetchImpl).- Sanitized-by-default
Replay.createReplay({...})exposes arun(...)async iterator that yieldsreplay.start/replay.event/replay.skipped/replay.endmarkers. Raw mode requires thecanReadRawcallback to returntrueand emits an audit-bridge entry on every invocation. - Hierarchical
CostTracker.createCostTracker({...})rolls up tokens + cost across parent-child spans and supports per-run / per-session / per-agent / per-user budgets with anonExceedcallback. - Structured logger.
createLogger({...})writes JSON or pretty records, automatically correlates with the current span viawithCurrentSpan(...), and pipes every field through the validator. - Zero-default telemetry.
getTelemetryStatus()andannounceTelemetryPosture()expose the v0.1 promise: the framework performs zero outbound network calls, no version pings, no crash reports, no auto-updates. TheGRAPHORIN_TELEMETRYandGRAPHORIN_NO_PHONE_HOMEenvironment variables are reserved for forward compatibility and are acknowledged at startup.
Installation
pnpm add @graphorin/observability
# Optional peer deps for OTLP export - install only when you need them:
pnpm add @opentelemetry/api @opentelemetry/sdk-node @opentelemetry/exporter-trace-otlp-httpQuick start
import {
createTracer,
createConsoleExporter,
createJSONLExporter,
withValidation,
} from '@graphorin/observability';
const tracer = createTracer({
serviceName: 'my-assistant',
exporters: [
// Auto-wrapped via the tracer-managed validator.
createConsoleExporter({ pretty: true }),
// Manually wrapped - useful when each exporter needs its own policy.
withValidation(createJSONLExporter({ path: './traces' }), {
minTier: 'internal',
}),
],
validation: { minTier: 'public', failOnUnredactedSensitive: false },
sampling: {
rate: 1.0,
rules: [{ type: 'memory.embed', rate: 0.1 }],
},
});
await tracer.span(
{ type: 'agent.run', attrs: { 'graphorin.agent.id': 'support-bot' } },
async (span) => {
span.setAttributes({ 'graphorin.session.id': 'session-123' });
return runAgent();
},
);
await tracer.shutdown();License
MIT © 2026 Oleksiy Stepurenko.
Project Graphorin · v0.6.0 · MIT License · © 2026 Oleksiy Stepurenko · https://github.com/o-stepper/graphorin