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.

Enable capture on a supported Node.js runtime, then invoke the Reactor or Proxy. View retained logs in the Customer Portal or the CLI, or query them through the API. To receive log batches through Webhooks, create a Webhook subscription.

Choose How to View Logs​

ViewUse it to
Portal HistorySearch retained logs by time range and filters, newest first.
Portal LiveFollow new logs in your browser.
CLI readRead logs from a time range, oldest first, and exit.
CLI tailFollow new logs in your terminal, optionally including recent history.
APIQuery retained logs for one Reactor or Proxy from your own code, with the same filters as Portal History.
WebhooksReceive log batches at your own endpoint.

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​

These record excerpts illustrate application messages and platform lifecycle records. See the Customer Portal, CLI, and Webhooks sections for the fields and formats available with each method.

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",
"source": "application",
"record_type": "log",
"level": "info",
"message": "Processing request",
"attributes": {
"operation": "tokenize"
},
...
}

Sanitization, Truncation 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.

Large string values in runtime-log records may be truncated after sanitization. Truncated values retain a complete UTF-8 prefix and end with the suffix …[truncated; original_bytes=N], where N is the full sanitized value's byte length before truncation. Oversized attribute keys may be omitted along with their values or subtrees. All runtime-log consumers receive the same sanitized, truncated values.

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.

Search Runtime-Log Messages​

Word search is limited to the message field and matches all query words in the same message, ignoring case and word order. For example, payment failed matches Payment authorization failed.

In the CLI, use --message-search 'payment failed' to search for both words.

In the API, send the words in the message[search_words] query parameter.

To match a complete message, use exact-message matching in the Customer Portal.

View Logs in the Customer Portal​

Select your Tenant in the Customer Portal and choose the Proxies or Reactors tab. Open the details from the Actions column, then select Logs beside Configuration. Your Portal user needs access to the selected Tenant and the log:read permission.

The Logs tab is available for Reactors using a supported Node.js runtime image and Proxies with at least one deployed code transform using a supported image. Enable capture on the Reactor or each Proxy transform whose logs you want to view.

Search History​

History is selected by default. To search captured logs:

  1. Choose History time range (UTC): Last 15 minutes, Last hour, Last 24 hours (default), or Custom with Start (UTC) and End (UTC).
  2. Set the filters for your investigation.
  3. Click Search history.

Results are newest first. Use Load More to load additional results within your selected time range, or Restart when prompted to start a fresh search. Available history is limited by your Tenant log retention, shown as Log Retention on the Customer Portal's Quotas page.

Use Source to choose All sources, Application, or Platform. Search message uses word search; a blank word-search field matches any message.

Enable Match entire message (case-sensitive) to match the complete stored message. With this option enabled, a blank field matches empty messages.

Expand Advanced filters to narrow the result:

FilterMatches
LevelApplication records at the selected level: debug, info, warn, or error.
Eventexecution.started or execution.completed platform records.
OutcomeCompleted executions with a lifecycle outcome: success, timeout, out_of_memory, application_error, or platform_error.
Trace ID (case-sensitive)The exact BT trace ID.
Proxy transformRequest or Response. Both directions are included by default. Available for Proxies only.

Use message and level filters for Application records, and event and outcome filters for Platform records. Incompatible controls are disabled or cleared. To investigate execution failures, select Platform and choose the relevant Outcome.

Use Show details to expand a record's full stored message and available metadata, including trace ID, source, record type, outcome, duration, transform direction, error, and attributes.

Follow Live Logs​

Switching to Live resets its filters while preserving your History search. Choose your filters, then click Start following to see logs from that point forward.

Live periodically checks for new logs.

Click Stop following before changing disabled filters. Stopping preserves the visible records. Starting again clears the Live list and begins a new watch.

Choose Live order: Newest first (default) or Oldest first. Auto-scroll keeps the view at the latest arriving records. Use History to inspect older records that are no longer shown in Live.

If Live reaches a retrieval limit, it stops following and keeps the last complete results visible. Narrow your filters and start again, or use History to search a shorter time range.

Read and Tail Logs with the CLI​

Install the CLI and authenticate with a Management API key that has the log:read permission. Select the API environment and region for your Tenant and enable capture on the Reactor or Proxy code transform.

Read the last hour, then exit:

Read Reactor runtime logs
bt reactors logs read '<REACTOR_ID>' --since 1h

Follow new logs, starting with the last five minutes:

Tail Reactor runtime logs
bt reactors logs tail '<REACTOR_ID>' --since 5m

See the Reactor read and tail references for flags and more examples.

CLI Output Formats​

Each CLI output record contains occurred_at and the applicable fields from this list: level, event, trace_id, transform_type, message, outcome, duration_ms, error, and attributes.

pretty is the default human-readable format. json emits compact objects, and json-pretty emits indented objects. Both JSON formats emit standalone objects separated by blank lines.

The following examples show the same application record in each format.

Illustrative pretty output
2026-08-11T12:00:00.010Z ERROR trace_id=example-trace response_transform Payment authorization failed | {"operation":"authorize"}

Query Logs with the API​

List Reactor Logs and List Proxy Logs return retained records for one Reactor or Proxy, newest first, with the same time range, source, level, trace ID, and message filters as Portal History. They require the log:read permission and use cursor pagination.

Troubleshoot Runtime Logs​

If you have trouble finding the logs you expect, check the following:

  1. Tenant and resource. Confirm the selected Tenant, Reactor or Proxy ID, and Proxy transform direction. For CLI commands, check the API environment and region.
  2. Logging configuration. Use a supported Node.js runtime image and enable runtime logs on the Reactor or relevant Proxy transform. After configuration changes, wait for the resource to become active. Use event.logger and choose a runtime.logs.level that includes the messages you want to capture.
  3. Search parameters. Review the time range, trace ID, message filter, and selected application-log level. In the Portal, select Platform to filter lifecycle records by Event or Outcome.
  4. Permissions. For CLI commands, use a Management API key with the log:read permission. In the Customer Portal, check your Tenant access and log:read permission.
  5. Tenant log retention. Check Log Retention on the Quotas page in the Customer Portal. Searches automatically limit the selected time range to that retention period.

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 Webhook Delivery 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.