log4net.redis+logstash+kibana+elasticsearch+redis 实现日志系统

摘要:
我在前端写了一篇文章log4net,NoSql+ElasticSearch实现了日志记录。由于项目原因,需要将日志根的java平台上的同事与logstack+kibana+弹性搜索+redis结构集成,以实现日志统计和分析。因此,需要一个组件将log4net日志输出到redis。我没有找到准备好的东西,所以我自己动手。请参阅log4net的代码。无SQL。Redis的C#客户端使用ServiceStackRedis,json序列化使用RestSharp。

前端时间写了个随笔 log4net.NoSql +ElasticSearch 实现日志记录 ,因项目原因需要把日志根java平台的同事集成采用logstash+kibana+elasticsearch+redis结构实现日志统计分析,所以需要一个将log4net日志输出到redis的组件。没有找到现成的,就自己动手了。参考了 log4net.NoSql的代码。

redis的C#客户端使用了 ServiceStackRedis,json序列化使用 RestSharp。代码结构如下:

log4net.redis+logstash+kibana+elasticsearch+redis 实现日志系统第1张

JsonLayout.cs代码:

log4net.redis+logstash+kibana+elasticsearch+redis 实现日志系统第2张log4net.redis+logstash+kibana+elasticsearch+redis 实现日志系统第3张
  public class JsonLayout : LayoutSkeleton
    {
        public readonly string HostName;
        private readonly ITextTransform _transform;

        public string LogType { get; set; }
        public string AppName { get; set; }

        public JsonLayout()
            : base()
        {
            HostName = Dns.GetHostName();
            _transform = TextTransform.Instance;
        }

        public override string ContentType
        {
            get { return "application/json"; }
        }

        public override void ActivateOptions()
        {
            //nothing to do here
        }

        public override void Format(TextWriter writer, LoggingEvent loggingEvent)
        {
            var info = loggingEvent.LocationInformation;
            var loggingEventJson = _transform.Serialize(new JsonLogMessage
                {
                    class_method = info.MethodName,
                    class_name = info.ClassName,
                    host_ip = HostName,
                    line_number = info.LineNumber,
                    log_level = loggingEvent.Level.DisplayName,
                    log_message = loggingEvent.MessageObject.ToString(),
                    exception = BuildExceptionMessage(loggingEvent),
                    log_time = loggingEvent.TimeStamp.ToString("yyyy-MM-dd HH:mm:ss"),
                    logger_name = loggingEvent.LoggerName,
                    run_time = "0", //目前获取不到
                    thread_name = loggingEvent.ThreadName,
                    host = HostName,
                    log_type = this.LogType,
                    app_name = this.AppName,
                    path = ""
                });

            writer.Write(loggingEventJson);
        }

        private JsonLogException BuildExceptionMessage(LoggingEvent loggingEvent)
        {
            if (loggingEvent.ExceptionObject == null)
                return new JsonLogException { exception_class = "", exception_message = "", exception_stacktrace = "" };

            var exception = loggingEvent.ExceptionObject;
            return
                new JsonLogException
                {
                    exception_class = exception.Source,
                    exception_message = exception.Message,
                    exception_stacktrace = exception.StackTrace
                };
        }
    }
View Code

RedisAppender.cs

log4net.redis+logstash+kibana+elasticsearch+redis 实现日志系统第4张log4net.redis+logstash+kibana+elasticsearch+redis 实现日志系统第5张
 public class RedisAppender : AppenderSkeleton
    {
        private volatile PooledRedisClient _pooledRedisClient;
        private readonly object _padlock = new object();

        public string Host { get; set; }
        public string Port { get; set; }
        public string ListId { get; set; }
        public string MaxPoolSize { get; set; }

        public RedisAppender()
        {
        }

        private PooledRedisClient Client
        {
            get
            {
                if (_pooledRedisClient != null) return _pooledRedisClient;

                lock (_padlock)
                {
                    if (_pooledRedisClient == null)
                    {
                        _pooledRedisClient = new PooledRedisClient(this.Host, int.Parse(this.Port), int.Parse(this.MaxPoolSize));
                    }
                }
                return _pooledRedisClient;
            }
        }

        protected override void Append(LoggingEvent loggingEvent)
        {
            var sb = new StringBuilder();
            var writer = new StringWriter(sb);
            base.Layout.Format(writer, loggingEvent);
            this.Client.AddItemToListAsync(ListId, writer.ToString());
        }
    }
View Code

PooledRedisClient.cs

