根據this log4net文章,您應該檢查是否在任何Log.Debug語句之前啓用調試以消除語句構建成本。在任何日誌語句之前,是否有更好的選擇來總是檢查(Log.IsDebugEnabled)?Log4Net消息在未調試時的構建成本
log4net的例子:
if (log.IsDebugEnabled)
{
log.Debug("This is entry number: " + i);
}
我不想支付語句建設的開銷,但也不想檢查每一個日誌聲明之前。
根據this log4net文章,您應該檢查是否在任何Log.Debug語句之前啓用調試以消除語句構建成本。在任何日誌語句之前,是否有更好的選擇來總是檢查(Log.IsDebugEnabled)?Log4Net消息在未調試時的構建成本
log4net的例子:
if (log.IsDebugEnabled)
{
log.Debug("This is entry number: " + i);
}
我不想支付語句建設的開銷,但也不想檢查每一個日誌聲明之前。
也不想檢查每一個日誌語句
當你發現自己一遍又一遍地重複相同的代碼之前,這聽起來像一個普通的抽象可能爲了。在這種情況下,您可以爲Log4Net創建自定義包裝。一些簡單的:
public static class Logger
{
private static ILog _log;
static Logger()
{
log4net.Config.XmlConfigurator.Configure();
_log = log4net.LogManager.GetLogger("Log4Net");
}
public static void Debug(string message)
{
if (_log.IsDebugEnabled)
_log.Debug(message);
}
public static void Info(string message)
{
_log.Info(message);
}
public static void Warn(string message)
{
_log.Warn(message);
}
public static void Error(string message)
{
_log.Error(message);
}
public static void Error(string message, Exception ex)
{
_log.Error(message, ex);
}
public static void Fatal(string message)
{
_log.Fatal(message);
}
public static void Fatal(string message, Exception ex)
{
_log.Fatal(message, ex);
}
}
在這種情況下,我使記錄器實例靜態。我不是100%肯定會始終按預期工作。通常我在依賴注入框架後面使用它,並將記錄器依賴性配置爲由框架處理的單例。您可以改爲使用實例方法將其作爲實例類,並將其放在靜態工廠類的後面。根據需要進行測試和調整。
有一對夫婦的額外的好處在這裏:
我的第三個好處通常使用一個例子可能是這樣的:
private static string GetLocation()
{
var frame = new StackTrace(1).GetFrame(1);
var method = frame.GetMethod();
return string.Format("{0}:{1}.{2}({3})", Environment.MachineName, method.ReflectedType.FullName, method.Name, frame.GetFileLineNumber().ToString());
}
這得到更有意義從運行系統調試信息(儘管可能有性能損失,對於高音量系統值得測試)。所以我傳遞錯誤日誌記錄功能可能是這樣的:
public void Error(string message, Exception ex)
{
_log.Error(string.Format("{0}:{1}", GetLocation(), message), ex);
}
我不會推薦用這種方式編寫一個包裝(將Info,Debug等委託給log4net的Info,Debug等)。 Log4net可以自己計算出適當的呼叫站點信息,而無需GetLocation中的代碼。正確包裝log4net的關鍵是使用Log方法並傳遞包裝類的類型作爲第一個參數。我會在答案中粘貼一個小例子。 – wageoghe
您可以使用lambda表達式。如:
log.Debug(() => "This is entry number:" + i);
這樣,lambda只在.IsDebugEnabled調用後才被評估。
我們定義了一個擴展類(來自http://www.beefycode.com/post/Extension-Methods-for-Deferred-Message-Formatting-in-Log4Net.aspx拍攝),有擴展的方法,如:
public static class Log4NetExtensionMethods
{
public static void Debug(this ILog log, Func<string> formattingCallback)
{
if(log.IsDebugEnabled)
{
log.Debug(formattingCallback());
}
}
// .. other methods as required...
}
我不知道是否有log4net的在最近的版本中添加的λ類型的支持 - 但是這已經工作爲了我。
如果您試圖在只有一個特定的類上啓用調試日誌記錄,這是如何工作的? – sgmoore
我會看預處理器(預編譯?)指令。
#if DEBUG
{your logging code here}
#endif
類似的東西應該爲你做,然後代碼只能在調試模式下編譯。
您還可以使用的Conditional
屬性在這樣一個方法: [System.Diagnostics.Conditional(「DEBUG」)] 私人無效YourMethodNameHere(YourMethodSignatureHere)
看看這個老問題有關何時/爲什麼/如何使用它們的更多信息。
http://stackoverflow.com/questions/3788605/if-debug-vs-conditionaldebug
@Grhm和@大衛有好的想法,但我不認爲大衛的包裝一樣好,因爲它可以。用這種方式包裝log4net。簡單地在包裝器上實現Debug,Info等,並將它們委託給log4net的Debug,Info等方法可以打破log4net記錄呼叫站點信息的能力。如果以這種方式換行,並告訴log4net記錄呼叫站點信息,log4net將在包裝器中寫出呼叫站點,而不是實際代碼中的呼叫站點,這正是您想要的。
我個人不喜歡使用單例記錄器,因爲你失去了調整程序不同部分日誌級別的能力。如果您正在處理多個組件,則可能需要爲一個組件啓用信息級別日誌記錄,但只對其他組件進行警告日誌記錄(或根本沒有)。使用單例記錄器,所有應用程序中的所有日誌記錄都處於同一級別。
當您錯誤地將log4net換行並且使用單個記錄器來覆蓋整個應用程序時,您正在否認自己大量的log4net內置(和強大)功能。
我回答了類似的問題(關於維護調用點信息)在這裏:
how to log method name when using wrapper class with Log4net
爲了節省時間,我已經包括了代碼示例在這裏(未編譯的和未經考驗的,而應該是接近).. 。
public class MyLog4NetWrapper
{
ILog log;
public MyLog4NetWrapper(string loggerName)
{
log = LogManager.GetLogger(loggerName)
}
public MyLog4NetWrapper(type loggerType)
{
log = LogManager.GetLogger(loggerType)
}
public void Info(string message)
{
if (log.IsInfoEnabled) log.Logger.Log(typeof(MyLog4NetWrapper), LogLevel.Info, message, null);
}
//Defer expensive calculations unless logging is enabled - thanks Grhm for the example
public void Info(Func<string> formattingCallback)
{
if(log.IsInfoEnabled)
{
log.Logger.Log(typeof(MyLog4NetWrapper), LogLevel.Info, formattingCallback(), null);
}
}
//Debug, Warn, Trace, etc are left as an exercise.
}
您可以在代碼中創建這些記錄器是這樣的:
public class MyClass
{
private static readonly ILog log = new MyLoggerWrapper(typeof(MyClass));
public void DoSomething()
{
log.Info("Hello world!");
}
}
編寫保存呼叫站點信息的log4net包裝器的技巧是使用Log方法並將包裝類型作爲第一個參數傳遞。
如果您要寫一個包裝器來實現您所問的功能(推遲執行日誌調用中的任何代價昂貴的代碼,而不明確檢查是否啓用了所需的日誌記錄級別),那麼您可能會並將該代碼放入包裝中,而不是將其作爲擴展方法來實現(這也會導致上述呼叫網站問題的相同丟失)。
祝你好運!
將不起作用,MyLog4NetWrapper不是繼承自ILog – stenly
最簡單和最乾淨的方法可能是使用DebugFormat
方法,該方法實際上會檢查調試級別是否啓用(請參閱Github-Code of log4net)。
如果包含命名空間log4net。UTIL,你可以呼籲的log4net的ILog以下擴展方法:
public static void ErrorExt(this ILog logger, Func<object> callback)
啓用日誌錯誤級別時,這隻會調用lambda函數。無需編寫自己的擴展方法。它還通過將創建包裝在try catch方法中來防止在創建實際日誌消息時創建錯誤。
這些陳述在哪裏?他們是否一貫使用(即您是否將他們複製並粘貼到相同類型的地方)? –