Operation logging starts in @autter/runtime-node and @autter/runtime-next
version 1.4.0. Update the ingester to 1.4.0 before upgrading SDKs: it creates
runtime_logs through migration 0011-runtime-logs and accepts /v1/logs.
You don't need to check this by hand. The SDK warns once at runtime when your
ingester is too old, and npx @autter/runtime-node doctor reports every
mismatch. See Version compatibility.
1.5.0 (ingester 1.5.0 first) adds request summaries, runtimeContext, inline
messages, kind on every summary, coded errors, fork/carriers, the AI rollup,
waitUntil, sinks and logger-only mode — all additive; a golden test proves a
1.4.0 operation still exports the same OTLP JSON apart from the two new summary
keys. Request-level features are documented in
REQUESTS-AND-ERRORS.md.
1.5.0 (ingester 1.5.0 first) adds request summaries, runtimeContext, inline
messages, kind on every summary, coded errors, fork/carriers, the AI rollup,
waitUntil, sinks and logger-only mode — all additive; a golden test proves a
1.4.0 operation still exports the same OTLP JSON apart from the two new summary
keys. Request-level features are documented in
REQUESTS-AND-ERRORS.md.
Initialize initAutterServer once, before the application starts. For Next.js,
use registerAutter in instrumentation.ts and import the APIs below from
@autter/runtime-next/server. Use the Node runtime; these APIs use Node's async
context and do not run in the browser or an edge worker (edge runtimes use
@autter/runtime-edge, which passes the context explicitly). Apps that run their
own OpenTelemetry SDK can use initAutterLogging instead of initAutterServer.
import {
initAutterServer, withRuntimeOperation, runtimeLogger,
} from "@autter/runtime-node";
const runtime = initAutterServer({
apiKey: process.env.AUTTER_RUNTIME_KEY!,
service: "payments-api",
release: process.env.GIT_SHA,
logging: { console: false, minLevel: "info" },
});
await withRuntimeOperation("checkout", async (operation) => {
operation.setContext({ "payment.provider": "stripe", "cart.item_count": 3 });
await operation.step("reserve_inventory", () => reserveInventory());
const payment = await operation.step("confirm_payment", () => confirmPayment());
runtimeLogger.info("Payment confirmation returned", { "payment.attempts": 2 });
if (!payment.confirmed) {
operation.outcome("failed", "Payment was not confirmed; no order created");
return;
}
await operation.step("create_order", () => createOrder(payment));
});
// Flush at the end of a short-lived invocation; shutdown before process exit.
await runtime.shutdown();withRuntimeOperation(name, fn, attributes?, options?) runs the callback in an always-recorded
process span and emits one completed operation summary (autter.operation.kind = "operation"; request middleware emits "request" summaries). options.from
continues work from a runtimeContext.carrier() (parent link, request id, and an
OTel span link to the producer trace); options.waitUntil receives the log flush
promise once the summary is emitted. It returns the callback's
result and rethrows its original error. An unhandled callback error records an
exception in the trace; the log summary is related evidence, not a second issue.
operation.setContext(attributes) merges redacted nested context (arrays are
replaced) and adds attributes to the operation and
its active span. operation.step(name, fn) records the step result and elapsed
time; it rethrows failures. A caught step error can be recovered by application
code: the final outcome follows the callback's result or an explicit outcome.
Up to 64 steps are recorded. Log names and context should describe the operation,
not contain request bodies, payment data, or personal information.
RuntimeLogContext supports nested objects, arrays and scalar values; standard
trace attributes encode structured values as JSON for OTLP compatibility.
operation.outcome(status, message?) accepts succeeded, failed, degraded,
cancelled, and pending. The default is succeeded when the callback returns.
Returning normally is not proof of business success: declare an outcome when
the intended result was not achieved. An explicit failed outcome also emits
the existing autter.outcome trace event, including the reporting call site.
pending means the operation has not confirmed its downstream result.
createRuntimeLogger(attributes?) creates a logger with debug, info, warn,
and error methods. runtimeLogger is the default instance; runtimeContext
exposes the same methods plus set, outcome, id, requestId, fork and
carrier for the current operation from anywhere in its call tree.
Inline messages (1.5.0). Inside an operation, debug and info messages are
folded into its summary as autter.operation.logs — { t, level, message, attrs? }, t in milliseconds since the operation started — instead of being
exported as separate records. warn and error are folded and exported.
autter.operation.level is the highest level seen (including a failed outcome).
Disable with logging.inline: false to get 1.4.0's one-record-per-message
behaviour. Outside an operation every message is its own record, as before. error records
diagnostic context; use captureException for exception grouping or declare a
failed operation outcome for business-failure grouping. Logs inherit the
active operation ID, name, parent operation ID, and application attributes, plus
the active OTel trace/span IDs. Concurrent operations keep separate contexts.
Async context does not cross a queue or process by itself: put
runtimeContext.carrier() in the job payload and pass it as
withRuntimeOperation(name, fn, {}, { from: payload.autter }) in the consumer.
runtimeContext.fork(name, fn) links a child to its parent even when the child
outlives it; runInBackground(name, fn) does the same without awaiting.
- Logs are OTLP/HTTP log records. Both OTLP JSON and protobuf are accepted.
evlog and other OTLP log exporters can use
/v1/logswith a server ingest key. - Source attributes are bounded and scrubbed again at ingestion. Tenant identity comes from the validated key, never the supplied event. Client/browser keys cannot send server logs.
- Redaction applies before console output and export. Never intentionally send secrets or personal data; pattern-based redaction cannot identify every secret.
logging.minLevelfilters ordinary messages (folded or not); completed operation summaries are retained independently.logging.consoledefaults to true and can be disabled without disabling export. Console output is JSON lines (as in 1.4.0) whenNODE_ENV=productionand a compact tree elsewhere;logging.sinksreplaces the default sinks, andlogging.filecontrols the local.autter/runtime/*.jsonlfiles (on by default only in development).- Summaries are never sampled. Inline messages are capped at 50 per operation
(
autter.operation.logs_truncatedmarks the rest), 300 characters each and about 6 KB per operation, and are placed last in the context budget so they never crowd out operation context. - Logs batch in memory (up to 1,000 records or 4 MiB, whichever comes first).
Requests contain up to 50 records or 512 KiB. Context has depth, field, step
and string limits; truncated context is marked. Each flush has a 10-second
budget and makes at most three attempts per batch. Failed batches remain
buffered for a later flush, with automatic retry intervals up to 30 seconds. Buffer overflow and failed shutdown delivery are
reported.
flushRuntimeLogs()rejects if delivery fails, andruntimeLogStats()reports buffered and dropped counts. This is best-effort telemetry, not durable delivery or an audit log. - Records expire after 14 days by default (
LOG_TTL_DAYSon ingester 1.5.0+). Successful operation counts represent captured summaries, not a guarantee that every application operation was observed.
Autter's repository Runtime Logs view displays captured messages, operation summaries, outcomes, steps, and trace IDs. Investigation readers retrieve related logs and spans using captured IDs and compare bounded successful operations. They disclose unavailable sources and truncation. Event text is untrusted diagnostic evidence, never instructions to an agent. Business context improves an investigation but does not establish a cause by itself.
The observations feed the existing root-cause analysis and draft-fix pipelines, which retain their repository settings, source checks and validation rules. A reported outcome call site can locate the reporting code; it is not proof that this location caused the failure. The fix agent must confirm the cause, reproduce applicable conditions, and validate the intended result.
Log and trace exporters are independent. Operation evidence may arrive after an initial analysis; refresh the evidence panel or rerun analysis to incorporate later arrivals. Shutdown attempts log export before closing tracers. Regular Runtime flushing exports logs and traces independently so a failed log export does not block exception telemetry.