.net 日志写RabbitMQ 整合netcore ILogger

NetCore 日志写RabbitMQ

using System;
using System.Collections.Concurrent;
using System.Configuration;
using System.IO;
using System.Text;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using RabbitMQ.Client;

using Timer = System.Timers.Timer;

namespace RabbitMQLog
{
    /// <summary>
    /// 日志写RabbitMQ工具类
    /// </summary>
    public class XRabbitMQLogHelper
    {
        #region 字段、属性、构造函数
        /// <summary>线程安全队列</summary>
        private static readonly ConcurrentQueue<RabbitMQLogModel> _que = new ConcurrentQueue<RabbitMQLogModel>();

        /// <summary>信号</summary>
        private static readonly ManualResetEvent _mre;

        /// <summary>日志级别</summary>
        private static LogLevelEnum logLevel = LogLevelEnum.Info;

        //RabbitMQClient
        private static IConnectionFactory mqFact;
        private static DateTime mqLastErrTime;
        private static Exception mqLastErr;

        private static String exchangeName;
        private static String routingKey;
        private static String queueName;

        private static Timer timer = new Timer(10 * 1000);

        /// <summary>构造函数</summary>
        static XRabbitMQLogHelper()
        {
            _mre = new ManualResetEvent(false);
            timer.Elapsed += Timer_Elapsed;
            timer.Start();

            //配置
            {
#if !netcoreapp
                {
                    //日志级别
                    var loglevelStr = ConfigurationManager.AppSettings["loglevel"];
                    if (!string.IsNullOrEmpty(loglevelStr))
                    {
                        var lltype = typeof(LogLevelEnum);
                        var flag = Enum.TryParse<LogLevelEnum>(loglevelStr, out var logLevel);
                        if (flag && Enum.IsDefined(lltype, logLevel))
                        {
                            XLogHelper.logLevel = logLevel;
                        }
                    }
                }
#endif
            }

            Task.Factory.StartNew(() => Initialize());
        }

        private static void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (mqLastErrTime.Year > 2000 && mqLastErrTime.AddSeconds(16) < DateTime.Now)
            {
                _mre.Set();
            }
        }
        #endregion

        /// <summary>
        /// 配置RabbitMQ
        /// </summary>
        /// <param name="factory"></param>
        /// <param name="exchangeName"></param>
        /// <param name="routingKey"></param>
        /// <param name="queueName"></param>
        public static void InitConfig(IConnectionFactory factory, String exchangeName, String routingKey, String queueName)
        {
            mqFact = factory;
            XRabbitMQLogHelper.exchangeName = exchangeName;
            XRabbitMQLogHelper.routingKey = routingKey;
            XRabbitMQLogHelper.queueName = queueName;

        }

        #region 信息日志
        /// <summary>日志,默认Info级别</summary>
        /// <param name="message">日志内容</param>
        /// <param name="logLevel"></param>
        public static void WriteLine(string message, String targetCls = "", LogLevelEnum logLevel = LogLevelEnum.Info, Exception ex = null)
        {
            try
            {
                if (logLevel < XRabbitMQLogHelper.logLevel) return;

                var threadId = Thread.CurrentThread.ManagedThreadId;
                var taskId = Task.CurrentId.HasValue ? Task.CurrentId.Value : -1;
                var m = FormatLog(threadId, taskId, logLevel, targetCls, message, ex);

                _que.Enqueue(m);
                _mre.Set();
            }
            catch
            {
            }
        }

        #endregion

        #region 私有方法/实体
        #region 日志初始化
        /// <summary>
        /// 日志初始化
        /// </summary>
        private static void Initialize()
        {
            while (true)
            {
                //等待信号通知
                _mre.WaitOne();
                //写入日志
                write();
                //重新设置信号
                _mre.Reset();
                Thread.Sleep(1);
            }
        }
        #endregion

