问题描述
使用 NLog 进行日志记录的最佳或最有用的配置是什么?(这些可以是简单的也可以是复杂的,只要它们有用即可.)
What are the best or most useful configurations for logging with NLog? (These can be simple or complex, as long as they're useful.)
我正在考虑一些示例,例如自动滚动特定大小的日志文件、更改布局(日志消息)(无论是否有异常)、一旦发生错误就升级日志级别等.
I'm thinking of examples like automatically rolling over log files at a certain size, changing the layout (log message) whether or not there is an exception, escalating the log level once an error has occurred, etc.
这里有一些链接:
推荐答案
其中一些属于一般 NLog(或日志记录)提示的类别,而不是严格的配置建议.
Some of these fall into the category of general NLog (or logging) tips rather than strictly configuration suggestions.
以下是 SO 上的一些常规日志记录链接(您可能已经看过其中的一些或全部):
Here are some general logging links from here at SO (you might have seen some or all of these already):
使用基于 Logger logger = LogManager.GetCurrentClassLogger()
类命名记录器的常见模式.这为您的记录器提供了高度的粒度,并为您的记录器配置提供了极大的灵活性(全局控制、按命名空间、按特定记录器名称等).
Use the common pattern of naming your logger based on the class Logger logger = LogManager.GetCurrentClassLogger()
. This gives you a high degree of granularity in your loggers and gives you great flexibility in the configuration of the loggers (control globally, by namespace, by specific logger name, etc).
在适当的地方使用非基于类名的记录器.也许您有一个真正想要单独控制日志记录的功能.也许你有一些横切日志问题(性能日志).
Use non-classname-based loggers where appropriate. Maybe you have one function for which you really want to control the logging separately. Maybe you have some cross-cutting logging concerns (performance logging).
如果您不使用基于类名的日志记录,请考虑以某种层次结构(可能按功能区域)命名您的记录器,以便您可以在配置中保持更大的灵活性.例如,您可能有一个数据库"功能区、一个分析"FA 和一个ui"FA.每一个都可能有子区域.因此,您可能会像这样请求记录器:
If you don't use classname-based logging, consider naming your loggers in some kind of hierarchical structure (maybe by functional area) so that you can maintain greater flexibility in your configuration. For example, you might have a "database" functional area, an "analysis" FA, and a "ui" FA. Each of these might have sub-areas. So, you might request loggers like this:
Logger logger = LogManager.GetLogger("Database.Connect");
Logger logger = LogManager.GetLogger("Database.Query");
Logger logger = LogManager.GetLogger("Database.SQL");
Logger logger = LogManager.GetLogger("Analysis.Financial");
Logger logger = LogManager.GetLogger("Analysis.Personnel");
Logger logger = LogManager.GetLogger("Analysis.Inventory");
等等.使用分层记录器,您可以全局(*"或根记录器)、FA(数据库、分析、UI)或子区域(Database.Connect 等)配置日志记录.
And so on. With hierarchical loggers, you can configure logging globally (the "*" or root logger), by FA (Database, Analysis, UI), or by subarea (Database.Connect, etc).
记录器有很多配置选项:
Loggers have many configuration options:
<logger name="Name.Space.Class1" minlevel="Debug" writeTo="f1" />
<logger name="Name.Space.Class1" levels="Debug,Error" writeTo="f1" />
<logger name="Name.Space.*" writeTo="f3,f4" />
<logger name="Name.Space.*" minlevel="Debug" maxlevel="Error" final="true" />
请参阅 NLog 帮助,详细了解每个选项的含义.这里最值得注意的项目可能是通配符记录器规则的能力,多个记录器规则可以为单个记录语句执行"的概念,并且记录器规则可以标记为最终",因此后续规则不会执行给定的日志语句.
See the NLog help for more info on exactly what each of the options means. Probably the most notable items here are the ability to wildcard logger rules, the concept that multiple logger rules can "execute" for a single logging statement, and that a logger rule can be marked as "final" so subsequent rules will not execute for a given logging statement.
使用 GlobalDiagnosticContext、MappedDiagnosticContext 和 NestedDiagnosticContext 为您的输出添加额外的上下文.
Use the GlobalDiagnosticContext, MappedDiagnosticContext, and NestedDiagnosticContext to add additional context to your output.
在配置文件中使用变量"来简化.例如,您可以为布局定义变量,然后在目标配置中引用该变量,而不是直接指定布局.
Use "variable" in your config file to simplify. For example, you might define variables for your layouts and then reference the variable in the target configuration rather than specify the layout directly.
<variable name="brief" value="${longdate} | ${level} | ${logger} | ${message}"/>
<variable name="verbose" value="${longdate} | ${machinename} | ${processid} | ${processname} | ${level} | ${logger} | ${message}"/>
<targets>
<target name="file" xsi:type="File" layout="${verbose}" fileName="${basedir}/${shortdate}.log" />
<target name="console" xsi:type="ColoredConsole" layout="${brief}" />
</targets>
或者,您可以创建一组自定义"属性以添加到布局中.
Or, you could create a "custom" set of properties to add to a layout.
<variable name="mycontext" value="${gdc:item=appname} , ${mdc:item=threadprop}"/>
<variable name="fmt1withcontext" value="${longdate} | ${level} | ${logger} | [${mycontext}] |${message}"/>
<variable name="fmt2withcontext" value="${shortdate} | ${level} | ${logger} | [${mycontext}] |${message}"/>
或者,您可以严格通过配置来执行诸如创建日"或月"布局渲染器之类的事情:
Or, you can do stuff like create "day" or "month" layout renderers strictly via configuration:
<variable name="day" value="${date:format=dddd}"/>
<variable name="month" value="${date:format=MMMM}"/>
<variable name="fmt" value="${longdate} | ${level} | ${logger} | ${day} | ${month} | ${message}"/>
<targets>
<target name="console" xsi:type="ColoredConsole" layout="${fmt}" />
</targets>
您还可以使用布局渲染来定义您的文件名:
You can also use layout renders to define your filename:
<variable name="day" value="${date:format=dddd}"/>
<targets>
<target name="file" xsi:type="File" layout="${verbose}" fileName="${basedir}/${day}.log" />
</targets>
如果您每天滚动文件,则每个文件都可以命名为Monday.log"、Tuesday.log"等.
If you roll your file daily, each file could be named "Monday.log", "Tuesday.log", etc.
不要害怕编写自己的布局渲染器.它很简单,允许您通过配置将自己的上下文信息添加到日志文件中.例如,这里有一个布局渲染器(基于 NLog 1.x,而不是 2.0),可以将 Trace.CorrelationManager.ActivityId 添加到日志中:
Don't be afraid to write your own layout renderer. It is easy and allows you to add your own context information to the log file via configuration. For example, here is a layout renderer (based on NLog 1.x, not 2.0) that can add the Trace.CorrelationManager.ActivityId to the log:
[LayoutRenderer("ActivityId")]
class ActivityIdLayoutRenderer : LayoutRenderer
{
int estimatedSize = Guid.Empty.ToString().Length;
protected override void Append(StringBuilder builder, LogEventInfo logEvent)
{
builder.Append(Trace.CorrelationManager.ActivityId);
}
protected override int GetEstimatedBufferSize(LogEventInfo logEvent)
{
return estimatedSize;
}
}
像这样告诉 NLog 你的 NLog 扩展在哪里(什么程序集):
Tell NLog where your NLog extensions (what assembly) like this:
<extensions>
<add assembly="MyNLogExtensions"/>
</extensions>
像这样使用自定义布局渲染器:
Use the custom layout renderer like this:
<variable name="fmt" value="${longdate} | ${ActivityId} | ${message}"/>
使用异步目标:
<nlog>
<targets async="true">
<!-- all targets in this section will automatically be asynchronous -->
</targets>
</nlog>
和默认目标包装器:
<nlog>
<targets>
<default-wrapper xsi:type="BufferingWrapper" bufferSize="100"/>
<target name="f1" xsi:type="File" fileName="f1.txt"/>
<target name="f2" xsi:type="File" fileName="f2.txt"/>
</targets>
<targets>
<default-wrapper xsi:type="AsyncWrapper">
<wrapper xsi:type="RetryingWrapper"/>
</default-wrapper>
<target name="n1" xsi:type="Network" address="tcp://localhost:4001"/>
<target name="n2" xsi:type="Network" address="tcp://localhost:4002"/>
<target name="n3" xsi:type="Network" address="tcp://localhost:4003"/>
</targets>
</nlog>
在适当的情况下.有关这些的更多信息,请参阅 NLog 文档.
where appropriate. See the NLog docs for more info on those.
告诉 NLog 观察并在配置发生变化时自动重新加载:
Tell NLog to watch and automatically reload the configuration if it changes:
<nlog autoReload="true" />
有几个配置选项可帮助排除 NLog 故障
There are several configuration options to help with troubleshooting NLog
<nlog throwExceptions="true" />
<nlog internalLogFile="file.txt" />
<nlog internalLogLevel="Trace|Debug|Info|Warn|Error|Fatal" />
<nlog internalLogToConsole="false|true" />
<nlog internalLogToConsoleError="false|true" />
有关详细信息,请参阅 NLog 帮助.
See NLog Help for more info.
NLog 2.0 添加了 LayoutRenderer 包装器,允许对布局渲染器的输出执行额外的处理(例如修剪空格、大写、小写等).
NLog 2.0 adds LayoutRenderer wrappers that allow additional processing to be performed on the output of a layout renderer (such as trimming whitespace, uppercasing, lowercasing, etc).
如果您想将代码与 NLog 的硬依赖隔离,请不要害怕包装记录器,但要正确包装.在 NLog 的 github 存储库中有如何包装的示例.包装的另一个原因可能是您希望自动向每个记录的消息添加特定的上下文信息(通过将其放入 LogEventInfo.Context).
Don't be afraid to wrap the logger if you want insulate your code from a hard dependency on NLog, but wrap correctly. There are examples of how to wrap in the NLog's github repository. Another reason to wrap might be that you want to automatically add specific context information to each logged message (by putting it into LogEventInfo.Context).
包装(或抽象)NLog(或任何其他与此相关的日志记录框架)有利有弊.只需稍加努力,您就可以在此处找到大量关于 SO 呈现双方的信息.
There are pros and cons to wrapping (or abstracting) NLog (or any other logging framework for that matter). With a little effort, you can find plenty of info here on SO presenting both sides.
如果您正在考虑包装,请考虑使用 Common.Logging.它运行良好,如果您愿意,可以轻松切换到另一个日志记录框架.此外,如果您正在考虑包装,请考虑如何处理上下文对象(GDC、MDC、NDC).Common.Logging 目前不支持对它们的抽象,但据说它在添加功能队列中.
If you are considering wrapping, consider using Common.Logging. It works pretty well and allows you to easily switch to another logging framework if you desire to do so. Also if you are considering wrapping, think about how you will handle the context objects (GDC, MDC, NDC). Common.Logging does not currently support an abstraction for them, but it is supposedly in the queue of capabilities to add.
这篇关于最有用的 NLog 配置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!