using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using Newtonsoft.Json;
using NLog;
using NLog.Config;
using NLog.Layouts;
using NLog.Targets;
using NLog.Targets.GraylogHttp;
using NLog.Targets.Wrappers;
namespace BIMLIB.Converter
{
public static class BimlibLogger
{
private static readonly ApplicationSettings _settings = BimlibSettingsManager.Instance.AppSettings;
private static Lazy<LogFactory> _instance = null;
private static LoggingConfiguration _logConfig = null;
private static Lazy<LogFactory> Instance
{
get
{
return _instance ?? (_instance = new Lazy<LogFactory>(BuildLogFactory));
}
}
public static Logger GetLogger()
{
return Instance.Value.GetCurrentClassLogger();
}
private static LogFactory BuildLogFactory()
{
LoggingConfiguration config = _logConfig ?? new LoggingConfiguration();
string headerStr = _settings.LogHeader;
Layout header = headerStr;
Layout layout = "${longdate} [${callsite:className=true:includeNamespace=true:fileName=false:includeSourcePath=false:methodName=true:cleanNamesOfAnonymousDelegates=true:cleanNamesOfAsyncContinuations=true}] -> ${level:format=FirstCharacter} : ${message}${onexception:inner=${newline}${exception:format=@}}";
#region Targets ----------------------------
#region FileTarget ----------------------------
Target fileTarget = FileTarget(header, layout).MakeAsyncTarget();
config.AddTarget(fileTarget);
config.AddRuleForAllLevels(fileTarget);
#endregion
#region ConsoleTarget ----------------------------
Target consoleTarget = ConsoleTarget(header, layout).MakeAsyncTarget();
config.AddTarget(consoleTarget);
config.AddRuleForAllLevels(consoleTarget);
#endregion
#region DebuggerTarget ----------------------------
Target debugTarget = DebuggerTarget(header, layout).MakeAsyncTarget();
config.AddTarget(debugTarget);
config.AddRuleForAllLevels(debugTarget);
#endregion
#region GelfTarget ----------------------------
if (_settings.Statistics)
{
Target gelfTarget = GelfTarget(headerStr).MakeAsyncTarget();
config.AddTarget(gelfTarget);
config.AddRuleForAllLevels(gelfTarget);
}
#endregion
#endregion
LogFactory logFactory = new LogFactory
{
Configuration = config
};
try
{
config.LoggingRules.ToList().ForEach(r => r.SetLoggingLevels(LogLevel.AllLevels.Min(), LogLevel.AllLevels.Max()));
_logConfig = config;
}
catch (Exception ex)
{
Debug.Write(ex);
}
return logFactory;
}
#region Target Methods
private static FileTarget FileTarget(Layout header, Layout layout)
{
#region FileTarget ----------------------------
FileTarget fileTarget = new FileTarget("log_file_target")
{
ArchiveAboveSize = 1048576,
ArchiveDateFormat = "yyyy.MM.dd_HH.mm.ss",
ArchiveEvery = FileArchivePeriod.Day,
ArchiveFileName = GetApplicationLogAndArchivePath(false),
ArchiveNumbering = ArchiveNumberingMode.Date,
ArchiveOldFileOnStartup = false,
AutoFlush = true,
ConcurrentWrites = true,
DeleteOldFileOnStartup = false,
EnableArchiveFileCompression = true,
EnableFileDelete = true,
Encoding = Encoding.UTF8,
FileName = GetApplicationLogAndArchivePath(true),
Header = header,
Layout = layout,
MaxArchiveFiles = 100,
OpenFileCacheTimeout = 30,
OpenFileFlushTimeout = 30,
OptimizeBufferReuse = true
};
#endregion
return fileTarget;
}
private static ColoredConsoleTarget ConsoleTarget(Layout header, Layout layout)
{
#region ConsoleTarget ----------------------------
ColoredConsoleTarget consoleTarget = new ColoredConsoleTarget("log_console_target")
{
Encoding = Encoding.UTF8,
EnableAnsiOutput = false,
UseDefaultRowHighlightingRules = true,
Layout = layout,
Header = header
};
ConsoleWordHighlightingRule dateHighLightRule = new ConsoleWordHighlightingRule
{
Regex = @"^(?=\d).+(?=\s\[)",
ForegroundColor = ConsoleOutputColor.Yellow
};
ConsoleWordHighlightingRule methodsHighLightRule = new ConsoleWordHighlightingRule
{
Regex = @"(?<=\[).+(?=\])",
ForegroundColor = ConsoleOutputColor.Blue
};
ConsoleWordHighlightingRule levelHighLightRule = new ConsoleWordHighlightingRule
{
Regex = @"(?<=>).+(?=\s:)",
ForegroundColor = ConsoleOutputColor.Red
};
ConsoleWordHighlightingRule messageHighLightRule = new ConsoleWordHighlightingRule
{
Regex = @"(?<=\s:\s).+",
ForegroundColor = ConsoleOutputColor.Green
};
consoleTarget.WordHighlightingRules.Add(dateHighLightRule);
consoleTarget.WordHighlightingRules.Add(methodsHighLightRule);
consoleTarget.WordHighlightingRules.Add(levelHighLightRule);
consoleTarget.WordHighlightingRules.Add(messageHighLightRule);
#endregion
return consoleTarget;
}
private static DebuggerTarget DebuggerTarget(Layout header, Layout layout)
{
#region DebuggerTarget ----------------------------
DebuggerTarget debugTarget = new DebuggerTarget("log_debug_target")
{
Layout = layout,
Header = header
};
#endregion
return debugTarget;
}
private static GraylogHttpTarget GelfTarget(string header)
{
#region GelfTarget ----------------------------
Layout gelfCommonLayout = "${message}";
IList<TargetPropertyWithContext> gelfParameterInfos =
new List<TargetPropertyWithContext>()
{
new TargetPropertyWithContext() { Name = "appdomain", Layout = "${appdomain}" },
new TargetPropertyWithContext() { Name = "assembly-version", Layout = "${assembly-version}" },
new TargetPropertyWithContext() { Name = "activityid", Layout = "${activityid}" },
new TargetPropertyWithContext() { Name = "callsite", Layout = "${callsite}" },
new TargetPropertyWithContext() { Name = "callsite-linenumber", Layout = "${callsite-linenumber}" },
new TargetPropertyWithContext() { Name = "environment-user", Layout = "${environment-user:userName=true:domain=true}" },
new TargetPropertyWithContext() { Name = "exeption_json_data", Layout = "${onexception:inner=${exception:format=@}}" },
new TargetPropertyWithContext() { Name = "frameWorkInfo", Layout = $"{RuntimeInformation.FrameworkDescription} ({RuntimeInformation.ProcessArchitecture})" },
new TargetPropertyWithContext() { Name = "guid", Layout = "${guid:format=N}" },
new TargetPropertyWithContext() { Name = "hostname", Layout = "${hostname}" },
new TargetPropertyWithContext() { Name = "identity", Layout = "${identity:authType=true:separator=\n:name=true:isAuthenticated=true}" },
new TargetPropertyWithContext() { Name = "level_name", Layout = "${level:format=Name}" },
new TargetPropertyWithContext() { Name = "local-ip", Layout = "${local-ip:addressFamily=InterNetwork}" },
new TargetPropertyWithContext() { Name = "logger", Layout = "${logger:shortName=false}" },
new TargetPropertyWithContext() { Name = "machinename", Layout = "${machinename}" },
new TargetPropertyWithContext() { Name = "osInfo", Layout = $"{RuntimeInformation.OSDescription} ({RuntimeInformation.OSArchitecture})" },
new TargetPropertyWithContext() { Name = "processid", Layout = "${processid}" },
new TargetPropertyWithContext() { Name = "processinfo_MainWindowHandle", Layout = "${processinfo:property=MainWindowHandle}" },
new TargetPropertyWithContext() { Name = "processinfo_PagedMemorySize", Layout = "${processinfo:property=PagedMemorySize}" },
new TargetPropertyWithContext() { Name = "processname", Layout = "${processname:fullName=true}" },
new TargetPropertyWithContext() { Name = "processtime", Layout = "${processtime:invariant=false}" },
new TargetPropertyWithContext() { Name = "sequenceid", Layout = "${sequenceid}" },
new TargetPropertyWithContext() { Name = "stacktrace", Layout = "${stacktrace:format=Raw:topFrames=3:skipFrames=0:separator=
}" },
new TargetPropertyWithContext() { Name = "threadid", Layout = "${threadid}" },
new TargetPropertyWithContext() { Name = "threadname", Layout = "${threadname}" },
new TargetPropertyWithContext() { Name = "timestamp", Layout = $"{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}" },
new TargetPropertyWithContext() { Name = "timestamp_local", Layout = @"${date:universalTime=false:format=yyyy-MM-dd HH\:mm\:ss zzz}" },
new TargetPropertyWithContext() { Name = "windows-identity", Layout = "${windows-identity:userName=true:domain=true}" }
};
GraylogHttpTarget gelfUdpTarget = new GraylogHttpTarget
{
AddNLogLevelName = true,
Facility = header,
GraylogServer = _settings.LogServerAddress,
IncludeCallSite = true,
IncludeCallSiteStackTrace = true,
IncludeEventProperties = true,
Layout = gelfCommonLayout,
Name = "GelfHttp",
OptimizeBufferReuse = true
};
foreach (TargetPropertyWithContext gelfParameterInfo in gelfParameterInfos)
{
gelfUdpTarget.ContextProperties.Add(gelfParameterInfo);
}
#endregion
return gelfUdpTarget;
}
private static Target MakeAsyncTarget(this Target targ)
{
return new AsyncTargetWrapper
{
BatchSize = 100,
ForceLockingQueue = true,
FullBatchSizeWriteLimit = 5,
Name = targ.Name,
OptimizeBufferReuse = true,
OverflowAction = AsyncTargetWrapperOverflowAction.Grow,
QueueLimit = 10000,
TimeToSleepBetweenBatches = 1,
WrappedTarget = targ
};
}
#endregion
private static string GetApplicationLogAndArchivePath(bool isLog)
{
string addition;
if (!isLog)
{
addition = ".{#}.zip";
}
else
{
addition = ".log";
}
try
{
if (!Directory.Exists(_settings.LogsFolder))
{
Directory.CreateDirectory(_settings.LogsFolder);
}
return Path.Combine(_settings.LogsFolder, _settings.ProductName + addition);
}
catch (Exception ex)
{
Debug.Write(ex);
return string.Empty;
}
}
}