Nlog、elasticsearch、Kibana以及logstash在项目中的应用(二)

上一篇说如何搭建elk的环境(不清楚的能够看个人上一篇博客http://www.cnblogs.com/never-give-up-1015/p/5715904.html),如今来讲一下如何用Nlog将日志经过logstash写入elasticsearch。html

 新建一个项目,用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中配置(网上一大堆,一搜就出来了),下面是个人配置文件json

<?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)。app

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

  output {
    stdout{

    }
}elasticsearch

 

input下面能够写多个搜集方式,好比ide

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#连接日志服务,根据条件查询日志,如何配置模板和映射等。

相关文章
相关标签/搜索