skills/mav-bp-logging/SKILL.md
Logging conventions for backend and frontend applications. Covers log levels, structured logging, centralised aggregation, and project logging guidance. Applied when writing or reviewing code that includes logging.
npx skillsauth add thermiteau/maverick-private mav-bp-loggingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Ensure all logging is meaningful, structured, and routed to centralised services. Noise-free, error-focused, actionable.
digraph levels {
rankdir=LR;
"error" [shape=box style=filled fillcolor="#ffcccc"];
"warn" [shape=box style=filled fillcolor="#fff3cc"];
"debug" [shape=box style=filled fillcolor="#cccccc"];
"error" -> "warn" -> "debug" [style=invis];
}
| Level | When to use | Example |
| ------- | ---------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| error | Failures requiring attention — unhandled exceptions, failed external calls, data corruption, auth failures | Database connection failed, Payment processing error, Unhandled promise rejection |
| warn | Recoverable issues that may indicate a problem — retries, fallbacks, deprecated usage, approaching limits | Rate limit approaching (80%), Retry 2/3 for S3 upload, Deprecated API version used |
| debug | Development diagnostics — removed or disabled in production | Request payload: {...}, Cache miss for key: x, Query took 230ms |
info level — it creates noise. If something is important enough to log in production, it's either a warn or an error. If it's only useful during development, it's debug.console.log in application code — use the project's structured logger. console.log is acceptable only in build scripts, CLI tools, and one-off debugging (removed before commit).All application logs must be JSON-formatted with consistent fields.
{
"timestamp": "2024-01-15T10:30:00.000Z",
"level": "error",
"message": "Failed to process payment",
"service": "payment-service",
"context": {}
}
Include relevant context to enable diagnosis:
{
"timestamp": "2024-01-15T10:30:00.000Z",
"level": "error",
"message": "Failed to process payment",
"service": "payment-service",
"context": {
"requestId": "req-abc-123",
"userId": "user-456",
"paymentId": "pay-789",
"amount": 2500,
"currency": "USD",
"provider": "stripe",
"errorCode": "card_declined",
"attempt": 1
},
"error": {
"name": "StripeCardError",
"message": "Your card was declined",
"stack": "Error: Your card was declined\n at ..."
}
}
For HTTP request/response logging (access logs), use either:
JSON format (preferred for structured aggregation):
{
"timestamp": "2024-01-15T10:30:00.000Z",
"method": "POST",
"path": "/api/payments",
"statusCode": 500,
"duration": 1230,
"requestId": "req-abc-123",
"userAgent": "Mozilla/5.0..."
}
Apache Combined Log Format (acceptable for HTTP-specific logs):
127.0.0.1 - user [15/Jan/2024:10:30:00 +0000] "POST /api/payments HTTP/1.1" 500 1230 "-" "Mozilla/5.0..."
Every backend project should have a single logger module that all other modules import.
// src/lib/logger.ts — example structure
import { createLogger } from "<logging-library>";
export const logger = createLogger({
level: process.env.LOG_LEVEL || "error",
format: "json",
service: process.env.SERVICE_NAME || "api",
// Transport configuration from project logging guide
});
// GOOD: Structured error with context
logger.error("Payment processing failed", {
requestId,
userId,
paymentId,
error: err.message,
stack: err.stack,
});
// GOOD: Warning with actionable context
logger.warn("Rate limit approaching", {
current: rateLimitCount,
limit: MAX_RATE_LIMIT,
percentUsed: (rateLimitCount / MAX_RATE_LIMIT) * 100,
windowResetAt: resetTimestamp,
});
// GOOD: Debug for development only
logger.debug("Query executed", {
table: "grades",
duration: queryDuration,
rowCount: results.length,
});
// BAD: Noise
logger.info("Processing request");
logger.info("Request completed successfully");
console.log("here");
console.log(JSON.stringify(data));
Log errors at the boundary where they are handled, not at every level they propagate through:
// GOOD: Log once at the handler level
app.setErrorHandler((error, request, reply) => {
logger.error("Unhandled request error", {
requestId: request.id,
method: request.method,
url: request.url,
error: error.message,
stack: error.stack,
});
reply.status(500).send({ error: "Internal server error" });
});
// BAD: Logging at every level
async function getUser(id: string) {
try {
return await db.users.findById(id);
} catch (err) {
logger.error("Failed to get user", { id, err }); // Logged here
throw err; // AND logged again by the caller, and again by the handler
}
}
Backend logs should be routed to a centralised logging service. The specific transport depends on the deployment environment and is defined in the project's logging guidance document.
Common transports:
| Environment | Service | Transport | | ----------- | --------------- | ------------------------------------- | | AWS | CloudWatch Logs | stdout → CloudWatch agent, or AWS SDK | | AWS Lambda | CloudWatch Logs | stdout (automatic) | | Generic | Datadog | datadog-transport or stdout → agent | | Generic | ELK Stack | stdout → Filebeat, or direct HTTP | | Docker/K8s | Any | stdout → container log driver |
Frontend logging has different constraints: logs are in the user's browser, sensitive data must never be exposed, and transport requires a reporting service.
// Error boundary (React example)
class ErrorBoundary extends React.Component {
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
errorReporter.captureError(error, {
componentStack: errorInfo.componentStack,
userId: getCurrentUserId(),
route: window.location.pathname,
});
}
}
// Global unhandled errors
window.addEventListener("unhandledrejection", (event) => {
errorReporter.captureError(event.reason, {
type: "unhandled_promise_rejection",
userId: getCurrentUserId(),
});
});
console.errorconsole.log before commit — debug logging in frontend code must not be committed| Service | Use case | | --------------- | ----------------------------------------------- | | Sentry | Error tracking with source maps and breadcrumbs | | CloudWatch RUM | AWS-native real user monitoring | | Datadog RUM | Full-stack observability | | Custom endpoint | POST errors to your own API → centralised logs |
Before applying these standards, load the project-specific logging implementation:
digraph lookup {
"docs/maverick/skills/logging/SKILL.md exists?" [shape=diamond];
"Read and use alongside these standards" [shape=box];
"Invoke upskill" [shape=box];
"Read generated skill" [shape=box];
"docs/maverick/skills/logging/SKILL.md exists?" -> "Read and use alongside these standards" [label="yes"];
"docs/maverick/skills/logging/SKILL.md exists?" -> "Invoke upskill" [label="no"];
"Invoke upskill" -> "Read generated skill";
"Read generated skill" -> "Read and use alongside these standards";
}
docs/maverick/skills/logging/SKILL.mdupskill skill with:
createLogger|getLogger|logger\.|console\.error|LOG_LEVEL|logging\.basicConfig**/logger.*, **/logging.*When reviewing code, flag these patterns:
| Pattern | Issue | Fix |
| -------------------------------------------------- | ----------------------------- | -------------------------------------------- |
| console.log(...) | Unstructured, not centralised | Replace with logger.debug(...) or remove |
| logger.info(...) | Creates noise | Evaluate: is it warn, error, or debug? |
| logger.error('Error') | No context | Add contextual metadata |
| catch (err) { logger.error(err) } then re-throws | Duplicate logging | Log at the boundary only |
| Logging PII/secrets | Security risk | Mask or remove |
| Different loggers in different files | Inconsistency | Use single logger module |
| try/catch that silently swallows | Lost errors | Log or re-throw |
development
Use when a best-practice skill needs project-specific implementation details and no project skill exists at docs/maverick/skills/<topic>/SKILL.md. Scans the codebase and generates a project-specific skill file.
testing
Create or update technical documentation for a project. Covers architecture, service interactions, data flows, and design decisions. Produces professional markdown with Mermaid diagrams.
development
How to process code review feedback — verify before implementing, push back when wrong, clarify before acting on partial understanding. Applied when receiving review from the code-reviewer agent or human reviewers.
development
Analyze a project's codebase against Maverick standard practices and write a findings report. Checks linting, unit tests, integration tests, documentation, and CI/CD. Run when onboarding an existing project or on demand.