一键导入
logging
Comprehensive logging standards for applications including structured logging, log levels, message formatting, and observability guidelines
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Comprehensive logging standards for applications including structured logging, log levels, message formatting, and observability guidelines
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Manage GitLab merge requests, issues, and pipelines from the command line using the glab CLI. Use when the user asks about GitLab MRs, issues, pipelines, labels, milestones, or needs to manage project work items via the command line.
Manage Bitbucket pull requests, issues, and repositories from the command line using the bkt CLI. Use when the user asks about Bitbucket PRs, issues, repos, pipelines, or needs to manage project work items via the command line.
Show ponytail's measured impact as a compact scoreboard: less code, less cost, more speed, from the benchmark medians. One-shot display, not a persistent mode, and not a per-repo number. Trigger: /ponytail-gain, "ponytail gain", "what does ponytail save", "show ponytail impact", "ponytail scoreboard".
Quick-reference card for all ponytail modes, skills, and commands. One-shot display, not a persistent mode. Trigger: /ponytail-help, "ponytail help", "what ponytail commands", "how do I use ponytail".
Use when about to claim work is complete, fixed, or passing, before committing or creating PRs - requires running verification commands and confirming output before making any success claims; evidence before assertions always
Build a compact mental model of recent project activity before any non-trivial task. Use proactively at the start of a session and before any investigation, planning, refactor, or multi-file change. Skip only for trivial fixes (typos, isolated docs, version bumps, mechanical refactors with a known target).
| name | logging |
| description | Comprehensive logging standards for applications including structured logging, log levels, message formatting, and observability guidelines |
Comprehensive logging guidelines for consistent, structured, and maintainable logging across the codebase.
All logs MUST be structured (JSON-serializable) for efficient querying and analysis.
Include relevant context (request ID, user ID, session ID) in every log.
Use correct log levels to enable effective filtering.
Avoid expensive operations in log statements.
| Level | When to Use | Examples |
|---|---|---|
| ERROR | Application errors requiring attention | Unhandled exceptions, failed critical operations |
| WARN | Unexpected but recoverable situations | Retry attempts, deprecated usage, rate limiting |
| INFO | Significant application events | Request handling, job completion, config changes |
| DEBUG | Detailed diagnostic information | Variable values, execution paths, timing |
| TRACE | Very detailed debugging | Loop iterations, method entry/exit |
REQUIRED: All log messages MUST follow this pattern:
[SERVICE_OR_CLASS]: MESSAGE
The prefix should be the actual class name or service name enclosed in square brackets.
import { logger } from "./logger";
// ✅ GOOD - Structured with context
logger.info("[UserService]: User created", {
userId: user.id,
email: user.email,
source: "registration",
});
// ✅ GOOD - Error with stack trace
logger.error("[PaymentService]: Payment processing failed", {
error: err.message,
stack: err.stack,
orderId: order.id,
amount: order.total,
});
// ❌ BAD - String interpolation loses structure
logger.info(`User ${userId} created with email ${email}`);
// ❌ BAD - Missing context
logger.error("Payment failed");
import structlog
logger = structlog.get_logger()
# ✅ GOOD - Structured with context
logger.info("[UserService]: User created",
user_id=user.id,
email=user.email,
source="registration"
)
# ✅ GOOD - Error with exception
logger.error("[PaymentService]: Payment processing failed",
error=str(e),
order_id=order.id,
amount=order.total,
exc_info=True
)
# ❌ BAD - f-string loses structure
logger.info(f"User {user_id} created with email {email}")
// ✅ GOOD - Structured logging with named parameters
_logger.LogInformation("[UserService]: User created - UserId: {UserId}, Email: {Email}",
user.Id, user.Email);
// ✅ GOOD - Error with exception
_logger.LogError(ex, "[PaymentService]: Payment failed - OrderId: {OrderId}, Amount: {Amount}",
order.Id, order.Total);
// ❌ BAD - String interpolation
_logger.LogInformation($"User {userId} created with email {email}");
// ✅ GOOD - Structured with context
logger.Info("[UserService]: User created",
zap.String("userId", user.ID),
zap.String("email", user.Email),
zap.String("source", "registration"),
)
// ✅ GOOD - Error with stack
logger.Error("[PaymentService]: Payment failed",
zap.Error(err),
zap.String("orderId", order.ID),
zap.Float64("amount", order.Total),
)
// ❌ BAD - Printf style
logger.Info(fmt.Sprintf("User %s created", userId))
Always include request-scoped identifiers:
// Middleware sets context
const requestContext = {
requestId: req.headers["x-request-id"] || uuid(),
userId: req.user?.id,
sessionId: req.session?.id,
traceId: req.headers["x-trace-id"],
};
// All logs in request include context
logger.info("[OrderController]: Order submitted", {
...requestContext,
orderId: order.id,
itemCount: order.items.length,
});
For async operations, propagate correlation:
async function processOrder(order: Order, correlationId: string) {
logger.info("[OrderProcessor]: Starting order processing", {
correlationId,
orderId: order.id,
});
// Pass to downstream services
await inventoryService.reserve(order.items, { correlationId });
await paymentService.charge(order.total, { correlationId });
logger.info("[OrderProcessor]: Order processing complete", {
correlationId,
orderId: order.id,
duration: Date.now() - startTime,
});
}
const startTime = performance.now();
await expensiveOperation();
const duration = performance.now() - startTime;
logger.info("[DataProcessor]: Operation completed", {
operationType: "batch-import",
recordCount: records.length,
durationMs: Math.round(duration),
recordsPerSecond: Math.round(records.length / (duration / 1000)),
});
// Avoid expensive serialization unless needed
if (logger.isDebugEnabled()) {
logger.debug("[CacheService]: Cache contents", {
keys: cache.keys(),
size: cache.size,
hitRate: cache.stats.hitRate,
});
}
try {
await processPayment(order);
} catch (error) {
logger.error("[PaymentService]: Payment processing failed", {
error: error.message,
stack: error.stack,
errorCode: error.code,
// Business context
orderId: order.id,
userId: order.userId,
amount: order.total,
paymentMethod: order.paymentMethod,
// Request context
requestId: context.requestId,
// Recovery info
retryable: isRetryableError(error),
attemptNumber: attempt,
});
throw error;
}
// Tag errors for monitoring/alerting
logger.error("[AuthService]: Authentication failed", {
errorCategory: "SECURITY",
errorType: "INVALID_CREDENTIALS",
userId: attemptedUserId,
ipAddress: request.ip,
userAgent: request.headers["user-agent"],
});
const maskEmail = (email: string) => {
const [local, domain] = email.split("@");
return `${local.slice(0, 2)}***@${domain}`;
};
const maskCardNumber = (card: string) => {
return `****-****-****-${card.slice(-4)}`;
};
logger.info("[PaymentService]: Payment authorized", {
email: maskEmail(user.email), // "jo***@example.com"
cardNumber: maskCardNumber(card), // "****-****-****-1234"
amount: order.total,
});
// TypeScript
logger.info("[OrderController]: Received order submission", {
userId: user.id,
itemCount: order.items.length,
correlationId: req.headers["x-request-id"],
});
logger.warn("[OrderController]: Validation failed", {
userId: user.id,
errors: validationErrors,
});
// C#
_logger.LogInformation("[OrderController]: Received order submission - UserId: {UserId}, ItemCount: {ItemCount}",
user.Id, order.Items.Count);
_logger.LogWarning("[OrderController]: Validation failed - UserId: {UserId}, Errors: {Errors}",
user.Id, validationErrors);
// TypeScript
logger.info("[OrderService]: Processing order", {
orderId: order.id,
userId: order.userId,
total: order.total,
});
logger.error(ex, "[NotificationService]: Failed to send notification", {
userId: user.id,
notificationType: "order-confirmation",
error: err.message,
});
# Python
logger.info("[OrderService]: Processing order",
order_id=order.id,
user_id=order.user_id,
total=order.total,
)
logger.error("[NotificationService]: Failed to send notification",
user_id=user.id,
notification_type="order-confirmation",
error=str(e),
exc_info=True,
)
logger.info("[EmailJobService]: Starting scheduled email job");
logger.warn("[EmailJobService]: No emails scheduled for processing");
logger.info("[EmailJobService]: Job completed", {
emailsSent: sentCount,
duration: Date.now() - startTime,
});
// Bad - not specific enough
logger.info("[Service]: Operation completed");
// Good - identifies exact service
logger.info("[OrderService]: Order processing completed", {
orderId: order.id,
});
// Bad - uses technology name instead of class name
logger.debug("REDIS: Cache hit for key " + key);
// Good - uses actual class name
logger.debug("[CacheService]: Cache hit", { key, ttl });
// Bad - logs sensitive information
logger.info("[AuthService]: User logged in", {
password: password,
token: jwtToken,
});
// Good - logs only non-sensitive identifiers
logger.info("[AuthService]: User logged in", {
userId: user.id,
sessionId: session.id,
});
// Bad - loses structured logging
logger.info(`User ${userId} performed action ${action}`);
// Good - uses structured logging
logger.info("[Service]: User performed action", {
userId,
action,
});
// Bad - can flood logs
for (const item of largeCollection) {
logger.debug("[Service]: Processing item", { itemId: item.id });
}
// Good - log summary instead
logger.info("[Service]: Processing batch", {
itemCount: largeCollection.length,
});
// Log only errors or specific cases
// Bad - vague
logger.error("[Service]: Error occurred");
// Good - specific and actionable
logger.error("[PaymentService]: Failed to process payment", {
orderId: order.id,
userId: order.userId,
amount: order.total,
paymentMethod: order.paymentMethod,
error: err.message,
});
// Preferred
logger.info("[Service]: Processing request");
logger.info("[Service]: Request processed successfully");
// Not preferred
logger.info("[Service]: Will process request");
logger.warn("[CacheService]: Cache miss", {
key: cacheKey,
expectedType: "user-profile",
fallbackUsed: true,
});
# .env
LOG_LEVEL=info # Minimum log level
LOG_FORMAT=json # json | pretty
LOG_DESTINATION=stdout # stdout | file | service
LOG_SERVICE_URL= # External logging service URL
import { trace, context } from "@opentelemetry/api";
function logWithTrace(level: string, message: string, data: object) {
const span = trace.getSpan(context.active());
const traceContext = span
? {
traceId: span.spanContext().traceId,
spanId: span.spanContext().spanId,
}
: {};
logger[level](message, { ...data, ...traceContext });
}
When writing unit tests, verify logging behavior:
// TypeScript/Jest
expect(logger.info).toHaveBeenCalledWith(
expect.stringContaining("[OrderService]"),
expect.objectContaining({ orderId: "123" })
);
// C# / .NET
_mockLogger.Verify(
x => x.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>((o, t) => o.ToString().Contains("[OrderService]")),
null,
It.IsAny<Func<It.IsAnyType, Exception, string>>()),
Times.Once);
Is it an error that needs attention? → ERROR
Is it unexpected but handled? → WARN
Is it a significant business event? → INFO
Is it helpful for debugging? → DEBUG
Is it very detailed/verbose? → TRACE
.agents/skills/systematic-debugging/ for debugging workflows.agents/skills/verification-before-completion/ for testing logs