diff --git a/AyCode.Core.Server/AyCode.Core.Server.csproj b/AyCode.Core.Server/AyCode.Core.Server.csproj index 30402ac..66e6116 100644 --- a/AyCode.Core.Server/AyCode.Core.Server.csproj +++ b/AyCode.Core.Server/AyCode.Core.Server.csproj @@ -6,4 +6,8 @@ enable + + + + diff --git a/AyCode.Core.Server/Loggers/GlobalLogger.cs b/AyCode.Core.Server/Loggers/GlobalLogger.cs new file mode 100644 index 0000000..17eb119 --- /dev/null +++ b/AyCode.Core.Server/Loggers/GlobalLogger.cs @@ -0,0 +1,67 @@ +using System.Runtime.CompilerServices; +using AyCode.Core.Enums; +using AyCode.Core.Loggers; + +namespace AyCode.Core.Server.Loggers +{ + public sealed class AcGlobalLoggerBase : AcLoggerBase + { } + + public sealed class GlobalLogger //: IAcLogWriterBase + { + private readonly AcGlobalLoggerBase _logger = new(); + private static readonly GlobalLogger Instance = new(); + + public static LogLevel LogLevel => Instance._logger.LogLevel; + public static AppType AppType => Instance._logger.AppType; + + private const string DefaultCategoryName = "GLOBAL_LOGGER"; + + static GlobalLogger() + { } + + private GlobalLogger() + { } + + + public static List GetWriters => Instance._logger.GetWriters; + public static TLogWriter Writer() where TLogWriter : IAcLogWriterBase => Instance._logger.Writer(); + + + public static void Detail(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null) + => Instance._logger.Detail(text, categoryName ?? DefaultCategoryName, memberName); + + //public static void Detail(string? text, [CallerMemberName] string? memberName = null) where TCallerClassType : class + // => Detail(text, typeof(TCallerClassType).Name, memberName); + + public static void Debug(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null) + => Instance._logger.Debug(text, categoryName ?? DefaultCategoryName, memberName); + + //public static void Debug(string? text, [CallerMemberName] string? memberName = null) where TCallerClassType : class + // => Debug(text, typeof(TCallerClassType).Name, memberName); + + public static void Info(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null) + => Instance._logger.Info(text, categoryName ?? DefaultCategoryName, memberName); + + //public static void Info(string? text, [CallerMemberName] string? memberName = null) where TCallerClassType : class + // => Info(text, typeof(TCallerClassType).Name, memberName); + + public static void Warning(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null) + => Instance._logger.Warning(text, categoryName ?? DefaultCategoryName, memberName); + + //public static void Warning(string? text, [CallerMemberName] string? memberName = null) where TCallerClassType : class + // => Warning(text, typeof(TCallerClassType).Name, memberName); + + public static void Suggest(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null) + => Instance._logger.Suggest(text, categoryName ?? DefaultCategoryName, memberName); + + //public static void Suggest(string? text, [CallerMemberName] string? memberName = null) where TCallerClassType : class + // => Suggest(text, typeof(TCallerClassType).Name, memberName); + + //public static void Error(string? text, Exception? ex = null, [CallerMemberName] string? memberName = null) where TCallerClassType : class + // => Error(text, ex, typeof(TCallerClassType).Name, memberName); + + public static void Error(string? text, Exception? ex = null, string? categoryName = null, [CallerMemberName] string? memberName = null) + => Instance._logger.Error(text, ex, categoryName ?? DefaultCategoryName, memberName); + } +} diff --git a/AyCode.Core/Consts/AcConst.cs b/AyCode.Core/Consts/AcConst.cs index 4187a2c..9d7a685 100644 --- a/AyCode.Core/Consts/AcConst.cs +++ b/AyCode.Core/Consts/AcConst.cs @@ -79,10 +79,10 @@ namespace AyCode.Core.Consts public static string[] AvailableDomainSuffixes = new string[] { "3d", "anata", "app", "art", "club", "game", "blog", "shop", "biz", "chat", "conf", "city", "com", "net", "cool", "dance", "date", "fun", "design", "digital", "estate", "metaverse", "mv", "events", "fans", "fashion", "makeup", "fin", "fm", "sport", "gallery", "io", "info", "job", "mev", "land", "world", "life", "live", "lol", "love", "market", "media", "museum", "news", "ngo", "ninja", "kiwi", "one", "org", "party", "pink", "press", "slide", "property", "pub", "race", "sale", "school", "science", "social", "study", "style", "support", "tattoo", "team", "tech", "theatre", "town", "trade", "travel", "tv", "university", "education", "video", "vip", "vision", "wiki", "work", "xxx", "yeti", "ac", "ad", "ae", "af", "ag", "ai", "al", "am", "ao", "aq", "ar", "as", "at", "au", "aw", "ax", "az", "ba", "bb", "bd", "be", "bf", "bg", "bh", "bi", "bj", "bm", "bn", "bo", "bq", "br", "bs", "bt", "bw", "by", "bz", "ca", "cc", "cd", "cf", "cg", "ch", "ci", "ck", "cl", "cm", "cn", "co", "cr", "cu", "cv", "cw", "cx", "cy", "cz", "de", "dj", "dk", "dm", "do", "dz", "ec", "ee", "eg", "eh", "er", "es", "et", "eu", "fi", "fj", "fk", "fm", "fo", "fr", "ga", "gd", "ge", "gf", "gg", "gh", "gi", "gl", "gm", "gn", "gp", "gq", "gr", "gs", "gt", "gu", "gw", "gy", "hk", "hm", "hn", "hr", "ht", "hu", "id", "ie", "il", "im", "in", "io", "iq", "ir", "is", "it", "je", "jm", "jo", "jp", "ke", "kg", "kh", "ki", "km", "kn", "kp", "kr", "kw", "ky", "kz", "la", "lb", "lc", "li", "lk", "lr", "ls", "lt", "lu", "lv", "ly", "ma", "mc", "md", "me", "mg", "mh", "mk", "ml", "mm", "mn", "mo", "mp", "mq", "mr", "ms", "mt", "mu", "mv", "mw", "mx", "my", "mz", "na", "nc", "ne", "nf", "ng", "ni", "nl", "no", "np", "nr", "nu", "nz", "om", "pa", "pe", "pf", "pg", "ph", "pk", "pl", "pm", "pn", "pr", "ps", "pt", "pw", "py", "qa", "re", "ro", "rs", "ru", "rw", "sa", "sb", "sc", "sd", "se", "sg", "sh", "si", "sk", "sl", "sm", "sn", "so", "sr", "ss", "st", "su", "sv", "sx", "sy", "sz", "tc", "td", "tf", "tg", "th", "tj", "tk", "tl", "tm", "tn", "to", "tr", "tt", "tv", "tw", "tz", "ua", "ug", "uk", "us", "uy", "uz", "va", "vc", "ve", "vg", "vi", "vn", "vu", "wf", "ws", "ye", "yt", "za", "zm", "zw" }; //TODO: kitörölni és DB-ből kiszedni! - J. - private static string _tiamProjectIdString = "684f34d1-163a-4077-918f-a9d9df5ce789"; + //private static string _tiamProjectIdString = "684f34d1-163a-4077-918f-a9d9df5ce789"; static AcConst() { - ProjectId = Guid.Parse(_tiamProjectIdString.ToLower()); + ProjectId = Guid.Parse(AcEnv.AppConfiguration["AyCode:ProjectId"].ToLower()); ProjectSalt = GenerateProjectSalt(ProjectId.ToString("N").ToLower()); //var anataFolder = AcDomain.IsProductVersion ? "Anata" : "AnataDev"; diff --git a/AyCode.Core/Consts/AcEnv.cs b/AyCode.Core/Consts/AcEnv.cs index 47fe73a..7cd6b2f 100644 --- a/AyCode.Core/Consts/AcEnv.cs +++ b/AyCode.Core/Consts/AcEnv.cs @@ -1,5 +1,6 @@ //using Anata.Logger; +using AyCode.Core.Enums; using Microsoft.Extensions.Configuration; namespace AyCode.Core.Consts @@ -24,7 +25,13 @@ namespace AyCode.Core.Consts private static IConfiguration? _appConfiguration = null; public static IConfiguration AppConfiguration => _appConfiguration ??= GetAppSettingsConfiguration(); - public static IConfiguration GetAppSettingsConfiguration(string appSettingsFileName = "appsettings.json") + public static TEnum GetEnum(this IConfiguration configuration, string configPath) where TEnum : struct + => (TEnum)Enum.Parse(typeof(TEnum), configuration[configPath]); + + public static TEnum GetEnum(this IConfigurationSection section, string configPath) where TEnum : struct + => (TEnum)Enum.Parse(typeof(TEnum), section[configPath]); + + private static IConfiguration GetAppSettingsConfiguration(string appSettingsFileName = "appsettings.json") { var config = new ConfigurationBuilder() .AddJsonFile(appSettingsFileName) diff --git a/AyCode.Core/Logger/Logger.cs b/AyCode.Core/Logger/Logger.cs deleted file mode 100644 index 12a1483..0000000 --- a/AyCode.Core/Logger/Logger.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; -using AyCode.Core.Consts; -using AyCode.Core.Enums; - -namespace AyCode.Core.Logger -{ - public static class Logger - { - public static LogLevel LogLevel { get; set; } = LogLevel.Detail; - public static AppType AppType { get; set; } = AppType.Server; - - public static void Detail(string text, [CallerMemberName] string? memberName = null) - => WriteToConsole(LogLevel.Detail, GetDiagnosticText(LogLevel.Detail, text, memberName, null)); - - public static void Debug(string text, [CallerMemberName] string? memberName = null) - => WriteToConsole(LogLevel.Debug, GetDiagnosticText(LogLevel.Debug, text, memberName, null)); - - public static void Info(string text, [CallerMemberName] string? memberName = null) - => WriteToConsole(LogLevel.Info, GetDiagnosticText(LogLevel.Info, text, memberName, null)); - - public static void Warning(string text, [CallerMemberName] string? memberName = null) - => WriteToConsole(LogLevel.Warning, GetDiagnosticText(LogLevel.Warning, text, memberName, null)); - - public static void Suggest(string text, [CallerMemberName] string? memberName = null) - => WriteToConsole(LogLevel.Suggest, GetDiagnosticText(LogLevel.Suggest, text, memberName, null)); - - public static void Error(string text, [CallerMemberName] string? memberName = null) - => WriteToConsole(LogLevel.Error, GetDiagnosticText(LogLevel.Error, text, memberName, null)); - - public static void Error(string text, Exception ex, [CallerMemberName] string? memberName = null) - => WriteToConsole(LogLevel.Error, GetDiagnosticText(LogLevel.Error, text, memberName, ex)); - - private static void WriteToConsole(LogLevel logLevel, string text) - { - if (logLevel < LogLevel) return; - - //lock (ForWriterLock) - { - //if (logLevel > LogLevel.Trace && logLevel < LogLevel.Suggest) - { - Console.WriteLine(text); - return; - } - - if (logLevel <= LogLevel.Trace) - { - Console.ForegroundColor = ConsoleColor.Gray; - Console.WriteLine(text); - } - else if (logLevel == LogLevel.Suggest) - { - Console.ForegroundColor = ConsoleColor.Cyan; - Console.WriteLine(text); - } - else - { - Console.ForegroundColor = logLevel == LogLevel.Warning ? ConsoleColor.Yellow : ConsoleColor.Red; - Console.WriteLine($"{AcEnv.NL}{text}{AcEnv.NL}"); - } - - Console.ForegroundColor = ConsoleColor.White; - } - } - - private static string GetDiagnosticText(LogLevel logLevel, string logText, string? callerName, Exception? ex) - { - var threadId = Environment.CurrentManagedThreadId; - - return $"[{DateTime.Now:HH:mm:ss.fff}] [{AppType.ToString()[0]}] {"[" + logLevel + "]",-9} {"[...->" + callerName + "]",-54} {"[" + threadId + "]",5} {logText}{ErrorText(ex)}"; - } - - private static string ErrorText(Exception? ex) - { - if (ex == null) return string.Empty; - - var errorType = ex.GetType().Name; - return string.IsNullOrWhiteSpace(errorType) ? string.Empty : $"{Environment.NewLine}[{errorType.ToUpper()}]: {ex}"; - } - } -} diff --git a/AyCode.Core/Loggers/AcConsoleLogWriter.cs b/AyCode.Core/Loggers/AcConsoleLogWriter.cs new file mode 100644 index 0000000..83d60b6 --- /dev/null +++ b/AyCode.Core/Loggers/AcConsoleLogWriter.cs @@ -0,0 +1,49 @@ +using AyCode.Core.Consts; +using AyCode.Core.Enums; +using AyCode.Utils.Extensions; + +namespace AyCode.Core.Loggers; + +public class AcConsoleLogWriter : AcTextLogWriterBase +{ + protected AcConsoleLogWriter() : this(null) + { } + + protected AcConsoleLogWriter(string? categoryName = null) : base(categoryName) + { } + + public AcConsoleLogWriter(AppType appType, LogLevel logLevel, string? categoryName = null) : base(appType, logLevel, categoryName) + { } + + protected override void WriteText(string? logText) + { + if (logText.IsNullOrWhiteSpace()) return; + + //lock (ForWriterLock) + { + //if (logLevel > LogLevel.Trace && logLevel < LogLevel.Suggest) + { + Console.WriteLine(logText); + return; + } + + if (LogLevel <= LogLevel.Trace) + { + Console.ForegroundColor = ConsoleColor.Gray; + Console.WriteLine(logText); + } + else if (LogLevel == LogLevel.Suggest) + { + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine(logText); + } + else + { + Console.ForegroundColor = LogLevel == LogLevel.Warning ? ConsoleColor.Yellow : ConsoleColor.Red; + Console.WriteLine($"{AcEnv.NL}{logText}{AcEnv.NL}"); + } + + Console.ForegroundColor = ConsoleColor.White; + } + } +} \ No newline at end of file diff --git a/AyCode.Core/Loggers/AcLogWriterBase.cs b/AyCode.Core/Loggers/AcLogWriterBase.cs new file mode 100644 index 0000000..55fa795 --- /dev/null +++ b/AyCode.Core/Loggers/AcLogWriterBase.cs @@ -0,0 +1,81 @@ +using System.Runtime.CompilerServices; +using AyCode.Core.Consts; +using AyCode.Core.Enums; + +namespace AyCode.Core.Loggers; + +public abstract class AcLogWriterBase : IAcLogWriterBase +{ + public string? CategoryName { get; } + + protected AppType AppType { get; set; } = AppType.Server; + protected LogLevel LogLevel { get; set; } = LogLevel.Error; + + protected AcLogWriterBase() : this(null) + {} + + protected AcLogWriterBase(string? categoryName = null) + { + CategoryName = categoryName; + + AppType = AcEnv.AppConfiguration.GetEnum("AyCode:Logger:AppType"); + + //AppType = (AppType)Enum.Parse(typeof(AppType), AcEnv.AppConfiguration["AyCode:Logger:AppType"], true); + + var writerSettings = AcEnv.AppConfiguration.GetSection("AyCode:Logger:LogWriters") + .GetChildren() + .FirstOrDefault(logWriter=> (logWriter["LogWriterType"].ToLower()).Equals(this.GetType().AssemblyQualifiedName, StringComparison.CurrentCultureIgnoreCase)); + + LogLevel = writerSettings.GetEnum("LogLevel"); + } + + protected AcLogWriterBase(AppType appType, LogLevel logLevel, string? categoryName = null) + { + AppType = appType; + LogLevel = logLevel; + + CategoryName = categoryName; + } + + public void Detail(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null) + => PrepareToWrite(LogLevel.Detail, text, memberName, categoryName ?? CategoryName); + + //public void Detail(string? text, [CallerMemberName] string? memberName = null) where TCallerClassType : class + // => Detail(text, typeof(TCallerClassType).Name, memberName); + + public void Debug(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null) + => PrepareToWrite(LogLevel.Debug, text, memberName, categoryName ?? CategoryName); + + //public void Debug(string? text, [CallerMemberName] string? memberName = null) where TCallerClassType : class + // => Debug(text, typeof(TCallerClassType).Name, memberName); + + public void Info(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null) + => PrepareToWrite(LogLevel.Info, text, memberName, categoryName ?? CategoryName); + + //public void Info(string? text, [CallerMemberName] string? memberName = null) where TCallerClassType : class + // => Info(text, typeof(TCallerClassType).Name, memberName); + + public void Warning(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null) + => PrepareToWrite(LogLevel.Warning, text, memberName, categoryName ?? CategoryName); + + //public void Warning(string? text, [CallerMemberName] string? memberName = null) where TCallerClassType : class + // => Warning(text, typeof(TCallerClassType).Name, memberName); + + public void Suggest(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null) + => PrepareToWrite(LogLevel.Suggest, text, memberName, categoryName ?? CategoryName); + + //public void Suggest(string? text, [CallerMemberName] string? memberName = null) where TCallerClassType : class + // => Suggest(text, typeof(TCallerClassType).Name, memberName); + + //public void Error(string? text, Exception? ex = null, [CallerMemberName] string? memberName = null) where TCallerClassType : class + // => Error(text, ex, typeof(TCallerClassType).Name, memberName); + + public void Error(string? text, Exception? ex = null, string? categoryName = null, [CallerMemberName] string? memberName = null) + => PrepareToWrite(LogLevel.Error, text, memberName, categoryName ?? CategoryName, ex); + + + protected virtual void PrepareToWrite(LogLevel logLevel, string? logText, string? callerMemberName, string? categoryName = null, Exception? ex = null) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/AyCode.Core/Loggers/AcLoggerBase.cs b/AyCode.Core/Loggers/AcLoggerBase.cs new file mode 100644 index 0000000..2f345a4 --- /dev/null +++ b/AyCode.Core/Loggers/AcLoggerBase.cs @@ -0,0 +1,101 @@ +using System.Runtime.CompilerServices; +using AyCode.Core.Consts; +using AyCode.Core.Enums; + +namespace AyCode.Core.Loggers; + +public abstract class AcLoggerBase : IAcLoggerBase +{ + protected readonly List LogWriters = []; + + public LogLevel LogLevel { get; set; } = LogLevel.Error; + public AppType AppType { get; set; } = AppType.Server; + + public string? CategoryName { get; set; } + + protected AcLoggerBase() : this(null) + { } + + protected AcLoggerBase(string? categoryName) + { + CategoryName = categoryName; + + AppType = AcEnv.AppConfiguration.GetEnum("AyCode:Logger:AppType"); + LogLevel = AcEnv.AppConfiguration.GetEnum("AyCode:Logger:LogLevel"); + + foreach (var logWriter in AcEnv.AppConfiguration.GetSection("AyCode:Logger:LogWriters").GetChildren()) + { + var logWriterType = Type.GetType(logWriter["LogWriterType"]); + var logWriterLogLevel = logWriter.GetEnum("LogLevel"); + + LogWriters.Add(Activator.CreateInstance(logWriterType, AppType, logWriterLogLevel, CategoryName) as IAcLogWriterBase); + } + } + + protected AcLoggerBase(string? categoryName, params IAcLogWriterBase[] logWriters) : + this(AcEnv.AppConfiguration.GetEnum("AyCode:Logger:AppType"), AcEnv.AppConfiguration.GetEnum("AyCode:Logger:LogLevel"), categoryName, logWriters) + { } + + protected AcLoggerBase(AppType appType, LogLevel logLevel, string? categoryName, params IAcLogWriterBase[] logWriters) + { + AppType = appType; + LogLevel = logLevel; + + CategoryName = categoryName; + + foreach (var acLogWriterBase in logWriters) + LogWriters.Add(acLogWriterBase); + } + + public List GetWriters => [.. LogWriters]; + public TLogWriter Writer() where TLogWriter : IAcLogWriterBase => LogWriters.OfType().First(); + + public virtual void Detail(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null) + { + if (LogLevel <= LogLevel.Detail) LogWriters.ForEach(x => x.Detail(text, categoryName ?? CategoryName, memberName)); + } + + //public virtual void Detail(string? text, [CallerMemberName] string? memberName = null) where TCallerClassType : class + // => Detail(text, typeof(TCallerClassType).Name, memberName); + + public virtual void Debug(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null) + { + if (LogLevel <= LogLevel.Debug) LogWriters.ForEach(x => x.Debug(text, categoryName ?? CategoryName, memberName)); + } + + //public virtual void Debug(string? text, [CallerMemberName] string? memberName = null) where TCallerClassType : class + // => Debug(text, typeof(TCallerClassType).Name, memberName); + + public virtual void Info(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null) + { + if (LogLevel <= LogLevel.Info) LogWriters.ForEach(x => x.Info(text, categoryName ?? CategoryName, memberName)); + } + + //public virtual void Info(string? text, [CallerMemberName] string? memberName = null) where TCallerClassType : class + // => Info(text, typeof(TCallerClassType).Name, memberName); + + public virtual void Warning(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null) + { + if (LogLevel <= LogLevel.Warning) LogWriters.ForEach(x => x.Warning(text, categoryName ?? CategoryName, memberName)); + } + + //public virtual void Warning(string? text, [CallerMemberName] string? memberName = null) where TCallerClassType : class + // => Warning(text, typeof(TCallerClassType).Name, memberName); + + public virtual void Suggest(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null) + { + if (LogLevel <= LogLevel.Suggest) LogWriters.ForEach(x => x.Suggest(text, categoryName ?? CategoryName, memberName)); + } + + //public virtual void Suggest(string? text, [CallerMemberName] string? memberName = null) where TCallerClassType : class + // => Suggest(text, typeof(TCallerClassType).Name, memberName); + + + public virtual void Error(string? text, Exception? ex = null, string? categoryName = null, [CallerMemberName] string? memberName = null) + { + if (LogLevel <= LogLevel.Error) LogWriters.ForEach(x => x.Error(text, ex, categoryName ?? CategoryName, memberName)); + } + + //public virtual void Error(string? text, Exception? ex = null, [CallerMemberName] string? memberName = null) where TCallerClassType : class + // => Error(text, ex, typeof(TCallerClassType).Name, memberName); +} \ No newline at end of file diff --git a/AyCode.Core/Loggers/AcTextLogWriterBase.cs b/AyCode.Core/Loggers/AcTextLogWriterBase.cs new file mode 100644 index 0000000..a02e5ef --- /dev/null +++ b/AyCode.Core/Loggers/AcTextLogWriterBase.cs @@ -0,0 +1,49 @@ +using AyCode.Core.Enums; +using AyCode.Utils.Extensions; + +namespace AyCode.Core.Loggers; + +public abstract class AcTextLogWriterBase : AcLogWriterBase +{ + protected AcTextLogWriterBase() : this(null) + { } + + protected AcTextLogWriterBase(string? categoryName = null) : base(categoryName) + { } + + protected AcTextLogWriterBase(AppType appType, LogLevel logLevel, string? categoryName = null) : base(appType, logLevel, categoryName) + { } + + protected override void PrepareToWrite(LogLevel logLevel, string? logText, string? callerMemberName, string? categoryName = null, Exception? ex = null) + { + if (logLevel < LogLevel) return; + + WriteText(GetDiagnosticText(logLevel, logText, callerMemberName, categoryName)); + + } + + protected virtual void WriteText(string? logText) + { + throw new NotImplementedException(); + } + + + protected virtual string GetDiagnosticText(LogLevel logLevel, string? logText, string? callerMemberName, string? categoryName = null, Exception? ex = null) + { + if (LogLevel > logLevel) return string.Empty; + + var threadId = Environment.CurrentManagedThreadId; + + if(categoryName.IsNullOrWhiteSpace()) categoryName = "..."; + + return $"[{DateTime.Now:HH:mm:ss.fff}] [{AppType.ToString()[0]}] {"[" + logLevel + "]",-9} {"[" + categoryName + "->" + callerMemberName + "]",-54} {"[" + threadId + "]",5} {logText}{ErrorText(ex)}"; + } + + protected virtual string ErrorText(Exception? ex) + { + if (ex == null) return string.Empty; + + var errorType = ex.GetType().Name; + return string.IsNullOrWhiteSpace(errorType) ? string.Empty : $"{Environment.NewLine}[{errorType.ToUpper()}]: {ex}"; + } +} \ No newline at end of file diff --git a/AyCode.Core/Loggers/IAcLogWriterBase.cs b/AyCode.Core/Loggers/IAcLogWriterBase.cs new file mode 100644 index 0000000..216f495 --- /dev/null +++ b/AyCode.Core/Loggers/IAcLogWriterBase.cs @@ -0,0 +1,26 @@ +using System.Runtime.CompilerServices; + +namespace AyCode.Core.Loggers; + +public interface IAcLogWriterBase +{ + public string? CategoryName { get; } + + public void Detail(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null); + //public void Detail(string? text, [CallerMemberName] string? memberName = null) where TCallerClassType : class; + + public void Debug(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null); + //public void Debug(string? text, [CallerMemberName] string? memberName = null) where TCallerClassType : class; + + public void Info(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null); + //public void Info(string? text, [CallerMemberName] string? memberName = null) where TCallerClassType : class; + + public void Warning(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null); + //public void Warning(string? text, [CallerMemberName] string? memberName = null) where TCallerClassType : class; + + public void Suggest(string? text, string? categoryName = null, [CallerMemberName] string? memberName = null); + //public void Suggest(string? text, [CallerMemberName] string? memberName = null) where TCallerClassType : class; + + public void Error(string? text, Exception? ex = null, string? categoryName = null, [CallerMemberName] string? memberName = null); + //public void Error(string? text, Exception? ex = null, [CallerMemberName] string? memberName = null) where TCallerClassType : class; +} \ No newline at end of file diff --git a/AyCode.Core/Loggers/IAcLoggerBase.cs b/AyCode.Core/Loggers/IAcLoggerBase.cs new file mode 100644 index 0000000..84893ab --- /dev/null +++ b/AyCode.Core/Loggers/IAcLoggerBase.cs @@ -0,0 +1,7 @@ +namespace AyCode.Core.Loggers; + +public interface IAcLoggerBase : IAcLogWriterBase +{ + public List GetWriters { get; } + public TLogWriter Writer() where TLogWriter : IAcLogWriterBase; +} \ No newline at end of file diff --git a/AyCode.Core/Logger/LogLevel.cs b/AyCode.Core/Loggers/LogLevel.cs similarity index 91% rename from AyCode.Core/Logger/LogLevel.cs rename to AyCode.Core/Loggers/LogLevel.cs index ac80d8a..efee4c7 100644 --- a/AyCode.Core/Logger/LogLevel.cs +++ b/AyCode.Core/Loggers/LogLevel.cs @@ -1,4 +1,4 @@ -namespace AyCode.Core.Logger +namespace AyCode.Core.Loggers { /// /// Az adatbásisban van egy LogLevel tábla, ha változtatunk az enum-ok értékén, akkor ott is igazítsuk hozzá! diff --git a/AyCode.Database/AcDbLogItemWriter.cs b/AyCode.Database/AcDbLogItemWriter.cs new file mode 100644 index 0000000..0afe982 --- /dev/null +++ b/AyCode.Database/AcDbLogItemWriter.cs @@ -0,0 +1,57 @@ +using AyCode.Core.Consts; +using AyCode.Core.Enums; +using AyCode.Core.Helpers; +using AyCode.Core.Loggers; +using AyCode.Database.DbContexts.Loggers; +using AyCode.Entities; +using AyCode.Entities.LogItems; +using AyCode.Interfaces.Entities; + +namespace AyCode.Database; + +public class AcDbLogItemWriter : AcLogItemWriterBase where TLoggerDbContext : AcLoggerDbContextBase + where TLogItem : class, IAcLogItem +{ + private TLoggerDbContext _ctx = Activator.CreateInstance(); + + protected AcDbLogItemWriter() : this(null) + { } + + protected AcDbLogItemWriter(string? categoryName = null) : base(categoryName) + { } + + public AcDbLogItemWriter(AppType appType, LogLevel logLevel, string? categoryName = null) : base(appType, logLevel, categoryName) + { } + + protected override void WriteLogItem(TLogItem logItem, Action? callback = null) + { + try + { + base.WriteLogItem(logItem, () => + { + _ctx.LogItems.Add(logItem); + _ctx.SaveChanges(); + }); + } + catch (Exception ex) + { + Console.WriteLine("ERRORORROROR! " + AcEnv.NL + ex.Message); + } + } + + //protected override void WriteLogItem(TLogItem logItem, Action>? callback = null) + //{ + // try + // { + // base.WriteLogItem(logItem, logItems => + // { + // _ctx.LogItems.AddRange(logItems); + // _ctx.SaveChanges(); + // }); + // } + // catch (Exception ex) + // { + // Console.WriteLine("ERRORORRORO"); + // } + //} +} \ No newline at end of file diff --git a/AyCode.Database/AyCode.Database.csproj b/AyCode.Database/AyCode.Database.csproj index da90f0b..a3f8139 100644 --- a/AyCode.Database/AyCode.Database.csproj +++ b/AyCode.Database/AyCode.Database.csproj @@ -26,6 +26,7 @@ + diff --git a/AyCode.Database/DataLayers/Users/AcUserDalBase.cs b/AyCode.Database/DataLayers/Users/AcUserDalBase.cs index a3b7a80..beb5338 100644 --- a/AyCode.Database/DataLayers/Users/AcUserDalBase.cs +++ b/AyCode.Database/DataLayers/Users/AcUserDalBase.cs @@ -11,6 +11,8 @@ using Microsoft.EntityFrameworkCore; using AyCode.Database.Extensions; using AyCode.Core.Consts; using AyCode.Core.Helpers; +using AyCode.Core.Loggers; +using AyCode.Core.Server.Loggers; using AyCode.Database.DbSets.Users; using AyCode.Interfaces.Addresses; using AyCode.Interfaces.Messages; @@ -141,6 +143,7 @@ namespace AyCode.Database.DataLayers.Users } catch (Exception ex) { + GlobalLogger.Error(ex.Message, ex); errorCodeInner = AcErrorCode.UnknownError; } diff --git a/AyCode.Database/DbContexts/Loggers/AcLoggerDbContextBase.cs b/AyCode.Database/DbContexts/Loggers/AcLoggerDbContextBase.cs new file mode 100644 index 0000000..3afe9c0 --- /dev/null +++ b/AyCode.Database/DbContexts/Loggers/AcLoggerDbContextBase.cs @@ -0,0 +1,11 @@ +using AyCode.Database.DbSets.Loggers; +using AyCode.Entities.LogItems; +using AyCode.Interfaces.Entities; +using Microsoft.EntityFrameworkCore; + +namespace AyCode.Database.DbContexts.Loggers; + +public class AcLoggerDbContextBase : AcDbContextBase, IAcLoggerDbContextBase where TLogItem : class, IAcLogItem +{ + public DbSet LogItems { get; set; } +} \ No newline at end of file diff --git a/AyCode.Database/DbContexts/Loggers/IAcLoggerDbContextBase.cs b/AyCode.Database/DbContexts/Loggers/IAcLoggerDbContextBase.cs new file mode 100644 index 0000000..e9f69a5 --- /dev/null +++ b/AyCode.Database/DbContexts/Loggers/IAcLoggerDbContextBase.cs @@ -0,0 +1,10 @@ +using AyCode.Database.DbSets.Loggers; +using AyCode.Entities.LogItems; +using AyCode.Interfaces.Entities; + +namespace AyCode.Database.DbContexts.Loggers; + +public interface IAcLoggerDbContextBase : IAcLogItemDbSetBase where TLogItem : class, IAcLogItem +{ + +} \ No newline at end of file diff --git a/AyCode.Database/DbSets/Loggers/IAcLogItemDbSetBase.cs b/AyCode.Database/DbSets/Loggers/IAcLogItemDbSetBase.cs new file mode 100644 index 0000000..dfa0e0e --- /dev/null +++ b/AyCode.Database/DbSets/Loggers/IAcLogItemDbSetBase.cs @@ -0,0 +1,11 @@ +using AyCode.Entities.LogItems; +using AyCode.Interfaces.Entities; +using AyCode.Interfaces.Users; +using Microsoft.EntityFrameworkCore; + +namespace AyCode.Database.DbSets.Loggers; + +public interface IAcLogItemDbSetBase where TLogItem : class, IAcLogItem +{ + DbSet LogItems { get; set; } +} \ No newline at end of file diff --git a/AyCode.Database/DbSets/Users/AcUserDbSetExtensions.cs b/AyCode.Database/DbSets/Users/AcUserDbSetExtensions.cs index fcc56de..1f9613a 100644 --- a/AyCode.Database/DbSets/Users/AcUserDbSetExtensions.cs +++ b/AyCode.Database/DbSets/Users/AcUserDbSetExtensions.cs @@ -1,5 +1,6 @@ using AyCode.Core.Extensions; -using AyCode.Core.Logger; +using AyCode.Core.Loggers; +using AyCode.Core.Server.Loggers; using AyCode.Database.Extensions; using AyCode.Entities; using AyCode.Entities.Users; @@ -45,7 +46,7 @@ public static class AcUserDbSetExtensions public static IQueryable? GetQueryableUserByEmail(this IAcUserDbSetBase ctx, string? email, bool onlyConfirmed) where TUser : class, IAcUserBase { - Logger.Info($"GetUserByEmail: {email}"); + GlobalLogger.Info($"GetUserByEmail: {email}"); if (string.IsNullOrWhiteSpace(email)) return null; @@ -57,7 +58,7 @@ public static class AcUserDbSetExtensions { var emailLower = user.EmailAddress.ToLower(); - Logger.Info($"GetUserByEmail: {emailLower}"); + GlobalLogger.Info($"GetUserByEmail: {emailLower}"); return ctx.Users.Add(user).State == Microsoft.EntityFrameworkCore.EntityState.Added; } @@ -86,7 +87,7 @@ public static class AcUserDbSetExtensions public static TUser? UpdateJwtRefreshToken(this IAcUserDbSetBase ctx, string email, string refreshToken) where TUser : class, IAcUserBase { - Console.WriteLine(@"UserDal Update refresh token"); + GlobalLogger.Info(@"UserDal Update refresh token"); if (string.IsNullOrWhiteSpace(refreshToken)) return null; diff --git a/AyCode.Database/Extensions/AcDbSessionExtension.cs b/AyCode.Database/Extensions/AcDbSessionExtension.cs index 411508c..99ef685 100644 --- a/AyCode.Database/Extensions/AcDbSessionExtension.cs +++ b/AyCode.Database/Extensions/AcDbSessionExtension.cs @@ -1,6 +1,7 @@ using AyCode.Core.Consts; using AyCode.Core.Helpers; -using AyCode.Core.Logger; +using AyCode.Core.Loggers; +using AyCode.Core.Server.Loggers; using AyCode.Database.DbContexts; using AyCode.Interfaces.Entities; @@ -22,7 +23,7 @@ public static class AcDbSessionExtension catch (Exception ex) { var errorText = $"Session({ctx}) callback error...{AcEnv.NL}"; - Logger.Error($"{errorText}", ex); + GlobalLogger.Error($"{errorText}", ex); throw new Exception($"{errorText}{ex}"); } diff --git a/AyCode.Database/Extensions/AcDbTransactionExtension.cs b/AyCode.Database/Extensions/AcDbTransactionExtension.cs index 4814cef..a6f8e9d 100644 --- a/AyCode.Database/Extensions/AcDbTransactionExtension.cs +++ b/AyCode.Database/Extensions/AcDbTransactionExtension.cs @@ -2,8 +2,9 @@ using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore; using AyCode.Database.DbContexts; -using AyCode.Core.Logger; using AyCode.Core.Consts; +using AyCode.Core.Loggers; +using AyCode.Core.Server.Loggers; namespace AyCode.Database.Extensions; @@ -45,7 +46,7 @@ public static class AcDbTransactionExtension transaction.Rollback(); if (throwException) throw new Exception(errorText, ex); - Logger.Error($"{errorText}", ex); + GlobalLogger.Error($"{errorText}", ex); } return result; } @@ -65,7 +66,7 @@ public static class AcDbTransactionExtension else { transaction.Rollback(); - Logger.Warning($"Transaction({ctx}) transaction ROLLBACK!"); + GlobalLogger.Warning($"Transaction({ctx}) transaction ROLLBACK!"); } } catch (Exception ex) @@ -73,7 +74,7 @@ public static class AcDbTransactionExtension if (throwException) throw; result = false; - Logger.Error($"Transaction({ctx}) transaction error...{AcEnv.NL}", ex); + GlobalLogger.Error($"Transaction({ctx}) transaction error...{AcEnv.NL}", ex); } finally { diff --git a/AyCode.Entities/AcLogItemWriterBase.cs b/AyCode.Entities/AcLogItemWriterBase.cs new file mode 100644 index 0000000..ca19a99 --- /dev/null +++ b/AyCode.Entities/AcLogItemWriterBase.cs @@ -0,0 +1,89 @@ +using AyCode.Core.Enums; +using AyCode.Core.Helpers; +using AyCode.Core.Loggers; +using AyCode.Entities.LogItems; +using AyCode.Interfaces.Entities; +using AyCode.Utils.Extensions; +using System.Collections.Concurrent; + +namespace AyCode.Entities; + +public abstract class AcLogItemWriterBase : AcLogWriterBase where TLogItem : class, IAcLogItem +{ + protected readonly Mutex MutexLock = new();//new(false, "GLOBAL"); + + protected AcLogItemWriterBase() : this(null) + { } + + protected AcLogItemWriterBase(string? categoryName = null) : base(categoryName) + { } + + protected AcLogItemWriterBase(AppType appType, LogLevel logLevel, string? categoryName = null) : base(appType, logLevel, categoryName) + { + } + + protected TLogItem CreateLogItem(int threadId, DateTime utcNow, LogLevel logLevel, string? logText, string? callerMemberName, string? categoryName = null, Exception? ex = null) + { + var logItem = Activator.CreateInstance(); + + logItem.TimeStampUtc = utcNow; + logItem.AppType = AppType; + logItem.LogLevel = logLevel; + logItem.CategoryName = categoryName; + logItem.CallerName = callerMemberName; + logItem.Text = logText; + logItem.Exception = ex?.Message; + logItem.ThreadId = threadId; + + return logItem; + } + + protected override void PrepareToWrite(LogLevel logLevel, string? logText, string? callerMemberName, string? categoryName = null, Exception? ex = null) + { + if (logLevel < LogLevel) return; + + var utcNow = DateTime.UtcNow; + var threadId = Environment.CurrentManagedThreadId; + + TaskHelper.RunOnThreadPool(() => WriteLogItem(CreateLogItem(threadId, utcNow, logLevel, logText, callerMemberName, categoryName))); + } + + protected virtual void WriteLogItem(TLogItem logItem, Action? callback = null) + { + using (MutexLock.UseWaitOne()) + { + callback?.Invoke(); + } + } + + //private volatile bool _isLocked = false; + //private readonly object _forLock = new(); + //private readonly List _logItemsCahce = new(); + //private readonly List _logItemsCahce2 = new(); + + //protected virtual void WriteLogItem(TLogItem logItem, Action>? callback = null) + //{ + // lock (_forLock) _logItemsCahce.Add(logItem); + + // if (_isLocked) return; + + + // using (MutexLock.UseWaitOne()) + // { + // _isLocked = true; + + // _logItemsCahce2.Clear(); + + // lock (_forLock) + // { + // _logItemsCahce2.AddRange(_logItemsCahce); + + // _logItemsCahce.Clear(); + // } + + // callback?.Invoke(_logItemsCahce2); + // } + + // _isLocked = false; + //} +} \ No newline at end of file diff --git a/AyCode.Entities/AyCode.Entities.csproj b/AyCode.Entities/AyCode.Entities.csproj index 1437f67..02a1e29 100644 --- a/AyCode.Entities/AyCode.Entities.csproj +++ b/AyCode.Entities/AyCode.Entities.csproj @@ -12,6 +12,7 @@ + diff --git a/AyCode.Entities/LogItems/AcLogItem.cs b/AyCode.Entities/LogItems/AcLogItem.cs new file mode 100644 index 0000000..c3182d1 --- /dev/null +++ b/AyCode.Entities/LogItems/AcLogItem.cs @@ -0,0 +1,24 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using AyCode.Core.Enums; +using AyCode.Core.Interfaces; +using AyCode.Core.Loggers; + +namespace AyCode.Entities.LogItems; + +[Table("LogItem")] +public class AcLogItem : IAcLogItem +{ + [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id { get; set; } + + public int LogHeaderId { get; set; } + public DateTime TimeStampUtc { get; set; } + public AppType AppType { get; set; } + public LogLevel LogLevel { get; set; } + public int ThreadId { get; set; } + public string? CategoryName { get; set; } + public string? CallerName { get; set; } + public string? Text { get; set; } + public string? Exception { get; set; } +} \ No newline at end of file diff --git a/AyCode.Entities/LogItems/IAcLogItem.cs b/AyCode.Entities/LogItems/IAcLogItem.cs new file mode 100644 index 0000000..1664ac7 --- /dev/null +++ b/AyCode.Entities/LogItems/IAcLogItem.cs @@ -0,0 +1,18 @@ +using AyCode.Core.Enums; +using AyCode.Core.Loggers; +using AyCode.Interfaces.Entities; + +namespace AyCode.Entities.LogItems; + +public interface IAcLogItem : IEntityInt +{ + public int LogHeaderId { get; set; } + public DateTime TimeStampUtc { get; set; } + public AppType AppType { get; set; } + public LogLevel LogLevel { get; set; } + public int ThreadId { get; set; } + public string? CategoryName { get; set; } + public string? CallerName { get; set; } + public string? Text { get; set; } + public string? Exception { get; set; } +} \ No newline at end of file diff --git a/AyCode.Services.Server/Emails/AcEmailServiceServer.cs b/AyCode.Services.Server/Emails/AcEmailServiceServer.cs index 1951686..bf2d89c 100644 --- a/AyCode.Services.Server/Emails/AcEmailServiceServer.cs +++ b/AyCode.Services.Server/Emails/AcEmailServiceServer.cs @@ -19,7 +19,7 @@ public class AcEmailServiceServer() : IAcEmailServiceServer _sendGridClient = new SendGridClient(configuration["SendGrid:Key"]); _fromEmailAddress = new EmailAddress(configuration["SendGrid:FromEmail"], configuration["SendGrid:FromName"]); - //Console.WriteLine($"{config.ServerUserName}; {config.FromEmail}; {config.FromName}"); + //Logger.Info($"{config.ServerUserName}; {config.FromEmail}; {config.FromName}"); } public async Task SendLostPasswordEmailAsync(string addressEmail, string verificationToken) diff --git a/AyCode.Services.Server/Logins/AcLoginServiceServer.cs b/AyCode.Services.Server/Logins/AcLoginServiceServer.cs index 8dd69ce..26d3e57 100644 --- a/AyCode.Services.Server/Logins/AcLoginServiceServer.cs +++ b/AyCode.Services.Server/Logins/AcLoginServiceServer.cs @@ -18,6 +18,8 @@ using Microsoft.EntityFrameworkCore; using AyCode.Database.DbContexts; using AyCode.Core.Consts; using AyCode.Core.Extensions; +using AyCode.Core.Loggers; +using AyCode.Core.Server.Loggers; using AyCode.Database.DataLayers.Users; using AyCode.Database.DbContexts.Users; using AyCode.Interfaces.Messages; @@ -124,13 +126,13 @@ public class AcLoginServiceServer { @@ -149,7 +151,7 @@ public class AcLoginServiceServer : AcLogItemWriterBase where TLogItem : class, IAcLogItem +{ + protected HttpClient _httpClient; + protected readonly HttpClientHandler _httpClientHandler; + + protected AcHttpClientLogItemWriter(HttpClient httpClient) : base(AppType.Web, LogLevel.Detail) + { + _httpClient = httpClient; + } + + protected AcHttpClientLogItemWriter(string? categoryName = null) : base(categoryName) + { + _httpClientHandler = new HttpClientHandler(); + _httpClient = new HttpClient(_httpClientHandler, false); + } + + protected AcHttpClientLogItemWriter(AppType appType, LogLevel logLevel, string? categoryName = null) : base(appType, logLevel, categoryName) + { + _httpClientHandler = new HttpClientHandler(); + _httpClient = new HttpClient(_httpClientHandler, false); + } + + + //protected override void WriteLogItem(TLogItem logItem, Action? callback = null) + //{ + // //throw new NotImplementedException(); + + // base.WriteLogItem(logItem, () => + // { + // //http.PostAsJson(url, Param); + // //_httpClient.Send() + // }); + //} + + //protected override void WriteLogItem(TLogItem logItem, Action>? callback = null) + //{ + // throw new NotImplementedException(); + + // base.WriteLogItem(logItem, logItems => + // { + // //_httpClient.Send() + // }); + //} +} \ No newline at end of file