AWS Lambda
开发人员指南
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

Java 中的 AWS Lambda 函数日志记录

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

适用于 Log4j™ 2 的自定义 Appender

AWS Lambda 推荐使用 Log4j 2 来提供自定义 Appender。您可使用由 Lambda 提供的自定义 Log4j(请参阅 Apache log4j)Appender 从您的 Lambda 函数记录日志。每个对 Log4j 方法的调用(如 log.info()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 Logs 限制。有关示例,请参阅示例 2:使用 LambdaLogger (Java) 编写日志

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

  • System.out()

  • System.err()

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

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:

      <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 插件,请如下设置插件配置:

      <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:

      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"); 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 文件来加载属性

      <?xml version="1.0" encoding="UTF-8"?> <Configuration packages="com.amazonaws.services.lambda.runtime.log4j2"> <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="info"> <AppenderRef ref="Lambda" /> </Root> </Loggers> </Configuration>

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

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

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 函数。处理程序代码接收示例事件但不对其执行任何操作。它只演示如何写入日志。

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

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

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