Implementing Diagnostings In .NET Applications

Tracing allows us to see various informational data about the running program.

As usual, we run applications in Debug mode and set breakpoints in the necessary places.

But this case is not valid for Release mode. Because the behavior of the program in the release mode is relatively different. In terms of memory optimization, the Garbage collector works more intensively, the compiler generates optimal code for code optimization, and can also change the location of code blocks. That is, as a result, we cannot see the one-to-one behavior in Debug mode in Release mode. Also, you don't have a built-in mechanism to track the application flow after the application is deployed.

Trace 

Controls the flow of the program, any problems that may occur in the program or simply to follow the progress of the flow.

Trace architecture in .NET

Tracing can generally be viewed as a combination of 4 blocks,

  • Source- The source that produces the trace messages
  • Listeners - where trace data will be written
  • Switch – Set log level of trace data
  • Filters - define which trace data will be processed by listeners.

To enable the tracing process, an object of the TraceSource class is created.

The data flow can be provided using one of the TraceInformation(), TraceData(), or TraceEvent() methods.

 TraceSource initially writes information to the Output-Debug window. But from the code example below, it is clear that no data is displayed in the Output window even though the command to send data is given.

The reason is that the Switch mechanism for Trace is in Off mode by default.

Implementing diagnostings in .NET applications

In the continuation of the article, after activating the Switch, it will be possible to see the messages.

But before moving on to Switch, let's take a closer look at the TraceSource methods.

TraceEvent()

TraceSource sends messages of a certain type to listeners rather than a single message.

That is, when writing a message, you need to indicate the type of that message.

The type of the message indicates which category it belongs to (error message, just informational message, category indicating that the program has thrown an exception or completely crashed, etc.).

These messages can be adjusted depending on how the program handles them. For example, if you specify TraceEventType.Information, this is just informational information, but if you specify TraceEventType.Critical, means that the program is already crashing.

 Id is just an identifier given to message steps as a convention. This can be set as a team or used by some agreement.

Implementing diagnostings in .NET applications

In the below example, id=1 is an input, and id=2 is output to the method.

Implementing diagnostings in .NET applications

TraceInformation() is used for sending informational messages to listeners via TraceSource. In fact, this method is a wrapper for the TraceEvent() method and replaces the TraceEvent(TraceEventType.Information, 0, message) template in the background. We can write

Implementing diagnostings in .NET applications

TraceData()

Through this method, you can directly take some object and give it to the listeners. Typically, an Exception instance is sent through this method in case of exceptions.

In the code example you wrote, if we want TraceSource methods to write messages to Output minimally, then Switch for TraceSource should be enabled. Switch allows us to filter data by type. Derived from the Switch class, SourceSwitch is used for filtering in TraceSource on the source side, as the name suggests. Its enum parameters control which group of messages can be sent to listeners.

public class HomeController: Controller {
    private readonly TraceSource _tracing;
    public HomeController() {
        _tracing = new TraceSource("ClassicMVCApp.HomeController");
        //Critical , Error v? warning m?lumatlarinin listener-lara gönd?rilm?sin? icaz? ver.
        _tracing.Switch = new SourceSwitch("ClassicMVCApp.AllSwitching") {
            Level = SourceLevels.Warning
        };
    }
    public ActionResult All() {
        var students = StudentDb.Students;
        return View(students);
    }
    public string GetNames() {
        _tracing.TraceEvent(TraceEventType.Information, 1, "GetNames action started");
        _tracing.TraceError("Some error message for testing purpose");
        List < string > names = new List < string > () {
            "Shoto Todoroki",
            "Midoriya",
            "Endeavor",
            "Katsuki"
        };
        string ns = String.Join(",", names);
        _tracing.TraceEvent(TraceEventType.Warning, 4, "Some warning message");
        _tracing.TraceEvent(TraceEventType.Information, 2, "GetNames action ended");
        return ns;
    }
}

Implementing diagnostings in .NET applications

As you can see from the example, Informational messages are not visible. Because it is not filtered by Switch.

To be able to configure the SourceSwitch data outside the application, we can remove it completely from the code and add it to the application via config. For this, you need to write this in the App.config or Web.config file under the configuration tag.

Implementing diagnostings in .NET applications

It is now possible to send data to listeners by simply creating a TraceSource object in the code and giving it the name given in the config (without specifying any SourceSwitch information in the code).

TraceSource can also write data to different listeners.