Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Responsible Logging

ASecurity

Designs and audits leveled, bounded, correlated logging for a long-lived service or daemon — a per-key rate-limit/dedup governor with suppression rollups, sampling that reports true totals, rotation plus the launchd/systemd captured-stdout trap, one-logger discipline, and observability that can never crash the process. Use when adding logging to a poll/retry/heartbeat loop, when logs eat disk or a daemon writes an unrotated file, when reviewing log level discipline, or when threading request/...

2 stars
0 votes
0 copies
0 views
Added 9/24/2026
toolspythonrustgobashnodeperformance

Security Analysis

A100/100

Pro scans all 8 files and shows the line behind each finding

Scanned 9/24/2026

$npx -y skills add curiositech/port-daddy --skill responsible-logging --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Responsible Logging?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Responsible Logging
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/curiositech-responsible-logging/badge)](https://www.skillsdirectory.com/skills/curiositech-responsible-logging)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
name: responsible-logging
description: >-
  Designs and audits leveled, bounded, correlated logging for a long-lived
  service or daemon — a per-key rate-limit/dedup governor with suppression
  rollups, sampling that reports true totals, rotation plus the launchd/systemd
  captured-stdout trap, one-logger discipline, and observability that can never
  crash the process. Use when adding logging to a poll/retry/heartbeat loop, when
  logs eat disk or a daemon writes an unrotated file, when reviewing log level
  discipline, or when threading request/tenant correlation ids. NOT for choosing
  a log-aggregation vendor, dashboards/metrics/tracing pipelines, or app business
  logic. Keywords: logging storm, log spam, error in a loop, dedup, rate limit,
  rollup, sampling, log rotation, unrotated stdout, launchd, systemd, structured
  logging, correlation id, tenant id, log governor.
allowed-tools: Read,Grep,Glob,Edit,Write,Bash(python3:*)
argument-hint: '[path-to-audit] [action: audit|design|review]'
metadata:
  category: Observability & Reliability
  tags:
  - logging
  - rate-limiting
  - dedup
  - log-rotation
  - correlation-id
  - daemon
---

# Responsible Logging

Make a long-lived service log **leveled, bounded, correlated, and non-fatal** — so a
persistently-failing loop reports once with a count instead of writing 313 GB overnight.

## When to Use

✅ **Use for**:
- Adding a log line to any loop: `for`/`while`/`setInterval`/`.on(...)`/retry/poll/heartbeat.
- A daemon eating disk, an unrotated log file, or a launchd/systemd captured-stdout blowup.
- Reviewing level discipline (`error` vs `warn` vs `info`) and `console.*`/`print` sprawl.
- Designing per-key dedup/rate-limit/sampling with **rollups**, or a log governor primitive.
- Threading `requestId`/`actorId`/`tenantId` correlation ids through logs (multi-tenant).
- Making observability fail-safe: a broken sink must not crash or stall the process.

❌ **NOT for**:
- Picking a log-aggregation vendor / building a metrics/tracing/APM pipeline (use `observability-apm-expert`, `log-aggregation-architect`).
- Dashboard or alerting-UI design.
- Application business logic, or non-logging performance work.

---

## The Cardinal Anti-Pattern (read this first)

> **Error-level logging inside an unthrottled retry/poll loop with no dedup.**

This one shape caused a real **313 GB** write storm: `semantic_resolution_failed` logged
**7,182×** with no backoff and no dedup, plus a **255 MB unrotated** captured-stdout file
and a 231 MB DB. Worse, an *identical* prior incident (`bosun_heartbeat_write_failed`) was
patched **narrowly at the call site and RECURRED months later** — the class stayed open
until a shared **log governor** primitive existed. Full story:
`references/case-study-port-daddy.md`.

The fix is never "add an `if` at that one call site." The fix is a reusable primitive plus
an audit that keeps the class closed.

---

## Core Process

```mermaid
flowchart TD
  A[Log line to add or review] --> B{Can it fire in a loop?<br/>for / while / interval / .on / retry / poll}
  B -->|No, one-shot| C[Passthrough logger.<br/>Level per discipline table]
  B -->|Yes| D{Is the SOURCE a<br/>persistent failure?}
  D -->|Yes| E[Back off the operation:<br/>circuit breaker + jitter.<br/>Governing the log alone<br/>leaves a hot, non-healing loop]
  D -->|No / also| F[Route through a per-key<br/>LogGovernor]
  E --> F
  F --> G{High-volume<br/>non-error stream?}
  G -->|Yes| H[sampleEveryN;<br/>rollup reports TRUE total]
  G -->|No| I[burst-per-window;<br/>rollup reports suppressed tail]
  H --> J[Compose UNDER correlation sink:<br/>request_id / actor_id / tenant_id auto-merged]
  I --> J
  J --> K[Verify sink is fail-safe:<br/>a throwing sink must not crash the process]
  K --> L[Run audit_logging.py; fail CI on CARDINAL]
```

### Step 1 — Audit the codebase

Enumerate every offending site before touching code. The bundled script reads structured
source tokens (not prose):

```bash
python3 scripts/audit_logging.py <path>          # human-readable, ranked
python3 scripts/audit_logging.py <path> --json   # for CI / further processing
```

It flags: **CARDINAL** error/warn logs inside unthrottled loops; **HIGH** launchd/systemd
captured-stdout traps and uncapped File transports; **MEDIUM** raw `console.*`/`print`
sprawl. Exit code is non-zero on findings — wire it into CI so the class cannot reopen.

### Step 2 — Reach for a primitive, not a patch

Match the situation to a primitive (details in `references/governor-primitive.md`):

| Situation | Reach for | Key rule |
|-----------|-----------|----------|
| Error/warn that can fire every tick | **LogGovernor** `governed({level, key})` | STABLE low-cardinality key |
| Chatty request/trace stream | `governed({sampleEveryN:N})` | rollup reports the **true** total |
| One-shot event (boot/shutdown/config) | passthrough `info()`/`error()` | no key needed |
| A dependency that fails permanently | **circuit breaker + jitter** around the load | governor bounds the *log*, not the *failure* |
| A file/table that grows forever | **rotation / retention policy** | governor doesn't bound data volume |

The governor bounds *how often you log*. It does **not** fix the failure — pair it with
backoff on the failing operation, or you get a quiet loop that still burns CPU forever.

### Step 3 — Get the governor key right

The single most common mistake. The key must be the **stable shape** of the event, never
its instance:

```ts
// ✅ collapses the storm
obs.governed({ key: 'semantic_resolution_failed', level: 'error',
               message: 'semantic_resolution_failed', meta: { term, error: String(err) } });

// ❌ every occurrence is a new key → nothing dedups → storm rebuilt
obs.governed({ key: `semantic_resolution_failed:${term}`, /* ... */ });
```

Varying detail (ids, terms, timestamps, tenant) goes in `meta`, never in the key.

### Step 4 — Rotation + the captured-stdout trap

An in-process rotating logger only rotates **files it owns**. Raw stdout captured by
launchd (`StandardOutPath`) or systemd (`StandardOutput=append:`) is **never rotated by
the service manager** — that is how 255 MB accumulated while winston rotated fine. Cap
in-process files (`maxsize` **and** `maxFiles`), keep stdout terse, and rotate any
captured stream out-of-band. Details + fixes: `references/rotation-and-capture-traps.md`.

### Step 5 — Correlation + fail-safe (the two horizons)

- **Multi-tenant horizon**: thread `{ requestId, actorId, tenantId }` via `AsyncLocalStorage`
  / contextvars / `context.Context` and compose the governor **under** a correlation sink so
  every line (and every rollup) carries the ids — no call-site changes. Attribution ≠
  authorization; never gate access on a log field.
- **Dev-on-dev horizon (now)**: the storm happened on an unwatched dev box. A `SelfMonitor`
  on the daemon's **own** DB/WAL/footprint (not whole-disk %) is what would have caught it.
  Wire `requestId` even single-tenant so the plumbing exists before real tenants arrive.
- **Fail-safe**: wrap every emit — `try { emit } catch {}` around the sink call. A broken sink must
  not crash the daemon. Test it: inject a throwing sink and assert requests still complete.
  See `references/multi-tenant-and-safety.md`.

---

## Anti-Patterns

### Anti-Pattern: Error-level log inside an unthrottled loop with no dedup

**Novice**: "It's an error, so I log it at `error` every time it happens. Logging is cheap
and I want to see all of them."
**Expert**: In a loop that fires every few seconds, "all of them" is unbounded. This exact
shape wrote **313 GB** and **7,182** identical `semantic_resolution_failed` lines with no
backoff. Logging is *not* cheap at loop frequency — it is disk, inodes, and DB rows.
Route loop-logs through a per-key governor: emit the first few per window, count the rest,
and flush **one rollup** (`…and 4,312 more in 60s`) so you keep the fact without the bytes.
And back off the failing operation itself — a bounded log over a hot non-healing loop is
still a CPU leak.
**Timeline**: 2026-05-31 `bosun_heartbeat_write_failed` patched narrowly at the call site →
recurred as `semantic_resolution_failed` (313 GB) → class closed only once a shared
`LogGovernor` primitive existed. A patch closes an instance; a primitive closes the class.
**LLM mistake**: models emit `logger.error(...)` unconditionally inside `catch` blocks and
`while` loops because that is the dominant pattern in training data — most of which is
short-lived request handlers, not daemons that run for weeks.
**Detection**: `python3 scripts/audit_logging.py <path>` → any `CARDINAL` finding.

### Anti-Pattern: Trusting the in-process logger to bound ALL output

**Novice**: "winston/pino is configured with `maxsize` and `maxFiles`, so my log volume is
bounded. Done."
**Expert**: The rotating logger only rotates **files it owns**. Every `console.log` /
`print` / `fmt.Println` goes to raw stdout, and when launchd/systemd captures that stream
it is **never rotated by the service manager**. In the incident, winston rotated at
50 MB × 5 perfectly while a captured-stdout file hit **255 MB** in one handle. Rotation is
necessary but not sufficient: you also need **one-logger discipline** (no raw-sink sprawl)
and out-of-band rotation (newsyslog/logrotate/journald) for any captured stream.
**Timeline**: Pre-2026-05 raw `console.*` sprawl coexisted with a correctly-configured
winston logger → the 313 GB storm rode mostly the raw path → fix consolidated on one
governed logger and audited raw sinks in CI.
**LLM mistake**: models treat "configured a rotating file transport" as equivalent to
"logging is bounded," ignoring the stdout/stderr the service manager captures.
**Detection**: `audit_logging.py` `HIGH` findings (`launchd-captured-stdout-never-rotated`,
`systemd-file-capture-never-rotated`, `unrotated-file-transport`) and `MEDIUM`
`raw-sink-bypasses-logger`.

---

## Level Discipline (quick reference)

| Level | Means | In a loop? |
|-------|-------|------------|
| `error` | a human must eventually act | **only via the governor** |
| `warn` | degraded but self-handling (breaker open, retrying) | governed |
| `info` | notable lifecycle event | governed or `sampleEveryN` |
| `debug` | developer detail, off in prod | governed if in a hot path |

---

## Bundle Contents

| File | What it is | Consult when |
|------|-----------|--------------|
| `scripts/audit_logging.py` | Stdlib-only auditor; ranks CARDINAL/HIGH/MEDIUM findings, non-zero exit for CI | Step 1 — before editing any logging code |
| `references/case-study-port-daddy.md` | The 313 GB incident, the recurrence, the five-primitive fix | Understanding *why* each rule exists; convincing a skeptic |
| `references/governor-primitive.md` | Stack-agnostic LogGovernor contract + pseudocode + porting notes | Building/reviewing a dedup/rate-limit/sampling primitive |
| `references/rotation-and-capture-traps.md` | Rotation settings, launchd/systemd capture trap, one-logger + level discipline | Any disk-growth, rotation, or stdout-capture question |
| `references/multi-tenant-and-safety.md` | Correlation-id threading, dev-on-dev horizon, fail-safe observability | Multi-tenant correlation, self-monitoring, auxiliary rules |

---

## Validation Checklist

```
□ Every loop-emitted error/warn goes through a per-key governor (audit_logging.py clean of CARDINAL)
□ Governor keys are stable + low-cardinality (no ids/terms/timestamps in the key)
□ Suppression emits a ROLLUP — the tail count is never silently dropped
□ Sampled streams report the TRUE total, not the sampled count
□ In-process File transports cap maxsize AND maxFiles
□ Captured stdout/stderr (launchd/systemd) is rotated by SOMETHING
□ One logger; no raw console.*/print sprawl (audit_logging.py clean of MEDIUM)
□ Correlation ids (request/actor/tenant) auto-merged under the governor
□ A throwing sink cannot crash the process (tested with an injected failing sink)
□ Fixed the CLASS (audited for siblings), not just the one call site
```

Attribution

curiositechcuriositech
View sourceSee grades on GitHubMore from curiositech →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

ucoz-landing-skill

Create and edit uCoz homepage landing pages via MCP: custom templates, hero sections, lead forms, navigation menus, SEO, and responsive layout. Includes a visual design system (style selection, layout/grid, section recipes, typography/spacing, color tokens, component states, icons, modern CSS/JS, motion, imagery, social proof, copy/voice, accessibility). Uses ucoz-mcp tools for templates, site file uploads, and site modules.

107 votes

Paperclip

Interact with the Paperclip control plane API for task coordination and governance. Use when checking assignments, updating issue status, posting comments, delegating work, managing routines, or calling Paperclip API endpoints.

953191 votes

Pptx

Presentation toolkit (.pptx). Create/edit slides, layouts, content, speaker notes, comments, for programmatic presentation creation and modification.

471861 votes

Daw Music

Digital Audio Workstation usage, music composition, interactive music systems, and game audio implementation for immersive soundscapes.

761 votes

Instantly Rdsthomas Mission Control

Instantly.ai cold email outreach API - manage campaigns, leads, accounts, and analytics. Use for cold email automation, lead management, campaign creation/monitoring, and email account warmup.

761 votes
View all in tools →