Getting started

ILogger represents the principal component used to write log messages.

public T Get<T>(string key)
{
    ILogger logger = Logger.Factory.Get();

    var item = _cache.Get<T>(key);
    if(item == null)
    {
        logger.Warn(string.Format("Cache entry for {0} was not found", key));
    }

    return item;
}
Viewing log messages

Viewing log messages

Create instance

ILogger has a scoped lifetime.

It should be created at the beginning of a method, and flushed at the end of the methods execution.

Web applications

For web applications, the ILogger is created and flushed automatically per each http request (connection).

To acquire the ILogger instance, use the Logger.Factory.Get() factory method.

public class HomeController : Controller
{
    private readonly ILogger _logger;
    public HomeController()
    {
        _logger = Logger.Factory.Get();
    }

    public IActionResult Index()
    {
        _logger.Debug("Hello World!");

        return View();
    }
}

Calling the Logger.Factory.Get() method multiple times will return the same instance of ILogger.

[TestMethod]
public void Factory_Returns_The_Same_Instance()
{
    for(int i = 1; i <= 5; i++)
    {
        ILogger logger = Logger.Factory.Get();
        logger.Info("Hello " + i);
    }

    ILogger myLogger = Logger.Factory.Get();

    int numberOfLogs = (Logger(myLogger)).DataContainer.LogMessages.Count();

    int expected = 5;
    int actual = numberOfLogs;

    Assert.IsTrue(actual == expected, "Logger.Factory.Get() should return the same instance");
}

Windows / Console applications

For non-web applications, create and flush the logger manually.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
static void Main(string[] args)
{
    ILogger logger = new Logger(url: "Main");

    try
    {
        logger.Info("Executing main");

        // execute Main
    }
    catch(Exception ex)
    {
        logger.Error(ex);
        throw;
    }
    finally
    {
        // notify the listeners
        Logger.NotifyListeners(logger);
    }
}

We use try-catch-finally to make sure that we capture any unhandled exceptions (line 13), and we notify the listeners (line 19).

Register the listeners

Listeners are responsible with saving the logs.

Listeners are registered at application startup using the KissLogConfiguration.Listeners container.

protected void Application_Start()
{
    // register the KissLog.net listener
    KissLogConfiguration.Listeners.Add(new KissLogApiListener(new KissLog.Apis.v1.Auth.Application(
        ConfigurationManager.AppSettings["KissLog.OrganizationId"],
        ConfigurationManager.AppSettings["KissLog.ApplicationId"])
    ));

    // register NLog listener
    KissLogConfiguration.Listeners.Add(new NLogTargetListener());

    if(bool.Parse(ConfigurationManager.AppSettings["UseSqlListener"]))
    {
        KissLogConfiguration.Listeners.Add(new SqlListener());
    }
}

Custom listeners can be created by implementing the ILogListener interface.

Listeners events

KissLog listeners are triggered automatically on three separate events:

  • OnBeginRequest() is executed when the HTTP request starts

  • OnMessage() is executed for each log message created

  • OnFlush() is executed when the HTTP request has completed

BEGIN [GET /api/getUsers]        <---- OnBeginRequest()


ILogger logger = Logger.Factory.Get();

logger.Debug("step 1");          <---- OnMessage()

...
logger.Info("step n");           <---- OnMessage()



END [200 OK GET /api/getUsers]   <---- OnFlush()

Configuration

Additional configuration options are available using the KissLogConfiguration.Options options.

In the example below, we use the AppendExceptionDetails(Exception ex) handler to log EntityFramework validation exceptions.

protected void Application_Start()
{
    KissLogConfiguration.Options
        .AppendExceptionDetails((Exception ex) =>
        {
            // log EntityFramework validation errors
            if (ex is DbEntityValidationException dbException)
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine("DbEntityValidationException:");

                foreach (var error in dbException.EntityValidationErrors.SelectMany(p => p.ValidationErrors))
                {
                    string message = string.Format("Field: {0}, Error: {1}", error.PropertyName, error.ErrorMessage);
                    sb.AppendLine(message);
                }

                return sb.ToString();
            }

            return null;
        });
}