1

AFAIK WCF has a very powerful configurable logging infrastructure, but in my case it's too complex. I want to implement something simple like access.log with pattern similar to this

%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"

Problem is that WCF is logging in XML in very complex format, and it's kinda verbose. Maybe there is some way to simplify this XML? It's ok that it's an XML instead of textfile, but it has multiple fields and data that takes space, makes log harder to read and so on.

The only way I found for now is implement my own IOperationInvoker for it, but maybe I can reuse builtin logging system? Please, advice.

Community
  • 1
  • 1
Alex Zhukovskiy
  • 9,565
  • 11
  • 75
  • 151
  • Are you referring to WCF Tracing? I don't think you can reuse it, though you can control how much information it logs. – Tim Apr 20 '16 at 00:25
  • @Tim WCF Tracing is fine if it logs this info with some additional when overhead is negligible. But it seems that it's not the case. – Alex Zhukovskiy Apr 20 '16 at 07:26

1 Answers1

0

I implemented it with custom behaviour. Here is implementation:

class LoggingBehaviour : IEndpointBehavior
{
    public void Validate(ServiceEndpoint endpoint)
    {
    }

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new LoggingMessageInspector());
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
    }
}

and custom logging inspector:

public class LoggingMessageInspector : IDispatchMessageInspector
{
    private static readonly Logger CurrentClassLogger = LogManager.GetCurrentClassLogger();

    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
    {
        return request.Headers.To;
    }

    public void BeforeSendReply(ref Message reply, object correlationState)
    {
        var requestUri = (Uri)correlationState;
        var currentContext = WebOperationContext.Current;
        if (currentContext == null)
        {
            CurrentClassLogger.Log(LogLevel.Error, "Cannot log reply to [{0}]: WebOperationContext is null", requestUri);
            return;
        }

        try
        {
            var httpRequest = currentContext.IncomingRequest;
            string host = httpRequest.Headers[HttpRequestHeader.Host];
            string method = httpRequest.Method;
            string userAgent = httpRequest.UserAgent;
            var statusCode = currentContext.OutgoingResponse.StatusCode;

            CurrentClassLogger.Log(LogLevel.Info, "[Host {0}] [{1} {2} {3} {4}] [{5}]", host, method, requestUri, (int) statusCode, statusCode,  userAgent);
        }
        catch (Exception ex)
        {
            CurrentClassLogger.Error("Cannot log reply to [{0}] : {1}", requestUri, ex);
        }
    }
}

Then use it!

foreach (var endpoint in ServiceHost.Description.Endpoints)
{
    endpoint.Behaviors.Add(new LoggingBehaviour());
}
Alex Zhukovskiy
  • 9,565
  • 11
  • 75
  • 151