NET 的 ELK 監控方案


NET 的 ELK 監控方案

https://www.jianshu.com/p/3c26695cfc38

背景就不多說了,誰家沒有個幾個十系統在跑啊。如何監控這幾十個系統的運行狀況,對於非運營人員來說,太TM五花八門了。。
背景就不多說了,誰家沒有個幾個十系統在跑啊。如何監控這幾十個系統的運行狀況,對於非運營人員來說,太TM五花八門了。。。

名詞
ELK = ElashticSearch + LogStash + Kibana
Lucene 是搜索引擎,搜索引擎的特點就不用說了吧。但是使用起來不是太直觀。
ElashticSearch (簡稱 ES) 是基於 Luncene 的。它提供了一套易於使用的語法,關鍵一點:它可以很方便的透過 http 來操作。
Logstash 主要是用來分析(處理)日志的(不知道這樣講妥不妥)。通過指定 Logstash 的 Output ,可以把處理的結果寫到 ES 中。
Kibana 是用於制定各種報表的。
也就是說ELK中的: E(存儲),L(處理), K(展示)

ELK 需要 JAVA 運行環境,但不代表它是 JAVA世界的專用工具。

由來已久的門派對立
做為.NET開發人員,對 JAVA工具 多多少是有點抵觸的,能不用就不用,能少用就少用,實在沒辦法在查資料。。。我也是這樣過來的。

log4net 相信大家都在用,所以我的最開始的方案是寫個 log4net 的Appender 擴展, 從 AppenderSkeleton 派生一個 ESAppender , 代碼很簡單,不在這里展示了。

但是寫日志的速度有點快(每天生產1.5G左右的文本日志,還是簡化過的。。。), ES 的狀態不確定,可能會導致數據丟失,或是ES處理不及時,拖程序的后腿等。搜集日志是小事,拖程序后腿就是大事了。。。

所以,最終還是老老實的使用 ELK 這一套完整的方案:
擴展log4net 寫 json 格式的日志, logstash 搜集這些日志。。。

如何整合 ELK 到.NET 項目中
正如上面所說的原因,此處用 log4net 寫json 格式的文本日志,因為 logstash 的配置語法是我們這些“基於界面”的,“頭腦簡單”的程序員不能理解的(太麻煩,真心疼JAVA程序員,每天面對那么多天書一樣的配置); json 格式的日志,在 logstash 中,是會被按原樣寫入到 ES中的,省去那一堆不能理解的 filter 的 配置。

擴展 log4net ,從 LayoutSkeleton 派生一個 JsonLayout

///


///
///

public class JsonLayout : LayoutSkeleton
{

public override string ContentType
{
    get
    {
        return "application/json";
    }
}


public JsonLayout()
{
    this.IgnoresException = false;
}

public override void ActivateOptions()
{
    //
}

public override void Format(TextWriter writer, LoggingEvent evt)
{
    if (!evt.Level.DisplayName.Equals("ES"))
        return;

    var info = evt.LocationInformation;

    var exTitle = "";
    var exStack = "";
    if (evt.ExceptionObject != null)
    {
        exTitle = evt.ExceptionObject.Message;
        exStack = evt.ExceptionObject.StackTrace;
    }

    var msg = new JsonMsg()
    {
        ESIndexPrefix = ESIndex.ESIndexPrefix,
        Logger = evt.LoggerName,
        //@Class = info.ClassName,//發布后,獲取不到該參數
        //File = info.FileName,//發布后,獲取不到該參數
        //Line = info.LineNumber,//發布后,獲取不到該參數
        //Method = info.MethodName,//發布后,獲取不到該參數
        CreatedOn = evt.TimeStamp,
        App = evt.Domain,
        //Level = evt.Level.Name, 無用,點硬盤
        Data = evt.MessageObject,
        ExTitle = exTitle,
        ExStack = exStack
    };

    var json = JsonConvert.SerializeObject(msg);
    writer.WriteLine(json);
}

}
IgnoresException = false 是忽略 Exception 的輸出,否則,會在 json 字符串后面追加一串字符串用於描述異常信息。

JsonMsg.cs

internal class JsonMsg
{

[JsonProperty("i")]
public string ESIndexPrefix
{
    get;
    set;
}

[JsonProperty("L")]
public string Logger
{
    get;
    set;
} 

[JsonProperty("On")]
public DateTime CreatedOn
{
    get;
    set;
}

[JsonProperty("D")]
public object Data
{
    get;
    set;
}

[JsonProperty("Ex")]
public string ExStack
{
    get;
    set;
}

[JsonProperty("ExT")]
public string ExTitle
{
    get;
    set;
}

public string App
{
    get;
    set;
}

}
添加一個 helper

public static class LogHelper
{

private static readonly Type DeclareType = typeof(LogHelper);

private static readonly Level Level = new Level(130000, "ES");

public static void ES(this ILog logger, AnalyzeLogItem data, Exception ex = null)
{
    logger.Logger.Log(DeclareType, Level, data, ex);
}

}
這段代碼中自定義了一個叫 "ES" 的 LEVEL, 還定義了一個很簡單的擴展函數,使用自定義的參數: AnalyzeLogItem, 這個 AnalyzeLogItem 就是要用於分析的數據,比如執行時間,執行是成功還是失敗,響應請求還是發送請求等等,依自己的需求而定。

然后修改一下 log4net.config

<appender-ref ref="InfoFileAppender" />
<appender-ref ref="ErrorFileAppender" />
<appender-ref ref="FatalFileAppender" />
<appender-ref ref="DebugFileAppender" />
<appender-ref ref="WARNFileAppender" />

<appender-ref ref="ESAppender" />
注意第一段(ESAppender)中的 layout type="XXX.JsonLayout,XXX", 修改為自己的包名。 另外,不能使用 UTF-8 。 因為在 WINDOWS 下,log4net 生產的UTF-8 日志文件默認是帶BOM 的,logstash 這種JAVA世界的工具,太理想化,好像壓根就沒有考慮過 BOM 的問題,從而導至數據丟失嚴重(有多嚴重?幾百萬日記只分析出來個零頭)。。。 如果logstash 控制台中出現以下這樣的字眼,那就八九不離十了:

11:17:54.244 [[main]<file] ERROR logstash.codecs.json - JSON parse error, original data now in message field {:error=>#<LogStash::Json::ParserError: Unexpected character ('???' (code 65279 / 0xfeff)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')
最后,在你的 AssemblyInfo 中添加:

[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]
配置 logstash
上面說了,我們直接生成 json 格式的日志記錄,就是為了避免復雜的 logstash 配置。 所以這里的配置很簡單:

input{
file {
path => [
"D:/Web/Api1/W1/logES/.",
"D:/Web/Api1/W2/logES/."
]
codec => "json"
}
}

output {
elasticsearch {
hosts => ["10.89.70.70:9600"]
index => "%{i}-%{+YYYY.MM.dd}"
}
}
path 節點中的兩行即是要分析的日志路徑,多條用逗號分開。
hosts 即 ES 的地址(用內網地址比外網地址快不止一個數量級)
index 即動態的 index 名稱, 其中的 i (%{i}) 即產生的 json log 中的 i (也就是上文中的 JsonMsg 中的 ESIndexPrefix). 這樣做的好處是可以將不同的系統的日志數據按 index 分類。
Kibana
kibana 的配置就不說了,太簡單, 這里只上一張最終的日志分析出來的效果圖:

作者:gruan
鏈接:https://www.jianshu.com/p/3c26695cfc38
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM