AWS Lambda
开发人员指南
AWS 服务或AWS文档中描述的功能,可能因地区/位置而异。点 击 Getting Started with Amazon AWS to see specific differences applicable to the China (Beijing) Region.

日志记录 (Java)

您的 Lambda 函数可包含日志记录语句。AWS Lambda 将这些日志写入 CloudWatch。我们建议您使用以下一种方法写入日志。

适用于 Log4j™ 2 的自定义 Appender

AWS Lambda 推荐使用 Log4j 2 来提供自定义 Appender。您可使用由 Lambda 提供的自定义 Log4j(请参阅 Apache log4j)Appender 从您的 Lambda 函数记录日志。每个对 Log4j 方法的调用(如 log.debug()log.error())都将生成一个 CloudWatch Logs 事件。自定义 Appender 称为 LambdaAppender 并且必须在 log4j2.xml 文件中使用。您必须在部署程序包(.jar 文件)中包含 aws-lambda-java-log4j2 工件 (artifactId:aws-lambda-java-log4j2)。有关示例,请参阅示例 1:使用 Log4J v2.8 编写日志

LambdaLogger.log()

每次调用 LambdaLogger.log() 都会得到一个 CloudWatch Logs 事件,假设事件大小在允许的限制内。有关 CloudWatch Logs 限制的信息,请参阅 Amazon CloudWatch 用户指南 中的 CloudWatch 日志限制。有关示例,请参阅示例 2:使用 LambdaLogger (Java) 编写日志

此外,您还可以在您的 Lambda 函数代码中使用以下语句来生成日志条目:

  • System.out()

  • System.err()

但请注意,AWS Lambda 将 System.outSystem.err 返回的每一行都视为独立的事件。要使输出行与日志条目一一对应时,使用该对象会很方便。当日志条目有多行输出时,AWS Lambda 会尝试使用换行符分析它们,以识别独立的事件。例如,下面的语句将两个词(“Hello”和“world”)记录为两个独立事件:

Copy
System.out.println("Hello \n world");

如何查找日志

可以通过以下方式找到您的 Lambda 函数写入的日志:

  • 在 CloudWatch Logs 中查找日志。context 对象(在 aws-lambda-java-core 库中)提供了 getLogStreamName()getLogGroupName() 方法。借助这些方法,您可以找到日志写入到了哪个特定日志流中。

  • 如果通过控制台调用 Lambda 函数,则调用类型始终为 RequestResponse(即同步执行),控制台将显示 Lambda 函数使用 LambdaLogger 对象写入的日志。AWS Lambda 还返回来自 System.outSystem.err 方法的日志。

  • 通过编程方法调用 Lambda 函数时,可以添加 LogType 参数以检索写入到 CloudWatch Logs 的最后 4 KB 日志数据。有关更多信息,请参阅 Invoke。AWS Lambda 在响应的 x-amz-log-results 头中返回该日志信息。使用 AWS Command Line Interface 调用函数时,可以为 --log-type 参数指定值 Tail

日志记录示例 (Java)

本节提供适用于 Log4j 的自定义 Appender 和用于记录信息的 LambdaLogger 对象的使用示例。

示例 1:使用 Log4J v2.8 编写日志

  • 下面显示了如何使用 Maven 构建项目以正确包含 Log4j v2.8 插件:

    • 对于 Maven pom.xml:

      Copy
      <dependencies> ... <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-lambda-java-log4j2</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.8.2</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.8.2</version> </dependency> .... </dependencies>
    • 如果使用 Maven shade 插件,请如下设置插件配置:

      Copy
      <plugins> ... <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>2.4.3</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="com.github.edwgiz.mavenShadePlugin.log4j2CacheTransformer.PluginsCacheFileTransformer"> </transformer> </transformers> </configuration> </execution> </executions> <dependencies> <dependency> <groupId>com.github.edwgiz</groupId> <artifactId>maven-shade-plugin.log4j2-cachefile-transformer</artifactId> <version>2.8.1</version> </dependency> </dependencies> </plugin> ... </plugins>
    • 以下 Java 代码示例说明了如何对 Lambda 使用 Log4j:

      Copy
      package example; import com.amazonaws.services.lambda.runtime.Context; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class Hello { // Initialize the Log4j logger. static final Logger logger = LogManager.getLogger(Hello.class); public String myHandler(String name, Context context) { // System.out: One log statement but with a line break (AWS Lambda writes two events to CloudWatch). System.out.println("log data from stdout \n this is continuation of system.out"); // System.err: One log statement but with a line break (AWS Lambda writes two events to CloudWatch). System.err.println("log data from stderr. \n this is a continuation of system.err"); // Use log4j to log the same thing as above and AWS Lambda will log only one event in CloudWatch. logger.debug("log data from log4j debug \n this is continuation of log4j debug"); logger.error("log data from log4j err. \n this is a continuation of log4j.err"); // Return will include the log stream name so you can look // up the log later. return String.format("Hello %s. log stream = %s", name, context.getLogStreamName()); } }
    • 前面的示例使用以下 log4j2.xml 文件来加载属性

      Copy
      <?xml version="1.0" encoding="UTF-8"?> <Configuration packages="com.amazonaws.services.lambda.runtime.log4j2.LambdaAppender"> <Appenders> <Lambda name="Lambda"> <PatternLayout> <pattern>%d{yyyy-MM-dd HH:mm:ss} %X{AWSRequestId} %-5p %c{1}:%L - %m%n</pattern> </PatternLayout> </Lambda> </Appenders> <Loggers> <Root level="debug"> <AppenderRef ref="Lambda" /> </Root> </Loggers> </Configuration>

示例 2:使用 LambdaLogger (Java) 编写日志

以下 Java 代码示例使用 System 方法和 LambdaLogger 对象编写日志,说明它们在 AWS Lambda 将日志信息记录到 CloudWatch 时的差异。

Copy
package example; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.LambdaLogger; public class Hello { public String myHandler(String name, Context context) { // System.out: One log statement but with a line break (AWS Lambda writes two events to CloudWatch). System.out.println("log data from stdout \n this is continuation of system.out"); // System.err: One log statement but with a line break (AWS Lambda writes two events to CloudWatch). System.err.println("log data from stderr \n this is continuation of system.err"); LambdaLogger logger = context.getLogger(); // Write log to CloudWatch using LambdaLogger. logger.log("log data from LambdaLogger \n this is continuation of logger.log"); // Return will include the log stream name so you can look // up the log later. return String.format("Hello %s. log stream = %s", name, context.getLogStreamName()); } }

下面是 CloudWatch Logs 中的日志条目示例。

注意:

  • 由于存在换行符,AWS Lambda 将每个 System.out.println()System.err.println() 语句日志记录中的日志字符串分析为两个独立事件(请注意屏幕截图中的两个向下箭头)。

  • LambdaLogger.log() 生成一个 CloudWatch 事件。

您可以执行以下操作来测试代码:

  • 使用这些代码创建部署程序包。

  • 将部署程序包上传到 AWS Lambda 以创建 Lambda 函数。

  • 使用字符串 ("this is a test") 作为示例事件来测试您的 Lambda 函数。处理程序代码接收示例事件但不对其执行任何操作。它只演示如何写入日志。

按照“入门”中提供的说明进行操作。有关更多信息,请参阅 步骤 2.3:(可选)创建用 Java 编写的 Lambda 函数。注意以下不同:

  • 创建部署程序包时,不要忘了 aws-lambda-java-core 库依赖项。

  • 在创建 Lambda 函数时,指定 example.Hello::myHandler (package.class::method) 作为处理程序值。