diff --git a/Log.cs b/Log.cs index 0ae408a..b8391f0 100644 --- a/Log.cs +++ b/Log.cs @@ -1,399 +1,453 @@ -using System; -using System.IO; -using System.Diagnostics; -using System.Collections; -using System.Runtime.CompilerServices; -using System.Collections.Generic; -using System.Reflection; -//using System.Threading.Tasks; - -namespace lib -{ - - - - [Flags] - public enum LogTypeNew - { - Invalid = 0, - - // Frequency - FrequencyBase = 1, - FrequencyBits = 2, - FrequencyMask = ( ( 1 << FrequencyBits ) - 1 ) << FrequencyBase, - - Detail = 0b01 << FrequencyBase, - Normal = 0b10 << FrequencyBase, - Overview = 0b11 << FrequencyBase, - - // Type - TypeBase = FrequencyBase + FrequencyBits, - TypeBits = 3, - TypeMask = ( ( 1 << TypeBits ) - 1 ) << TypeBase, - - Startup = 0b001 << TypeBase, - Running = 0b010 << TypeBase, - Shutdown = 0b011 << TypeBase, - Error = 0b101 << TypeBase, - - } - - - [Flags] - public enum LogType - { - Invalid = 0, - Trace = 1, - Debug = 2, - Info = 3, - Warn = 4, - Error = 5, - Fatal = 6, - } - - public struct LogEvent - { - public DateTime Time; - public LogType LogType; - public string Cat; - public string Msg; - public object Obj; - - public LogEvent( LogType logType, string cat, string msg, object obj ) - { - Time = DateTime.Now; - LogType = logType; - Cat = cat; - Msg = msg; - Obj = obj; - } - } - - public delegate void Log_delegate( LogEvent evt ); - - - public class Log : TraceListener - { - static public void create( string filename ) - { - s_log = new Log( filename ); - } - - static public void destroy() - { - string msg = "==============================================================================\nLogfile shutdown at " + DateTime.Now.ToString(); - - var evt = new LogEvent( LogType.Info, "System", msg, null ); - - s_log.writeToAll( evt ); - - s_log.stop(); - - s_log = null; - } - - static public Log s_log; - - /* - static public Log log - { - get - { - return s_log; - } - } - */ - - // Forwards. - static public void fatal( string msg, string cat = "", object obj = null ) - { - log( msg, LogType.Fatal, cat, obj ); - } - - static public void error( string msg, string cat = "", object obj = null ) - { - log( msg, LogType.Error, cat, obj ); - } - - static public void warn( string msg, string cat = "", object obj = null ) - { - log( msg, LogType.Warn, cat, obj ); - } - - static public void info( string msg, string cat = "", object obj = null ) - { - log( msg, LogType.Info, cat, obj ); - } - - static public void debug( string msg, string cat = "", object obj = null ) - { - log( msg, LogType.Debug, cat, obj ); - } - - static public void trace( string msg, string cat = "", object obj = null ) - { - log( msg, LogType.Trace, cat, obj ); - } - - static public void log( string msg, LogType type = LogType.Debug, string cat = "unk", object obj = null ) - { - lock( s_log ) - { - var evt = new LogEvent( type, cat, msg, obj ); - - s_log.writeToAll( evt ); - } - } - - - static public void logProps( object obj, string header, LogType type = LogType.Debug, string cat = "", string prefix = "" ) - { - var list = scr.GetAllProperties( obj.GetType() ); - - lock( s_log ) - { - var evt = new LogEvent( type, cat, header, obj ); - - s_log.writeToAll( evt ); - - foreach( var pi in list ) - { - try - { - var v = pi.GetValue( obj ); - - log( $"{prefix}{pi.Name} = {v}", type, cat ); - } - catch( Exception ex ) - { - log( $"Exception processing {pi.Name} {ex.Message}", type, cat ); - } - } - - } - } - - //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 ) ) - { - lib.Log.info( $"Properly got {value}{trueString}" ); - } - else - { - lib.Log.warn( $"Got {notExpectedValue} instead of {value}{falseString}" ); - } - } - - - private Log( string filename ) - { - //TODO: Fix this so itll work without a directory. - Directory.CreateDirectory( Path.GetDirectoryName( filename ) ); - - m_stream = new FileStream( filename, FileMode.Append, FileAccess.Write ); - m_writer = new StreamWriter( m_stream ); - - m_errorStream = new FileStream( filename + ".error", FileMode.Append, FileAccess.Write ); - m_errorWriter = new StreamWriter( m_errorStream ); - - //Debug.Listeners.Add( this ); - - string msg = "\n==============================================================================\nLogfile " + filename + " startup at " + DateTime.Now.ToString(); - - var evt = new LogEvent( LogType.Info, "System", msg, null ); - - writeToAll( evt ); - } - - public override void Write( string msg ) - { - WriteLine( msg ); - } - - public override void WriteLine( string msg ) - { - error( msg ); - //base.WriteLine( msg ); - } - - void stop() - { - m_writer.Close(); - m_stream.Close(); - - m_errorWriter.Close(); - m_errorStream.Close(); - } - - public void addDelegate( Log_delegate cb ) - { - m_delegates.Add( cb ); - } - - /* - private void writeFileAndLine( StackTrace st ) - { - StackFrame frame = st.GetFrame( 1 ); - - string srcFile = frame.GetFileName(); - string srcLine = frame.GetFileLineNumber().Tostring(); - - Console.WriteLine( $"{srcFile} ({srcLine}):" ); - } - - private void writeStack( StackTrace st ) - { - for( int i=0; i { - StackTrace st = new StackTrace( true ); - - writeStack( st ); - - string msgPrint = msg; - - if( args.Length > 0 ) - { - msgPrint = string.Format( msg, args ); - } - - writeToAll( "error", "log", msgPrint ); - //} ); - } - private void warn_i( string msg, object obj ) - { - //var t = Task.Run( () => { - StackTrace st = new StackTrace( true ); - - writeStack( st ); - - string msgPrint = msg; - - if( args.Length > 0 ) - { - msgPrint = string.Format( msg, args ); - } - - writeToAll( "warn", "log", msgPrint ); - //}); - } - private void info_i( string msg, object obj ) - { - //var t = Task.Run( () => { - StackTrace st = new StackTrace( true ); - - string msgPrint = msg; - - if( args.Length > 0 ) - { - msgPrint = string.Format( msg, args ); - } - - writeToAll( "info", "log", msgPrint ); - //} ); - } - */ - - private Stream m_stream; - private StreamWriter m_writer; - - private Stream m_errorStream; - private StreamWriter m_errorWriter; - - private ArrayList m_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.Threading.Tasks; + +namespace lib +{ + + + + [Flags] + public enum LogTypeNew + { + Invalid = 0, + + // Frequency + FrequencyBase = 1, + FrequencyBits = 2, + FrequencyMask = ( ( 1 << FrequencyBits ) - 1 ) << FrequencyBase, + + Detail = 0b01 << FrequencyBase, + Normal = 0b10 << FrequencyBase, + Overview = 0b11 << FrequencyBase, + + // Type + TypeBase = FrequencyBase + FrequencyBits, + TypeBits = 3, + TypeMask = ( ( 1 << TypeBits ) - 1 ) << TypeBase, + + Startup = 0b001 << TypeBase, + Running = 0b010 << TypeBase, + Shutdown = 0b011 << TypeBase, + Error = 0b101 << TypeBase, + + } + + + [Flags] + public enum LogType + { + Invalid = 0, + Trace = 1, + Debug = 2, + Info = 3, + High = 4, + Warn = 5, + Error = 6, + Fatal = 7, + } + + 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 m_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 ) ) + { + if( m_shortname.TryGetValue( path, out var autoCat ) ) + { + cat = autoCat; + } + else + { + var pathPieces = path.Split('\\'); + + var lastDir = pathPieces[pathPieces.Length - 1]; + + ImmutableInterlocked.AddOrUpdate( ref m_shortname, path, 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 ); + + + + public class Log : TraceListener + { + static public void create( string filename ) + { + s_log = new Log( filename ); + } + + + static public void destroy() + { + string msg = "==============================================================================\nLogfile shutdown at " + DateTime.Now.ToString(); + + var evt = CreateLogEvent( LogType.Info, msg, "System", null ); + + s_log.writeToAll( evt ); + + s_log.stop(); + + s_log = null; + } + + static public Log s_log; + + /* + static public Log log + { + get + { + return s_log; + } + } + */ + + + 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; + } + + + + + // Forwards. + static public void fatal( string msg, string cat = "", object obj = null, [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) + { + log( 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 = "" ) + { + log( 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 = "" ) + { + log( msg, LogType.Warn, 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 = "" ) + { + log( msg, LogType.Info, 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 = "" ) + { + log( msg, LogType.High, 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 = "" ) + { + log( 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 = "" ) + { + log( msg, LogType.Trace, path, line, member, cat, obj ); + } + + static public void log( 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_log ) + { + s_log.writeToAll( evt ); + } + } + + static public void logProps( object obj, string header, LogType type = LogType.Debug, string cat = "", string prefix = "" ) + { + var list = scr.GetAllProperties( obj.GetType() ); + + lock( s_log ) + { + var evt = CreateLogEvent( type, header, cat, obj ); + + s_log.writeToAll( evt ); + + foreach( var pi in list ) + { + try + { + var v = pi.GetValue( obj ); + + log( $"{prefix}{pi.Name} = {v}", type, cat ); + } + catch( Exception ex ) + { + log( $"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 ) ) + { + lib.Log.info( $"Properly got {value}{trueString}" ); + } + else + { + lib.Log.warn( $"Got {notExpectedValue} instead of {value}{falseString}" ); + } + } + + + private Log( string filename ) + { + //TODO: Fix this so itll work without a directory. + Directory.CreateDirectory( Path.GetDirectoryName( filename ) ); + + m_stream = new FileStream( filename, FileMode.Append, FileAccess.Write ); + m_writer = new StreamWriter( m_stream ); + + m_errorStream = new FileStream( filename + ".error", FileMode.Append, FileAccess.Write ); + m_errorWriter = new StreamWriter( m_errorStream ); + + //Debug.Listeners.Add( this ); + + string msg = "\n==============================================================================\nLogfile " + filename + " startup at " + DateTime.Now.ToString(); + + var evt = CreateLogEvent( LogType.Info, msg, "System", null ); + + writeToAll( evt ); + } + + public override void Write( string msg ) + { + WriteLine( msg ); + } + + public override void WriteLine( string msg ) + { + error( msg ); + //base.WriteLine( msg ); + } + + void stop() + { + m_writer.Close(); + m_stream.Close(); + + m_errorWriter.Close(); + m_errorStream.Close(); + } + + public void addDelegate( Log_delegate cb ) + { + m_delegates.Add( cb ); + } + + /* + private void writeFileAndLine( StackTrace st ) + { + StackFrame frame = st.GetFrame( 1 ); + + string srcFile = frame.GetFileName(); + string srcLine = frame.GetFileLineNumber().Tostring(); + + Console.WriteLine( $"{srcFile} ({srcLine}):" ); + } + + private void writeStack( StackTrace st ) + { + for( int i=0; i { + StackTrace st = new StackTrace( true ); + + writeStack( st ); + + string msgPrint = msg; + + if( args.Length > 0 ) + { + msgPrint = string.Format( msg, args ); + } + + writeToAll( "error", "log", msgPrint ); + //} ); + } + private void warn_i( string msg, object obj ) + { + //var t = Task.Run( () => { + StackTrace st = new StackTrace( true ); + + writeStack( st ); + + string msgPrint = msg; + + if( args.Length > 0 ) + { + msgPrint = string.Format( msg, args ); + } + + writeToAll( "warn", "log", msgPrint ); + //}); + } + private void info_i( string msg, object obj ) + { + //var t = Task.Run( () => { + StackTrace st = new StackTrace( true ); + + string msgPrint = msg; + + if( args.Length > 0 ) + { + msgPrint = string.Format( msg, args ); + } + + writeToAll( "info", "log", msgPrint ); + //} ); + } + */ + + private Stream m_stream; + private StreamWriter m_writer; + + private Stream m_errorStream; + private StreamWriter m_errorWriter; + + private ArrayList m_delegates = new ArrayList(); + } + + + + + + + + + +}