-
-
Save Kasiviswanathan3876/30bf696b475a3f813252547b2fc89f74 to your computer and use it in GitHub Desktop.
RequestLogger
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Concurrent; | |
using System.Collections.Generic; | |
using System.Data; | |
using System.Data.SqlClient; | |
using System.IO; | |
using System.Text; | |
using System.Web; | |
using Microsoft.WindowsAzure.ServiceRuntime; | |
public static class RequestLogger | |
{ | |
private static string _logsConnectionString; | |
public static void Init(string logsConnectionString) | |
{ | |
_logsConnectionString = logsConnectionString; | |
using (var connection = new SqlConnection(_logsConnectionString)) | |
using (var comm = connection.CreateCommand()) | |
{ | |
comm.CommandText = Sql.CreateIfNotExists; | |
comm.CommandType = CommandType.Text; | |
connection.Open(); | |
comm.ExecuteNonQuery(); | |
} | |
} | |
static readonly ConcurrentDictionary<string, DateTimeOffset> RequestStartTimes = new ConcurrentDictionary<string, DateTimeOffset>(); | |
static readonly ConcurrentDictionary<string, List<string>> RequestComments = new ConcurrentDictionary<string, List<string>>(); | |
static readonly ConcurrentDictionary<string, string> RequestBodies = new ConcurrentDictionary<string, string>(); | |
public static void BeginRequest() | |
{ | |
try | |
{ | |
var httpContext = HttpContext.Current; | |
var requestId = CreateRequestId(httpContext); | |
RequestStartTimes.TryAdd(requestId, DateTimeOffset.UtcNow); | |
var body = new StreamReader(httpContext.Request.InputStream).ReadToEnd(); | |
httpContext.Request.InputStream.Position = 0; | |
RequestBodies.TryAdd(requestId, body); | |
} | |
catch (Exception) | |
{ | |
// TODO: log | |
} | |
} | |
private static string CreateRequestId(HttpContext httpContext) | |
{ | |
var requestId = Guid.NewGuid().ToString(); | |
httpContext.Items["RequestLogger.RequestId"] = requestId; | |
return requestId; | |
} | |
public static void LogComment(string comment) | |
{ | |
try | |
{ | |
var httpContext = HttpContext.Current; | |
var requestId = (string) httpContext.Items["RequestLogger.RequestId"] ?? CreateRequestId(httpContext); | |
if (!RequestComments.ContainsKey(requestId)) | |
{ | |
RequestComments.TryAdd(requestId, new List<string>()); | |
} | |
RequestComments[requestId].Add(comment); | |
} | |
catch (Exception) | |
{ | |
// TODO: log | |
} | |
} | |
public static void EndRequest() | |
{ | |
try | |
{ | |
var httpContext = HttpContext.Current; | |
var request = httpContext.Request; | |
var response = httpContext.Response; | |
var endedAt = DateTimeOffset.UtcNow; | |
var requestId = (string)httpContext.Items["RequestLogger.RequestId"]; | |
DateTimeOffset startedAt = DateTimeOffset.MinValue; | |
string body = null; | |
string comments = null; | |
if (requestId != null) | |
{ | |
if (RequestStartTimes.ContainsKey(requestId)) | |
{ | |
RequestStartTimes.TryRemove(requestId, out startedAt); | |
} | |
if (RequestBodies.ContainsKey(requestId)) | |
{ | |
RequestBodies.TryRemove(requestId, out body); | |
} | |
if (RequestComments.ContainsKey(requestId)) | |
{ | |
List<string> commentsList; | |
RequestComments.TryRemove(requestId, out commentsList); | |
comments = string.Join(";", commentsList); | |
} | |
} | |
string authorizationHeader = null; | |
var headers = new StringBuilder(); | |
foreach (string header in request.Headers) | |
{ | |
if (header == "Authorization") | |
{ | |
authorizationHeader = request.Headers[header]; | |
} | |
else | |
{ | |
headers.AppendFormat("{0}: {1}", header, request.Headers[header]); | |
headers.AppendLine(); | |
} | |
} | |
InsertLog(request.HttpMethod, request.Url.ToString(), authorizationHeader, headers.ToString(), body, | |
startedAt, endedAt, response.StatusCode, comments); | |
} | |
catch (Exception) | |
{ | |
// TODO: log | |
} | |
} | |
private static void InsertLog(string httpMethod, string url, string authorizationHeader, string otherHeaders, string body, | |
DateTimeOffset? startedAt, DateTimeOffset endedAt, int responseCode, string comments) | |
{ | |
using (var connection = new SqlConnection(_logsConnectionString)) | |
using (var comm = connection.CreateCommand()) | |
{ | |
comm.CommandText = Sql.InsertLog; | |
comm.CommandType = CommandType.Text; | |
comm.Parameters.Add("@InstanceId", SqlDbType.NVarChar).Value = RoleEnvironment.IsAvailable ? RoleEnvironment.CurrentRoleInstance.Id.Truncate(100) : "(local)"; | |
comm.Parameters.Add("@Method", SqlDbType.NVarChar).Value = httpMethod.Truncate(10); | |
comm.Parameters.Add("@Url", SqlDbType.NVarChar).Value = url; | |
comm.Parameters.Add("@AuthorizationHeader", SqlDbType.NVarChar).Value = | |
(object)authorizationHeader ?? DBNull.Value; | |
comm.Parameters.Add("@OtherHeaders", SqlDbType.NVarChar).Value = otherHeaders; | |
comm.Parameters.Add("@Body", SqlDbType.NVarChar).Value = (object)body ?? DBNull.Value; | |
comm.Parameters.Add("@StartedAt", SqlDbType.DateTimeOffset).Value = (object)startedAt ?? DBNull.Value; | |
comm.Parameters.Add("@EndedAt", SqlDbType.DateTimeOffset).Value = endedAt; | |
comm.Parameters.Add("@DurationMs", SqlDbType.Int).Value = | |
startedAt.HasValue ? (object) (endedAt - startedAt.Value).TotalMilliseconds : DBNull.Value; | |
comm.Parameters.Add("@ResponseCode", SqlDbType.Int).Value = responseCode; | |
comm.Parameters.Add("@Comments", SqlDbType.NVarChar).Value = (object)comments ?? DBNull.Value; | |
connection.Open(); | |
comm.ExecuteNonQuery(); | |
} | |
} | |
public static class Sql | |
{ | |
public const string CreateIfNotExists = @" | |
if not exists (select * from sys.tables where name = 'RequestLogs2') | |
begin | |
create table RequestLogs2 ( | |
Id bigint not null identity(1,1) primary key clustered, | |
InstanceId nvarchar(100) not null, | |
Method nvarchar(10) null, | |
Url nvarchar(max) null, | |
AuthorizationHeader nvarchar(max) null, | |
OtherHeaders nvarchar(max) null, | |
Body nvarchar(max) null, | |
StartedAt datetime null, | |
EndedAt datetime null, | |
DurationMs int null, | |
ResponseCode int null, | |
Comments nvarchar(max) null | |
) | |
end"; | |
public const string InsertLog = @" | |
insert into RequestLogs2 (InstanceId, Method, Url, AuthorizationHeader, OtherHeaders, Body, StartedAt, EndedAt, DurationMs, ResponseCode, Comments) | |
values (@InstanceId, @Method, @Url, @AuthorizationHeader, @OtherHeaders, @Body, @StartedAt, @EndedAt, @DurationMs, @ResponseCode, @Comments)"; | |
} | |
public static string Truncate(this string s, int maxLength) | |
{ | |
if (s == null) | |
return null; | |
if (s.Length < maxLength) | |
return s; | |
return s.Substring(0, maxLength); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment