首页 > web前端 > js教程 > 使用 Lambda 的 Powertools 缓冲日志并在出现错误时自动刷新

使用 Lambda 的 Powertools 缓冲日志并在出现错误时自动刷新

Susan Sarandon
发布: 2024-12-19 20:23:15
原创
256 人浏览过

Buffer Logs and Flush Automatically on Error with Powertools for Lambda

最新版本的 AWS Powertools for Lambda 让使用自定义功能扩展 Logger 变得更加轻松:

Logger 类现在更具可扩展性
您现在可以覆盖 Logger 方法 createAndPopulateLogItem、printLog 和 processLogItem,这些方法以前是私有的。这允许您扩展记录器并添加新功能,例如实现您自己的消息缓冲区。
发布 v2.12.0

我正在使用这个新的扩展性来实现一个有用的功能:日志缓冲和刷新。这个想法很简单:在生产环境中,我们通常只记录重要信息,例如警告和错误,因为日志空间可能会变得昂贵并且会产生噪音。但是,当发生错误时,我们希望获得所有可能的信息:分散在函数中的所有调试和信息日志都应该可用。但它们并不是因为我们将日志级别设置得太低。

缓冲和冲洗

如果我们在内部收集所有这些调试和信息日志,并且如果发生错误等重要事件,我们将它们打印到控制台怎么办?我把日志分为两类:低级日志和高级日志。如果我们配置的日志级别是 WARN,则 DEBUG 或 INFO 日志将是低级别日志,而 ERROR 将是高级日志。

现在,当我们打印低级日志时,我们不会像现在这样丢弃它,而是将日志缓冲在内部列表中。一旦我们有了高级日志,我们就会将所有缓冲的日志刷新到控制台。

执行

为了添加此功能,我们创建一个新类,该类从 Powertools 扩展 Logger 类并重写 processLogItem()。这是由不同的日志方法(如 logger.debug())调用的中心方法。如果日志项处于正确的级别,原始实现会将日志项打印到控制台。通过重写此方法,我们可以根据日志级别添加缓冲和刷新日志的特殊逻辑。

import { LogItem, Logger as PowertoolsLogger } from '@aws-lambda-powertools/logger';
import type { LogItemExtraInput, LogItemMessage } from '@aws-lambda-powertools/logger/types';

export class Logger extends PowertoolsLogger {
  #buffer: Record<string, Array<[number, string]>> = {};

  get buffer(): Record<string, Array<[number, string]>> {
    return this.#buffer;
  }

  protected override processLogItem(logLevel: number, input: LogItemMessage, extraInput: LogItemExtraInput): void {
    const xRayTraceId = this['envVarsService'].getXrayTraceId() as string;

    // Flush buffer when log level is higher than the configured log level
    if (logLevel > this.level && xRayTraceId) {
      const buffer = this.#buffer[xRayTraceId] ?? [];

      // Print all log items in the buffer
      if (buffer.length) this.info(`Flushing buffer with ${buffer.length} log items`);

      for (const [bufferLogLevel, bufferLogItem] of buffer) {
        // Create a new LogItem from the stringified log item
        this.printLog(bufferLogLevel, new LogItem(JSON.parse(bufferLogItem)));
      }

      // Clear the buffer after flushing
      // This also removes entries from other X-Ray trace IDs
      this.#buffer = {};
    }

    // Buffer the log item when log level is lower than the configured log level
    if (logLevel < this.level && xRayTraceId) {
      const buffer = this.#buffer[xRayTraceId] ?? [];
      // Add the stringified log item to the buffer
      // Serializing the log item ensures it is not mutated after being added to the buffer
      buffer.push([logLevel, JSON.stringify(this.createAndPopulateLogItem(logLevel, input, extraInput))]);

      // Update the buffer with the new log item
      // This also removes other X-Ray trace IDs from the buffer
      this.#buffer = {
        [xRayTraceId]: buffer,
      };
    }

    // Call the parent method to ensure the log item is processed
    super.processLogItem(logLevel, input, extraInput);
  }
}
登录后复制
登录后复制

