上一次我们介绍并演示了如果使用 consul 做为我们微服务的注册中心,来实现服务的注册与发现。那么本次我们讲会演示如何做日志聚合。日志聚合比较常用的有 elk 等,但是这次我想要介绍的是一款比较小众的日志聚合工具 – seq 。

日志聚合

日志是我们写程序离不开的一个东西。在我们排查问题的时候日志就是我们的救命稻草。我们的每个服务都在不停的生产日志。但是实施微服务后,如果按照传统的写本地文件的日志方案,显然会面临跟修改配置一样麻烦的境地。不同的日志分散在各个服务器、容器内,这种情况下查日志简直是生不如死。
日志聚合组件为我们解决了这个问题。所有的服务通过接口发送日志到聚合服务,再由聚合服务进行统一存储,并且提供统一的查询、分析的能力。
日志聚合组件业界有 elk、exceptionless、seq 等。

seq

seq 是一款使用现代化技术构建的结构化日志存储,查询,分析工具。比起 elk 这种组合要轻量级许多。只需要一个安装包就具有数据存储,查询,图表分析功能。它对 windows 友好,直接提供了安装包。当然也可以使用 docker 来部署。seq 对于单个用户是免费的,这对于一些小团队并没有什么问题。seq 一个比较强大的功能是提供了类似 sql 语句的数据查询及处理能力,使得用户可以直接写 select from 来得到自己想要的数据。

seq 的 dashboard 页面。

seq 的查询界面。

使用 docker 安装

docker run --name seq -e accept_eula=y -p 8900:80 -p 5341:5341 datalust/seq

使用 docker run 运行一个实例。8900 绑定容器的 80 端口,该端口是 web 管理界面的入口。5341 绑定容器的 5341 端口,该端口是日志写入时候真正的端口。

使用 docker-compose 安装

  seq_server:
    image: datalust/seq
    restart: always
    container_name: seq_server
    hostname: seq_server
    environment:
      - accept_eula=y
    ports:
      - 8900:80
      - 5341:5341

把上面的 docker 命令改写成 docker-compose 命令。
安装好 seq 之后,我们访问一下 如果管理后台出现说明我们安装成功了。

nlog 集成 seq

seq 安装成功之后,我们可以开始跟 asp.net core 项目进行集成了。这里采用 nlog 日志组件进行演示,如何跟 seq 集成。

点击 “api keys” 、“add api key” 弹出新增 api key 界面。

我们可以在这个界面为每个服务指定一个 apikey 当写入 seq 的是用来区分服务。填写 title 信息,选择具有的权限,还可以自定义一些属性,这些属性会附加到每个日志记录上。比如我们这里为 member_center 这个 apikey 自定义一个 app = member_center 的属性。

install-package nlog.targets.seq

nuget 安装 nlog 的 seq 扩展。

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/nlog.xsd"
      xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
      autoreload="true"
      internalloglevel="info"
      internallogfile="logs/internal-nlog.txt">

  <extensions>
    <add assembly="nlog.targets.seq"/>
  </extensions>
  <!-- the targets to write to -->
  <targets>

    <!-- write to the void aka just remove -->
    <target xsi:type="null" name="blackhole" />

    <target name="seq" xsi:type="bufferingwrapper" buffersize="1000" flushtimeout="2000"  >
      <target xsi:type="seq" serverurl="http://192.168.18.164:5341" apikey="vuryxr8bmxuvknbwvnup">
        <property name="threadid" value="${threadid}" as="number" />
        <property name="stacktrace" value="${onexception:inner=${stacktrace}}"/>
      </target>
    </target>
  </targets>

  <!-- rules to map from logger name to target -->
  <rules>
    <!--skip microsoft logs and so log only own logs-->
    <logger name="microsoft.*" minlevel="trace" writeto="blackhole" final="true" />

    <logger name="*" minlevel="trace" writeto="seq" />
  </rules>
</nlog>

在项目根目录添加一个 nlog.config 的 xml 配置文件。添加一个 seq 的 target ,在这个 target 上填写 serverurl(seq的服务地址),apikey。

        public static ihostbuilder createhostbuilder(string[] args) =>
            host.createdefaultbuilder(args)
                .configurewebhostdefaults(webbuilder =>
                {
                    webbuilder.configurekestrel(options =>
                    {
                        options.listenanyip(6003);
                    });
                    webbuilder.usestartup<startup>();
                })
                .usenlog();

在 program 文件的 createhostbuilder 方法最后追加 usenlog 调用。

    [apicontroller]
    [route("[controller]")]
    public class testcontroller : controllerbase
    {
        private readonly ilogger _logger;

        public testcontroller(iloggerfactory loggerfactory)
        {
            _logger = loggerfactory.createlogger<testcontroller>();
        }

        [httpget("testlogseq")]
        public string testlogseq()
        {
            _logger.logtrace("this is a test log for trace level .");
            _logger.logdebug("this is a test log for debug level .");
            _logger.loginformation("this is a test log for info level .");
            _logger.logwarning("this is a test log for warning level .");
            _logger.logerror(new exception("this is a ex for seq log ."), "this is a test log for error level .");

            return "ok";
        }
    }

添加一个 testcontroller 编写一个 testlogseq 方法,在这里打一些日志。

我们访问一下这个接口,打开 seq 的站点可以看到我们的日志已经写到 seq 里面了。

查询

我们的服务每天都会产生数以万计的日志,现在把所有服务的日志都聚合在一起,那数量就更加庞大。在海量日志中查找需要的日志,显然变得很困难。
还好 seq 带有强大的查询功能。我们可以像在数据库里查询那样,使用 sql 语句来进行查询。
下面演示几个查询例子:

  1. like 查询
@message like '%init%'

查询日志消息里带有 init 关键字的日志

2. = 查询

@level = 'error'

查询日志级别为 error 的日志。

app = 'hotel_base'

查询所有 hotel_base 服务的日志。

3. 聚合函数

select count(1) from stream group by @level

按日志级别分组,统计每个级别的数量。

以上简单的演示了几个查询方案,seq 的查询相当的强大,具体请查考官方文档:

总结

通过以上内容,我们简单的演示了 seq 日志聚合工具的安装、与.net core 进行集成,查询日志等功能。seq 虽然比起 elk 比较冷门,但是最近跟一些朋友交流下来,发现很多朋友都开始使用 seq 来做为日志聚合工具了。这也说明 seq 确实有一定的实力,大家不妨一试。

项目地址

相关文章

net core with 微服务 – 什么是微服务
.net core with 微服务 – 架构图
.net core with 微服务 – ocelot 网关
.net core with 微服务 – consul 注册中心

关注我的公众号一起玩转技术