---
name: gfiber-logging
description: >-
  Decides the level of a log line in GFiber services and keeps INFO volume bounded.
  Use when writing or reviewing logging code, choosing between DEBUG, INFO, WARN and
  ERROR, adding observability to a service, judging whether a line belongs in a log or
  a metric, or auditing a service for log volume before a merge request.
---

# GFiber Logging

Level policy and field conventions for log lines in GFiber services.

Canonical source: [How To: What logs belong at INFO, DEBUG, WARN and ERROR in GFiber services](https://bass.netcracker.com/display/GF/How+To%3A++What+logs+belongs+at+INFO%2C+DEBUG%2C+WARN+and+ERROR+in+GFiber+services). When this skill and the BASS page disagree, the page wins and this skill gets updated.

References: [references/levels.md](references/levels.md), [references/cases.md](references/cases.md), [references/anti-patterns.md](references/anti-patterns.md), [references/audit.md](references/audit.md).

## Hard rules

- **INFO is capped** — work received, work finished, one result per work item. Nothing else.
- **No unbounded collection at INFO** — the count is INFO, the collection behind it is DEBUG.
- **No INFO inside a loop** over alarms, ONTs, targets, services, tickets or messages. The per-item result line is the one legitimate exception.
- **Cap identifier lists** at 50 entries followed by `+N more`.
- **Always the `Ctx` variant** — `LogInfoCtx`, never `LogInfo`. The plain call drops `request_id` and every business identifier.
- **Never a full request or response body at INFO** — log a projection; bodies go to DEBUG or behind on-demand troubleshooting.
- **Mint correlation ids at ingress**, not deeper. An id created inside the handler cannot join the lines written before it.
- **No secrets, tokens or customer PII** at any level.
- **DEBUG is not present in production** — `LOG_LEVEL` is `INFO` in every shipped chart. A decision that must be explainable in production cannot live at DEBUG.

## Workflow: one log line

1. Walk the decision list in [references/levels.md](references/levels.md) and stop at the first yes.
2. If the answer was INFO, confirm the line matches one of the four INFO cases. If it does not, it is DEBUG.
3. Look the situation up in [references/cases.md](references/cases.md). Startup, scheduled ticks, Kafka, health probes and upstream calls all have a fixed answer there.
4. Apply the field format from [references/levels.md](references/levels.md): `key=value`, snake_case, subject prefix, `%q` only for values that can be empty or contain spaces.
5. Confirm the identifiers. On WARN and ERROR, add them only where no per-item result line will run for that work.

## Workflow: adding logging to a service

1. Read [references/cases.md](references/cases.md) and pick the reference implementation closest to the service shape (request handler, batch policy, scheduler, Kafka consumer).
2. Run the static audit in [references/audit.md](references/audit.md) to record the starting numbers.
3. Add the three INFO lines the policy expects, in this order, because each one is useless without the previous: work received, per-item result, batch summary.
4. Add WARN on every branch that rejects or drops work, with a fixed reason vocabulary and a counter.
5. Add ERROR on every branch that loses work after retries, carrying the identifiers and the step that stopped.
6. Demote or delete what the audit flagged: collection dumps, per-object INFO, ticks that fire on a timer, lines whose whole content is already in the runtime prefix.
7. Re-run the audit and report before and after.

## Workflow: reviewing a merge request

1. Apply the checklist in [references/audit.md](references/audit.md).
2. Check the level of each added line against [references/cases.md](references/cases.md), not against how important the code feels.
3. Scan for the known anti-patterns in [references/anti-patterns.md](references/anti-patterns.md). Pointer maps, bad verbs and silent rejections are the three that recur.
4. If the change touches a high-volume path, require the volume gate table in the merge request description.

## Workflow: auditing a service for volume

1. Run the static audit script from [references/audit.md](references/audit.md) at the service checkout root.
2. Exclude lines already behind an on-demand troubleshooting guard; the ungated count is the one that matters.
3. Rank by `dump` and `loop` rather than by raw INFO count: a service with few INFO lines that all print collections is worse than one with many bounded lines.
4. Measure the real numbers on a reference scenario per the volume gate, not only the static count.

## Choosing the channel

Most of the volume problem is picking the wrong channel. Full table in [references/levels.md](references/levels.md).

- "How often" or "how slow" is a **metric**, and it cannot carry an identifier.
- "What happened to this specific id" is a **log**, and it costs shared retention.
- "What did we do to this item, on the record" is a **BLM action log**, and it is not reachable from the SA Graylog streams.

## Safety

- **Read-only** — this skill reasons about code and proposes changes. It runs no mutation of its own.
- Source trees under `sources/product/` are read-only; propose changes, never edit.
- Sync sources with `gfiber-sources` before auditing a service.

## Related skills

| Skill | Role |
|-------|------|
| `gfiber-sources` | Clone or checkout the service before auditing it |
| `gfiber-sa-troubleshooting` | Consumer of these logs; its Graylog searches are why identifiers must be literal |
| `gfiber-svt-analysis` | Registered SVT cases used as the reference scenario for the volume gate |
| `skills/_shared/code-reviewer` | General review pass; this skill covers the logging dimension only |