您可能会问为什么我们在这里使用 X 射线追踪 ID。在处理程序函数之外实例化 Logger 是很常见的。但是,由于 Lambda 执行环境可能会重复用于多次调用,因此缓冲区可能包含先前调用的日志项。这就是缓冲区被实现为对象而不是简单数组的原因。我们使用 X-Ray Trace ID 作为标识符,仅缓冲来自同一调用的日志项。
缓冲区被实现为一个对象而不是一个简单的数组。当缓冲区被刷新时,我们可以简单地重置对象,从而从其他调用中清除项目。

本地测试

让我们快速在本地验证一下实现:

// set X-Ray Trace ID manually if running locally
process.env._X_AMZN_TRACE_ID = '1-abcdef12-3456abcdef123456abcdef12';

// log level = WARN
const logger = new Logger({ logLevel: 'WARN' });

logger.debug('debug'); // < log level
logger.info('info');   // < log level
logger.warn('warn');   // = log level
logger.error('error'); // > log level
登录后复制

这是我们得到的输出:

import { LogItem, Logger as PowertoolsLogger } from '@aws-lambda-powertools/logger';
import type { LogItemExtraInput, LogItemMessage } from '@aws-lambda-powertools/logger/types';

export class Logger extends PowertoolsLogger {
  #buffer: Record<string, Array<[number, string]>> = {};

  get buffer(): Record<string, Array<[number, string]>> {
    return this.#buffer;
  }

  protected override processLogItem(logLevel: number, input: LogItemMessage, extraInput: LogItemExtraInput): void {
    const xRayTraceId = this['envVarsService'].getXrayTraceId() as string;

    // Flush buffer when log level is higher than the configured log level
    if (logLevel > this.level && xRayTraceId) {
      const buffer = this.#buffer[xRayTraceId] ?? [];

      // Print all log items in the buffer
      if (buffer.length) this.info(`Flushing buffer with ${buffer.length} log items`);

      for (const [bufferLogLevel, bufferLogItem] of buffer) {
        // Create a new LogItem from the stringified log item
        this.printLog(bufferLogLevel, new LogItem(JSON.parse(bufferLogItem)));
      }

      // Clear the buffer after flushing
      // This also removes entries from other X-Ray trace IDs
      this.#buffer = {};
    }

    // Buffer the log item when log level is lower than the configured log level
    if (logLevel < this.level && xRayTraceId) {
      const buffer = this.#buffer[xRayTraceId] ?? [];
      // Add the stringified log item to the buffer
      // Serializing the log item ensures it is not mutated after being added to the buffer
      buffer.push([logLevel, JSON.stringify(this.createAndPopulateLogItem(logLevel, input, extraInput))]);

      // Update the buffer with the new log item
      // This also removes other X-Ray trace IDs from the buffer
      this.#buffer = {
        [xRayTraceId]: buffer,
      };
    }

    // Call the parent method to ensure the log item is processed
    super.processLogItem(logLevel, input, extraInput);
  }
}
登录后复制
登录后复制

警告是第一条消息,因为调试和信息日志已被缓冲。当错误被记录时,我们在实际打印错误之前刷新了缓冲的日志(并打印了信息)。

征求意见

我的幼稚实现有一些警告。最重要的是,缓冲区大小不受限制,这意味着如果缓冲区增长太大,可能会导致内存问题。有几种方法可以缓解此问题,例如,将缓冲区实现为滑动窗口,仅保留最新日志或限制总缓冲区大小。

此外,缓冲日志仅在受控情况下刷新,例如在 logger.error() 上,但在未处理的错误上不会刷新。如果我们将缓冲区公开并使用像 Middy.js 这样的中间件,则可以轻松实现此行为。 Middy 公开了一个 onError 事件,我们可以利用该事件来刷新缓冲区。

我在官方 AWS Powertools for Lambda 存储库的评论请求中更详细地介绍了这一点。

如果您希望看到此功能成为 Powertools for Lambda 的一部分,请在那里分享您的想法和反馈?

以上是使用 Lambda 的 Powertools 缓冲日志并在出现错误时自动刷新的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板