Wcf通讯基础框架方案(四)——横切日志
在第一篇文章中已经列出了几种日志的概览:
所有的日志都有一个最终基类,来看看这个类:
[DataContract(Namespace = "WcfExtension")]
[KnownType(typeof(WcfExceptionInfo))]
[KnownType(typeof(ServerExceptionInfo))]
[KnownType(typeof(ClientExceptionInfo))]
[KnownType(typeof(WcfInvokeInfo))]
[KnownType(typeof(ServerInvokeInfo))]
[KnownType(typeof(ClientInvokeInfo))]
[KnownType(typeof(WcfMessageInfo))]
[KnownType(typeof(ServerMessageInfo))]
[KnownType(typeof(ClientMessageInfo))]
[KnownType(typeof(StartInfo))]
[KnownType(typeof(ServerStartInfo))]
[KnownType(typeof(ClientStartInfo))]
public abstract class AbstractLogInfo
{
[DataMember]
[PersistenceColumn(IsIndex = true)]
public string ID { get; set; }[DataMember]
[PersistenceColumn(IsIndex = true)]
public string RequestIdentity { get; set; }[DataMember]
[PersistenceColumn(IsIndex = true)]
public DateTime Time { get; set; }[DataMember]
[PersistenceColumn(IsIndex = true)]
public string MachineName { get; set; }[DataMember]
[PersistenceColumn(IsIndex = true)]
public string MachineIP { get; set; }[DataMember]
public string ExtraInfo { get; set; }public override string ToString()
{
StringBuilder sb = new StringBuilder();
this.GetType().GetProperties().ToList().ForEach(p =>
{
var o = p.GetValue(this, null);
sb.AppendLine(p.Name + ": " + o);
if (o is Dictionary<string, string>)
{
var dic = o as Dictionary<string, string>;
foreach (var key in dic)
{
sb.AppendLine(" " + key.Key + ": " + key.Value);
}
}});
return sb.ToString();
}
}值得关注的几点:1) 这里的日志我们会保存在Mongodb中,会有一些Attribute告诉日志服务端,字段是否需要做索引,是否需要分库等等。
2) 每一条日志都会有一个GUID作为ID,这个没什么特别的。但要注意一点,如果服务端执行方法出现异常的话,会把异常ID在Message里面返回给客户端。这个异常ID也就是这条异常日志的ID。客户端只能收到有关服务端异常的Message而不会收到更多的堆栈等信息。原因两个,一减少Fault消息大小,二客户端也不应该知道这么多服务端的信息,客户端也不一定能理解服务端的异常,服务端有自己的异常日志。
3) 每一条日志都会有一个RequestIdentity,这是一个请求的上下文关联字段。从客户端发出请求开始,到服务端处理,再到客户端接收到服务端的反馈消息。其中所有的调用日志、异常日志和消息日志都会有相同的RequestIdentity。也就是说在后台通过这个RequestIdentity可以查询到一条一种类型的日志关联的整个请求过程中的其它日志。打个比方,如果在查看客户端执行日志的时候发现方法执行失败,那么直接可以查看到对应的服务端失败的那条执行日志,以及服务端对应的那个异常日志和客户端对应的异常的日志,如果开启消息日志的话,还可以查到对应的客户端和服务端收发的消息。
4) 每条日志都会有机器名和机器IP地址,以及时间。ExtraInfo存的是一些其它信息,在这里我存的是记录这个日志的方法名称。
每一种类型的日志都会有服务端日志和客户端日志两种,分别实现两个接口:
internal inte易做图ce IServerInfo
{
string ServiceName { get; set; }
}internal inte易做图ce IClientInfo
{
string ClientTypeName { get; set; }string ContractName { get; set; }
}
我认为,服务端日志需要关注服务的类型,而客户端日志关注的是契约的类型,以及调用这个契约所在的类(比如某个页面的类型名),这样可以方便定位问题。因为服务的实现位置相对固定,而调用服务接口的地方就五花八门了。再来看看其它集中日志类型增加了哪些东西:
[DataContract(Namespace = "WcfExtension")]
public abstract class WcfExceptionInfo : AbstractLogInfo
{
[DataMember]
[PersistenceColumn(IsIndex = true)]
public string Type { get; set; }[DataMember]
public string Message { get; set; }[DataMember]
public string StackTrace { get; set; }
}异常日志记录异常类型、异常消息和堆栈。[DataContract(Namespace = "WcfExtension")]
public abstract class WcfMessageInfo : AbstractLogInfo
{
[DataMember]
public MessageDirection MessageDirection { get; set; }[DataMember]
public string Message { get; set; }
}
}消息日志记录完整的消息以及消息的方向。[DataContract(Namespace = "WcfExtension")]
[KnownType(typeof(ApplicationContext))]
public abstract class WcfInvokeInfo : AbstractLogInfo
&n
补充:综合编程 , 其他综合 ,