log4net.redis+logstash+kibana+elasticsearch+redis 实现日志系统第6张log4net.redis+logstash+kibana+elasticsearch+redis 实现日志系统第7张
  public class PooledRedisClient
    {
        private readonly string _baseUri;
        private readonly PooledRedisClientManager _clientManager;
        /// <summary>
        /// 实例化连接池客户端
        /// </summary>
        /// <param name="host"></param>
        /// <param name="port"></param>
        /// <param name="maxPoolSize">默认值10</param>
        public PooledRedisClient(string host, int port, int maxPoolSize = 10)
        {
            _baseUri = string.Format("{0}:{1}", host, port);
            var config = new RedisClientManagerConfig();
            config.MaxReadPoolSize = maxPoolSize;
            config.MaxWritePoolSize = maxPoolSize;
            _clientManager = new PooledRedisClientManager(new string[] { _baseUri }, new string[] { _baseUri }, config);
        }
        /// <summary>
        /// 异步记录
        /// </summary>
        /// <param name="listId"></param>
        /// <param name="log"></param>
        public void AddItemToListAsync(string listId, string log)
        {
            //使用Task任务异步执行
            var task = new Task(() =>
            {
                try
                {
                    using (var clinet = _clientManager.GetClient())
                    {
                        clinet.AddItemToList(listId, log);
                    }
                }
                catch (Exception ex)
                {
                    Trace.WriteLine(ex.Message);
                }
            });
            task.Start();
        }

    }
View Code

在RedisClient连接时用了连接池,写日志时用Task做了异步。这种写法不知道会不会存在问题?!

配置文件

log4net.redis+logstash+kibana+elasticsearch+redis 实现日志系统第8张log4net.redis+logstash+kibana+elasticsearch+redis 实现日志系统第9张
<?xml version="1.0"?>
<log4net>
  <!--Redis日志记录-->
  <appender name="redisAppender" type="log4net.Redis.Appender.RedisAppender, log4net.Redis">
    <Host value="192.168.0.10" />
    <Port value="6379" />
    <MaxPoolSize value="500" />
    <ListId value="logstash" />
    <layout type="log4net.Redis.Layout.JsonLayout,log4net.Redis" >
      <LogType value="iis_log" />
      <AppName value="Demo" />
    </layout>
  </appender>
  <root>
    <level value="ALL" />
    <appender-ref ref="redisAppender" />
  </root>
</log4net>
View Code

Layout和Appender里的属性配置和代码里属性配置名称一致,Log4net的框架就可以读取配置数据反射到实体属性上。

代码下载地址:

http://download.csdn.net/detail/zbl131/7702673

参考文章:

1.用Kibana和logstash快速搭建实时日志查询、收集与分析系统

http://storysky.blog.51cto.com/628458/1158707/

2.使用ServiceStackRedis链接Redis简介

http://www.cnblogs.com/daizhj/archive/2011/02/17/1956860.html

3.ServiceStack.Redis的问题与修正

http://blog.csdn.net/susubuhui/article/details/8930417

4.对ServiceStack.Redis的连接池进行故障转移改造

http://www.cnblogs.com/smark/archive/2013/05/24/3096488.html

免责声明:文章转载自《log4net.redis+logstash+kibana+elasticsearch+redis 实现日志系统》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇VSS的配置和使用QVariant与自定义数据类型转换的方法下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

C#操作word模板

    string newDocFileName = Guid.NewGuid().ToString().Replace("-", "");        string strServerPath = Server.MapPath("") + "\\Model.doc";  //模板路径        string strSavePath = Serve...

解析如何利用ElasticSearch和Redis检索和存储十亿信息

如果从企业应用的生存率来看,选择企业团队信息作为主要业务,HipChat的起点绝非主流;但是如果从赚钱的角度上看,企业市场的高收益确实值得任何公司追逐,这也正是像JIRA和Confluence这样的智能工具制造商Atlassian于2012年收购HipChat的原因。 同时,或许你不知道的是,在Atlassian资源和人脉的帮助下,HipChat已经...

Filter(过滤器)

Filter(过滤器) Filter 功能: 1.用来拦截传入和传出的响应。 2.修改或以某种方式处理正在客户端和服务端之间交换的数据流。 使用方法: 与使用Servlet相似,Filter是JavaWeb提供的一个接口,开发者只要自定义一个类并且实现该接口即可。 注意事项: 1.接口实现时一定要引用 Filter(Javax.servlet) 2.doF...

读取FTP上的excel文件,并写入数据库

今天遇到一些问题,需要从ftp上读取一些excel文件,并需要将excel中的数据写入到数据库,这样就可以通过管理页面查看这些数据。 我将相关工作分为三步,1、从ftp上读取相关文件,并将excel文件下载到本地。2、读取本地下载完成的excel,读取相关信息 3、将读取的信息存储到数据库中。 1、获取java操作ftp操作,首先要从maven仓库http...

CentOS (6.5|7.4)网卡安装报"Error, some other host already uses address"的解决方案

CentOS 6.5 网卡安装报"Error, some other host already uses address"的解决方案  解决办法: vi /etc/sysconfig/network-scripts/ifup-eth 注解掉下面的几行内容,然后再执行ifup eth0 if ! /sbin/arping -q -c 2 -w 3 -D...

google guava工具包

guava这个工具包里有好多有用的工具类 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>${guava.version}</version><...