QA Interview Hub · Knowledge base · Quizzes

Logs and observability

Logs for a QA

What a log entry holds and what the levels mean

A log is a journal of events an application writes about itself. For a QA it is the shortest path from "something broke" to "here is where and why". A typical entry contains:

  • timestamp — the time of the event (preferably UTC, with milliseconds and a zone, for example ISO 8601);
  • level (severity);
  • source — the service, instance, class or module, sometimes the thread;
  • message — what happened;
  • context — request id / trace id, user id (pseudonymised), parameters, an error code, a stack trace.

The levels, from most detailed to most critical:

  • TRACE — very detailed execution flow, usually off;
  • DEBUG — developer details: variable values, logic branches; usually off in production;
  • INFO — normal meaningful events: the service started, an order was created;
  • WARN — something odd, but the system coped: a retry, a deprecated API, a slow response;
  • ERROR — an operation failed (a request ended with an error), attention is needed;
  • FATAL — the application cannot continue (not present in every library).

The level threshold is set by configuration: at INFO you will not see DEBUG. So "there is nothing in the logs" sometimes only means the needed level is turned off in that environment.

What a QA checks: that an error really lands in ERROR (and is not swallowed), that user validation failures (400) do not flood ERROR, that an entry has enough context to investigate, and that it contains no passwords, tokens or personal data.

Structured and plain-text logs

A plain-text log is a free-form line for a human:

2026-10-12 09:14:03,512 ERROR [checkout] Payment failed for order 8841: gateway timeout

It is easy to read by eye but hard to analyse: to extract an order id or a duration you need regexes that break when the wording changes.

A structured log is usually one JSON object per line (NDJSON / JSON Lines):

{"ts":"2026-10-12T09:14:03.512Z","level":"error","service":"checkout","msg":"payment failed","orderId":8841,"traceId":"4bf92f3577b34da6a3ce929d0e0e4736","error":"gateway timeout","durationMs":30012}

Fields can be filtered and aggregated without parsing text: "all errors of the checkout service in the last hour, grouped by error". That is why modern systems write structured logs and keep the message stable (no variables inside), moving the variable parts into fields.

Practical rules:

  • one event, one line; the stack trace goes into a field and is not spread over dozens of lines (otherwise the aggregator splits the entry);
  • field names are the same across all services (for example traceId, userId);
  • do not log whole large request/response bodies;
  • a "pretty" format is fine locally for humans, JSON in production.

For a QA: structured logs let an automated test find an entry precisely by a field rather than by a substring of the message.

Where to find logs and how to localise a bug with them

Where logs live:

  • browser: DevTools → Console (JS errors, console.error, resource errors), Network (statuses and response bodies);
  • backend: container stdout/stderr (docker logs, kubectl logs), files on a server and, in mature systems, a centralised store (ELK/OpenSearch, Loki, Datadog);
  • CI: the job console and artifacts (service logs, reports);
  • mobile: Android — adb logcat / Logcat in Android Studio; iOS — the Xcode console, Console.app, log stream; crash reports — Crashlytics/Sentry.

How to localise a bug:

  1. Reproduce it and record the exact time and environment (mind the time zone!).
  2. In DevTools look at Console and Network: are there red requests? What status? If a request went out and returned 5xx, the problem is on the backend; if the request never went out or there is a JS exception, it is on the frontend; 4xx is often wrong data or authorisation.
  3. Take the request id / trace id from a response header or the error body and find the backend entries by it.
  4. Find the first error in the chain, not the last: cascading failures produce dozens of following ERRORs.
  5. Look at what came before: WARNs, retries, configuration changes, a deploy.

What to add to a bug report: steps, expected/actual result, environment and build version, time with the zone, request/trace id, a relevant log excerpt (without secrets), a screenshot or HAR/trace. Such a report saves the developer time on reproduction.