Exceptionless(二) - 使用進階

markjiang7m2發表於2019-06-29

Exceptionless(二) - 使用進階

作者:markjiang7m2
原文地址:https://www.cnblogs.com/markjiang7m2/p/11100563.html
官網地址:http://letyouknow.net

在上一篇文章Exceptionless - .Net Core開源日誌框架中就說到如何對Exceptionless進行本地化部署,不過我也跟大家說了,僅限於能用的階段。那今天我就繼續來探討一下如何再用好。

後臺執行服務

上次我就是直接通過指令碼Start-ElasticSearch.ps1啟動ElasticSearch和Kibana服務,但是大家也能看到,服務是執行起來了,同時還有兩個命令視窗,如果一個不小心把視窗關閉了,服務也就關閉了,而且一旦伺服器重啟了,這兩個服務也不會自動啟動。
我這裡先暫時把Kibana扔一邊去,來看看ElasticSearch服務。ElasticSearch是直接有指令碼支援將ElasticSearch安裝為Windows服務,在後臺執行。

less_23_searchservicebat

就是這個elasticsearch-service.bat指令碼,支援一下引數:

  • install 將Elasticsearch作為服務安裝
  • remove 刪除已安裝的Elasticsearch服務(並在啟動時停止服務)
  • start 啟動Elasticsearch服務(如果已安裝)
  • stop 停止Elasticsearch服務(如果啟動)
  • manager 啟動一個GUI來管理已安裝的服務

安裝
命令列,進入到elasticsearch-service.bat所在的目錄,然後執行下面的指令碼

elasticsearch-service.bat install

啟動

less_25_servicestarted

這個時候我們可以直接在瀏覽器訪問9200埠看看服務是否正常

less_26_serviceconfirm

