一个简单的远程日志平台






4.83/5 (20投票s)
在本文中,我们解释了如何构建一个简单易用的日志平台,同时兼顾性能和安全。
引言
日志是我们应用程序中最常见的组成部分之一,无论是网站还是客户端应用程序,都离不开适当的日志支持。如今,NLog 或 log4net 等库为我们提供了一种强大的方式来跟踪应用程序的运行情况并提供错误报告。然而,大多数日志都局限于其产生的范围,隐藏在服务器内部。有时,我曾在项目中看到过在重要事件或严重错误发生时发送电子邮件的做法。如今,有许多方法可以实现日志的集中管理。这可以通过收集日志或将事件发送到开发人员可以访问的中央日志接收器来实现。这在某些商业环境中很常见,随着事态的发展,我认为这很有必要,而且这种做法将来会越来越普遍。
日志集中管理可以通过两种不同的方法实现:
- 使用“本地部署”的中央日志收集器,我们可以在其中定义日志源。
- 使用面向服务的架构,我们将错误或事件发送给此实体。
第一种方法可以使用许多工具(商业或免费)来实现。这些工具通常安装复杂,并且有维护成本,所以我们通常选择第二种,它只是购买许多在线工具中的一种,这些工具以 SAAS(软件即服务)的形式进行转售。这种方式的优点是成本低,但有时因为对数据收集缺乏信任(大多数服务都保证数据源是加密和隔离的)而不被选择。
因此,在本文中,我们试图结合这两种解决方案的优点,创建一个轻量级且易于安装的平台服务,我们只需要将其安装在 Web 服务器上即可提供基本的日志收集功能。此外,我们将实现一个 NLog 目标(类似于 log4net 的 Appender),以展示如何在不重写现有应用程序的情况下使用此服务。最后,我们将进行一些基准测试,以测试性能并检测这种日志会使应用程序变慢多少。
注意:本文是 HubLink 项目的前身。我们将“作为服务的日志收集”扩展为一个更广泛的“服务中心”概念,它允许将通用功能委派给这个外部系统。
要求
由于日志通常是密集的,我们预计会产生大量服务调用。这意味着每次调用都会给调用应用程序带来成本,并且必须将此成本保持在尽可能低的水平以获得良好的性能。报告可以通过引入一些缓冲系统(如 nlog logger 中的缓冲区)来实现,以避免大量小请求,并在后台执行少量请求。此外,我们必须始终保持服务的低响应时间。同时,在客户端,我们引入缓冲以提高服务器端的性能;在服务器端,我们引入队列以加快响应速度。通过这种方式,请求将尽快处理,只需将原始请求放入内存队列,然后将有一个后台作业将项目入队并写入数据库。
架构
简单来说,这是一个公开 Web 服务来收集数据的 Web 应用程序,这是一个文档记录完善的领域。我们在此技术栈上构建此应用程序。
- ASP.NET MVC 5
- Hangfire
- NHibernate
- NLog
- .NET Framework 4.5
这里不是解释如何构建应用程序的地方,所以我们只展示最重要的部分。
- Web API(数据收集):应用程序的这部分公开了 REST 接口,允许远程应用程序发送日志。这是使用 ASP.NET API 框架实现的,支持 JSON 或 XML 输入格式。
- Web UI (MVC 5):这是用户可以搜索日志并管理应用程序设置或用户的“网站”。
- 后台作业:为了保持简单,我们将这部分放在 ASP.NET 应用程序中。这有一些影响,在此处总结了,但使用功能强大的 Hangfire 库,我们可以解决大部分问题,将所有功能都打包到 Web 应用程序中(否则我们不得不部署一个服务、一个计划任务或类似的东西)。
Web API
提供了 REST API 来向此应用程序发送日志信息。实际上,这部分是一个 ASP.NET WEB API 应用程序,所以我们继承了一些很酷的功能,比如 API 手册和序列化实现的抽象(本例中为 JSON 或 XML)。
在下面的图表中,我们解释了存储日志的流程。客户端调用到达 WebApi 控制器,控制器将其放入队列,然后后台作业将其持久化到数据库。
NLog 目标
在上一节中,我解释了创建一个 Web 应用程序并用它收集数据是多么简单。但是,我们需要有人生成这些日志,但这不会通过重写应用程序来实现,而是通过简单地更改日志记录器来实现。无论您使用 log4net 还是 NLog 系统,这都是可能的,这也是我推荐的方式。
在这个例子中,我实现了一个简单的 NLog
日志记录器。为此,我们只需实现一个如下的类:
namespace NLog.WebLog
{
[Target("WebTarget")]
public class WebTarget : TargetWithLayout
{
public WebTarget()
{
this.Destination = "localhost";
}
public WebTarget(String Destination)
{
this.Destination = Destination;
}
[RequiredParameter]
public string Destination { get; set; }
protected override void Write(LogEventInfo logEvent)
{
//Get the log message from base type
string logMessage = this.Layout.Render(logEvent);
//create a new entry to send
LogEntry entry = new LogEntry();
entry.Message = logMessage;
//... fill more data
entry.SourceDate = DateTime.Now;
//Make the request
DoRequest(Destination, JsonConvert.SerializeObject(entry));
}
}
Destination
是客户端配置中设置的 REST 端点的完整 URL(请参阅“如何使用”部分)。此目标继承自 TargetWithLayout
类,因此我们已经得到了一个格式化的消息,如 web.config 或 app.config 中配置的那样。
如何使用
使用此远程日志系统非常简单,一旦您在服务器上安装并配置了 Web 应用程序,您只需将其集成到您的应用程序中即可。如果您使用的是 NLog
或 log4net
等标准库,这非常简单。在此演示中,我们实现了一个 NLog
目标,该目标将缓冲的日志写入服务器。您只需将此配置放在 web.config 或应用程序配置文件中。
下面是 NLog
库的一个示例,请参阅源代码中的 TestApp
示例以消除任何混淆。
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" throwExceptions="true" >
<extensions>
<add assembly="NLog.WebLog"/>
</extensions>
<targets>
<target name="f1" xsi:type="File" fileName=".\testlog.txt"/>
<!-- registering a new target for logs-->
<target name="wlog.logger" xsi:type="WebTarget"
destination="https://:55044/api/log"
layout="${longdate}|${level:uppercase=true}|${logger}|${message}" />
</targets>
<rules>
<!-- you can just log everything and then set retention or display policy on remote environment-->
<logger name="*" minlevel="Trace" writeTo="wlog.logger" />
</rules>
</nlog>
在这个示例中,我们将所有内容都记录到了远程平台。通常,这不是最佳实践,因为过多的日志很难管理,当您需要查找某个事件日志或发现错误时,它们会浪费大量磁盘空间。使用提供强大过滤系统的远程平台,这些问题就不那么重要了。您需要记住的唯一方面是性能:无论我们使用批量日志系统来最小化网络开销并延迟写入,但“过多的日志”总意味着“变慢”。
将所有日志记录到远程系统然后再进行过滤,这可能看起来是一种天真的方法,但如果我们暂时忽略性能问题和远程环境的磁盘空间,它将非常实用,并且为开发人员提供了一个非常强大的平台,他们可以快速处理日志,而无需访问生产环境。
性能测试
鉴于我们的前提,我们在设计此应用程序时考虑了性能。无论如何,在我们的工作中,良好的意愿是不够的,所以我们还提供了一组测试来证明我们达到了性能目标。
下表显示了我们在本地环境(i5 四核 1.86 GHz + 8GB RAM + HD SSD)中进行的测试结果。此测试包含在源代码中,因此您只需运行它即可检查这些测试,但我预计在大多数环境中结果相似(绝对值可能不同,但百分比上,我们应该有相同的比较)。
*缓冲区设置:缓冲区大小=1000 个元素;刷新超时:160 秒;#日志 | 文件 时间(毫秒) | WLog 时间(毫秒) | Wlog+Buffer* 时间(毫秒) |
---|---|---|---|
1 | 4.64 | 8.7 | 10.7 |
10 | 4.13 | 6.22 | 0.005 |
100 | 4.44 | 6.25 | 0.005 |
1000 | 5.91 | 4.17 | 3.83 |
10000 | 8.99 | 5.73 | 7.88 |
测试 1:Web 服务器和客户端在同一台机器上,假定没有网络延迟
在第一个测试中,我们看到文件写入和不带缓冲的 wlog 写入之间的差异很小,这仅仅是因为我们没有网络过载(或者网络过载可以忽略不计),并且因为客户端日志实现了异步技术,从而降低了对性能的影响。引入缓冲区可以提高此性能,因为缓冲区有时间刷新而不会影响用户。事实上,我们使用了 1000 个元素的缓冲区,每分钟刷新一次(如果未满),因此当我们每分钟发送不到 500 条日志时,它的效果非常好,但当我们开始承受更重的负载时,调用者需要承担刷新成本,从而导致平均性能下降。确实,我们可以像对 wlog 目标那样,对文件日志应用一些优化,但在实践中,大多数系统使用默认配置的日志,所以我们可以假设我们可以使用这种解决方案而不会影响性能。
#日志 | 文件 时间(毫秒) | WLog* 时间(毫秒) | Wlog+Buffer* 时间(毫秒) |
---|---|---|---|
10 | 3 | 5 | 6 |
100 | 3 | 5 | 6 |
1000 | 3 | 5 | 6 |
10000 | 3 | 5 | 6 |
测试 2:客户端调用托管 Web 应用程序的远程服务器。
在第二个(更现实的)情况下,缓冲和非缓冲情况之间的差异变得相关,并且缓冲的好处很明显。但是,性能差异对于大多数应用程序来说是可以接受的。
那么网络延迟呢?网络延迟可能取决于许多因素,例如跳数、距离、介质质量等,但考虑到异步方法,这种延迟不会直接影响性能。根据在 LAN 环境中服务器进行的测试,与安装在本地的服务器相比,没有有意义的差异。
关注点
在本文中,我们展示了如何构建一个简单的远程日志平台以及如何在实践中集成它。此外,在做到这一点时,我们讨论了远程日志系统并解释了其好处。
- 所有应用程序日志集中一处
- 实时查看分布式环境中的一切动态
- 轻松搜索
- 无保留期问题
- 轻松更改警报/事件,直接在 Web 上进行调整
- 无安全问题:开发人员在浏览器中读取日志(配置文件)。
实际上,使用这样的日志系统并非强制性,因为使用数据库日志记录器或一些其他手动解决方案(如共享文件夹日志、定时复制等)可以达到类似的结果。此外,一个结构良好的日志平台的优势非常高,尤其是在复杂的项目/大型团队中,引入它非常重要。
我们理解这类平台并非万能的。事实上,它们是有成本的,可能是 SaaS 的月度费用,或者是本地解决方案的硬件/维护成本。根据我的经验,比较在线解决方案的性能和成本与雇员的小时工资,我发现 SaaS 解决方案非常方便。当然,有些人可能不信任将数据远程发送出去,但我认为存在不同类型的应用程序。
最后但同样重要的是,关于这个项目和这篇文章的一点评论。正如您可能想象到的,没有真正的理由去构建自己的 Web 日志收集器。我解释说,有许多外部工具可供集成。但这并不是一个商业项目。它有教学目的,使我们能够反思日志记录(传统方法),并提供一个简单但完整的 Web 应用程序的示例(我们拥有大多数在商业应用程序中普遍共享的元素)。
待办事项
关于如何改进这项工作,只有几句话。
- 在实际案例中进行测试(风险自负……)
- 为其他库(例如
log4net
)实现插件,并测试性能是来自Nlog
还是此项目提供的。 - 实现一个具有多个插入的服务,并在客户端实现自定义缓冲。
参考文献
您想试试吗?您想测试一下吗?只需从 Codeplex 项目页面 http://wlog.codeplex.com/ 获取您需要的内容。
您想试试吗?您想测试一下吗?只需从 Codeplex 项目页面 https://github.com/arduosoft/wlog 获取您需要的内容。
- 源代码:您可以 通过克隆 GitHub 仓库 下载源代码。
- 二进制文件:您可以从 codeplex 项目页面 codeplex 下载二进制文件。
如何联系我?请在 GitHub 上打开一个 issue,或给我发送私信,分享您对项目的任何看法或提交 issue。
历史
- 2017-04-01:项目已重命名为“HubLink”并发布为 Beta 版本。
- 2016-12-03:文章参考更新。项目已迁移到 GitHub。
- 2016-01-10:文章提交。
- 2015-12-20:在 Codeplex 上首次发布。
- 2015-11-11:项目启动。