views:

290

answers:

5

I basically want to write a customer logger/tracer which also logs the class and method name of the method that calls the logger/tracer. This should be fast so that it does not affect the performance of the application, strongly typed and clean. Does anyone have good ideas?

Here are the few I had but I worry about performance due to reflection:

  • StackTrace/StackFrame (too much overhead?)

  • MethodInfo.GetCurrentMethod() (still too slow? and not very clean)

  • pass method as delegate (C# can do that implicitly and I have access to the MethodInfo, but not very clean)

I appreciate anyone's comments.

UPDATE:

I liked the cleanless of StackFrame so I asked a more specific question here with regards to StackFrame's performance and I got some really good response including performance tests. It turns out that MethodInfo.GetCurrentMethod() is the fastest (takes about 1 microsecond on my computer) and new StackFrame(1) can be requested on demand (takes about 15-20 microseconds on my computer). I threw out the method as delegate option since it's too messy when the method has several parameters.

CONCLUSION:

I've looked at all the options and the best is to write a custom plug-in for PostSharp which injects the method name as string in MSIL during compilation when applying a custom attribute like [Trace] to it. It's the fastest and most maintainable option in my opinion. This even enables a lot more things like passing the parameters names and arguments without any kind of reflection and catching and logging exceptions automatically. This my related question for more information.

+2  A: 

When you are already inside the method (or if you are intercepting the method), I don't think that you can do much better than MethodInfo.GetCurrentMethod - which is not too terribly fast - if you want to stay type-safe.

Since you want to do this for logging, have you considered doing this in an asynchronous operation so that you don't slow down the main thread?

Depending on the load already on your application, it may or may not help.

Mark Seemann
Yeah, I was thinking about that too. But what happens when the application is busy though? Wouldn't that postpone the logging and wouldn't it be lost when the application crashes?
Hermann
Depends on how you implement the async operation. If you just throw it on the ThreadPool then, yes, you are correct, and the ordering is not guaranteed. However, you could also write it to MSMQ, which can give you in-order, durable logging.
Mark Seemann
The async option would only alleviate the actual writing to the log (which could still be beneficial). The actual "GetCurrentMethod" call would still impose the performance penalty on the main thread.
STW
@Yoooder: Yes, that's what I meant by "Depending on the load already on your application". IIRC, MethodInfo.GetCurrentMethod mostly makes use of CPU, so if the overall bottleneck is somewhere else (say, disk I/O), then it would help. If CPU is the bottleneck, it will not - but then I can't think of anything that would...
Mark Seemann
+1  A: 

The best way to do this is at compile time: C++ traditionally used the __FILE__ and __LINE__ preprocessor symbols in macros to do this. Unfortunately the C# compiler doesn't offer macros or an equivalent to __FILE__ and __LINE__ at the moment.

This effectively means that your only option is to log this information at runtime, which means either tediously adding manual tracing to each method you want to log or taking the hit of using reflection as you described.

Stu Mackellar
+1  A: 

I think Log4PostSharp would do the job very well.

Gael Fraiteur
I don't want to use another logger, especially not something based on log4net, but I _really) like the idea of injecting MSIL code. I'll have to research if I can use that somehow.
Hermann
Reading Stu's answer -- it would take approx. one hours to develop the equivalent of __FILE__ and __LINE__ using PostSharp (or __TYPE__ and __METHOD__). Well, 1 hours to me.
Gael Fraiteur
I'll have a look at PostSharp. Thank you Gael!
Hermann
If correctly configured, it's not that slow. But you may suffer if you have tons of small projects. PostSharp is better at large projects (because the per-project overhead is significant). Be sure to use 1.5 RTM installed using the installer.
Gael Fraiteur
After looking at all the options, I am gonna go with a custom plugin for PostSharp. Thanks everyone!
Hermann
+1  A: 

Simply put, the fastest way is to do it statically at compile-time:

public void DoSomething()
{
    TraceCall("DoSomething");
} 

public void TraceCall(string methodName)
{
    if (!tracingEnabled) { return; }
    // Log the call
}

The question then is essentially the same as your previous question; what's the best way to do this in a maintainable and accurate fastion? The run-time options we previously discussed take a relatively severe performance hit, but the trade-off is that they can be easily implemented.

As was mentioned int he previous thread, this is beginning to lean towards Aspect-Oriented-Programming; PostSharp is one such library that can help find the balance of statically compiled performance with simple maintenance.

STW
You're right. I hope it does not take too much effort to implement this with PostSharp. I guess it depends on each individual the needs, but I would not call 20 microseconds a severe performance hit.
Hermann
@Hermann: unless you're writing something that has to handle the throughput of Google, 20ms is entirely negligable. The tests we did in the other question were showing that if you needed to initiate logging calls for 100,000 methods it would add--at most--1.5 seconds. Regardless of the fact that some methods are substantially faster than others all methods are marginal at the end of the day.
STW
A: 

If you are concerned with speed than the actual log message should be created using Event Tracing for Windows. ETW is a high speed logging library implemented as a driver that is accessible from both Kernel Mode and User Mode. Tracing can be dynamically turned on and off. The logging adds very little overhead to the application. I have used ETW to implement tracing in high throughput server apps. Check out NTrace.

Steve