Code Smarter Not Harder #2: Simple Logging in #CaliburnMicro

Interesting enough today that I sat on a webcast concerning Caliburn.Micro that they talked specifically about how to troubleshoot your bindings and was surprised that the presenter did not seem to know about the ability to log from Caliburn.Micro. Not really surprising because unless you dig down into the framework code you would never really notice that Rob Eisenberg ( Blog | Twitter ) is actually outputting a lot of stuff that could be picked up upon if only you would wire it up. So I am going to show you how to set up a very simple Debug Window log handler so that you can actually see what the framework is trying to do for you underneath the covers and I find it an invaluable resource to use when you are trying to debug projects.

First off let’s go ahead and set up our project using by grabbing a WPF Caliburn.Micro template from the online gallery and creating our project.

image

Now I have added just a few folders to keep everything in line with the project but basically I am going to add a really simple class to the framework area of my project.

image

Nothing special here…. now in order to consume what the framework has for us I need to add a few small references

using Caliburn.Micro;
using System.Diagnostics;

Now we can have our logging class implement the ILog interface provided by the framework. And you will end up with the following code.

   1:          #region ILog Members
   2:   
   3:          public void Error(Exception exception)
   4:          {
   5:               throw new NotImplementedException();
   6:          }
   7:   
   8:          public void Info(string format, params object[] args)
   9:          {
  10:                throw new NotImplementedException();
  11:          }
  12:   
  13:          public void Warn(string format, params object[] args)
  14:          {
  15:              throw new NotImplementedException();
  16:          }
  17:   
  18:          #endregion

So basically, the framework is going to send us three types of messages, an Error, a Warning, and an Info. You can clearly see that the error message returns us the exception and if you look at the other two you will notice that the framework doesn’t even make us format our own message by providing us with the necessary format string and arguments to feed into a String.Format statement. Pretty cool indeed.

So let’s wire this up. First thing is first.We’ll create the constructor and some function to format our message so that everything looks the same and to add in some date/time information. So we create a small formatting function like this and wire up the constructor.

   1:          private readonly Type _type;
   2:   
   3:          public DebugWindowLogger(Type type)
   4:          {
   5:              _type = type;
   6:          }
   7:   
   8:   
   9:          private string FormatLogMessage(string format, 
  10:              params object[] args)
  11:          {
  12:              return string.Format("[{0}] {1}",
  13:                  DateTime.Now.ToString("u"),
  14:                  string.Format(format, args));
  15:          }

 

Now we can go about filling out our ILog interface members which is pretty self explanatory. So here is the code for the completed class….

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:  using Caliburn.Micro;
   6:  using System.Diagnostics;
   7:   
   8:  namespace SilverwingTech.SQLDoxs.Resources.Framework
   9:  {
  10:      class DebugWindowLogger : ILog
  11:      {
  12:   
  13:          private readonly Type _type;
  14:   
  15:          public DebugWindowLogger(Type type)
  16:          {
  17:              _type = type;
  18:          }
  19:   
  20:   
  21:          private string FormatLogMessage(string format, 
  22:              params object[] args)
  23:          {
  24:              return string.Format("[{0}] {1}",
  25:                  DateTime.Now.ToString("u"),
  26:                  string.Format(format, args));
  27:          }
  28:   
  29:   
  30:          #region ILog Members
  31:   
  32:          public void Error(Exception exception)
  33:          {
  34:              Debug.WriteLine(
  35:                  FormatLogMessage(exception.ToString()), "ERROR");
  36:          }
  37:   
  38:          public void Info(string format, params object[] args)
  39:          {
  40:              Debug.WriteLine(
  41:                  FormatLogMessage(format, args), "INFO");
  42:          }
  43:   
  44:          public void Warn(string format, params object[] args)
  45:          {
  46:              Debug.WriteLine(
  47:                  FormatLogMessage(format, args), "WARNING");
  48:          }
  49:   
  50:          #endregion
  51:      }
  52:  }

 

Simple as 1,2,3 …… the last thing we need to do is to wire up the logging in the Bootstrapper class file so that it is wired up when our application is launched. To do that we just simply need to override the base Configure method of the Bootstrapper and insert one line of code to tell the framework.. “Hey! Here’s the logging class I would like to use”.

   1:  using Caliburn.Micro;
   2:  using SilverwingTech.SQLDoxs.Resources.Framework;
   3:  namespace SilverwingTech.SQLDoxs
   4:  {
   5:      public class Bootstrapper : 
   6:          Caliburn.Micro.Bootstrapper<SilverwingTech.SQLDoxs.ViewModels.ShellViewModel>
   7:      {
   8:          protected override void Configure()
   9:          {
  10:              // set up logging 
  11:              LogManager.GetLog = type => new DebugWindowLogger(type);
  12:   
  13:              base.Configure();
  14:          }
  15:      }
  16:  }

Now we’re ready to run our little sample app because the template has already made a rudimentary ShellView and ShellViewModel for us with a single Title property thats wired up to a TextBlock.

image

Now when we run our program and watch the Debug Window we see all of the messages sent from the framework nicely displayed for us to pilfer through and see what’s going on

image

Totally awesome! Now its a lot easier to figure out where some of your bindings may be going astray!

Hopefully, this little post will help some of you out

 

Cheers!

AJ