6

我们继承了我们想要改进的设计不佳的 WCF 服务。它的一个问题是它有一百多个方法(在两个不同的接口上),我们怀疑其中大部分没有使用。我们决定对每个方法进行一些日志记录,以跟踪它们何时以及如何被调用。为了使跟踪代码易于重构和防错字,我们这样实现它:

public void LogUsage()
{
    try
    {
        MethodBase callingMethod = new StackTrace().GetFrame(1).GetMethod();
        string interfaceName = callingMethod.DeclaringType.GetInterfaces()[0].Name;
        _loggingDao.LogUsage(interfaceName, callingMethod.Name, GetClientAddress(), GetCallingUrl());
    }
    catch (Exception exception)
    {
        _legacyLogger.Error("Error in usage tracking", exception);
    }
}

LogUsage()然后在我们要跟踪的每个方法的开头调用。

该服务的流量非常高,每天大约有 500,000 多个呼叫。99.95% 的时间里,这段代码执行得很漂亮。但另外 0.05% 的时间,GetInterfaces()返回一个空(但不是null)数组。

为什么GetInterfaces()偶尔会返回不一致的结果?

这似乎微不足道——0.05% 的错误率是我们通常只能梦想的。但关键是要识别所有的服务接触点,如果这个错误总是来自一个(或几个)方法调用,那么我们的跟踪是不完整的。我试图通过调用服务上的每个方法来在我的开发环境中重现此错误,但无济于事。

4

2 回答 2

4

StackTrace是出了名的不可靠,尤其是在多线程环境中。或者更确切地说,它非常可靠,但有时不是很实用。询问“最后调用的方法”可能会产生意想不到的结果。尝试记录 DeclaringType。你可能会对在那里发现的东西感到惊讶。请注意,虽然现在这是 0.05% 的故障率,但它可能会随着应用程序的复杂性而增加。

为了正确实现可重用的跟踪代码,您需要依赖 .NET 4.5 功能Caller Information,通过使用动态代理(例如Castle Dynamic Proxy)或使用 AOP 框架(例如PostSharp)。或者,您可以手动编写跟踪代码。

于 2012-09-20T20:46:30.990 回答
3

来自 Erik Lippert(在 MS 的 C# 编译器团队工作)响应从 StackFrame 获取类型 T

堆栈帧实际上并没有告诉您谁调用了您的方法。堆栈帧告诉您控制权将返回到哪里。栈帧是延续的具体化。调用该方法的人以及控制权返回的位置几乎总是相同的事实是您感到困惑的根源,但我向您保证,它们不必相同。

整篇文章值得一读……

于 2012-09-21T14:33:21.600 回答