log4net to remote web api interface

在log4.net 中配置节点,实现将本地日志发送到其它机器的web api接口中

1、webconfig中增加节点

    <appender name="HttpAppender" type="Log4Net.HttpAppender.AsyncBatchHttpAppender, Log4Net.HttpAppender">

      <threshold value="Debug" />

      <!-- Required: HTTP endpoint --> 
      <ServiceUrl value="http://127.0.0.1:8088" /> 

      <!-- Required: Project/System ID/Name --> 
      <ProjectKey value="FRIENDLY_DISPLAY_NAME" />

      <!-- Optional: Defaults to machine name -->
      <!--<Environment value="dev|stage|prod" />-->
      <Environment value="dev" />
      <!-- Optional: Maximum number of events to submit per processing round. Default's to 40 -->
      <BatchMaxSize value="20" />

      <!-- Optional: Maximum number of events to submit per processing round. Default's to 40 -->
      <BatchSleepTime value="200" />

      <!-- Optional: Attach request headers and form values to http logging data. Default's to error,fatal,warn -->
      <LogHttpForLevels value="All" />

      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="%date [%identity] %-5level %logger - %message%newline" />
      </layout>
    </appender>

2、代码中增加

    using System.Linq;
    using System.Net;
    using System.Threading;
    using System.Web;
    using log4net.Appender;
    using log4net.Core;
    using MedicalManage.Common.Http;

    /// <summary>
    /// post  json data to target 
    /// </summary>
    public class AsyncBatchHttpAppender : AppenderSkeleton
    {
        private readonly Queue<LoggingEventModel> _queue;
        private readonly object _lockObject = new object();
        private readonly ManualResetEvent _manualResetEvent;
        private bool _onClosing;
        private readonly string[] _logHttpForLevels;

        // Configuration values (set in appender config)
        public string ServiceUrl { get; set; }
        public string ProjectKey { get; set; }
        public string Environment { get; set; }
        public string LogHttpForLevels { get; set; }
        public int BatchMaxSize { get; set; }
        public int BatchSleepTime { get; set; }

        public AsyncBatchHttpAppender()
        {
            _logHttpForLevels = string.IsNullOrWhiteSpace(LogHttpForLevels)
                ? new[] { "error", "fatal", "warn" }
                : LogHttpForLevels.Split(',').Select(x => x.ToLower().Trim()).ToArray();

            //initialize our queue
            _queue = new Queue<LoggingEventModel>();

            //put the event initially in non-signalled state
            _manualResetEvent = new ManualResetEvent(false);

            //start the asyn process of handling pending tasks
            Start();
        }

        protected override void Append(LoggingEvent[] loggingEvents)
        {
            foreach (var loggingEvent in loggingEvents)
                Append(loggingEvent);
        }

        protected override void Append(LoggingEvent loggingEvent)
        {
            if (FilterEvent(loggingEvent))
                enqueue(loggingEvent);
        }

        private void Start()
        {
            // hopefully user doesnt open and close the GUI or CONSOLE OR WEBPAGE
            // right away. anyway lets add that condition too
            if (!_onClosing)
            {
                var thread = new Thread(processMessageQueue);
                thread.Start();
            }
        }

        private void processMessageQueue()
        {
            // we keep on processing tasks until shutdown on repository is called
            while (!_onClosing)
            {
                LoggingEventModel loggingEvent;

                var queuedLoggingEvents = new List<LoggingEventModel>();
                int count = 0, max = BatchMaxSize > 0 ? BatchMaxSize : 40;

                while (deQueue(out loggingEvent))
                {
                    if (count == max) break;
                    queuedLoggingEvents.Add(loggingEvent);
                    Debug.WriteLine("Dequeued " + loggingEvent.message);
                    count++;
                }

                if (queuedLoggingEvents.Any())
                {
                    Debug.WriteLine("++" + queuedLoggingEvents.Count + " EVENTS TO PUBLISH++");

                    try
                    {
                        processQueuedLoggingEvents(queuedLoggingEvents);
                    }
                    catch (Exception e)
                    {
                        Debug.WriteLine("There was an error attempting to submit the logging events to endpoint");
                        Debug.Write(e.Message);
                        Debug.Write(e.StackTrace);
                    }

                    Debug.WriteLine("+++");
                }
                else
                    Debug.WriteLine("++0 EVENTS++");

                // if closing is already initiated break
                if (_onClosing) break;

                // if they are no pending tasks sleep 10 seconds and try again
                var batchSleepTime = BatchSleepTime == 0 ? 200 : BatchSleepTime;
                Thread.Sleep(batchSleepTime);
                Debug.WriteLine("Sleeping for " + batchSleepTime + "ms");
            }

            // we are done with our logging, sent the signal to the parent thread
            // so that it can commence shut down
            _manualResetEvent.Set();
        }

        private void processQueuedLoggingEvents(IEnumerable<LoggingEventModel> queuedLoggingEvents)
        {
            using (var client = new WebClientEx())
            {
                var start = DateTime.Now;
                try
                {
                    var loggingMessagesToSend = new List<object>();

                    foreach (var loggingEvent in queuedLoggingEvents)
                        loggingMessagesToSend.Add(loggingEvent);

                    var json = Serialize.NewTownJsonHelper.SerializeWithFormatShowAll(loggingMessagesToSend);

                    // Add headers required to submit request and additional data
                    client.Headers.Add("X-ProjectKey", ProjectKey);
                    client.Headers.Add("X-Environment", Environment ?? System.Environment.MachineName);

                    // Set content type and encoding
                    client.Headers.Add("Content-Type", "application/json; charset=utf-8");
                    client.Encoding = System.Text.Encoding.UTF8;

                    client.Timeout = 10;

                    Debug.Write("Sending JSON data: " + json);


                    // up the payload
                    //client.UploadString(ServiceUrl, "POST", json);
                    client.UploadStringAsync(new Uri(ServiceUrl), "POST", json);
                    Debug.WriteLine("Sent collection of events: " + loggingMessagesToSend.Count);
                }
                catch (WebException ex)
                {
                    Debug.WriteLine("Error sending logging event to logmon dropoff {0}. Response data: {1}", ex.Message, ex.StackTrace);
                    throw;
                }
                finally
                {
                    Debug.WriteLine("Took " + ((DateTime.Now) - start).TotalMilliseconds + "ms to submit");
                }
            }
        }

        private LoggingEventModel createLoggingEventModel(LoggingEvent loggingEvent)
        {
            var loggingEventModel = new LoggingEventModel
            {
                user = string.IsNullOrWhiteSpace(loggingEvent.Identity) ? null : loggingEvent.Identity,
                logger = loggingEvent.LoggerName,
                level = loggingEvent.Level.Name.ToLower(),
                message = loggingEvent.RenderedMessage,
                time_stamp = loggingEvent.TimeStamp.ToUniversalTime().ToString("u")
            };


            // Grab stack trace
            if (null != loggingEvent.ExceptionObject && !string.IsNullOrWhiteSpace(loggingEvent.ExceptionObject.StackTrace))
                loggingEventModel.stack_trace = loggingEvent.ExceptionObject.StackTrace;

            // Attach additional http request data when available
            if (null != HttpContext.Current)
            {
                var context = HttpContext.Current;

                // For fatal and error attach headers and any form data
                var headers = new List<object>();
                var formParams = new List<object>();

                if (_logHttpForLevels.Contains(loggingEvent.Level.Name.ToLower()))
                {
                    foreach (var headerKey in context.Request.Headers.AllKeys)
                    {
                        var value = context.Request.Headers[headerKey];
                        if (!string.IsNullOrWhiteSpace(value))
                            headers.Add(new { key = headerKey, value });
                    }

                    if (context.Request.Form.Keys.Count > 0)
                    {
                        foreach (var key in context.Request.Form.AllKeys)
                        {
                            var value = context.Request.Form[key];
                            if (!string.IsNullOrWhiteSpace(value))
                                formParams.Add(new { key, value = context.Request.Form[key] });
                        }
                    }
                }

                loggingEventModel.http = new
                {
                    session_id = null != context.Session ? context.Session.SessionID : null,
                    current_user = string.IsNullOrWhiteSpace(context.User.Identity.Name) ? null : context.User.Identity.Name,
                    http_method = context.Request.HttpMethod,
                    url = context.Request.Url,
                    url_referrer = context.Request.UrlReferrer,
                    user_agent = context.Request.UserAgent,
                    user_host_address = context.Request.UserHostAddress,
                    user_host_name = context.Request.UserHostName,
                    authentication_type = string.IsNullOrWhiteSpace(context.User.Identity.AuthenticationType) ? null : context.User.Identity.AuthenticationType,
                    request_headers = headers.Count > 0 ? headers : null,
                    form_params = formParams.Count > 0 ? formParams : null
                };
            }

            return loggingEventModel;
        }

        private void enqueue(LoggingEvent loggingEvent)
        {
            lock (_lockObject)
            {
                Debug.WriteLine("Enqued " + loggingEvent.MessageObject);
                _queue.Enqueue(createLoggingEventModel(loggingEvent));
            }
        }

        private bool deQueue(out LoggingEventModel loggingEvent)
        {
            lock (_lockObject)
            {
                if (_queue.Count > 0)
                {
                    loggingEvent = _queue.Dequeue();
                    return true;
                }

                loggingEvent = null;
                return false;
            }
        }

        protected override void OnClose()
        {
            //set the OnClosing flag to true, so that
            //AppendLoggingEvents would know it is time to wrap up
            //whatever it is doing
            _onClosing = true;

            //wait till we receive signal from manualResetEvent
            //which is signalled from AppendLoggingEvents
            _manualResetEvent.WaitOne(TimeSpan.FromSeconds(5));
            //manualResetEvent.WaitOne();

            base.OnClose();
        }

    }
    public class LoggingEventModel
    {
        public string user { get; set; }
        public string logger { get; set; }
        public string level { get; set; }
        public string message { get; set; }
        public string stack_trace { get; set; }
        public string time_stamp { get; set; }
        public object http { get; set; } 
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值