我开始使用NLog.Interface
,因此我可以使用ILogger
界面代替Logger
上提供的NLog
类(主要用于单元测试)
当我使用${stacktrace}
时,我会得到这样的结果:
... => LoginViewModel.LogIn => LoggerAdapter.Info
我想删除LoggerAdapter.Info
部分(因为NLog.Interface
包含了Logger
内的LoggerAdapter
类而包括在内)。
我怎么能这样做?
答案 0 :(得分:4)
您可以创建自定义LayoutRenderer,它将跳过一些堆栈帧:
[LayoutRenderer("stacktrace")]
public class CustomStackTraseLayoutRenderer : StackTraceLayoutRenderer
{
[DefaultValue(0)]
public int SkipFrames { get; set; } // configurable
protected override void Append(StringBuilder builder, LogEventInfo logEvent)
{
int startingFrame = logEvent.UserStackFrameNumber + TopFrames - 1;
if (startingFrame >= logEvent.StackTrace.FrameCount)
startingFrame = logEvent.StackTrace.FrameCount - 1;
bool first = true;
int endingFrame = logEvent.UserStackFrameNumber + SkipFrames;
for (int i = startingFrame; i >= endingFrame; --i)
{
StackFrame f = logEvent.StackTrace.GetFrame(i);
switch (Format)
{
case StackTraceFormat.Raw:
builder.Append(f.ToString());
break;
case StackTraceFormat.Flat:
if (!first)
builder.Append(this.Separator);
var type = f.GetMethod().DeclaringType;
builder.Append(type == null ? "<no type>" : type.Name);
builder.Append(".");
builder.Append(f.GetMethod().Name);
first = false;
break;
case StackTraceFormat.DetailedFlat:
if (!first)
builder.Append(this.Separator);
builder.Append("[" + f.GetMethod() + "]");
first = false;
break;
}
}
}
}
添加自定义布局渲染器:
<extensions>
<add prefix="custom" assembly="YourAssemblyName"/>
</extensions>
<targets>
<target xsi:type="ColoredConsole" name="c"
layout="${time} ${custom.stacktrace:skipframes=1} ${level} ${message}">
</target>
</targets>
答案 1 :(得分:2)
请参阅此处的答案,以获取有关正确包装NLog Logger的方法的简要示例,以便保留呼叫站点信息:
Problem matching specific NLog logger name
这是另一个涉及包装NLog Logger的问题。实际上,问题不在于包装NLog Logger,但是我的回答指出了另一个答案实现NLog Logger包装器的问题。
What is the best way of using NLog with MEF?
关键是根据NLog Logger.Log
方法实现包装器的日志记录方法,并将包装器的type
作为第一个参数传递。
为了节省您的时间,我在这里发布了一个稍微缩短版的NLog Logger包装器代码:
class NLogLogger : ILogger
{
private NLog.Logger logger;
public NLogLogger(Type t)
{
logger = NLog.LogManager.GetLogger(t.FullName);
}
//Trace, Warn, Error, Fatal eliminated for brevity
public bool IsInfoEnabled
{
get { return logger.IsInfoEnabled; }
}
public bool IsDebugEnabled
{
get { return logger.IsDebugEnabled; }
}
public void Info(string format, params object [] args)
{
if (logger.IsInfoEnabled)
{
Write(LogLevel.Info, format, args);
}
}
public void Debug(string format, params object [] args)
{
if (logger.IsDebugEnabled)
{
Write(LogLevel.Debug, format, args);
}
}
private void Write(LogLevel level, string format, params object [] args)
{
LogEventInfo le = new LogEventInfo(level, logger.Name, null, format, args);
logger.Log(typeof(NLogLogger), le);
}
}
您可以像这样使用包装器:
class MyClass
{
private static readonly logger = new NLogLogger(typeof(MyClass));
public void DoSomething()
{
logger.Info("Hello from DoSomething");
}
}
或者您可以将记录器注入您的班级。