繼續使用上次部署好的Exceptionless
(如何使用IIS部署Exceptionless Web服務,請看Exceptionless - .Net Core開源日誌框架

因為我是直接用回之前ElasticSearch的節點,而且也沒有清空資料,所以可以直接用之前註冊的賬號重新登入

less_27_weblogin

也是成功的,ElasticSearch服務已經執行在後臺了。

自動啟動
通過ElasticSearch提供的GUI可以將服務設定為自動啟動

elasticsearch-service.bat manager

Startup Type選擇為Automatic,再點選OK儲存

less_28_serviceauto

這樣,即使伺服器重啟了,我們的ElasticSearch服務也會自動啟動

其實,有玩過Windows服務的朋友一定知道,上面的一些操作在Windows自帶的服務管理器也能完成

同時按下"WIN+R" 開啟服務的命令執行視窗。在服務執行視窗中輸入services.msc

在列表中也可以找到ElasticSearch服務,雙擊開啟屬性視窗,跟剛剛的GUI操作就是一樣的了

less_29_windowsservice

再看Web.config

上次我只是改了Exceptionless的埠設定,其實這裡面還包含很多配置資訊

<add name="RedisConnectionString" connectionString="localhost:6379,abortConnect=false" />
<add name="ElasticSearchConnectionString" connectionString="http://localhost:9200" />

官方是建議大家安裝和配置Redis,這樣就可以同時執行多個例項,並且重啟不會丟失狀態,強烈建議在Linux上執行Redis 3.0+版本,RedisConnectionString就是Redis的連線串

ElasticSearchConnectionString是必須的,指向ElasticSearch服務,如果有多個節點,則使用,隔開

<!-- Exceptionless Web 基礎Url -->
<add key="BaseURL" value="http://localhost:50001/#" />
<!-- 是否啟用ssl -->
<add key="EnableSSL" value="false" />
<!-- 
Dev: Use this mode when debugging. (Outbound emails will not be sent)
QA: Use this mode when deployed to staging. (Outbound emails restricted)
Production: Use this mode when deployed to production.
-->
<add key="WebsiteMode" value="Production" />
<!-- Controls whether users can signup. -->
<add key="EnableAccountCreation" value="true" />
<!-- Controls whether daily summary emails are sent -->
<add key="EnableDailySummary" value="true" />

網站模式WebsiteMode主要是限制郵件傳送,預設值是Dev,不傳送郵件,所以我這裡設定為Production

郵件傳送配置,記得跟上面的WebsiteMode一起配置

<add key="SmtpHost" value="smtp.qq.com" />
<add key="SmtpPort" value="25" />
<add key="SmtpEncryption" value="SSL" />
<add key="SmtpUser" value="xxx@qq.com" />
<add key="SmtpPassword" value="xxx" />

我在案例中使用的是自己的qq郵箱。我在qq郵箱中已經開啟了SMTP服務,並且也通過一個控制檯應用程式測試可以傳送郵件。
但是在Exceptionless這裡一樣的設定就是不行,在Web中點選傳送郵件,log記錄錯誤如下:
ERROR MailMessageJob Job run "MailMessageJob" failed: 由於意外的資料包格式,握手失敗。 System.IO.IOException: 由於意外的資料包格式,握手失敗。

清除Url
我們現在使用的Url都會帶有#!,例如

http://localhost:50001/#!/type/error/dashboard

可以按照下面步驟清除字元#!

  • 首先保證你的IIS是否已經安裝了重寫模組,可通過雙擊IIS中的模組檢視是否包含了RewriteModule
  • 更新Web.config檔案
    • 釋放出在system.webServer中的rewrite節點
    • 刪除BaseURL值中的/#
    • 註釋了在system.webServer\modules中的<remove name="RewriteModule" />標籤
  • 修改app.config.77fc9ddd679d37dc.js檔案中USE_HTML5_MODE的值為true

程式外執行作業
預設情況下,所有作業都在當前的Web程式中執行。如果發現事件處理開始變慢的時候,可以啟動並擴充套件多個作業例項。通過在程式外執行作業,可以確保所有作業是否正常執行。

  • 首先是要配置安裝Redis,這樣可以保證Exceptionless與作業之間能夠進行通訊
  • 更新Web.config中的RunJobsInProcess值為false
  • 更新作業的配置,有兩種方法可選:
    • 使用環境變數進行配置Exceptionless。新增環境變數Exceptionless_{SETTING NAME} (例如: Exceptionless_BaseURL, Exceptionless_ElasticSearchConnectionString)。這是官方推薦的方法,因為它更簡單,而且當部署到azure時非常好用
    • 開啟App_Data\jobs資料夾,然後按照在根目錄中Web.config的配置,再重新配置每個作業的xxx.exe.config
  • 在每個作業資料夾中都有一個run.bat檔案,雙擊它就會執行這個作業。當然,也可以將這些作業全部設定為Windows服務在後臺執行

更多設定
除了上面提到的設定,Exceptionless還支援很多自定義配置,下面是全部的設定列表,大家可根據自己的需要進行定製
列表按照這個格式進行排列:設定項 (資料型別,預設值)

EnableSSL (bool)
BaseURL (string)
InternalProjectId (string, "54b56e480ef9605a88a13153")
WebsiteMode (WebsiteMode, "Dev")
AppScope (string, String.Empty)
TestEmailAddress (string)
AllowedOutboundAddresses (List<string>, "exceptionless.io")
RunJobsInProcess (bool, true)
BotThrottleLimit (int, 25)
ApiThrottleLimit (int, Int32.MaxValue)
EventSubmissionDisabled (bool)
MaximumEventPostSize (long, 1000000)
MaximumRetentionDays (int, 180)
EnableDailySummary (bool)
MetricsServerName (string, "127.0.0.1")
MetricsServerPort (int, 8125)
EnableMetricsReporting (bool)
RedisConnectionString (string)
EnableRedis (bool)
DisableSnapshotJobs (bool)
DisableIndexConfiguration (bool)
ElasticSearchConnectionString (string)
ElasticSearchNumberOfShards (int, 1)
ElasticSearchNumberOfReplicas (int)
EnableElasticsearchTracing (bool)
LdapConnectionString (string)
EnableActiveDirectoryAuth (bool)
EnableSignalR (bool, true)
Version (string)
EnableIntercom (bool)
IntercomAppSecret (string)
EnableAccountCreation (bool, true)
MicrosoftAppId (string)
MicrosoftAppSecret (string)
FacebookAppId (string)
FacebookAppSecret (string)
GitHubAppId (string)
GitHubAppSecret (string)
GoogleAppId (string)
GoogleAppSecret (string)
GoogleGeocodingApiKey (string)
EnableBilling (bool)
StripeApiKey (string)
StorageFolder (string)
AzureStorageConnectionString (string)
EnableAzureStorage (bool)
BulkBatchSize (int, 1000)
SmtpHost (string)
SmtpPort (int, 587)
SmtpEnableSsl (bool, true)
SmtpUser (string)
SmtpPassword (string)

更多日誌型別

Exceptionless除了支援記錄Exception,也可以記錄LogMessage、Broken Links 、Feature Usages

LogMessage
LogMessage支援多種級別的日誌資訊

  • Other
  • Trace
  • Debug
  • Info
  • Warn
  • Error
  • Fatal
  • Off

用法也很簡單,直接在你想要記錄日誌的地方直接加一句

ExceptionlessClient.Default.CreateLog("日誌資訊", LogLevel.Debug).AddTags("tag1", "tag2").Submit();

所以我們在應用的過程中,可以新增一個統一的介面

public interface ILogger
{
    void Debug(string message, params string[] tags);
    void Error(string message, params string[] tags);
    void Fatal(string message, params string[] tags);
    void Info(string message, params string[] tags);
    void Off(string message, params string[] tags);
    void Other(string message, params string[] tags);
    void Trace(string message, params string[] tags);
    void Warn(string message, params string[] tags);
}
using Exceptionless;
using Exceptionless.Logging;
public class ExceptionlessLogger : ILogger
{
    public void Debug(string message, params string[] tags)
    {
        ExceptionlessClient.Default.CreateLog(message, LogLevel.Debug).AddTags(tags).Submit();
    }

    public void Error(string message, params string[] tags)
    {
        ExceptionlessClient.Default.CreateLog(message, LogLevel.Error).AddTags(tags).Submit();
    }

    public void Fatal(string message, params string[] tags)
    {
        ExceptionlessClient.Default.CreateLog(message, LogLevel.Fatal).AddTags(tags).Submit();
    }

    public void Info(string message, params string[] tags)
    {
        ExceptionlessClient.Default.CreateLog(message, LogLevel.Info).AddTags(tags).Submit();
    }

    public void Off(string message, params string[] tags)
    {
        ExceptionlessClient.Default.CreateLog(message, LogLevel.Off).AddTags(tags).Submit();
    }

    public void Other(string message, params string[] tags)
    {
        ExceptionlessClient.Default.CreateLog(message, LogLevel.Other).AddTags(tags).Submit();
    }

    public void Trace(string message, params string[] tags)
    {
        ExceptionlessClient.Default.CreateLog(message, LogLevel.Trace).AddTags(tags).Submit();
    }

    public void Warn(string message, params string[] tags)
    {
        ExceptionlessClient.Default.CreateLog(message, LogLevel.Warn).AddTags(tags).Submit();
    }
}

然後在Startup.csConfigureServices方法注入ExceptionlessLogger

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<ILogger, ExceptionlessLogger>();
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

這樣就可以更方便地使用了

public class ValuesController : ControllerBase
{
    public ILogger _logger;
    public ValuesController(ILogger logger)
    {
        _logger = logger;
    }
    
    // GET api/values/{id}
    [HttpGet("{id}")]
    public ActionResult<string> Get(int id)
    {
        try
        {
            _logger.Info("Test msg", "tag1", "tag2");
            throw new Exception();
        }
        catch (Exception ex)
        {
            ex.ToExceptionless().AddTags("tag1", "tag2").Submit();
        }
        return $"value {id}";
    }
}

Broken Links
記錄404找不到請求的日誌

像我這裡沒有新增favicon.ico圖示,使用Chrome瀏覽器會自動請求這個資源,因此,Exceptionless就記錄了這樣的日誌

less_30_brokenlinks

也可以直接在Api服務中呼叫如下面語句新增這種型別的日誌

ExceptionlessClient.Default.CreateNotFound("404 not found").SetType("404").SetSource($"api/values/{id}");

Feature Usages
類似的也可以新增Feature Usages日誌

ExceptionlessClient.Default.CreateFeatureUsage("Feature 1").SetSource($"api/values/{id}").SetType("FeatureType").Submit();

事件

上面所說的所有日誌型別,最終都會通過事件進行記錄,Exceptionless也支援我們直接記錄一個事件

例子如下:

var dataDic = new Exceptionless.Models.DataDictionary();
dataDic.Add("key", "value");
ExceptionlessClient.Default.SubmitEvent(new Exceptionless.Models.Event
{
    Count = 1,
    Date = DateTime.Now,
    Data = dataDic,
    Geo = "geo",
    Message = "message",
    ReferenceId = "referencelId",
    Source = "source",
    Tags = new Exceptionless.Models.TagSet() { "tags" },
    Type = "type"
});

Exceptionless同時也支援我們捕獲事件提交過程和事件提交後的事件,這樣我們就可以在過程中做一些操作,例如可以忽略404的請求,或者針對某些特殊日誌返回某些資訊

為了程式碼的整潔,可以將Exceptionless的配置單獨放到一個cs檔案中

新增一個ExceptionlessBuilderExtensions

public static class ExceptionlessBuilderExtensions
{
    public static IApplicationBuilder UseExceptionless(this IApplicationBuilder app, IConfiguration configuration)
    {
        ExceptionlessClient.Default.Configuration.ApiKey = configuration["Exceptionless:ApiKey"];
        ExceptionlessClient.Default.Configuration.ServerUrl = configuration["Exceptionless:ServerUrl"];
        ExceptionlessClient.Default.SubmittingEvent += OnSubmittingEvent;
        app.UseExceptionless();

        return app;
    }

    private static void OnSubmittingEvent(object sender, EventSubmittingEventArgs e)
    {
        if (e.Event.IsNotFound())
        {
            e.Cancel = true;//取消事件提交
            return;
        }

        // 修改日誌資訊
        if (e.Event.Source == "sourceA")
        {
            e.Event.AddTags("systemLog");
        }

        //TODO:
    }

    private static void OnSubmittedEvent(object sender, EventSubmittedEventArgs e)
    {
        // 做點什麼東西
        if (e.Event.Source == "sourceA")
        {
            //TODO:
        }
    }
}

然後修改Startup.cs

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    ……

    app.UseExceptionless(Configuration);

    ……
}

