基于rabbitmq的日志系统(.NET和java)

很多年不写博客了,希望写一些东西总结总结。
我从2011年开始做工业软件生产执行系统架构,2016年对整体架构进行重新规划和重构。

我们MES架构中关于日志模块的设计思路,接下来我会介绍在MES业务下Java和MongoDB的一些思路总结

架构采用WebAPI,日志采用log4,中间用RabbitMQ进行分流,架构图如下:
基于rabbitmq的日志系统(.NET和java)_第1张图片
框架采用MEF+Autofac的IOC框架,每个二次开发部分采用插件形式进行扩展开发,需要进行日志的项目统一引用MQProxy代理项目,通过代理项目采用WCF方式传输到MQHandler项目(127.0.0.1:9005),然后MQHandler调用各自方法(操作日志、异常日志、其它)放到RabbitMQ服务中;然后独立一个LogHandler服务(日志处理项目Windows服务)定时从RabbitMQ服务获取数据分量调用log4开源框架写入到txt文件中。
框架由于大数据的原因,覆写Java客户端,也往RabbitMQ服务写入消息,同样用上面的LogHandler服务进行日志的写入。


调用MQProxy项目,一句话输出日志:

//错误日志调用如下:
ClientMQProxy.Instance().SendErrorLog("Department/QueryMenu:" + ex.Message.ToString(), new StackTrace(new StackFrame(true)));

//异常日志调用如下:
ClientMQProxy.Instance().SendInfoLog("Department/QueryMenu:");

IPlugin接口


MQProxy项目

internal interface IClientMQProxy
{
    /// 
    /// 同步发送错误日志数据信息
    /// 
    /// 传输日志内容对象
    /// 堆栈跟踪对象
    void SendErrorLog(string strlogDataTransmissionObj, StackTrace stackTrace);

    /// 
    /// 同步发送错误日志数据信息
    /// 
    /// 传输日志内容对象
    void SendErrorLog(string strlogDataTransmissionObj);

    /// 
    /// 同步发送操作日志数据信息
    /// 
    /// 传输操作日志内容对象
    void SendInfoLog(string strInfoDataTransmissionObj);
}

public class ClientMQProxy : IClientMQProxy
{
    /// 
    /// Http绑定元素
    /// 
    static BasicHttpBinding HttpBind { get; set; }

    /// 
    /// “日志数据消息”契约接口抽象对象
    /// 
    IPlugin.IMQProxy iMQProxy;

    /// 
    /// 静态实例对象
    /// 
    static ClientMQProxy instace = null;

    /// 
    ///
    /// 
    static readonly object padlock = new object();

    /// 
    /// 静态实例方法(返回静态字段)
    /// 
    public static ClientMQProxy Instance()
    {
        lock (padlock)
        {
            if (instace == null)
            {
                instace = new ClientMQProxy();
                HttpBind = MQProxyTransferConfig.BasicHttpBinding_Text(HttpBind, new XmlDictionaryReaderQuotas());
                instace.RunService("http://127.0.0.1:9005");
            }
            return instace;
        }
    }

    /// 
    /// 根据“服务类型”来进行服务的启动
    /// 
    /// 需要连入的日志服务地址
    void RunService(string strEndpointAddress)
    {
        try
        {
            //增加服务的同时,添加到字典里
            iMQProxy = DataBind(HttpBind, strEndpointAddress);
        }
        catch{ }
    }

    /// 
    /// 客户端发送错误日志调用方法
    /// 
    /// 
    public void SendInfoLog(string strInfoDataTransmissionObj)
    {
        if (string.IsNullOrWhiteSpace(strInfoDataTransmissionObj))
            return;

        StringBuilder sb = new StringBuilder();
        sb.Append(strInfoDataTransmissionObj);

        string strErrorMsg = "";
        try
        {
            //申明传输消息体对象
            MsgDataTransmissionObj dto = new MsgDataTransmissionObj();
            //序列化发送到服务端
            MemoryStream memStream = Serialize(sb.ToString(), out strErrorMsg);
            dto.DataContent = memStream;
            if (iMQProxy != null)//发送消息体
                iMQProxy.SendInfoMessage(dto);
        }
        catch (Exception ex)
        {
            string strTempStackTrace = "";
            if (ex.StackTrace != null)
                strTempStackTrace = "\r\n错误点:" + ex.StackTrace.ToString() + strErrorMsg;
        }
    }

    /// 
    /// 客户端发送错误日志调用方法
    /// 
    /// 日志数据传输对象
    /// 堆栈跟踪对象,调用示例: new StackTrace(new StackFrame(true))
    public void SendErrorLog(string strLogDataTransmissionObj, StackTrace stackTrace)
    {
        StringBuilder sb = new StringBuilder();

        if (stackTrace != null && stackTrace.FrameCount > 0)
        {
            StackFrame sf = stackTrace.GetFrame(0);
            string strTraceFileName = sf.GetFileName();//获取包含所执行代码的文件名
            string strTraceMethodName = sf.GetMethod().Name;//获取出错的方法名
            string strTraceCodeLineNum = sf.GetFileLineNumber().ToString();//获取出错的代码的行号
            string strTraceCodeColNum = sf.GetFileColumnNumber().ToString();//获取出错的代码的列号

            //拼接堆栈跟踪信息
            sb.Append("Trace DateTime:");
            sb.Append(DateTime.Now.Year.ToString() + "-" +
                DateTime.Now.Month.ToString("00") + "-" +
                DateTime.Now.Day.ToString("00") + " " +
                DateTime.Now.Hour.ToString("00") + ":" +
                DateTime.Now.Minute.ToString("00") + ":" +
                DateTime.Now.Second.ToString("00") + "\r\n");
            sb.Append("Trace File Name:" + strTraceFileName + "\r\n");
            sb.Append("Trace Method Name:" + strTraceMethodName + "\r\n");
            sb.Append("Trace Code Line Num:" + strTraceCodeLineNum + "\r\n");
            sb.Append("Trace Code Column Num:" + strTraceCodeColNum + "\r\n");
        }
        sb.Append("Trace Log Message:" + strLogDataTransmissionObj + "\r\n");

        string strErrorMsg = "";
        try
        {
            //申明传输消息体对象
            MsgDataTransmissionObj dto = new MsgDataTransmissionObj();

            //序列化发送到服务端
            MemoryStream memStream = Serialize(sb.ToString(), out strErrorMsg);

            dto.DataContent = memStream;

            if (iMQProxy != null)//发送消息体
                iMQProxy.SendErrorMessage(dto);
        }
        catch (Exception ex)
        {
            string strTempStackTrace = "";

            if (ex.StackTrace != null)
                strTempStackTrace = "\r\n错误点:" + ex.StackTrace.ToString() + strErrorMsg;
        }
    }

