Skip to main content

Logs

Send structured logs from your device to RelayX. Each call mirrors to the local console for development and publishes a copy to the backend, where the App SDK can stream live logs or query history.

Overview

The log module exposes three methods, one per severity level: info, warn, and error. Logging is fire-and-forget. The methods are synchronous, return nothing, and never throw on transport errors. When the device is offline, log entries buffer and flush on reconnect.

Telemetry vs Logs vs Events

All three are fire-and-forget, but they describe different things:

TelemetryLogsEvents
What it capturesNumeric measurements (temperature, current)Free-form messages about what the device is doingDiscrete moments (door opened, boot complete)
SchemaValidated against your device schemaNone. Any string.None. You define the name and payload.
LevelsNoneinfo, warn, errorNone
Typical useCharts and alertsDiagnostics, debugging, audit trailTriggering app-side workflows

If you would write it to stdout for a human to read later, it is a log.

API

info() / warn() / error()

Each level is its own method. Pass any number of arguments. They are formatted into a single string and sent as one message.

device.log.info(...args)
device.log.warn(...args)
device.log.error(...args)
ParameterTypeDescription
...argsanyStrings, numbers, booleans, null, undefined, plain objects, arrays, Date, Error.

Returns nothing. Methods are synchronous, do not return a promise.

Throws ValidationError if any top-level argument is a Function, Symbol, BigInt, Map, Set, or class instance other than Date or Error. Validation is shallow, nested values are not walked.

Sync, not async

Unlike telemetry.publish() and event.send(), log methods do not return a promise. Do not await them. This keeps logging fast inside hot paths and tight loops.

Send a Log

The most common pattern is a one-liner with a message and some context.

device.log.info("Boot complete", { firmware: "1.2.0", uptimeMs: 3200 });
device.log.warn("Retrying transport publish");
device.log.error("Sensor read failed", err);

Arguments can be any mix of strings, numbers, booleans, plain objects, arrays, Date, or Error. They are joined with a single space when sent. Error instances render as Name: message followed by the stack trace. Objects and arrays are JSON-stringified.

Console Mirroring

Every log call also writes to the local console before publishing. This guarantees you see the message during development even if the device is offline or transport publish fails.

LevelJavaScriptPythonC++
infoconsole.infoprint(..., file=sys.stdout)ESP_LOGI
warnconsole.warnprint(..., file=sys.stderr)ESP_LOGW
errorconsole.errorprint(..., file=sys.stderr)ESP_LOGE

The C++ runtime uses the tag relay-log for ESP-IDF console output.

Buffering and Flushing

JavaScript and Python share the same buffering policy. Log entries are pushed onto a single in-memory buffer shared across all three levels. The buffer flushes when one of two conditions is met:

TriggerThreshold
Entry count15 entries
Time5 seconds since the first entry into an empty buffer

Whichever fires first wins. Subsequent enqueues do not reset the timer, so a steady trickle of logs flushes on the 5-second cadence rather than waiting indefinitely.

Offline Behavior

Logs sent while the device is disconnected are held in the transport's offline buffer and flushed in order once the connection is restored.

info

Buffered logs are stored in memory only. If the device process restarts while offline, buffered logs are lost.

Graceful Shutdown

device.disconnect() drains the log buffer and waits for every in-flight publish to settle before tearing down the transport. No log entry is silently dropped on graceful disconnect.

await device.log.error("Shutting down due to fatal error", err);
await device.disconnect();

Validation Errors

Argument validation runs before the console mirror or the publish, so an invalid argument raises immediately and nothing is logged.

// Throws ValidationError. Functions are not loggable.
device.log.info("handler", () => {});

// Works. Errors render with stack.
device.log.error("Sensor read failed", new Error("EIO"));

Reading Logs from the App SDK

The App SDK provides matching log.stream(), log.off(), and log.history() methods to consume the logs your devices produce. See the App SDK Logs reference for details.