NLog 如何设置 LoggerName?
How is NLog setting the LoggerName?
我遇到了一个有趣的、显然是临时性的 NLog 问题,或者可能是我使用它的方式。
我正在尝试创建一个日志服务抽象,目的是为了避免硬依赖,并且我已经在 NLog.FluentBuilder
class 上建立了我的抽象模型。所以我有一对接口:
public interface ILog
{
IFluentLogBuilder Trace([CallerFilePath] string callerFilePath = null);
IFluentLogBuilder Debug([CallerFilePath] string callerFilePath = null);
IFluentLogBuilder Info([CallerFilePath] string callerFilePath = null);
IFluentLogBuilder Warn([CallerFilePath] string callerFilePath = null);
IFluentLogBuilder Error([CallerFilePath] string callerFilePath = null);
IFluentLogBuilder Fatal([CallerFilePath] string callerFilePath = null);
void Shutdown();
}
public interface IFluentLogBuilder
{
IFluentLogBuilder Exception(Exception exception);
IFluentLogBuilder LoggerName(string loggerName);
IFluentLogBuilder Message(string message);
IFluentLogBuilder Message(string format, params object[] args);
IFluentLogBuilder Message(IFormatProvider provider, string format, params object[] args);
IFluentLogBuilder Property(string name, object value);
IFluentLogBuilder Properties(IDictionary<string,object> properties);
IFluentLogBuilder TimeStamp(DateTime timeStamp);
IFluentLogBuilder StackTrace(StackTrace stackTrace, int userStackFrame);
void Write([CallerMemberName] string callerMemberName = null, [CallerFilePath] string callerFilePath = null,
[CallerLineNumber] int callerLineNumber = default);
void WriteIf(Func<bool> condition, [CallerMemberName] string callerMemberName = null,
[CallerFilePath] string callerFilePath = null, [CallerLineNumber] int callerLineNumber = default);
void WriteIf(bool condition, [CallerMemberName] string callerMemberName = null,
[CallerFilePath] string callerFilePath = null, [CallerLineNumber] int callerLineNumber = default);
}
我的想法是能够为不同的日志记录框架创建适配器,当然我制作的第一个适配器是针对 NLog 的,因为那是我打算使用的。该实现本质上是 NLog 流畅界面的简化克隆,因此这是我的版本的部分抽象:
ILog
实现
public sealed class LoggingService : ILog
{
private static readonly ILogger DefaultLogger = LogManager.GetCurrentClassLogger();
static LoggingService()
{
LogManager.AutoShutdown = true;
}
public IFluentLogBuilder Trace([CallerFilePath] string callerFilePath = null)
{
return CreateLogBuilder(LogLevel.Trace, callerFilePath);
}
// Methods for other log levels elided for clarity...
private IFluentLogBuilder CreateLogBuilder(LogLevel logLevel, string callerFilePath)
{
string name = !string.IsNullOrWhiteSpace(callerFilePath)
? Path.GetFileNameWithoutExtension(callerFilePath)
: null;
var logger = string.IsNullOrWhiteSpace(name) ? DefaultLogger : LogManager.GetLogger(name);
var builder = new LogBuilder(logger, logLevel);
return builder;
}
/// <inheritdoc />
public void Shutdown() => LogManager.Shutdown();
}
IFluentLogBuilder
实现
internal sealed class LogBuilder : IFluentLogBuilder
{
private readonly LogEventInfo logEvent;
private readonly ILogger logger;
public LogBuilder(ILogger logger, LogLevel level)
{
if (logger == null)
throw new ArgumentNullException(nameof(logger));
if (level == null)
throw new ArgumentNullException(nameof(level));
this.logger = logger;
logEvent = new LogEventInfo { LoggerName = logger.Name, Level = level };
}
/// <inheritdoc />
public IFluentLogBuilder Exception(Exception exception)
{
logEvent.Exception = exception;
return this;
}
/// <inheritdoc />
public IFluentLogBuilder LoggerName(string loggerName)
{
logEvent.LoggerName = loggerName;
return this;
}
/// <inheritdoc />
public IFluentLogBuilder Message(string message)
{
logEvent.Message = message;
return this;
}
// Some other builder methods elided for clarity... (they all follow the pattern).
/// <inheritdoc />
public void Write([CallerMemberName] string callerMemberName = null,
[CallerFilePath] string callerFilePath = null,
[CallerLineNumber] int callerLineNumber = default)
{
if (!logger.IsEnabled(logEvent.Level)) return;
SetCallerInfo(callerMemberName, callerFilePath, callerLineNumber);
logger.Log(logEvent);
}
private void SetCallerInfo(string callerMethodName, string callerFilePath, int callerLineNumber)
{
if (callerMethodName != null || callerFilePath != null || callerLineNumber != 0)
logEvent.SetCallerInfo(null, callerMethodName, callerFilePath, callerLineNumber);
}
/// <summary>
/// Builds and returns the <see cref="LogEventInfo"/> without writing it to the log.
/// </summary>
internal LogEventInfo Build() => logEvent;
}
我省略了一些不会给问题添加任何额外信息的方法,基本上它们
都遵循相同的模式。这与 NLog.Fluent.LogBuilder
class.
中的内容非常相似,但不完全相同
所以不,它变得有趣。
测试程序
我在我的库中包含了一个 .NET Core 3.0 控制台应用程序作为示例程序。
我已经完整地复制了这篇文章,但是没有大量的评论,这只会让
在路上。
程序只数到 1000,打印出每个数字,并产生一些
异常使事情变得更有趣并展示语义日志记录。
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using TA.Utils.Core;
namespace TA.Utils.Logging.NLog.SampleConsoleApp
{
class Program
{
static readonly List<int> SuperstitiousNumbers = new List<int> {13, 7, 666, 3, 8, 88, 888};
async static Task Main(string[] args)
{
var log = new LoggingService();
log.Info()
.Message("Application stating - version {Version}", GitVersion.GitInformationalVersion)
.Property("SemVer", GitVersion.GitFullSemVer)
.Property("GitCommit", GitVersion.GitCommitSha)
.Property("CommitDate", GitVersion.GitCommitDate)
.Write();
var seed = DateTime.Now.Millisecond;
var gameOfChance = new Random(seed);
log.Debug().Property("seed",seed).Write();
for (int i = 0; i < 1000; i++)
{
try
{
log.Debug().Message("Starting iteration {iteration}", i).Write();
if (SuperstitiousNumbers.Contains(i))
{
throw new SuperstitiousNumberException($"Skipping {i} because it is a superstitious number");
}
// There's a small chance of a random "failure"
if (gameOfChance.Next(100) < 3)
throw new ApplicationException("Random failure");
}
catch (SuperstitiousNumberException ex)
{
log.Warn()
.Message("Superstitious looking number: {number}", i)
.Exception(ex)
.Property("SuperstitiousNumbers", SuperstitiousNumbers)
.Write();
}
catch (ApplicationException ae)
{
log.Error().Exception(ae).Message("Failed iteration {iteration}", i).Write();
}
await Task.Delay(TimeSpan.FromMilliseconds(1000));
log.Debug().Message("Finished iteration {iteration}", i).Write();
}
log.Info().Message("Program terminated").Write();
log.Shutdown();
}
}
}
此程序产生以下日志输出。
00:01:09.4823 | INFO | LogBuilder | Application stating - version "1.1.1-beta.1+18.Branch.hotfix-1.1.1.Sha.8b8fa5a008c35d4fc21c99d0bd9a01f6d32c9a53"
00:01:09.5339 | DEBUG | LogBuilder |
00:01:09.5339 | DEBUG | LogBuilder | Starting iteration 0
00:01:10.5636 | DEBUG | LogBuilder | Finished iteration 0
00:01:10.5636 | DEBUG | LogBuilder | Starting iteration 1
00:01:11.5762 | DEBUG | LogBuilder | Finished iteration 1
00:01:11.5762 | DEBUG | LogBuilder | Starting iteration 2
00:01:12.5893 | DEBUG | LogBuilder | Finished iteration 2
00:01:12.5893 | DEBUG | LogBuilder | Starting iteration 3
00:01:12.5893 | WARN | LogBuilder | Superstitious looking number: 3
00:01:13.6325 | DEBUG | LogBuilder | Finished iteration 3
00:01:13.6325 | DEBUG | LogBuilder | Starting iteration 4
00:01:14.6484 | DEBUG | LogBuilder | Finished iteration 4
00:01:14.6484 | DEBUG | LogBuilder | Starting iteration 5
00:01:15.6534 | DEBUG | LogBuilder | Finished iteration 5
00:01:15.6534 | DEBUG | LogBuilder | Starting iteration 6
00:01:16.6653 | DEBUG | LogBuilder | Finished iteration 6
00:01:16.6653 | DEBUG | LogBuilder | Starting iteration 7
00:01:16.6653 | WARN | LogBuilder | Superstitious looking number: 7
00:01:17.6787 | DEBUG | LogBuilder | Finished iteration 7
00:01:17.6787 | DEBUG | LogBuilder | Starting iteration 8
00:01:17.6787 | WARN | LogBuilder | Superstitious looking number: 8
00:01:18.6890 | DEBUG | LogBuilder | Finished iteration 8
00:01:18.6890 | DEBUG | LogBuilder | Starting iteration 9
00:01:19.6926 | DEBUG | LogBuilder | Finished iteration 9
00:01:19.6935 | DEBUG | LogBuilder | Starting iteration 10
00:01:20.7071 | DEBUG | LogBuilder | Finished iteration 10
00:01:20.7071 | DEBUG | LogBuilder | Starting iteration 11
00:01:21.7110 | DEBUG | LogBuilder | Finished iteration 11
00:01:21.7110 | DEBUG | LogBuilder | Starting iteration 12
00:01:22.7367 | DEBUG | LogBuilder | Finished iteration 12
00:01:22.7404 | DEBUG | LogBuilder | Starting iteration 13
00:01:22.7404 | WARN | LogBuilder | Superstitious looking number: 13
00:01:23.7621 | DEBUG | LogBuilder | Finished iteration 13
00:01:23.7621 | DEBUG | LogBuilder | Starting iteration 14
00:01:24.7756 | DEBUG | Program | Finished iteration 14
00:01:24.7756 | DEBUG | Program | Starting iteration 15
00:01:25.7876 | DEBUG | Program | Finished iteration 15
00:01:25.7876 | DEBUG | Program | Starting iteration 16
00:01:26.8040 | DEBUG | Program | Finished iteration 16
00:01:26.8040 | DEBUG | Program | Starting iteration 17
00:01:27.8176 | DEBUG | Program | Finished iteration 17
00:01:27.8176 | DEBUG | Program | Starting iteration 18
00:01:28.8277 | DEBUG | Program | Finished iteration 18
00:01:28.8277 | DEBUG | Program | Starting iteration 19
00:01:29.8372 | DEBUG | Program | Finished iteration 19
00:01:29.8372 | DEBUG | Program | Starting iteration 20
所以这是牛肉。为什么源名称在第 14 次迭代中途从 LogBuilder
更改为 Program
?为什么曾经 LogBuilder
?
我问自己的一个问题是:“它总是在同一个地方发生变化吗”,答案是否定的。它会随着正负一次迭代而变化。
我猜这可能与我正在使用的缓冲日志目标有关...这是我的 NLog.config
文件:
<?xml version="1.0" encoding="utf-8"?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true">
<extensions>
<add assembly="NLog.Targets.Seq"/>
</extensions>
<targets async="true" >
<target xsi:type="ColoredConsole" name="console"
layout="${time} | ${pad:padding=-5:inner=${uppercase:${level}}} | ${pad:padding=-31:inner=${callsite:className=true:fileName=false:includeSourcePath=false:methodName=false:includeNamespace=false}} | ${message}" >
<highlight-row condition="level == LogLevel.Debug" foregroundColor="DarkGreen" />
<highlight-row condition="level == LogLevel.Info" foregroundColor="White" />
<highlight-row condition="level == LogLevel.Warn" foregroundColor="Yellow" />
<highlight-row condition="level == LogLevel.Error" foregroundColor="Red" />
<highlight-row condition="level == LogLevel.Fatal" foregroundColor="Red" backgroundColor="White" />
</target>
<target name="seq" xsi:type="BufferingWrapper" bufferSize="1000"
flushTimeout="500" slidingTimeout="false">
<target xsi:type="Seq" name="seq" serverUrl="http://seq.nowhere.com:5341" apiKey="imnotfallingforthatone">
<!-- Augment the log data with some extra properties -->
<property name="ProcessId" value="${processid}" />
<property name="ProcessName" value="${processname}" />
<property name="ThreadId" value="${threadid}" as="number" />
<property name="Machine" value="${machinename}" />
<property name="Host" value="${hostname}" />
<property name="User" value="${environment-user}" />
</target>
</target>
<target xsi:type="Trace" name="debug" rawWrite="true">
<layout>${pad:padding=-5:inner=${uppercase:${level}}}|${pad:padding=-16:fixedLength=true:alignmentOnTruncation=right:inner=${callsite:className=true:fileName=false:includeSourcePath=false:methodName=false:includeNamespace=false}}| ${message}</layout>
</target>
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="console" />
<logger name="*" minlevel="Trace" writeTo="debug" />
<logger name="*" minlevel="Trace" writeTo="seq" />
</rules>
</nlog>
如果您能提供任何见解,我将不胜感激。仅供参考 project is open-source 如果您想克隆它并在 IDE.
中检查它
记录器名称创建如下:
- 当使用
Logger.GetLogger(string name)
时,名称不加更改地使用
- 使用
LogManager.GetCurrentClassLogger()
时,会在堆栈跟踪中搜索 class 的名称。在某些情况下,这可能会很棘手,因为内联和异步技巧使得很难找到正确的名称。
在这种情况下,实际上不需要使用 LogManager.GetCurrentClassLogger()
,我建议将其替换为 Logger.GetLogger(string name)
另请注意,您设计的 fluent API 有点不合常规 - 至少对于您示例中添加的属性而言。
- 已经有流畅的界面,见NLog.Fluent namespace
- 某些属性最好添加到上下文中 class(例如 GDC、MDLC,请参阅 context in NLog) or added as a custom layout renderer
我遇到了一个有趣的、显然是临时性的 NLog 问题,或者可能是我使用它的方式。
我正在尝试创建一个日志服务抽象,目的是为了避免硬依赖,并且我已经在 NLog.FluentBuilder
class 上建立了我的抽象模型。所以我有一对接口:
public interface ILog
{
IFluentLogBuilder Trace([CallerFilePath] string callerFilePath = null);
IFluentLogBuilder Debug([CallerFilePath] string callerFilePath = null);
IFluentLogBuilder Info([CallerFilePath] string callerFilePath = null);
IFluentLogBuilder Warn([CallerFilePath] string callerFilePath = null);
IFluentLogBuilder Error([CallerFilePath] string callerFilePath = null);
IFluentLogBuilder Fatal([CallerFilePath] string callerFilePath = null);
void Shutdown();
}
public interface IFluentLogBuilder
{
IFluentLogBuilder Exception(Exception exception);
IFluentLogBuilder LoggerName(string loggerName);
IFluentLogBuilder Message(string message);
IFluentLogBuilder Message(string format, params object[] args);
IFluentLogBuilder Message(IFormatProvider provider, string format, params object[] args);
IFluentLogBuilder Property(string name, object value);
IFluentLogBuilder Properties(IDictionary<string,object> properties);
IFluentLogBuilder TimeStamp(DateTime timeStamp);
IFluentLogBuilder StackTrace(StackTrace stackTrace, int userStackFrame);
void Write([CallerMemberName] string callerMemberName = null, [CallerFilePath] string callerFilePath = null,
[CallerLineNumber] int callerLineNumber = default);
void WriteIf(Func<bool> condition, [CallerMemberName] string callerMemberName = null,
[CallerFilePath] string callerFilePath = null, [CallerLineNumber] int callerLineNumber = default);
void WriteIf(bool condition, [CallerMemberName] string callerMemberName = null,
[CallerFilePath] string callerFilePath = null, [CallerLineNumber] int callerLineNumber = default);
}
我的想法是能够为不同的日志记录框架创建适配器,当然我制作的第一个适配器是针对 NLog 的,因为那是我打算使用的。该实现本质上是 NLog 流畅界面的简化克隆,因此这是我的版本的部分抽象:
ILog
实现
public sealed class LoggingService : ILog
{
private static readonly ILogger DefaultLogger = LogManager.GetCurrentClassLogger();
static LoggingService()
{
LogManager.AutoShutdown = true;
}
public IFluentLogBuilder Trace([CallerFilePath] string callerFilePath = null)
{
return CreateLogBuilder(LogLevel.Trace, callerFilePath);
}
// Methods for other log levels elided for clarity...
private IFluentLogBuilder CreateLogBuilder(LogLevel logLevel, string callerFilePath)
{
string name = !string.IsNullOrWhiteSpace(callerFilePath)
? Path.GetFileNameWithoutExtension(callerFilePath)
: null;
var logger = string.IsNullOrWhiteSpace(name) ? DefaultLogger : LogManager.GetLogger(name);
var builder = new LogBuilder(logger, logLevel);
return builder;
}
/// <inheritdoc />
public void Shutdown() => LogManager.Shutdown();
}
IFluentLogBuilder
实现
internal sealed class LogBuilder : IFluentLogBuilder
{
private readonly LogEventInfo logEvent;
private readonly ILogger logger;
public LogBuilder(ILogger logger, LogLevel level)
{
if (logger == null)
throw new ArgumentNullException(nameof(logger));
if (level == null)
throw new ArgumentNullException(nameof(level));
this.logger = logger;
logEvent = new LogEventInfo { LoggerName = logger.Name, Level = level };
}
/// <inheritdoc />
public IFluentLogBuilder Exception(Exception exception)
{
logEvent.Exception = exception;
return this;
}
/// <inheritdoc />
public IFluentLogBuilder LoggerName(string loggerName)
{
logEvent.LoggerName = loggerName;
return this;
}
/// <inheritdoc />
public IFluentLogBuilder Message(string message)
{
logEvent.Message = message;
return this;
}
// Some other builder methods elided for clarity... (they all follow the pattern).
/// <inheritdoc />
public void Write([CallerMemberName] string callerMemberName = null,
[CallerFilePath] string callerFilePath = null,
[CallerLineNumber] int callerLineNumber = default)
{
if (!logger.IsEnabled(logEvent.Level)) return;
SetCallerInfo(callerMemberName, callerFilePath, callerLineNumber);
logger.Log(logEvent);
}
private void SetCallerInfo(string callerMethodName, string callerFilePath, int callerLineNumber)
{
if (callerMethodName != null || callerFilePath != null || callerLineNumber != 0)
logEvent.SetCallerInfo(null, callerMethodName, callerFilePath, callerLineNumber);
}
/// <summary>
/// Builds and returns the <see cref="LogEventInfo"/> without writing it to the log.
/// </summary>
internal LogEventInfo Build() => logEvent;
}
我省略了一些不会给问题添加任何额外信息的方法,基本上它们
都遵循相同的模式。这与 NLog.Fluent.LogBuilder
class.
所以不,它变得有趣。
测试程序
我在我的库中包含了一个 .NET Core 3.0 控制台应用程序作为示例程序。
我已经完整地复制了这篇文章,但是没有大量的评论,这只会让 在路上。
程序只数到 1000,打印出每个数字,并产生一些 异常使事情变得更有趣并展示语义日志记录。
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using TA.Utils.Core;
namespace TA.Utils.Logging.NLog.SampleConsoleApp
{
class Program
{
static readonly List<int> SuperstitiousNumbers = new List<int> {13, 7, 666, 3, 8, 88, 888};
async static Task Main(string[] args)
{
var log = new LoggingService();
log.Info()
.Message("Application stating - version {Version}", GitVersion.GitInformationalVersion)
.Property("SemVer", GitVersion.GitFullSemVer)
.Property("GitCommit", GitVersion.GitCommitSha)
.Property("CommitDate", GitVersion.GitCommitDate)
.Write();
var seed = DateTime.Now.Millisecond;
var gameOfChance = new Random(seed);
log.Debug().Property("seed",seed).Write();
for (int i = 0; i < 1000; i++)
{
try
{
log.Debug().Message("Starting iteration {iteration}", i).Write();
if (SuperstitiousNumbers.Contains(i))
{
throw new SuperstitiousNumberException($"Skipping {i} because it is a superstitious number");
}
// There's a small chance of a random "failure"
if (gameOfChance.Next(100) < 3)
throw new ApplicationException("Random failure");
}
catch (SuperstitiousNumberException ex)
{
log.Warn()
.Message("Superstitious looking number: {number}", i)
.Exception(ex)
.Property("SuperstitiousNumbers", SuperstitiousNumbers)
.Write();
}
catch (ApplicationException ae)
{
log.Error().Exception(ae).Message("Failed iteration {iteration}", i).Write();
}
await Task.Delay(TimeSpan.FromMilliseconds(1000));
log.Debug().Message("Finished iteration {iteration}", i).Write();
}
log.Info().Message("Program terminated").Write();
log.Shutdown();
}
}
}
此程序产生以下日志输出。
00:01:09.4823 | INFO | LogBuilder | Application stating - version "1.1.1-beta.1+18.Branch.hotfix-1.1.1.Sha.8b8fa5a008c35d4fc21c99d0bd9a01f6d32c9a53"
00:01:09.5339 | DEBUG | LogBuilder |
00:01:09.5339 | DEBUG | LogBuilder | Starting iteration 0
00:01:10.5636 | DEBUG | LogBuilder | Finished iteration 0
00:01:10.5636 | DEBUG | LogBuilder | Starting iteration 1
00:01:11.5762 | DEBUG | LogBuilder | Finished iteration 1
00:01:11.5762 | DEBUG | LogBuilder | Starting iteration 2
00:01:12.5893 | DEBUG | LogBuilder | Finished iteration 2
00:01:12.5893 | DEBUG | LogBuilder | Starting iteration 3
00:01:12.5893 | WARN | LogBuilder | Superstitious looking number: 3
00:01:13.6325 | DEBUG | LogBuilder | Finished iteration 3
00:01:13.6325 | DEBUG | LogBuilder | Starting iteration 4
00:01:14.6484 | DEBUG | LogBuilder | Finished iteration 4
00:01:14.6484 | DEBUG | LogBuilder | Starting iteration 5
00:01:15.6534 | DEBUG | LogBuilder | Finished iteration 5
00:01:15.6534 | DEBUG | LogBuilder | Starting iteration 6
00:01:16.6653 | DEBUG | LogBuilder | Finished iteration 6
00:01:16.6653 | DEBUG | LogBuilder | Starting iteration 7
00:01:16.6653 | WARN | LogBuilder | Superstitious looking number: 7
00:01:17.6787 | DEBUG | LogBuilder | Finished iteration 7
00:01:17.6787 | DEBUG | LogBuilder | Starting iteration 8
00:01:17.6787 | WARN | LogBuilder | Superstitious looking number: 8
00:01:18.6890 | DEBUG | LogBuilder | Finished iteration 8
00:01:18.6890 | DEBUG | LogBuilder | Starting iteration 9
00:01:19.6926 | DEBUG | LogBuilder | Finished iteration 9
00:01:19.6935 | DEBUG | LogBuilder | Starting iteration 10
00:01:20.7071 | DEBUG | LogBuilder | Finished iteration 10
00:01:20.7071 | DEBUG | LogBuilder | Starting iteration 11
00:01:21.7110 | DEBUG | LogBuilder | Finished iteration 11
00:01:21.7110 | DEBUG | LogBuilder | Starting iteration 12
00:01:22.7367 | DEBUG | LogBuilder | Finished iteration 12
00:01:22.7404 | DEBUG | LogBuilder | Starting iteration 13
00:01:22.7404 | WARN | LogBuilder | Superstitious looking number: 13
00:01:23.7621 | DEBUG | LogBuilder | Finished iteration 13
00:01:23.7621 | DEBUG | LogBuilder | Starting iteration 14
00:01:24.7756 | DEBUG | Program | Finished iteration 14
00:01:24.7756 | DEBUG | Program | Starting iteration 15
00:01:25.7876 | DEBUG | Program | Finished iteration 15
00:01:25.7876 | DEBUG | Program | Starting iteration 16
00:01:26.8040 | DEBUG | Program | Finished iteration 16
00:01:26.8040 | DEBUG | Program | Starting iteration 17
00:01:27.8176 | DEBUG | Program | Finished iteration 17
00:01:27.8176 | DEBUG | Program | Starting iteration 18
00:01:28.8277 | DEBUG | Program | Finished iteration 18
00:01:28.8277 | DEBUG | Program | Starting iteration 19
00:01:29.8372 | DEBUG | Program | Finished iteration 19
00:01:29.8372 | DEBUG | Program | Starting iteration 20
所以这是牛肉。为什么源名称在第 14 次迭代中途从 LogBuilder
更改为 Program
?为什么曾经 LogBuilder
?
我问自己的一个问题是:“它总是在同一个地方发生变化吗”,答案是否定的。它会随着正负一次迭代而变化。
我猜这可能与我正在使用的缓冲日志目标有关...这是我的 NLog.config
文件:
<?xml version="1.0" encoding="utf-8"?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true">
<extensions>
<add assembly="NLog.Targets.Seq"/>
</extensions>
<targets async="true" >
<target xsi:type="ColoredConsole" name="console"
layout="${time} | ${pad:padding=-5:inner=${uppercase:${level}}} | ${pad:padding=-31:inner=${callsite:className=true:fileName=false:includeSourcePath=false:methodName=false:includeNamespace=false}} | ${message}" >
<highlight-row condition="level == LogLevel.Debug" foregroundColor="DarkGreen" />
<highlight-row condition="level == LogLevel.Info" foregroundColor="White" />
<highlight-row condition="level == LogLevel.Warn" foregroundColor="Yellow" />
<highlight-row condition="level == LogLevel.Error" foregroundColor="Red" />
<highlight-row condition="level == LogLevel.Fatal" foregroundColor="Red" backgroundColor="White" />
</target>
<target name="seq" xsi:type="BufferingWrapper" bufferSize="1000"
flushTimeout="500" slidingTimeout="false">
<target xsi:type="Seq" name="seq" serverUrl="http://seq.nowhere.com:5341" apiKey="imnotfallingforthatone">
<!-- Augment the log data with some extra properties -->
<property name="ProcessId" value="${processid}" />
<property name="ProcessName" value="${processname}" />
<property name="ThreadId" value="${threadid}" as="number" />
<property name="Machine" value="${machinename}" />
<property name="Host" value="${hostname}" />
<property name="User" value="${environment-user}" />
</target>
</target>
<target xsi:type="Trace" name="debug" rawWrite="true">
<layout>${pad:padding=-5:inner=${uppercase:${level}}}|${pad:padding=-16:fixedLength=true:alignmentOnTruncation=right:inner=${callsite:className=true:fileName=false:includeSourcePath=false:methodName=false:includeNamespace=false}}| ${message}</layout>
</target>
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="console" />
<logger name="*" minlevel="Trace" writeTo="debug" />
<logger name="*" minlevel="Trace" writeTo="seq" />
</rules>
</nlog>
如果您能提供任何见解,我将不胜感激。仅供参考 project is open-source 如果您想克隆它并在 IDE.
中检查它记录器名称创建如下:
- 当使用
Logger.GetLogger(string name)
时,名称不加更改地使用 - 使用
LogManager.GetCurrentClassLogger()
时,会在堆栈跟踪中搜索 class 的名称。在某些情况下,这可能会很棘手,因为内联和异步技巧使得很难找到正确的名称。
在这种情况下,实际上不需要使用 LogManager.GetCurrentClassLogger()
,我建议将其替换为 Logger.GetLogger(string name)
另请注意,您设计的 fluent API 有点不合常规 - 至少对于您示例中添加的属性而言。
- 已经有流畅的界面,见NLog.Fluent namespace
- 某些属性最好添加到上下文中 class(例如 GDC、MDLC,请参阅 context in NLog) or added as a custom layout renderer