使用 ELK 堆栈进行应用程序日志记录
Posted
技术标签:
【中文标题】使用 ELK 堆栈进行应用程序日志记录【英文标题】:Application logging with ELK stack 【发布时间】:2017-04-09 23:35:34 【问题描述】:使用 NLog 和 Elasticsearch target 将日志转发到 AWS Elasticsearch as a Service 集群,以便在 Kibana 中进行可视化。
这工作正常,但由于 ES 集群可用性和集群故障转移的影响,当日志通过 HTTP 使用 elasticsearch-net client 发送时,我担心在生产中使用它。
我正在考虑为 NLog 使用不同的目标,将日志发送到更可靠的目的地(文件、S3?),然后让其他东西(Logstash、AWS Lambda)接收它们并将它们发送到 ES,这样可以最大限度地减少应用程序本身的风险。
想听听你的想法
更新
主要关注的是应用可用性,并使用辅助目标来防止丢失日志。
Using latest NLog 和 throwExceptions 设置为 false,此时不使用异步目标,但考虑到这一点,因为我们有很多异步代码。
为了提供更多上下文,“应用程序”是一组 API(WebAPI 和 WCF),它们的转速为 10 - 15K RPM。
场景
请求进来,ES集群不可用。
案例 1 - 没有异步目标的 NLog
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
autoReload="true"
throwExceptions="false"
internalLogLevel="Off"
internalLogFile="c:\temp\nlog-internal.log">
<targets>
<target name="elastic"
xsi:type="BufferingWrapper"
flushTimeout="5000">
<target xsi:type="ElasticSearch"
layout="$logger | $threadid | $message"
index="logstash-$date:format=yyyy.MM.dd"
includeAllProperties="true"
uri="...">
<field name="user"
layout="$windows-identity:userName=True:domain=False"/>
<field name="host"
layout="$machinename"/>
<field name="number"
layout="1"
layoutType="System.Int32"/>
</target>
</target>
</targets>
<rules>
<logger name="*"
minlevel="Debug"
writeTo="elastic" />
</rules>
</nlog>
问:
当无法达到目标时,主线程会发生什么?案例 2 - 带有异步目标的 NLog
对带有 queueLimit="10000" batchSize="100" 的弹性搜索目标使用异步包装器
问:
是否创建了另一个线程[B]? 后续请求是否会重用线程 [B] 并对日志记录请求进行排队? 达到 queueLimit 时会发生什么? 是否会启动其他线程 [B1 ... Bn]? (这将淹没连接池)【问题讨论】:
【参考方案1】:好问题。
没什么好担心的,但是正确配置 NLog 很重要。
不确定什么应该是可靠的,运行程序或不丢失日志消息,所以对于这些情况:
如果你害怕丢失一些日志消息
写入多个目标(来自 NLog),例如文件和 Elasticsearch。 可选,使用 fallbackgroupwrapper(以防写入目标时出错) 如果启用异步,check the overflow/queue settings - 默认启用丢弃(以防止 CPU 或内存过载)如果您担心日志记录会破坏您的应用程序:
使用最新的稳定版 NLog 不要启用throwExceptions
(默认禁用)
如果您启用async
,错误将写入另一个线程中的目标,因此它不会破坏您的应用程序。
当使用async
、check the overflow and queue settings
更新
案例一,
当无法达到目标时,主线程会发生什么?
什么都没有。主程序将消息排入缓冲区。另一个 (Timer
) 线程正在处理这些消息。如果这将失败,并且throwException
未启用,则只会将错误写入 internalLog(启用时)。所有异常都会被捕获。写入目标失败时,您将丢失消息。
案例 2,
是否创建了另一个线程[B]?
将创建一个Timer
。这将创建一个线程来处理消息。
后续请求是否会重用线程 [B] 并将日志记录请求排队?
是的,但不能保证它会是同一个线程。计时器将从池中创建一个线程。注意:只有一个线程会同时处于活动状态。
达到 queueLimit 时会发生什么?
取决于您的配置。默认情况下,它会默认丢弃,如上所述。见check the overflow/queue settings。就内存和 CPU 而言,这是最安全的选择。您可以选择丢弃、阻塞(停止主线程)或增加队列(通过了解内存使用情况)。
会启动额外的线程 [B1 ... Bn] 吗? (这将淹没连接池)
没有。 1个定时器,1个线程池。详情请查看MSDN page for Timer 或reference source。
【讨论】:
没有考虑 throwExceptions 标志。感谢您指出了这一点!我已经更新了问题,你能再看看吗?以上是关于使用 ELK 堆栈进行应用程序日志记录的主要内容,如果未能解决你的问题,请参考以下文章
精通springcloud:分布式日志记录和跟踪使用,ELK Stack集中日志
ini 使用ELK堆栈(Elasticsearch + Logstash + Kibana)进行脱机SSHD日志分析