2011-03-02 58 views
5

NLOG允許我使用SplitGroup登錄我的消息幾個目標。我想一次使用此功能日誌中的每個消息共同的,用戶特定的和特定日期的日誌如何在NLog中將不同的佈局應用於同一個目標?

<variable name="commonLog" value="${logDir}\Common.log" /> 
<variable name="username" value="${identity:fSNormalize=true:authType=false:isAuthenticated=false}" /> 
<variable name="userLog" value="${logDir}\ByUser\${username}.log" /> 
<variable name="dateLog" value="${logDir}\ByDate\${shortdate}.log" /> 

<target name="logFiles" xsi:type="SplitGroup"> 
    <target xsi:type="File" fileName="${commonLog}" layout="${myLayout}" /> 
    <target xsi:type="File" fileName="${userLog}" layout="${myLayout}" /> 
    <target xsi:type="File" fileName="${dateLog}" layout="${myLayout}" /> 
</target> 

這是偉大的,但我也想使用不同的佈局不同程度的嚴重程度。例如,errorLayout將包括異常信息,並插入[!]標記,以便我以後可以突出日誌查看類似錯誤BareTail

<variable name="stamp" value="${date} ${username} ${logger}" /> 

<variable name="debugLayout" value="${stamp} ... ${message}" /> 
<variable name="infoLayout" value="${stamp} [i] ${message}" /> 
<variable name="warnLayout" value="${stamp} [!] ${message}" /> 
<variable name="errorLayout" 
    value="${warnLayout}${newline}${pad:padding=10:inner=${exception:format=ToString}}" /> 

<!-- logFiles target --> 

<rules> 
    <logger name="*" level="Debug" writeTo="logFiles" layout="debugLayout" /> 
    <logger name="*" level="Info" writeTo="logFiles" layout="infoLayout" /> 
    <logger name="*" level="Warn" writeTo="logFiles" layout="warnLayout" /> 
    <logger name="*" level="Error" writeTo="logFiles" layout="errorLayout" /> 
</rules> 

此代碼假定Error總是配有例外和Warning,說自己是,但事實並非點。

問題是這個配置是錯誤。它不會工作,因爲logger沒有layout屬性。它僅限於target。正在使用

佈局必須通過目標來宣佈自己,但我看到了不同的嚴重程度指定不同的佈局的手段。

現在,我不得不四次複製粘貼相同的配置代碼只是爲了有四種不同的layout S代表同一個文件集:

<targets> 
    <target name="logFilesDebug" xsi:type="SplitGroup"> 
    <target xsi:type="File" fileName="${commonLog}" layout="${debugLayout}" /> 
    <target xsi:type="File" fileName="${userLog}" layout="${debugLayout}" /> 
    <target xsi:type="File" fileName="${dateLog}" layout="${debugLayout}" /> 
    </target> 

    <target name="logFilesInfo" xsi:type="SplitGroup"> 
    <target xsi:type="File" fileName="${commonLog}" layout="${infoLayout}" /> 
    <target xsi:type="File" fileName="${userLog}" layout="${infoLayout}" /> 
    <target xsi:type="File" fileName="${dateLog}" layout="${infoLayout}" /> 
    </target> 

    <target name="logFilesWarn" xsi:type="SplitGroup"> 
    <target xsi:type="File" fileName="${commonLog}" layout="${warnLayout}" /> 
    <target xsi:type="File" fileName="${userLog}" layout="${warnLayout}" /> 
    <target xsi:type="File" fileName="${dateLog}" layout="${warnLayout}" /> 
    </target> 

    <target name="logFilesError" xsi:type="SplitGroup"> 
    <target xsi:type="File" fileName="${commonLog}" layout="${errorLayout}" /> 
    <target xsi:type="File" fileName="${userLog}" layout="${errorLayout}" /> 
    <target xsi:type="File" fileName="${dateLog}" layout="${errorLayout}" /> 
    </target> 
</targets> 