    /// 
    /// 客户端发送错误日志调用方法
    /// 
    /// 日志数据传输对象
    public void SendErrorLog(string strLogDataTransmissionObj)
    {
        if (string.IsNullOrWhiteSpace(strLogDataTransmissionObj))
            return;

        string strErrorMsg = "";
        try
        {
            //申明传输消息体对象
            MsgDataTransmissionObj dto = new MsgDataTransmissionObj();

            //序列化发送到服务端
            MemoryStream memStream = Serialize(strLogDataTransmissionObj, out strErrorMsg);

            dto.DataContent = memStream;

            if (iMQProxy != null)//发送消息体
                iMQProxy.SendErrorMessage(dto);
        }
        catch (Exception ex)
        {
            string strTempStackTrace = "";

            if (ex.StackTrace != null)
                strTempStackTrace = "\r\n错误点:" + ex.StackTrace.ToString() + strErrorMsg;
        }
    }

    /// 
    /// “数据消息”绑定
    /// 
    /// 绑定元素对象
    /// 端节点地址
    /// 
    IMQProxy DataBind(System.ServiceModel.Channels.Binding binding, string str_EndpointAddress)
    {
        //创建通道
        ChannelFactory channelFactory = new ChannelFactory(binding, str_EndpointAddress);
        IPlugin.IMQProxy iDataContract = channelFactory.CreateChannel();

        channelFactory.Closing += new EventHandler(channelFactory_Closing);
        channelFactory.Faulted += new EventHandler(channelFactory_Faulted);

        return iDataContract;
    }
}

MQHandler项目

//日志Host启动WCF服务类
internal sealed class RunSelfHostLog
{
    /// 
    /// 端节点地址
    /// 
    string strBaseAddress { get; set; }

    /// 
    /// 启动Windows服务名称
    /// 
    string strSrvName { get; set; }

    /// 
    /// 构造
    /// 
    /// 地址
    /// 服务名称
    public RunSelfHostLog(string strBaseAddress, string strSrvName)
    {
        this.strBaseAddress = strBaseAddress;
        this.strSrvName = strSrvName;
    }

    /// 
    /// 创建服务,并打开
    /// 
    /// 错误消息
    internal bool Run(out string strErrorMsg)
    {
        strErrorMsg = "";

        //需要创建的承载日志的wcf服务类型
        Type type = typeof(MQService);

        //绑定元素对象
        Binding binding = new BasicHttpBinding();

        //终结点实现的协议
        Type objContract = typeof(IPlugin.IMQProxy);

        try
        {
            Uri uri = new Uri(strBaseAddress);
        }
        catch
        {
            strErrorMsg = "创建【" + strSrvName + "】服务指定的地址:【" + strBaseAddress + "】有错误";

            //调用消息框架发送日志
            MQBase mqBase = new MQBase();
            mqBase.SendErrorLogMessage(strErrorMsg);

            return false;
        }

        try
        {
            ServiceHost serviceHost = new ServiceHost(type);

            BasicHttpBinding httpBind = (BasicHttpBinding)binding;                
            httpBind = MQProxyTransferConfig.BasicHttpBinding_Text(httpBind, new XmlDictionaryReaderQuotas());
            serviceHost.AddServiceEndpoint(objContract, httpBind, strBaseAddress);

            serviceHost.Open();

            return true;
        }
        catch (Exception ee)
        {
            //调用消息框架发送日志
            MQBase mqBase = new MQBase();
            mqBase.SendErrorLogMessage(ee.Message.ToString());
            new LogErrorHandler(ee.Message.ToString());
            return false;
        }
    }
}

//启动Program
sealed class Program
{
    /// 
    /// 程序运行
    /// 
    private static void ExeRun()
    {
        Common.ExeRunTootip();

        RunCode();
    }

    /// 
    /// 服务运行
    /// 
    private static void SrvRun()
    {
        Common.SrvRunTootip();

        ServiceBase[] ServicesToRun;

        ServicesToRun = new ServiceBase[] { new Service() };

        ServiceBase.Run(ServicesToRun);
    }

    internal static void RunCode()
    {
        string strErrorMsg = "";

        //调用消息框架发送日志
        new LogInfoHandler(DateTime.Now.ToString() + "初始化MES.Service.MQHandler RunCode()");

        RunSelfHostLog runLogSelfHost = new RunSelfHostLog("http://127.0.0.1:9005", "MES_MQHandler");
        if (runLogSelfHost.Run(out strErrorMsg))
        {
            //启动日志服务成功
            strErrorMsg = "服务(service):【MES_MQHandler】已经启动(Has been launched)\n" +
                "地址(service address):【http://127.0.0.1:9005】\n" +
                "**************************************************\n";

            //调用消息框架发送日志
            new LogInfoHandler(strErrorMsg);
        }
        else
        {
            //启动日志服务失败
            strErrorMsg = "MES_MQHandler服务未启动(The service did not start)\n错误信息(The error message):" + strErrorMsg;

            //调用消息框架发送日志
            new LogErrorHandler(strErrorMsg);
        }

        Common.PrintTootip(strErrorMsg);
    }
}

