這個問題要分大緻分為三個階段:
- 何為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
});