当前位置:编程学习 > 网站相关 >>

Wcf通讯基础框架方案(四)——横切日志

在第一篇文章中已经列出了几种日志的概览:

image

 

所有的日志都有一个最终基类,来看看这个类:

[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 interface IServerInfo
{
    string ServiceName { get; set; }
}

internal interface 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

补充:综合编程 , 其他综合 ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,