Lambda如何实现多行日志记录 -> CloudWatch

14
我的多行日志事件最终都变成了多个事件 - 每行一个事件。根据文档

每次调用 LambdaLogger.log() 都会产生 CloudWatch Logs 事件...

但是:

但请注意,AWS Lambda 将 System.out 和 System.err 返回的每一行视为单独的事件。

查看LambdaAppender 的源代码,它似乎仍然将事件记录到 System.out 中。那么这是否意味着多行消息总是会被分解为多个事件?
我已经了解了如何配置multi_line_start_pattern,但它似乎只适用于您部署日志代理时,而在Lambda中不可用。
[编辑] LambdaAppender 记录到 LambdaLogger ,该对象记录到 System.out
[编辑] 我发现一些帖子提出了解决方法 - 在打印消息时使用 '\r' 作为行末。这似乎适用于我的代码生成的消息。但在各个地方记录的堆栈跟踪仍然是一个问题。
[编辑] 我已经使用了两个解决方法:
  1. Log complex data structures (e.g. sizable maps) in JSON. CloudWatch actually recognizes JSON strings in log events, and pretty print them.
  2. Replace '\n' with '\r'. For stack traces I created a utility method (this is in Kotlin, but the idea is generic enough):

    fun formatThrowable(t: Throwable): String {
        val buffer = StringWriter()
        t.printStackTrace(PrintWriter(buffer))
        return buffer.toString().replace("\n", "\r")
    }
    

我认为从长远来看,更理想的解决方案是实现一个Appender,它可以装饰ConsoleAppender,并在所有通过的消息上执行\r替换。


你在哪里看到它写入 System.out?因为我看到它写入了一个 LambdaLogger 实例,这是非分布式 AWS 运行时代码的一部分。 - kdgregory
如果我理解正确的话,LambdaLogger 的源代码实际上在同一个项目中:https://github.com/aws/aws-lambda-java-libs/blob/master/aws-lambda-java-core/src/main/java/com/amazonaws/services/lambda/runtime/LambdaRuntime.java。 - jingx
你肯定是正确的 - 在评论之前,我没有花时间查看存储库中的其他项目。但是,我知道(或者至少相信)我在与主要消息相同的CloudWatch事件中看到了一个异常日志记录。这让我想知道System.out是否是一种AWS特定的PrintStream,它基于写入而不是换行符进行刷新。这完全是我猜测的,但可以通过以下方式轻松验证:(1)使用Class.getName()和(2)打印包含换行符的字符串。 - kdgregory
2个回答

3
最佳实践是在日志中使用JSON。不要发送多行输出,而是发送格式化的JSON(无论您使用的语言是什么,您都会发现已经有一个库可以为您执行此操作)。您会惊讶地发现从那里浏览日志变得非常容易。例如,aws cloudwatch insights自动检测您的字段,允许在几秒钟内对其进行解析和查询。

1
我建议使用项目slf4j-simple-lambda,并参考此博客以获取更多解释。
使用slf4j和slf4j-simple-lambda优雅地解决了您的问题,并且解决方案很轻量级。该项目包括使用参数org.slf4j.simpleLogger.newlineMethod,该参数用于解决此问题。默认情况下,它的值为auto,应能自动检测需要手动换行处理的情况。
披露:我是slf4j-simple-lambda的合著者和该博客的作者。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接