219 lines
11 KiB
VB.net
219 lines
11 KiB
VB.net
Imports System.Net.Http
|
|
Imports System.IO
|
|
Imports Microsoft.Extensions.Logging
|
|
Imports System.Threading.Tasks
|
|
Imports System.Configuration
|
|
|
|
'// Ejemplo de uso de la extensión LogVariable():
|
|
'//
|
|
'// ' Registrar información de una variable
|
|
'// Dim peassoVariable As String = "Hello, World!"
|
|
'// logger.LogVariable("peassoVariable", peassoVariable, LogLevel.Debug)
|
|
|
|
'// El uso del destino Pushover está limitado a danmun.
|
|
|
|
Public NotInheritable Class TsLoggerConfiguration
|
|
'// Identificador del evento a registrar (0 para todos).
|
|
Public Property EventId As Integer = 0
|
|
'// Nivel mínimo de registro.
|
|
Private Property _minimumLogLevel As LogLevel = LogLevel.Trace
|
|
Public Property MinimumLogLevel As String
|
|
Get
|
|
Return _minimumLogLevel
|
|
End Get
|
|
Set(logLevelString As String)
|
|
If Not [Enum].TryParse(logLevelString, True, _minimumLogLevel) Then
|
|
'// Valor predeterminado en caso de que no se pueda
|
|
'// interpretar la configuración.
|
|
_minimumLogLevel = LogLevel.Trace
|
|
End If
|
|
End Set
|
|
End Property
|
|
'// Indica si se debe registrar en la consola.
|
|
Public Property LogToConsole As Boolean = False
|
|
'// Indica si se debe registrar en la salida de depuración.
|
|
Public Property LogToDebug As Boolean = True
|
|
'// Indica si se debe registrar en un archivo.
|
|
Public Property LogToFile As Boolean = False
|
|
'// Ruta base para los archivos de registro (debe ser válida y accesible).
|
|
Public Property LogFilePath As String
|
|
Public Property LogToPushover As Boolean = False
|
|
Public Property PushoverMinimumLogLevel As LogLevel = LogLevel.Error
|
|
Public Property LogToSlack As Boolean = False
|
|
Public Property SlackDestination As String = "#notificaciones"
|
|
Public Property NetworkInSeparateThread As Boolean = False
|
|
Public Property IncludeSourceInfo As Boolean = False
|
|
'// Mapeo entre los niveles de registro y los colores de la consola.
|
|
Friend ReadOnly Property LogLevelToColorMap As Dictionary(Of LogLevel, ConsoleColor) = New Dictionary(Of LogLevel, ConsoleColor) From {
|
|
{LogLevel.Trace, ConsoleColor.DarkCyan},
|
|
{LogLevel.Debug, ConsoleColor.Cyan},
|
|
{LogLevel.Information, ConsoleColor.Green},
|
|
{LogLevel.Warning, ConsoleColor.DarkYellow},
|
|
{LogLevel.Error, ConsoleColor.Red},
|
|
{LogLevel.Critical, ConsoleColor.Magenta}
|
|
}
|
|
End Class
|
|
|
|
Public NotInheritable Class TsLogger
|
|
Implements ILogger
|
|
|
|
Private ReadOnly _name As String
|
|
Private ReadOnly _getCurrentConfig As Func(Of TsLoggerConfiguration)
|
|
Private ReadOnly _config As TsLoggerConfiguration
|
|
|
|
'// Constructor con nombre y función para obtener la configuración actual.
|
|
Public Sub New(name As String, getCurrentConfig As Func(Of TsLoggerConfiguration))
|
|
If String.IsNullOrEmpty(name) Then Throw New ArgumentException("El nombre no puede estar vacío", NameOf(name))
|
|
If getCurrentConfig Is Nothing Then Throw New ArgumentNullException(NameOf(getCurrentConfig))
|
|
_name = name
|
|
_getCurrentConfig = getCurrentConfig
|
|
End Sub
|
|
|
|
'// Constructor con nombre y configuración directa.
|
|
Public Sub New(name As String, config As TsLoggerConfiguration)
|
|
If String.IsNullOrEmpty(name) Then Throw New ArgumentException("El nombre no puede estar vacío", NameOf(name))
|
|
If config Is Nothing Then Throw New ArgumentNullException(NameOf(config))
|
|
_name = name
|
|
_config = config
|
|
End Sub
|
|
|
|
'// Obtener la configuración actual.
|
|
Private Function GetCurrentConfiguration() As TsLoggerConfiguration
|
|
Return If(_getCurrentConfig IsNot Nothing, _getCurrentConfig.Invoke(), _config)
|
|
End Function
|
|
|
|
'// Verifica si el nivel de registro está habilitado.
|
|
Public Function IsEnabled(logLevel As LogLevel) As Boolean Implements ILogger.IsEnabled
|
|
Return logLevel >= GetCurrentConfiguration().MinimumLogLevel
|
|
End Function
|
|
|
|
'// Registra un mensaje con la configuración dada.
|
|
Public Sub Log(Of TState)(logLevel As LogLevel, eventId As EventId, state As TState, exception As Exception, formatter As Func(Of TState, Exception, String)) Implements ILogger.Log
|
|
Try
|
|
Dim config As TsLoggerConfiguration = GetCurrentConfiguration() '// Obtener la configuración.
|
|
If Not IsEnabled(logLevel) Then Return
|
|
|
|
'// Obtener la información del archivo de código fuente si está habilitado.
|
|
Dim sourceInfo As String = ""
|
|
If config.IncludeSourceInfo Then
|
|
Dim stackTrace As New Diagnostics.StackTrace(True)
|
|
Dim frame As Diagnostics.StackFrame = stackTrace.GetFrame(1)
|
|
Dim fileName As String = frame.GetFileName()
|
|
Dim method As String = frame.GetMethod().Name
|
|
Dim line As Integer = frame.GetFileLineNumber()
|
|
sourceInfo = $" [Archivo: {fileName}, Método: {method}, Línea: {line}]"
|
|
End If
|
|
|
|
'// Mensaje básico sin la fecha y hora.
|
|
Dim basicMessage As String = $"[{eventId.Id,2}: {logLevel,-12}] {_name} - {formatter(state, exception)}{sourceInfo}"
|
|
'// Agregar la fecha y hora actual al inicio del mensaje para consola y archivo.
|
|
Dim timestamp As String = DateTime.Now.ToString("yyyy-MM-dd_HH·mm·sszz")
|
|
Dim messageWithTimestamp As String = $"{timestamp} {basicMessage}"
|
|
|
|
'// Registrar en la consola si está habilitado.
|
|
If config.LogToConsole Then
|
|
Console.ForegroundColor = config.LogLevelToColorMap(logLevel)
|
|
Console.WriteLine(messageWithTimestamp)
|
|
End If
|
|
|
|
'// Registrar en la salida de depuración si está habilitado.
|
|
If config.LogToDebug Then
|
|
Debug.WriteLine(basicMessage)
|
|
End If
|
|
|
|
'// Registrar en un archivo si está habilitado.
|
|
If config.LogToFile Then
|
|
If String.IsNullOrEmpty(config.LogFilePath) Then
|
|
Debug.WriteLine($"La ruta del archivo de registro no está especificada. Se omite el registro en archivos para el mensaje: {basicMessage}")
|
|
Else
|
|
Try
|
|
'// Intentar crear el directorio si no existe.
|
|
Directory.CreateDirectory(config.LogFilePath)
|
|
Dim folderPath As String = Path.Combine(config.LogFilePath, DateTime.Now.ToString("yyyy\\MM"))
|
|
Directory.CreateDirectory(folderPath)
|
|
|
|
Dim fileName As String = $"{DateTime.Now:yyyy-MM-dd_HH·mm·sszz}_{_name}.log"
|
|
Dim filePath As String = Path.Combine(folderPath, fileName)
|
|
|
|
Using writer As New StreamWriter(filePath, append:=True)
|
|
writer.WriteLine(messageWithTimestamp)
|
|
End Using
|
|
Catch ex As IOException
|
|
Debug.WriteLine($"Error al intentar crear o acceder a la ruta del archivo de registro '{config.LogFilePath}'. Error: {ex}")
|
|
End Try
|
|
End If
|
|
End If
|
|
|
|
'// Enviar notificación a Pushover si está habilitado.
|
|
If config.LogToPushover AndAlso logLevel >= config.PushoverMinimumLogLevel Then
|
|
Dim parameters As New Dictionary(Of String, String) From {
|
|
{"token", "a42g7oaz2t4u7unbdg5nm7qaqocht6"},
|
|
{"user", "uxzAV6NcPoxkAGLSNWSsZX9SfPeUo5"},
|
|
{"message", basicMessage},
|
|
{"title", $"{_name}"}, '// Utilizar el nombre del registrador como título.
|
|
{"priority", GetPushoverPriority(logLevel)} '// Establecer la prioridad en función del nivel de registro.
|
|
}
|
|
If config.NetworkInSeparateThread Then
|
|
Task.Run(Sub()
|
|
Using client As New HttpClient()
|
|
Dim response = client.PostAsync("https://api.pushover.net/1/messages.json", New FormUrlEncodedContent(parameters)).Result
|
|
Debug.WriteLine(response.ToString)
|
|
End Using
|
|
End Sub)
|
|
Else
|
|
Using client As New HttpClient()
|
|
Dim response = client.PostAsync("https://api.pushover.net/1/messages.json", New FormUrlEncodedContent(parameters)).Result
|
|
Debug.WriteLine(response.ToString)
|
|
End Using
|
|
End If
|
|
End If
|
|
|
|
'// Enviar notificación a Slack si está habilitado.
|
|
If config.LogToSlack Then
|
|
If config.NetworkInSeparateThread Then
|
|
Task.Run(Sub()
|
|
tsl5.Utilidades.EnviarNotificacionSlack(basicMessage, otroTexto:=timestamp, descripcionRemitente:=$"TsLogger {_name}", destinatario:=config.SlackDestination)
|
|
End Sub)
|
|
Else
|
|
tsl5.Utilidades.EnviarNotificacionSlack(basicMessage, otroTexto:=timestamp, descripcionRemitente:=$"TsLogger {_name}", destinatario:=config.SlackDestination)
|
|
End If
|
|
End If
|
|
Catch ex As Exception
|
|
Debug.WriteLine($"Excepción en TsLogger: {ex}")
|
|
End Try
|
|
End Sub
|
|
|
|
'// Implementación básica de BeginScope (no se necesita un manejo detallado de alcance en esta implementación).
|
|
Private Function ILogger_BeginScope(Of TState)(state As TState) As IDisposable Implements ILogger.BeginScope
|
|
Return New EmptyDisposable()
|
|
End Function
|
|
|
|
'// Clase auxiliar para cumplir con la interfaz IDisposable requerida por BeginScope.
|
|
Private Class EmptyDisposable
|
|
Implements IDisposable
|
|
Public Sub Dispose() Implements IDisposable.Dispose
|
|
'// No se requiere ninguna acción aquí.
|
|
End Sub
|
|
End Class
|
|
' Método auxiliar para convertir el nivel de registro en una prioridad para Pushover.
|
|
Private Function GetPushoverPriority(logLevel As LogLevel) As String
|
|
Select Case logLevel
|
|
Case LogLevel.Critical
|
|
Return "1" ' Prioridad alta
|
|
Case LogLevel.Error
|
|
Return "1" ' Prioridad alta
|
|
Case LogLevel.Warning
|
|
Return "0" ' Prioridad normal
|
|
Case LogLevel.Information
|
|
Return "-1" ' Prioridad baja
|
|
Case LogLevel.Debug
|
|
Return "-1" ' Prioridad baja
|
|
Case LogLevel.Trace
|
|
Return "-2" ' Prioridad mínima
|
|
Case Else
|
|
Return "0" ' Prioridad normal
|
|
End Select
|
|
End Function
|
|
End Class
|
|
|