通过 Logback 记录到 App Engine request_log
Posted
技术标签:
【中文标题】通过 Logback 记录到 App Engine request_log【英文标题】:Logging to App Engine request_log through Logback 【发布时间】:2020-03-07 20:47:28 【问题描述】:我有一个使用 App Engine 标准环境 - Java 11 在 Ninja Framework 上构建的应用,使用 Ninja 附带的注入 Logger,即 Apache Logback .通常,这会记录到实例的stdout
,因此我的所有消息都以每条目一行的格式出现,并且在stdout
日志通道上,这在尝试跟踪生产中的错误时不太方便.
有一个关于使用 Logback [1] 登录到 Stackdriver 的 Google 文档指南,我已经尝试过,但没有效果:日志现在以 application.log
结尾,即仍然是一个单独的频道,request_log
频道是空的。
我尝试通过将projects/dive-site-overwatch/logs/appengine.googleapis.com%2Frequest_log
作为<log>
元素放在logback.xml
中来更改推荐的配置,这导致所有请求都失败,因为URL 编码的solidus 上的“无效格式”。相反,按原样添加solidus 会导致异常,因为它是非法字符。
我当前部署的 Logback 配置如下(你可以看出我的想法已经用完了......):
<configuration>
<statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />
<appender name = "STDOUT" class = "ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="tech.provingground.dive_overwatch.etc.logging.layouts.StackdriverLayout">
<pattern>%-4relative [%thread] %-5level %logger35 - %msg</pattern>
</layout>
</encoder>
</appender>
<appender name = "CLOUD" class = "com.google.cloud.logging.logback.LoggingAppender">
<log>application.log</log> <!-- Optional : default java.log -->
<flushLevel>WARN</flushLevel> <!-- Optional : default ERROR -->
<enhancer>tech.provingground.dive_overwatch.etc.logging.enhancers.TestEnhancer</enhancer>
<encoder>
<layout class="tech.provingground.dive_overwatch.etc.logging.layouts.StackdriverLayout">
<pattern>%-4relative [%thread] %-5level %logger35 - %msg</pattern>
</layout>
</encoder>
</appender>
<root level = "info">
<appender-ref ref = "CLOUD" />
<!-- <appender-ref ref = "STDOUT" />-->
</root>
</configuration>
查看应用程序的标准,我可以看到许多指向 Stackdriver 拒绝请求的日志:
java.lang.RuntimeException: java.util.concurrent.TimeoutException: Waited 6 seconds for com.google.common.util.concurrent.CollectionFuture$ListFuture@77fbc3ba[status=PENDING, info=[futures=[[com.google.api.core.ApiFutureToListenableFuture@772ddfb8, com.google.api.core.ApiFutureToListenableFuture@7d905614, com.google.api.core.ApiFutureToListenableFuture@7396512d, com.google.api.core.ApiFutureToListenableFuture@5ad9baf6]]]]
at com.google.cloud.logging.LoggingImpl.flush(LoggingImpl.java:581)
at com.google.cloud.logging.LoggingImpl.write(LoggingImpl.java:562)
at com.google.cloud.logging.logback.LoggingAppender.append(LoggingAppender.java:215)
at com.google.cloud.logging.logback.LoggingAppender.append(LoggingAppender.java:70)
at ch.qos.logback.core.UnsynchronizedAppenderBase.doAppend(UnsynchronizedAppenderBase.java:84)
[...]
如果是身份验证错误,我可以理解 403 或类似状态代码,但标准环境应该提供服务帐户,并自动授予 Logs Writer 角色。 p>
我有点难过。有没有办法让我的应用程序日志与我的其他请求日志在同一个位置,在常规的request_log
中?
[1]https://cloud.google.com/logging/docs/setup/java#logback_appender_for
【问题讨论】:
【参考方案1】:您应该查看这个example,它使用 logback 进行 JSON 日志记录!关键元素是它包含跟踪 ID,以便消息与请求日志相关。
来自样本:
// Build structured log messages as an object.
Object globalLogFields = null;
// Add log correlation to nest all log messages beneath request log in Log Viewer.
String traceHeader = req.headers("x-cloud-trace-context");
if (traceHeader != null && project != null)
String trace = traceHeader.split("/")[0];
globalLogFields =
kv(
"logging.googleapis.com/trace",
String.format("projects/%s/traces/%s", project, trace));
// Create a structured log entry using key value pairs.
logger.error(
"This is the default display field.",
kv("component", "arbitrary-property"),
kv("severity", "NOTICE"),
globalLogFields);
【讨论】:
这一步更接近我想要实现的目标,但它仍然没有将日志行与请求放在同一个条目中。即使我添加了StructuredArgument logNameField = kv("logging.googleapis.com/logName", String.format("projects/%s/logs/%s", project, "appengine.googleapis.com%2Frequest_log"));
之类的字段,它们仍然被放置在标准输出中。以上是关于通过 Logback 记录到 App Engine request_log的主要内容,如果未能解决你的问题,请参考以下文章
Java Syslog 仅使用 logback 记录到本地机器
如何将数据从 Android 移动设备发送到 Google App Engine 数据存储区?