C# 异常处理中函数参数的通用日志记录

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/135782/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 15:02:34  来源:igfitidea点击:

Generic logging of function parameters in exception handling

提问by Guy

A lot of my C# code follows this pattern:

我的很多 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));
    }
}

Is there a way in .NET to get a Key/Value list of the parameters to a function so that I can call another function to construct my error logging string? OR Do you have a more generic / better way of doing this?

.NET 中有没有办法获取函数参数的键/值列表,以便我可以调用另一个函数来构造我的错误日志记录字符串?或者你有更通用/更好的方法吗?

采纳答案by Panos

You could use Reflection and the convention that you must pass the parameters to the LogError with the right order:

您可以使用反射和必须以正确顺序将参数传递给 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));
}

回答by David Basarab

When I have done this I just created a generic dictionary for the logging.

完成此操作后,我只是为日志记录创建了一个通用字典。

I have this LogArgs class. And logging in a base class that I call when I have an exception.

我有这个 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>();
    }

}

Then at the start of every method I do

然后在我做的每一种方法的开始

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);

When I have an error I log it this way.

当我有错误时,我会以这种方式记录它。

base.Logger.LogError(args, ex);

回答by Joe

No there isn't a way to do this.

不,没有办法做到这一点。

The normal practice is to not catch exceptions unless you can handle them.

通常的做法是不捕获异常,除非您可以处理它们。

I.e. you would normally only catch exceptions and log them in a top-level exception handler. You will then get a stack trace, but won't of course get details of all the parameters of all method calls in the stack.

即您通常只会捕获异常并将它们记录在顶级异常处理程序中。然后您将获得堆栈跟踪,但当然不会获得堆栈中所有方法调用的所有参数的详细信息。

Obviously when debugging you want as much detail as possible. Other ways to achieve this are:

显然,在调试时您需要尽可能多的细节。实现这一目标的其他方法是:

  • Use Debug.Assert statements liberally to test assumptions you are making.

  • Instrument your application with logging that can be activate selectively. I use Log4Net, but there are also other alternatives, including using the System.Diagnostics.Trace class.

  • 大量使用 Debug.Assert 语句来测试您所做的假设。

  • 使用可以选择性激活的日志记录来检测您的应用程序。我使用 Log4Net,但还有其他选择,包括使用 System.Diagnostics.Trace 类。

In any case, if you do catch exceptions only to log them (I'd do this at a tier boundary in an n-tier application, so that exceptions are logged on the server), then you should always rethrow them:

在任何情况下,如果您捕获异常只是为了记录它们(我会在 n 层应用程序的层边界执行此操作,以便将异常记录在服务器上),那么您应该始终重新抛出它们:

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

回答by JoshL

You could use a similar style of constructing the message, but add the params keyword in your LogError method to handle the arguments. For example:

您可以使用类似的方式构造消息,但在 LogError 方法中添加 params 关键字来处理参数。例如:

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

回答by Jacob

You could use aspect oriented programming with PostSharp (have a look at http://www.postsharp.org, and the tutorial at http://www.codeproject.com/KB/cs/ps-custom-attributes-1.aspx). Basically you could do something like this:

您可以在 PostSharp 中使用面向方面的编程(查看http://www.postsharp.orghttp://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
}

Perhaps not quite what you want, but I'm sure it can be adapted to suit your needs.

也许不是你想要的,但我相信它可以适应你的需求。

回答by HydPhani

There are scenarios of a few parameters or Large number of parameters...

有几个参数或大量参数的场景......

  1. Few parameters, without much ado, better write them as part of the logging/exception message.

  2. In large parameters, a multi-layer application would be using ENTITIES ( like customer, CustomerOrder...) to transfer data between layers. These entities should implement override ToString() methods of class Object, there by,

  1. 很少有参数,不费吹灰之力,最好将它们作为日志记录/异常消息的一部分编写。

  2. 在大参数中,多层应用程序将使用实体(如客户、客户订单...)在层之间传输数据。这些实体应该实现类 Object 的覆盖 ToString() 方法,从而,

Logmessage(" method started " + paramObj.ToString()) would give the list of data in the object.. Any opinions? :)

Logmessage(" method started " + paramObj.ToString()) 会给出对象中的数据列表。有什么意见吗?:)

thanks

谢谢

回答by joym8

This is little dated post but just in case someone comes across this like I did - I solved this issue by using PostSharp.

这是一篇过时的帖子,但以防万一有人像我一样遇到这个问题 - 我使用PostSharp解决了这个问题。

It's not practically free though. The Express license (downloadable via NuGet in VS) allows you to decorate your method with [Log]attribute and then choose your already configured mechanism for logging, like log4netnLogetc. Now you will start seeing Debug level entries in your log giving parameter details.

虽然它实际上不是免费的。Express 许可证(可通过 VS 中的 NuGet 下载)允许您使用[Log]属性装饰您的方法,然后选择您已经配置的日志记录机制,如log4net nLog等。现在您将开始在日志中看到调试级别条目,提供参数详细信息。

With express license I could only decorate a maximum of 50 methods in my project. If it fits your needs you're good to go!

使用快速许可,我最多只能在我的项目中装饰 50 个方法。如果它符合您的需求,您就可以开始了!