/// <summary> /// Processes the incoming request. This method is not depended on the environment and so can be unit tested. /// Note that the incoming request may not be the POST request with log data. /// /// Effect of this method: /// * setting StatusCode on the response parameter /// * adding headers to the response parameter /// * logging contents of log request /// </summary> /// <param name="json"> /// JSON payload in the incoming request /// </param> /// <param name="logRequestBase"> /// * Type of browser that sent the request /// * IP address that sent the address /// * Url that the request was sent to /// * Request Id sent as part of the request /// * Request data to be given to onLogging event handler /// </param> /// <param name="serverSideTimeUtc">Current time in UTC</param> /// <param name="httpMethod">HTTP method of the request</param> /// <param name="origin">Value of the Origin request header</param> /// <param name="response"> /// Empty response object. This method can add headers, etc. /// </param> internal static void ProcessLogRequest(string json, LogRequestBase logRequestBase, DateTime serverSideTimeUtc, string httpMethod, string origin, LogResponse response) { JsnlogConfiguration jsnlogConfiguration = JavascriptLogging.GetJsnlogConfiguration(); ILoggingAdapter logger = JavascriptLogging.GetLogger(); if ((httpMethod != "POST") && (httpMethod != "OPTIONS")) { response.StatusCode = (int)HttpStatusCode.MethodNotAllowed; return; } string corsAllowedOriginsRegex = jsnlogConfiguration.corsAllowedOriginsRegex; bool originIsAllowed = ((!string.IsNullOrEmpty(corsAllowedOriginsRegex)) && (!string.IsNullOrEmpty(origin)) && Regex.IsMatch(origin, corsAllowedOriginsRegex)); if (originIsAllowed) { response.AppendHeader("Access-Control-Allow-Origin", origin); } response.StatusCode = (int)HttpStatusCode.OK; if (httpMethod == "OPTIONS") { // Standard HTTP response (not related to CORS) response.AppendHeader("Allow", "POST"); // Only if the origin is allowed send CORS headers if (originIsAllowed) { response.AppendHeader("Access-Control-Max-Age", Constants.CorsAccessControlMaxAgeInSeconds.ToString()); response.AppendHeader("Access-Control-Allow-Methods", "POST"); response.AppendHeader("Access-Control-Allow-Headers", "jsnlog-requestid, content-type"); } return; } // httpMethod must be POST List <FinalLogData> logDatas = ProcessLogRequestExec(json, logRequestBase, serverSideTimeUtc, jsnlogConfiguration); // --------------------------------- // Pass log data to Common Logging foreach (FinalLogData logData in logDatas) { logger.Log(logData); } }
/// <summary> /// Processes the incoming request. This method is not depended on the environment and so can be unit tested. /// Note that the incoming request may not be the POST request with log data. /// /// Effect of this method: /// * setting StatusCode on the response parameter /// * adding headers to the response parameter /// * logging contents of log request /// </summary> /// <param name="json"> /// JSON payload in the incoming request /// </param> /// <param name="logRequestBase"> /// * Type of browser that sent the request /// * IP address that sent the address /// * Url that the request was sent to /// * Request Id sent as part of the request /// * Request data to be given to onLogging event handler /// </param> /// <param name="serverSideTimeUtc">Current time in UTC</param> /// <param name="httpMethod">HTTP method of the request</param> /// <param name="origin">Value of the Origin request header</param> /// <param name="response"> /// Empty response object. This method can add headers, etc. /// </param> internal static void ProcessLogRequest(string json, LogRequestBase logRequestBase, DateTime serverSideTimeUtc, string httpMethod, string origin, LogResponse response) { JsnlogConfiguration jsnlogConfiguration = JavascriptLogging.GetJsnlogConfiguration(); ILoggingAdapter logger = JavascriptLogging.GetLogger(); if ((httpMethod != "POST") && (httpMethod != "OPTIONS")) { response.StatusCode = (int)HttpStatusCode.MethodNotAllowed; return; } string corsAllowedOriginsRegex = jsnlogConfiguration.corsAllowedOriginsRegex; bool originIsAllowed = ((!string.IsNullOrEmpty(corsAllowedOriginsRegex)) && (!string.IsNullOrEmpty(origin)) && Regex.IsMatch(origin, corsAllowedOriginsRegex)); if (originIsAllowed) { response.AppendHeader("Access-Control-Allow-Origin", origin); } response.StatusCode = (int)HttpStatusCode.OK; if (httpMethod == "OPTIONS") { // Standard HTTP response (not related to CORS) response.AppendHeader("Allow", "POST"); // Only if the origin is allowed send CORS headers if (originIsAllowed) { response.AppendHeader("Access-Control-Max-Age", Constants.CorsAccessControlMaxAgeInSeconds.ToString()); response.AppendHeader("Access-Control-Allow-Methods", "POST"); response.AppendHeader("Access-Control-Allow-Headers", "jsnlog-requestid, content-type"); } return; } // httpMethod must be POST List<FinalLogData> logDatas = ProcessLogRequestExec(json, logRequestBase, serverSideTimeUtc, jsnlogConfiguration); // --------------------------------- // Pass log data to Common Logging foreach (FinalLogData logData in logDatas) { logger.Log(logData); } }
private static async Task ProcessRequestAsync(HttpContext context) { var headers = context.Request.Headers.ToDictionary(); string urlReferrer = headers.SafeGet("Referer"); string url = context.Request.GetDisplayUrl(); var logRequestBase = new LogRequestBase( userAgent: headers.SafeGet("User-Agent"), userHostAddress: context.Wrapper().GetUserIp(), requestId: context.Wrapper().GetLogRequestId(), url: (urlReferrer ?? url).ToString(), queryParameters: context.Request.Query.ToDictionary(), cookies: context.Request.Cookies.ToDictionary(), headers: headers); DateTime serverSideTimeUtc = DateTime.UtcNow; string httpMethod = context.Request.Method; string origin = headers.SafeGet("Origin"); Encoding encoding = HttpHelpers.GetEncoding(headers.SafeGet("Content-Type")); string json; using (var reader = new StreamReader(context.Request.Body, encoding)) { json = await reader.ReadToEndAsync(); } var response = new LogResponse(); LoggerProcessor.ProcessLogRequest(json, logRequestBase, serverSideTimeUtc, httpMethod, origin, response); // Send dummy response. That way, the log request will not remain "pending" // in eg. Chrome dev tools. // // This must be given a MIME type of "text/plain" // Otherwise, the browser may try to interpret the empty string as XML. // When the user uses Firefox, and right clicks on the page and chooses "Inspect Element", // then in that debugger's console it will say "no element found". // See // http://www.acnenomor.com/307387p1/how-do-i-setup-my-ajax-post-request-to-prevent-no-element-found-on-empty-response // http://stackoverflow.com/questions/975929/firefox-error-no-element-found/976200#976200 ToAspNet5Response(response, context.Response); context.Response.ContentType = "text/plain"; context.Response.ContentLength = 0; }
/// <summary> /// Processes a request with logging info. Unit testable. /// /// Returns log info in easily digestable format. /// </summary> /// <param name="json">JSON sent from client by AjaxAppender</param> /// <param name="serverSideTimeUtc">Current time in UTC</param> /// <param name="jsnlogConfiguration">Contains all config info</param> internal static List <FinalLogData> ProcessLogRequestExec(string json, LogRequestBase logRequestBase, DateTime serverSideTimeUtc, JsnlogConfiguration jsnlogConfiguration) { var logDatas = new List <FinalLogData>(); FinalLogData logData = null; try { LogRequestData logRequestData = LogMessageHelpers.DeserializeJson <LogRequestData>(json); foreach (var logItem in logRequestData.lg) { logData = null; // in case ProcessLogItem throws exception logData = ProcessLogItem(logItem, logRequestBase, serverSideTimeUtc, jsnlogConfiguration); if (logData != null) { logDatas.Add(logData); } } } catch (Exception e) { try { string message = string.Format("Exception: {0}, json: {1}, FinalLogData: {{{2}}}, logRequestBase: {{{3}}}", e, json, logData, logRequestBase); var internalErrorFinalLogData = new FinalLogData(null) { FinalMessage = message, FinalLogger = Constants.JSNLogInternalErrorLoggerName, FinalLevel = Level.ERROR }; logDatas.Add(internalErrorFinalLogData); } catch { } } return(logDatas); }
private static FinalLogData ProcessLogItem(LogRequestSingleMsg logItem, LogRequestBase logRequestBase, DateTime serverSideTimeUtc, JsnlogConfiguration jsnlogConfiguration) { string serversideLoggerNameOverride = jsnlogConfiguration.serverSideLogger; string messageFormat = jsnlogConfiguration.serverSideMessageFormat; string levelOverride = jsnlogConfiguration.serverSideLevel; string dateFormat = jsnlogConfiguration.dateFormat; try { LevelUtils.ValidateLevel(levelOverride); } catch (Exception e) { throw new PropertyException("levelOverride", e); } // ---------------- string message = logItem.m; string logger = logItem.n; string level = logItem.l; // note that level as sent by the javascript is a number DateTime utcDate = DateTime.UtcNow; string timestampMs = logItem.t; try { double ms = double.Parse(timestampMs); utcDate = DateTime.SpecifyKind((new DateTime(1970, 1, 1)).AddMilliseconds(ms), DateTimeKind.Utc); } catch { } // ---------------- string jsonmessage = ""; if (messageFormat.Contains("%jsonmessage")) { jsonmessage = LogMessageHelpers.EnsureValidJson(message); } // ---------------- var logRequest = new LogRequest(message, logger, level, utcDate, jsonmessage, logRequestBase); var loggingEventArgs = new LoggingEventArgs(logRequest) { Cancel = false, ServerSideMessageFormat = messageFormat }; // ---------------- if (string.IsNullOrWhiteSpace(logger)) { logger = Constants.RootLoggerNameServerSide; } loggingEventArgs.FinalLogger = serversideLoggerNameOverride ?? logger; string consolidatedLevel = levelOverride ?? level; loggingEventArgs.FinalLevel = LevelUtils.ParseLevel(consolidatedLevel).Value; // ---------------- loggingEventArgs.FinalMessage = messageFormat .Replace("%message", message) .Replace("%jsonmessage", jsonmessage) .Replace("%utcDateServer", serverSideTimeUtc.ToString(dateFormat)) .Replace("%utcDate", utcDate.ToString(dateFormat)) .Replace("%dateServer", Utils.UtcToLocalDateTime(serverSideTimeUtc).ToString(dateFormat)) .Replace("%date", Utils.UtcToLocalDateTime(utcDate).ToString(dateFormat)) .Replace("%level", level) .Replace("%newline", System.Environment.NewLine) .Replace("%userAgent", logRequestBase.UserAgent) .Replace("%userHostAddress", logRequestBase.UserHostAddress) .Replace("%requestId", logRequestBase.RequestId ?? "") .Replace("%url", logRequestBase.Url) .Replace("%logger", logger); // ---------------- JavascriptLogging.RaiseLoggingEvent(loggingEventArgs); // If user wrote event handler that decided not to log the message, return null if (loggingEventArgs.Cancel) { return null; } return loggingEventArgs; }
/// <summary> /// Processes a request with logging info. Unit testable. /// /// Returns log info in easily digestable format. /// </summary> /// <param name="json">JSON sent from client by AjaxAppender</param> /// <param name="serverSideTimeUtc">Current time in UTC</param> /// <param name="jsnlogConfiguration">Contains all config info</param> internal static List<FinalLogData> ProcessLogRequestExec(string json, LogRequestBase logRequestBase, DateTime serverSideTimeUtc, JsnlogConfiguration jsnlogConfiguration) { var logDatas = new List<FinalLogData>(); FinalLogData logData = null; try { LogRequestData logRequestData = LogMessageHelpers.DeserializeJson<LogRequestData>(json); foreach (var logItem in logRequestData.lg) { logData = null; // in case ProcessLogItem throws exception logData = ProcessLogItem(logItem, logRequestBase, serverSideTimeUtc, jsnlogConfiguration); if (logData != null) { logDatas.Add(logData); } } } catch (Exception e) { try { string message = string.Format("Exception: {0}, json: {1}, FinalLogData: {{{2}}}, logRequestBase: {{{3}}}", e, json, logData, logRequestBase); var internalErrorFinalLogData = new FinalLogData(null) { FinalMessage = message, FinalLogger = Constants.JSNLogInternalErrorLoggerName, FinalLevel = Level.ERROR }; logDatas.Add(internalErrorFinalLogData); } catch { } } return logDatas; }
private static FinalLogData ProcessLogItem(LogRequestSingleMsg logItem, LogRequestBase logRequestBase, DateTime serverSideTimeUtc, JsnlogConfiguration jsnlogConfiguration) { string serversideLoggerNameOverride = jsnlogConfiguration.serverSideLogger; string messageFormat = jsnlogConfiguration.serverSideMessageFormat; string levelOverride = jsnlogConfiguration.serverSideLevel; string dateFormat = jsnlogConfiguration.dateFormat; try { LevelUtils.ValidateLevel(levelOverride); } catch (Exception e) { throw new PropertyException("levelOverride", e); } // ---------------- string message = logItem.m; string logger = logItem.n; string level = logItem.l; // note that level as sent by the javascript is a number string entryId = logItem.u; DateTime utcDate = DateTime.UtcNow; string timestampMs = logItem.t; try { double ms = double.Parse(timestampMs); utcDate = DateTime.SpecifyKind((new DateTime(1970, 1, 1)).AddMilliseconds(ms), DateTimeKind.Utc); } catch { } // ---------------- string jsonmessage = ""; if (messageFormat.Contains("%jsonmessage")) { jsonmessage = LogMessageHelpers.EnsureValidJson(message); } // ---------------- var logRequest = new LogRequest(message, logger, level, utcDate, entryId, jsonmessage, logRequestBase); var loggingEventArgs = new LoggingEventArgs(logRequest) { Cancel = false, ServerSideMessageFormat = messageFormat }; // ---------------- if (string.IsNullOrWhiteSpace(logger)) { logger = Constants.RootLoggerNameServerSide; } loggingEventArgs.FinalLogger = serversideLoggerNameOverride ?? logger; string consolidatedLevel = levelOverride ?? level; loggingEventArgs.FinalLevel = LevelUtils.ParseLevel(consolidatedLevel).Value; // ---------------- loggingEventArgs.FinalMessage = messageFormat .Replace("%message", message) .Replace("%entryId", entryId) .Replace("%jsonmessage", jsonmessage) .Replace("%utcDateServer", serverSideTimeUtc.ToString(dateFormat)) .Replace("%utcDate", utcDate.ToString(dateFormat)) .Replace("%dateServer", Utils.UtcToLocalDateTime(serverSideTimeUtc).ToString(dateFormat)) .Replace("%date", Utils.UtcToLocalDateTime(utcDate).ToString(dateFormat)) .Replace("%level", level) .Replace("%newline", System.Environment.NewLine) .Replace("%userAgent", logRequestBase.UserAgent) .Replace("%userHostAddress", logRequestBase.UserHostAddress) .Replace("%requestId", logRequestBase.RequestId ?? "") .Replace("%url", logRequestBase.Url) .Replace("%logger", logger); // ---------------- JavascriptLogging.RaiseLoggingEvent(loggingEventArgs); // If user wrote event handler that decided not to log the message, return null if (loggingEventArgs.Cancel) { return(null); } return(loggingEventArgs); }