Wednesday, March 24, 2010

Logging to Logverse

If you haven't heard of Logverse, it's a service that allows applications to log to it. And just about anything can be logged to it--errors, user actions, debug information... whatever you want.

It's perfect for applications out in the field, like desktop and mobile applications. But even web or other server applications can take advantage of it.

You don't need to use a logging framework to use Logverse. But if you use The Object Guy's Logging Framework, it is extremely easy to create a logger that logs to Logverse.

I have two very small classes here. The first is just a utility class that will write to Logverse.

public class LogverseWriter
{
   private readonly Guid LogId;
   private readonly string SubscriptionKey;

   public LogverseWriter(string aLogId, string aSubscriptionKey)
   {
      LogId = new Guid(aLogId);
      SubscriptionKey = aSubscriptionKey;
   }

   public bool Write(Dictionary<string, string> values)
   {
      var logEntryInfo = new Logverse.LogEntryInfo()
         {
           LogId = LogId,
           SubscriptionKey = SubscriptionKey,
           ClientTimeStampUtc = DateTime.UtcNow
         };

      logEntryInfo.Fields = values;

      var service = new Logverse.LogServiceClient();
      var result = service.Log(logEntryInfo);
      service.Close();

      return result.Result == Logverse.LogResult.EResult.Logged;
   }
}

The second class I have is the LogverseLogger.

public class LogverseLogger : Logger
{
   private readonly LogverseWriter LogverseWriter;

   public LogverseLogger(string aLogId, string aSubscriptionKey)
   {
      LogverseWriter = new LogverseWriter(aLogId, aSubscriptionKey);
   }

   protected override bool DoLog(LogEntry aLogEntry)
   {
      return LogverseWriter.Write(
              new Dictionary<string, string>()
              {
                { "Category", aLogEntry.Category != null ? aLogEntry.Category.ToString() : "" },
                { "Severity", aLogEntry.SeverityString },
                { "Message",  aLogEntry.Message }
              });
   }

   public static void Create(string aLogId, string aSubscriptionKey)
   {
      ConfigLogger.Instance.AddLogger("logverse_" + aLogId, new LogverseLogger(aLogId, aSubscriptionKey));
   }
}

The Logverse logger can't currently be configured using the web.config (or app.config), so at the beginning of the application I call the Create method. Here's an example for a web application. This code would go into global.asax.cs.

protected void Application_Start(object sender, EventArgs e)
{
   LogverseLogger.Create("<mylogid>", "<mysubscriptionkey>");
}

WOW!

Now that was easy. And now I can log to Logverse. Pretty cool, huh?

One might ask, "What about exception handling?" Good question. Actually, it isn't required in the Logger, because that's handled automatically by the framework. (Cool!) However, if you were to use the LogverseWriter class independently, then you'd probably would want to put some exception handling in it. The only reason I didn't was so that I'd have an excuse to talk about it in this paragraph. :)

Friday, March 19, 2010

Logverse Videos



Sunday, March 14, 2010

Logverse

Logverse is coming...

Saturday, January 2, 2010

Configuration Insanity

Obviously something is wrong when a logging framework is so complicated that people feel they need a special GUI to configure it. This is what I'm talking about.

My framework doesn't require any configuration. But it supports it, if that's your style. It's intuitive enough--just like the rest of the framework--that you won't feel the need to call The Geek Squad to help you figure it out.

Watch this re-post of a 7-minute video showing how easy it is to use and configure.

Friday, January 1, 2010

Multi-threaded Logging

In light of my previous post, I thought it would be a good idea for me to demonstrate logging in a multi-threaded application using my framework.

Watch this very short video. It's just a little over 3 minutes long.

Thursday, December 31, 2009

Scary Framework

I don't really want to bag on another logging framework, but I've come across many posts that are downright scary. Here's an example of a situation with one of the most popular logging frameworks. Read down a bit and you'll hear about deadlocks that happened every day--until they removed that logging framework.

I've also read about other serious deadlock issues with that framework. But posting more links would be just piling on.

Try this one for yourself (if you're masochistic enough to be using that other framework). Delete the log file while your application is running. Oops. You can't do that, can you? Because the file is locked. I sure hope you don't have another application writing to the same file--or another logger in the same application.

For me, I think I'll stick with a framework that doesn't require a Ph.D. to configure--and one that is thread-safe, and yet I can be sure won't put my application into any deadlock situations. Like this one.

Exceptional Gotchas!

Yes, the pun was intended.

Many ASP.NET developers think that having code in the Application_Error method in Global.asax.cs is adequate for dealing with any unhandled exceptions within their web application. While it usually is adequate--for most basic web applications, there are particular cases where this simply won't catch all errors.

Specifically, if you have code running on the server that is in a thread pool, or you've spawned a separate thread, or you have callback code for a timer, if an unhandled exception occurs, you just might be out of luck.

You can easily test this for yourself by creating a web page with two buttons, one that throws an exception when you click it, and the other that uses a thread from the thread pool and throws an exception within it. Something like this:

public partial class _Default : System.Web.UI.Page
    {
        private void ThrowException()
        {
            throw new ApplicationException("Ouch!");
        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            ThrowException();
        }

        protected void Button2_Click(object sender, EventArgs e)
        {
            System.Threading.ThreadPool.QueueUserWorkItem( new System.Threading.WaitCallback(DoWork));
        }

        private void DoWork(object dummy)
        {
            ThrowException();
        }
    }

In addition to the HttpUnhandledException that gets sent to the Application_Error method, you need to handle the UnhandledException event on the AppDomain.

You can set up a handler in the Application_Start method in Global.asax.cs. But if you go a step further, you can create something a little more reusable. Here's an HttpModule that will demonstrate handling both kinds of web exeptions--those occurring during a normal web request, and those occurring on separate threads. Perhaps it should be part of the Logging Framework.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using BitFactory.Logging;

namespace WebAppA
{
    public class MyExceptionModule : IHttpModule
    {
        private HttpServerUtility Server { get; set; }

        #region IHttpModule Members

        public void Dispose()
        {            
        }

        public void Init(HttpApplication context)
        {
            // deal with any non-main thread exceptions
            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

            // deal with any HttpUnhandledExceptions 
            context.Error += new EventHandler(context_Error);

            Server = context.Server;
        }

        void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            // If we are here, the process is about to die
            ConfigLogger.Instance.LogFatal(((Exception)e.ExceptionObject).Message);
        }

        void context_Error(object sender, EventArgs e)
        {
            // The outer exception is usually an HttpUnhandledException, so use the InnerException if it exists.
            // Even more detail can be retrieved by iterateing over each InnerException, if desired.
            Exception ex = Server.GetLastError();
            ex = ex.InnerException ?? ex;
            ConfigLogger.Instance.LogError(ex.Message);
        }

        #endregion
    }
}


Modify the above to suit your needs. In addition, the following would go into your web.config file.

<httpModules>
  <add name="MyExceptionModule" type="WebAppA.MyExceptionModule, WebAppA" />
</httpModules>


You might consider putting something like this into a separate utility assembly that you can reuse in all your web projects.