        #region 写入日志
        /// <summary>
        /// 写入日志
        /// </summary>
        private static void write()
        {
            if (mqLastErrTime.Year > 2000 && mqLastErrTime.AddSeconds(10) > DateTime.Now) return;

            try
            {
                using (var conn = mqFact.CreateConnection(nameof(XRabbitMQLogHelper)))
                {
                    mqLastErrTime = DateTime.MinValue;
                    using (var channel = conn.CreateModel())
                    {
                        //开启生产者Ack
                        channel.ConfirmSelect();

                        var prop = channel.CreateBasicProperties();
                        prop.Persistent = true;

                        //prop.MessageId = msgID;
                        //prop.Timestamp = new AmqpTimestamp(timeStamp);

                        //开始生产消息
                        //判断日志队列中是否有内容,从列队中获取内容,并删除列队中的内容
                        while (_que.Any() && _que.TryDequeue(out var m))
                        {
                            var str = JsonNetHelper.SerializeObject(m);
                            var arr = str.ToByteArr();
                            //发布到MQ
                            channel.BasicPublish(exchangeName, routingKey, prop, arr);
                        }

                        //确认生产者ACK
                        if (!channel.WaitForConfirms())
                        {
                            throw new Exception("The message is not reached to the server!");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                mqLastErr = ex;
                mqLastErrTime = DateTime.Now;
            }

        }
        #endregion

        #endregion

        #region 辅助
        /// <summary>
        /// 格式化日志
        /// </summary>
        /// <param name="threadId"></param>
        /// <param name="taskId"></param>
        /// <param name="logEnum"></param>
        /// <param name="targetCls"></param>
        /// <param name="msg"></param>
        /// <param name="ex"></param>
        /// <returns></returns>
        public static RabbitMQLogModel FormatLog(int threadId, int taskId, LogLevelEnum logEnum, String targetCls, string msg, Exception ex = null)
        {
            var taskIdStr = taskId > -1 ? taskId + "" : "-";

            var now = DateTime.Now;
            var m = new RabbitMQLogModel()
            {
                CreateTime = now,

                ThreadID = threadId + "",
                TaskID = taskIdStr,

                LogLevel = logEnum + "",
                Source = targetCls,
                Message = msg,

            };

            if (ex != null)
            {
                var err = CreateErrorMessage(ex);

                m.Error = err;
            }

            //扩展字段
            //{
            //    var dic = new Dictionary<String, Object>();
            //    dic["Machine"] = Environment.MachineName;
            //    dic["PID"] = MyEnvironment.ProcessID;
            //    dic["SoftVer"] = MyEnvironment.Version;

            //    m.ExtProp = dic;
            //}

            return m;
        }

        /// <summary>
        /// 创建异常消息
        /// </summary>
        /// <param name="ex">异常信息</param>
        /// <param name="remark">备注</param>
        /// <returns>结果</returns>
        private static RabbitMQErrLogModel CreateErrorMessage(Exception ex)
        {
            var m = new RabbitMQErrLogModel();
            if (ex == null) return null;

            var iex = ex.InnerException;
            if (iex != null)
            {
                var im = new RabbitMQErrLogModel()
                {
                    ErrType = iex.GetType().FullName,
                    Message = iex.Message,
                    Source = iex.Source,
                    StackTrace = iex.StackTrace,
                };

                m.InnerErr = im;
            }

            m.ErrType = ex.GetType().FullName;
            m.Message = ex.Message;
            m.Source = ex.Source;
            m.StackTrace = ex.StackTrace;

            return m;
        }
        #endregion

    }

    public class RabbitMQLogModel
    {
        public DateTime CreateTime { get; set; }

        public String ThreadID { get; set; }
        public String TaskID { get; set; }

        public String LogLevel { get; set; }
        public String Source { get; set; }
        public String Message { get; set; }
        public RabbitMQErrLogModel Error { get; set; }

        /// <summary>扩展</summary>
        public IDictionary<String, Object> ExtProp { get; set; }
        //机器名、进程ID、软件版本
        //public String MachineName { get; set; } = Environment.MachineName;
        //public Int32 ProcessID { get; set; } = MyEnvironment.ProcessID;
        //public String SoftVersion { get; set; } = MyEnvironment.Version;
    }

    public class RabbitMQErrLogModel
    {
        public String ErrType { get; set; }
        public String Message { get; set; }
        public String Source { get; set; }
        public String StackTrace { get; set; }

        public RabbitMQErrLogModel InnerErr { get; set; }

        /// <summary></summary>
        /// <returns></returns>
        public override string ToString()
        {
            return $"Err:{ErrType} {Message} {Source} {StackTrace} {InnerErr}";
        }
    }

}

整合ILogger

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using RabbitMQ.Client;

namespace RabbitMQLog
{
    /// <summary>
    /// 
    /// </summary>
    public class MyRabbitMQLogger : ILogger
    {
        private readonly string categoryName;
        private readonly MyRabbitMQLoggerProviderOptions option;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="categoryName"></param>
        /// <param name="factory"></param>
        /// <param name="option"></param>
        public MyRabbitMQLogger(string categoryName, IConnectionFactory factory, MyRabbitMQLoggerProviderOptions option)
        {
            (this.categoryName, this.option) = (categoryName, option);

            if (option != null)
            {
                XRabbitMQLogHelper.InitConfig(factory, option.ExchangeName, option.RoutingKey, option.QueueName);
            }
        }

        public IDisposable BeginScope<TState>(TState state)
        {
            return null;
        }

        public bool IsEnabled(LogLevel logLevel)
        {
            return true;
        }

        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
        {
            var msg = formatter(state, exception);
            switch (logLevel)
            {
                case LogLevel.Trace:
                case LogLevel.Debug:
                    XRabbitMQLogHelper.WriteLine(msg, categoryName, LogLevelEnum.Debug);
                    break;
                case LogLevel.Information:
                    XRabbitMQLogHelper.WriteLine(msg, categoryName, LogLevelEnum.Info);
                    break;
                case LogLevel.Warning:
                    XRabbitMQLogHelper.WriteLine(msg, categoryName, LogLevelEnum.Warn);
                    break;
                case LogLevel.Error:
                    XRabbitMQLogHelper.WriteLine(msg, categoryName, LogLevelEnum.Error, exception);
                    break;
                case LogLevel.Critical:
                    XRabbitMQLogHelper.WriteLine(msg, categoryName, LogLevelEnum.Fatal, exception);
                    break;
                case LogLevel.None:
                default:
                    break;
            }


            //var msg = $"{logLevel}::{this.categoryName}::{formatter(state, exception)}::{DateTime.Now}";

            //using (var writer = File.AppendText(this.path))
            //{
            //    writer.WriteLine(msg);
            //}
        }


    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using RabbitMQ.Client;

namespace RabbitMQLog
{
    public class MyRabbitMQLoggerProvider : ILoggerProvider
    {
        private IConnectionFactory factory;
        private MyRabbitMQLoggerProviderOptions option;

        public MyRabbitMQLoggerProvider(IConnectionFactory factory, MyRabbitMQLoggerProviderOptions option)
        {
            this.factory = factory;
            this.option = option;
        }

        public ILogger CreateLogger(string categoryName)
        {
            return new MyRabbitMQLogger(categoryName, this.factory, this.option);
        }

        public void Dispose()
        {

        }

    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace RabbitMQLog
{
    /// <summary>
    /// 
    /// </summary>
    public class MyRabbitMQLoggerProviderOptions
    {
        /// <summary></summary>
        public String HostName { get; set; }
        /// <summary></summary>
        public Int32 Port { get; set; }
        /// <summary></summary>
        public String UserName { get; set; }
        /// <summary></summary>
        public String Password { get; set; }
        /// <summary></summary>
        public String VirtualHost { get; set; }


        /// <summary></summary>
        public String ExchangeName { get; set; }
        /// <summary></summary>
        public String QueueName { get; set; }
        /// <summary></summary>
        public String RoutingKey { get; set; }

    }
}
{
     "RabbitMQLogger": {
    "HostName": "vmdev.hhh.xyz",
    "Port": 5672,
    "UserName": "root",
    "Password": "123",
    "VirtualHost": "log",

    "ExchangeName": "applog",
    "QueueName": "qqq",
    "RoutingKey": "qqq"
  }  
}

netcore 注入

.ConfigureServices((hostContext, services) =>
{
    services.AddHttpClient();

    services.AddTransient<IMyService, MyService>();

    {
        var cfg = hostContext.Configuration.GetSection(ConfigConsts.RABBITMQ_Log_CONFIG);
        var mqCfg = cfg.Get<MyRabbitMQLoggerProviderOptions>();
        var cf = new ConnectionFactory()
        {
            HostName = mqCfg.HostName,
            Port = mqCfg.Port,

            UserName = mqCfg.UserName,
            Password = mqCfg.Password,

            VirtualHost = mqCfg.VirtualHost,
        };

        cf.HandshakeContinuationTimeout = TimeSpan.FromSeconds(15);

        RabbitMQTools.Init(cf);

        services.AddSingleton(cf);
    }

    services.AddHostedService<LogToRabbitMQHostService>();
})
.ConfigureLogging(logbuild =>
{
    logbuild.ClearProviders();
    //logbuild.AddConsole();
    //logbuild.SetMinimumLevel(LogLevel.Debug);//控制全部的日志输出
    //logbuild.AddNLog();

    // 注入 AddMyRabbitMQLog
    using (var sp = logbuild.Services.BuildServiceProvider())
    {
        var mqFact2 = sp.GetServices<ConnectionFactory>();
        var mqFact = mqFact2.First(d => d.VirtualHost.EqualIgnoreCase(RabbitMQConst.DEFAULT_LOG_VIRTUALHOST));
        var option = sp.GetService<IConfiguration>().GetSection(ConfigConsts.RABBITMQ_Log_CONFIG).Get<MyRabbitMQLoggerProviderOptions>();

        logbuild.AddMyRabbitMQLog(mqFact, option);
    }
})

over

原文地址:https://www.cnblogs.com/huawublog/p/14510191.html