//实现IMQProxy接口的服务实例类,接收所有从127.0.0.1:9005发送的消息,然后分发给异常、操作、其它的处理方式
[ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = InstanceContextMode.PerCall)]//单会话
sealed class MQService : IMQProxy
{
    /// 
    /// 通过WCF服务接收到代理提交的异常日志内容
    /// 
    /// 传输消息体对象
    public void SendErrorMessage(MsgDataTransmissionObj msgDto)
    {
        try
        {
            string strLogContent = Desrialize<string>(typeof(string), msgDto.DataContent);
            if (!string.IsNullOrWhiteSpace(strLogContent))
                new LogErrorHandler(strLogContent);
        }
        catch (Exception ex)
        {
            string strTmp = "";
            if (ex.InnerException != null)
                strTmp = ex.InnerException.Message.ToString();
            else
                strTmp = ex.Message.ToString();

            new LogErrorHandler(strTmp);
        }
    }

    /// 
    /// 通过WCF服务接收到代理提交的操作日志内容
    /// 
    /// 传输消息体对象
    public void SendInfoMessage(MsgDataTransmissionObj msgDto)
    {
        try
        {
            string strLogContent = Desrialize<string>(typeof(string), msgDto.DataContent);
            if (!string.IsNullOrWhiteSpace(strLogContent))
                new LogInfoHandler(strLogContent);
        }
        catch (Exception ex)
        {
            string strTmp = "";
            if (ex.InnerException != null)
                strTmp = ex.InnerException.Message.ToString();
            else
                strTmp = ex.Message.ToString();

            new LogErrorHandler(strTmp);
        }
    }

    /// 
    /// 反序列化 内存流对象到对象
    /// 
    /// 类型对象
    /// 要转换为对象的内存流对象
    /// 错误信息
    /// 反序列化出来的对象
    public static T Desrialize(Type obj, MemoryStream memoryStream)
    {
        DataContractSerializer dataContractSerializer = new DataContractSerializer(obj);//序列化对象
        memoryStream.Position = 0;//归为偏移为0
        T iBusMessage = (T)dataContractSerializer.ReadObject(memoryStream);

        return iBusMessage;
    }
}


分给如下3个类(LogErrorHandler.cs、LogInfoHandler.cs、其它)进行处理:


/// 
/// 消息服务端接受到代理发送的异常日志消息后进行处理
/// 
public class LogErrorHandler
{
    /// 
    /// 异常日志处理
    /// 
    /// 
    public LogErrorHandler(string strLogInfo)
    {
        if (string.IsNullOrWhiteSpace(strLogInfo))
            return;

        try
        {
            if (!SaveLogTimer.Enabled)//定时器没运行,运行定时器
            {
                SaveLogTimer.Enabled = true;
                ScheduleTimer();
            }

            //调发送日志的方法
            if (SaveLogList != null)
                SaveLogList.Enqueue(strLogInfo.ToString());
        }
        catch
        { }
    }

    /// 
    /// 保存到db的时间组件
    /// 
    static System.Timers.Timer SaveLogTimer = new System.Timers.Timer();

    /// 
    /// 需要保存的日志列表
    ///         
    static Queue SaveLogList = new Queue();

    /// 
    /// 保存日志信息
    /// 
    internal static void ScheduleTimer()
    {
        //发布监听定时器初始化设置
        SaveLogTimer.Enabled = true;//启动定时器
        SaveLogTimer.Interval = 90000;//时间间隔为20秒钟
        SaveLogTimer.Elapsed += new ElapsedEventHandler((timeO, timeE) =>
        {
            string strErrorMsg = "";
            string strTempStackTrace = "";

            while (SaveLogList.Count > 0)
            {
                try
                {
                    var strTmp = SaveLogList.ToArray();
                    SaveLogList.Clear();
                    foreach (string data in strTmp)
                    {
                        if (!string.IsNullOrWhiteSpace(data))
                        {
                            Console.WriteLine(data);
                            //调用消息框架发送日志
                            MQBase mqBase = new MQBase();
                            mqBase.SendErrorLogMessage(data);
                        }
                    }
                }
                catch (Exception ex)
                {
                    if (ex.StackTrace != null)
                        strTempStackTrace = "\r\n错误点:" + ex.StackTrace.ToString() + strErrorMsg;

                    //调用消息框架发送日志
                    MQBase mqBase = new MQBase();
                    mqBase.SendErrorLogMessage(strTempStackTrace);
                }
            }
        });
        SaveLogTimer.Start();
    }
}

/// 
/// 消息服务端接受到代理发送的操作日志消息后进行处理
/// 
public class LogInfoHandler
{
    /// 
    /// 异常日志处理
    /// 
    /// 
    public LogInfoHandler(string strLogInfo)
    {
        if (string.IsNullOrWhiteSpace(strLogInfo))
            return;

        if (Program.IsRunOptLog == "0")//不运行操作日志
            return;

        try
        {
            if (!SaveLogTimer.Enabled)//定时器没运行,运行定时器
            {
                SaveLogTimer.Enabled = true;
                ScheduleTimer();
            }

            //调发送日志的方法              
            if (SaveLogList != null)
                SaveLogList.Enqueue(strLogInfo.ToString());
        }
        catch
        { }
    }

    /// 
    /// 保存到db的时间组件
    /// 
    static System.Timers.Timer SaveLogTimer = new System.Timers.Timer();

    /// 
    /// 需要保存的日志列表
    ///         
    static Queue SaveLogList = new Queue();

