ApplicationLogger.cs
using GenXdev.AsyncSockets.Configuration;
using GenXdev.AsyncSockets.Logging; using GenXdev.Buffers; using GenXdev.Helpers; using Ninject; using System.Diagnostics; using System.Net.Sockets; using System.Text; using GenXdev.Misc; namespace GenXdev.AsyncSockets.Handlers { public class ApplicationLogger : IServiceLogger { static int MAX_LOG_FILE_SIZE = (1024 * 1024 * 10); #if (Logging) static long Sequence = 0; #endif static long LastHour = System.DateTime.UtcNow.Hour; public object SyncRoot { get; private set; } UTF8Encoding utf8 = new UTF8Encoding(false); GenXdev.Additional.HiPerfTimer.NativeMethods StopWatch = new GenXdev.Additional.HiPerfTimer.NativeMethods(true); GenXdev.Additional.HiPerfTimer.NativeMethods StopWatch2 = new GenXdev.Additional.HiPerfTimer.NativeMethods(true); ILoggingConfiguration Config; //#if (Release) // bool LogToConsole = false; //#else bool LogToConsole = #if (Debug) true; #else Process.GetCurrentProcess().ProcessName.ToLowerInvariant().Contains("console") || Process.GetCurrentProcess().ProcessName.ToLowerInvariant().Contains("test"); #endif //#endif System.DateTime LogStartTime = System.DateTime.UtcNow; DynamicBuffer BufferMain; DynamicBuffer BufferDump; public string LogFilePath { get; private set; } [Inject] public ApplicationLogger(IKernel Kernel, ILoggingConfiguration Config, string LogFilePath = null) { // this instance may only be used once OnlyOneInstanceChecker.Check(this.GetType()); this.Config = Config; this.BufferMain = Kernel.Get<DynamicBuffer>(); this.BufferDump = Kernel.Get<DynamicBuffer>(); this.SyncRoot = new object(); this.LogFilePath = Path.Combine(GenXdev.Helpers.Environment.GetApplicationRootDirectory(), Path.GetFileNameWithoutExtension(GenXdev.Helpers.Environment.GetEntryAssemblyLocation()) + ".log"); if (!String.IsNullOrWhiteSpace(LogFilePath)) { if (Path.IsPathRooted(LogFilePath)) { if (Directory.Exists(LogFilePath)) { this.LogFilePath = Path.Combine(LogFilePath, Path.GetFileName(this.LogFilePath)); } else { this.LogFilePath = LogFilePath; } } else { this.LogFilePath = Path.Combine(Path.GetDirectoryName(this.LogFilePath), LogFilePath); } } var directory = Path.GetDirectoryName(this.LogFilePath); if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } else { DeleteOldLogFiles(); } } System.DateTime lastMaintenance = System.DateTime.MinValue; long state = 0; #if (Logging) volatile bool Stopped; #endif public void Stop() { StopWatch.Stop(); #if (Logging) Stopped = true; #endif BufferMain.MoveTo(BufferDump); ProcessLog(false); } public void Start() { StopWatch.Start(); #if (Logging) Stopped = false; #endif } void ProcessLog(object ignore) { System.DateTime logDate; lock (BufferMain.SyncRoot) { logDate = LogStartTime; LogStartTime = System.DateTime.UtcNow; } try { BufferDump.Position = 0; var filename = Path.Combine( Path.GetDirectoryName(LogFilePath), logDate.Year.ToString() + logDate.Month.ToString().PadLeft(2, '0') + logDate.Day.ToString().PadLeft(2, '0') + logDate.Hour.ToString().PadLeft(2, '0') + "_" + Path.GetFileName(LogFilePath) ); using (var fs = new FileStream(filename, FileMode.Append, FileAccess.Write, FileShare.Read)) { BufferDump.Position = 0; BufferDump.WriteToStream(fs); } BufferDump.Reset(); DeleteOldLogFiles(); } catch { } finally { Interlocked.Exchange(ref state, 0); } } private bool LoggingHoursOk(System.DateTime now) { return now.Hour >= Config.LogHoursFrom && now.Hour <= Config.LogHoursUntil; } private bool ShouldDumpLogfile(System.DateTime now) { long prevHour = (now.Hour + 23) % 24; return (BufferMain.Count > MAX_LOG_FILE_SIZE * 2) || (this.StopWatch2.Duration > 60) || Interlocked.CompareExchange(ref LastHour, now.Hour, prevHour) == prevHour; } private void DeleteOldLogFiles() { var now = System.DateTime.UtcNow; now = new System.DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0, System.DateTimeKind.Utc); if (!LoggingHoursOk(now)) return; var logFiles = ( from q in Directory.EnumerateFiles(Path.GetDirectoryName(LogFilePath)) orderby Path.GetFileName(q) descending select q ).ToList<String>(); long spaceUsed = 0; foreach (var logFile in logFiles) { var fn = Path.GetFileName(logFile); if (!logFile.EndsWith("_" + Path.GetFileName(LogFilePath))) continue; try { var date = new System.DateTime( Int32.Parse(fn.Substring(0, 4)), Int32.Parse(fn.Substring(4, 2)), Int32.Parse(fn.Substring(6, 2)), Int32.Parse(fn.Substring(8, 2)), 0, 0, System.DateTimeKind.Utc ); var fileSize = new FileInfo(logFile).Length; var diskQuotaOverrun = spaceUsed + fileSize > Config.MegabytesToKeep * 1000000; var ageOfLogFile = now - date; var fileIsToOld = Config.HoursToKeep > 0 && ageOfLogFile.TotalHours >= Config.HoursToKeep; if (fileIsToOld || diskQuotaOverrun) { if (LogToConsole) { Console.WriteLine("Deleting logfile " + fn + " " + (fileIsToOld ? "to old (" + ageOfLogFile.TotalHours.ToString() + " hours old. " : "") + (diskQuotaOverrun ? "disk quota overrun: " + Math.Round((spaceUsed + fileSize) / 1000000d, 1).ToString() + " MB" : "") ); } GenXdev.Helpers.FileSystem.ForciblyDeleteFile(logFile, false); } else { spaceUsed += fileSize; } } catch (Exception e) { if (LogToConsole) Console.WriteLine("Error processing log file " + fn + " : " + e.Message); } } } public void Log(String Message) { #if (Logging) var now = System.DateTime.UtcNow; if (Stopped || String.IsNullOrWhiteSpace(Message)) return; Message = Message.Trim(); Message = Message[0] + Message.Substring(1); Message = "#" + Interlocked.Increment(ref Sequence).ToString().PadLeft(10) + " | " + now.ToString() + " | " + Message + "\r\n"; if (LoggingHoursOk(now)) lock (BufferMain.SyncRoot) { if (ShouldDumpLogfile(now)) { if (Interlocked.CompareExchange(ref state, 1, 0) == 0) { BufferDump.Reset(); BufferMain.MoveTo(BufferDump); this.StopWatch2.Reset(); if (!ThreadPool.QueueUserWorkItem(ProcessLog)) { ProcessLog(null); } } } BufferMain.Add(utf8.GetBytes(Message)); } #if (DEBUG) System.Diagnostics.Debug.Write(Message); #endif if (LogToConsole) { int i = Message.IndexOf(" =>"); if (i > 0) { Console.WriteLine(Message.Substring(0, i)); } else { Console.Write(Message); } } #endif } public void LogException(Exception e, String Message = "") { #if (Logging) if (!(LogToConsole || Config.LoggingEnabled)) return; try { Message = (Message == null ? "" : Message) + "\r\n" + e.StackTrace; } catch { } try { if (((int)Config.LogLevel & (int)ServiceLogLevel.LongExceptions) > 0) { Log(StopWatch.Duration.ToString("0.00000").PadLeft(10) + " | " + (String.IsNullOrWhiteSpace(Message) ? "" : Message + " | ") + e.ToLogString(Message)); } else if (((int)Config.LogLevel & (int)ServiceLogLevel.ShortExceptions) > 0) { Log(StopWatch.Duration.ToString("0.00000").PadLeft(10) + " | " + (String.IsNullOrWhiteSpace(Message) ? "" : Message + " | ") + e.Message); } } catch { } #endif } public void LogSocketHandlerException(Exception e, SocketAsyncEventArgs saea, String Message = "") { #if (Logging) if (!(LogToConsole || Config.LoggingEnabled)) return; try { SocketHandlerBase controller = (SocketHandlerBase)saea.Handler(); string cn = controller.GetType().ToString(); int i = cn.LastIndexOf('.'); if ((i > 0) && (i < cn.Length - 1)) cn = cn.Substring(i + 1); if (controller != null) { cn += "#" + controller.UniqueSocketId; } if (((int)Config.LogLevel & (int)ServiceLogLevel.LongExceptions) > 0) { Log(StopWatch.Duration.ToString("0.00000").PadLeft(10) + " | " + cn + " | " + (String.IsNullOrWhiteSpace(Message) ? "" : Message + " | ") + e.ToLogString(Message)); } else if (((int)Config.LogLevel & (int)ServiceLogLevel.ShortExceptions) > 0) { Log(StopWatch.Duration.ToString("0.00000").PadLeft(10) + " | " + cn + " | " + (String.IsNullOrWhiteSpace(Message) ? "" : Message + " | ") + e.Message); } } catch { } #endif } public void LogPerformanceStatusMessage(String Message) { #if (Logging) if (!(LogToConsole || Config.LoggingEnabled)) return; try { if (((int)Config.LogLevel & (int)ServiceLogLevel.Performance) > 0) { Log(Message); } } catch { } #endif } public void LogPerformanceStatusMessage(LogCallback callback) { #if (Logging) if (!(LogToConsole || Config.LoggingEnabled)) return; try { if (((int)Config.LogLevel & (int)ServiceLogLevel.Performance) > 0) { Log(callback()); } } catch { } #endif } public void LogSocketFlowMessage(SocketAsyncEventArgs saea, String Message) { #if (Logging) if (!(LogToConsole || Config.LoggingEnabled)) return; try { if (((int)Config.LogLevel & (int)ServiceLogLevel.SocketFlow) > 0) { SocketHandlerBase controller = (SocketHandlerBase)saea.Handler(); string cn = ""; if (controller != null) { cn = controller.GetType().ToString(); int i = cn.LastIndexOf('.'); if ((i > 0) && (i < cn.Length - 1)) cn = cn.Substring(i + 1); cn += " | h_" + controller.UniqueSocketId; } Log(StopWatch.Duration.ToString("0.00000").PadLeft(10) + " | " + cn + " | " + Message); } } catch { } #endif } public void LogSocketFlowMessage(SocketAsyncEventArgs saea, LogCallback callback) { #if (Logging) if (!(LogToConsole || Config.LoggingEnabled)) return; try { if (((int)Config.LogLevel & (int)ServiceLogLevel.SocketFlow) > 0) { SocketHandlerBase controller = (SocketHandlerBase)saea.Handler(); string cn = ""; if (controller != null) { cn = controller.GetType().ToString(); int i = cn.LastIndexOf('.'); if ((i > 0) && (i < cn.Length - 1)) cn = cn.Substring(i + 1); cn += " | h_" + controller.UniqueSocketId; } Log(StopWatch.Duration.ToString("0.00000").PadLeft(10) + " | " + cn + " | " + callback()); } } catch { } #endif } public void LogHandlerFlowMessage(SocketAsyncEventArgs saea, String Message) { #if (Logging) if (!(LogToConsole || Config.LoggingEnabled)) return; try { if (((int)Config.LogLevel & (int)ServiceLogLevel.HandlerFlow) > 0) { SocketHandlerBase controller = (SocketHandlerBase)saea.Handler(); string cn = ""; if (controller != null) { cn = controller.GetType().ToString(); int i = cn.LastIndexOf('.'); if ((i > 0) && (i < cn.Length - 1)) cn = cn.Substring(i + 1); cn += " | h_" + controller.UniqueSocketId; } Log(StopWatch.Duration.ToString("0.00000").PadLeft(10) + " | " + cn + " | " + Message); } } catch { } #endif } public void LogHandlerFlowMessage(SocketAsyncEventArgs saea, LogCallback callback) { #if (Logging) if (!(LogToConsole || Config.LoggingEnabled)) return; try { if (((int)Config.LogLevel & (int)ServiceLogLevel.HandlerFlow) > 0) { SocketHandlerBase controller = (SocketHandlerBase)saea.Handler(); string cn = ""; if (controller != null) { cn = controller.GetType().ToString(); int i = cn.LastIndexOf('.'); if ((i > 0) && (i < cn.Length - 1)) cn = cn.Substring(i + 1); cn += " | h_" + controller.UniqueSocketId; } Log(StopWatch.Duration.ToString("0.00000").PadLeft(10) + " | " + cn + " | " + callback()); } } catch { } #endif } public void LogProgramFlowInfoMessage(String Message) { #if (Logging) if (!(LogToConsole || Config.LoggingEnabled)) return; try { if (((int)Config.LogLevel & (int)ServiceLogLevel.ProgramFlow) > 0) { Log(StopWatch.Duration.ToString("0.00000").PadLeft(10) + " | " + Message); } } catch { } #endif } public void LogProgramFlowInfoMessage(LogCallback callback) { #if (Logging) if (!(LogToConsole || Config.LoggingEnabled)) return; try { if (((int)Config.LogLevel & (int)ServiceLogLevel.ProgramFlow) > 0) { Log(StopWatch.Duration.ToString("0.00000").PadLeft(10) + " | " + callback()); } } catch { } #endif } } } |