Log tracing in .NET Framework
Tags: logging, tracing
Published: 2021-03-08 18:20:53

Logging is a very vital part in Software development. It is used to record and trace error states in the development process. It helps to investigate errors after a problem has occurred. The recording can be done in the command line, a log file, an event log, a specialised database or a web service.  
Tracing is the special use of logging to record information about a program’s execution. The information is used by programmers for debugging and depending on the details contained in a trace log can be used to diagnose common problems with software.

In this article, I am going to show how tracing logs in .NET framework works which uses the TraceSource class. The basis of tracing is to trace messages that are sent to listeners using switches that forward the data to the respective assigned output medium which could be a log file.

To demonstrate this, let's create a simple console application that runs a Powershell script. The following steps show how tracing works with snapshots and code examples.

* Create the Powershell script: The script simply gets some processes running on a computer system using the Get-Process cmdlet.
```
get-process
```
* Create a new console project in Visual Studio using the .NET framework and C# programming language. Check out [this tutorial](https://docs.microsoft.com/de-de/visualstudio/get-started/csharp/tutorial-console?view=vs-2019) for details.

* Create an instance of the TraceSource class with the parameter “LogTracing” which is the name of the Tracesource.
```c#
private static TraceSource mySource = new TraceSource("LogTracing")
```
* Write the process for running the powershell script from the console application. The code snippet below shows how to do it. The parameters “RedirectStandardError” and “RedirectStandardOutput” determine if the errors and output respectively should be redirected to another location e.g. a log file. The "DataReceivedEventHandler" handles the events that are being received and passes it to the process that is considered i.e., output or error data.
```c#
static void RunScript()
{
 var psFile =Path.Combine(Directory.GetParent(Directory.GetCurrentDirectory()).Parent.FullName, @"log_tracing.ps1");
            if (File.Exists(psFile))
            {
                var startInfo = new ProcessStartInfo()
                {
                    FileName = "powershell.exe",
                    Arguments = $"-ExecutionPolicy unrestricted -file \"{psFile}\"",
                    UseShellExecute = false,
                    Verb = "runas",
                    RedirectStandardError = true,
                    RedirectStandardOutput = true
                };
                using(Process myprocess = Process.Start(startInfo))
                {
                    myprocess.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
                    myprocess.ErrorDataReceived += new DataReceivedEventHandler(ErrorHandler);
                    myprocess.BeginOutputReadLine();
                    myprocess.BeginErrorReadLine();
                    myprocess.WaitForExit();
                }
            }
        }
```
* The ErrorHandler and OutputHandler methods are shown in the snippet below. The TraceSource class has a TraceEvent method that writes a trace message to a trace listener. The trace listener will be added in the App.config file.
```c#
private static void ErrorHandler(object sender, DataReceivedEventArgs e)
{
  // write the error text to the file if there is something to write
   if (!String.IsNullOrEmpty(e.Data))
   {
      mySource.TraceEvent(TraceEventType.Error, 2, e.Data);
   }
}

private static void OutputHandler(object sender, DataReceivedEventArgs e)
{
  // write the output text to the file if there is something to write
 if (!String.IsNullOrEmpty(e.Data))
 {
   mySource.TraceEvent(TraceEventType.Information, 1, e.Data);
 }
}
```
* In the App.Config file, the trace listener is added and also the TraceSource name "LogTracing". The switchName and switchType are defined. The listener with the name "LogTracingListener" is added. There are 4 TraceLevel enumerations which are Verbose, Warning, Information and Error. You can find more information [in the docs] (https://docs.microsoft.com/de-de/dotnet/api/system.diagnostics.tracelevel?view=net-5.0). Focus is on "Information" in this article.
```c#
<system.diagnostics>
    <sources>
      <source name="LogTracing"
        switchName="sourceSwitch"
        switchType="System.Diagnostics.SourceSwitch">
        <listeners>
          <add name="LogTracingListener"/>
          <remove name="Default"/>
        </listeners>
      </source>
    </sources>
    <switches>
      <add name="sourceSwitch" value="Information"/>
    </switches>
    <sharedListeners>
      <add name="LogTracingListener"
        type="System.Diagnostics.TextWriterTraceListener"
        initializeData="LogTracingListener.txt">
        <filter type="System.Diagnostics.EventTypeFilter"
          initializeData="Information"/>
      </add>
    </sharedListeners>
  </system.diagnostics>
```
* Run the code and you will find the log file in the bin folder of the project. 

Please check the [Microsoft docs](https://docs.microsoft.com/de-de/dotnet/framework/debug-trace-profile/how-to-use-tracesource-and-filters-with-trace-listeners) for more info. Also, check the [repo](https://github.com/obinnadtq/TraceSourceDemo) for the code.

Thanks for reading!