    /// 
    /// 保存日志信息
    /// 
    internal static void ScheduleTimer()
    {
        //发布监听定时器初始化设置
        SaveLogTimer.Enabled = true;//启动定时器
        SaveLogTimer.Interval = 10000;//时间间隔为20秒钟
        SaveLogTimer.Elapsed += new ElapsedEventHandler((timeO, timeE) =>
        {
            string strErrorMsg = "";
            string strTempStackTrace = "";

            while (SaveLogList.Count > 0)
            {
                try
                {
                    var strTmp = SaveLogList.ToArray();
                    SaveLogList.Clear();
                    foreach (string data in strTmp)
                    {
                        if (!string.IsNullOrWhiteSpace(data))
                        {
                            //调用消息框架发送日志
                            MQBase mqBase = new MQBase();
                            mqBase.SendInfoLogMessage(data);
                        }
                    }
                }
                catch (Exception ex)
                {
                    if (ex.StackTrace != null)
                        strTempStackTrace = "\r\n错误点:" + ex.StackTrace.ToString() + strErrorMsg;

                    //调用消息框架发送日志
                    MQBase mqBase = new MQBase();
                    mqBase.SendErrorLogMessage(strTempStackTrace);
                }
            }
        });
        SaveLogTimer.Start();
    }
}

这两个类都调用如下的MQBase类统一处理到RabbitMQ服务:
internal class MQBase
{
    /// 
    /// 用于发送消息的Connection
    /// 
    internal IConnection SendConnection { get; set; }

    /// 
    /// 用于发送消息的Channel
    /// 
    internal IModel SendChannel { get; set; }

    /// 
    /// ip地址:172.21.34.23
    /// 
    static string HostName { get; set; }

    /// 
    /// 端口
    /// 
    static int Port { get; set; }

    /// 
    /// 用户名
    /// 
    static string UserName { get; set; }

    /// 
    /// 密码
    /// 
    static string Password { get; set; }

    /// 
    /// 心跳超时时间(默认60)
    /// 
    static ushort heartbeat { get; set; }

    /// 
    /// 异常日志消息:发布端指定消息交换机名称
    /// 
    internal const string exchange_ErrorLog = "exchange_ErrorLog";

    /// 
    /// 异常日志消息:Queue的name为:Queue_ErrorLog
    /// 
    internal const string Queue_ErrorLog = "Queue_ErrorLog";

    /// 
    /// 异常日志消息:routingKey = "routingKey_ErrorLog",绑定到Queue_ErrorLog上
    /// 
    internal const string routingKey_ErrorLog = "routingKey_ErrorLog";

    /// 
    /// 操作日志消息:发布端指定消息交换机名称
    /// 
    internal const string exchange_InfoLog = "exchange_InfoLog";

    /// 
    /// 操作日志消息:Queue的name为:Queue_InfoLog
    /// 
    internal const string Queue_InfoLog = "Queue_InfoLog";

    /// 
    /// 操作日志消息:routingKey = "routingKey_InfoLog",绑定到Queue_InfoLog上
    /// 
    internal const string routingKey_InfoLog = "routingKey_InfoLog";

    /// 
    /// RMIS消息:routingKey = "routingKey_ErrorLog",绑定到Queue_ErrorLog上
    /// 
    internal const string routingKey_RMISData = "routingKey_RMISData";

    public MQBase() { }

    /// 
    /// 构造
    /// 
    /// ip地址:172.21.34.23
    /// 端口:默认5672
    /// 用户名(mesmq)
    /// 密码(mesmq)
    public MQBase(string HostName, int Port, string UserName, string Password, ushort heartbeat)
    {                       
        MQBase.HostName = HostName;
        MQBase.Port = Port;
        MQBase.UserName = UserName;
        MQBase.Password = Password;
        MQBase.heartbeat = heartbeat;
    }

    /// 
    /// 创建一个IConnection
    /// 
    /// 
    internal static IConnection CreateConnection()
    {
        try
        {
            //创建连接对象
            var SendConnection = new ConnectionFactory()
            {
                HostName = HostName,
                Port = Port,
                UserName = UserName,
                Password = Password,
                RequestedHeartbeat = heartbeat,//心跳超时时间
                AutomaticRecoveryEnabled = true//自动重连
            };
            return SendConnection.CreateConnection();
        }
        catch
        {
            return null;
        }
    }

    /// 
    /// 发送RMIS data消息到RabbitMQ
    /// 
    /// 消息内容
    /// RMIS消息:Queue的name
    /// 
    public bool SendRmisDataMessage(string strRmisDataContent, string Queue_RMISData)
    {
        if (string.IsNullOrWhiteSpace(strRmisDataContent))
            return false;

        try
        {
            using (SendConnection = CreateConnection())//建立链接
            {
                using (SendChannel = SendConnection.CreateModel())//创建channel
                {
                    //定义消息交换机为匹配key模式,如果 routing key 匹配, 那么Message就会被传递到相应的queue中。
                    SendChannel.ExchangeDeclare("exchange_" + Queue_RMISData, "direct");

                    SendChannel.QueueDeclare(Queue_RMISData, true, false, false, null);//添加Queue_ErrorLog到队列

                    var properties = SendChannel.CreateBasicProperties();
                    properties.Persistent = true;//需要持久化Message,即在Publish的时候指定一个properties
                    properties.Expiration = "60000";

                    //通过绑定将指定的添加queue_name_1的队列、相同的RoutingKey名称使用Direct的Exchange方式进行关联
                    SendChannel.QueueBind(Queue_RMISData,//队列名
                                      "exchange_" + Queue_RMISData,//消息交换机名
                                      routingKey_RMISData);//指定routingKey

                    //Producer只能发送到exchange,它是不能直接发送到queue的
                    SendChannel.BasicPublish("exchange_" + Queue_RMISData,//发给指定的Exchange 
                                         routingKey_RMISData,//指定routing key只有匹配的可以收到
                                         properties,//指定基本属性 
                                         Encoding.UTF8.GetBytes(strRmisDataContent));
                }
            }
            return true;
        }
        catch
        {
            return false;
        }
    }

