zoukankan      html  css  js  c++  java
  • Nlog、elasticsearch、Kibana以及logstash在项目中的应用(二)

    上一篇说如何搭建elk的环境(不清楚的可以看我的上一篇博客http://www.cnblogs.com/never-give-up-1015/p/5715904.html),现在来说一下如何用Nlog将日志通过logstash写入elasticsearch。

     新建一个项目,用nuget引入Nlog,随便写几行打日志的代码(写成循环是为了方便测试)

     1             var log = LogManager.GetCurrentClassLogger();
     2             while (true)
     3             {
     4                 log.Info("high Hkaos one");
     5                 log.Debug("high Hkaos two");
     6                 log.Warn("high Hkaos three");
     7                 log.Error("high Hkaos four");
     8                 Console.WriteLine("success");
     9                 Console.ReadKey();
    10             }

    我是采用udp的方式传输,所以在配置Nlog的时候需要设置type为Network,至于message的格式可以在layout中配置(网上一大堆,一搜就出来了),下面是我的配置文件

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <configSections>
        <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/>
      </configSections>
      <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
      </startup>
      <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <targets>
          <target name="network" xsi:type="Network" address="udp://192.168.4.12:4561" layout="${message}"/>
        </targets>
        <rules>
              <logger name="*" minlevel="Debug" writeTo="network" />
        </rules>
      </nlog>
    </configuration>

    一开始没有写configSections和rules,所以一直没有打日志,晕死。

    配置完毕之后,在配置logstash。由于Nlog是通过udp一直向配置的地址端口发送日志,所以在配置文件(这个配置就是自己手动建的文件,不懂的看上一篇博客)中的input要监听Nlog中配置的地址。logstash的input中可以写多种搜集日志的方式,有兴趣的可以去官网地址看看(https://www.elastic.co/guide/en/logstash/current/input-plugins.html)。

    input { 
        udp{
            host=>"192.168.4.12"
            port=>4561
        }    
    }

      output {
        stdout{

        }
    }

     

    input下面可以写多个搜集方式,比如

    input { 
        stdin{
        
        }
        udp{
            host=>"192.168.4.12"
            port=>4561
        }    
    }

    配置完成之后就可以测试一下。运行程序之前记得启动logstash,elasticsearch和kibana暂时不用可以不用启动。

    同时观察启动logstash的窗口

    出现了刚刚打印的日志,yes! 成功了。

    那我们先看看如何把日志写到elasticsearch里面并且通过kibana查看。很简单,我们在output中把原先输入到屏幕上的信息同时也输入到elasticsearch中就Ok了。同时呢,output的输出方式也有很多,可以去看看(https://www.elastic.co/guide/en/logstash/current/output-plugins.html),elasticsearch的选项有很多,这里有详细的介绍(https://www.elastic.co/guide/en/logstash/current/plugins-outputs-elasticsearch.html),下面是我的配置

    output {
            stdout{
            }
            elasticsearch {
            hosts => ["127.0.0.1:9200"]
            index => "logstash-%{+YYYY.MM.dd}"
            document_type => "logs"
            }
    }

    hosts就是elasticsearch的地址,可以配置多个,是个数组,index是索引的名称,相当于数据库的库名字,这里就是命名就是logstash-当天日期,每天都会新建一个库,document_type是类型的名称,相当于数据库中的表,老版本是index_type,新版本不让用了,如果用的话就会报错,告诉你这个方法被弃用了,让你用document_type。配置好之后需要重新启动logstash,首先要先启动elasticsearch和kibana。(Tip:重启logstash的话可以用Ctrl+C重启,连续按,能输入为止)。走起!

    界面是没啥变化,这时候要登录kibana看看,地址在启动kibana的时候被被打印出来

    界面如下:

    刚刚的日志被打印了出来,bingo!右边的字段可以自己选择添加是否显示在右边,右上角有个last 15 minutes,表示查看最新15分钟的,点击之后你可以任意选择你想查看的时间段。

    同时呢,elasticsearch也自带了查询的插件,不过需要安装,方法也简单,cmd进入elasticsearch的目录 运行plugin -install mobz/elasticsearch-head,就会自动安装了,成功之后地址为http://localhost:9200/_plugin/head/,可以直接访问,下面是界面

    在基本查询里面你可以查询打印的日志,还有执行的查询语句和原始的json。

    但是这些只能打印出message,比如我要打印其他的东西怎么办,比如方法名,hash值,是debug还是info还是error以及其他自定义的字段,这时候会有人说那就全部打印在message里面,那为啥还要这么麻烦用这个工具呢,直接打印到文件里面直接Ctrl+F就好了。所以我们要通过Nlog打印自定义的字段。这就要自己在Nlog里面定义了。

    这也是在网上查找了资料才找到的方法,需要继承Nlog的LayoutRenderer,重写Append方法

        [LayoutRenderer("json")]
        public class JsonLayoutRenderer : LayoutRenderer
        {
            protected override void Append(StringBuilder builder, LogEventInfo loggingEvent)
            {
                var msg = loggingEvent.FormattedMessage.AsJson<JsonLogMessage>();
    
                msg.priority = loggingEvent.Level.ToString();
                msg.logger_name = loggingEvent.LoggerName;
                msg.thread = loggingEvent.SequenceID.ToString();
                msg.application = "TestApplication";
                var json = msg.AsJsonString();
                builder.Append(json);
            }
        }

    本来是通过赋值的方法在LogEventInfo中取我想要的值比如Method,file,class等等,Log4net中是直接可以取得到的,但是Nlog不行,唉,蛋疼,所以只能吧数据写到json序列化之后写到message里面,然后在这个方法里面反序列化回来。大神们有什么好方法希望给解惑啊!

    这是对象信息

      public class JsonLogMessage
        {
            public string @class { get; set; }
            public string file { get; set; }
            public string host { get; set; }
            public string logger_name { get; set; }
            public string path { get; set; }
            public string priority { get; set; }
            public string thread { get; set; }
            public string application { get; set; }
            public string message { get; set; }
            public string addUser { get; set; }
            public string addUserName { get; set; }
            public string objName { get; set; }
            public string objId { get; set; }
            public int hash { get; set; }
            public string method { get; set; }
            public DateTime timestamp { get; set; }
        }

    本来timestamp字段不想写上去的,但是后来通过代码取不到时间,也是一个蛋疼的问题。

    那message的格式修改了,所以打日志的方法也就要变了,由于Append的方式改变了,所以布局方式需要重新修改,只要在程序运行前加一段代码就好,代码里面用的AsJosn和AsJosnString是封装好的json序列化和反序列化的方法,所以大家要用的话就直接用json原生的方法就好了。另外在配置文件中需要改变layout的布局方式,将layout="${message}修改成layout="${json}

    private static void Main(string[] args)
            {
                ConfigurationItemFactory.Default.LayoutRenderers.RegisterDefinition("json", typeof(JsonLayoutRenderer));
    
                var log = LogManager.GetCurrentClassLogger();
                while (true)
                {
                    var josn1 = new JsonLogMessage("Main", -1, "high Hkaos one", "tester", "testName", "objName", "objId");
                    var josn2 = new JsonLogMessage("Main", -1, "high Hkaos two", "tester", "testName", "objName", "objId");
                    var josn3 = new JsonLogMessage("Main", -1, "high Hkaos three", "tester", "testName", "objName", "objId");
                    var josn4 = new JsonLogMessage("Main", -1, "high Hkaos four", "tester", "testName", "objName", "objId");
    
                    log.Info(josn1.AsJsonString());
                    log.Debug(josn2.AsJsonString());
                    log.Warn(josn3.AsJsonString());
                    log.Error(josn4.AsJsonString());
                    Console.WriteLine("success");
                    Console.ReadKey();
                }
            }

    运行!

    完蛋了,看到这个我就知道有错了,虽然日志出来了,但是我们在head插件或者kibana中看看(我用的是head插件)

    日志的信息全部打印到message里面,操蛋了。我要的不是这样子的。去Google了一下,发现要是用json的话,需要在input里面加codec=>"json",好了,那就修改一下input

    input { 
        stdin{
    
        }
        udp{
            host=>"192.168.4.12"
            port=>4561
            codec=>"json"
        }    
    }

    重启一下logstash,再来一遍

    这次明显打印的不一样了,再看看head里面数据

    yes!要的就是这个效果。

    之后我吧Nlog的配置改成了代码写的,使用配置文件总有一些不方便的地方,比如说地址。下面是代码

     private static void Main(string[] args)
            {
                ConfigurationItemFactory.Default.LayoutRenderers.RegisterDefinition("json", typeof(JsonLayoutRenderer));
    
                var log = LogManager.GetCurrentClassLogger();
                var udpTarget = new NetworkTarget()
                {
                    Address = "udp://192.168.4.12:4561",
                    Encoding = Encoding.UTF8,
                    Layout = "${json}",
                    NewLine = true,
                };
    
                var config = new LoggingConfiguration();
                config.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, udpTarget));
                LogManager.Configuration = config;
    
                while (true)
                {
                    var josn1 = new JsonLogMessage("Main", -1, "high Hkaos one", "tester", "testName", "objName", "objId");
                    var josn2 = new JsonLogMessage("Main", -1, "high Hkaos two", "tester", "testName", "objName", "objId");
                    var josn3 = new JsonLogMessage("Main", -1, "high Hkaos three", "tester", "testName", "objName", "objId");
                    var josn4 = new JsonLogMessage("Main", -1, "high Hkaos four", "tester", "testName", "objName", "objId");
    
                    log.Info(josn1.AsJsonString());
                    log.Debug(josn2.AsJsonString());
                    log.Warn(josn3.AsJsonString());
                    log.Error(josn4.AsJsonString());
                    Console.WriteLine("success");
                    Console.ReadKey();
                }
            }

    配置文件里面直接删除原来添加的东西就好了。

    就写到这里吧,下一篇准备些一下如何用C#链接日志服务,根据条件查询日志,如何配置模板和映射等。

    任凭弱水三千,只取一瓢饮
  • 相关阅读:
    loj2042 「CQOI2016」不同的最小割
    loj2035 「SDOI2016」征途
    luogu2120 [ZJOI2007]仓库建设
    luogu3195 [HNOI2008]玩具装箱TOY
    51nod 1069 Nim游戏 + BZOJ 1022: [SHOI2008]小约翰的游戏John(Nim游戏和Anti-Nim游戏)
    HDU 5723 Abandoned country(最小生成树+边两边点数)
    BZOJ 1497: [NOI2006]最大获利(最大权闭合图)
    51nod 1615 跳跃的杰克
    SPOJ 839 Optimal Marks(最小割的应用)
    UVa 11107 生命的形式(不小于k个字符串中的最长子串)
  • 原文地址:https://www.cnblogs.com/never-give-up-1015/p/5720488.html
Copyright © 2011-2022 走看看