4.1 KiB
Auditing a service and the volume gate
Static audit
Run from the checkout root of any Go service under sources/project/. Heuristic, not a linter: it flags short projection methods such as toShortString() as dumps, and it does not know about on-demand troubleshooting guards. Read what it prints; do not treat the counts as a gate on their own.
import re, glob
files = [f for f in glob.glob('**/*.go', recursive=True)
if not f.endswith('_test.go') and '/vendor/' not in f]
info = dump = loop = noctx = 0
for path in files:
depth, loops = 0, []
for i, line in enumerate(open(path, errors='ignore'), 1):
stripped = line.strip()
if re.search(r'\bfor .*\{\s*$', stripped):
loops.append(depth)
depth += line.count('{') - line.count('}')
loops = [d for d in loops if d < depth]
if re.search(r'logging\.Log(Info|Debug|Warning|Error|Fatal)\(', line):
noctx += 1
print(f'noCtx {path}:{i}: {stripped[:100]}')
if re.search(r'logging\.LogInfo(Ctx)?\(', line):
info += 1
if '%+v' in line and not re.search(r'%\+v[^"]*"\s*,\s*len\(', line):
dump += 1
print(f'dump {path}:{i}: {stripped[:100]}')
if loops:
loop += 1
print(f'loop {path}:{i}: {stripped[:100]}')
print(f'INFO={info} dump={dump} loop={loop} noCtx={noctx}')
To exclude lines already behind an on-demand troubleshooting guard, track the brace depth of the block opened by IsAlarmTroubleshootingActive( and skip lines while inside it. In gfiber-policy-executor that moved the count from 77 INFO sites to 34 ungated ones, which is the number that matters.
How to read the output
| Signal | Meaning |
|---|---|
high dump against low INFO |
the few INFO lines the service has are the expensive kind |
any loop |
a line scaling with item count rather than request count; the per-item result line is the one legitimate case |
noCtx |
lines that cannot be attached to a work item |
Volume gate
Any change to logging on a high-volume path states its volume impact in the merge request. Measure the same scenario before and after, in the same namespace and window, using the graylog-search entry in scripts/data/index.yaml with --scope containers and a container plus level filter, per scripts/data/graylog-search.example.md.
Repeat for INFO, DEBUG, WARN and ERROR, then rerun on the branch build.
| Metric | Before | After | Delta |
|---|---|---|---|
| INFO messages per run | |||
| INFO bytes per run | |||
| DEBUG messages per run | |||
| WARN and ERROR per run | |||
| Longest single INFO line, bytes |
Acceptance: INFO message count and INFO bytes must not increase. DEBUG is allowed to grow, since it is off in production.
For SA services use the registered SVT cases from skills/gfiber-svt-analysis/cases/index.yaml. Services without an SVT case need a reference scenario agreed with the reviewer before the gate means anything.
On the same run, confirm that a sample identifier from it is still findable at LOG_LEVEL: INFO with the SA alarm template from queries/graylog/index.yaml. That is the regression the policy exists to prevent, and it is satisfied by the per-item result line rather than by anything new.
Merge request checklist
The hard rules in levels.md double as the review checklist. In addition:
- Every new INFO line matches one of the four INFO cases.
- No new INFO line prints a collection, a struct or a body.
- No new INFO line sits inside a loop over domain objects.
- Every identifier list is capped.
- Every call is the
Ctxvariant. - WARN and ERROR on failure paths carry the identifiers of the work they lost.
- The summary line is written from a
deferthat survives a panic. - New metric labels come from a fixed vocabulary, with no identifiers in them.
go vetis clean and no line prints a pointer address or a%!smarker.