很多年不写博客了,希望写一些东西总结总结。
我从2011年开始做工业软件生产执行系统架构,2016年对整体架构进行重新规划和重构。
我们MES架构中关于日志模块的设计思路,接下来我会介绍在MES业务下Java和MongoDB的一些思路总结
架构采用WebAPI,日志采用log4,中间用RabbitMQ进行分流,架构图如下:
框架采用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();
}
}
同样声明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;
}
}
}