    /// 
    /// 发送操作日志消息到RabbitMQ
    /// 
    /// 日志内容
    /// 
    public bool SendInfoLogMessage(string strLogContent)
    {
        if (string.IsNullOrWhiteSpace(strLogContent))
            return false;

        try
        {
            using (SendConnection = CreateConnection())//建立链接
            {
                using (SendChannel = SendConnection.CreateModel())//创建channel
                {
                    //定义消息交换机为匹配key模式,如果 routing key 匹配, 那么Message就会被传递到相应的queue中。
                    SendChannel.ExchangeDeclare(exchange_InfoLog, "direct");

                    SendChannel.QueueDeclare(Queue_InfoLog, true, false, false, null);//添加Queue_ErrorLog到队列

                    var properties = SendChannel.CreateBasicProperties();
                    properties.Persistent = true;//需要持久化Message,即在Publish的时候指定一个properties

                    //通过绑定将指定的添加queue_name_1的队列、相同的RoutingKey名称使用Direct的Exchange方式进行关联
                    SendChannel.QueueBind(Queue_InfoLog,//队列名
                                      exchange_InfoLog,//消息交换机名
                                      routingKey_InfoLog);//指定routingKey

                    var body = Encoding.UTF8.GetBytes(strLogContent);

                    //Producer只能发送到exchange,它是不能直接发送到queue的
                    SendChannel.BasicPublish(exchange_InfoLog,//发给指定的Exchange 
                                         routingKey_InfoLog,//指定routing key只有匹配的可以收到
                                         properties,//指定基本属性 
                                         body);
                }
            }
            return true;
        }
        catch
        {
            return false;
        }
    }

    /// 
    /// 发送异常日志消息到RabbitMQ
    /// 
    /// 日志内容
    /// 
    public bool SendErrorLogMessage(string strLogContent)
    {
        if (string.IsNullOrWhiteSpace(strLogContent))
            return false;

        try
        {
            using (SendConnection = CreateConnection())//建立链接
            {
                using (SendChannel = SendConnection.CreateModel())//创建channel
                {
                    //定义消息交换机为匹配key模式,如果 routing key 匹配, 那么Message就会被传递到相应的queue中。
                    SendChannel.ExchangeDeclare(exchange_ErrorLog, "direct");

                    SendChannel.QueueDeclare(Queue_ErrorLog, true, false, false, null);//添加Queue_ErrorLog到队列

                    var properties = SendChannel.CreateBasicProperties();
                    properties.Persistent = true;//需要持久化Message,即在Publish的时候指定一个properties

                    //通过绑定将指定的添加queue_name_1的队列、相同的RoutingKey名称使用Direct的Exchange方式进行关联
                    SendChannel.QueueBind(Queue_ErrorLog,//队列名
                                      exchange_ErrorLog,//消息交换机名
                                      routingKey_ErrorLog);//指定routingKey

                    var body = Encoding.UTF8.GetBytes(strLogContent);

                    //Producer只能发送到exchange,它是不能直接发送到queue的
                    SendChannel.BasicPublish(exchange_ErrorLog,//发给指定的Exchange 
                                         routingKey_ErrorLog,//指定routing key只有匹配的可以收到
                                         properties,//指定基本属性 
                                         body);
                }
            }
            return true;
        }
        catch
        {
            return false;
        }
    }

    /// 
    /// 从RabbitMQ处理日志消息
    /// 
    /// 
    public bool HandlerLogMessage()
    {
        using (SendConnection = CreateConnection())//建立链接
        {
            using (SendChannel = SendConnection.CreateModel())//创建channel
            {
                //定义消息交换机为匹配key模式,如果 routing key 匹配, 那么Message就会被传递到相应的queue中。
                SendChannel.ExchangeDeclare(exchange_ErrorLog, "direct");//接收端如果关闭之后,自动创建的Queue会自动被删

                SendChannel.QueueDeclare(Queue_ErrorLog, true, false, false, null);

                //通过绑定将不同的Queue名称、相同的Routing Key名称采用Direct的Exchange方式进行关联
                SendChannel.QueueBind(Queue_ErrorLog, exchange_ErrorLog, routingKey_ErrorLog);

                Console.WriteLine(" [*] Waiting for messages. " + "To exit press CTRL+C");

                var consumer = new QueueingBasicConsumer(SendChannel);
                SendChannel.BasicConsume(Queue_ErrorLog, true, consumer);
                Console.WriteLine(" Consumer1开始");

                while (true)
                {
                    var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();

                    var body = ea.Body;
                    var message = Encoding.UTF8.GetString(body);
                    Console.WriteLine(" Consumer1接收queueName【测试direct_queue_name_1】的消息是:{0},", message);
                    Console.WriteLine(" Consumer1接收完成");
                }
            }
        }
    }
}

LogHandler日志处理项目,从RabbitMQ服务接收数据,通过定时器定时调用log4写入到txt中:

internal class MQBase
{
    /// 
    /// 用于发送消息的Connection
    /// 
    internal IConnection SendConnection { get; set; }

    /// 
    /// 用于发送消息的Channel
    /// 
    internal IModel SendChannel { get; set; }

    /// 
    /// ip地址:172.21.34.23
    /// 
    static string HostName { get; set; }

    /// 
    /// 端口
    /// 
    static int Port { get; set; }

    /// 
    /// 用户名
    /// 
    static string UserName { get; set; }

    /// 
    /// 密码
    /// 
    static string Password { get; set; }

    /// 
    /// 心跳超时时间(默认60)
    /// 
    static ushort heartbeat { get; set; }

    /// 
    /// 异常日志消息:发布端指定消息交换机名称
    /// 
    internal const string exchange_ErrorLog = "exchange_ErrorLog";

    /// 
    /// 异常日志消息:Queue的name为:Queue_ErrorLog
    /// 
    internal const string Queue_ErrorLog = "Queue_ErrorLog";

    /// 
    /// 异常日志消息:routingKey = "routingKey_ErrorLog",绑定到Queue_ErrorLog上
    /// 
    internal const string routingKey_ErrorLog = "routingKey_ErrorLog";

    /// 
    /// 操作日志消息:发布端指定消息交换机名称
    /// 
    internal const string exchange_InfoLog = "exchange_InfoLog";

