Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby-on-rails-4/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用树状结构进行日志记录_C#_Logging_Tree_Log4net - Fatal编程技术网

C# 如何使用树状结构进行日志记录

C# 如何使用树状结构进行日志记录,c#,logging,tree,log4net,C#,Logging,Tree,Log4net,我想用log4net(我现在正在这么做)来记录一个文件,但是使用log4net,只有简单的日志输出,每行都有一条消息 现在我想登录到同一个日志文件,但采用树状结构。例如,我有以下方法调用,每个方法都记录其方法名(应该有缩进): 应打印此日志,例如: 2016-07-26 15:44:56,042 > firstMethod 2016-07-26 15:44:56,043 > secondMethod 2016-07-26 15:44:56,044

我想用
log4net
(我现在正在这么做)来记录一个文件,但是使用log4net,只有简单的日志输出,每行都有一条消息

现在我想登录到同一个日志文件,但采用树状结构。例如,我有以下方法调用,每个方法都记录其方法名(应该有缩进):

应打印此日志,例如:

2016-07-26 15:44:56,042    > firstMethod
2016-07-26 15:44:56,043         > secondMethod
2016-07-26 15:44:56,044              > thirdMethod
2016-07-26 15:44:56,045              < thirdMethod
2016-07-26 15:44:56,046         < secondMethod
2016-07-26 15:44:56,047    < firstMethod
2016-07-26 15:44:56042>第一种方法
2016-07-26 15:44:56043>第二种方法
2016-07-26 15:44:56044>第三种方法
2016-07-26 15:44:56045<第三种方法
2016-07-26 15:44:56046<第二种方法
2016-07-26 15:44:56047<第一种方法

符号在方法的开头和结尾打印在方法中。

这不是很有效,但您可以考虑使用调用堆栈来获取方法的层次结构,然后根据调用堆栈中调用的深度填充/缩进每个日志条目

 StackTrace stackTrace = new StackTrace();          
 StackFrame[] stackFrames = stackTrace.GetFrames();
替代方案可能包括使用或(可能)书写。另一个想法是忘记缩进,使用完整的名称空间和方法名来跟踪日志条目的来源。这样,您仍然可以看到树状视图

var methodInfo = System.Reflection.MethodBase.GetCurrentMethod();
var fullName = methodInfo.DeclaringType.FullName + "." + methodInfo.Name;

尽管如此,这似乎是一个非常典型的要求。你真的需要这样做吗

这不是很有效,但是您可以考虑使用调用堆栈来获得方法的层次结构,然后根据调用堆栈中调用的深度填充/缩进每个日志条目

 StackTrace stackTrace = new StackTrace();          
 StackFrame[] stackFrames = stackTrace.GetFrames();
替代方案可能包括使用或(可能)书写。另一个想法是忘记缩进,使用完整的名称空间和方法名来跟踪日志条目的来源。这样,您仍然可以看到树状视图

var methodInfo = System.Reflection.MethodBase.GetCurrentMethod();
var fullName = methodInfo.DeclaringType.FullName + "." + methodInfo.Name;

尽管如此,这似乎是一个非常典型的要求。你真的需要这样做吗

添加另一种方法来记录,并在其中填充enter/exit参数,如何:

int curLevel = 0;
public void MyLogInfo( bool enter, [System.Runtime.CompilerServices.CallerMemberName] string callingMethod = "", )
{
    string prefix;
    if (enter)
    {
      prefix = "> ";
      curLevel++;
    }
    else
    {
      prefix = "< ";
      curLevel--;
    }
    logger.info(prefix.PadLeft(curLevel+prefix.Length) + callingMethod);
}
int curLevel=0;
public void MyLogInfo(bool-enter,[System.Runtime.CompilerServices.CallerMemberName]字符串callingMethod=“”,)
{
字符串前缀;
如果(输入)
{
前缀=“>”;
curLevel++;
}
其他的
{
前缀=“<”;
卷发--;
}
logger.info(prefix.PadLeft(curLevel+prefix.Length)+调用方法);
}
您只需调用MyLogInfo(true)或MyLogInfo(false)-.NET将设置callingMethod名称(如果您自己没有指定)


