diff --git a/src/kontalog/dbj_core_kontalog.cs b/src/kontalog/dbj_core_kontalog.cs index ea7d1c5..08c90f8 100644 --- a/src/kontalog/dbj_core_kontalog.cs +++ b/src/kontalog/dbj_core_kontalog.cs @@ -1,8 +1,8 @@ -#define LOCAL_ISO_8601 +#define DBJ_ISO_8601 // using System; using System.Runtime.CompilerServices; -using System.Collections.Concurrent; +// using System.Collections.Concurrent; // using System.Threading; // using System.Threading.Tasks; @@ -29,7 +29,9 @@ namespace dbjcore; public static class Kontalog { -#if LOCAL_ISO_8601 + private static readonly object katanac_ = new object(); + +#if DBJ_ISO_8601 // Console.WriteLine("Hello my UTC timestamp : " + iso8601(1)); // Console.WriteLine("Hello iso8601 with 'T' : " + iso8601(2)); // Console.WriteLine("Hello full iso8601 : " + iso8601(3)); @@ -55,6 +57,7 @@ public static string iso8601(short kind_ = 0) } #endif +#if DBJ_DIY_ASYNC_CONSOLE private static readonly int Queue_size = 0xFF; // "blocking" means "wait until the operation can be completed" // Note that blocking on maximum capacity is only enabled @@ -62,9 +65,29 @@ public static string iso8601(short kind_ = 0) // has been created with a maximum capacity specified in the constructor private static BlockingCollection Queue_ = new BlockingCollection(Queue_size); - +#endif + private static void OnProcessExit_flush_kontalog(object ? sender, EventArgs e) + { +#if DBJ_DIY_ASYNC_CONSOLE + // Consume all remaining items in the queue + while (!Queue_.IsCompleted) + { + if (Queue_.TryTake(out string? item)) + { + // "Flushing item on exit: " + Console.WriteLine(item); + } + } +#else + Console.Out.FlushAsync(); +#endif + } static Kontalog() { + // Register a handler for application exit + AppDomain.CurrentDomain.ProcessExit += OnProcessExit_flush_kontalog; + +#if DBJ_DIY_ASYNC_CONSOLE // this code works, unfortunately ;) // WARNING: Console.Writeline will be out of sync, if used in a program var thread = new Thread( @@ -75,19 +98,26 @@ static Kontalog() while (!Queue_.IsCompleted) { - string data = string.Empty; + // string data = string.Empty; // https://learn.microsoft.com/en-us/dotnet/standard/collections/thread-safe/blockingcollection-overview try { - data = Queue_.Take(); + if (Queue_.TryTake(out string? item)) + { + // Process or log the item + Console.WriteLine(item); + } } - catch (InvalidOperationException) { } - - if (data != string.Empty) + catch (Exception x_) { - System.Console.WriteLine(data); + Console.WriteLine(x_); } + // if (data != string.Empty) + // { + // System.Console.WriteLine(data); + // } + // Slow down consumer just a little to cause // collection to fill up faster, and lead to "AddBlocked" //const int spin_wait = 0xFFFFF; @@ -96,25 +126,39 @@ static Kontalog() }); thread.IsBackground = true; thread.Start(); +#endif } +#if DBJ_DIY_ASYNC_CONSOLE [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Add(string format, params object[] args) { + lock (katanac_) + { if (args.Length < 1) Queue_.Add(format); else { Queue_.Add(string.Format(format, args)); } + } } +#endif #if KONTALOG_HANDLES_SQLSVR_CLIENT_EXCEPTION [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Add(Microsoft.Data.SqlClient.SqlException sqx) { + lock (katanac_) + { +#if DBJ_DIY_ASYNC_CONSOLE Queue_.Add( string.Format("[" + iso8601() + "]" + "SQL SRV name: {0}\nSQL Exception code: {1}\nmessage: {2}", sqx.Server, sqx.ErrorCode, sqx.Message)); +#else + Console.Out.WriteLineAsync( + string.Format("[" + iso8601() + "]" + "SQL SRV name: {0}\nSQL Exception code: {1}\nmessage: {2}", sqx.Server, sqx.ErrorCode, sqx.Message)); +#endif + } } #endif // and now lets turn this into the 'logging lib' @@ -137,9 +181,12 @@ public static bool Production } } +#if DBJ_DIY_ASYNC_CONSOLE [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void log_(Level lvl_, string format, params object[] args) { + lock (katanac_) + { // if in Production only fatal messages will be logged if (Production) { @@ -154,7 +201,32 @@ public static void log_(Level lvl_, string format, params object[] args) { Queue_.Add(prefix_ + string.Format(format, args)); } + } } +#else + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void log_(Level lvl_, string format, params object[] args) + { + lock (katanac_) + { + // if in Production only fatal messages will be logged + if (Production) + { + if (lvl_ > Level.fatal) return; + } + + var prefix_ = "[" + iso8601() + "|" + lvl_.ToString() + "]"; + + if (args.Length < 1) + Console.Out.WriteLineAsync(prefix_ + format); + else + { + Console.Out.WriteLineAsync(prefix_ + string.Format(format, args)); + } + } + } +#endif + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void fatal(string format, params object[] args) {