天天看点

.net webapi项目如何集成Exceptionless

这个问题要分大致分为三个阶段:

  • 何为Exceptionelss,为什么要用,用了有什么用,能解决什么问题?
  • 怎样集成到项目中(.NET各种项目),怎样查看记录下来的日志?
  • 可否拦截所有请求,如果可以,怎样做?
  • 其他高阶操作?

以下一一解答这些问题。

what

Exceptionless是一个很好用的日志框架。

所谓框架,是比库(比如类似的NLog,Log4Net等)要大的概念的。

将Exceptionless集成到项目中后,在相应的日志页面就可以看到Exceptionless拦截到的请求的一切(或者几乎一切)内容,比如一个http请求,可以看到它的Request详情、cookie、token、http里面的header、auth,以及Response,耗时,处理请求时的操作系统状态,使用的内存量、如果有异常的话还可以显示堆栈详情……总之,它可以让你在难以调试的环境中保留问题产生时的大量详情,让你可以很容易地重现问题、排查问题以及解决问题。

如下图。

.net webapi项目如何集成Exceptionless
.net webapi项目如何集成Exceptionless
.net webapi项目如何集成Exceptionless

等等很多详情,更多图就不上了。

设想一下,如果你线上有问题,缺根本没法重现,无规律出现,那该有多么地抓狂。

如果你调试小程序,但小程序的请求不认ip地址,只认域名,那又该如何调试和重现问题。

这些都可以迎刃而解。

how

不是说只能应用在.net项目中,只是我只用在过.net项目中,包括.net framework 和 .net core,当前时间2019.7.20.

方法:

  • 上Exceptionless官网,https://be.exceptionless.io ,注册一个账号,然后在账户的管理中心里配置项目,指明项目是什么类型(如是控制台,是windowsService,是webapi,是webform等等),然后下一页会清楚地告诉你需要添加什么引用,需要在什么地方配置什么内容,非常容易。
  • .net webapi项目如何集成Exceptionless
  • 然后在此账户的日志页就可以看到了。
  • .net webapi项目如何集成Exceptionless
  • 然后其实你可能会疑惑,明明发了很多请求啊,为什么这日志里都没有呢?

    原因很简单,因为Exceptionless默认只拦截Exception信息,所以如果一切正常没有Exception被throw出来的话是看不到的。

    当然你也可以自己主动throw一些什么出来,这官网文档里都有。

ex.ToExceptionless.Submit();      

这样的。

whether

可否拦截所有请求呢,怎么做?

可以。

自定义一个过滤器,将过滤器添加到每个api接口的Attribute上,即可生效。

思路很简答了,想怎么实现花样就多了。

不罗嗦,直接上我的代码(webapi项目)。

  1. 项目中直接写一个​

    ​MiniProFileter.cs​

    ​​文件

    内容:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Web;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using Exceptionless;
using Exceptionless.Models;
using Exceptionless.Plugins;
using Newtonsoft.Json;
using XueTian.Model;

namespace XueTian.WebApi.Util
{
    /// <summary>
    /// 
    /// </summary>
    public class MiniProFileter : ActionFilterAttribute
    {
        /// <summary>
        /// 自定义过滤器,使用Exceptionless拦截每一个请求
        /// </summary>
        /// <param name="actionContext"></param>
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
#if DEBUG

            //base.OnActionExecuting(actionContext);

            //var headerDict = actionContext.Request.Headers.ToDictionary(k => k.Key, v => v.Value);
            //string auth = null;
            //if (headerDict.Keys.Contains("auth"))
            //{
            //    auth = headerDict["auth"].ToList().FirstOrDefault();
            //}
            //DataDictionary dataDict = new DataDictionary() {
            //    { "auth",auth },
            //     { "requestInfo",actionContext.ActionArguments }
            //};

            //var controller = actionContext.ControllerContext.Controller.ToString().Split(new char[] { '.' }).ToList().Last() ?? "--";
            //var source = actionContext.Request.RequestUri.AbsoluteUri.ToString().Split(new char[] { '/' }).ToList().Last() ?? "==";

            //ExceptionlessClient.Default.SubmitEvent(new Event
            //{
            //    Type = controller,
            //    Source = source,
            //    Message = "微信小程序日志--OnActionExecuting",
            //    Data = dataDict
            //});

#endif
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="actionExecutedContext"></param>
        public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
        {


            //auth
            var headerDict = actionExecutedContext.Request.Headers.ToDictionary(k => k.Key, v => v.Value);
            string auth = null;
            if (headerDict.Keys.Contains("auth"))
            {
                auth = headerDict["auth"].ToList().FirstOrDefault();
            }
            //host
            string host = null;
            if (headerDict.Keys.Contains("Host"))
            {
                host = headerDict["Host"].ToList().FirstOrDefault();
            }
            //referer
            string referer = null;
            if (headerDict.Keys.Contains("Referer"))
            {
                referer = headerDict["Referer"].ToList().FirstOrDefault();
            }


            //response
            object responseObj = null;
            var resReult = actionExecutedContext.Response.TryGetContentValue(out responseObj);

            DataDictionary dataDict = new DataDictionary() {
                {"auth",auth },
                {"host",host },
                {"request", actionExecutedContext.ActionContext.ActionArguments },
                { "response",resReult ? responseObj : actionExecutedContext.Response.Content}
            };

            //
            var controller = actionExecutedContext.ActionContext.ControllerContext.Controller.ToString().Split(new char[] { '.' }).ToList().Last() ?? "--";
            var source = actionExecutedContext.Request.RequestUri.AbsoluteUri.ToString().Split(new char[] { '/' }).ToList().Last() ?? "==";

            ExceptionlessClient.Default.SubmitEvent(new Event
            {
                Type = source,
                Source = controller,
                Message = actionExecutedContext.Request.GetClientIpAddress(),
                Tags = new TagSet(new[] { actionExecutedContext.Request.Method.ToString(),actionExecutedContext.Request.Headers.Host,actionExecutedContext.Request.Version.ToString(), actionExecutedContext.Request.RequestUri.UserInfo }),
                Date = new DateTimeOffset(DateTime.Now),
                Data = dataDict,
            });


        }
    }
}      
  1. 控制器中直接使用,如下图:
  2. .net webapi项目如何集成Exceptionless
  3. 至于过滤器究竟是放在控制器的class上,还是具体的方法上,不再多说,稍有经验的都懂。
  4. 最后,日志可见所有请求。
  5. .net webapi项目如何集成Exceptionless

Others

其他高阶操作?

默认的免费账户的请求数量是很少的,如何解决呢?

当然最简单是付费,如果不想付费(当然还是建议付费的,毕竟支持一下别人的劳动),那办法就很容易想到,多注册账号,反正换个密钥就能用。

补充

ExceptionlessClient.Default.Configuration.ServerUrl = "http://exceptionless.mydomain.cn";  //可以写死

            ExceptionlessClient.Default.SubmitEvent(new Event
            {
                Type = KnownTypes.Log,//随便写
                Source = controller + " @ " + DateTime.Now.ToString("MM-dd HH:mm:ss:fff"),//随便写
                Message = actionExecutedContext.Request.GetClientIpAddress(),//随便写
                Tags = new TagSet() { KnownTags.Internal },  //随便写
                Data = dataDict
            });      

继续阅读