Skip to the content.

Building A Custom Handler

Custom handlers can be used to put the trace format out in any format that you wish, this allows for integration with other logging tools or writing in a format suited for your needs.

Creating a custom handler

This is the simplest form of custom handler, although it does not actually do anything it is a valid handler.

 public class CustomHandler : BaseHandler, IBilgeMessageListener {

        public string Name => "CustomHandler";

        public string GetStatus() {
            return "OK";
        }

        public Task HandleMessageAsync(MessageMetadata[] msg) {
            return Task.CompletedTask;
        }
    }

We are going to want to do something more useful though - lets put the message out to the console in JSON format, using the system JsonSerializer we can write JSON to the console.

 public class CustomHandler : BaseHandler, IBilgeMessageListener {

        public string Name => nameof(CustomHandler);

        public string GetStatus() {
            return "OK";
        }

        public Task HandleMessageAsync(MessageMetadata[] msg) {

            foreach (var nextMsg in msg) {
                var f = JsonSerializer.Serialize(nextMsg, typeof(MessageMetadata));
                Console.WriteLine(f);
            }
            
            return Task.CompletedTask;
        }
    }

Json on the console

Note that the HandleMessageAsync is an async method, returning a task therefore if you are writing to a network or filesystem you can use the async methods to not block.

The main elements of the MessageMetadata structure that are passed in are:


// Contains the type of command - log message, verbose message, flow message etc.
TraceCommandTypes CommandType;  

// Contains the main message that has been logged.
string Body;

// Contains secondary information passed to the log
string FurtherDetails;

// Contains supporting context data information
IDictionary<string, string> MessageTags;

// Contains structured logging information.
dynamic StructuredData { get; set; }

Using Message Status

The handlers have a status method, this is used to indicate issues with the handler for diagnostic purposes - when no trace is being written its a good idea to be able to find out why that is. You should return a status of your handler wherever possible.

 public class CustomHandler : BaseHandler, IBilgeMessageListener {
        private string statusString = "OK";
        public string Name => nameof(CustomHandler);

        public string GetStatus() {
            return "OK";
        }

        public Task HandleMessageAsync(MessageMetadata[] msg) {
            try {
                foreach (var nextMsg in msg) {
                    var f = JsonSerializer.Serialize(nextMsg, typeof(MessageMetadata));
                    Console.WriteLine(f);
                }
            } catch (NotSupportedException nx) {
                statusString = "HandlerFailed > " + DateTime.Now.ToString() + " > " + nx.Message;
            }
            return Task.CompletedTask;
        }
    }