Getting started
This guide walks through adding a named log stream to a Layeron app.
You will create a stream, register it with the app, emit records from a route, and configure sampling and redaction for production-friendly output.
Prerequisites
Section titled “Prerequisites”Before you begin, make sure you have:
- A Layeron backend app.
@layeron/coreand@layeron/modulesinstalled.- At least one route where you want to emit logs.
1. Import The Module
Section titled “1. Import The Module”Import log from @layeron/modules.
import { log } from "@layeron/modules"log creates a Layeron module. You register that module with app.use(...),
the same way you register database and other backend capabilities.
2. Create A Named Stream
Section titled “2. Create A Named Stream”Create a stream with a stable platform namespace/name identity.
const appLog = log({ name: "app", namespace: "api",})Choose a name that describes the stream. Use
Namespaces for namespace defaults and naming rules.
For example:
| Namespace | Name | Use |
|---|---|---|
api | app | General API route logs. |
api | database | Query and persistence logs. |
webhooks | stripe | Stripe webhook handling logs. |
admin | auth | Admin authentication logs. |
This identity model makes future filtering and retention policies predictable.
3. Register The Stream
Section titled “3. Register The Stream”Add the stream to your backend app.
app.use(appLog)Layeron records the stream in the app specification. During compilation, the stream contributes a Log Product Worker and observability intent to the Worker target. During runtime, route code sends records to that Product Worker through WorkerEntrypoint RPC.
4. Emit Route Logs
Section titled “4. Emit Route Logs”Use the stream inside route handlers.
app.get("/api/health", (request) => { appLog.info("health checked", { path: new URL(request.url).pathname, })
return { ok: true }})Use log levels to express severity:
appLog.debug("cache lookup", { key })appLog.info("post created", { postId })appLog.warn("retry scheduled", { attempt })appLog.error("delivery failed", { eventId })appLog.fatal("startup failed")5. Capture Errors
Section titled “5. Capture Errors”Use capture(...) when you catch an error and want it recorded as an error
record.
app.post("/api/posts", async (request) => { try { const body = await request.json() return Response.json({ body }) } catch (error) { appLog.capture(error, { route: "/api/posts", })
return Response.json({ error: "invalid_json" }, { status: 400 }) }})Captured errors are emitted through the same stream identity.
6. Add Sampling
Section titled “6. Add Sampling”Sampling controls how many records are emitted.
const appLog = log({ name: "app", namespace: "api", sampling: { success: 0.25, error: 1, },})Use success for normal log records. Use error for error and fatal records.
Both values are numbers from 0 to 1.
7. Add Workers Logs Head Sampling
Section titled “7. Add Workers Logs Head Sampling”Use workerLogs.headSamplingRate when you want Cloudflare Workers Logs to
sample whole Worker invocations before log records are collected.
const appLog = log({ name: "app", namespace: "api", workerLogs: { headSamplingRate: 0.5, },})Layeron sampling applies to records in the named stream. Workers Logs head
sampling applies to the whole Worker invocation.
8. Redact Sensitive Attributes
Section titled “8. Redact Sensitive Attributes”Redaction removes sensitive values before a record is emitted.
const appLog = log({ name: "app", namespace: "api", redaction: { fields: ["authorization", "cookie", "token"], headers: ["authorization", "cookie"], },})Use redaction for values that should never appear in logs, such as tokens, cookies, secrets, and authorization headers.
You can also keep shared redaction rules in Policy and pass them to the log stream:
import { log, policy } from "@layeron/modules"
const appPolicy = policy({ name: "app", redaction: [{ id: "sensitive-log-fields", target: "log", fields: ["authorization", "token"], headers: ["authorization", "cookie"], }],})
const appLog = log({ name: "app", namespace: "api", redaction: appPolicy.redactionPolicy(["sensitive-log-fields"]),})The log stream receives inline fields and headers for runtime redaction. The compiled app also keeps the Policy reference for plans, deployment state, and dashboard views.
9. Retain Logs
Section titled “9. Retain Logs”Workers Logs are useful for short-term viewing. Add archive retention when you need records to remain queryable through Layeron:
const appLog = log({ name: "app", namespace: "api", retention: { mode: "archive", days: 30, },})After deployment, read retained records with the CLI:
layer logs list . --env production --namespace api --name app --since 1h10. Runtime Target
Section titled “10. Runtime Target”In the Cloudflare runtime target, the Log Product Worker emits structured records through Workers Logs and writes retained records through Layeron Storage when archive retention is enabled. Storage owns the R2 bucket behind that archive.