Search code examples
c#servicestackhttplistenerrequest

Generic logging of AppHost requests incl. bodies in ServiceStack


I want to Log every single HTTP Request that my ServiceStack AppHost tries to handle. I've come up with a decent solution but i dont know if this might explode somewhere, as i inject a MemoryStream to HttpListenerRequest because the InputStream won't let me seek back.

My Log

    public static void R(HttpListenerRequest request)
    {
        var guid = Guid.NewGuid().ToString().Replace("-", "");
        L(LogType.Request, "{1} Url: {0} LocalEndPoint: {2} RemoteEndPoint: {3}", request.Url, request.HttpMethod, request.LocalEndPoint.ToString(), request.RemoteEndPoint.ToString());
        foreach (var header in request.Headers.AllKeys)
        {
            Trace.WriteLine(string.Format("{0} H  {1}: {2}", (char)LogType.Request, header, request.Headers[header]));
        }
        string content = null;
        if (request.InputStream != null)
        {
            MemoryStream memStream = new MemoryStream();
            request.InputStream.CopyTo(memStream);
            request.InputStream.Close();
            request.InputStream.Dispose();
            memStream.Position = 0;
            var reader = new StreamReader(memStream);
            {
                content = reader.ReadToEnd();
                memStream.Position = 0;
                request.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
                    .Where(field => field.Name == "m_RequestStream")
                    .First()
                    .SetValue(request, memStream);
            }
        }

        if (!string.IsNullOrEmpty(content))
        {
            foreach (var line in content.Split('\n'))
            {
                Trace.WriteLine(string.Format("{0} B  {1}", (char)LogType.Request, line));
            }                
        }
    }

Inside the AppHost

    protected override Task ProcessRequestAsync(HttpListenerContext context)
    {
        var request = context?.Request;
        if (request != null)
        {
            Log.R(request);
        }

        return base.ProcessRequestAsync(context);
    }

As said, this is currently working, but I'm afraid of releasing it. So maybe you got a better way of logging all requests with bodies.


Solution

  • You can use this approach, although I'd recommend using the built-in Request Logger. You can log the Request Body with EnableRequestBodyTracking=true which will enable buffering of the Request Body and configuring LimitToServiceRequests=false will also log non-Service requests, e.g:

    Plugins.Add(new RequestLogsFeature {
        EnableRequestBodyTracking = true,
        LimitToServiceRequests = false,
    });