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
{
@ -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 );

View File

@ -54,36 +54,36 @@ public record struct Value<T>( 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<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
@ -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<int, string> s_files = ImmutableDictionary<int, string>.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<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();
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>( 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;
}
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<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();
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<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();
@ -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<T>( 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<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.
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() )
{
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<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 )
{
/*
//*
s_filters.AddOrUpdate( name,
( k ) => new List<FilterFn> { filter },
( k, v ) => {
( k, v ) =>
{
v.Add( filter );
return v;
} );
*/
//*/
}
[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 );
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 ) );

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