天天看點

.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
            });      

繼續閱讀