使用log4net或NLog进行WCF日志记录/跟踪和活动ID传播

21

我曾经看到很多关于日志记录的问题,最佳实践,什么是最好的日志平台等等。以下是一些来自SO的链接,其中包含有关此主题的非常好的讨论:

logging best practices

log4net vs TraceSource

best logging solution for .NET 3.5 project

.NET 3.5 logging

BEGIN EDIT:

在输入了这篇长文章之后,我想要弄清楚的主要事情是 WCF 日志记录/跟踪和活动 ID 传播与 System.Diagnostics 和 TraceSources 的紧密耦合程度。您是否可以使用第三方日志记录平台(如log4net或NLog)获得“良好”的WCF日志记录/跟踪和活动 ID 传播。如果这样做,您该如何实现?

请参阅本文末尾的几个关于 ServiceTraceViewer 的问题,

END EDIT。

这些帖子中没有详细讨论我的问题。 我对涉及日志记录和 WCF 的人们正在做什么很感兴趣。 如果您正在开发包含 WCF 服务且在项目中具有日志记录的项目,则是否会特别努力使用 WCF 特定的日志记录功能? 特别是,您是否尝试整合诸如活动跟踪、活动传播和端到端跟踪之类的内容? 正如MSDN上所述的那样。这里是另一篇来自 MSDN 的关于传播活动的文章。

这些文章相当好地解释了如何使用 System.Diagnostics TraceSources 进行活动跟踪、活动传播和端到端跟踪。 它展示了如何通过 app.config/web.config 文件配置 WCF 以“打开”这些选项。 WCF 内部使用 TraceSources 记录通信的结果。

以下是一些示例代码(来自上面链接的第二篇 MSDN 文章),更多或更少显示了如何通过 System.Diagnostics 和 TraceSources 实现活动传播:

TraceSource ts = new TraceSource("myUserTraceSource");
Guid oldID = Trace.CorrelationManager.ActivityId;
Guid traceID = Guid.NewGuid();
ts.TraceTransfer(0, "transfer", traceID);
Trace.CorrelationManager.ActivityId = traceID; // Trace is static
ts.TraceEvent(TraceEventType.Start, 0, "Add request");

double value1 = 100.00D;
double value2 = 15.99D;
ts.TraceInformation("Client sends message to Add " + value1 + ", " + value2);
double result = client.Add(value1, value2);
ts.TraceInformation("Client receives Add response '" + result + "'");

ts.TraceTransfer(0, "transfer", oldID);
ts.TraceEvent(TraceEventType.Stop, 0, "Add request");
Trace.CorrelationManager.ActivityId = oldID;

以下是一种方法,您可以在服务内部判断WCF是否已经传播了一个活动:

// Check if an activity was set in scope by WCF, i.e., if it was 
// propagated from the client. If not, i.e., ambient activity is 
// equal to Guid.Empty, create a new one.
if(Trace.CorrelationManager.ActivityId == Guid.Empty)
{
    Guid newGuid = Guid.NewGuid();
    Trace.CorrelationManager.ActivityId = newGuid;
}
// Emit your Start trace.
ts.TraceEvent(TraceEventType.Start, 0, "Add Activity");

// Emit the processing traces for that request.
serviceTs.TraceInformation("Service receives Add " 
                        + n1 + ", " + n2);
// double result = n1 + n2;
serviceTs.TraceInformation("Service sends Add result" + result);

// Emit the Stop trace and exit the method scope.
ts.TraceEvent(TraceEventType.Stop, 0, "Add Activity");
// return result;

根据我所看到的所有示例,活动传播是通过配置(通常通过 app.config) System.ServiceModel.TraceSource 并将其 propagateActivity 属性设置为“true”来实现的。通过在 Trace.CorrelationManager.ActivityId 上设置活动id(guid),实际上可以传播活动。如果您正在使用 log4net 或 NLog,WCF 日志记录和活动传播是否可以有效地使用?

我的项目将大量使用 WCF。我们目前正在尝试决定我们的日志记录解决方案。我认为我已经相当了解如何使用 System.Diagnostics 和 TraceSources 处理 WCF 日志记录和活动传播。我想更好地了解类似于 log4net 和 NLog 这样的日志平台是否提供了某种“本地”支持。它们是否提供一些基础结构,以便可以“手动”实现活动传播。也许像这样:

//Inside client code:
ILog logger = LogManager.GetLogger("client");
Guid oldActivity = Trace.CorrelationManager.ActivityId;
if (oldActivity == Guid.Empty)
{
  Trace.CorrelationManager.ActivityId = Guid.NewGuid();
}

