Click here to Skip to main content
15,861,125 members
Articles / Programming Languages / C#
Article

Considerations for implementing trace facilities in release builds of .NET applications

Rate me:
Please Sign up or sign in to vote.
3.61/5 (11 votes)
4 Nov 20029 min read 112K   58   8
What is the best technique to produce trace output in release build of .NET application, i.e. when application is shipped to a customer or runs in a production environment? The article discusses pros and cons of standard .NET trace facilities, and presents some alternatives.

Introduction

This article was written as a part of a presentation for Norwegian .NET User Group.

Some time ago in my article about custom .NET trace listeners I presented various methods to customize generation of .NET application trace output. Originally I planned to update that article to include more advanced customization, but I changed my mind due to several reasons:

  • Built-in .NET trace facilities have serious limitations that prevent .NET Trace class from being the best choice for production level tracing; because of these limitations developers should customize standard Trace only up to a certain level – above that level they should consider other options;
  • New custom trace listener examples have been posted on the Web since I wrote my article, including an SQL-based trace listener (explained in the article Tracing in .NET and Implementing Your Own Trace Listeners at 15seconds.com), so I decided to use hyper-link capabilities instead of writing my own version of the same thing;
  • Microsoft recently announced their plans for future .NET development, and next version of VS.NET (code-named “Everett”) will include Enterprise Instrumentation Framework that will provide functionality currently missing in standard .NET trace.

So instead of writing new fancy trace listeners, I decided to investigate the following questions:

  • Should release builds of .NET applications be compiled with TRACE option?
  • Does built-in .NET trace provides a good choice for trace output generation in production environment?
  • What are alternatives to .NET Trace class?

Release builds: to trace or not to trace

This will of course be a matter of choice, although Microsoft has shown their own preferences: TRACE symbol is not defined for release build of newly generated managed C++ projects, but release builds of C# projects have TRACE defined. Looks confusing but I think it is reasonable: it is useful to have a trace backdoor for final versions of your applications, and as long as there are no active listeners (specified in the configuration file), there will be no trace output. On the other hand, C++ language traditions does not have default trace capabilities, so C++ developers accept that they should remember to explicitly define TRACE symbol for release builds of their applications.

But there are different opinions on this matter. Richard Grimes in his book Developing Applications with Visual Studio.NET criticized the idea of enabling trace in release builds. He listed four arguments:

  • Trace messages are always generated (even when not collected), so it affects performance;
  • Code that generates trace messages takes up space in a binary;
  • If customer uses his own version of a trace listener, and this version is badly written, your application will suffer from the code it has nothing to do with;
  • Leaving trace messages in your release means that you have not fully tested your code; your application should only suffer from exceptional situations which should be reported to Windows Event Log.

I must say I fully agree only with the first of these statements: if your application produces detailed output of its activities, it will always affect performance. On the other hand, this must be a conscious choice: low level routines that can be used within loops should probably limit its output to debug builds, but if you need an activity report from an application in production, you will just have to take performance cost.

I don't think trace messages add up so much to your binary size that you should consider removing them just for this reason. Modern technology trend does not care much about disk space consumption. Look at .NET with its XCOPY deployment! And how much of your application CD will be taken by trace messages? Just a small fraction.

The argument about custom trace listeners that can affect your application execution requires your attention: yes, adding trace functionality adds a new dimension to your application and sets certain requirements to trace consumers. But this is a general concern that you have to take when shipping your program to a customer: hardware, operating system service pack, device drivers – there is a lot of parameters that you can’t control but must consider. Again, I don’t think you should disable application trace just for this reason.

And finally, the argument that I most strongly oppose: leaving trace messages in the release build indicates that you have not fully tested your code. Such statement brings us back to the world of stand-alone applications running on stand-alone machines, where if a program fails, it must be that particular program’s responsibility. Modern computer programs aggregate so much of external functionality that in case of failure it’s not often possible to point a finger to a single module – system administrators must collect enough information to trace back a sequence of steps that led to an error.

So my personal choice is to enhance release versions of applications with trace capabilities, either by defining TRACE symbol during compilation, or by using custom reporting facilities. Take some precautions to limit the size of your trace output (one approach was demonstrated in my previous article), but give your users an option to generate program activity report.

Release builds: is .NET Trace class a right choice?

Now that I have convinced you that you should have trace or some alternative enabled in release builds (or at least I convinced myself one more time), let’s see if existing .NET Trace class can be used as a basis for trace in a production environment. As with any .NET class, you can override default trace functionality (by implementing custom listeners, not by subclassing Trace class that is sealed). However, there are two major design limitations of standard .NET Trace that may force you looking for alternatives. I described them in my previous article, but let me summarize it here:

  • Methods of Trace and TraceListener have no way of defining message severity level – you can use conditional methods, but conditions that are tested using either BooleanSwitch or TraceSwitch are not forwarded to a listener, i.e. listeners are not able to categorize incoming messages by its TraceSwitch level. As a result, trace output will not contain information about error level.
  • When using standard trace functionality there is no way of assigning different trace listeners different severity thresholds. Trace output is the same for all listeners, though you will hardly send to Windows Event Log the same amount of information you will write into a text file.

I consider these omissions to be a design flaw: leaving message severity levels out of .NET trace implementation puts a serious limit on usability of Trace class in production environment. I can think about only one reason why Trace was designed in such a way: internally Trace class is almost a clone of Debug class – they share the same implementation and differ only in preprocessor symbols and default listeners. I wish Trace had more on its own and was more extensible.

