在上一篇文章Exceptionless - .Net Core開源日誌框架中就說到如何對Exceptionless進行本地化部署,不過我也跟大家說了,僅限於能用的階段。那今天我就繼續來探討一下如何再用好。 ...
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服務,在後臺運行。
就是這個elasticsearch-service.bat
腳本,支持一下參數:
- install 將Elasticsearch作為服務安裝
- remove 刪除已安裝的Elasticsearch服務(併在啟動時停止服務)
- start 啟動Elasticsearch服務(如果已安裝)
- stop 停止Elasticsearch服務(如果啟動)
- manager 啟動一個GUI來管理已安裝的服務
安裝
命令行,進入到elasticsearch-service.bat
所在的目錄,然後執行下麵的腳本
elasticsearch-service.bat install
啟動
這個時候我們可以直接在瀏覽器訪問9200
埠看看服務是否正常
繼續使用上次部署好的Exceptionless
(如何使用IIS部署Exceptionless Web服務,請看Exceptionless - .Net Core開源日誌框架)
因為我是直接用回之前ElasticSearch的節點,而且也沒有清空數據,所以可以直接用之前註冊的賬號重新登錄
也是成功的,ElasticSearch服務已經運行在後臺了。
自動啟動
通過ElasticSearch提供的GUI可以將服務設置為自動啟動
elasticsearch-service.bat manager
將Startup Type
選擇為Automatic
,再點擊OK保存
這樣,即使伺服器重啟了,我們的ElasticSearch服務也會自動啟動
其實,有玩過Windows服務的朋友一定知道,上面的一些操作在Windows自帶的服務管理器也能完成
同時按下"WIN+R" 打開服務的命令運行視窗。在服務運行視窗中輸入services.msc
在列表中也可以找到ElasticSearch服務,雙擊打開屬性視窗,跟剛剛的GUI操作就是一樣的了
再看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="[email protected]" />
<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.cs
的ConfigureServices
方法註入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就記錄了這樣的日誌
也可以直接在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
查詢
前面記錄日誌的時候,有添加了tag
、Type
等信息,這時候就可以使用Filter進行查詢了。
語法:
[FilterType]:[value1] {or} {[value2]}
or是用於查詢多個該類型值的日誌時使用
例如:tag:tag1
列幾個可能比較常用的
- 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