Skip to main content

Runtime Logs

Runtime Logs help you observe and troubleshoot Reactor and Proxy code-transform executions. They capture messages emitted by your code and platform lifecycle events, such as when execution starts, completes, times out, or fails.

Configurable runtime-log records use the structure documented on this page and can be delivered through Webhooks.

Enable Runtime Logs

Set runtime.logs.enabled to true on a Reactor or on each Proxy code transform whose records you want to capture. Configurable runtime-log capture is disabled by default.

{
"runtime": {
"image": "node24",
"logs": {
"enabled": true,
"level": "info"
}
}
}

Changing runtime.logs.enabled or runtime.logs.level updates the Reactor or affected Proxy code transform asynchronously. While the resource is updating, invocations use the previous active configuration. If the resource becomes outdated, invocations continue using the previous working version. The new log settings apply after the resource returns to active.

See the Reactor API and Pre-Configured Proxies API for complete configuration examples.

Choose a Log Level

runtime.logs.level is optional and defaults to info.

LevelUse it for
debugDetailed diagnostic context during development or focused troubleshooting. This can produce a high volume of records.
infoNormal execution milestones and meaningful operations.
warnUnexpected or degraded conditions from which execution can continue.
errorFailures that prevent an operation from completing as intended.

The configured level includes application records at that level and every more severe level. For example, warn captures warn and error records. This setting does not filter platform lifecycle records.

Log Application Activity

Use the logger passed on the Reactor or transform event:

module.exports = async function handler(event) {
const { logger } = event;

logger.debug("Received request");
logger.info("Processing request", { operation: "tokenize" });
logger.warn("Using fallback configuration");
logger.error("Processing failed", new Error("Processor unavailable"));

// ...
};

The logger supports logger.debug, logger.info, logger.warn, and logger.error. logger.log is an alias for logger.info.

Use the runtime logger

Output written through console.* is not captured as a runtime-log record. Use the injected logger instead.

Application records use source: "application" and record_type: "log". They contain a level and message, and can include structured attributes and direct JavaScript Error details.

Understand Platform Lifecycle Records

Basis Theory emits platform lifecycle records independently of application logging calls. These records use source: "platform" and record_type: "lifecycle":

  • execution.started indicates that runtime execution started.
  • execution.completed indicates that runtime execution ended and includes an outcome.

A completed execution has one of these outcomes:

OutcomeMeaning
successRuntime execution completed successfully.
timeoutRuntime execution exceeded its configured timeout.
out_of_memoryRuntime execution exhausted its available memory.
application_errorApplication code failed without a platform error classification.
platform_errorThe runtime platform reported another recognized failure.

An execution.completed record can include duration_ms, the elapsed execution time in milliseconds.

Runtime Log Record Types

SourceRecord typeDescriptionType-specific fields
applicationlogA message or structured diagnostic context emitted through event.logger.level, message, attributes, error
platformlifecycleExecution lifecycle information emitted automatically by the runtime.event, outcome, duration_ms

Record Examples

debug, info, and warn application records share the same shape; error records can also include the nested error object.

{
"occurred_at": "2026-08-11T12:00:00.010Z",
"sequence": 1,
"source": "application",
"record_type": "log",
"level": "info",
"message": "Processing request",
"attributes": {
"operation": "tokenize"
}
}

Sanitization and Capture Limitations

Basis Theory bounds and sanitizes customer application messages, attributes, and direct Error details before publishing them. Sensitive values in supported content are replaced with [REDACTED]. Only the documented runtime-log fields are published. Internal execution metadata and identifiers are omitted.

Runtime Logs are fail-open: a failure to capture or deliver records does not change the customer code result. Abrupt runtime termination can prevent final records, including an execution.completed lifecycle record, from being captured.

Do not log sensitive data

Avoid logging sensitive information, including secrets, authentication tokens, or payment card data, in messages or attributes. Sanitization reduces accidental exposure but does not replace controlling what your code logs.

Receive Runtime Logs through Webhooks

For Node.js runtime images, enable configurable runtime-log capture and subscribe to:

  • reactor.log for Reactor runtime records.
  • proxy.log for Proxy request-transform and response-transform runtime records.

Register these values in the Webhook events list through the Create Webhook API. Follow the Webhooks overview for signature verification, retries, and idempotent processing.

Each delivery has three contract layers:

Runtime Log Event Data Fields

Runtime-log event batches have these data fields:

NameTypePresenceApplies toDescription
invocation_idStringRequiredreactor.log, proxy.logInvocation identity shared by every batch from one invocation.
reactorObjectRequiredreactor.logCustomer-visible Reactor resource.
reactor.idStringRequiredreactor.logReactor identifier.
proxyObjectRequiredproxy.logCustomer-visible Proxy resource.
proxy.idStringRequiredproxy.logProxy identifier.
transform_typeStringRequiredproxy.logrequest_transform or response_transform.
sequence_startNumberRequiredreactor.log, proxy.logSequence of the first record in this batch.
sequence_endNumberRequiredreactor.log, proxy.logSequence of the last record in this batch.
recordsArrayRequiredreactor.log, proxy.logNon-empty ordered array. Each item follows the runtime-log record fields.

