log-analysis — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited log-analysis (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Implement structured, queryable logging with proper levels and correlation IDs to enable fast diagnosis of production issues.
Always log structured data, not interpolated strings:
// BAD: Unstructured string logs
console.log(`User ${userId} failed to login from ${ip} with error: ${err.message}`);
// Hard to parse, search, and aggregate
// GOOD: Structured JSON logging
import pino from "pino";
const logger = pino({ level: "info" });
logger.error({
event: "login_failed",
userId,
ip,
error: err.message,
errorCode: err.code,
}, "User login failed");# Python structured logging
import structlog
logger = structlog.get_logger()
logger.error(
"login_failed",
user_id=user_id,
ip=ip,
error=str(err),
error_code=getattr(err, "code", None),
)// Go structured logging with slog
import "log/slog"
slog.Error("login failed",
"event", "login_failed",
"userId", userId,
"ip", ip,
"error", err.Error(),
)Use levels consistently across the entire application:
LEVEL WHEN TO USE EXAMPLE
----- ----------- -------
error Something failed, needs attention Database connection lost
Action: alert on-call, investigate Payment processing failed
warn Unexpected but handled, may need review Rate limit approaching
Action: review in daily triage Deprecated API called
info Normal but significant operations User registered
Action: none, useful for auditing Order completed
debug Detailed flow for development Cache hit/miss
Action: none, disabled in production SQL query executedconst logger = pino({ level: process.env.LOG_LEVEL || "info" });
// ERROR: Operation failed, requires investigation
logger.error({ orderId, error: err.message }, "Payment charge failed");
// WARN: Handled but notable
logger.warn({ userId, attempts: 4, max: 5 }, "Login attempt threshold approaching");
// INFO: Normal business events
logger.info({ orderId, total, itemCount }, "Order placed successfully");
// DEBUG: Development-time detail (disabled in production)
logger.debug({ query, params, durationMs: 12 }, "Database query executed");Assign a unique ID to each request and propagate it through all logs and service calls:
import { randomUUID } from "crypto";
import { AsyncLocalStorage } from "async_hooks";
const requestContext = new AsyncLocalStorage<{ correlationId: string }>();
// Middleware: assign correlation ID
function correlationMiddleware(req: Request, res: Response, next: NextFunction) {
const correlationId = req.headers["x-correlation-id"] as string || randomUUID();
res.setHeader("x-correlation-id", correlationId);
requestContext.run({ correlationId }, () => next());
}
// Logger: include correlation ID automatically
function getLogger() {
const ctx = requestContext.getStore();
return logger.child({ correlationId: ctx?.correlationId });
}
// Usage in any handler or service
function processOrder(order: Order) {
const log = getLogger();
log.info({ orderId: order.id }, "Processing order");
// All logs from this request share the same correlationId
}Output enables tracing a single request across services:
{"level":"info","correlationId":"abc-123","service":"api","msg":"Order received","orderId":"ord-1"}
{"level":"info","correlationId":"abc-123","service":"inventory","msg":"Stock reserved","orderId":"ord-1"}
{"level":"info","correlationId":"abc-123","service":"payment","msg":"Payment charged","orderId":"ord-1"}
{"level":"error","correlationId":"abc-123","service":"email","msg":"Notification failed","error":"SMTP timeout"}Add persistent context to every log entry from a scope:
// Child loggers for adding scope context
const serviceLogger = logger.child({ service: "order-service", version: "2.1.0" });
const requestLogger = serviceLogger.child({ correlationId, userId });
// All logs from this request include service, version, correlationId, userId
requestLogger.info({ orderId }, "Order created");# Python: bind context to logger
logger = structlog.get_logger()
log = logger.bind(service="order-service", correlation_id=correlation_id, user_id=user_id)
log.info("order_created", order_id=order_id)
# Output includes all bound context automatically# Search JSON logs with jq
# Find all errors for a specific correlation ID
cat app.log | jq 'select(.correlationId == "abc-123" and .level == "error")'
# Count errors by type in the last hour
cat app.log | jq 'select(.level == "error") | .event' | sort | uniq -c | sort -rn
# Find slow requests (> 1000ms)
cat app.log | jq 'select(.durationMs > 1000) | {path: .path, duration: .durationMs}'
# Trace a request across services
cat *.log | jq 'select(.correlationId == "abc-123")' | jq -s 'sort_by(.timestamp)'logger.info(\User ${id}\) defeats structured search. Use fields.error for non-errors or info for debug-level detail makes filtering useless.logger.error("Failed") — failed what? Add the operation, entity ID, and error.// BAD: Sensitive data in logs
logger.info({ password: user.password }, "User login");
// BAD: No context
logger.error("Something went wrong");
// BAD: Wrong level
logger.error("Cache miss for key: user:123"); // This is debug, not error
// GOOD: Masked sensitive data, full context, correct level
logger.info({ userId: user.id, email: maskEmail(user.email) }, "User login successful");
logger.error({ orderId, error: err.message, stack: err.stack }, "Payment processing failed");
logger.debug({ key: "user:123", hit: false }, "Cache lookup");Log Levels:
error Operation failed, needs attention
warn Unexpected but handled
info Normal significant events
debug Development detail
Structured Logging Checklist:
- JSON format, not string interpolation
- Consistent field names across services
- Correlation ID on every request
- Timestamps in ISO 8601 (UTC)
- Service name and version in every entry
- Error entries include message + stack
- No sensitive data (mask PII, tokens)
Libraries:
Node.js: pino, winston
Python: structlog, python-json-logger
Go: slog (stdlib), zap, zerolog
Java: SLF4J + Logback, Log4j2
Analysis:
jq Query JSON logs from the command line
grep -c Count occurrences
tail -f Follow log output in real time~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.