But before you decide that you will implement your own trace facilities (or use the ones I’ll mention in the next section), remember that once you replace built-in .NET Trace class, you no longer use unified trace output. If your application consists of several components written by different developers – or even vendors – you will risk ending up with several trace outputs, generated by different trace engines.

So what criteria should be used to select trace implementation for release builds? The choice is of course yours, but I would consider the following:

  • If you develop reusable components, you should not add dependencies on custom trace implementation: use built-in .NET classes, they will be a least common denominator;
  • For most of desktop applications built-in trace listeners (debug, text and event log) provide sufficient number of options; if you’re not satisfied with the output format, you can always customize it by subclassing either listener itself or corresponding Stream-based class; so in this case you should also try to stay with standard .NET Trace class;
  • If you develop enterprise level applications, especially if your program should meat 24x7 availability requirement, you will most likely need to optimize trace output for clarity, so in case of failure you should be able to quickly locate suspicious parts in the system log; in such case you will need not only to filter trace output per listener, but also store severity level per message – none of these options are available from built-in .NET trace classes, so you will need to look for alternatives.

Trace for enterprises

So what is a replacement for built-in .NET Trace class in case you need more sensitive control over trace output? It seems that Microsoft is aware of current .NET trace limitations and is going to help us reasonably soon: next version of Visual Studio.NET (code-named "Everett") will include Enterprise Instrumentation Framework (EIF) that will fill the gaps and provide a lot of new features. EIF will have support for configurable event filtering and severity levels, so developers should be able to write the following code:

 // Note that the syntax may change when EIF is released

TraceMessageEvent.Raise("My trace message"); 
ErrorMessageEvent.Raise("My error", 1, "CODE");   // message, severity, error code

And of course SQL databases can be configured as trace event repository which makes EIF a good choice for audit purposes.

While Enterprise Instrumentation Framework meets your tomorrow demands, if you are more concerned about where you want to go today, you must look somewhere else. One nice alternative is a solution TrimaTrace developed by a Norwegian company Trimanet.It is much more powerful than standard .NET trace functionality, it can be used remotely via TCP and has very good performance (more than 30,000 messages per second locally on a Pentium III machine with 1 GHz CPU). TrimaTrace has unbeatable affordability, because it’s free.

After I uploaded the first edition of this article, I received a reference to another alternative - .NET implementation of the popular log4j Java API providing flexible and arbitrarily granular control over log management and configuration. This implementation is also free and is hosted on SourceForge by NeoWorks.

Conclusion

Every modern design decision is complex: all simple questions are already answered, and we are left with necessity to compare and compromise. Topics like debugging options and formatting trace output seem to be unimportant in the face of real problems we have to solve every day. However, don’t oversimplify them: they are parts of the foundation of your development environment, and it’s worth arranging them properly.

Resources

  1. Vagif Abilov. Writing custom .NET trace listeners.
  2. Richard Grimes. Developing Applications with Visual Studio.NET.
  3. Mansoor Ahmed Siddiqui. Tracing in .NET and Implementing Your Own Trace Listeners.
  4. TrimaTrace, a freeware .NET trace tool by Trimanet.
  5. Log4Net, a freeware .NET port of Java log API by NeoWorks.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Architect Miles AS
Norway Norway
Vagif Abilov is a Russian/Norwegian software developer and architect working for Miles. He has more than twenty years of programming experience that includes various programming languages, currently using mostly C# and F#.

Vagif writes articles and speaks at user group sessions and conferences. He is a contributor and maintainer of several open source projects, including Simple.Data OData adapter, Simple.OData.Client and MongOData.

Comments and Discussions

 
GeneralProgram to hear trace events Pin
Ricardo Mendes24-Aug-05 10:51
Ricardo Mendes24-Aug-05 10:51 
GeneralFileRollingTraceListener Pin
rido7-May-05 10:45
rido7-May-05 10:45 
GeneralThere's no performance issue! Pin
Hugo Hallman5-Nov-04 13:17
Hugo Hallman5-Nov-04 13:17 
GeneralMultiple TraceListeners with multiple TraceSwitches Pin
Heath Stewart7-Nov-02 9:46
protectorHeath Stewart7-Nov-02 9:46 
GeneralFYI Pin
Marc Clifton20-Oct-02 11:38
mvaMarc Clifton20-Oct-02 11:38 
GeneralRe: FYI Pin
Vagif Abilov20-Oct-02 20:38
professionalVagif Abilov20-Oct-02 20:38 
Thank you, Marc. I also checked your article - it's great. Perhaps if I read it before submitting mine, some of my point might be slightly different (just slightly!) Smile | :)

Vagif Abilov
MCP (Visual C++)
Oslo, Norway


Hex is for sissies. Real men use binary. And the most hardcore types use only zeros - uppercase zeros and lowercase zeros.
Tomasz Sowinski
GeneralConsiderations for implementing trace facilities in release builds of .NET applications Pin
Anonymous20-Oct-02 9:36
Anonymous20-Oct-02 9:36 
GeneralRe: Considerations for implementing trace facilities in release builds of .NET applications Pin
Vagif Abilov20-Oct-02 20:21
professionalVagif Abilov20-Oct-02 20:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.