diff --git a/logging/Log.cs b/logging/Log.cs index 119bfec..bb9503a 100644 --- a/logging/Log.cs +++ b/logging/Log.cs @@ -1,487 +1,495 @@ -using System; -using System.IO; -using System.Diagnostics; -using System.Collections; -using System.Runtime.CompilerServices; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Reflection; -using System.Collections.Concurrent; -using System.Linq; -using System.Threading; -//using System.Threading.Tasks; - -static public class log -{ - - - [Flags] - public enum LogType - { - Invalid = 0, - Trace = 1, - Debug = 2, - Info = 3, - High = 4, - Warn = 5, - Error = 6, - Fatal = 7, - } - - [Flags] - public enum Endpoints - { - None = 0, - - File = 1 << 0, - Console = 1 << 1, - - All = File | Console, - } - - - public struct LogEvent - { - public DateTime Time; - public LogType LogType; - public string Msg; - public string Path; - public int Line; - public string Member; - - public string Cat; - public object Obj; - - - - static ImmutableDictionary s_shortname = ImmutableDictionary.Empty; - - - public LogEvent( LogType logType, string msg, string path, int line, string member, string cat, object obj ) - { - - //Cache the automatic category names - if( string.IsNullOrEmpty( cat ) ) - { - var pathHash = path.GetHashCode(); - if( s_shortname.TryGetValue( pathHash, out var autoCat ) ) - { - cat = autoCat; - } - else - { - var pathPieces = path.Split( '\\' ); - - if(pathPieces.Length < 2) - { - pathPieces = path.Split('/'); - } - - - var lastDir = pathPieces[ pathPieces.Length - 2 ]; - - ImmutableInterlocked.AddOrUpdate( ref s_shortname, pathHash, lastDir, ( key, value ) => { return lastDir; } ); - - cat = lastDir; - } - } - - Time = DateTime.Now; - LogType = logType; - Msg = msg; - Path = path; - Line = line; - Member = member; - Cat = cat; - Obj = obj; - } - } - - public delegate void Log_delegate( LogEvent evt ); - - - - - static public void create( string filename, Endpoints endpoints ) - { - startup( filename, endpoints ); - } - - - static public void destroy() - { - string msg = "==============================================================================\nLogfile shutdown at " + DateTime.Now.ToString(); - - var evt = CreateLogEvent( LogType.Info, msg, "System", null ); - - s_events.Enqueue( evt ); - - stop(); - } - - - static LogEvent CreateLogEvent( LogType logType, string msg, string cat, object obj, [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) - { - var logEvent = new LogEvent( logType, msg, path, line, member, cat, obj ); - - return logEvent; - } - - static internal ConcurrentQueue s_events = new ConcurrentQueue(); - - static private Thread s_thread; - - /* - static public Log log - { - get - { - return s_log; - } - } - */ - - - - - // Forwards. - static public void fatal( string msg, string cat = "", object obj = null, [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) - { - logBase( msg, LogType.Fatal, path, line, member, cat, obj ); - } - - static public void error( string msg, string cat = "", object obj = null, [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) - { - logBase( msg, LogType.Error, path, line, member, cat, obj ); - } - - static public void warn( string msg, string cat = "", object obj = null, [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) - { - logBase( msg, LogType.Warn, path, line, member, cat, obj ); - } - - static public void high(string msg, string cat = "", object obj = null, [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "") - { - logBase(msg, LogType.High, path, line, member, cat, obj); - } - - static public void info( string msg, string cat = "", object obj = null, [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) - { - logBase( msg, LogType.Info, path, line, member, cat, obj ); - } - - static public void debug( string msg, string cat = "", object obj = null, [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) - { - logBase( msg, LogType.Debug, path, line, member, cat, obj ); - } - - static public void trace( string msg, string cat = "", object obj = null, [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) - { - logBase( msg, LogType.Trace, path, line, member, cat, obj ); - } - - static object s_lock = new object(); - - static public void logBase_old( string msg, LogType type = LogType.Debug, string path = "", int line = -1, string member = "", string cat = "unk", object obj = null ) - { - // @@@@@ TODO Get rid of this lock. - var evt = new LogEvent( type, msg, path, line, member, cat, obj ); - - lock( s_lock ) - { - writeToAll( evt ); - } - } - - static public void logBase( string msg, LogType type = LogType.Debug, string path = "", int line = -1, string member = "", string cat = "unk", object obj = null ) - { - var evt = new LogEvent( type, msg, path, line, member, cat, obj ); - - s_events.Enqueue( evt ); - } - - - static public void logProps( object obj, string header, LogType type = LogType.Debug, string cat = "", string prefix = "", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) - { - var list = refl.GetAllProperties( obj.GetType() ); - - lock( s_lock ) - { - var evt = new LogEvent( type, header, path, line, member, cat, obj ); - //var evt = CreateLogEvent( type, header, cat, obj ); - - //lock( s_log ) - { - //var evt = CreateLogEvent( type, header, cat, obj ); - - s_events.Enqueue( evt ); - - //s_log.writeToAll( evt ); - - foreach( var pi in list ) - { - try - { - var v = pi.GetValue( obj ); - - logBase( $"{prefix}{pi.Name} = {v}", type, path, line, member, cat ); - } - catch( Exception ex ) - { - logBase( $"Exception processing {pi.Name} {ex.Message}", LogType.Error, "log" ); - } - } - - } - } - } - - //This might seem a little odd, but the intent is that usually you wont need to set notExpectedValue. - static public void expected( T value, string falseString, string trueString = "", T notExpectedValue = default( T ) ) - { - - if( !value.Equals( notExpectedValue ) ) - { - log.info( $"Properly got {value}{trueString}" ); - } - else - { - log.warn( $"Got {notExpectedValue} instead of {value}{falseString}" ); - } - } - - static Endpoints s_endpoints = Endpoints.Console; - - static void startup( string filename, Endpoints endpoints ) - { - var start = new ThreadStart( run ); - - s_thread = new Thread( start ); - s_thread.Start(); - - //TODO: Fix this so itll work without a directory. - Directory.CreateDirectory( Path.GetDirectoryName( filename ) ); - - string dir = Path.GetDirectoryName( filename ); - - if( dir.Length > 0 ) - { - Directory.CreateDirectory( dir ); - } - - s_stream = new FileStream( filename, FileMode.Append, FileAccess.Write ); - s_writer = new StreamWriter( s_stream ); - - s_errorStream = new FileStream( filename + ".error", FileMode.Append, FileAccess.Write ); - s_errorWriter = new StreamWriter( s_errorStream ); - - //Debug.Listeners.Add( this ); - - //var evt = CreateLogEvent( LogType.Info, $"startup", "System", null ); - - //s_events.Enqueue( evt ); - - /* - if( (endpoints & Endpoints.Console) == Endpoints.Console ) - { - addDelegate(WriteToConsole); - } - */ - - - - info( $"startup" ); - - } - - static bool s_running = true; - - static void run() - { - while( s_running ) - { - while( s_events.TryDequeue( out var evt ) ) - { - writeToAll( evt ); - } - - // TODO PERF Replace this with a semaphore/mutex - Thread.Sleep( 0 ); - } - } - - static void stop() - { - s_running = false; - - s_writer.Close(); - s_stream.Close(); - - s_errorWriter.Close(); - s_errorStream.Close(); - - } - - static public void addDelegate( Log_delegate cb ) - { - s_delegates.Add( cb ); - } - - public static char getSymbol( LogType type ) - { - switch( type ) - { - case LogType.Trace: - return ' '; - case LogType.Debug: - return ' '; - case LogType.Info: - return ' '; - case LogType.High: - return '+'; - case LogType.Warn: - return '+'; - case LogType.Error: - return '*'; - case LogType.Fatal: - return '*'; - default: - return '?'; - } - } - - private static void setConsoleColor( log.LogEvent evt ) - { - switch( evt.LogType ) - { - case log.LogType.Trace: - Console.ForegroundColor = ConsoleColor.DarkGray; - break; - case log.LogType.Debug: - Console.ForegroundColor = ConsoleColor.Gray; - break; - case log.LogType.Info: - Console.ForegroundColor = ConsoleColor.DarkGreen; - break; - case log.LogType.High: - Console.ForegroundColor = ConsoleColor.Cyan; - break; - case log.LogType.Warn: - Console.ForegroundColor = ConsoleColor.Yellow; - break; - case log.LogType.Error: - Console.ForegroundColor = ConsoleColor.DarkRed; - Console.BackgroundColor = ConsoleColor.DarkGray; - break; - case log.LogType.Fatal: - Console.ForegroundColor = ConsoleColor.Red; - Console.BackgroundColor = ConsoleColor.DarkGray; - break; - } - } - - static public string msgHeader( LogEvent evt ) - { - char sym = getSymbol( evt.LogType ); - - var truncatedCat = evt.Cat.Substring( 0, Math.Min( 8, evt.Cat.Length ) ); - - var msgHdr = string.Format( "{0,-8}{1}| ", truncatedCat, sym ); - - return msgHdr; - } - - static public string msgFrom( LogEvent evt ) - { - var msgHdr = msgHeader( evt ); - - string finalLine = $"{msgHdr}{evt.Msg}"; - - return finalLine; - } - - static private void writeToAll( LogEvent evt ) - { - try - { - // _SHOULDNT_ need this since we lock at the top. - //lock( this ) - { - - var finalLine = msgFrom( evt ); - - //Console.WriteLine( finalMsg ); - //Console.Out.Write( finalMsg ); - - if( (s_endpoints & Endpoints.File) == Endpoints.File ) - { - s_writer.WriteLine( finalLine ); - } - - if( (s_endpoints & Endpoints.Console) == Endpoints.Console ) - { - setConsoleColor( evt ); - Console.WriteLine( finalLine ); - Console.ResetColor(); - } - - - //Debug.WriteLine( finalLine ); - - s_writer.Flush(); - - foreach( Log_delegate cb in s_delegates ) - { - cb( evt ); - } - } - } - catch( Exception ex ) - { - Console.WriteLine( "EXCEPTION DURING LOGGING" ); - Console.WriteLine( "EXCEPTION DURING LOGGING" ); - Console.WriteLine( "EXCEPTION DURING LOGGING" ); - Console.WriteLine( "EXCEPTION DURING LOGGING" ); - Console.WriteLine( "EXCEPTION DURING LOGGING" ); - Console.WriteLine( $"Exception {ex}" ); - - Debug.WriteLine( "EXCEPTION DURING LOGGING" ); - Debug.WriteLine( "EXCEPTION DURING LOGGING" ); - Debug.WriteLine( "EXCEPTION DURING LOGGING" ); - Debug.WriteLine( "EXCEPTION DURING LOGGING" ); - Debug.WriteLine( "EXCEPTION DURING LOGGING" ); - Debug.WriteLine( $"Exception {ex}" ); - } - } - - public static void WriteToConsole(LogEvent evt) - { - char sym = getSymbol(evt.LogType); - - var truncatedCat = evt.Cat.Substring(0, Math.Min(8, evt.Cat.Length)); - - string finalLine = string.Format("{0,-8}{1}| {2}", truncatedCat, sym, evt.Msg); - - Console.WriteLine(finalLine); - } - - - - - private static Stream s_stream; - private static StreamWriter s_writer; - - private static Stream s_errorStream; - private static StreamWriter s_errorWriter; - - private static ArrayList s_delegates = new ArrayList(); - - - - - - - - - -} +using System; +using System.IO; +using System.Diagnostics; +using System.Collections; +using System.Runtime.CompilerServices; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Reflection; +using System.Collections.Concurrent; +using System.Linq; +using System.Threading; +//using System.Threading.Tasks; + +static public class log +{ + + + [Flags] + public enum LogType + { + Invalid = 0, + Trace = 1, + Debug = 2, + Info = 3, + High = 4, + Warn = 5, + Error = 6, + Fatal = 7, + } + + [Flags] + public enum Endpoints + { + None = 0, + + File = 1 << 0, + Console = 1 << 1, + + All = File | Console, + } + + + public struct LogEvent + { + public DateTime Time; + public LogType LogType; + public string Msg; + public string Path; + public int Line; + public string Member; + + public string Cat; + public object Obj; + + + + static ImmutableDictionary s_shortname = ImmutableDictionary.Empty; + + + public LogEvent( LogType logType, string msg, string path, int line, string member, string cat, object obj ) + { + + //Cache the automatic category names + if( string.IsNullOrEmpty( cat ) ) + { + var pathHash = path.GetHashCode(); + if( s_shortname.TryGetValue( pathHash, out var autoCat ) ) + { + cat = autoCat; + } + else + { + var pathPieces = path.Split( '\\' ); + + if(pathPieces.Length < 2) + { + pathPieces = path.Split('/'); + } + + + var lastDir = pathPieces[ pathPieces.Length - 2 ]; + + ImmutableInterlocked.AddOrUpdate( ref s_shortname, pathHash, lastDir, ( key, value ) => { return lastDir; } ); + + cat = lastDir; + } + } + + Time = DateTime.Now; + LogType = logType; + Msg = msg; + Path = path; + Line = line; + Member = member; + Cat = cat; + Obj = obj; + } + } + + public delegate void Log_delegate( LogEvent evt ); + + + + + static public void create( string filename, Endpoints endpoints ) + { + startup( filename, endpoints ); + } + + + static public void destroy() + { + string msg = "==============================================================================\nLogfile shutdown at " + DateTime.Now.ToString(); + + var evt = CreateLogEvent( LogType.Info, msg, "System", null ); + + s_events.Enqueue( evt ); + + stop(); + } + + + static LogEvent CreateLogEvent( LogType logType, string msg, string cat, object obj, [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) + { + var logEvent = new LogEvent( logType, msg, path, line, member, cat, obj ); + + return logEvent; + } + + static internal ConcurrentQueue s_events = new ConcurrentQueue(); + + static private Thread s_thread; + + /* + static public Log log + { + get + { + return s_log; + } + } + */ + + + static public string relativePath( string fullPath ) + { + var cwd = Directory.GetCurrentDirectory(); + + var rel = fullPath.Substring( cwd.Length ); + + return rel; + } + + // Forwards. + static public void fatal( string msg, string cat = "", object obj = null, [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) + { + logBase( msg, LogType.Fatal, path, line, member, cat, obj ); + } + + static public void error( string msg, string cat = "", object obj = null, [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) + { + logBase( msg, LogType.Error, path, line, member, cat, obj ); + } + + static public void warn( string msg, string cat = "", object obj = null, [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) + { + logBase( msg, LogType.Warn, path, line, member, cat, obj ); + } + + static public void high(string msg, string cat = "", object obj = null, [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "") + { + logBase(msg, LogType.High, path, line, member, cat, obj); + } + + static public void info( string msg, string cat = "", object obj = null, + [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) + { + logBase( msg, LogType.Info, path, line, member, cat, obj ); + } + + static public void debug( string msg, string cat = "", object obj = null, [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) + { + logBase( msg, LogType.Debug, path, line, member, cat, obj ); + } + + static public void trace( string msg, string cat = "", object obj = null, [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) + { + logBase( msg, LogType.Trace, path, line, member, cat, obj ); + } + + static object s_lock = new object(); + + static public void logBase_old( string msg, LogType type = LogType.Debug, string path = "", int line = -1, string member = "", string cat = "unk", object obj = null ) + { + // @@@@@ TODO Get rid of this lock. + var evt = new LogEvent( type, msg, path, line, member, cat, obj ); + + lock( s_lock ) + { + writeToAll( evt ); + } + } + + static public void logBase( string msg, LogType type = LogType.Debug, string path = "", int line = -1, string member = "", string cat = "unk", object obj = null ) + { + var evt = new LogEvent( type, msg, path, line, member, cat, obj ); + + s_events.Enqueue( evt ); + } + + + static public void logProps( object obj, string header, LogType type = LogType.Debug, string cat = "", string prefix = "", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) + { + var list = refl.GetAllProperties( obj.GetType() ); + + lock( s_lock ) + { + var evt = new LogEvent( type, header, path, line, member, cat, obj ); + //var evt = CreateLogEvent( type, header, cat, obj ); + + //lock( s_log ) + { + //var evt = CreateLogEvent( type, header, cat, obj ); + + s_events.Enqueue( evt ); + + //s_log.writeToAll( evt ); + + foreach( var pi in list ) + { + try + { + var v = pi.GetValue( obj ); + + logBase( $"{prefix}{pi.Name} = {v}", type, path, line, member, cat ); + } + catch( Exception ex ) + { + logBase( $"Exception processing {pi.Name} {ex.Message}", LogType.Error, "log" ); + } + } + + } + } + } + + //This might seem a little odd, but the intent is that usually you wont need to set notExpectedValue. + static public void expected( T value, string falseString, string trueString = "", T notExpectedValue = default( T ) ) + { + + if( !value.Equals( notExpectedValue ) ) + { + log.info( $"Properly got {value}{trueString}" ); + } + else + { + log.warn( $"Got {notExpectedValue} instead of {value}{falseString}" ); + } + } + + static Endpoints s_endpoints = Endpoints.Console; + + static void startup( string filename, Endpoints endpoints ) + { + var start = new ThreadStart( run ); + + s_thread = new Thread( start ); + s_thread.Start(); + + //TODO: Fix this so itll work without a directory. + Directory.CreateDirectory( Path.GetDirectoryName( filename ) ); + + string dir = Path.GetDirectoryName( filename ); + + if( dir.Length > 0 ) + { + Directory.CreateDirectory( dir ); + } + + s_stream = new FileStream( filename, FileMode.Append, FileAccess.Write ); + s_writer = new StreamWriter( s_stream ); + + s_errorStream = new FileStream( filename + ".error", FileMode.Append, FileAccess.Write ); + s_errorWriter = new StreamWriter( s_errorStream ); + + //Debug.Listeners.Add( this ); + + //var evt = CreateLogEvent( LogType.Info, $"startup", "System", null ); + + //s_events.Enqueue( evt ); + + /* + if( (endpoints & Endpoints.Console) == Endpoints.Console ) + { + addDelegate(WriteToConsole); + } + */ + + + + info( $"startup" ); + + } + + static bool s_running = true; + + static void run() + { + while( s_running ) + { + while( s_events.TryDequeue( out var evt ) ) + { + writeToAll( evt ); + } + + // TODO PERF Replace this with a semaphore/mutex + Thread.Sleep( 0 ); + } + } + + static void stop() + { + s_running = false; + + s_writer.Close(); + s_stream.Close(); + + s_errorWriter.Close(); + s_errorStream.Close(); + + } + + static public void addDelegate( Log_delegate cb ) + { + s_delegates.Add( cb ); + } + + public static char getSymbol( LogType type ) + { + switch( type ) + { + case LogType.Trace: + return ' '; + case LogType.Debug: + return ' '; + case LogType.Info: + return ' '; + case LogType.High: + return '+'; + case LogType.Warn: + return '+'; + case LogType.Error: + return '*'; + case LogType.Fatal: + return '*'; + default: + return '?'; + } + } + + private static void setConsoleColor( log.LogEvent evt ) + { + switch( evt.LogType ) + { + case log.LogType.Trace: + Console.ForegroundColor = ConsoleColor.DarkGray; + break; + case log.LogType.Debug: + Console.ForegroundColor = ConsoleColor.Gray; + break; + case log.LogType.Info: + Console.ForegroundColor = ConsoleColor.DarkGreen; + break; + case log.LogType.High: + Console.ForegroundColor = ConsoleColor.Cyan; + break; + case log.LogType.Warn: + Console.ForegroundColor = ConsoleColor.Yellow; + break; + case log.LogType.Error: + Console.ForegroundColor = ConsoleColor.DarkRed; + Console.BackgroundColor = ConsoleColor.DarkGray; + break; + case log.LogType.Fatal: + Console.ForegroundColor = ConsoleColor.Red; + Console.BackgroundColor = ConsoleColor.DarkGray; + break; + } + } + + static public string msgHeader( LogEvent evt ) + { + char sym = getSymbol( evt.LogType ); + + var truncatedCat = evt.Cat.Substring( 0, Math.Min( 8, evt.Cat.Length ) ); + + var msgHdr = string.Format( "{0,-8}{1}| ", truncatedCat, sym ); + + return msgHdr; + } + + static public string msgFrom( LogEvent evt ) + { + var msgHdr = msgHeader( evt ); + + string finalLine = $"{msgHdr}{evt.Msg}"; + + return finalLine; + } + + static private void writeToAll( LogEvent evt ) + { + try + { + // _SHOULDNT_ need this since we lock at the top. + //lock( this ) + { + + var finalLine = msgFrom( evt ); + + //Console.WriteLine( finalMsg ); + //Console.Out.Write( finalMsg ); + + if( (s_endpoints & Endpoints.File) == Endpoints.File ) + { + s_writer.WriteLine( finalLine ); + } + + if( (s_endpoints & Endpoints.Console) == Endpoints.Console ) + { + setConsoleColor( evt ); + Console.WriteLine( finalLine ); + Console.ResetColor(); + } + + + //Debug.WriteLine( finalLine ); + + s_writer.Flush(); + + foreach( Log_delegate cb in s_delegates ) + { + cb( evt ); + } + } + } + catch( Exception ex ) + { + Console.WriteLine( "EXCEPTION DURING LOGGING" ); + Console.WriteLine( "EXCEPTION DURING LOGGING" ); + Console.WriteLine( "EXCEPTION DURING LOGGING" ); + Console.WriteLine( "EXCEPTION DURING LOGGING" ); + Console.WriteLine( "EXCEPTION DURING LOGGING" ); + Console.WriteLine( $"Exception {ex}" ); + + Debug.WriteLine( "EXCEPTION DURING LOGGING" ); + Debug.WriteLine( "EXCEPTION DURING LOGGING" ); + Debug.WriteLine( "EXCEPTION DURING LOGGING" ); + Debug.WriteLine( "EXCEPTION DURING LOGGING" ); + Debug.WriteLine( "EXCEPTION DURING LOGGING" ); + Debug.WriteLine( $"Exception {ex}" ); + } + } + + public static void WriteToConsole(LogEvent evt) + { + char sym = getSymbol(evt.LogType); + + var truncatedCat = evt.Cat.Substring(0, Math.Min(8, evt.Cat.Length)); + + string finalLine = string.Format("{0,-8}{1}| {2}", truncatedCat, sym, evt.Msg); + + Console.WriteLine(finalLine); + } + + + + + private static Stream s_stream; + private static StreamWriter s_writer; + + private static Stream s_errorStream; + private static StreamWriter s_errorWriter; + + private static ArrayList s_delegates = new ArrayList(); + + + + + + + + + +}