using HRD.AppLogger; using NLog; using NLog.Config; using NLog.Targets; using System; using System.Collections.Generic; using System.IO; namespace HRD.AppLogger { public enum EN_LoggingLevel { Trace = 1, Debug = 2, Info = 3, Warn = 4, Error = 5, Fatal = 6, Off = 7 } } public static class AppLoggerConfig { private static readonly string DBLOG_CommandText = @" INSERT INTO dbo.DBLog ( MachineName, Application, Logged, Level, Message, Logger, CallSite, Webrequest, Stacktrace, InnerException, Exception, Version, Entity ) VALUES ( @machineName, @application, @logged, @level, @message, @logger, @callsite, iif(@webrequestaction='',@webrequest, concat(@webrequest,' | action:',@webrequestaction)), @stacktrace, @innerException, @exception, @Version, @Entity );"; private static readonly Dictionary DBLOG_Parameters = new Dictionary() { //Globals {"@version", "${gdc:item=Version}"}, {"@application", "${gdc:item=Application}"}, //Local //{"@webrequest", "${mdlc:item=Webrequest}"}, {"@entity", "${mdlc:item=Entity}"}, //WebApi {"@webrequest", "${aspnet-request-url}"}, {"@webrequestaction", "${aspnet-mvc-action}"}, //Nlog {"@machineName", "${machinename}" }, {"@logged", "${date}"}, {"@level", "${level:upperCase=true}"}, {"@message", "${message}"}, {"@logger", "${logger}"}, {"@callSite", "${callsite:fileName=true:includeSourcePath=false:skipFrames=1}"}, //{"@callSite", "${callsite:filename=false:className=true:methodName=true}"}, {"@stacktrace", "${stacktrace:topFrames=10}"}, {"@InnerException", "${exception:format=Message,StackTrace,Data:maxInnerExceptionLevel=10}"}, {"@Exception", "${exception:format=ToString}"}, }; public static string AssemblyName { get; set; } public static string AssemblyVersion { get; set; } public static EN_LoggingLevel DBLogLevel { get; set; } = EN_LoggingLevel.Warn; public static EN_LoggingLevel FileLogLevel { get; set; } = EN_LoggingLevel.Error; public static string LogDirectory { get; set; } = String.Empty; public static string NlogConnectionstring { get; set; } public static LogLevel NlogDBLogLevel { get; set; } public static LogLevel NlogFileLogLevel { get; set; } public static NlogSentryConfig NlogSentryConfig { get; set; } = new NlogSentryConfig(); public static LoggingConfiguration CreateConfig() { NlogDBLogLevel = MapLogLevel(DBLogLevel); NlogFileLogLevel = MapLogLevel(FileLogLevel); var config = new LoggingConfiguration(); DatabaseTarget dbTarget = CreateDatabaseTarget(config); var dbRule = new LoggingRule("*", NlogDBLogLevel, dbTarget); config.LoggingRules.Add(dbRule); //Rules FileTarget targetFile = CreateFileTarget(config); var rule = new LoggingRule("*", NlogFileLogLevel, targetFile); config.LoggingRules.Add(rule); if (NlogSentryConfig.NlogSentryIsEnable) { AddSentry(config); } return config; } public static void Init( string assemblyName, string assemblyVersion, EN_LoggingLevel dbLogLevel = EN_LoggingLevel.Warn , EN_LoggingLevel fileLoogLevel = EN_LoggingLevel.Off , string logDirectory = "") { AssemblyVersion = assemblyVersion; AssemblyName = assemblyName; DBLogLevel = dbLogLevel; FileLogLevel = fileLoogLevel; LogDirectory = logDirectory; } private static void AddSentry(LoggingConfiguration config) { config.AddSentry(o => { o.Dsn = NlogSentryConfig.Dsn; o.Layout = "${message}"; o.BreadcrumbLayout = "${logger}: ${message} #url: ${aspnet-request-url} | #action: ${aspnet-mvc-action}"; // Optionally specify a separate format for breadcrumbs o.MinimumBreadcrumbLevel = NlogSentryConfig.MinimumBreadcrumbLevel; // Debug and higher are stored as breadcrumbs (default is Info) o.MinimumEventLevel = NlogSentryConfig.MinimumEventLevel; // Error and higher is sent as event (default is Error) // If DSN is not set, the SDK will look for an environment variable called SENTRY_DSN. If // nothing is found, SDK is disabled. o.AttachStacktrace = NlogSentryConfig.AttachStacktrace; o.SendDefaultPii = NlogSentryConfig.SendDefaultPii; // Send Personal Identifiable information like the username of the user logged in to the device o.IncludeEventDataOnBreadcrumbs = NlogSentryConfig.IncludeEventDataOnBreadcrumbs; // Optionally include event properties with breadcrumbs o.ShutdownTimeoutSeconds = 5; o.TracesSampleRate = 0.3; //Optionally specify user properties via NLog (here using MappedDiagnosticsLogicalContext as an example) // o.User = new SentryNLogUser // { // Id = "${mdlc:item=id}", // Username = "${mdlc:item=username}", // Email = "${mdlc:item=email}", // IpAddress = "${mdlc:item=ipAddress}", // Other = //{ // new TargetPropertyWithContext("mood", "joyous") //}, //}; o.AddTag("Backend", "${gdc:item=Application}"); // Send the logger name as a tag o.AddTag("BackendVersion", "${gdc:item=Version}"); // Send the logger name as a tag o.AddTag("logger", "${logger}"); // Send the logger name as a tag // Other configuration }); } private static DatabaseTarget CreateDatabaseTarget(LoggingConfiguration config) { var dbTarget = new DatabaseTarget { ConnectionString = NlogConnectionstring, CommandText = DBLOG_CommandText }; foreach (var item in DBLOG_Parameters) { dbTarget.Parameters.Add(new DatabaseParameterInfo(item.Key, item.Value)); } config.AddTarget("database", dbTarget); return dbTarget; } private static FileTarget CreateFileTarget(LoggingConfiguration config) { var targetFile = new FileTarget { FileName = Path.Combine( !string.IsNullOrEmpty(LogDirectory) ? LogDirectory : "${basedir}/_logs/", "${gdc:item=Application}" + "_V." + "${gdc:item=Version}" + $"_{DateTime.Now:yyyyMMdd}.log"), Layout = "${date}|${uppercase:${level}}|${stacktrace}|${message}" + "|${exception:format=Message,StackTrace,Data:maxInnerExceptionLevel=10}" + "${event-properties:item=EventId.Id}" }; config.AddTarget("logfile", targetFile); return targetFile; } private static LogLevel MapLogLevel(EN_LoggingLevel loggingLevel) { LogLevel logLevel = LogLevel.Error; switch (loggingLevel) { case EN_LoggingLevel.Trace: logLevel = LogLevel.Trace; break; case EN_LoggingLevel.Debug: logLevel = LogLevel.Debug; break; case EN_LoggingLevel.Info: logLevel = LogLevel.Info; break; case EN_LoggingLevel.Warn: logLevel = LogLevel.Warn; break; case EN_LoggingLevel.Error: logLevel = LogLevel.Error; break; case EN_LoggingLevel.Fatal: logLevel = LogLevel.Fatal; break; case EN_LoggingLevel.Off: logLevel = LogLevel.Off; break; default: break; } return logLevel; } public static void SetSentryUser(int id, string login, string email, IDictionary others = null) { NlogSentryConfig.SentryUser = new Sentry.User { Id = id.ToString(), Username = login, Email = email }; if (others != null) NlogSentryConfig.SentryUser.Other = others; Sentry.SentrySdk.ConfigureScope(scope => { scope.User = NlogSentryConfig.SentryUser; }); } }