exception处理中函数参数的通用日志记录
很多我的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中获取函数的键/值列表,以便我可以调用另一个函数来构造我的错误记录字符串? 或者你有更通用/更好的方法吗?
您可以使用Reflection和约定,您必须使用正确的顺序将参数传递给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)); }
您可以在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 }
也许不是你想要的,但我相信它可以根据你的需要进行调整。
没有办法做到这一点。
通常的做法是不捕获exception,除非你能处理它们。
也就是说,您通常只会捕获exception并将它们记录在顶级exception处理程序中。 然后,您将获得堆栈跟踪,但当然不会获得堆栈中所有方法调用的所有参数的详细信息。
显然,在调试时,您需要尽可能多的细节。 实现这一目标的其他方法是:
-
使用Debug.Assert语句来测试您正在进行的假设。
-
使用可以选择性激活的日志记录来检测应用程序。 我使用Log4Net,但也有其他选择,包括使用System.Diagnostics.Trace类。
在任何情况下,如果您只捕获exception以记录它们(我在n层应用程序的层边界执行此操作,以便在服务器上记录exception),那么您应该始终重新抛出它们:
try { ... } catch(Exception ex) { log(ex); throw; }
当我这样做时,我刚刚为日志记录创建了一个通用字典。
我有这个LogArgs类。 并登录我遇到exception时调用的基类。
public class LogArgs { public string MethodName { get; set; } public string ClassName { get; set; } public Dictionary Paramters { get; set; } public LogArgs() { this.Paramters = new Dictionary(); } }
然后在每个方法的开始我做
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);
您可以使用类似的构造消息的方式,但在LogError方法中添加params关键字来处理参数。 例如:
public void LogError(string message, params object[] parameters) { if (parameters.Length > 0) LogError(string.Format(message, parameters)); else LogError(message); }
这是一个过时的post,但万一有人遇到过像我这样的事情 – 我通过使用PostSharp解决了这个问题。
虽然它实际上并不是免费的。 Express许可证(可通过VS中的NuGet下载)允许您使用[Log]
属性修饰方法,然后选择已配置的日志记录机制,如log4net nLog等。现在您将开始在日志中看到调试级别条目,提供参数详细信息。
使用快速许可证,我只能在我的项目中装饰最多50个方法。 如果它符合您的需求,您很高兴!
有几个参数或大量参数的场景……
-
没有太多麻烦的参数很少,最好将它们作为记录/exception消息的一部分写出来。
-
在大型参数中,多层应用程序将使用ENTITIES(如customer,CustomerOrder …)在层之间传输数据。 这些实体应该实现类Object的重写ToString()方法,其中,
Logmessage(“方法启动”+ paramObj.ToString())会给出对象中的数据列表..有什么意见? 🙂
谢谢