<rules> 
    <logger name="*" level="Debug" writeTo="logFilesDebug" /> 
    <logger name="*" level="Info" writeTo="logFilesInfo" /> 
    <logger name="*" level="Warn" writeTo="logFilesWarn" /> 
    <logger name="*" level="Error" writeTo="logFilesError" /> 
</rules> 

這只是傷害了我的眼睛。
有沒有更好的方式來做到這一點,避免重複?

回答

1

我不知道,但我認爲你可能堅持與重複。你想要在同一個文件上使用4種不同的佈局,你需要3個不同的文件。一個目標需要一個佈局。所以,如果你只想登錄到1個文件,你仍然需要定義4個目標,每個目標指向同一個文件,每個都有自己的佈局。我不認爲NLog有更方便的方法將多個Layouts與Target相關聯,然後根據日誌消息的內容選擇一個Layout。

根據您想要使用您的格式實現的目標,您可以通過編寫自定義的LayoutRenderer來減少重複工作。在你的例子中,你會發現Debug版面裏面有「...」,Info有[i],Warn有[!],Error有警告+異常。您可以編寫一個LayoutRenderer來添加特殊標記,具體取決於消息的級別。這樣,您可以將Debug,Info和Warn全部集成到一個Layout中,並且Error將保留其自己的Layout。

例如:

事情是這樣的自定義LayoutRenderer(基於NLOG 1.0刷新,而不是2.0):

[LayoutRenderer("LevelMarkerLayoutRenderer")] 
    class LevelMarkerLayoutRenderer : LayoutRenderer 
    {  
    int estimatedSize = 3;  
    protected override void Append(StringBuilder builder, LogEventInfo logEvent) 
    {  
     string marker; 
     switch (logEvent.Level) 
     { 
     case Debug: 
      marker = "..."; 
      break; 
     case Info: 
      marker = "[i]"; 
      break; 
     case Warn: 
      marker = "[!]"; 
      break; 
     case Error: 
      marker = "[!]"; 
      break; 
     case Fatal: 
      marker = "[!]"; 
      break; 
     default: 
      marker = "?"; 
     } 

     builder.Append(marker);  
    }  

    protected override int GetEstimatedBufferSize(LogEventInfo logEvent)  
    {  
     return estimatedSize;  
    } 
    } 

現在,您可以配置兩個佈局: 「正常」 和「錯誤」。

喜歡的東西:

<variable name="stamp" value="${date} ${username} ${logger}" /> 

<variable name="normal" value="${stamp} ${LevelMarkerLayoutRenderer} ${message}" /> 
<variable name="error" 
    value="${warnLayout}${newline}${pad:padding=10:inner=${exception:format=ToString}}" /> 

你也許甚至創建一個自定義LayoutRenderer來處理異常。如果沒有例外,請不要輸出任何內容。如果是異常,concatenate換行符,填充和異常字符串。

如果你有一個「條件」異常佈局渲染器,那麼你可能只是一個佈局可能看起來像這樣的:

<variable name="normal" value="${stamp} ${LevelMarkerLayoutRenderer} ${message} ${ConditionalExceptionLayoutRenderer}" /> 

大多數時候,ConditionalExceptionLayoutRenderer會產生空,因爲不會有一個例外。

希望這會有所幫助。

+0

感謝您的評論。現在我想堅持最小的依賴關係,但是當我重新設計系統時,也許我會實現這一點。 –

8

另一種解決方案是在佈局中使用when條件。

target.Layout = "${longdate}|[${level}]|${logger}|${message}${onexception:inner=|${exception}${when:when=(level > LogLevel.Warn):inner=|[!] ${exception:format=ToString:innerFormat=Message:maxInnerExceptionLevel=5} }}" 

我想在出現錯誤時提供異常消息。當出現錯誤時,我想要完整的堆棧跟蹤。

+0

這應該是被接受的答案。如果我正確理解OP,應該重新考慮這個問題來具體解決這個問題:「我還希望針對不同嚴重程度使用不同的佈局」,然後這將是適當的答案。 – MattM

相關問題