Logging is the optimum way to monitor application behavior, which is essential for a software project once out for the production. C# .NET provides logging API that works with a variety of built-in and third-party logging providers. Application behavior could be monitored by saving, emitting, indexing the log data.

Logging allows the user to find a resolution for unhandled exceptions. Moreover, Logs serves resolutions in problem-solving on different platforms for debugging purposes. Bugs Analysis and application performance is analyzed using the generated logs. Logging help gather statistics and data to use with relevance to Big Data.

  1. Culture of Logging
  2. Logs Level
  3. Frameworks
  4. Best Practice for Logging

Logging Practices C#

Culture of Logging

There are 4 goals to accomplish in Logging to monitor and log the application.

Basic Logs:  There have to have some basic logging in your code for every Key Transaction.

Provisional Logs: Log data with contextual and relevant logs.

Collective Logs: Logs should be consolidated in an accessible path to all stakeholders.

Active Approach in Usage: Real-time Monitoring of logs is essential for errors.

A very basic example that we usually come across

Catch(exception a)
{
   Log.error(a)
}

In this example, the exception may likely have a stack trace. It is a pro-active approach to real-time monitor the bugs.
Logs give users invaluable information on other components like third party libraries.

Logs Level

Logging is the best practice to get rid of any errors coming to your ways. It may save the user from errors and is essential for troubleshooting. The only difficulty is that it could take a big chunk of storage in hard drive. Logs in big chunks could be challenging to search in some instances.

It is the part where logging levels may use to filter out the outputs. Every logging level is associated with the type of logged data.  DEBUG, INFO, and TRACE events are usually non-error conditions which report on the behavior of an application.

It depends upon the use of it, as Logging is disabled in production and acts passively. It enables in a non-production environment. Production environments have checks of WARN and ERROR enabled to report bugs and warnings. It limits production logging to time-sensitive and critical data that effects application availability.

Frameworks provide liberty to developers to use each logging level with freedom. Dev Teams usually establishes a reliable pattern on what to Log on what Level. It may vary from application to application but should be limited to a single application.

Frameworks

There are various frameworks and tools used in .NET. TraceSource, log4Net, and SeriLog are part of the discussion in this article. The three of those mentioned above are the most used and differs from one another but perform similar functions.

1. TraceSource

TraceSource is a native library in Microsoft Bundles. It must detect in the same directory as the executable application.

Configuration

TraceSource needs enabling in the configuration files, named as application.config. After enabling the TraceSoruce, it could use to write messages to the console.

class TraceTest
{
private static TraceSource ts = new TraceSource("TraceTest");
static void Main(string[] args)
{
ts.TraceEvent(TraceEventType.Error, 1, "Error message.");
ts.Close();
return;
}

It allows users if a series of debug tests are to be run and compare the results or maintain an event of a log.

Working of TraceSource

  • This library writes its message to a listener object.
  • Object sends the received messages to pre-determined locations.
  • Initialize Listener using this code to the config file
<configuration>
<system.diagnostics>
<trace autoflush="false" indentsize="4">
<listeners>
<add name="myListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="TextWriterOutput.log" />
<remove name="Default" />
</listeners>
</trace>
</system.diagnostics>
</configuration>

For the implementation, the below snippet clears up space pretty much clear.

Trace.Listeners.Add(new TextWriterTraceListener("TextWriterOutput.log", "myListener"));
Trace.TraceInformation("Test message.");
// You must close or flush the trace to empty the output buffer.
Trace.Flush();

2. Serilog

Serilog offers diagnostic Logging to the console, files, and away. It is easy to composite. Serilog has a clean API, which is portable between recent .NET platforms.

Configuration

It uses a simple C# API for configuration of Logging. For external configuration, it sparingly blendes using the Serilog.Settings.AppSettings package.

Loggers are created using LoggerConfiguration() in serilog.

Log.Logger = new LoggerConfiguration().CreateLogger();
Log.Information("No one listens to me!");

NuGet is available to implement Serilog within C# .Net.

3. Sink

Sinks may configure with Writeto() function. Log event sinks record log events to some external depiction.
It can be a file, console, or a data store. The distribution of SeriLog sinks is through NuGet.

Log.Logger = new LoggerConfiguration()
    .WriteTo.Console()
    .CreateLogger();
Log.Information("Ah, there you are!");

Serilog is most straightforward to set up, and it facilitates with a big group of Sinks as well.

4. Log4Net

Log4Net is the firstborn of the three frameworks. It finds itself in older .Net Projects. Log4net was dock from Java’s log4j project

Log4net sets up with an XML configuration (log4net.config) file that looks like this with assembly function.

<log4net>
  <appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
    <file value="my_log.log" />
    <appendToFile value="true" />
    <maximumFileSize value="50KB" />
    <maxSizeRollBackups value="2" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date %level %message%newline" />
    </layout>
  </appender>
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config")

Once XML configurations are done, Logging is executable.

class MyClass
{
    private static readonly log4net.ILog _log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
    public void Foo()
    {
        _log.Debug("Foo started");
    }
}

log4net supports structured Logging. It covers a minimum of logging targets called appenders. However, it supports fewer targets than others out of the box. Log4net is vast that whatever isn’t supported could be found on the internet with a custom implementation.

Best Practice for Logging

Developers need to follow best practices when creating them to contain the right information when required. One should follow the best approach while creating the logs as they contain useful and useless logs at the same time. The library can be developed from scratch for Logging purposes which serves the project in the longer-term. However, developers mostly benefit from using a built-in or already made SDKs, a better and more timesaving option.

Importance of W’s

Debug logs report application events that are beneficial when diagnosing a problem. Investigations in the application failures need the “W” words: What, When, Where, Who and Why:

  • Who was using the application when it failed?
  • Where in the program application failed?
  • What was the system behavior when it failed?
  • When did the failure take place?
  • Why did the application fail?

“Why the application failed?” is the outcome of a failure investigation and purpose of Logging. Logging targets handle the “when” with timestamps in addition to the log records. The rest of the “Ws” come from logging declarations added to the code. Logging is more effective with two best practices. Which are

  1. Logging Context
  2. Structured Logging

Logging context means adding the “Ws” to log entries. Without context, it can be challenging to relate application failures to logs. It is a typical log statement.

try
{
   // do something
}
Catch(sa as exception){
   Logger.error(sa);
   Throw;
}

TraceSource and Log4NET have features that allow adding this contextual information to logs. It makes them far more useful. It adds the contextual data as metadata to the log entries.

Structured Logging urges on formatting the data to logged stably. SeriLog and Log4NET both support arrangements. Indexing is more efficient in structured logs, making them easier to search.

Enable high-severity logs in production

As briefed above, there is useful as well as unnecessary data gets logged in the activity. For enhancing the performance and avoid using more storage, the target should be Warn and Error messages.

It could be minimized by using #IF Debug in the logging configuration before deploying it in production.

Importance of Log Levels

All frameworks consist of some by default logging levels to each specific message. Info refers to levels, Debug, Warn, Error, and Fatal.

  • Debug & Info usually co-relates as they refer to the vital information to understand the flow and structure.
  • Warn refers to the general warning. It refers to doubtlessness in the program.
  • Error is self-explanatory, as it refers to the error message.
  • Fatal refers to a significant error, which requires termination of the Program or Application.

Logging primary purpose is to debug the production environment where the developer has no option to explore or debug the code for the exception. Logging gives the developer first-hand information on what happened during the course of execution and what caused the exception. It depends on the developer’s witness of what level of logging is implemented and what data is logged that can be later analyzed to trace issues.