Application Security Testing: An Integral Part of DevOps
The Trace and Debug classes are included in the .NET framework for adding tracing support in an application. Proper tracing in the code helps in application debugging, bug fixing, and profiling. Three unique features of the .NET tracing support are: support of trace filtering using Trace Switches, Trace Listeners, and trace configuration using application configuration files without recompilation of the application.
As a convention, the Debug Class is used to instrument the code for pure debugging purposes; and this code instrumentation is not included in release builds. This is the default setting of the VS.NET. VS.NET removes the code instrumentation based on the Debug Class from release builds. Only code instrumentation based on the Trace Class is enabled in release builds. However, it is possible to change the default setting, if required.
Note that all members of the Trace and Debug classes are static. Thus, for its use, no member variables of these classes are required to be declared. Also, both classes have exactly the same members with similar signatures. For a complete members list of the classes, check the .NET SDK documentation.
Compiling to Include Debug/Trace Support
To enable tracing based on the Trace Class in an application, the compile time symbol, TRACE, must be defined. If this symbol is not defined, all tracing code based on the Trace Class is removed from the application during the compilation process. Similarly, tracing based on the Debug Class is controlled by the DEBUG symbol. This is the first level of filtering support as discussed above.
There are two methods to define the TRACE (or DEBUG) symbol to include the tracing support. The first one is to use the #define directive in the application code as given in the following snippet. The #define statement must be the first statement in the file.
#define DEBUG // #define TRACE to enable Tracing based on // the Trace Class using System; ...
The second method is to define the flag while compiling the application, as shown in the following.
csc /define:DEBUG myfile.cs ... // C# users vbc /define:TRACE=True myfile.vb ... // VB .NET users
Enabling or Disabling Tracing Using Trace Switches
It is possible to enable or disable Tracing based on the Trace/Debug classes using Trace Switches. By using trace switches, the level of tracing can be controlled by using the application configuration file. There are two types of tracing switches: BooleanSwitch and TraceSwitch. The BooleanSwitch is used as a flag to enable and disable the tracing. On the other hand, the TraceSwitch supports tracing levels so that trace messages at a particular level can be enabled or disabled. This is a very powerful filtering mechanism. It can be changed using configuration files without re-compilation of the application.
The following gives an example of the use of the trace switches.
BooleanSwitch boolSwitch = new BooleanSwitch("ABooleanSwitch", "Demo bool Switch"); TraceSwitch traceSwitch = new TraceSwitch("ATraceSwitch", "Demo trace switch"); // Set the switch values programmatically boolSwitch.Enabled = true; traceSwitch.Level = TraceLevel.Info; Trace.WriteLineIf(boolSwitch.Enabled, "bool switch is enabled"); Trace.WriteLineIf(traceSwitch.TraceInfo, "traceSwitch.TraceInfo is enabled"); Trace.WriteLineIf(traceSwitch.TraceError, "traceSwitch.TraceError is enabled");
When using TraceSwitch, the tracing occurs only if the current trace level is equal to or less than the specified level. For instance, in the above example, the message "traceSwitch.TraceError is enabled" will not be displayed, because the 'Trace Error' level is less than the current value of the tracing level (Trace Info). The following table shows the enumeration values of TraceLevel. To set the tracing level of a Trace Switch, these values should be used instead of using hard-coded numeric values.
|Enumerated Value||Integer Value||Remarks|
|Error||1||Only error messages|
The above example explained the use of the WriteLineIf method of the Trace Class. A Trace Switch can also be used in a condition statement, as shown in the following code.
if(boolSwitch.Enabled) Trace.WriteLine("Boolean switch is enabled");
The above examples discussed the use of trace switches where the trace level is set programmatically. It is also possible, which is more common and effective, to set the trace level by using the application configuration files. In this method, there is no need to change and thus re-compile the application.
The following section explains the use of trace switches using application configuration files. The application configuration file for Windows as an application is named appplicationName.exe.config. For ASP.NET application files, it is named web.config.
- Add the following after the <configuration> but before the </configuration> tag. Note that the names here are the same as the name of trace switches (first parameter passed to the constructor) used in the application. Also note that we have used only two switches, so there are only two entries. However, there should be one entry for each trace switch used in the application.
<system.diagnostics> <switches> <!-- 0 - Disabled 1 - Enabled --> <add name="ABooleanSwitch" value="0" /> <!-- 0 - Disabled 1 - Gives error messages 2 - Gives errors and warnings 3 - Gives more detailed error information 4 - Gives verbose trace information --> <add name="ATraceSwitch" value = "0" /> </switches> </system.diagnostics>In this configuration, both switches are switched off.
- If a BooleanSwitch is required to be turned ON, change its value to something other than 0. For example, in the above, make the change to '<add name="ABooleanSwitch" value="1" />.
- If a TraceSwitch is needed to be switched ON, change the value to the appropriate level given in table above (1 to 4).
The tracing based on the Trace and Debug is sent to trace listeners registered for the application. By default, if no trace listeners are registered for the application, the tracing is sent to the DefaultTraceListener. The default listener sends the tracing message to the OutputDebugString, which can be captured using a debug monitor like DebugView from SysInternals.
The following example shows how to add a console, file, and event log as debug listeners.
Debug.Listeners.Add(new TextWriterTraceListener(Console.Out)); Debug.Listeners.Add(new TextWriterTraceListener(File.Create( "Output.txt"))); Debug.Listeners.Add(new EventLogTraceListener("SwitchesDemo"));
The download includes a MyTrace.cs and MyTrace.exe.config file to experiment the Trace and Debug classes. Use the command-line C# compiler (csc) to compile the application with and without various combinations of /define:TRACE and /define:DEBUG switches.