logging-best-practices

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Logging Best Practices Skill

日志记录最佳实践指南

Version: 1.0.0
版本: 1.0.0

Purpose

目的

This skill provides guidelines for implementing effective logging in applications. It focuses on wide events (also called canonical log lines) - a pattern where you emit a single, context-rich event per request per service, enabling powerful debugging and analytics.
本指南为应用程序中实现高效日志记录提供准则,重点关注宽事件(Wide Events)(也称为标准日志行(Canonical Log Lines))——即在每个服务的每个请求中输出单个、上下文丰富的事件,从而实现强大的调试与分析功能。

When to Apply

适用场景

Apply these guidelines when:
  • Writing or reviewing logging code
  • Adding console.log, logger.info, or similar
  • Designing logging strategy for new services
  • Setting up logging infrastructure
在以下场景中应用这些准则:
  • 编写或审核日志记录代码时
  • 添加console.log、logger.info或类似日志语句时
  • 为新服务设计日志记录策略时
  • 搭建日志记录基础设施时

Core Principles

核心原则

1. Wide Events (CRITICAL)

1. 宽事件(至关重要)

Emit one context-rich event per request per service. Instead of scattering log lines throughout your handler, consolidate everything into a single structured event emitted at request completion.
typescript
const wideEvent: Record<string, unknown> = {
  method: 'POST',
  path: '/checkout',
  requestId: c.get('requestId'),
  timestamp: new Date().toISOString(),
};

try {
  const user = await getUser(c.get('userId'));
  wideEvent.user = { id: user.id, subscription: user.subscription };

  const cart = await getCart(user.id);
  wideEvent.cart = { total_cents: cart.total, item_count: cart.items.length };

  wideEvent.status_code = 200;
  wideEvent.outcome = 'success';
  return c.json({ success: true });
} catch (error) {
  wideEvent.status_code = 500;
  wideEvent.outcome = 'error';
  wideEvent.error = { message: error.message, type: error.name };
  throw error;
} finally {
  wideEvent.duration_ms = Date.now() - startTime;
  logger.info(wideEvent);
}
在每个服务的每个请求中输出单个上下文丰富的事件。不要在处理程序中分散日志语句,而是将所有信息整合为单个结构化事件,在请求完成时输出。
typescript
const wideEvent: Record<string, unknown> = {
  method: 'POST',
  path: '/checkout',
  requestId: c.get('requestId'),
  timestamp: new Date().toISOString(),
};

try {
  const user = await getUser(c.get('userId'));
  wideEvent.user = { id: user.id, subscription: user.subscription };

  const cart = await getCart(user.id);
  wideEvent.cart = { total_cents: cart.total, item_count: cart.items.length };

  wideEvent.status_code = 200;
  wideEvent.outcome = 'success';
  return c.json({ success: true });
} catch (error) {
  wideEvent.status_code = 500;
  wideEvent.outcome = 'error';
  wideEvent.error = { message: error.message, type: error.name };
  throw error;
} finally {
  wideEvent.duration_ms = Date.now() - startTime;
  logger.info(wideEvent);
}

2. High Cardinality & Dimensionality (CRITICAL)

2. 高基数与高维度(至关重要)

Include fields with high cardinality (user IDs, request IDs - millions of unique values) and high dimensionality (many fields per event). This enables querying by specific users and answering questions you haven't anticipated yet.
包含高基数字段(用户ID、请求ID——数百万个唯一值)和高维度字段(每个事件包含多个字段)。这支持按特定用户查询,并解答你未曾预料到的问题。

3. Business Context (CRITICAL)

3. 业务上下文(至关重要)

Always include business context: user subscription tier, cart value, feature flags, account age. The goal is to know "a premium customer couldn't complete a $2,499 purchase" not just "checkout failed."
始终包含业务上下文:用户订阅层级、购物车价值、功能标志、账户时长。目标是了解“一位高级客户无法完成2499美元的购买”,而不仅仅是“结账失败”。