Exceptionless 日誌查詢

Exceptionless Web站點已經幫我們做好專案、時間、日誌型別的分類,大家可以很直觀地進行操作查詢。
我這裡要關注的是Filter查詢

前面記錄日誌的時候,有新增了tagType等資訊,這時候就可以使用Filter進行查詢了。
語法:

[FilterType]:[value1] {or} {[value2]}

or是用於查詢多個該型別值的日誌時使用

例如:tag:tag1

less_32_filtertag

列幾個可能比較常用的

  • source:"my log source" or "my log source"
  • type:error
  • level:Error
  • ip:127.0.0.1

如果是要同時輸入多種型別的條件:

[FilterType]:[value] {OR|AND} {[FilterType]:[value]}

例如:tag:tag1 OR ip:127.0.0.1

更多的語法可以看官網說明
https://github.com/exceptionless/Exceptionless/wiki/Filtering-Searching

總結

在這篇文章中,我基本就是順著Exceptionless Self Hosting的介紹做了一遍,不過有一些東西因為沒有實際環境,所以也沒有去做,然後我這個也只是一個Demo,暫時也沒有做相關的壓力測試,所以也不知道這貨真正在生產環境大量用起來的時候會有一些什麼表現,會不會踩到什麼坑。歡迎大家在留言區跟我一起交流。今天就先跟大家介紹到這裡,希望大家能持續關注我們。

參考文獻
本文在編寫過程中引用或參考了以下文章中的部分內容,如有侵權,請聯絡修改或刪除。
https://www.cnblogs.com/edisonchou/p/exceptionless_deployment_on_production_env_introduction.html
https://www.cnblogs.com/ants/p/8580890.html

相關文章