2008-09-25 49 views
20

很多我的C#代碼通用日誌記錄遵循以下模式:的異常功能參數處理

void foo(string param1, string param2, string param3) 
{ 
    try 
    { 
     // do something... 
    } 
    catch(Exception ex) 
    { 
     LogError(String.Format("Error in foo(param1={0}, param2={1}, param3={2}), exception={3}", param1, param2, param3, ex.Message)); 
    } 
} 

是否有.NET的方式來獲取參數的鍵/值列表的功能,使我可以調用另一個函數來構造我的錯誤日誌字符串? 或 你有更通用/更好的方式來做到這一點嗎?

+0

可能與語言中的Reflection有關嗎? – nlucaroni 2008-09-25 20:27:09

+0

你可以通過反射來實現,但在許多函數調用過程中它會變得很昂貴。 – 2008-09-25 20:28:48

+3

我不認爲你可以用Reflection或StackTrace/StackFrame來做到這一點。我認爲你唯一的選擇可能是使用AOP或後處理框架,如PostSharp。 – 2008-09-25 20:29:16

回答

24

您可以使用反射,並且你必須傳遞的參數與正確的順序LOGERROR約定:

private static void MyMethod(string s, int x, int y) 
{ 
    try 
    { 
     throw new NotImplementedException(); 
    } 
    catch (Exception ex) 
    { 
     LogError(MethodBase.GetCurrentMethod(), ex, s, x, y); 
    } 
} 

private static void LogError(MethodBase method, Exception ex, params object[] values) 
{ 
    ParameterInfo[] parms = method.GetParameters(); 
    object[] namevalues = new object[2 * parms.Length]; 

    string msg = "Error in " + method.Name + "("; 
    for (int i = 0, j = 0; i < parms.Length; i++, j += 2) 
    { 
     msg += "{" + j + "}={" + (j + 1) + "}, "; 
     namevalues[j] = parms[i].Name; 
     if (i < values.Length) namevalues[j + 1] = values[i]; 
    } 
    msg += "exception=" + ex.Message + ")"; 
    Console.WriteLine(string.Format(msg, namevalues)); 
} 
1

當我這樣做時,我只是爲日誌記錄創建了一個通用字典。

我有這個LogArgs類。登錄一個當我有異常時調用的基類。

public class LogArgs 
{ 

    public string MethodName { get; set; } 
    public string ClassName { get; set; } 
    public Dictionary<string, object> Paramters { get; set; } 


    public LogArgs() 
    { 
     this.Paramters = new Dictionary<string, object>(); 
    } 

} 

然後在每個方法的開始我做的

LogArgs args = new LogArgs { ClassName = "ClassName", MethodName = "MethodName" }; 
args.Paramters.Add("Param1", param1); 
args.Paramters.Add("Param2", param2); 
args.Paramters.Add("Param3", param3); 

base.Logger.MethodStartLog(args); 

當我有一個錯誤我日誌這種方式。

base.Logger.LogError(args, ex); 
+4

有趣的想法,但是當你聽到自己說「在每個方法的開始我做X」時,考慮使用AOP框架(例如PostSharp,如其他用戶所建議的)。 – Abel 2014-09-26 13:33:40

5

不,沒有辦法做到這一點。

通常的做法是不接收異常,除非你能處理它們。

I.e.您通常只會捕獲異常並將它們記錄在頂級異常處理程序中。然後你會得到一個堆棧跟蹤,但當然不會獲取堆棧中所有方法調用的所有參數的詳細信息。

顯然,在調試時,您希望獲得儘可能多的細節。其他實現此目的的方法如下:

  • 使用Debug.Assert語句可以自由地測試您所做的假設。

  • 通過可以有選擇地激活的日誌記錄來處理應用程序。我使用Log4Net,但也有其他選擇,包括使用System.Diagnostics.Trace類。

在任何情況下,如果只捕捉異常登錄他們(我在N層應用層邊界做到這一點,使異常記錄在服務器上),那麼你應該總是重新拋出它們:

try 
{ 
    ... 
} 
catch(Exception ex) 
{ 
    log(ex); 
    throw; 
} 
+0

這展開了堆棧,這意味着不同的調用堆棧將被重新記錄。爲了規避這一點,現在是可能採取的異常過濾器的優勢: `嘗試 { // ... } 趕上(異常前)時(日誌(前)){ // 從未進入 } ` 其中函數`log`總是返回`false`。 – ensisNoctis 2017-04-04 13:20:46

1

您可以使用類似的構造消息的樣式,但在LogError方法中添加params關鍵字來處理參數。例如:

public void LogError(string message, params object[] parameters) 
    { 
     if (parameters.Length > 0) 
      LogError(string.Format(message, parameters)); 
     else 
      LogError(message); 
    } 
6

你可以使用面向方面的編程與PostSharp(看看http://www.postsharp.org,教程http://www.codeproject.com/KB/cs/ps-custom-attributes-1.aspx)。基本上你可以做這樣的事情:

public class LogExceptionAttribute : OnExceptionAspect 
{ 
public override void OnException(MethodExecutionEventArgs eventArgs) 
{ 
    log.error("Exception occurred in method {0}", eventArgs); 
} 
} 

[LoggingOnExceptionAspect] 
public foo(int number, string word, Person customer) 
{ 
    // ... something here throws an exception 
} 

也許不是你想要的,但我相信它可以適應你的需要。

-2

有幾個參數或參數大量的場景......

  1. 幾個參數,不無事生非,更好地把它們寫的日誌/異常消息的一部分。

  2. 在大參數中,多層應用程序將使用ENTITIES(如customer,CustomerOrder ...)在層之間傳輸數據。這些機構應實行 覆蓋的ToString()類對象的方法,有通過,

的LogMessage(「方法啓動」 + paramObj.ToString())將給予在對象數據的列表.. 任何意見呢? :)

感謝

0

這是有點過時的文章,但以防萬一有人遇到這種像我一樣 - 我用PostSharp解決了這個問題。

雖然它不是幾乎免費的。 Express許可證(可通過VS中的NuGet下載)允許您使用[Log]屬性修飾您的方法,然後選擇已配置的日誌記錄機制,如log4netnLog等。現在您將看到日誌中的調試級別條目,提供參數詳細信息。

有了快遞許可證,我只能在我的項目中裝飾最多50種方法。如果它符合你的需求,那麼你很好去!