This commit is contained in:
Marc Hernandez 2026-02-09 14:57:45 -08:00
parent 3bf3220beb
commit 40dd96d06e
3 changed files with 326 additions and 92 deletions

View File

@ -11,6 +11,25 @@ x)
*/ */
static public class cfg
{
static public T load<T>( string filename ) where T : lib.Config
{
return (T)lib.ConfigBase.load<T>( filename );
}
static public lib.Config load( string filename )
{
return lib.ConfigBase.load( filename, null );
}
}
namespace lib namespace lib
{ {
@ -184,6 +203,8 @@ namespace lib
internal static ConfigCfg s_cfg = new(); internal static ConfigCfg s_cfg = new();
public static ConfigCfg Cfg => s_cfg;
static public void startup( string filename ) static public void startup( string filename )
{ {
res.Mgr.Register( ConfigBase.load ); res.Mgr.Register( ConfigBase.load );

View File

@ -54,36 +54,36 @@ public record struct Value<T>( T _val, string _exp = "" )
public struct SourceLoc public struct SourceLoc
{ {
readonly string _reason = ""; readonly string _reason = "";
readonly string _dbgName = ""; readonly string _dbgMethod = "";
readonly string _dbgPath = ""; readonly string _dbgPath = "";
readonly string _dbgFile = ""; readonly string _dbgFile = "";
readonly int _dbgLine = -1; 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; _reason = reason;
_dbgName = dbgName; _dbgMethod = dbgMethod;
_dbgPath = dbgPath; _dbgPath = dbgPath;
_dbgLine = dbgLine; _dbgLine = dbgLine;
_dbgFile = log.whatFile( dbgPath ); _dbgFile = log.whatFile( dbgPath );
} }
public string ToLogString() => $"{_dbgFile}.{_dbgName}"; public string ToLogString() => $"{_dbgFile}.{_dbgMethod}";
public string Log => ToLogString(); public string Log => ToLogString();
public string File => _dbgFile; public string File => _dbgFile;
public string Method => _dbgName; public string Method => _dbgMethod;
static public SourceLoc Record( static public SourceLoc Record(
string reason = "", string reason = "",
[CallerMemberName] string dbgName = "", [CallerMemberName] string dbgMethod = "",
[CallerFilePath] string dbgPath = "", [CallerFilePath] string dbgPath = "",
[CallerLineNumber] int dbgLine = 0 [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 #endregion // CLR Logging
[Flags] [Flags]
public enum LogType public enum Levels
{ {
Invalid = 0, Invalid = 0,
Trace = 1, Trace = 1,
@ -186,7 +186,7 @@ static public class log
public struct LogEvent public struct LogEvent
{ {
public DateTime Time; public DateTime Time;
public LogType LogType; public Levels Levels;
public string Msg; public string Msg;
public string Path; public string Path;
public int Line; public int Line;
@ -199,7 +199,7 @@ static public class log
static ImmutableDictionary<int, string> s_shortname = ImmutableDictionary<int, string>.Empty; static ImmutableDictionary<int, string> s_shortname = ImmutableDictionary<int, string>.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 //Cache the automatic category names
@ -229,7 +229,7 @@ static public class log
} }
Time = DateTime.Now; Time = DateTime.Now;
LogType = logType; Levels = level;
Msg = msg; Msg = msg;
Path = dbgPath; Path = dbgPath;
Line = dbgLine; 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; return logEvent;
} }
@ -261,7 +261,7 @@ static public class log
static public void shutdown() static public void shutdown()
{ {
string msg = "==============================================================================\nLogfile shutdown at " + DateTime.Now.ToString(); 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 s_events.Add( evt ); // Use Add instead of Enqueue
stop(); stop();
@ -277,8 +277,8 @@ static public class log
static ImmutableDictionary<int, string> s_files = ImmutableDictionary<int, string>.Empty; static ImmutableDictionary<int, string> s_files = ImmutableDictionary<int, string>.Empty;
#region Util #region Util
static public SourceLoc loc( [CallerMemberName] string dbgName = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 ) static public SourceLoc loc( [CallerMemberName] string dbgMethod = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1 )
=> new SourceLoc( "", dbgName, dbgPath, dbgLine ); => new SourceLoc( "", dbgMethod, dbgPath, dbgLine );
static public string whatFile( string path, bool incExtension = false ) static public string whatFile( string path, bool incExtension = false )
@ -336,11 +336,11 @@ static public class log
#region Forwards #region Forwards
static public T call<T>( Func<T> func, [CallerMemberName] string dbgName = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerArgumentExpression( "func" )] string dbgExp = "" ) static public T call<T>( Func<T> 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(); var val = func();
log.info( $"| Got {val}", "", null, dbgPath, dbgLine, dbgName, dbgExp ); log.info( $"| Got {val}", "", null, dbgPath, dbgLine, dbgMethod, dbgExp );
return val; return val;
} }
@ -349,38 +349,38 @@ static public class log
[CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" ) [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerMemberName] string dbgMethod = "", [CallerArgumentExpression( "msg" )] string dbgExp = "" )
*/ */
static public T var<T>( T val, [CallerMemberName] string dbgName = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerArgumentExpression( "val" )] string dbgExp = "" ) static public T var<T>( 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; 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(); val();
} }
static public T operations<T>( Func<T> val, [CallerMemberName] string dbgName = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerArgumentExpression( "val" )] string dbgExp = "" ) static public T operations<T>( Func<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 );
var v = val(); var v = val();
return v; 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(); val();
} }
static public T operations<T>( string prefix, Func<T> val, [CallerMemberName] string dbgName = "", [CallerFilePath] string dbgPath = "", [CallerLineNumber] int dbgLine = -1, [CallerArgumentExpression( "val" )] string dbgExp = "" ) static public T operations<T>( string prefix, Func<T> 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(); var v = val();
@ -388,48 +388,48 @@ static public class log
} }
[StackTraceHidden] [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(); func();
log.info( $"| Done", "", null, dbgPath, dbgLine, dbgName, dbgExp ); log.info( $"| Done", "", null, dbgPath, dbgLine, dbgMethod, dbgExp );
} }
[StackTraceHidden] [StackTraceHidden]
static public void info( string msg, string cat = "", SourceLoc? loc = null, 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 = "" ) [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] [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 = "" ) 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] [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 = "" ) 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] [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 = "" ) 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] [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 = "" ) 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] [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 = "" ) 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 // 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 = "" ) 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( $"*******************************************************************************", logBase( $"*******************************************************************************",
LogType.Raw, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); Levels.Raw, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc );
logBase( $"{dbgMethod}: {msg} | Caught At:", LogType.Error, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); logBase( $"{dbgMethod}: {msg} | Caught At:", Levels.Error, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc );
logBase( $"{dbgPath}({dbgLine}): {dbgMethod}: ---------------", logBase( $"{dbgPath}({dbgLine}): {dbgMethod}: ---------------",
LogType.Raw, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc ); Levels.Raw, dbgPath, dbgLine, dbgMethod, cat, dbgExp, loc );
LogStackTrace( ex ); LogStackTrace( ex );
} }
@ -458,15 +458,50 @@ static public class log
[StackTraceHidden] [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 = "" ) 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 #endregion
static private bool hasMethod( string name, Type t )
{
var mi = t.GetMethod( name );
return mi != null;
}
static private bool hasMethod<T>( string name ) => hasMethod( name, typeof( T ) );
#region Helpers #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() ); var list = refl.GetAllProperties( obj.GetType() );
@ -482,12 +517,23 @@ static public class log
try try
{ {
var v = pi.GetValue( obj ); 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 ); logBase( $"{prefix}{pi.Name} = {v}", type, dbgPath, dbgLine, dbgMethod, dbgExpObj, cat );
} }
catch( Exception ex ) 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<Type> 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<object>( 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. //This might seem a little odd, but the intent is that usually you wont need to set notExpectedValue.
static public void expected<T>( T value, string falseString, string trueString = "", T? notExpectedValue = default( T ) ) static public void expected<T>( T value, string falseString, string trueString = "", T? notExpectedValue = default( T ) )
{ {
@ -523,7 +683,7 @@ static public class log
foreach( var fr in stackTrace.GetFrames() ) 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_lock = new object();
static object s_lockTypeCallback = new object(); static object s_lockTypeCallback = new object();
static ImmutableDictionary<LogType, Action<LogEvent>> s_callbacks = ImmutableDictionary<LogType, Action<LogEvent>>.Empty; static ImmutableDictionary<Levels, Action<LogEvent>> s_callbacks = ImmutableDictionary<Levels, Action<LogEvent>>.Empty;
//static ConcurrentDictionary<string, List<FilterFn>> s_filters = new(); static ConcurrentDictionary<string, List<FilterFn>> s_filters = new();
static public void addFilter( string name, FilterFn filter ) static public void addFilter( string name, FilterFn filter )
{ {
/* //*
s_filters.AddOrUpdate( name, s_filters.AddOrUpdate( name,
( k ) => new List<FilterFn> { filter }, ( k ) => new List<FilterFn> { filter },
( k, v ) => { ( k, v ) =>
{
v.Add( filter ); v.Add( filter );
return v; return v;
} ); } );
*/ //*/
} }
[StackTraceHidden] [StackTraceHidden]
static public void addDirectCallback( LogType logType, Action<LogEvent> callback ) static public void addDirectCallback( Levels level, Action<LogEvent> callback )
{ {
//ImmutableInterlocked.Add( ref s_callbacks, logType, callback ); //ImmutableInterlocked.Add( ref s_callbacks, level, callback );
var added = II.TryAdd( ref s_callbacks, logType, callback ); var added = II.TryAdd( ref s_callbacks, level, callback );
if( !added ) 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 ); LogEvent evt = new LogEvent( type, msg, dbgPath, dbgLine, dbgMethod, cat, exp, loc );
return evt; return evt;
} }
[StackTraceHidden] [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 ); var evt = logCreateEvent( msg, type, dbgPath, dbgLine, dbgMethod, cat, exp );
@ -639,9 +800,9 @@ static public class log
{ {
var time = DateTime.Now; var time = DateTime.Now;
// Header for this run // Header for this run
var blankLine = new LogEvent( LogType.Raw, $"", "", 0, "", "lib.time", "", null ); var blankLine = new LogEvent( Levels.Raw, $"", "", 0, "", "lib.time", "", null );
var beginLine = new LogEvent( LogType.Raw, $"Begin B E G I N ******************************************************************************************************************", "", 0, "", "lib.time", "", null ); var beginLine = new LogEvent( Levels.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 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. // MODIFIED: All writes are now safely enqueued to be processed by the logger thread.
// This prevents the StreamWriter buffer corruption that caused null bytes. // This prevents the StreamWriter buffer corruption that caused null bytes.
@ -653,13 +814,13 @@ static public class log
s_events.Add( blankLine ); 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 ); 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 ); 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 ); s_events.Add( optionsLine );
StartThread(); StartThread();
@ -699,7 +860,7 @@ static public class log
// automatically finish when s_events.CompleteAdding() is called from another thread. // automatically finish when s_events.CompleteAdding() is called from another thread.
foreach( var evt in s_events.GetConsumingEnumerable() ) foreach( var evt in s_events.GetConsumingEnumerable() )
{ {
/* //*
// Apply filters // Apply filters
var cat = evt.Cat; var cat = evt.Cat;
var blocked = false; var blocked = false;
@ -762,23 +923,23 @@ static public class log
s_delegates.Add( cb ); s_delegates.Add( cb );
} }
public static char getSymbol( LogType type ) public static char getSymbol( Levels type )
{ {
switch( type ) switch( type )
{ {
case LogType.Trace: case Levels.Trace:
return ' '; return ' ';
case LogType.Debug: case Levels.Debug:
return ' '; return ' ';
case LogType.Info: case Levels.Info:
return ' '; return ' ';
case LogType.High: case Levels.High:
return '+'; return '+';
case LogType.Warn: case Levels.Warn:
return '+'; return '+';
case LogType.Error: case Levels.Error:
return '*'; return '*';
case LogType.Fatal: case Levels.Fatal:
return '*'; return '*';
default: default:
return '?'; return '?';
@ -787,35 +948,35 @@ static public class log
private static void setConsoleColor( log.LogEvent evt ) 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; Console.ForegroundColor = ConsoleColor.DarkGray;
break; break;
case log.LogType.Debug: case log.Levels.Debug:
Console.ForegroundColor = ConsoleColor.Gray; Console.ForegroundColor = ConsoleColor.Gray;
break; break;
case log.LogType.Info: case log.Levels.Info:
Console.ForegroundColor = ConsoleColor.DarkGreen; Console.ForegroundColor = ConsoleColor.DarkGreen;
break; break;
case log.LogType.High: case log.Levels.High:
Console.ForegroundColor = ConsoleColor.Cyan; Console.ForegroundColor = ConsoleColor.Cyan;
break; break;
case log.LogType.Warn: case log.Levels.Warn:
Console.ForegroundColor = ConsoleColor.Yellow; Console.ForegroundColor = ConsoleColor.Yellow;
break; break;
case log.LogType.Error: case log.Levels.Error:
Console.ForegroundColor = ConsoleColor.DarkRed; Console.ForegroundColor = ConsoleColor.DarkRed;
Console.BackgroundColor = ConsoleColor.DarkGray; Console.BackgroundColor = ConsoleColor.DarkGray;
break; break;
case log.LogType.Fatal: case log.Levels.Fatal:
Console.ForegroundColor = ConsoleColor.Red; Console.ForegroundColor = ConsoleColor.Red;
Console.BackgroundColor = ConsoleColor.DarkGray; Console.BackgroundColor = ConsoleColor.DarkGray;
break; break;
case log.LogType.Invalid: case log.Levels.Invalid:
case log.LogType.Time: case log.Levels.Time:
case log.LogType.Raw: case log.Levels.Raw:
Console.ForegroundColor = ConsoleColor.Red; Console.ForegroundColor = ConsoleColor.Red;
break; break;
@ -831,11 +992,11 @@ static public class log
static public string headerPrint( LogEvent evt ) static public string headerPrint( LogEvent evt )
{ {
if( evt.LogType != LogType.Raw ) if( evt.Levels != Levels.Raw )
{ {
var span = evt.Time - s_startTime; 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 ) ); 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 ) static public string headerFile( LogEvent evt )
{ {
if( evt.LogType != LogType.Raw ) if( evt.Levels != Levels.Raw )
{ {
try try
{ {
var span = evt.Time - s_startTime; 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 ) ); 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; 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"; msg = "B R O K E N msg";
} }
@ -948,12 +1109,12 @@ static public class log
{ {
s_lastDisplaySeconds = curSeconds; 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; minuteEvt.Time = evt.Time;
writeSpecialEvent( minuteEvt ); writeSpecialEvent( minuteEvt );
} }
if( evt.LogType != LogType.Raw ) if( evt.Levels != Levels.Raw )
{ {
var curSecond = (int)span.TotalSeconds; var curSecond = (int)span.TotalSeconds;
@ -1034,7 +1195,7 @@ static public class log
public static void WriteToConsole( LogEvent evt ) 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 ) ); var truncatedCat = evt.Cat.Substring( 0, Math.Min( 8, evt.Cat.Length ) );

52
time/Time.cs Normal file
View File

@ -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();
}
}
}