diff --git a/cfg/Config.cs b/cfg/Config.cs index 61b399f..d18c0d6 100644 --- a/cfg/Config.cs +++ b/cfg/Config.cs @@ -11,6 +11,25 @@ x) */ + + +static public class cfg +{ + + + static public T load( string filename ) where T : lib.Config + { + return (T)lib.ConfigBase.load( filename ); + } + + static public lib.Config load( string filename ) + { + return lib.ConfigBase.load( filename, null ); + } + + +} + namespace lib { @@ -184,6 +203,8 @@ namespace lib internal static ConfigCfg s_cfg = new(); + public static ConfigCfg Cfg => s_cfg; + static public void startup( string filename ) { res.Mgr.Register( ConfigBase.load ); diff --git a/logging/Log.cs b/logging/Log.cs index e1f1a5f..cf79c53 100644 --- a/logging/Log.cs +++ b/logging/Log.cs @@ -54,36 +54,36 @@ public record struct Value( T _val, string _exp = "" ) public struct SourceLoc { readonly string _reason = ""; - readonly string _dbgName = ""; + readonly string _dbgMethod = ""; readonly string _dbgPath = ""; readonly string _dbgFile = ""; readonly int _dbgLine = -1; - public SourceLoc( string reason, string dbgName, string dbgPath, int dbgLine ) + public SourceLoc( string reason, string dbgMethod, string dbgPath, int dbgLine ) { _reason = reason; - _dbgName = dbgName; + _dbgMethod = dbgMethod; _dbgPath = dbgPath; _dbgLine = dbgLine; _dbgFile = log.whatFile( dbgPath ); } - public string ToLogString() => $"{_dbgFile}.{_dbgName}"; + public string ToLogString() => $"{_dbgFile}.{_dbgMethod}"; public string Log => ToLogString(); public string File => _dbgFile; - public string Method => _dbgName; + public string Method => _dbgMethod; static public SourceLoc Record( string reason = "", - [CallerMemberName] string dbgName = "", + [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = 0 ) { - return new SourceLoc( reason, dbgName, dbgPath, dbgLine ); + return new SourceLoc( reason, dbgMethod, dbgPath, dbgLine ); } @@ -154,7 +154,7 @@ static public class log #endregion // CLR Logging [Flags] - public enum LogType + public enum Levels { Invalid = 0, Trace = 1, @@ -186,7 +186,7 @@ static public class log public struct LogEvent { public DateTime Time; - public LogType LogType; + public Levels Levels; public string Msg; public string Path; public int Line; @@ -199,7 +199,7 @@ static public class log static ImmutableDictionary s_shortname = ImmutableDictionary.Empty; - public LogEvent( LogType logType, string msg, string dbgPath, int dbgLine, string dbgMethod, string cat, string exp, SourceLoc? loc ) + public LogEvent( Levels level, string msg, string dbgPath, int dbgLine, string dbgMethod, string cat, string exp, SourceLoc? loc ) { //Cache the automatic category names @@ -229,7 +229,7 @@ static public class log } Time = DateTime.Now; - LogType = logType; + Levels = level; Msg = msg; Path = dbgPath; Line = dbgLine; @@ -240,9 +240,9 @@ static public class log } } - static LogEvent CreateLogEvent( LogType logType, string msg, string cat, SourceLoc? loc, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", string exp = "" ) + static LogEvent CreateLogEvent( Levels level, string msg, string cat, SourceLoc? loc, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", string exp = "" ) { - var logEvent = new LogEvent( logType, msg, dbgPath, dbgLine, dbgMethod, cat, exp, loc ); + var logEvent = new LogEvent( level, msg, dbgPath, dbgLine, dbgMethod, cat, exp, loc ); return logEvent; } @@ -261,7 +261,7 @@ static public class log static public void shutdown() { string msg = "==============================================================================\nLogfile shutdown at " + DateTime.Now.ToString(); - var evt = CreateLogEvent( LogType.Info, msg, "System", null ); + var evt = CreateLogEvent( Levels.Info, msg, "System", null ); s_events.Add( evt ); // Use Add instead of Enqueue stop(); @@ -277,8 +277,8 @@ static public class log static ImmutableDictionary s_files = ImmutableDictionary.Empty; #region Util - static public SourceLoc loc( [CallerMemberName] string dbgName = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) - => new SourceLoc( "", dbgName, dbgPath, dbgLine ); + static public SourceLoc loc( [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) + => new SourceLoc( "", dbgMethod, dbgPath, dbgLine ); static public string whatFile( string path, bool incExtension = false ) @@ -336,11 +336,11 @@ static public class log #region Forwards - static public T call( Func func, [CallerMemberName] string dbgName = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerArgumentExpression( "func" )] string dbgExp = "" ) + static public T call( Func func, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerArgumentExpression( "func" )] string dbgExp = "" ) { - log.info( $"Fn {dbgExp}", "", null, dbgPath, dbgLine, dbgName, dbgExp ); + log.info( $"Fn {dbgExp}", "", null, dbgPath, dbgLine, dbgMethod, dbgExp ); var val = func(); - log.info( $"| Got {val}", "", null, dbgPath, dbgLine, dbgName, dbgExp ); + log.info( $"| Got {val}", "", null, dbgPath, dbgLine, dbgMethod, dbgExp ); return val; } @@ -349,38 +349,38 @@ static public class log [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" ) */ - static public T var( T val, [CallerMemberName] string dbgName = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerArgumentExpression( "val" )] string dbgExp = "" ) + static public T var( T val, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerArgumentExpression( "val" )] string dbgExp = "" ) { - log.info( $"{dbgExp} = {val}", "", null, dbgPath, dbgLine, dbgName, dbgExp ); + log.info( $"{dbgExp} = {val}", "", null, dbgPath, dbgLine, dbgMethod, dbgExp ); return val; } - static public void operations( Action val, [CallerMemberName] string dbgName = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerArgumentExpression( "val" )] string dbgExp = "" ) + static public void operations( Action val, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerArgumentExpression( "val" )] string dbgExp = "" ) { - log.info( $"{dbgExp} = {val}", "", null, dbgPath, dbgLine, dbgName, dbgExp ); + log.info( $"{dbgExp} = {val}", "", null, dbgPath, dbgLine, dbgMethod, dbgExp ); val(); } - static public T operations( Func val, [CallerMemberName] string dbgName = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerArgumentExpression( "val" )] string dbgExp = "" ) + static public T operations( Func val, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerArgumentExpression( "val" )] string dbgExp = "" ) { - log.info( $"{dbgExp} = {val}", "", null, dbgPath, dbgLine, dbgName, dbgExp ); + log.info( $"{dbgExp} = {val}", "", null, dbgPath, dbgLine, dbgMethod, dbgExp ); var v = val(); return v; } - static public void operations( string prefix, Action val, [CallerMemberName] string dbgName = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerArgumentExpression( "val" )] string dbgExp = "" ) + static public void operations( string prefix, Action val, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerArgumentExpression( "val" )] string dbgExp = "" ) { - log.info( $"{prefix} {dbgExp} = {val}", "", null, dbgPath, dbgLine, dbgName, dbgExp ); + log.info( $"{prefix} {dbgExp} = {val}", "", null, dbgPath, dbgLine, dbgMethod, dbgExp ); val(); } - static public T operations( string prefix, Func val, [CallerMemberName] string dbgName = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerArgumentExpression( "val" )] string dbgExp = "" ) + static public T operations( string prefix, Func val, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerArgumentExpression( "val" )] string dbgExp = "" ) { - log.info( $"{prefix} {dbgExp} = {val}", "", null, dbgPath, dbgLine, dbgName, dbgExp ); + log.info( $"{prefix} {dbgExp} = {val}", "", null, dbgPath, dbgLine, dbgMethod, dbgExp ); var v = val(); @@ -388,48 +388,48 @@ static public class log } [StackTraceHidden] - static public void call( Action func, [CallerMemberName] string dbgName = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerArgumentExpression( "func" )] string dbgExp = "" ) + static public void call( Action func, [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerArgumentExpression( "func" )] string dbgExp = "" ) { - log.info( $"{dbgExp}", "", null, dbgPath, dbgLine, dbgName, dbgExp ); + log.info( $"{dbgExp}", "", null, dbgPath, dbgLine, dbgMethod, dbgExp ); func(); - log.info( $"| Done", "", null, dbgPath, dbgLine, dbgName, dbgExp ); + log.info( $"| Done", "", null, dbgPath, dbgLine, dbgMethod, dbgExp ); } [StackTraceHidden] static public void info( string msg, string cat = "", SourceLoc? loc = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" ) { - logBase( msg, LogType.Info, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); + logBase( msg, Levels.Info, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); } [StackTraceHidden] static public void debug( string msg, string cat = "", SourceLoc? loc = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" ) { - logBase( msg, LogType.Debug, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); + logBase( msg, Levels.Debug, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); } [StackTraceHidden] static public void trace( string msg, string cat = "", SourceLoc? loc = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" ) { - logBase( msg, LogType.Trace, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); + logBase( msg, Levels.Trace, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); } [StackTraceHidden] static public void warn( string msg, string cat = "", SourceLoc? loc = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" ) { - logBase( msg, LogType.Warn, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); + logBase( msg, Levels.Warn, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); } [StackTraceHidden] static public void high( string msg, string cat = "", SourceLoc? loc = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" ) { - logBase( msg, LogType.High, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); + logBase( msg, Levels.High, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); } [StackTraceHidden] static public void error( string msg, string cat = "", SourceLoc? loc = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" ) { - logBase( $"{dbgMethod}: {msg}", LogType.Error, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); + logBase( $"{dbgMethod}: {msg}", Levels.Error, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); } @@ -437,7 +437,7 @@ static public class log // VERY SPECIALIZED ONLY USE IF YOU KNOW WHAT YOU ARE DOING static public void row_internal( string msg, string cat = "", SourceLoc? loc = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" ) { - logBase( msg, LogType.Raw, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); + logBase( msg, Levels.Raw, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); } @@ -446,10 +446,10 @@ static public class log { logBase( $"*******************************************************************************", - LogType.Raw, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); - logBase( $"{dbgMethod}: {msg} | Caught At:", LogType.Error, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); + Levels.Raw, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); + logBase( $"{dbgMethod}: {msg} | Caught At:", Levels.Error, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); logBase( $"{dbgPath}({dbgLine}): {dbgMethod}: ---------------", - LogType.Raw, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); + Levels.Raw, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); LogStackTrace( ex ); } @@ -458,15 +458,50 @@ static public class log [StackTraceHidden] static public void fatal( string msg, string cat = "", SourceLoc? loc = null, [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" ) { - logBase( msg, LogType.Fatal, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); + logBase( msg, Levels.Fatal, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); } - //new LogEvent( LogType.Raw, $"", "", 0, "", "lib.time", "", null ) + //new LogEvent( Levels.Raw, $"", "", 0, "", "lib.time", "", null ) #endregion + static private bool hasMethod( string name, Type t ) + { + var mi = t.GetMethod( name ); + + return mi != null; + } + + static private bool hasMethod( string name ) => hasMethod( name, typeof( T ) ); + + #region Helpers - static public void logProps( object obj, string header, LogType type = LogType.Debug, string cat = "", string prefix = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "obj" )] string dbgExpObj = "", SourceLoc? loc = null ) + + static public void environment( string header = "", string footer = "", Levels level = Levels.Info, string cat = "", string prefix = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "obj" )] string dbgExpObj = "", SourceLoc? loc = null ) + { + log.var( System.Environment.ProcessId, dbgMethod, dbgPath, dbgLine ); + + log.var( System.Environment.CommandLine, dbgMethod, dbgPath, dbgLine ); + + log.var( System.Environment.CurrentDirectory, dbgMethod, dbgPath, dbgLine ); + log.var( System.Environment.SystemDirectory, dbgMethod, dbgPath, dbgLine ); + + log.var( System.Environment.GetEnvironmentVariable( "PATH" ), dbgMethod, dbgPath, dbgLine ); + log.var( System.Environment.GetEnvironmentVariable( "USER" ), dbgMethod, dbgPath, dbgLine ); + log.var( System.Environment.GetEnvironmentVariable( "HOME" ), dbgMethod, dbgPath, dbgLine ); + + log.var( System.Environment.ProcessorCount, dbgMethod, dbgPath, dbgLine ); + log.var( System.Environment.Is64BitOperatingSystem, dbgMethod, dbgPath, dbgLine ); + log.var( System.Environment.Is64BitProcess, dbgMethod, dbgPath, dbgLine ); + + log.var( System.Environment.MachineName, dbgMethod, dbgPath, dbgLine ); + + log.var( System.Environment.Version, dbgMethod, dbgPath, dbgLine ); + log.var( System.Environment.OSVersion, dbgMethod, dbgPath, dbgLine ); + + } + + static public void props_orig( object obj, string header, int depth = 0, Levels type = Levels.Debug, string cat = "", string prefix = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "obj" )] string dbgExpObj = "", SourceLoc? loc = null ) { var list = refl.GetAllProperties( obj.GetType() ); @@ -482,12 +517,23 @@ static public class log try { var v = pi.GetValue( obj ); + var isNull = v != null; + + if( isNull ) + { + logBase( $"{prefix}{pi.Name} = null", type, dbgPath, dbgLine, dbgMethod, dbgExpObj, cat ); + continue; + } + + //var isPOD = + logBase( $"{prefix}{pi.Name} = {v}", type, dbgPath, dbgLine, dbgMethod, dbgExpObj, cat ); } catch( Exception ex ) { - logBase( $"Exception processing {pi.Name} {ex.Message}", LogType.Error, dbgPath, dbgLine, dbgMethod, cat, dbgExpObj, loc ); + logBase( $"{prefix}{pi.Name} = {ex.Message}", type, dbgPath, dbgLine, dbgMethod, dbgExpObj, cat ); + //logBase( $"Exception processing {pi.Name} {ex.Message}", Levels.Error, dbgPath, dbgLine, dbgMethod, cat, dbgExpObj, loc ); } } @@ -495,6 +541,120 @@ static public class log } } + + private static readonly HashSet s_podTypes = new() + { + typeof(string), typeof(bool), typeof(byte), typeof(sbyte), + typeof(char), typeof(decimal), typeof(double), typeof(float), + typeof(int), typeof(uint), typeof(long), typeof(ulong), + typeof(short), typeof(ushort), typeof(DateTime), typeof(DateTimeOffset), + typeof(TimeSpan), typeof(Guid) + }; + + static public void props( object obj, string header, int maxDepth = 0, Levels level = Levels.Debug, string cat = "", string prefix = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "obj" )] string dbgExpObj = "", SourceLoc? loc = null ) + { + // May not need this + //var visited = new HashSet( ReferenceEqualityComparer.Instance ); + + props_r( obj, header, maxDepth, level, cat, prefix, dbgPath, dbgLine, dbgMethod, dbgExpObj, loc ); + } + + static private void props_r( object obj, string header, int maxDepth = 0, Levels level = Levels.Debug, string cat = "", string prefix = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "obj" )] string dbgExpObj = "", SourceLoc? loc = null ) + { + // 1. Handle Null + if( obj is null ) + { + return; + } + + Type type = obj.GetType(); + + var tc = Type.GetTypeCode( type ); + + + //logBase( string msg, Levels type = Levels.Debug, string dbgPath = "", int dbgLine = -1, string dbgMethod = "", string cat = "unk", string exp = "", SourceLoc? loc = null ) + + + // 2. Handle POD (Plain Old Data) & Strings + if( tc != TypeCode.Object ) + { + logBase( $"{header}{dbgExpObj} = {obj}", level, dbgPath, dbgLine, dbgMethod, cat, dbgExpObj ); + return; + } + + // 3. Handle Overridden ToString() (User Rule) + // Check if the type overrides ToString() directly (not just inheriting object.ToString) + var toStringMethod = type.GetMethod( "ToString", Type.EmptyTypes ); + if( toStringMethod != null && toStringMethod.DeclaringType != typeof( object ) ) + { + logBase( $"{header}{dbgExpObj} = {obj.ToString()}", level, dbgPath, dbgLine, dbgMethod, cat, dbgExpObj ); + return; + } + + // 4. Cycle Detection + /* + if( !visited.Add( obj ) ) + { + sb.Append( $"{{$Cyclic:{type.Name}}}" ); + return; + } + //*/ + + // 5. Handle Collections (IEnumerable) + if( obj is IEnumerable collection ) + { + logBase( $"{header}{dbgExpObj}[{type.Name}] [[[", level, dbgPath, dbgLine, dbgMethod, cat, dbgExpObj ); + + if( maxDepth == 0 ) + { + } + else + { + var collectionHader = $"{header}{header}"; + var count = 0; + foreach( var item in collection ) + { + //if( count != 0 ) + props_r( item, collectionHader, --maxDepth, level, cat, prefix, dbgPath, dbgLine, dbgMethod, $"{count}" ); + } + } + logBase( $"{header}{dbgExpObj}[{type.Name}] ]]]", level, dbgPath, dbgLine, dbgMethod, cat, dbgExpObj ); + return; + } + + + logBase( $"{header}{dbgExpObj}[{type.Name}] ->", level, dbgPath, dbgLine, dbgMethod, cat, dbgExpObj ); + + // 6. Handle Complex Objects (Properties) + if( maxDepth == 0 ) + { + return; + } + + // Get all readable properties + var props = type.GetProperties( BindingFlags.Public | BindingFlags.Instance ) + .Where( p => p.CanRead && p.GetIndexParameters().Length == 0 ); + + var nextHeader = $"{header}{header}"; + + //bool firstProp = true; + foreach( var pi in props ) + { + var name = pi.Name; + var piType = pi.PropertyType; + try + { + var value = pi.GetValue( obj ); + props_r( value, nextHeader, --maxDepth, level, cat, prefix, dbgPath, dbgLine, dbgMethod, name ); + } + catch( Exception ex ) + { + logBase( $"{nextHeader}{name}[{piType.Name}] ex {ex.Message}", level, dbgPath, dbgLine, dbgMethod, cat, name ); + } + } + } + + //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 ) ) { @@ -523,7 +683,7 @@ static public class log foreach( var fr in stackTrace.GetFrames() ) { - logBase( $"{fr.Log}", LogType.Raw ); + logBase( $"{fr.Log}", Levels.Raw ); } } @@ -535,43 +695,44 @@ static public class log static object s_lock = new object(); static object s_lockTypeCallback = new object(); - static ImmutableDictionary> s_callbacks = ImmutableDictionary>.Empty; + static ImmutableDictionary> s_callbacks = ImmutableDictionary>.Empty; - //static ConcurrentDictionary> s_filters = new(); + static ConcurrentDictionary> s_filters = new(); static public void addFilter( string name, FilterFn filter ) { - /* + //* s_filters.AddOrUpdate( name, ( k ) => new List { filter }, - ( k, v ) => { + ( k, v ) => + { v.Add( filter ); return v; } ); - */ + //*/ } [StackTraceHidden] - static public void addDirectCallback( LogType logType, Action callback ) + static public void addDirectCallback( Levels level, Action callback ) { - //ImmutableInterlocked.Add( ref s_callbacks, logType, callback ); - var added = II.TryAdd( ref s_callbacks, logType, callback ); + //ImmutableInterlocked.Add( ref s_callbacks, level, callback ); + var added = II.TryAdd( ref s_callbacks, level, callback ); if( !added ) { - log.warn( $"Failed to add callback for {logType}" ); + log.warn( $"Failed to add callback for {level}" ); } } - static public LogEvent logCreateEvent( string msg, LogType type = LogType.Debug, string dbgPath = "", int dbgLine = -1, string dbgMethod = "", string cat = "unk", string exp = "", SourceLoc? loc = null ) + static public LogEvent logCreateEvent( string msg, Levels type = Levels.Debug, string dbgPath = "", int dbgLine = -1, string dbgMethod = "", string cat = "unk", string exp = "", SourceLoc? loc = null ) { LogEvent evt = new LogEvent( type, msg, dbgPath, dbgLine, dbgMethod, cat, exp, loc ); return evt; } [StackTraceHidden] - static public void logBase( string msg, LogType type = LogType.Debug, string dbgPath = "", int dbgLine = -1, string dbgMethod = "", string cat = "unk", string exp = "", SourceLoc? loc = null ) + static public void logBase( string msg, Levels type = Levels.Debug, string dbgPath = "", int dbgLine = -1, string dbgMethod = "", string cat = "unk", string exp = "", SourceLoc? loc = null ) { var evt = logCreateEvent( msg, type, dbgPath, dbgLine, dbgMethod, cat, exp ); @@ -639,9 +800,9 @@ static public class log { var time = DateTime.Now; // Header for this run - var blankLine = new LogEvent( LogType.Raw, $"", "", 0, "", "lib.time", "", null ); - var beginLine = new LogEvent( LogType.Raw, $"Begin B E G I N ******************************************************************************************************************", "", 0, "", "lib.time", "", null ); - var timeLine = new LogEvent( LogType.Raw, $"D A T E {time.Year}/{time.Month.ToString( "00" )}/{time.Day.ToString( "00" )} T I M E {time.Hour.ToString( "00" )}:{time.Minute.ToString( "00" )}:{time.Second.ToString( "00" )}.{time.Millisecond.ToString( "000" )}{time.Microsecond.ToString( "000" )}", "", 0, "", "lib.time", "", null ); + var blankLine = new LogEvent( Levels.Raw, $"", "", 0, "", "lib.time", "", null ); + var beginLine = new LogEvent( Levels.Raw, $"Begin B E G I N ******************************************************************************************************************", "", 0, "", "lib.time", "", null ); + var timeLine = new LogEvent( Levels.Raw, $"D A T E {time.Year}/{time.Month.ToString( "00" )}/{time.Day.ToString( "00" )} T I M E {time.Hour.ToString( "00" )}:{time.Minute.ToString( "00" )}:{time.Second.ToString( "00" )}.{time.Millisecond.ToString( "000" )}{time.Microsecond.ToString( "000" )}", "", 0, "", "lib.time", "", null ); // MODIFIED: All writes are now safely enqueued to be processed by the logger thread. // This prevents the StreamWriter buffer corruption that caused null bytes. @@ -653,13 +814,13 @@ static public class log s_events.Add( blankLine ); } - LogEvent msgStartupBegin = new LogEvent( LogType.Info, $"startup BEGIN", "", 0, "", "log.startup", "", null ); + LogEvent msgStartupBegin = new LogEvent( Levels.Info, $"startup BEGIN", "", 0, "", "log.startup", "", null ); s_events.Add( msgStartupBegin ); - LogEvent msgFilename = new LogEvent( LogType.Info, $"Logging in {filename}", "", 0, "", "log.startup", "", null ); + LogEvent msgFilename = new LogEvent( Levels.Info, $"Logging in {filename}", "", 0, "", "log.startup", "", null ); s_events.Add( msgFilename ); - var optionsLine = new LogEvent( LogType.Info, $"Endpoints: {endpoints}", "", 0, "", "log.startup", "", null ); + var optionsLine = new LogEvent( Levels.Info, $"Endpoints: {endpoints}", "", 0, "", "log.startup", "", null ); s_events.Add( optionsLine ); StartThread(); @@ -699,7 +860,7 @@ static public class log // automatically finish when s_events.CompleteAdding() is called from another thread. foreach( var evt in s_events.GetConsumingEnumerable() ) { - /* + //* // Apply filters var cat = evt.Cat; var blocked = false; @@ -762,23 +923,23 @@ static public class log s_delegates.Add( cb ); } - public static char getSymbol( LogType type ) + public static char getSymbol( Levels type ) { switch( type ) { - case LogType.Trace: + case Levels.Trace: return ' '; - case LogType.Debug: + case Levels.Debug: return ' '; - case LogType.Info: + case Levels.Info: return ' '; - case LogType.High: + case Levels.High: return '+'; - case LogType.Warn: + case Levels.Warn: return '+'; - case LogType.Error: + case Levels.Error: return '*'; - case LogType.Fatal: + case Levels.Fatal: return '*'; default: return '?'; @@ -787,35 +948,35 @@ static public class log private static void setConsoleColor( log.LogEvent evt ) { - switch( evt.LogType ) + switch( evt.Levels ) { - case log.LogType.Trace: + case log.Levels.Trace: Console.ForegroundColor = ConsoleColor.DarkGray; break; - case log.LogType.Debug: + case log.Levels.Debug: Console.ForegroundColor = ConsoleColor.Gray; break; - case log.LogType.Info: + case log.Levels.Info: Console.ForegroundColor = ConsoleColor.DarkGreen; break; - case log.LogType.High: + case log.Levels.High: Console.ForegroundColor = ConsoleColor.Cyan; break; - case log.LogType.Warn: + case log.Levels.Warn: Console.ForegroundColor = ConsoleColor.Yellow; break; - case log.LogType.Error: + case log.Levels.Error: Console.ForegroundColor = ConsoleColor.DarkRed; Console.BackgroundColor = ConsoleColor.DarkGray; break; - case log.LogType.Fatal: + case log.Levels.Fatal: Console.ForegroundColor = ConsoleColor.Red; Console.BackgroundColor = ConsoleColor.DarkGray; break; - case log.LogType.Invalid: - case log.LogType.Time: - case log.LogType.Raw: + case log.Levels.Invalid: + case log.Levels.Time: + case log.Levels.Raw: Console.ForegroundColor = ConsoleColor.Red; break; @@ -831,11 +992,11 @@ static public class log static public string headerPrint( LogEvent evt ) { - if( evt.LogType != LogType.Raw ) + if( evt.Levels != Levels.Raw ) { var span = evt.Time - s_startTime; - char sym = getSymbol( evt.LogType ); + char sym = getSymbol( evt.Levels ); var truncatedCat = evt.Cat.Substring( 0, Math.Min( s_catWidth, evt.Cat.Length ) ); @@ -854,13 +1015,13 @@ static public class log static public string headerFile( LogEvent evt ) { - if( evt.LogType != LogType.Raw ) + if( evt.Levels != Levels.Raw ) { try { var span = evt.Time - s_startTime; - char sym = getSymbol( evt.LogType ); + char sym = getSymbol( evt.Levels ); var truncatedCat = evt.Cat.Substring( 0, Math.Min( s_catWidth, evt.Cat.Length ) ); @@ -910,7 +1071,7 @@ static public class log var msg = evt.Msg; - if( ( string.IsNullOrWhiteSpace( msg ) && evt.LogType != LogType.Raw ) || msg.Contains( (char)0 ) ) + if( ( string.IsNullOrWhiteSpace( msg ) && evt.Levels != Levels.Raw ) || msg.Contains( (char)0 ) ) { msg = "B R O K E N msg"; } @@ -948,12 +1109,12 @@ static public class log { s_lastDisplaySeconds = curSeconds; - var minuteEvt = new LogEvent( LogType.Raw, $"T I M E ==> {evt.Time.Hour.ToString( "00" )}:{evt.Time.Minute.ToString( "00" )}:{evt.Time.Second.ToString( "00" )}.{evt.Time.Millisecond.ToString( "000" )} : {evt.Time.ToShortDateString()}", "", 0, "", "lib.time", "", null ); + var minuteEvt = new LogEvent( Levels.Raw, $"T I M E ==> {evt.Time.Hour.ToString( "00" )}:{evt.Time.Minute.ToString( "00" )}:{evt.Time.Second.ToString( "00" )}.{evt.Time.Millisecond.ToString( "000" )} : {evt.Time.ToShortDateString()}", "", 0, "", "lib.time", "", null ); minuteEvt.Time = evt.Time; writeSpecialEvent( minuteEvt ); } - if( evt.LogType != LogType.Raw ) + if( evt.Levels != Levels.Raw ) { var curSecond = (int)span.TotalSeconds; @@ -1034,7 +1195,7 @@ static public class log public static void WriteToConsole( LogEvent evt ) { - char sym = getSymbol( evt.LogType ); + char sym = getSymbol( evt.Levels ); var truncatedCat = evt.Cat.Substring( 0, Math.Min( 8, evt.Cat.Length ) ); diff --git a/time/Time.cs b/time/Time.cs new file mode 100644 index 0000000..3ce825e --- /dev/null +++ b/time/Time.cs @@ -0,0 +1,52 @@ + + + + + +namespace time; + + + + + +// This class should be static. It will then only run occasionally, based on passed in TimeSpan +public class EveryState +{ + public DateTime Last { get; private set; } + public TimeSpan Interval { get; private set; } + public bool Latch { get; private set; } + + public EveryState( TimeSpan interval ) + { + Last = DateTime.Now; + Interval = interval; + } + + //For first active call, Latch will be true. It will remain true until the next first call to Every + // This allows cohesive between different functions + public void Every( Action fn ) + { + var now = DateTime.Now; + + + if( now - Last >= Interval ) + { + Latch = true; + fn(); + Last = now; + } + else + { + Latch = false; + } + } + + public void Contingent( Action fn ) + { + if( Latch ) + { + fn(); + } + } + +}