基于rabbitmq的日志系统(.NET和java)
很多年不写博客了,希望写一些东西总结总结。
我从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
{
/// <summary>
/// 同步发送错误日志数据信息
/// </summary>
/// <param name="strlogDataTransmissionObj">传输日志内容对象</param>
/// <param name="stackTrace">堆栈跟踪对象</param>
void SendErrorLog(string strlogDataTransmissionObj, StackTrace stackTrace);
/// <summary>
/// 同步发送错误日志数据信息
/// </summary>
/// <param name="strlogDataTransmissionObj">传输日志内容对象</param>
void SendErrorLog(string strlogDataTransmissionObj);
/// <summary>
/// 同步发送操作日志数据信息
/// </summary>
/// <param name="strInfoDataTransmissionObj">传输操作日志内容对象</param>
void SendInfoLog(string strInfoDataTransmissionObj);
}
public class ClientMQProxy : IClientMQProxy
{
/// <summary>
/// Http绑定元素
/// </summary>
static BasicHttpBinding HttpBind { get; set; }
/// <summary>
/// “日志数据消息”契约接口抽象对象
/// </summary>
IPlugin.IMQProxy iMQProxy;
/// <summary>
/// 静态实例对象
/// </summary>
static ClientMQProxy instace = null;
/// <summary>
/// 锁
/// </summary>
static readonly object padlock = new object();
/// <summary>
/// 静态实例方法(返回静态字段)
/// </summary>
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;
}
}
/// <summary>
/// 根据“服务类型”来进行服务的启动
/// </summary>
/// <param name="strEndpointAddress">需要连入的日志服务地址</param>
void RunService(string strEndpointAddress)
{
try
{
//增加服务的同时,添加到字典里
iMQProxy = DataBind(HttpBind, strEndpointAddress);
}
catch{ }
}
/// <summary>
/// 客户端发送错误日志调用方法
/// </summary>
/// <param name="strInfoDataTransmissionObj"></param>
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;
}
}
/// <summary>
/// 客户端发送错误日志调用方法
/// </summary>
/// <param name="strLogDataTransmissionObj">日志数据传输对象</param>
/// <param name="stackTrace">堆栈跟踪对象,调用示例: new StackTrace(new StackFrame(true))</param>
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;
}
}
/// <summary>
/// 客户端发送错误日志调用方法
/// </summary>
/// <param name="strLogDataTransmissionObj">日志数据传输对象</param>
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;
}
}
/// <summary>
/// “数据消息”绑定
/// </summary>
/// <param name="binding">绑定元素对象</param>
/// <param name="str_EndpointAddress">端节点地址</param>
/// <returns></returns>
IMQProxy DataBind(System.ServiceModel.Channels.Binding binding, string str_EndpointAddress)
{
//创建通道
ChannelFactory<IPlugin.IMQProxy> channelFactory = new ChannelFactory<IPlugin.IMQProxy>(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
{
/// <summary>
/// 端节点地址
/// </summary>
string strBaseAddress { get; set; }
/// <summary>
/// 启动Windows服务名称
/// </summary>
string strSrvName { get; set; }
/// <summary>
/// 构造
/// </summary>
/// <param name="strBaseAddress">地址</param>
/// <param name="strSrvName">服务名称</param>
public RunSelfHostLog(string strBaseAddress, string strSrvName)
{
this.strBaseAddress = strBaseAddress;
this.strSrvName = strSrvName;
}
/// <summary>
/// 创建服务,并打开
/// </summary>
/// <param name="strErrorMsg">错误消息</param>
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)
{
//调