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