Skip to content

fsl logs: read logs in the terminal

You do not need the cloud console to read your logs. fsl logs reads them from the command line and prints one JSON entry per line, for you or for a coding agent.

fsl logs asks the same questions as the Cloud Logging console, and the same command reads the emulator’s local files. Its flags are named after SQL clauses: --where severity=ERROR --since 2h --group-by labels.screen.

Guess a field that does not exist and the error names the valid ones, so the next try is right.

Production entries come through gcloud logging read. The gcloud CLI, signed in with gcloud auth login, is the only setup. It reads with its own sign-in, not the application-default credentials. No Google library is added to your install. The project id and bucket name are never printed, not even in an error.

For the project, pass --project <id>, or let it read .firebaserc. Add --local to read .fsl-logs/*.jsonl instead, with the same flags and the same output.

Terminal window
# One user's story: client and server, in time order
npx fsl logs --where labels.userId=<uid> --since 2h --select timestamp,severity,labels.screen,message
# Which screen had the most errors in a release
npx fsl logs --where severity=ERROR --where labels.releaseId=<sha> \
--group-by labels.screen --select labels.screen,count --order-by "count desc" --limit 10
# The same, against .fsl-logs/ instead of the cloud
npx fsl logs --local --where severity=ERROR --group-by labels.screen --select labels.screen,count

Fields are written as Cloud Logging stores them: labels.screen, labels.userId, labels.releaseId, severity, message, timestamp. Use labels.screen, not screen. Payload fields start with jsonPayload., for example jsonPayload.error.message.

Flag Meaning
--where field=value One condition. Repeat it for more. Operators: =, !=, >=, <=, ~ (contains).
--select a,b,count The fields to print. Fewer fields, smaller output. With no value it prints the fields.
--group-by field Count or aggregate per value. --select names the aggregate: count, min(f), max(f).
--order-by "field desc" Sort order. Entries come oldest first unless you order them.
--limit N Rows to print. 100 by default, 1000 at most.
--distinct field The distinct values of one field.
--since 1h 30m, 1h, 2d, or an ISO time. 1 hour by default.
--repeats <repeatKey> One repeating error: its full copies, its summaries, and a last line with the true count. Looks back 7 days unless --since says otherwise.
--local Read .fsl-logs/*.jsonl instead of Cloud Logging.
--project <id> The Google Cloud project. Read from .firebaserc when not given.

Group, count and --select before you fetch whole entries. Ten lines of counts beat five thousand lines of entries. A whole entry includes its stack and breadcrumbs, so ask for them one entry at a time.

stdout holds only entries, one JSON object per line. Everything else goes to stderr.

  • No matches. stdout stays empty and one line on stderr says so, for example 0 entries matched in the last 1h. An empty result is not mistaken for a broken command.
  • A cut result. When --limit cut the rows, a line on stderr says how many more there were.
  • A large window. A production query reads the newest 5000 entries in the window and says on stderr when it hit that. Narrow it with --since or --where.
  • A wrong flag or field. An unknown flag is an error that lists the valid flags and shows an example. An unknown field names the nearest one and points at fsl logs schema.

A repeating error sends a few full copies and then one summary that counts the rest, so counting entries gives the wrong number. Take the error’s labels.repeatKey and ask for it directly:

Terminal window
npx fsl logs --repeats <repeatKey>

See Rate limits and missing logs.

fsl logs schema lists every label in your logs, how many entries have it, and sample values.

Terminal window
npx fsl logs schema
npx fsl logs schema --add venueId "the venue the order belongs to" --add tableId
npx fsl logs schema --refresh

--add records a label your code can write but the logs have not shown yet, with an optional meaning, for the next reader. --refresh re-reads the logs and keeps the --add entries. --remove <name> drops one of the --add entries, --json prints JSON, and --local reads the local files.

It reads the last 500 entries and keeps the result in .fsl-logs/schema.json for a day, in two parts: fromLogs, which --refresh rewrites, and fromCode, which --add fills and --refresh leaves alone.

When an entry has labels.hasAttachments="true", fetch its files by labels.logId:

Terminal window
npx fsl logs attachments <logId>

Files download to .fsl-logs/attachments/<logId>/ through gcloud storage, and each path is printed. The bucket comes from --bucket <name>, else FIREBASE_STORAGE_BUCKET, else VITE_FIREBASE_STORAGE_BUCKET, with .env.local loaded. See Screenshots and files.

npx fsl install-skills installs a /fsl-logs skill that teaches a coding agent how to use fsl logs. See Skills for coding agents.

Made by Dasasian