2008-09-25 105 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种方法。如果它符合你的需求,那么你很好去!