Skip to content

Instantly share code, notes, and snippets.

@danbarua
Created August 16, 2013 11:04
Show Gist options
  • Save danbarua/6249022 to your computer and use it in GitHub Desktop.
Save danbarua/6249022 to your computer and use it in GitHub Desktop.
Redis request logger for ServiceStack
using System;
using System.Collections.Generic;
using System.Linq;
using ServiceStack.Common.Web;
using ServiceStack.Redis;
using ServiceStack.ServiceHost;
using ServiceStack.ServiceInterface;
using ServiceStack.ServiceInterface.Providers;
using ServiceStack.ServiceInterface.ServiceModel;
using ServiceStack.ServiceModel;
using ServiceStack.Text;
namespace TTL.Digivoice.Web.Api.Helpers
{
public class RedisRollingRequestLogger : IRequestLogger
{
public const int DefaultCapacity = 1000;
private readonly IRedisClientsManager redisClientsManager;
private readonly string namespacePrefix;
private int capacity;
private readonly string requestIdKey;
private readonly string listKey;
public RedisRollingRequestLogger(IRedisClientsManager redisClientsManager, string namespacePrefix,
int? capacity = DefaultCapacity)
{
if (redisClientsManager == null) throw new ArgumentNullException("redisClientsManager");
if (string.IsNullOrEmpty(namespacePrefix)) throw new ArgumentNullException("namespacePrefix");
this.redisClientsManager = redisClientsManager;
this.namespacePrefix = namespacePrefix;
this.capacity = capacity.GetValueOrDefault(DefaultCapacity);
requestIdKey = "servicestack:stats:{0}:requestId".Fmt(namespacePrefix);
listKey = "servicestack:stats:{0}:requestLogs".Fmt(namespacePrefix);
}
public void Log(IRequestContext requestContext, object requestDto, object response, TimeSpan elapsed)
{
using (var client = redisClientsManager.GetClient())
{
var requestType = requestDto != null ? requestDto.GetType() : null;
if (ExcludeRequestDtoTypes != null
&& requestType != null
&& ExcludeRequestDtoTypes.Contains(requestType))
return;
var requestId = client.Increment(requestIdKey, 1);
var entry = new RequestLogEntry
{
Id = requestId,
DateTime = DateTime.UtcNow,
RequestDuration = elapsed,
};
var httpReq = requestContext != null ? requestContext.Get<IHttpRequest>() : null;
if (httpReq != null)
{
entry.HttpMethod = httpReq.HttpMethod;
entry.AbsoluteUri = httpReq.AbsoluteUri;
entry.PathInfo = httpReq.PathInfo;
entry.IpAddress = requestContext.IpAddress;
entry.ForwardedFor = httpReq.Headers[HttpHeaders.XForwardedFor];
entry.Referer = httpReq.Headers[HttpHeaders.Referer];
entry.Headers = httpReq.Headers.ToDictionary();
entry.UserAuthId = httpReq.GetItemOrCookie(HttpHeaders.XUserAuthId);
entry.SessionId = httpReq.GetSessionId();
entry.Items = httpReq.Items;
entry.Session = EnableSessionTracking ? httpReq.GetSession() : null;
if (!EnableSessionTracking)
{
entry.Items.Remove(ServiceExtensions.RequestItemsSessionKey);
}
}
if (HideRequestBodyForRequestDtoTypes != null
&& requestType != null
&& !HideRequestBodyForRequestDtoTypes.Contains(requestType))
{
entry.RequestDto = requestDto;
if (httpReq != null)
{
entry.FormData = httpReq.FormData.ToDictionary();
if (EnableRequestBodyTracking)
{
entry.RequestBody = httpReq.GetRawBody();
}
}
}
if (!response.IsErrorResponse())
{
if (EnableResponseTracking)
entry.ResponseDto = response;
}
else
{
if (EnableErrorTracking)
entry.ErrorResponse = InMemoryRollingRequestLogger.ToSerializableErrorResponse(response);
}
client.Lists[listKey].Prepend(entry.ToJson());
client.Lists[listKey].Trim(0, capacity);
}
}
public List<RequestLogEntry> GetLatestLogs(int? take)
{
using (var client = redisClientsManager.GetClient())
{
return !take.HasValue
? client.Lists[listKey]
.Select(x => x.FromJson<RequestLogEntry>())
.ToList()
: client.Lists[listKey].GetRange(0, take.Value)
.Select(x => x.FromJson<RequestLogEntry>())
.ToList();
}
}
public bool EnableSessionTracking { get; set; }
public bool EnableRequestBodyTracking { get; set; }
public bool EnableResponseTracking { get; set; }
public bool EnableErrorTracking { get; set; }
public string[] RequiredRoles { get; set; }
public Type[] ExcludeRequestDtoTypes { get; set; }
public Type[] HideRequestBodyForRequestDtoTypes { get; set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment