mcpField
A
api-logging-guidelines

api-logging-guidelines

github.com/inkeep开发1.5k52 次安装4 天前更新
代码仓库

关于 api-logging-guidelines

这套指南介绍 API 路由的日志规范,涵盖日志级别、事件上下文、隐私和性能。它帮助开发者减少重复或例行日志,同时保留有用的错误与业务事件记录。

主要功能

  1. 01日志级别选择指南
  2. 02避免重复记录请求日志
  3. 03错误与业务事件模式
  4. 04敏感数据排除要求
  5. 05现有日志迁移检查清单

适用场景

  1. 01发布前审查 API 路由日志
  2. 02重构冗余或重复日志
  3. 03为错误和安全事件补充上下文

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/inkeep/agents --skill api-logging-guidelines

安装后在 Claude Code 中输入/api-logging-guidelines确认已加载。

详细介绍

API 路由日志记录指南

全面介绍如何在 API 路由中恰当地使用日志记录,以保持日志整洁、实用且高效。


核心原则

1. 避免重复记录日志

不要记录中间件已经记录的内容:

// ❌ BAD - Request details are already logged by middleware
logger.info({ tenantId, projectId }, 'Getting project details');

依赖请求中间件进行日志记录:

  • 请求/响应中间件已经记录:方法、路径、状态、耗时、路径参数
  • 这些日志包含 URL 路径中的租户/项目 ID
  • 添加重复日志只会增加噪声,没有价值
2. 日志级别指南
级别使用场景示例
ERROR需要关注的意外故障数据库连接失败、未处理的异常、关键服务错误
WARN可恢复的问题或值得关注的模式触发速率限制、使用已弃用的 API、启用回退行为
INFO重要的业务事件(不是常规操作)创建用户账户、处理付款、变更关键配置
DEBUG详细的诊断信息查询参数、中间计算结果、缓存命中/未命中详情
3. 应记录的内容

记录以下重要事件:

// ✅ GOOD - Important business event
logger.info({
  userId,
  oldPlan: 'free',
  newPlan: 'pro',
  mrr: 99
}, 'User upgraded subscription');

// ✅ GOOD - Error with context
logger.error({
  error,
  tenantId,
  webhookUrl,
  attemptNumber: 3
}, 'Webhook delivery failed after retries');

// ✅ GOOD - Security-relevant event
logger.warn({
  ip: c.req.header('x-forwarded-for'),
  userId,
  attemptedResource
}, 'Unauthorized access attempt');

// ✅ GOOD - Performance issue
logger.warn({
  duration: 5234,
  query,
  resultCount: 10000
}, 'Slow query detected');
4. 不应记录的内容

避免记录常规操作:

// ❌ BAD - Routine CRUD operation
logger.info('Getting user by ID');

// ❌ BAD - Already logged by middleware
logger.info(`Processing GET request to /api/users/${id}`);

// ❌ BAD - No actionable information
logger.info('Starting database query');

// ❌ BAD - Sensitive information
logger.info({ password, apiKey }, 'User login attempt');

// ❌ BAD - Overly granular
logger.debug('Entering function processUser');
logger.debug('Exiting function processUser');

API 路由模式

模式 1:错误处理
// ✅ GOOD - Log errors with context
export const route = router.get('/:id', async (c) => {
  try {
    const result = await riskyOperation();
    return c.json(result);
  } catch (error) {
    // Log error with relevant context
    logger.error({
      error,
      userId: c.get('userId'),
      operation: 'riskyOperation',
      // Include any relevant debugging context
      requestId: c.get('requestId')
    }, 'Operation failed');

    // Return generic error to client (don't leak internals)
    return c.json({ error: 'Internal server error' }, 500);
  }
});
模式 2:业务事件
// ✅ GOOD - Log significant business events
export const route = router.post('/subscription/upgrade', async (c) => {
  const { planId } = await c.req.json();

  const result = await upgradeSubscription(userId, planId);

  // This is worth logging - it's a significant business event
  logger.info({
    userId,
    oldPlan: result.previousPlan,
    newPlan: result.newPlan,
    mrr: result.mrr,
    timestamp: new Date().toISOString()
  }, 'Subscription upgraded');

  return c.json(result);
});
模式 3:性能监控
// ✅ GOOD - Log performance issues
export const route = router.get('/search', async (c) => {
  const start = Date.now();
  const results = await performSearch(query);
  const duration = Date.now() - start;

  // Only log if performance is concerning
  if (duration > 1000) {
    logger.warn({
      duration,
      query,
      resultCount: results.length,
      cached: false
    }, 'Slow search query');
  }

  return c.json(results);
});
模式 4:安全事件
// ✅ GOOD - Log security-relevant events
export const route = router.post('/api/admin/*', async (c) => {
  const hasPermission = await checkPermission(userId, resource);

  if (!hasPermission) {
    // Log unauthorized access attempts
    logger.warn({
      userId,
      resource,
      ip: c.req.header('x-forwarded-for'),
      userAgent: c.req.header('user-agent')
    }, 'Unauthorized access attempt');

    return c.json({ error: 'Forbidden' }, 403);
  }

  // Proceed with authorized request...
});

按环境划分的指南

开发环境
// More verbose logging acceptable in development
if (process.env.NODE_ENV === 'development') {
  logger.debug({ params, body }, 'Request details');
}
生产环境
  • 将 INFO 级别日志限制为仅记录重要事件
  • 切勿记录敏感数据(密码、令牌、密钥、个人身份信息)
  • 使用结构化日志,以便更好地搜索
  • 包含关联 ID,以便追踪请求

迁移策略

重构现有的冗余日志记录时:

  1. 识别重复日志:移除与中间件日志重复的日志
  2. 降低常规操作的日志级别:将常规操作的日志从 INFO 调整为 DEBUG
  3. 完善错误日志:为错误日志添加更多上下文
  4. 添加业务事件日志:确保记录重要的业务事件
  5. 检查日志级别:确保每条日志都使用恰当的级别
之前:
router.get('/:id', async (c) => {
  const { id } = c.req.param();
  logger.info({ id }, 'Getting item by ID');  // Redundant

  const item = await getItem(id);
  logger.info({ item }, 'Retrieved item');     // Too verbose

  return c.json(item);
});
之后:
router.get('/:id', async (c) => {
  const { id } = c.req.param();

  try {
    const item = await getItem(id);
    // No logging needed - routine successful operation
    return c.json(item);
  } catch (error) {
    // Only log errors
    logger.error({ error, id }, 'Failed to retrieve item');
    return c.json({ error: 'Item not found' }, 404);
  }
});

无需冗余日志的调试方式

不要使用冗余日志记录,而应采用以下策略:

  1. 有选择地启用调试模式:排查问题时,为特定模块启用 DEBUG 级别
  2. 使用追踪:使用 OpenTelemetry/Jaeger 进行分布式追踪
  3. 使用指标:使用 Prometheus/StatsD 获取性能指标
  4. 使用错误跟踪:使用 Sentry/Rollbar 汇总错误
  5. 使用功能标志:调试时为特定用户/请求启用冗余日志记录

总结检查清单

添加日志语句前,请先确认:

  • 中间件是否已经记录了这些内容?(方法、路径、状态、参数)
  • 这是重要的业务事件,还是常规操作?
  • 这条日志是否提供了可采取行动的信息?
  • 我使用的日志级别是否正确?
  • 我是否包含了有用的上下文,同时避免记录敏感数据?
  • 这条日志在生产环境中是否有用,还是只会造成噪声?

请记住:好的日志重在信号,而非数量。每条日志都应有其用途。

评论

支持 Markdown