Runtime Log Record Fields

Each runtime-log record has this shape:

NameTypePresenceDescription
occurred_atStringRequiredISO 8601 timestamp when the record occurred.
sequenceNumberRequiredInvocation-local record order.
sourceStringRequiredapplication for logger output or platform for runtime lifecycle records.
record_typeStringRequiredlog for application records or lifecycle for platform records.
eventStringLifecycle onlyexecution.started or execution.completed.
levelStringApplication onlydebug, info, warn, or error.
messageStringApplication onlySanitized application message. If no message argument is supplied, this is the direct Error's message when present, otherwise an empty string.
attributesObjectOptional application fieldSanitized structured attributes supplied to the logger.
errorObjectOptional application fieldSanitized details from a direct JavaScript Error.
error.typeStringWhen error is presentError type or name.
error.messageStringWhen error is presentError message.
error.stack_traceStringOptional when error is presentSanitized stack trace.
outcomeStringCompleted lifecycle onlysuccess, timeout, out_of_memory, application_error, or platform_error.
duration_msNumberOptional completed lifecycle fieldElapsed execution time in milliseconds.

occurred_at describes when an individual record occurred. Use sequence, not a timestamp, to order records from the same invocation.

The following tabs show complete deliveries for each event type.

reactor.log
{
"event": {
"id": "730ffeb4-d511-5d96-bc79-98ae023a8bc7",
"type": "reactor.log",
"timestamp": "2026-08-11T12:00:00.100Z",
"tenant_id": "869d5b1c-1ae8-4ce6-96c6-73a602b407ff",
"trace_id": "ecae00ef-164d-4c0e-aa58-3f306fc7600b",
"data": {
"invocation_id": "8230820d-6e6d-4a87-b801-991e2c4535d1",
"reactor": {
"id": "5b493235-6917-4307-906a-2cd6f1a90b13"
},
"sequence_start": 0,
"sequence_end": 2,
"records": [
{
"occurred_at": "2026-08-11T12:00:00.000Z",
"sequence": 0,
"source": "platform",
"record_type": "lifecycle",
"event": "execution.started"
},
{
"occurred_at": "2026-08-11T12:00:00.010Z",
"sequence": 1,
"source": "application",
"record_type": "log",
"level": "info",
"message": "Validating payload",
"attributes": {
"operation": "validate_payload"
}
},
{
"occurred_at": "2026-08-11T12:00:00.018Z",
"sequence": 2,
"source": "platform",
"record_type": "lifecycle",
"event": "execution.completed",
"outcome": "success",
"duration_ms": 18.4
}
]
}
},
"delivered_at": "2026-08-11T12:00:00.673Z"
}

Process Ordered Webhook Batches

One invocation can produce multiple bounded Webhook events. Every batch for the invocation shares invocation_id. Within each event, sequence_start and sequence_end identify the first and last included record, and every record has its own sequence.

Webhook delivery order is not record order. Deduplicate repeated deliveries by event.id, group batches by invocation_id, and order their records by sequence.

For example, these deliveries arrive as batch B, batch A, and a retry of batch A:

Delivery order: B, A, A
[
{
"event": {
"id": "8d8fd53b-a0a5-553c-8aeb-32dd7133885d",
"data": {
"invocation_id": "c7a9e2b4-1d63-4f85-a0c2-5e7b913d684f",
"sequence_start": 2,
"sequence_end": 3,
"records": [
{ "sequence": 2, "message": "record 2" },
{ "sequence": 3, "message": "record 3" }
]
}
}
},
{
"event": {
"id": "f032f5bc-c05c-5889-b833-9778c406592a",
"data": {
"invocation_id": "c7a9e2b4-1d63-4f85-a0c2-5e7b913d684f",
"sequence_start": 0,
"sequence_end": 1,
"records": [
{ "sequence": 0, "message": "record 0" },
{ "sequence": 1, "message": "record 1" }
]
}
}
},
{
"event": {
"id": "f032f5bc-c05c-5889-b833-9778c406592a",
"data": {
"invocation_id": "c7a9e2b4-1d63-4f85-a0c2-5e7b913d684f",
"sequence_start": 0,
"sequence_end": 1,
"records": [
{ "sequence": 0, "message": "record 0" },
{ "sequence": 1, "message": "record 1" }
]
}
}
}
]

After deduplicating by event ID and sorting by record sequence, the result is 0, 1, 2, 3.

Delivery is at least once. Do not depend on Webhook arrival time or any timestamp for ordering. Sequences are invocation-local ordering keys, but abrupt termination can prevent records from being captured. Do not assume that every invocation contains a complete or contiguous sequence.

Existing CLI Live Logs

You can continue using the CLI's existing live log stream for real-time Reactor and Proxy troubleshooting. CLI streaming is separate from configurable runtime-log capture and does not provide the normalized application and lifecycle record format documented on this page. See Reactor Logs and Proxy Logs for details.