using (LogManager.NDC.Push(Trace.CorrelationManager.ActivityId))
{
  log.Info("Before calling WCF Service");

  wcfService.Method();

  log.Info("After calling WCF Service");
}
Trace.CorrelationManager.ActivityId = oldActivity;
如果log4net/NLog日志格式配置为记录NDC堆栈的顶部,那么客户端记录的每条消息(在活动范围内)都将被“标记”为活动ID。假设WCF服务实现类似,那么在服务调用期间记录的所有消息也将被记录(尽管可能在单独的文件中),并带有相同的活动ID。因此,将能够将“服务”日志文件中的记录消息与“客户端”日志中的相应消息进行关联。
因此,如果您使用WCF并且记录日志,请考虑以下问题:
  1. 您是否使用活动传播?
  2. 您是否使用TraceSources进行日志记录?
  3. 您是否使用其他日志平台(例如log4net,NLog)?
  4. 如果您使用另一个日志平台,您如何进行活动传播?
  5. 您是否使用第三方日志记录的混合(大多数日志记录使用log4net/NLog,WCF服务边界日志使用System.Diagnostics.TraceSource)?
ServiceTraceViewer怎么样?您使用它吗?我看到的大多数示例都是通过TraceSources和XmlTraceListener生成输出的。它能否消费来自log4net,NLog等的输出?它是否与TraceSource为基础的日志记录“最佳”配合?如果是这样,在WCF服务边界上仅记录少量基于TraceSource的日志(捕获一些应用程序上下文以及WCF通信信息)是否足够在ServiceTraceViewer中查看?我曾经短暂地使用过ServiceTraceViewer,只是作为我持续学习WCF过程的一部分。
如果您读到这里,感谢您的阅读。也许我过于考虑了日志记录、WCF活动传播以及在ServiceTraceViewer中查看日志的整合。它似乎是在选择日志平台和/或记录策略时的一个重要考虑因素,但是我对这些日志平台或WCF的经验不足以确定。

1
你找到使用NLog进行相关性的答案了吗? - Michael Freidgeim
好问题。关于这个主题有很多文档,但显然很少信息:P - anton.burger
2个回答

3

仅代表我的个人看法,我使用基于AOP的日志记录,这是我自己编写/维护的,但它就像其他一些日志框架一样......我的日志框架是基于装饰器的,但我可以将其扩展到任何进入调用堆栈的内容。

因此,在您有像这样的代码时:

using (LogManager.NDC.Push(Trace.CorrelationManager.ActivityId)) {
  log.Info("Before calling WCF Service");

  wcfService.Method();

  log.Info("After calling WCF Service");
}
Trace.CorrelationManager.ActivityId = oldActivity;

如果服务器上有类似这样的内容,那么我的方法在这方面是有效的,但是我的方法对于内部日志记录不起作用。我的设置是这样的:

[LogMethod( CaptureDirection = LoggingDirection.InOut /*Optional*/, CaptureVariables = Yes /*Optional*/ )]
public ClassName MyMethodName(params){
  //magic logging happens here on method entry

  DoSomething();

  //if you need logging here I can't do anything with my AOP system

  DoSomethingElse();


  //magic logging happens here on method exit
}

此外,您是否希望在客户端和服务器之间建立相关日志记录?如何协商这两者?如何确保一个与另一个相关联?

是的,我们希望在客户端和服务器之间关联日志记录。假设客户端实际上是一个.NET 4.0客户端(不是Silverlight,因为Silverlight不支持Trace.CorrelationManager.*)。客户端可以设置Trace.Correlationmanager.ActivityId = <new guid>。如果日志记录捕获该值,则每个日志记录语句都可以用ActivityId标记。现在,如果我们可以将该ActivityId传递到服务器,则服务器的日志记录语句也可以使用ActivityId标记每个日志记录语句。如果所有客户端和服务器的所有日志记录... - wageoghe
1
如果所有的日志信息都指向同一个地方,比如一个数据库,那么我们可以通过查询具有相同 ActivityId 的所有日志消息,并按时间排序,从而查看与客户端调用对应的服务器日志。如果您使用 System.Diagnostics 日志/跟踪,则可以在某种程度上免费使用 WCF ActivityId 传播(如我原始问题中所链接的)。我想了解 ActivityId 传播如何/是否与 log4net 和 NLog 等非 System.Diagnostics 日志/跟踪集成。 - wageoghe
由于Silverlight不支持Trace.CorrelationManager.*,因此在使用WCF ActivityId传播时存在问题,因此即使要在Silverlight中“启动”Activity,也需要进行一些工作。 - wageoghe
@wageoghe 我甚至不知道有 Trace.CorrelationManager 这个东西... 太有趣了。我完全不知道该如何继续下去。祝你好运。 - jcolebrand
你应该看一下。如果你经常使用WCF,你可能会发现它很有用。在调用代码中,你可以通过设置ActivityId来“启动”一个活动,如果你在app.config/web.config文件中正确配置了WCF,ActivityId将被传播到你所调用的WCF服务。如果WCF服务能够同时处理多个请求,那么在每个日志消息中记录ActivityId可以将服务器的日志消息与客户端调用(以及任何它可能正在执行的日志记录)相关联。 - wageoghe

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接