Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WCF services, logging vertically

I've been looking at logging for WCF services (including technologies like NLog and PostSharp), but I have something I haven't yet resolved... I don't know if I'm missing something obvious or it's just not possible.

Let's say I have a WCF service tier with 100+ web service call entry points. One of these is causing a problem. Beneath that tier is a business logic tier and a database tier. What I want to do (I think) is turn on logging for that service call (which would include the activity ID for correlation), so that any calls to that service are logged, and any log messages in the lower tiers are also logged. I don't really want to turn on logging at the assembly level for the lower tiers because they'll be shared by many of the web service methods.

Is this even possible, via an existing framework or by using something like the CorrelationManager in a creative way?

like image 295
Dan Fox Avatar asked Oct 15 '12 08:10

Dan Fox


1 Answers

In log4net you can set a property on the thread context that will be included in all logging events for the thread.

public class WcfServiceClass
{
    public void ProblemServiceMethod()
    {
        using (log4net.ThreadContext.Stacks["logThisMethod"].Push("ProblemServiceMethod"))
        {
            // can also add the correlationId to the logs using this method.
            // call business logic...

        }
    }
}

Then create a custom appender that filters by it.

public class IfContextSetFilterAppender : log4net.Appender.AppenderSkeleton
{
    protected override void Append(LoggingEvent loggingEvent)
    {
        bool logThisEntry = false;
        string serviceMethodBeingLogged;

        foreach (object p in loggingEvent.GetProperties())
        {
            System.Collections.DictionaryEntry dEntry = (System.Collections.DictionaryEntry)p;
            if (dEntry.Key == "logThisMethod")
            {
                logThisEntry = true;
                serviceMethodBeingLogged = dEntry.Value.ToString();
            }
        }

        if (!logThisEntry)
            return; // don't log it.

        // log it.
    }
}

That’s the very simplistic (but clear) example of the idea.

If I was really building this into as large scale a service as you describe, I would:

  1. Create a IOperationInvoker endpoint behavior that grabs the method name and sets a log4net context value for all calls its applied to.

  2. (Optionally) Have the appender read from app.config the filter list of the all service method names that should be logged. (If you are selective in what methods the OperationInvoker behavior are applied to, the appender doesn't need this complexity.)

By doing the behavior you have several options for controlling logging on a production service through configuration alone without ever touching the service code.

like image 73
ErnieL Avatar answered Oct 07 '22 18:10

ErnieL