    /// 
    /// 操作日志消息:Queue的name为:Queue_InfoLog
    /// 
    internal const string Queue_InfoLog = "Queue_InfoLog";

    /// 
    /// 操作日志消息:routingKey = "routingKey_InfoLog",绑定到Queue_InfoLog上
    /// 
    internal const string routingKey_InfoLog = "routingKey_InfoLog";

    public MQBase() { }

    /// 
    /// 构造
    /// 
    /// ip地址:172.21.34.23
    /// 端口:默认5672
    /// 用户名(mesmq)
    /// 密码(mesmq)
    public MQBase(string HostName, int Port, string UserName, string Password, ushort heartbeat)
    {
        MQBase.HostName = HostName;
        MQBase.Port = Port;
        MQBase.UserName = UserName;
        MQBase.Password = Password;
        MQBase.heartbeat = heartbeat;

    }

    /// 
    /// 创建一个IConnection
    /// 
    /// 
    internal static IConnection CreateConnection()
    {
        try
        {
            //创建连接对象
            var SendConnection = new ConnectionFactory()
            {  
                HostName = HostName,
                Port = Port,
                UserName = UserName,
                Password = Password,
                RequestedHeartbeat = heartbeat,//心跳超时时间
                AutomaticRecoveryEnabled = true//自动重连
            };
            return SendConnection.CreateConnection();
        }
        catch (Exception ex)
        {
            string strErrorMsg = "";
            if (ex.InnerException != null)
                strErrorMsg = "创建一个IConnection CreateConnection 有错误:" + ex.InnerException.Message.ToString();
            else
                strErrorMsg = "创建一个IConnection CreateConnection 有错误:" + ex.Message.ToString();

            Program.logs.Error(strErrorMsg);
            return null;
        }
    }

    /// 
    /// Info日志处理
    /// 
    public void InfoLogHandler()
    {
        try
        {
            using (SendConnection = CreateConnection())//建立链接
            {
                using (SendChannel = SendConnection.CreateModel())//创建channel
                {
                    //定义消息交换机为匹配key模式,如果 routing key 匹配, 那么Message就会被传递到相应的queue中。
                    SendChannel.ExchangeDeclare(exchange_InfoLog, "direct");//接收端如果关闭之后,自动创建的Queue会自动被删

                    SendChannel.QueueDeclare(Queue_InfoLog, true, false, false, null);

                    //通过绑定将不同的Queue名称、相同的Routing Key名称采用Direct的Exchange方式进行关联
                    SendChannel.QueueBind(Queue_InfoLog, exchange_InfoLog, routingKey_InfoLog);

                    //var consumer = new EventingBasicConsumer(mqBase.SendChannel);//创建事件驱动的消费者类型

                    int i_MsgCount = 0;
                    int.TryParse(SendChannel.MessageCount(Queue_InfoLog).ToString(), out i_MsgCount);

                    var consumer = new QueueingBasicConsumer(SendChannel);
                    SendChannel.BasicConsume(Queue_InfoLog, true, consumer);

                    int i = 0;
                    while (i < i_MsgCount)
                    {
                        var ea = consumer.Queue.Dequeue();
                        var body = ea.Body;
                        var message = Encoding.UTF8.GetString(body);

                        Program.logs.Info(message);
                        i++;
                    }
                }
            }
        }
        catch (Exception ex)
        {
            string strErrorMsg = "";
            if (ex.InnerException != null)
                strErrorMsg = "Info日志处理 InfoLogHandler 有错误:" + ex.InnerException.Message.ToString();
            else
                strErrorMsg = "Info日志处理 InfoLogHandler 有错误:" + ex.Message.ToString();

            Program.logs.Error(strErrorMsg);
        }
    }

    /// 
    /// Error日志处理
    /// 
    public void ErrorLogHandler()
    {
        try
        {
            using (SendConnection = CreateConnection())//建立链接
            {
                using (SendChannel = SendConnection.CreateModel())//创建channel
                {
                    //定义消息交换机为匹配key模式,如果 routing key 匹配, 那么Message就会被传递到相应的queue中。
                    SendChannel.ExchangeDeclare(exchange_ErrorLog, "direct");//接收端如果关闭之后,自动创建的Queue会自动被删

                    SendChannel.QueueDeclare(Queue_ErrorLog, true, false, false, null);

                    //通过绑定将不同的Queue名称、相同的Routing Key名称采用Direct的Exchange方式进行关联
                    SendChannel.QueueBind(Queue_ErrorLog, exchange_ErrorLog, routingKey_ErrorLog);

                    //var consumer = new EventingBasicConsumer(mqBase.SendChannel);//创建事件驱动的消费者类型

                    int i_MsgCount = 0;
                    int.TryParse(SendChannel.MessageCount(Queue_ErrorLog).ToString(), out i_MsgCount);

                    var consumer = new QueueingBasicConsumer(SendChannel);
                    SendChannel.BasicConsume(Queue_ErrorLog, true, consumer);

                    int i = 0;
                    while (i < i_MsgCount)
                    {
                        var ea = consumer.Queue.Dequeue();
                        var body = ea.Body;
                        var message = Encoding.UTF8.GetString(body);

                        Program.logs.Error(message);
                        i++;
                    }
                }
            }
        }
        catch (Exception ex)
        {
            string strErrorMsg = "";
            if (ex.InnerException != null)
                strErrorMsg = "Info日志处理 InfoLogHandler 有错误:" + ex.InnerException.Message.ToString();
            else
                strErrorMsg = "Info日志处理 InfoLogHandler 有错误:" + ex.Message.ToString();

            Program.logs.Error("Error日志处理 ErrorLogHandler 有错误!");
        }
    }
}

在Program.cs中主要声明ILog接口和Timer组件,主要代码如下:
public class Program
{
    /// 
    /// 初始化日志类
    /// 
    public static ILog logs = LogHelper.GetInstance(Application.StartupPath + "\\Log4net\\Log4Net.config");

