diff --git a/Log.cs b/Log.cs index 6450484969be97f36db8c3bc20943c313ad3ac88..96fb79c06d13238c52172545a24f87ec70a1797e 100644 --- a/Log.cs +++ b/Log.cs @@ -1,55 +1,99 @@ using System; using System.Collections.Generic; using System.IO; +using System.Text.RegularExpressions; using Newtonsoft.Json; namespace FIORest { - public enum LogLevel - { - Info, - Warning, - Error - } - - public static class Logger - { - public static void Log(string message) - { - Log(LogLevel.Info, message); - } - - public static void Log(LogLevel logLevel, string message) - { - switch(logLevel) - { - case LogLevel.Info: - Console.Out.WriteLine($"\t{message}"); - break; - case LogLevel.Warning: - Console.Error.WriteLine($"\tWARNING: {message}"); - break; - case LogLevel.Error: - Console.Error.WriteLine($"\tERROR: {message}"); - break; - } - } - - public static void LogBadRequest(string body, string UserName, Dictionary ExData) - { - if (String.IsNullOrWhiteSpace(UserName)) - { - UserName = "UnknownUserName"; - } - - Directory.CreateDirectory(Globals.Opts.BadRequestPath); - string UserBadRequestsPath = Path.Combine(Globals.Opts.BadRequestPath, UserName); - Directory.CreateDirectory(UserBadRequestsPath); - string TimeBadRequestPath = Path.Combine(UserBadRequestsPath, $"{DateTime.Now.Ticks}-{Path.GetRandomFileName()}"); - Directory.CreateDirectory(TimeBadRequestPath); - File.WriteAllText(Path.Combine(TimeBadRequestPath, "ExData.json"), JsonConvert.SerializeObject(ExData, Formatting.Indented)); - File.WriteAllText(Path.Combine(TimeBadRequestPath, "Request.json"), body); - } - } + public enum LogLevel + { + Info, + Warning, + Error + } + + public static class Logger + { + public static void Log(string message) + { + Log(LogLevel.Info, message); + } + + public static void Log(LogLevel logLevel, string message) + { + switch (logLevel) + { + case LogLevel.Info: + Console.Out.WriteLine($"\t{message}"); + break; + case LogLevel.Warning: + Console.Error.WriteLine($"\tWARNING: {message}"); + break; + case LogLevel.Error: + Console.Error.WriteLine($"\tERROR: {message}"); + break; + } + } + + private const string StackFramePattern = @"\sFIORest\..*\sin\s.+[/\\](?(.+))\.cs:line\s(?\d+)$"; + private static Regex StackFrameRegex = new Regex(StackFramePattern, RegexOptions.Compiled); + + public static void LogBadRequest(string body, string UserName, Dictionary ExData) + { + if (!ExData.ContainsKey("Message") || !ExData.ContainsKey("Type") || !ExData.ContainsKey("StackTrace")) + { + return; + } + + if (String.IsNullOrWhiteSpace(UserName)) + { + UserName = "UnknownUserName"; + } + + string Message = ExData["Message"]; + string StackTrace = ExData["StackTrace"]; + + string RootPathFolder = null; + if (StackTrace != null) + { + // Try to find a FIORest stackframe. + var StackFrames = StackTrace.Split(new String[] { "\r\n", "\\r\\n" }, StringSplitOptions.RemoveEmptyEntries); + foreach(var StackFrame in StackFrames) + { + MatchCollection mc = StackFrameRegex.Matches(StackFrame); + if (mc.Count == 1) + { + RootPathFolder = $"{mc[0].Groups["File"]}_cs_{mc[0].Groups["LineNumber"]}"; + break; + } + } + } + + if (RootPathFolder == null) + { + // Fallback to Message HashCode + RootPathFolder = Message.GetHashCode().ToString(); + } + + string FullBadRequestPath = Path.GetFullPath(Globals.Opts.BadRequestPath); + Directory.CreateDirectory(FullBadRequestPath); + + // Create the directory for the directory for this BadRequest grouping if it doesn't exist. Also add a Message.txt file to the root of it + string RequestRootPath = Path.Combine(FullBadRequestPath, RootPathFolder); + if (!Directory.Exists(RequestRootPath)) + { + Directory.CreateDirectory(RequestRootPath); + File.WriteAllText(Path.Combine(RequestRootPath, "Message.txt"), Message); + } + + // Now create the individual BadRequest directory + DateTime now = DateTime.UtcNow; + string ThisBadRequestPath = Path.Combine(RequestRootPath, $"{now.Year}-{now.Month}-{now.Day}-{now.Hour}-{now.Minute}-{now.Second}-{now.Millisecond}-{UserName}"); + Directory.CreateDirectory(ThisBadRequestPath); + File.WriteAllText(Path.Combine(ThisBadRequestPath, "ExData.json"), JsonConvert.SerializeObject(ExData, Formatting.Indented)); + File.WriteAllText(Path.Combine(ThisBadRequestPath, "Request.json"), body); + } + } }