Skip to content

Logs

Your app’s log holds what it writes with console.log, console.warn and console.error, and every exception it doesn’t catch. For a container app, it holds what the app writes to stdout and stderr. Lines usually appear within half a minute of being written: Cloudflare, which keeps them, takes that long to make them readable.

When your app returns a 500, or Cloudflare’s error 1101 for an exception the Worker didn’t catch, check the log first.

Terminal window
jiayang logs acme/hello
10:04:30 LOG v3 GET /pay charging order 1182
10:04:31 ERROR v3 GET /pay Cannot read properties of undefined (reading 'id')

Each line has the time in UTC, the level, the version whose code wrote it, the request being handled, and what the app wrote. A line written outside a request says what started it instead, such as cron or alarm.

Each line shows the version that wrote it. A container’s output, and a line we can’t trace to an upload, shows the version that was live when it was written, so for a minute or two after a deploy it can show the new version.

In a Worker app, an exception your code doesn’t catch is logged at error with its message, not its type or its stack. To see where one was thrown, catch it and log err.stack with console.error.

By default you get the last hour, oldest first. A line can take up to half a minute to arrive, so a read without --follow may be missing the last few. --follow keeps printing new lines until you stop it:

Terminal window
jiayang logs acme/hello --follow
Flag Shows
--since 15m Lines from that far back: 30s, 15m, 2h, 1d, or an RFC 3339 time. The default is 1h.
--level warn Lines at that level or louder: debug, info, warn or error. info includes console.log. A container app’s output is info unless it says otherwise, as below.
--version 3 Lines written by version 3. A version the app never had is refused.
--search "order 1182" Lines with that text in them. Not case-sensitive.
--limit 500 Up to that many lines before following, keeping the newest. The default is 100, and the most is 500.
--platform For a container app, our own lines as well: its container starting, restarting for a new version or configuration, and stopping, and a request it stopped in the middle of. They’re marked platform. Without the flag they’re left out, and jiayang logs says how many.

--json prints the page as JSON, or one line of JSON per log line with --follow. Either way the lines are oldest first, as in the text. With --follow, a line that took longer to arrive prints when it does, after newer ones already printed.

When a container starts, we ask it for / to see that it’s up, with no signed-in user. An app that requires one answers 401, so a server that logs its requests prints a GET / with 401 each time the container starts. That line is the check, not a visitor.

In the dashboard, the app’s Logs tab shows the same lines and adds new ones while the tab is open. An agent reads them with the app_logs tool.

Cloudflare can’t tell a container’s stdout from its stderr, so everything a container writes is info, stderr and tracebacks included. --level error and the dashboard’s Errors filter leave those lines out. To find an exception, read the lines without a level, or search for it:

Terminal window
jiayang logs acme/api --search Traceback

A line has a level of its own only when your app writes it as a JSON object with a level field, such as {"level":"error","message":"card declined"}. The level is debug, info, warn or error, written like warn, WARN or Warn. The names other loggers use work too: warning is warn, and critical, fatal and panic are error. A name it doesn’t know, such as http, reads as log: --level info shows the line and --level warn doesn’t. A field with another name, such as severity, isn’t read.

The app’s editors and owners, and the workspace’s owners and admins, can read its logs. A viewer, in the workspace or not, can open the app but can’t read its logs, because they can hold anything your code printed about the people using it:

error: Only acme/hello's editors and owners, and the workspace's owners and admins, can read its logs.

The log holds only what your app writes. We don’t add a line per request. To see requests, use jiayang watch or the audit log.

Before a line reaches you, we remove:

  • anything shaped like a signed token, such as the identity token in X-Jiayang-Identity if your code prints its request headers
  • our own tokens (jyb_, jyu_, jyo_ and the like)
  • query strings from the request line
  • terminal control codes

Everything else is kept as your app wrote it, so keep secrets and personal data out of your log lines.

Cloudflare keeps every line for 7 days, then deletes it. Your plan sets how far back you can read them:

Plan Readable for Lines a day
Free 1 day 20,000
Team 7 days 100,000
Business 7 days 300,000
Enterprise 7 days 300,000

The daily count covers every app in the workspace and resets at midnight UTC. Once the workspace reaches it, logging stops until the next UTC day, and anything the apps write in the meantime is lost. Moving to a plan that allows more lines than that turns it back on within five minutes. jiayang logs and the dashboard tell you when this has happened. Your apps keep running.

  • A line can take up to half a minute to arrive. Try again, or use --follow.
  • Check --since: the default is the last hour.
  • The workspace may have reached its lines for the day. jiayang logs says so.
  • If jiayang logs says reading logs isn’t turned on yet, we can’t read them for now and we already know about it. Your apps’ lines are still kept, and the ones your plan can read appear once reading works.
  • A container’s output is logged only after the container has started. A container that fails to start writes nothing. See Container apps.

To keep your apps’ logs next to the rest of yours, add a log drain. It sends each app’s lines to your own HTTPS endpoint, Datadog, Grafana Loki or an S3 bucket as they’re written. Drains are on Team, Business and Enterprise.

  • Log drains: send logs to Datadog, Loki, a bucket or your own endpoint.
  • Audit log: every request let in or turned away.
  • Troubleshooting: common errors and what to do about each.