    /// 
    /// 保存到db的时间组件
    /// 
    static System.Timers.Timer SaveLogTimer = new System.Timers.Timer();

    /// 
    /// 保存日志信息
    /// 
    internal static void ScheduleTimer()
    {
        //发布监听定时器初始化设置
        SaveLogTimer.Enabled = true;//启动定时器
        SaveLogTimer.Interval = 10000;//时间间隔为10秒钟
        SaveLogTimer.Elapsed += new ElapsedEventHandler((timeO, timeE) =>
        {
            try
            {
                MQBase mqBase = new MQBase();
                mqBase.InfoLogHandler();
                mqBase.ErrorLogHandler();

                logs.Info(DateTime.Now.ToString() + "MES.Service.LogHandler 保存日志信息 ScheduleTimer");
            }
            catch
            {
                Common.PrintTootip(DateTime.Now.ToString() + "保存日志信息ScheduleTimer 有错误!");
                logs.Error("保存日志信息ScheduleTimer 有错误!");
            }

        });
        SaveLogTimer.Start();
    }
}

在Java中呢,引用amqp等jar,如下:
基于rabbitmq的日志系统(.NET和java)_第2张图片

同样声明RabbitMQ代理处理化类,如下:

package MES;

import org.w3c.dom.*;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;

/*
 * MQ消息框架代理初始化
 */
public class MQProxyInit {
    //MQ服务器地址
    private static String strMQServerAddress = "";
    //MQ服务器端口
    private static int iMQServerPort = 5672;
    //MQ用户名
    private static String strMQUserName = "";
    //MQ密码
    private static String strMQPassword = "";
    //心跳超时时间(默认60)
    private static int iMQheartbeat = 60;
    //文本构造器对象
    private static DocumentBuilder db = null;
    //文本对象
    private static Document document = null;

    static {
        try {
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            db = dbFactory.newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        }
    }

    //构造函数
    public  MQProxyInit() {
    }

    //构造函数
    public MQProxyInit(String xmlPath) {
        try {
            if (xmlPath == null || xmlPath == "")
                return;

            File file = new File(xmlPath);
            if (!file.exists())
                return;

            document = db.parse(file);
            if (document == null)
                return;

            NodeList list = document.getElementsByTagName("add");

            if (list.getLength() == 0)
                return;

            for (int i = 0; i < list.getLength(); i++) {
                //获取第i个add结点
                Node keyNode = list.item(i);
                //获取第i个add的所有属性
                NamedNodeMap namedNodeMap = keyNode.getAttributes();
                keyNode = namedNodeMap.getNamedItem("key");
                Node valueNode = namedNodeMap.getNamedItem("value");
                if (keyNode != null && valueNode != null) {
                    String strTmp = keyNode.getTextContent().trim();
                    if (strTmp.equals("MQServerAddress")) {
                        strMQServerAddress = valueNode.getTextContent();
                    }
                    if (strTmp.equals("MQServerPort")) {
                        String strPort = valueNode.getTextContent();
                        if (Common.isInteger(strPort))
                            iMQServerPort = Integer.parseInt(strPort);
                    }
                    if (strTmp.equals("MQUserName")) {
                        strMQUserName = valueNode.getTextContent();
                    }
                    if (strTmp.equals("MQPassword")) {
                        strMQPassword = valueNode.getTextContent();
                    }
                }
            }

            MQBase mqbase = new MQBase(strMQServerAddress, iMQServerPort,strMQUserName,strMQPassword,iMQheartbeat);
        } catch (IOException e) {
            String strInfo = "处理 MQ代理配置初始化 有错误!错误如下:";
            Common.FormatExceptionInfo(strInfo, e);
        } catch (SAXException e) {
            String strInfo = "处理 MQ代理配置初始化 有错误!错误如下:";
            Common.FormatExceptionInfo(strInfo, e);
        } catch (Exception e) {
            String strInfo = "处理 MQ代理配置初始化 有错误!错误如下:";
            Common.FormatExceptionInfo(strInfo, e);
        }
    }
}

同样需要一个MQBase.java进行消息处理类,每隔30秒用timer把队列数据放到RabbitMQ中:
package MES;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.Date;
import java.util.LinkedList;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeoutException;

/*
 * MQ消息处理
 */
public class MQBase {
    // ip地址
    private static String HostName = "127.0.0.1";

    // 端口
    private static int Port = 5672;

    // 用户名
    private static String UserName = "";

    // 密码
    private static String Password = "";

    // 心跳超时时间(默认60秒)
    private static int heartbeat = 60;

    // 消息交换机“异常日志消息”
    private final static String exchange_ErrorLog = "exchange_ErrorLog";

    // Queue的“异常日志消息”
    private final static String Queue_ErrorLog = "Queue_ErrorLog";

    // routingKey的“异常日志消息”
    private final static String routingKey_ErrorLog = "routingKey_ErrorLog";

    // 消息交换机“操作日志消息”
    private final static String exchange_InfoLog = "exchange_InfoLog";

    // Queue的“操作日志消息”
    private final static String Queue_InfoLog = "Queue_InfoLog";

    // routingKey的“操作日志消息”
    private final static String routingKey_InfoLog = "routingKey_InfoLog";

    // rabbitmq客户端连接对象
    private Connection connection;

    // 用于发送消息的Channel
    private Channel channel;

    // 声明BasicProperties.Builder对象
    private AMQP.BasicProperties.Builder builder;

    // 声明BasicProperties对象
    private AMQP.BasicProperties properties;

    // 推送ErrorLog消息到MQ的时间组件
    private static Timer timer_ErrorLog = new Timer();

    // 推送InfoLog消息到MQ的时间组件
    private static Timer timer_InfoLog = new Timer();

    // 链表队列--Error日志
    private static LinkedList linkedList_ErrorLog = new LinkedList<>();

    // 链表队列——Info日志
    private static LinkedList linkedList_InfoLog = new LinkedList<>();