4. Environment Characteristics (CRITICAL)

4. 环境特征(至关重要)

Include environment and deployment info in every event: commit hash, service version, region, instance ID. This enables correlating issues with deployments and identifying region-specific problems.
在每个事件中包含环境与部署信息:提交哈希、服务版本、区域、实例ID。这支持将问题与部署关联起来,并识别特定区域的问题。

5. Single Logger (HIGH)

5. 单一日志实例(重要)

Use one logger instance configured at startup and import it everywhere. This ensures consistent formatting and automatic environment context.
使用一个在启动时配置好的日志实例,并在所有地方导入它。这确保格式一致,并自动包含环境上下文。

6. Middleware Pattern (HIGH)

6. 中间件模式(重要)

Use middleware to handle wide event infrastructure (timing, status, environment, emission). Handlers should only add business context.
使用中间件处理宽事件的基础设施(计时、状态、环境、输出)。处理程序只需添加业务上下文即可。

7. Structure & Consistency (HIGH)

7. 结构与一致性(重要)

  • Use JSON format consistently
  • Maintain consistent field names across services
  • Simplify to two log levels:
    info
    and
    error
  • Never log unstructured strings
  • 始终使用JSON格式
  • 在所有服务中保持一致的字段名称
  • 简化为两个日志级别:
    info
    error
  • 绝不记录非结构化字符串

Anti-Patterns to Avoid

需避免的反模式

  1. Scattered logs: Multiple console.log() calls per request
  2. Multiple loggers: Different logger instances in different files
  3. Missing environment context: No commit hash or deployment info
  4. Missing business context: Logging technical details without user/business data
  5. Unstructured strings:
    console.log('something happened')
    instead of structured data
  6. Inconsistent schemas: Different field names across services
  1. 分散日志:每个请求包含多个console.log()调用
  2. 多日志实例:不同文件中使用不同的日志实例
  3. 缺失环境上下文:无提交哈希或部署信息
  4. 缺失业务上下文:仅记录技术细节,无用户/业务数据
  5. 非结构化字符串:使用
    console.log('something happened')
    而非结构化数据
  6. 不一致的Schema:不同服务中使用不同的字段名称

Guidelines

准则

Wide Events (
rules/wide-events.md
)

宽事件(
rules/wide-events.md

  • Emit one wide event per service hop
  • Include all relevant context
  • Connect events with request ID
  • Emit at request completion in finally block
  • 每个服务跳转输出一个宽事件
  • 包含所有相关上下文
  • 使用请求ID关联事件
  • 在finally块中于请求完成时输出

Context (
rules/context.md
)

上下文(
rules/context.md

  • Support high cardinality fields (user_id, request_id)
  • Include high dimensionality (many fields)
  • Always include business context
  • Always include environment characteristics (commit_hash, version, region)
  • 支持高基数字段(user_id、request_id)
  • 包含高维度信息(多个字段)
  • 始终包含业务上下文
  • 始终包含环境特征(commit_hash、version、region)

Structure (
rules/structure.md
)

结构(
rules/structure.md

  • Use a single logger throughout the codebase
  • Use middleware for consistent wide events
  • Use JSON format
  • Maintain consistent schema
  • Simplify to info and error levels
  • Never log unstructured strings
  • 在整个代码库中使用单一日志实例
  • 使用中间件实现一致的宽事件
  • 使用JSON格式
  • 保持一致的Schema
  • 简化为info和error级别
  • 绝不记录非结构化字符串

Common Pitfalls (
rules/pitfalls.md
)

常见陷阱(
rules/pitfalls.md

  • Avoid multiple log lines per request
  • Design for unknown unknowns
  • Always propagate request IDs across services
References:
  • 避免每个请求包含多个日志行
  • 为未知的未知情况设计
  • 始终跨服务传播请求ID
参考资料: