MONSTER: Rename Monorepo to Modules, only keep Projects under Modules.*
This commit is contained in:
590
Logging/LogConfig.vb
Normal file
590
Logging/LogConfig.vb
Normal file
@@ -0,0 +1,590 @@
|
||||
Imports System.IO
|
||||
Imports System.Reflection
|
||||
Imports NLog
|
||||
Imports NLog.Config
|
||||
Imports NLog.Targets
|
||||
|
||||
''' <module>LogConfig</module>
|
||||
''' <version>0.0.1.0</version>
|
||||
''' <date>02.10.2018</date>
|
||||
''' <summary>
|
||||
''' Module that writes file-logs to different locations:
|
||||
''' local application data, the current directory or a custom path.
|
||||
''' Files and directories will be automatically created.
|
||||
''' </summary>
|
||||
''' <dependencies>
|
||||
''' NLog, >= 4.5.8
|
||||
''' </dependencies>
|
||||
''' <example>
|
||||
''' Imports DigitalData.Modules.Logging
|
||||
'''
|
||||
''' Class FooProgram
|
||||
''' Private Logger as Logger
|
||||
''' Private LogConfig as LogConfig
|
||||
'''
|
||||
''' Public Sub New()
|
||||
''' LogConfig = new LogConfig(args)
|
||||
''' Logger = LogConfig.GetLogger()
|
||||
''' End Sub
|
||||
'''
|
||||
''' Public Sub Bar()
|
||||
''' Logger.Info("Baz")
|
||||
''' End Sub
|
||||
''' End Class
|
||||
'''
|
||||
''' Class FooLib
|
||||
''' Private Logger as NLog.Logger
|
||||
'''
|
||||
''' Public Sub New(LogConfig as LogConfig)
|
||||
''' Logger = LogConfig.GetLogger()
|
||||
''' End Sub
|
||||
'''
|
||||
''' Public Sub Bar()
|
||||
''' Logger.Info("Baz")
|
||||
''' End Sub
|
||||
''' End Class
|
||||
''' </example>
|
||||
''' <remarks>
|
||||
''' If logpath can not be written to, falls back to temp folder as defined in:
|
||||
''' https://docs.microsoft.com/de-de/dotnet/api/system.io.path.gettemppath?view=netframework-4.7.2
|
||||
'''
|
||||
''' If used in a service, LogPath must be set to CustomPath, otherwise the Log will be written to System32!
|
||||
'''
|
||||
''' For NLog Troubleshooting, set the following Environment variables to write the NLog internal Log:
|
||||
''' - NLOG_INTERNAL_LOG_LEVEL: Debug
|
||||
''' - NLOG_INTERNAL_LOG_FILE: ex. C:\Temp\Nlog_Internal.log
|
||||
''' </remarks>
|
||||
Public Class LogConfig
|
||||
#Region "Private Properties"
|
||||
Private Const OPEN_FILE_CACHE_TIMEOUT As Integer = 30
|
||||
Private Const OPEN_FILE_FLUSH_TIMEOUT As Integer = 5
|
||||
Private Const AUTO_FLUSH As Boolean = False
|
||||
|
||||
Private Const KEEP_FILES_OPEN As Boolean = False
|
||||
Private Const KEEP_FILES_OPEN_DEBUG As Boolean = True
|
||||
|
||||
' MAX_ARCHIVES_FILES works like this (in version 4.5.8):
|
||||
' 0 = keep ALL archives files
|
||||
' 1 = only keep latest logfile and NO archive files
|
||||
' n = keep n archive files
|
||||
Private Const MAX_ARCHIVE_FILES_DEFAULT As Integer = 0
|
||||
Private Const MAX_ARCHIVE_FILES_DEBUG_DETAIL As Integer = 0
|
||||
Private Const ARCHIVE_EVERY As FileArchivePeriod = FileArchivePeriod.Day
|
||||
|
||||
Private Const FILE_NAME_FORMAT_DEFAULT As String = "${shortdate}-${var:product}${var:suffix}${event-properties:item=ModuleName}.log"
|
||||
Private Const FILE_NAME_FORMAT_DEBUG As String = "${shortdate}-${var:product}${var:suffix}${event-properties:item=ModuleName}-Debug.log"
|
||||
Private Const FILE_NAME_FORMAT_TRACE As String = "${shortdate}-${var:product}${var:suffix}${event-properties:item=ModuleName}-Trace.log"
|
||||
Private Const FILE_NAME_FORMAT_ERROR As String = "${shortdate}-${var:product}${var:suffix}${event-properties:item=ModuleName}-Error.log"
|
||||
|
||||
Private Const TARGET_DEFAULT As String = "defaultTarget"
|
||||
Private Const TARGET_ERROR_EX As String = "errorExceptionTarget"
|
||||
Private Const TARGET_ERROR As String = "errorTarget"
|
||||
Private Const TARGET_DEBUG As String = "debugTarget"
|
||||
Private Const TARGET_TRACE As String = "traceTarget"
|
||||
'Private Const TARGET_MEMORY As String = "memoryTarget"
|
||||
|
||||
Private Const LOG_FORMAT_BASE As String = "${time}|${logger:shortName=True}|${level:uppercase=true}"
|
||||
Private Const LOG_FORMAT_CALLSITE As String = "${callsite:className=false:fileName=true:includeSourcePath=false:methodName=true}"
|
||||
Private Const LOG_FORMAT_EXCEPTION As String = "${exception:format=Message,StackTrace:innerFormat=Message:maxInnerExceptionLevel=3}"
|
||||
|
||||
Private Const LOG_FORMAT_DEFAULT As String = LOG_FORMAT_BASE & " >> ${message}"
|
||||
Private Const LOG_FORMAT_ERROR As String = LOG_FORMAT_BASE & " >> " & LOG_FORMAT_EXCEPTION
|
||||
Private Const LOG_FORMAT_DEBUG As String = LOG_FORMAT_BASE & " >> " & LOG_FORMAT_CALLSITE & " -> " & "${message}"
|
||||
|
||||
Private Const FILE_NAME_ACCESS_TEST = "accessTest.txt"
|
||||
Private Const FOLDER_NAME_LOG = "Log"
|
||||
|
||||
Private Const FILE_KEEP_RANGE As Integer = 30
|
||||
'Private Const MAX_MEMORY_LOG_COUNT As Integer = 1000
|
||||
|
||||
Private ReadOnly _failSafePath As String = Path.GetTempPath()
|
||||
Private ReadOnly _basePath As String = _failSafePath
|
||||
|
||||
Private _config As LoggingConfiguration
|
||||
Private _isDebug As Boolean = False
|
||||
Private _isTrace As Boolean = False
|
||||
|
||||
#End Region
|
||||
#Region "Public Properties"
|
||||
Public Enum PathType As Integer
|
||||
AppData = 0
|
||||
CurrentDirectory = 1
|
||||
CustomPath = 2
|
||||
Temp = 3
|
||||
End Enum
|
||||
|
||||
''' <summary>
|
||||
''' Returns the NLog.LogFactory object that is used to create Loggers
|
||||
''' </summary>
|
||||
''' <returns>LogFactory object</returns>
|
||||
Public ReadOnly Property LogFactory As LogFactory
|
||||
|
||||
''' <summary>
|
||||
''' Returns the path to the current default logfile
|
||||
''' </summary>
|
||||
''' <returns>Filepath to the logfile</returns>
|
||||
Public ReadOnly Property LogFile As String
|
||||
|
||||
''' <summary>
|
||||
''' Returns the path to the current log directory
|
||||
''' </summary>
|
||||
''' <returns>Directory path to the log directory</returns>
|
||||
Public ReadOnly Property LogDirectory As String
|
||||
|
||||
''' <summary>
|
||||
''' Determines if a debug log will be written
|
||||
''' </summary>
|
||||
''' <returns>True, if debug log will be written. False otherwise.</returns>
|
||||
Public Property Debug As Boolean
|
||||
Get
|
||||
Return _isDebug
|
||||
End Get
|
||||
Set(isDebug As Boolean)
|
||||
_isDebug = isDebug
|
||||
ReloadConfig(isDebug, _isTrace)
|
||||
End Set
|
||||
End Property
|
||||
|
||||
Public Property Trace As Boolean
|
||||
Get
|
||||
Return _isTrace
|
||||
End Get
|
||||
Set(isTrace As Boolean)
|
||||
_isTrace = isTrace
|
||||
ReloadConfig(_isDebug, isTrace)
|
||||
End Set
|
||||
End Property
|
||||
|
||||
''' <summary>
|
||||
''' Returns Logs in Memory as List(Of String) if Debug is enabled
|
||||
''' Returns an empty list if debug is disabled
|
||||
''' </summary>
|
||||
''' <returns>A list of log messages</returns>
|
||||
Public ReadOnly Property Logs As List(Of String)
|
||||
Get
|
||||
'Dim oTarget = _config.FindTargetByName(Of MemoryTarget)(TARGET_MEMORY)
|
||||
'Return oTarget?.Logs.ToList()
|
||||
Return New List(Of String)
|
||||
End Get
|
||||
End Property
|
||||
|
||||
Public ReadOnly Property NLogConfig As LoggingConfiguration
|
||||
Get
|
||||
Return _config
|
||||
End Get
|
||||
End Property
|
||||
|
||||
#End Region
|
||||
|
||||
''' <summary>
|
||||
''' Initializes a new LogConfig object with the options supplied as a LogOptions object
|
||||
''' </summary>
|
||||
''' <param name="Options"></param>
|
||||
Public Sub New(Options As LogOptions)
|
||||
MyClass.New(Options.LogPath, Options.CustomLogPath, Options.Suffix, Options.CompanyName, Options.ProductName, Options.FileKeepInterval)
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' Initializes a new LogConfig object with a logpath and optinally a filename-suffix.
|
||||
''' </summary>
|
||||
''' <param name="LogPath">The basepath to write logs to. Can be AppData, CurrentDirectory or CustomPath.</param>
|
||||
''' <param name="CustomLogPath">If `logPath` is set to custom, this defines the custom logPath.</param>
|
||||
''' <param name="Suffix">If set to anything other than Nothing, extends the logfile name with this suffix.</param>
|
||||
''' <param name="CompanyName">CompanyName is used to construct log-path in when LogPath is set to PathType:AppData</param>
|
||||
''' <param name="ProductName">ProductName is used to construct log-path in when LogPath is set to PathType:AppData</param>
|
||||
''' <param name="FileKeepRangeInDays">Amount of days where files are kept and not deleted.</param>
|
||||
Public Sub New(LogPath As PathType,
|
||||
Optional CustomLogPath As String = Nothing,
|
||||
Optional Suffix As String = Nothing,
|
||||
Optional CompanyName As String = Nothing,
|
||||
Optional ProductName As String = Nothing,
|
||||
Optional FileKeepRangeInDays As Integer = FILE_KEEP_RANGE)
|
||||
|
||||
If LogPath = PathType.AppData And (ProductName Is Nothing Or CompanyName Is Nothing) Then
|
||||
Throw New ArgumentException("Modules.Logging: PathType is AppData and either CompanyName or ProductName was not supplied!")
|
||||
End If
|
||||
|
||||
If LogPath = PathType.CurrentDirectory Then
|
||||
Throw New ArgumentException("Modules.Logging: LogPath.CurrentDirectory is deprecated. Please use LogPath.CustomPath!")
|
||||
End If
|
||||
|
||||
If LogPath = PathType.AppData Then
|
||||
Dim appDataDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
|
||||
_basePath = Path.Combine(appDataDir, CompanyName, ProductName, FOLDER_NAME_LOG)
|
||||
ElseIf LogPath = PathType.Temp Then
|
||||
_basePath = _failSafePath
|
||||
Else 'Custom Path
|
||||
_basePath = CustomLogPath
|
||||
End If
|
||||
|
||||
' If directory does not exist, try to create it!
|
||||
If Not Directory.Exists(_basePath) Then
|
||||
Try
|
||||
Directory.CreateDirectory(_basePath)
|
||||
Catch ex As Exception
|
||||
' If creation fails, use failSafe path
|
||||
_basePath = _failSafePath
|
||||
End Try
|
||||
End If
|
||||
|
||||
' Try to create a file in `basePath` to check write permissions
|
||||
Try
|
||||
Dim fileAccessPath = Path.Combine(_basePath, FILE_NAME_ACCESS_TEST)
|
||||
Using fs As FileStream = File.Create(fileAccessPath)
|
||||
fs.WriteByte(0)
|
||||
End Using
|
||||
|
||||
File.Delete(fileAccessPath)
|
||||
Catch ex As Exception
|
||||
' If creation fails, use failSafe path
|
||||
_basePath = _failSafePath
|
||||
End Try
|
||||
|
||||
' Set the suffix to the given string if it exists
|
||||
Dim logFileSuffix As String = String.Empty
|
||||
|
||||
If Suffix IsNot Nothing AndAlso Suffix.Count > 0 Then
|
||||
logFileSuffix = $"-{Suffix}"
|
||||
End If
|
||||
|
||||
Dim oProductName As String = "Main"
|
||||
|
||||
If ProductName IsNot Nothing Then
|
||||
oProductName = ProductName
|
||||
End If
|
||||
|
||||
' Create config object and initalize it
|
||||
_config = GetConfig(oProductName, logFileSuffix)
|
||||
|
||||
' Save config
|
||||
LogFactory = New LogFactory With {
|
||||
.Configuration = _config
|
||||
}
|
||||
|
||||
' Save log paths for files/directory
|
||||
LogDirectory = _basePath
|
||||
LogFile = GetCurrentLogFilePath()
|
||||
|
||||
Dim oLogger = GetLogger()
|
||||
oLogger.Info("Logging started for [{0}{1}] in [{2}]", oProductName, logFileSuffix, LogFile)
|
||||
oLogger.Info("Logging Version [{0}]", Assembly.GetExecutingAssembly().GetName().Version)
|
||||
|
||||
' Clear old Logfiles as defined in `FileKeepInterval`
|
||||
ClearOldLogfiles(FileKeepRangeInDays)
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' Clears old LogFiles from the configured logpath for compliance with the GDPR
|
||||
''' </summary>
|
||||
''' <param name="FileKeepRange">Days in which logfiles should be kept. All files older than `Now - FileKeepInterval` will be deleted.</param>
|
||||
''' <returns>True, if files were deleted as expected or no files were deleted. Otherwise false.</returns>
|
||||
Private Function ClearOldLogfiles(FileKeepRange As Integer) As Boolean
|
||||
Dim oClassName As String = GetClassFullName()
|
||||
Dim oLogger As Logger = GetLogger(oClassName)
|
||||
|
||||
Try
|
||||
Dim oContinueOnError = True
|
||||
Dim oUnableToDeleteCounter = 0
|
||||
Dim oDirectory As New DirectoryInfo(LogDirectory)
|
||||
Dim oDateLimit As Date = Date.Now.AddDays(-FileKeepRange)
|
||||
Dim oFiles As List(Of FileInfo) = oDirectory.
|
||||
EnumerateFiles().
|
||||
Where(Function(oFileInfo As FileInfo) oFileInfo.Extension = ".log" And oFileInfo.LastWriteTime < oDateLimit).
|
||||
ToList()
|
||||
|
||||
If oFiles.Count = 0 Then
|
||||
oLogger.Info("No logfiles were marked for deletion in the range [last {0} days].", FileKeepRange)
|
||||
Return True
|
||||
End If
|
||||
|
||||
oLogger.Info("Deleting [{0}] old logfiles that are marked for deletion in the range [last {1} days].", oFiles.Count, FileKeepRange)
|
||||
|
||||
For Each oFile As FileInfo In oFiles
|
||||
Try
|
||||
oFile.Delete()
|
||||
Catch ex As Exception
|
||||
oUnableToDeleteCounter += 1
|
||||
oLogger.Warn("File {0} could not be deleted!")
|
||||
End Try
|
||||
Next
|
||||
|
||||
If oUnableToDeleteCounter > 0 Then
|
||||
oLogger.Info("Delete old logfiles partially. {0} files could not be deleted.", oUnableToDeleteCounter)
|
||||
Else
|
||||
oLogger.Info("Deleted [{0}] old logfiles.", oFiles.Count)
|
||||
End If
|
||||
|
||||
Return True
|
||||
Catch ex As Exception
|
||||
oLogger.Error(ex)
|
||||
|
||||
Return False
|
||||
End Try
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' Returns the Logger for the calling class
|
||||
''' </summary>
|
||||
''' <returns>An object of Logging.Logger</returns>
|
||||
<DebuggerStepThrough()>
|
||||
Public Function GetLogger() As Logger
|
||||
Dim oClassName As String = GetClassFullName()
|
||||
Return GetLogger(oClassName, String.Empty)
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' Returns the Logger for the specified classname
|
||||
''' </summary>
|
||||
''' <returns>An object of Logging.Logger</returns>
|
||||
<DebuggerStepThrough()>
|
||||
Public Function GetLogger(ClassName As String) As Logger
|
||||
Return GetLogger(ClassName, String.Empty)
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' Returns the Logger for the specified module using event-properties
|
||||
''' </summary>
|
||||
''' <remarks>
|
||||
''' https://github.com/NLog/NLog/wiki/EventProperties-Layout-Renderer
|
||||
''' https://stackoverflow.com/questions/31337030/separate-log-file-for-specific-class-instance-using-nlog/32065824#32065824
|
||||
''' </remarks>
|
||||
''' <returns>An object of Logging.Logger</returns>
|
||||
<DebuggerStepThrough()>
|
||||
Public Function GetLoggerFor(ModuleName As String) As Logger
|
||||
Dim oClassName As String = GetClassFullName()
|
||||
Return GetLogger(oClassName, ModuleName)
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' Returns the Logger for a class specified by `ClassName`
|
||||
''' </summary>
|
||||
''' <param name="ClassName">The name of the class the logger belongs to</param>
|
||||
''' <returns>An object of Logging.Logger</returns>
|
||||
Public Function GetLogger(ClassName As String, ModuleName As String) As Logger
|
||||
Dim oLogger = LogFactory.GetLogger(Of Logger)(ClassName)
|
||||
|
||||
If ModuleName IsNot Nothing AndAlso ModuleName.Length > 0 Then
|
||||
Return oLogger.WithProperty("ModuleName", $"-{ModuleName}")
|
||||
End If
|
||||
|
||||
Return oLogger
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' Clears the internal log
|
||||
''' </summary>
|
||||
Public Sub ClearLogs()
|
||||
'Dim oTarget = _config.FindTargetByName(Of MemoryTarget)(TARGET_MEMORY)
|
||||
'oTarget?.Logs.Clear()
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' Gets the fully qualified name of the class invoking the calling method,
|
||||
''' including the namespace but Not the assembly.
|
||||
''' </summary>
|
||||
''' <returns>The fully qualified class name</returns>
|
||||
''' <remarks>This method is very resource-intensive!</remarks>
|
||||
<DebuggerStepThrough()>
|
||||
Public Shared Function GetClassFullName(Optional IncludeMethodNames As Boolean = False, Optional Parts As Integer = 0) As String
|
||||
Dim oFramesToSkip As Integer = 2
|
||||
Dim oClassName As String = String.Empty
|
||||
Dim oStackTrace = Environment.StackTrace
|
||||
Dim oStackTraceLines = oStackTrace.Replace(vbCr, "").Split({vbLf}, StringSplitOptions.RemoveEmptyEntries)
|
||||
|
||||
For i As Integer = 0 To oStackTraceLines.Length - 1
|
||||
Dim oCallingClassAndMethod = oStackTraceLines(i).Split({" ", "<>", "(", ")"}, StringSplitOptions.RemoveEmptyEntries)(1)
|
||||
Dim oMethodStartIndex As Integer = oCallingClassAndMethod.LastIndexOf(".", StringComparison.Ordinal)
|
||||
|
||||
If oMethodStartIndex > 0 Then
|
||||
If IncludeMethodNames Then
|
||||
oMethodStartIndex = oCallingClassAndMethod.Count
|
||||
End If
|
||||
|
||||
Dim oCallingClass = oCallingClassAndMethod.Substring(0, oMethodStartIndex)
|
||||
oClassName = oCallingClass.TrimEnd("."c)
|
||||
|
||||
If Not oClassName.StartsWith("System.Environment") AndAlso oFramesToSkip <> 0 Then
|
||||
i += oFramesToSkip - 1
|
||||
oFramesToSkip = 0
|
||||
Continue For
|
||||
End If
|
||||
|
||||
If Not oClassName.StartsWith("System.") Then Exit For
|
||||
End If
|
||||
Next
|
||||
|
||||
If Parts > 0 Then
|
||||
Dim oParts = oClassName.
|
||||
Split(".").
|
||||
Reverse().
|
||||
Take(Parts).
|
||||
Reverse()
|
||||
|
||||
oClassName = String.Join(".", oParts)
|
||||
End If
|
||||
|
||||
Return oClassName
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' Returns the initial log configuration
|
||||
''' </summary>
|
||||
''' <param name="productName">The chosen productname</param>
|
||||
''' <param name="logFileSuffix">The chosen suffix</param>
|
||||
''' <returns>A NLog.LoggingConfiguration object</returns>
|
||||
Private Function GetConfig(productName As String, logFileSuffix As String) As LoggingConfiguration
|
||||
_config = New LoggingConfiguration()
|
||||
_config.Variables("product") = productName
|
||||
_config.Variables("suffix") = logFileSuffix
|
||||
|
||||
' Add default targets
|
||||
_config.AddTarget(TARGET_ERROR_EX, GetErrorExceptionLogTarget(_basePath))
|
||||
_config.AddTarget(TARGET_ERROR, GetErrorLogTarget(_basePath))
|
||||
_config.AddTarget(TARGET_DEFAULT, GetDefaultLogTarget(_basePath))
|
||||
_config.AddTarget(TARGET_DEBUG, GetDebugLogTarget(_basePath))
|
||||
_config.AddTarget(TARGET_TRACE, GetTraceLogTarget(_basePath))
|
||||
'_config.AddTarget(TARGET_MEMORY, GetMemoryDebugTarget())
|
||||
|
||||
' Add default rules
|
||||
AddDefaultRules(_config)
|
||||
|
||||
Return _config
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' Adds the default rules
|
||||
''' </summary>
|
||||
''' <param name="config">A NLog.LoggingConfiguration object</param>
|
||||
Private Sub AddDefaultRules(ByRef config As LoggingConfiguration)
|
||||
config.AddRuleForOneLevel(LogLevel.Error, TARGET_ERROR_EX)
|
||||
config.AddRuleForOneLevel(LogLevel.Fatal, TARGET_ERROR_EX)
|
||||
config.AddRuleForOneLevel(LogLevel.Warn, TARGET_DEFAULT)
|
||||
config.AddRuleForOneLevel(LogLevel.Info, TARGET_DEFAULT)
|
||||
'config.AddRuleForAllLevels(TARGET_MEMORY)
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' Returns the full path of the current default log file.
|
||||
''' </summary>
|
||||
''' <returns>Full path of the current default log file</returns>
|
||||
Private Function GetCurrentLogFilePath()
|
||||
Dim logEventInfo As New LogEventInfo() With {.TimeStamp = Date.Now}
|
||||
Dim target As FileTarget = _config.FindTargetByName(TARGET_DEFAULT)
|
||||
Dim fileName As String = target.FileName.Render(logEventInfo)
|
||||
|
||||
Return fileName
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' Reconfigures and re-adds all loggers, optionally adding the debug rule.
|
||||
''' </summary>
|
||||
''' <param name="Debug">Adds the Debug rule if true.</param>
|
||||
''' <param name="Trace">Adds the Trace rule if true.</param>
|
||||
Private Sub ReloadConfig(Optional Debug As Boolean = False, Optional Trace As Boolean = False)
|
||||
' Clear Logging Rules
|
||||
_config.LoggingRules.Clear()
|
||||
|
||||
' Add default rules
|
||||
AddDefaultRules(_config)
|
||||
|
||||
' Add debug rule, if configured
|
||||
If Debug = True Then
|
||||
_config.AddRule(LogLevel.Debug, LogLevel.Error, TARGET_DEBUG)
|
||||
End If
|
||||
|
||||
If Trace = True Then
|
||||
_config.AddRule(LogLevel.Trace, LogLevel.Error, TARGET_TRACE)
|
||||
End If
|
||||
|
||||
' Reload all running loggers
|
||||
LogFactory.ReconfigExistingLoggers()
|
||||
End Sub
|
||||
|
||||
#Region "Log Targets"
|
||||
Private Function GetDefaultLogTarget(basePath As String) As FileTarget
|
||||
Dim defaultLog As New FileTarget() With {
|
||||
.FileName = Path.Combine(basePath, FILE_NAME_FORMAT_DEFAULT),
|
||||
.Name = TARGET_DEFAULT,
|
||||
.Layout = LOG_FORMAT_DEFAULT,
|
||||
.MaxArchiveFiles = MAX_ARCHIVE_FILES_DEFAULT,
|
||||
.ArchiveEvery = ARCHIVE_EVERY,
|
||||
.KeepFileOpen = KEEP_FILES_OPEN,
|
||||
.Encoding = Text.Encoding.Unicode
|
||||
}
|
||||
|
||||
Return defaultLog
|
||||
End Function
|
||||
Private Function GetErrorExceptionLogTarget(basePath As String) As FileTarget
|
||||
Dim errorLogWithExceptions As New FileTarget() With {
|
||||
.FileName = Path.Combine(basePath, FILE_NAME_FORMAT_ERROR),
|
||||
.Name = TARGET_ERROR_EX,
|
||||
.Layout = LOG_FORMAT_ERROR,
|
||||
.MaxArchiveFiles = MAX_ARCHIVE_FILES_DEFAULT,
|
||||
.ArchiveEvery = ARCHIVE_EVERY,
|
||||
.KeepFileOpen = KEEP_FILES_OPEN,
|
||||
.Encoding = Text.Encoding.Unicode
|
||||
}
|
||||
|
||||
Return errorLogWithExceptions
|
||||
End Function
|
||||
|
||||
Private Function GetErrorLogTarget(basePath As String) As FileTarget
|
||||
Dim errorLog As New FileTarget() With {
|
||||
.FileName = Path.Combine(basePath, FILE_NAME_FORMAT_ERROR),
|
||||
.Name = TARGET_ERROR,
|
||||
.Layout = LOG_FORMAT_DEFAULT,
|
||||
.MaxArchiveFiles = MAX_ARCHIVE_FILES_DEFAULT,
|
||||
.ArchiveEvery = ARCHIVE_EVERY,
|
||||
.KeepFileOpen = KEEP_FILES_OPEN,
|
||||
.Encoding = Text.Encoding.Unicode
|
||||
}
|
||||
|
||||
Return errorLog
|
||||
End Function
|
||||
|
||||
Private Function GetDebugLogTarget(basePath As String) As FileTarget
|
||||
Dim debugLog As New FileTarget() With {
|
||||
.FileName = Path.Combine(basePath, FILE_NAME_FORMAT_DEBUG),
|
||||
.Name = TARGET_DEBUG,
|
||||
.Layout = LOG_FORMAT_DEBUG,
|
||||
.MaxArchiveFiles = MAX_ARCHIVE_FILES_DEBUG_DETAIL,
|
||||
.ArchiveEvery = ARCHIVE_EVERY,
|
||||
.KeepFileOpen = KEEP_FILES_OPEN_DEBUG,
|
||||
.OpenFileCacheTimeout = OPEN_FILE_CACHE_TIMEOUT,
|
||||
.AutoFlush = AUTO_FLUSH,
|
||||
.OpenFileFlushTimeout = OPEN_FILE_FLUSH_TIMEOUT,
|
||||
.Encoding = Text.Encoding.Unicode
|
||||
}
|
||||
|
||||
Return debugLog
|
||||
End Function
|
||||
|
||||
Private Function GetTraceLogTarget(basePath As String) As FileTarget
|
||||
Dim debugLog As New FileTarget() With {
|
||||
.FileName = Path.Combine(basePath, FILE_NAME_FORMAT_TRACE),
|
||||
.Name = TARGET_DEBUG,
|
||||
.Layout = LOG_FORMAT_DEBUG,
|
||||
.MaxArchiveFiles = MAX_ARCHIVE_FILES_DEBUG_DETAIL,
|
||||
.ArchiveEvery = ARCHIVE_EVERY,
|
||||
.KeepFileOpen = KEEP_FILES_OPEN_DEBUG,
|
||||
.OpenFileCacheTimeout = OPEN_FILE_CACHE_TIMEOUT,
|
||||
.AutoFlush = AUTO_FLUSH,
|
||||
.OpenFileFlushTimeout = OPEN_FILE_FLUSH_TIMEOUT,
|
||||
.Encoding = Text.Encoding.Unicode
|
||||
}
|
||||
|
||||
Return debugLog
|
||||
End Function
|
||||
|
||||
'Private Function GetMemoryDebugTarget() As MemoryTarget
|
||||
' Dim memoryLog As New MemoryTarget() With {
|
||||
' .Layout = LOG_FORMAT_DEBUG,
|
||||
' .Name = TARGET_MEMORY,
|
||||
' .OptimizeBufferReuse = True,
|
||||
' .MaxLogsCount = MAX_MEMORY_LOG_COUNT
|
||||
' }
|
||||
|
||||
' Return memoryLog
|
||||
'End Function
|
||||
#End Region
|
||||
End Class
|
||||
10
Logging/LogOptions.vb
Normal file
10
Logging/LogOptions.vb
Normal file
@@ -0,0 +1,10 @@
|
||||
Imports DigitalData.Modules.Logging.LogConfig
|
||||
|
||||
Public Class LogOptions
|
||||
Property LogPath As PathType
|
||||
Property CustomLogPath As String = Nothing
|
||||
Property Suffix As String = Nothing
|
||||
Property CompanyName As String = Nothing
|
||||
Property ProductName As String = Nothing
|
||||
Property FileKeepInterval As Integer = 0
|
||||
End Class
|
||||
27
Logging/Logger.vb
Normal file
27
Logging/Logger.vb
Normal file
@@ -0,0 +1,27 @@
|
||||
Imports NLog
|
||||
|
||||
Public Class Logger
|
||||
Inherits NLog.Logger
|
||||
|
||||
<DebuggerStepThrough()>
|
||||
Public Sub NewBlock(blockId As String)
|
||||
Dim message As String = $"-----> Start of Block {blockId}"
|
||||
Dim logEventInfo As New LogEventInfo(LogLevel.Info, Name, message)
|
||||
Dim logEventDebug As New LogEventInfo(LogLevel.Debug, Name, message)
|
||||
Dim WrapperType As Type = GetType(Logger)
|
||||
|
||||
Log(WrapperType, logEventDebug)
|
||||
Log(WrapperType, logEventInfo)
|
||||
End Sub
|
||||
|
||||
<DebuggerStepThrough()>
|
||||
Public Sub EndBlock()
|
||||
Dim message As String = $"<----- End of Block"
|
||||
Dim logEventInfo As New LogEventInfo(LogLevel.Info, Name, message)
|
||||
Dim logEventDebug As New LogEventInfo(LogLevel.Debug, Name, message)
|
||||
Dim WrapperType As Type = GetType(Logger)
|
||||
|
||||
Log(WrapperType, logEventDebug)
|
||||
Log(WrapperType, logEventInfo)
|
||||
End Sub
|
||||
End Class
|
||||
116
Logging/Logging.vbproj
Normal file
116
Logging/Logging.vbproj
Normal file
@@ -0,0 +1,116 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{903B2D7D-3B80-4BE9-8713-7447B704E1B0}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>DigitalData.Modules.Logging</RootNamespace>
|
||||
<AssemblyName>DigitalData.Modules.Logging</AssemblyName>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<MyType>Windows</MyType>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<DefineDebug>true</DefineDebug>
|
||||
<DefineTrace>true</DefineTrace>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DocumentationFile>DigitalData.Modules.Logging.xml</DocumentationFile>
|
||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<DefineDebug>false</DefineDebug>
|
||||
<DefineTrace>true</DefineTrace>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DocumentationFile>DigitalData.Modules.Logging.xml</DocumentationFile>
|
||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OptionExplicit>On</OptionExplicit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OptionCompare>Binary</OptionCompare>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OptionStrict>Off</OptionStrict>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OptionInfer>On</OptionInfer>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NLog.4.7.15\lib\net45\NLog.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.IO.Compression" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.ServiceModel" />
|
||||
<Reference Include="System.Transactions" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Import Include="Microsoft.VisualBasic" />
|
||||
<Import Include="System" />
|
||||
<Import Include="System.Collections" />
|
||||
<Import Include="System.Collections.Generic" />
|
||||
<Import Include="System.Data" />
|
||||
<Import Include="System.Diagnostics" />
|
||||
<Import Include="System.Linq" />
|
||||
<Import Include="System.Xml.Linq" />
|
||||
<Import Include="System.Threading.Tasks" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="LogConfig.vb" />
|
||||
<Compile Include="Logger.vb" />
|
||||
<Compile Include="LogOptions.vb" />
|
||||
<Compile Include="My Project\AssemblyInfo.vb" />
|
||||
<Compile Include="My Project\Application.Designer.vb">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Application.myapp</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="My Project\Resources.Designer.vb">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="My Project\Settings.Designer.vb">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<Compile Include="TraceListener.vb" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="My Project\Resources.resx">
|
||||
<Generator>VbMyResourcesResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.vb</LastGenOutput>
|
||||
<CustomToolNamespace>My.Resources</CustomToolNamespace>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="My Project\Application.myapp">
|
||||
<Generator>MyApplicationCodeGenerator</Generator>
|
||||
<LastGenOutput>Application.Designer.vb</LastGenOutput>
|
||||
</None>
|
||||
<None Include="My Project\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<CustomToolNamespace>My</CustomToolNamespace>
|
||||
<LastGenOutput>Settings.Designer.vb</LastGenOutput>
|
||||
</None>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
|
||||
</Project>
|
||||
13
Logging/My Project/Application.Designer.vb
generated
Normal file
13
Logging/My Project/Application.Designer.vb
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
'------------------------------------------------------------------------------
|
||||
' <auto-generated>
|
||||
' Dieser Code wurde von einem Tool generiert.
|
||||
' Laufzeitversion:4.0.30319.42000
|
||||
'
|
||||
' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
|
||||
' der Code erneut generiert wird.
|
||||
' </auto-generated>
|
||||
'------------------------------------------------------------------------------
|
||||
|
||||
Option Strict On
|
||||
Option Explicit On
|
||||
|
||||
10
Logging/My Project/Application.myapp
Normal file
10
Logging/My Project/Application.myapp
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<MyApplicationData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<MySubMain>false</MySubMain>
|
||||
<SingleInstance>false</SingleInstance>
|
||||
<ShutdownMode>0</ShutdownMode>
|
||||
<EnableVisualStyles>true</EnableVisualStyles>
|
||||
<AuthenticationMode>0</AuthenticationMode>
|
||||
<ApplicationType>1</ApplicationType>
|
||||
<SaveMySettingsOnExit>true</SaveMySettingsOnExit>
|
||||
</MyApplicationData>
|
||||
35
Logging/My Project/AssemblyInfo.vb
Normal file
35
Logging/My Project/AssemblyInfo.vb
Normal file
@@ -0,0 +1,35 @@
|
||||
Imports System
|
||||
Imports System.Reflection
|
||||
Imports System.Runtime.InteropServices
|
||||
|
||||
' Allgemeine Informationen über eine Assembly werden über die folgenden
|
||||
' Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
|
||||
' die einer Assembly zugeordnet sind.
|
||||
|
||||
' Werte der Assemblyattribute überprüfen
|
||||
|
||||
<Assembly: AssemblyTitle("Modules.Logging")>
|
||||
<Assembly: AssemblyDescription("")>
|
||||
<Assembly: AssemblyCompany("Digital Data")>
|
||||
<Assembly: AssemblyProduct("Modules.Logging")>
|
||||
<Assembly: AssemblyCopyright("Copyright © 2022")>
|
||||
<Assembly: AssemblyTrademark("2.5.4.2")>
|
||||
|
||||
<Assembly: ComVisible(False)>
|
||||
|
||||
'Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird.
|
||||
<Assembly: Guid("fd9ac226-1f78-499e-909c-f0b4d74bbfaf")>
|
||||
|
||||
' Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
|
||||
'
|
||||
' Hauptversion
|
||||
' Nebenversion
|
||||
' Buildnummer
|
||||
' Revision
|
||||
'
|
||||
' Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
|
||||
' übernehmen, indem Sie "*" eingeben:
|
||||
' <Assembly: AssemblyVersion("1.0.*")>
|
||||
|
||||
<Assembly: AssemblyVersion("2.5.4.2")>
|
||||
<Assembly: AssemblyFileVersion("2.5.4.2")>
|
||||
63
Logging/My Project/Resources.Designer.vb
generated
Normal file
63
Logging/My Project/Resources.Designer.vb
generated
Normal file
@@ -0,0 +1,63 @@
|
||||
'------------------------------------------------------------------------------
|
||||
' <auto-generated>
|
||||
' Dieser Code wurde von einem Tool generiert.
|
||||
' Laufzeitversion:4.0.30319.42000
|
||||
'
|
||||
' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
|
||||
' der Code erneut generiert wird.
|
||||
' </auto-generated>
|
||||
'------------------------------------------------------------------------------
|
||||
|
||||
Option Strict On
|
||||
Option Explicit On
|
||||
|
||||
Imports System
|
||||
|
||||
Namespace My.Resources
|
||||
|
||||
'Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert
|
||||
'-Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert.
|
||||
'Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen
|
||||
'mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu.
|
||||
'''<summary>
|
||||
''' Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
|
||||
'''</summary>
|
||||
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0"), _
|
||||
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
|
||||
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
|
||||
Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _
|
||||
Friend Module Resources
|
||||
|
||||
Private resourceMan As Global.System.Resources.ResourceManager
|
||||
|
||||
Private resourceCulture As Global.System.Globalization.CultureInfo
|
||||
|
||||
'''<summary>
|
||||
''' Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird.
|
||||
'''</summary>
|
||||
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||
Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
|
||||
Get
|
||||
If Object.ReferenceEquals(resourceMan, Nothing) Then
|
||||
Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("DigitalData.Modules.Logging.Resources", GetType(Resources).Assembly)
|
||||
resourceMan = temp
|
||||
End If
|
||||
Return resourceMan
|
||||
End Get
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle
|
||||
''' Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden.
|
||||
'''</summary>
|
||||
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||
Friend Property Culture() As Global.System.Globalization.CultureInfo
|
||||
Get
|
||||
Return resourceCulture
|
||||
End Get
|
||||
Set
|
||||
resourceCulture = value
|
||||
End Set
|
||||
End Property
|
||||
End Module
|
||||
End Namespace
|
||||
117
Logging/My Project/Resources.resx
Normal file
117
Logging/My Project/Resources.resx
Normal file
@@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
73
Logging/My Project/Settings.Designer.vb
generated
Normal file
73
Logging/My Project/Settings.Designer.vb
generated
Normal file
@@ -0,0 +1,73 @@
|
||||
'------------------------------------------------------------------------------
|
||||
' <auto-generated>
|
||||
' Dieser Code wurde von einem Tool generiert.
|
||||
' Laufzeitversion:4.0.30319.42000
|
||||
'
|
||||
' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
|
||||
' der Code erneut generiert wird.
|
||||
' </auto-generated>
|
||||
'------------------------------------------------------------------------------
|
||||
|
||||
Option Strict On
|
||||
Option Explicit On
|
||||
|
||||
|
||||
Namespace My
|
||||
|
||||
<Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
|
||||
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.7.0.0"), _
|
||||
Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||
Partial Friend NotInheritable Class MySettings
|
||||
Inherits Global.System.Configuration.ApplicationSettingsBase
|
||||
|
||||
Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings()),MySettings)
|
||||
|
||||
#Region "Automatische My.Settings-Speicherfunktion"
|
||||
#If _MyType = "WindowsForms" Then
|
||||
Private Shared addedHandler As Boolean
|
||||
|
||||
Private Shared addedHandlerLockObject As New Object
|
||||
|
||||
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||
Private Shared Sub AutoSaveSettings(sender As Global.System.Object, e As Global.System.EventArgs)
|
||||
If My.Application.SaveMySettingsOnExit Then
|
||||
My.Settings.Save()
|
||||
End If
|
||||
End Sub
|
||||
#End If
|
||||
#End Region
|
||||
|
||||
Public Shared ReadOnly Property [Default]() As MySettings
|
||||
Get
|
||||
|
||||
#If _MyType = "WindowsForms" Then
|
||||
If Not addedHandler Then
|
||||
SyncLock addedHandlerLockObject
|
||||
If Not addedHandler Then
|
||||
AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings
|
||||
addedHandler = True
|
||||
End If
|
||||
End SyncLock
|
||||
End If
|
||||
#End If
|
||||
Return defaultInstance
|
||||
End Get
|
||||
End Property
|
||||
End Class
|
||||
End Namespace
|
||||
|
||||
Namespace My
|
||||
|
||||
<Global.Microsoft.VisualBasic.HideModuleNameAttribute(), _
|
||||
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
|
||||
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute()> _
|
||||
Friend Module MySettingsProperty
|
||||
|
||||
<Global.System.ComponentModel.Design.HelpKeywordAttribute("My.Settings")> _
|
||||
Friend ReadOnly Property Settings() As Global.DigitalData.Modules.Logging.My.MySettings
|
||||
Get
|
||||
Return Global.DigitalData.Modules.Logging.My.MySettings.Default
|
||||
End Get
|
||||
End Property
|
||||
End Module
|
||||
End Namespace
|
||||
7
Logging/My Project/Settings.settings
Normal file
7
Logging/My Project/Settings.settings
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" UseMySettingsClassName="true">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
||||
249
Logging/TraceListener.vb
Normal file
249
Logging/TraceListener.vb
Normal file
@@ -0,0 +1,249 @@
|
||||
Imports System
|
||||
Imports System.Configuration
|
||||
Imports System.Diagnostics
|
||||
Imports System.Globalization
|
||||
Imports System.IO
|
||||
Imports System.Security.Permissions
|
||||
Imports System.Text.RegularExpressions
|
||||
|
||||
<HostProtection(Synchronization:=True)>
|
||||
Public Class RollingXmlWriterTraceListener
|
||||
Inherits XmlWriterTraceListener
|
||||
|
||||
Private Shared ReadOnly LogFileNumberCaptureName As String = "LogFileNumber"
|
||||
Private attributesLoaded As Boolean = False
|
||||
Private logfileSuffixExpression As Regex = New Regex("_(?<" & LogFileNumberCaptureName & ">\d*)\.", RegexOptions.Compiled)
|
||||
Private currentFileSuffixNumber As Integer = 0
|
||||
Private _maxTraceFileSize As Long = 128 * 1024 * 1024
|
||||
Private basicTraceFileName As String = String.Empty
|
||||
|
||||
Public Sub New(ByVal filename As String)
|
||||
MyBase.New(filename)
|
||||
Me.basicTraceFileName = filename
|
||||
Me.currentFileSuffixNumber = Me.GetTraceFileNumber()
|
||||
Me.StartNewTraceFile()
|
||||
End Sub
|
||||
|
||||
Public Sub New(ByVal filename As String, ByVal name As String)
|
||||
MyBase.New(filename, name)
|
||||
Me.basicTraceFileName = filename
|
||||
Me.StartNewTraceFile()
|
||||
End Sub
|
||||
|
||||
Public ReadOnly Property CurrentTraceFileName As String
|
||||
Get
|
||||
Return Path.Combine(Path.GetDirectoryName(Me.basicTraceFileName), Path.GetFileNameWithoutExtension(Me.basicTraceFileName) & "_" & Me.currentFileSuffixNumber.ToString().PadLeft(4, "0"c) & Path.GetExtension(Me.basicTraceFileName))
|
||||
End Get
|
||||
End Property
|
||||
|
||||
Public Property MaxTraceFileSize As Long
|
||||
Get
|
||||
|
||||
If Not Me.attributesLoaded Then
|
||||
Me.LoadAttributes()
|
||||
End If
|
||||
|
||||
Return Me._maxTraceFileSize
|
||||
End Get
|
||||
Set(ByVal value As Long)
|
||||
|
||||
If Not Me.attributesLoaded Then
|
||||
Me.LoadAttributes()
|
||||
End If
|
||||
|
||||
Me._maxTraceFileSize = value
|
||||
End Set
|
||||
End Property
|
||||
|
||||
Protected ReadOnly Property IsRollingConditionReached As Boolean
|
||||
Get
|
||||
Dim streamWriter As StreamWriter = CType(Me.Writer, StreamWriter)
|
||||
Dim fileStream As FileStream = CType(streamWriter.BaseStream, FileStream)
|
||||
Dim traceFileName As String = fileStream.Name
|
||||
Dim traceFileInfo As FileInfo = New FileInfo(traceFileName)
|
||||
|
||||
If traceFileInfo.Length > Me._maxTraceFileSize Then
|
||||
Return True
|
||||
Else
|
||||
Return False
|
||||
End If
|
||||
End Get
|
||||
End Property
|
||||
|
||||
Public Overrides Sub Fail(ByVal message As String)
|
||||
If Me.IsRollingConditionReached Then
|
||||
Me.StartNewTraceFile()
|
||||
End If
|
||||
|
||||
MyBase.Fail(message)
|
||||
End Sub
|
||||
|
||||
Public Overrides Sub Fail(ByVal message As String, ByVal detailMessage As String)
|
||||
If Me.IsRollingConditionReached Then
|
||||
Me.StartNewTraceFile()
|
||||
End If
|
||||
|
||||
MyBase.Fail(message, detailMessage)
|
||||
End Sub
|
||||
|
||||
Public Overrides Sub TraceData(ByVal eventCache As TraceEventCache, ByVal source As String, ByVal eventType As TraceEventType, ByVal id As Integer, ByVal data As Object)
|
||||
If Me.IsRollingConditionReached Then
|
||||
Me.StartNewTraceFile()
|
||||
End If
|
||||
|
||||
MyBase.TraceData(eventCache, source, eventType, id, data)
|
||||
End Sub
|
||||
|
||||
Public Overrides Sub TraceData(ByVal eventCache As TraceEventCache, ByVal source As String, ByVal eventType As TraceEventType, ByVal id As Integer, ParamArray data As Object())
|
||||
If Me.IsRollingConditionReached Then
|
||||
Me.StartNewTraceFile()
|
||||
End If
|
||||
|
||||
MyBase.TraceData(eventCache, source, eventType, id, data)
|
||||
End Sub
|
||||
|
||||
Public Overrides Sub TraceEvent(ByVal eventCache As TraceEventCache, ByVal source As String, ByVal eventType As TraceEventType, ByVal id As Integer)
|
||||
If Me.IsRollingConditionReached Then
|
||||
Me.StartNewTraceFile()
|
||||
End If
|
||||
|
||||
MyBase.TraceEvent(eventCache, source, eventType, id)
|
||||
End Sub
|
||||
|
||||
Public Overrides Sub TraceEvent(ByVal eventCache As TraceEventCache, ByVal source As String, ByVal eventType As TraceEventType, ByVal id As Integer, ByVal message As String)
|
||||
If Me.IsRollingConditionReached Then
|
||||
Me.StartNewTraceFile()
|
||||
End If
|
||||
|
||||
MyBase.TraceEvent(eventCache, source, eventType, id, message)
|
||||
End Sub
|
||||
|
||||
Public Overrides Sub TraceEvent(ByVal eventCache As TraceEventCache, ByVal source As String, ByVal eventType As TraceEventType, ByVal id As Integer, ByVal format As String, ParamArray args As Object())
|
||||
If Me.IsRollingConditionReached Then
|
||||
Me.StartNewTraceFile()
|
||||
End If
|
||||
|
||||
MyBase.TraceEvent(eventCache, source, eventType, id, format, args)
|
||||
End Sub
|
||||
|
||||
Public Overrides Sub TraceTransfer(ByVal eventCache As TraceEventCache, ByVal source As String, ByVal id As Integer, ByVal message As String, ByVal relatedActivityId As Guid)
|
||||
If Me.IsRollingConditionReached Then
|
||||
Me.StartNewTraceFile()
|
||||
End If
|
||||
|
||||
MyBase.TraceTransfer(eventCache, source, id, message, relatedActivityId)
|
||||
End Sub
|
||||
|
||||
Public Overrides Sub Write(ByVal o As Object)
|
||||
If Me.IsRollingConditionReached Then
|
||||
Me.StartNewTraceFile()
|
||||
End If
|
||||
|
||||
MyBase.Write(o)
|
||||
End Sub
|
||||
|
||||
Public Overrides Sub Write(ByVal o As Object, ByVal category As String)
|
||||
If Me.IsRollingConditionReached Then
|
||||
Me.StartNewTraceFile()
|
||||
End If
|
||||
|
||||
MyBase.Write(o, category)
|
||||
End Sub
|
||||
|
||||
Public Overrides Sub Write(ByVal message As String)
|
||||
If Me.IsRollingConditionReached Then
|
||||
Me.StartNewTraceFile()
|
||||
End If
|
||||
|
||||
MyBase.Write(message)
|
||||
End Sub
|
||||
|
||||
Public Overrides Sub Write(ByVal message As String, ByVal category As String)
|
||||
If Me.IsRollingConditionReached Then
|
||||
Me.StartNewTraceFile()
|
||||
End If
|
||||
|
||||
MyBase.Write(message, category)
|
||||
End Sub
|
||||
|
||||
Public Overrides Sub WriteLine(ByVal o As Object)
|
||||
If Me.IsRollingConditionReached Then
|
||||
Me.StartNewTraceFile()
|
||||
End If
|
||||
|
||||
MyBase.WriteLine(o)
|
||||
End Sub
|
||||
|
||||
Public Overrides Sub WriteLine(ByVal o As Object, ByVal category As String)
|
||||
If Me.IsRollingConditionReached Then
|
||||
Me.StartNewTraceFile()
|
||||
End If
|
||||
|
||||
MyBase.WriteLine(o, category)
|
||||
End Sub
|
||||
|
||||
Public Overrides Sub WriteLine(ByVal message As String)
|
||||
If Me.IsRollingConditionReached Then
|
||||
Me.StartNewTraceFile()
|
||||
End If
|
||||
|
||||
MyBase.WriteLine(message)
|
||||
End Sub
|
||||
|
||||
Public Overrides Sub WriteLine(ByVal message As String, ByVal category As String)
|
||||
If Me.IsRollingConditionReached Then
|
||||
Me.StartNewTraceFile()
|
||||
End If
|
||||
|
||||
MyBase.WriteLine(message, category)
|
||||
End Sub
|
||||
|
||||
Protected Overrides Function GetSupportedAttributes() As String()
|
||||
Return New String(0) {"MaxTraceFileSize"}
|
||||
End Function
|
||||
|
||||
Private Sub StartNewTraceFile()
|
||||
Dim streamWriter As StreamWriter = CType(Me.Writer, StreamWriter)
|
||||
Dim fileStream As FileStream = CType(streamWriter.BaseStream, FileStream)
|
||||
fileStream.Close()
|
||||
Me.currentFileSuffixNumber += 1
|
||||
Me.Writer = New StreamWriter(New FileStream(Me.CurrentTraceFileName, FileMode.Create))
|
||||
End Sub
|
||||
|
||||
Private Function GetTraceFileNumber() As Integer
|
||||
Dim directoryName As String = Path.GetDirectoryName(Me.basicTraceFileName)
|
||||
Dim basicTraceFileNameWithoutExtension As String = Path.GetFileNameWithoutExtension(Me.basicTraceFileName)
|
||||
Dim basicTraceFileNameExtension As String = Path.GetExtension(Me.basicTraceFileName)
|
||||
Dim existingLogFiles As String() = Directory.GetFiles(directoryName, basicTraceFileNameWithoutExtension & "*")
|
||||
Dim highestNumber As Integer = -1
|
||||
|
||||
For Each existingLogFile As String In existingLogFiles
|
||||
Dim match As Match = Me.logfileSuffixExpression.Match(existingLogFile)
|
||||
|
||||
If match IsNot Nothing Then
|
||||
Dim tempInt As Integer
|
||||
|
||||
If match.Groups.Count >= 1 AndAlso Integer.TryParse(match.Groups(LogFileNumberCaptureName).Value, tempInt) AndAlso tempInt >= highestNumber Then
|
||||
highestNumber = tempInt
|
||||
End If
|
||||
End If
|
||||
Next
|
||||
|
||||
Return highestNumber
|
||||
End Function
|
||||
|
||||
Private Sub LoadAttributes()
|
||||
If Attributes.ContainsKey("MaxTraceFileSize") AndAlso Not String.IsNullOrEmpty(Attributes("MaxTraceFileSize")) Then
|
||||
Dim tempLong As Long = 0
|
||||
Dim attributeValue As String = Attributes("MaxTraceFileSize")
|
||||
|
||||
If Long.TryParse(attributeValue, tempLong) Then
|
||||
Me._maxTraceFileSize = Long.Parse(Attributes("MaxTraceFileSize"), NumberFormatInfo.InvariantInfo)
|
||||
Else
|
||||
Throw New ConfigurationErrorsException(String.Format("Trace listener {0} has an unparseable configuration attribute ""MaxTraceFileSize"". The value ""{1}"" cannot be parsed to a long value.", Me.Name, attributeValue))
|
||||
End If
|
||||
End If
|
||||
|
||||
Me.attributesLoaded = True
|
||||
End Sub
|
||||
End Class
|
||||
4
Logging/packages.config
Normal file
4
Logging/packages.config
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="NLog" version="4.7.15" targetFramework="net461" />
|
||||
</packages>
|
||||
Reference in New Issue
Block a user