    // 构造函数
    public MQBase(String strHostName, int iPort, String strUserName, String strPassword, int iheartbeat) {
        HostName = strHostName;
        Port = iPort;
        UserName = strUserName;
        Password = strPassword;
        heartbeat = iheartbeat;

        // 启动Timer组件执行
        ScheduleTimer();
    }

    // 构造函数
    public MQBase() {
    }

    // 创建一个IConnection
    private Connection CreateConnection() throws IOException, TimeoutException {
        //创建连接工厂
        ConnectionFactory factory = new ConnectionFactory();

        //设置RabbitMQ相关信息
        factory.setHost(HostName);
        factory.setUsername(UserName);
        factory.setPassword(Password);
        factory.setPort(Port);
        factory.setRequestedHeartbeat(heartbeat);//心跳超时时间
        factory.setAutomaticRecoveryEnabled(true);//自动重连

        if(builder == null) {
            //声明BasicProperties的Builder对象
            builder = new AMQP.BasicProperties.Builder();
        }

        //deliveryMode=1代表不持久化,deliveryMode=2代表持久化
        builder.deliveryMode(2);

        if(properties == null) {
            properties = builder.build();
        }

        //创建一个新的连接
        return factory.newConnection();
    }

    // 发送异常日志消息到RabbitMQ
    private boolean SendErrorLogMessage(String strLogContent) {
        if (strLogContent == "")
            return false;

        try {
            if (connection == null) {
                //建立链接
                connection = CreateConnection();
            }

            if (channel == null) {
                //创建channel
                channel = connection.createChannel();
            }

            //定义消息交换机为匹配key模式,如果 routing key 匹配, 那么Message就会被传递到相应的queue中。
            channel.exchangeDeclare(exchange_ErrorLog, "direct");

            //添加Queue_ErrorLog到队列
            channel.queueDeclare(Queue_ErrorLog, true, false, false, null);

            //通过绑定将指定的添加queue_name_1的队列、相同的RoutingKey名称使用Direct的Exchange方式进行关联
            channel.queueBind(Queue_ErrorLog,//队列名
                    exchange_ErrorLog,//消息交换机名
                    routingKey_ErrorLog);//指定routingKey

            //System.out.println("basicPublish" + Common.GetCurrentTime(true));

            //Producer只能发送到exchange,它是不能直接发送到queue的
            channel.basicPublish(exchange_ErrorLog,//发给指定的Exchange
                    routingKey_ErrorLog,//指定routing key只有匹配的可以收到
                    properties,//指定基本属性
                    strLogContent.getBytes());

            //System.out.println("end" + Common.GetCurrentTime(true));

            return true;
        }
        catch (Exception e) {
            return false;
        }
    }

    // 发送操作日志消息到RabbitMQ
    private boolean SendInfoLogMessage(String strLogContent) {
        if (strLogContent == "")
            return false;

        try {
            if (connection == null) {
                //建立链接
                connection = CreateConnection();
            }

            if (channel == null) {
                //创建channel
                channel = connection.createChannel();
            }

            //定义消息交换机为匹配key模式,如果 routing key 匹配, 那么Message就会被传递到相应的queue中。
            channel.exchangeDeclare(exchange_InfoLog, "direct");

            //添加Queue_ErrorLog到队列
            channel.queueDeclare(Queue_InfoLog, true, false, false, null);

            //通过绑定将指定的添加queue_name_1的队列、相同的RoutingKey名称使用Direct的Exchange方式进行关联
            channel.queueBind(Queue_InfoLog,//队列名
                    exchange_InfoLog,//消息交换机名
                    routingKey_InfoLog);//指定routingKey

            //Producer只能发送到exchange,它是不能直接发送到queue的
            channel.basicPublish(exchange_InfoLog,//发给指定的Exchange
                    routingKey_InfoLog,//指定routing key只有匹配的可以收到
                    properties,//指定基本属性
                    strLogContent.getBytes());

            return true;
        }
        catch (Exception e) {
            return false;
        }
    }

    // 写入ErrorLog链表队列
    public static void SendErrorLogMessageHandler(String strContent) {
        linkedList_ErrorLog.addLast(strContent);
    }

    // 写入InfoLog链表队列
    public static void SendInfoLogMessageHandler(String strContent) {
        linkedList_InfoLog.addLast(strContent);
    }

    // 执行Timer组件开始
    private static void ScheduleTimer() {
        try {
            Date day = new Date();

            timer_ErrorLog.schedule(new TimerTask() {
                public void run() {
                    if (!linkedList_ErrorLog.isEmpty()) {
                        StringBuilder sb = new StringBuilder();
                        Object[] tmp = linkedList_ErrorLog.toArray();
                        linkedList_ErrorLog.clear();
                        for (int i = 0; i < tmp.length; i++) {
                            sb.append(tmp[i] + "\r\n");
                        }
                        MQBase mqBase = new MQBase();
                        mqBase.SendErrorLogMessage(sb.toString());
                    }
                }
            }, day, 30000);

            timer_InfoLog.schedule(new TimerTask() {
                public void run() {
                    if (!linkedList_InfoLog.isEmpty()) {
                        StringBuilder sb = new StringBuilder();
                        Object[] tmp = linkedList_InfoLog.toArray();
                        linkedList_InfoLog.clear();
                        for (int i = 0; i < tmp.length; i++) {
                            sb.append(tmp[i] + "\r\n");
                        }
                        MQBase mqBase = new MQBase();
                        mqBase.SendInfoLogMessage(sb.toString());
                    }
                }
            }, day, 30000);
        }
        catch (Exception e) {
            return;
        }
    }

    // 取消timer
    public static void cancel() {
        try {
            timer_ErrorLog.cancel();
            timer_InfoLog.cancel();
        }
        catch (Exception e) {
            return;
        }
    }
}

在Main.java中进行如下调用:
基于rabbitmq的日志系统(.NET和java)_第3张图片

你可能感兴趣的:(MES大数据平台)