这个问题要分大致分为三个阶段:
- 何为Exceptionelss,为什么要用,用了有什么用,能解决什么问题?
- 怎样集成到项目中(.NET各种项目),怎样查看记录下来的日志?
- 可否拦截所有请求,如果可以,怎样做?
- 其他高阶操作?
以下一一解答这些问题。
what
Exceptionless是一个很好用的日志框架。
所谓框架,是比库(比如类似的NLog,Log4Net等)要大的概念的。
将Exceptionless集成到项目中后,在相应的日志页面就可以看到Exceptionless拦截到的请求的一切(或者几乎一切)内容,比如一个http请求,可以看到它的Request详情、cookie、token、http里面的header、auth,以及Response,耗时,处理请求时的操作系统状态,使用的内存量、如果有异常的话还可以显示堆栈详情……总之,它可以让你在难以调试的环境中保留问题产生时的大量详情,让你可以很容易地重现问题、排查问题以及解决问题。
如下图。
等等很多详情,更多图就不上了。
设想一下,如果你线上有问题,缺根本没法重现,无规律出现,那该有多么地抓狂。
如果你调试小程序,但小程序的请求不认ip地址,只认域名,那又该如何调试和重现问题。
这些都可以迎刃而解。
how
不是说只能应用在.net项目中,只是我只用在过.net项目中,包括.net framework 和 .net core,当前时间2019.7.20.
方法:
- 上Exceptionless官网,https://be.exceptionless.io ,注册一个账号,然后在账户的管理中心里配置项目,指明项目是什么类型(如是控制台,是windowsService,是webapi,是webform等等),然后下一页会清楚地告诉你需要添加什么引用,需要在什么地方配置什么内容,非常容易。
- 然后在此账户的日志页就可以看到了。
-
然后其实你可能会疑惑,明明发了很多请求啊,为什么这日志里都没有呢?
原因很简单,因为Exceptionless默认只拦截Exception信息,所以如果一切正常没有Exception被throw出来的话是看不到的。
当然你也可以自己主动throw一些什么出来,这官网文档里都有。
如
ex.ToExceptionless.Submit();
这样的。
whether
可否拦截所有请求呢,怎么做?
可以。
自定义一个过滤器,将过滤器添加到每个api接口的Attribute上,即可生效。
思路很简答了,想怎么实现花样就多了。
不罗嗦,直接上我的代码(webapi项目)。
- 项目中直接写一个
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,
});
}
}
}
- 控制器中直接使用,如下图:
- 至于过滤器究竟是放在控制器的class上,还是具体的方法上,不再多说,稍有经验的都懂。
- 最后,日志可见所有请求。
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
});