您必须确保在登录的每个方法的进入/退出时始终调用该方法-可能会检查您是否将curLevel递减到零以下。

如何添加另一个用于登录的方法,并使用参数进行输入/退出,并在其中填充:

int curLevel = 0;
public void MyLogInfo( bool enter, [System.Runtime.CompilerServices.CallerMemberName] string callingMethod = "", )
{
    string prefix;
    if (enter)
    {
      prefix = "> ";
      curLevel++;
    }
    else
    {
      prefix = "< ";
      curLevel--;
    }
    logger.info(prefix.PadLeft(curLevel+prefix.Length) + callingMethod);
}
int curLevel=0;
public void MyLogInfo(bool-enter,[System.Runtime.CompilerServices.CallerMemberName]字符串callingMethod=“”,)
{
字符串前缀;
如果(输入)
{
前缀=“>”;
curLevel++;
}
其他的
{
前缀=“<”;
卷发--;
}
logger.info(prefix.PadLeft(curLevel+prefix.Length)+调用方法);
}
您只需调用MyLogInfo(true)或MyLogInfo(false)-.NET将设置callingMethod名称(如果您自己没有指定)


您必须确保在登录的每个方法的进入/退出时始终调用该方法-可能会检查您是否将curLevel减至零以下。

您可以使用NDC实现类似的行为。但它已被弃用。现在,您可以使用上下文和上下文堆栈。查看以下文档:

您可以定义多个堆栈(而不是缩进)。一个堆栈用于一组要调试的行为。假设您要记录创建销售订单及其项目的过程。在本例中,此堆栈是在ThreadContext中定义的。但是,您可以在GlobalContext、LogicalThreadContext或LoggingEvent中定义它

using(log4net.ThreadContext.Stacks["SalesOrderLogic"].Push("SalesOrder"))
{
    log.Info("Created the sales order");

    using(log4net.ThreadContext.Stacks["SalesOrderLogic"].Push("Items"))
    {
        log.Info("Created the sales order items");
    }
}
然后您应该将其添加到配置中:

<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%logger - %property{SalesOrderStatus} - [%level]- %message%newline" />
  </layout>
</appender>

免责声明:我没有测试此代码

注1:旧NDC将出现在一个线程中。因此,如果您在一个线程中推送消息,它将不会出现在另一个线程中。与新的上下文堆栈方法不同,它只有一个堆栈

注2:不要忘记签出上下文。这是非常有用的


注3:如果您研究Ninject和log4net一起工作,您可能会发现它很有用

您可以使用NDC实现类似的行为。但它已被弃用。现在,您可以使用上下文和上下文堆栈。查看以下文档:

您可以定义多个堆栈(而不是缩进)。一个堆栈用于一组要调试的行为。假设您要记录创建销售订单及其项目的过程。在本例中,此堆栈是在ThreadContext中定义的。但是,您可以在GlobalContext、LogicalThreadContext或LoggingEvent中定义它

using(log4net.ThreadContext.Stacks["SalesOrderLogic"].Push("SalesOrder"))
{
    log.Info("Created the sales order");

    using(log4net.ThreadContext.Stacks["SalesOrderLogic"].Push("Items"))
    {
        log.Info("Created the sales order items");
    }
}
然后您应该将其添加到配置中:

<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%logger - %property{SalesOrderStatus} - [%level]- %message%newline" />
  </layout>
</appender>

免责声明:我没有测试此代码

注1:旧NDC将出现在一个线程中。因此,如果您在一个线程中推送消息,它将不会出现在另一个线程中。与新的上下文堆栈方法不同,它只有一个堆栈

注2:不要忘记签出上下文。这是非常有用的


注3:如果您研究Ninject和log4net一起工作,您可能会发现它很有用。请注意,您的日志输出和方法调用在这里并不匹配<将调用code>firstMethod,并将在调用
secondMethod
之前返回。请注意,您的日志输出和方法调用在此处并不匹配
firstMethod
将被调用,并将在调用
secondMethod
之前返回。是的,就像这样,但相同方法中的其他输出也应使用相同的缩进打印…您可以调整该方法,以使用枚举而不是bool作为第一个参数,以指示是否输入该方法(增量为curLevel,p