• .Net分布式异常报警系统-客户端及服务端API


    客户端的作用就是捕获未处理异常, 发送异常到服务端。 关于捕获未处理异常的方法参考 http://www.cnblogs.com/youring2/archive/2012/04/25/2469974.html  http://www.cnblogs.com/eaglet/archive/2009/02/17/1392191.html 这两篇博客。
    总结下来对于web程序来说, 捕获未处理异常有两种方式:
    1. 定义一个HttpModule, 在这个module的context_Error方法中来捕获未处理的异常。 
    2. 在Global.asax中有一个Application_Error的方法, 当程序发生未处理异常的时候, 会调用这个方法。 
    对于以上两种方式, 以上两篇博客也做了对比, 对异常的捕获, HttpModule会优于Global,同时从编程的角度来说, 如果使用Global, 那就意味着代码侵入。 所以最后决定采用了HttpModule的方式。
    public class ErrorLogModule : IHttpModule
        {
     
            #region IHttpModule Members
     
            public void Dispose()
            {
            }
     
            public void Init(HttpApplication context)
            {
                context.Error += context_Error;
            }
     
            #endregion
     
            private void context_Error(object sender, EventArgs e)
            {
                HttpApplication application = (HttpApplication) sender;
                ClientErrorEntity errorMessage = new ClientErrorEntity(application.Server.GetLastError().GetBaseException(),
                    application.Context);
                SendErrorEntity.SendError(errorMessage);
            }
        } 
    View Code
    异常信息组装。 
     public ClientErrorEntity(Exception exception, HttpContext httpContext)
            {
                Id = Guid.NewGuid().ToString("N");
     
                MachineName = Environment.MachineName;
                Ip = Common.GetLocalIp();
                ExceptionType = exception.GetType().FullName;
                ExceptionMessage = exception.Message;
                ExceptionSource = exception.Source;
                ExceptionDetail = exception.ToString();
                DateTime = DateTime.Now;
                HttpException httpException = exception as HttpException;
                if (httpException != null)
                {
                    HttpStatusCode = httpException.GetHttpCode();
                }
     
                if (httpContext != null)
                {
                    HttpRequest request = httpContext.Request;
                    RequestUrl = request.Url.AbsoluteUri;
                    ServerVariables = Common.ConvertCollectionToDictionary(request.ServerVariables);
                    QueryString = Common.ConvertCollectionToDictionary(request.QueryString);
                    Form = Common.ConvertCollectionToDictionary(request.Form);
                    Cookies = Common.ConvertCollectionToDictionary(request.Cookies);
                }
                Type = 0;
            }  
    View Code
    这里实现了异常信息的发送,为了避免影响主逻辑, 采用了异步的方式。 注意一个问题, 对于API的地址, 我们采用的硬编码的方式, 当然正式环境为了避免单点, 应该采用域名的方式, 然后通过负载均衡在在多台服务器中选择。 如果仅仅有一台服务器, 那我们要将这个地址放在配置文件中, 一旦地址发生了变化,可以方便我们更改。  
      public static void SendError(ClientErrorEntity errorMessage)
            {
                try
                {
                    string jsonstr = JsonConvert.SerializeObject(errorMessage);
                    //异步, 确保不会影响主逻辑
                    sendPostdelegate.BeginInvoke("http://192.168.16.39:90/api/Error", jsonstr, ContentType.Json, 3000,
                       Encoding.UTF8,
                       Encoding.UTF8, Response, sendPostdelegate);   //这里请求地址 建议改为域名的方式,  如果没有域名,建议请求地址和webtoken类似为可配置
                }
                catch (Exception exception)
                {
                    Common.Log("错误信息上传失败:" + exception.Message);
                }
            } 
    View Code
    为了标示异常是从哪个网站发出的, 我们会对每个网站分配一个token,token会随异常信息一起发送到服务端。 
     <configSections>
        <section name="WebWarningSetting" type="System.Configuration.SingleTagSectionHandler"/>
      </configSections>
      <WebWarningSetting WebToken="1E8C46FC74DC41569EFF63C92A7A4087"/>  
    View Code
    服务端API主要功能是接收异常信息,考虑到性能问题, 并没有将异常信息直接入库,而是将异常信息放入到Redis的List中,  因为提供的驱动中Redis的List的Value并不支持对象, 所以这里采用分开存放的方法, 将ErrorEntity.Id放入到队列中, ErrorEntity则以普通的方式set到Redis中, 在获取数据的时候,从队列中获取到ErrorEntity.Id , 这样取出来的Id确保顺序不会变, 再根据这个Id, 通过get取出实体。这种方法其实还有待考虑, 虽然List不支持复杂Value, 但是通过json序列化,我们还是可以直接将ErrorEntity放入到List中。
      public HttpResponseMessage Post([FromBody]ErrorEntityDto errorEntity)
            {
                if (errorEntity != null && !string.IsNullOrWhiteSpace(errorEntity.Id))
                {
                    if (RedisHelper.EnqueueItemOnList("ErrorEntityQueue", errorEntity.Id))    //先将ErrorEntity.Id放入到队列中,确保顺序不会变
                    {
                        if (RedisHelper.Set(errorEntity.Id, errorEntity))  //将实体添加到Redis中
                        {
                            return ReturnPlainText("ok");
                        }
                        return ReturnPlainText("set  error");
                    }
                    return ReturnPlainText("add item to list error");
                }
                return ReturnPlainText("modle error");
            }  
     
    View Code
  • 相关阅读:
    个人作业2——英语学习APP案例分析
    结对编程1—— 基于界面的四则运算(38/39)
    个人作业1——四则运算题目生成
    软件工程实践项目课程的自我目标
    IE6/IE7/IE8/Firefox/Chrome/Safari的CSS hack兼容一览表
    微信小程序爬坑日记之蜜汁缩进
    微信小程序爬坑日记之背景图片设置
    你不知道的 js 保留字
    微信小程序爬坑日记之下拉刷新
    ES7-Es8 js代码片段
  • 原文地址:https://www.cnblogs.com/beyondbit/p/4755334.html
Copyright © 2020-2023  润新知