mirror of
https://github.com/KeymonSoft/jRDC-Multi.git
synced 2026-04-17 21:06:24 +00:00
- feat: Implementa control de logs de SQLite granular por DBKey y corrige la concurrencia del Timer en Hot-Swap.
- Este commit introduce una mejora crucial en el rendimiento y la flexibilidad del servidor al permitir el control detallado del registro de logs en SQLite (users.db) por cada base de datos configurada (DB1, DB2, etc.).
- Cambios Principales y Beneficios:
1. Control Granular de Logs: Se reemplazó el flag de control global de logs por un mapa (SQLiteLoggingStatusByDB), permitiendo al administrador deshabilitar el costoso proceso de escritura de query_logs y errores para bases de datos específicas mediante la propiedad enableSQLiteLogs en sus archivos .properties correspondientes.
2. Estabilización del Timer y Hot-Swap:
◦ Se corrigió un problema de concurrencia y estado asegurando que timerLogs se inicialice incondicionalmente, resolviendo el error IllegalStateException: Interval must be larger than 0 que ocurría durante el reload.
◦ El Timer de limpieza (borraArribaDe15000Logs y VACUUM) ahora se activa solo si al menos una base de datos tiene el logging habilitado (IsAnySQLiteLoggingEnabled), minimizando el overhead de E/S de disco cuando los logs no se requieren.
3. Recarga Dinámica de Estado: El comando manager?command=reload ahora lee la configuración enableSQLiteLogs de todos los conectores nuevos y actualiza atómicamente el estado global de logs, aplicando los cambios sin requerir un reinicio del servidor.
472 lines
18 KiB
Plaintext
472 lines
18 KiB
Plaintext
AppType=StandardJava
|
|
Build1=Default,b4j.JRDCMulti
|
|
File1=config.DB2.properties
|
|
File10=stop.bat
|
|
File2=config.DB3.properties
|
|
File3=config.DB4.properties
|
|
File4=config.properties
|
|
File5=login.html
|
|
File6=reiniciaProcesoBow.bat
|
|
File7=reiniciaProcesoPM2.bat
|
|
File8=start.bat
|
|
File9=start2.bat
|
|
FileGroup1=Default Group
|
|
FileGroup10=Default Group
|
|
FileGroup2=Default Group
|
|
FileGroup3=Default Group
|
|
FileGroup4=Default Group
|
|
FileGroup5=Default Group
|
|
FileGroup6=Default Group
|
|
FileGroup7=Default Group
|
|
FileGroup8=Default Group
|
|
FileGroup9=Default Group
|
|
Group=Default Group
|
|
Library1=byteconverter
|
|
Library2=javaobject
|
|
Library3=jcore
|
|
Library4=jrandomaccessfile
|
|
Library5=jserver
|
|
Library6=jshell
|
|
Library7=json
|
|
Library8=jsql
|
|
Library9=bcrypt
|
|
Module1=Cambios
|
|
Module10=Manager
|
|
Module11=ParameterValidationUtils
|
|
Module12=ping
|
|
Module13=RDCConnector
|
|
Module14=TestHandler
|
|
Module2=ChangePassHandler
|
|
Module3=DBHandlerB4X
|
|
Module4=DBHandlerJSON
|
|
Module5=DoLoginHandler
|
|
Module6=faviconHandler
|
|
Module7=GlobalParameters
|
|
Module8=LoginHandler
|
|
Module9=LogoutHandler
|
|
NumberOfFiles=10
|
|
NumberOfLibraries=9
|
|
NumberOfModules=14
|
|
Version=10.3
|
|
@EndOfDesignText@
|
|
'Non-UI application (console / server application)
|
|
|
|
#Region Project Attributes
|
|
|
|
#CommandLineArgs:
|
|
#MergeLibraries: True
|
|
' VERSION 5.09.16
|
|
'###########################################################################################################
|
|
'###################### PULL #############################################################
|
|
'Ctrl + click ide://run?file=%WINDIR%\System32\cmd.exe&Args=/c&Args=git&Args=pull
|
|
'###########################################################################################################
|
|
'###################### PUSH #############################################################
|
|
'Ctrl + click ide://run?file=%WINDIR%\System32\WindowsPowerShell\v1.0\powershell.exe&Args=github&Args=..\..\
|
|
'###########################################################################################################
|
|
'###################### PUSH TORTOISE GIT #########################################################
|
|
'Ctrl + click ide://run?file=%WINDIR%\System32\WindowsPowerShell\v1.0\powershell.exe&Args=TortoiseGitProc&Args=/command:commit&Args=/path:"../"&Args=/closeonend:2
|
|
'###########################################################################################################
|
|
#End Region
|
|
|
|
'change based on the jdbc jar file
|
|
'#AdditionalJar: mysql-connector-java-5.1.27-bin
|
|
'#AdditionalJar: postgresql-42.7.0
|
|
#AdditionalJar: ojdbc11
|
|
' Librería para manejar la base de datos SQLite
|
|
#AdditionalJar: sqlite-jdbc-3.7.2
|
|
|
|
Sub Process_Globals
|
|
' --- Variables globales accesibles desde cualquier parte del proyecto ---
|
|
|
|
' Objeto principal del servidor HTTP de B4J.
|
|
Public srvr As Server
|
|
|
|
' La versión actual de este servidor jRDC modificado.
|
|
Public const VERSION As Float = 2.23
|
|
|
|
' Tipos personalizados (clases) para la serialización y deserialización de datos
|
|
Type DBCommand (Name As String, Parameters() As Object)
|
|
Type DBResult (Tag As Object, Columns As Map, Rows As List)
|
|
|
|
' Contiene una lista de los identificadores de bases de datos configuradas (ej. "DB1", "DB2").
|
|
Public listaDeCP As List
|
|
|
|
' Una lista temporal para almacenar los nombres de archivos de configuración encontrados.
|
|
Private cpFiles As List
|
|
|
|
' Mapas globales para gestionar los conectores de base de datos y los comandos SQL.
|
|
Public Connectors, commandsMap As Map
|
|
|
|
' Objeto SQL para interactuar con la base de datos de usuarios y logs (SQLite).
|
|
Public SQL1 As SQL
|
|
|
|
' Objeto para realizar operaciones de hashing de contraseñas de forma segura.
|
|
Private bc As BCrypt
|
|
|
|
' Objeto de bloqueo (ReentrantLock) para proteger Main.Connectors durante Hot-Swap.
|
|
Public MainConnectorsLock As JavaObject
|
|
|
|
' Timer para ejecutar tareas periódicas, como la limpieza de logs.
|
|
Public timerLogs As Timer
|
|
|
|
' NUEVAS VARIABLES para control granular de logs
|
|
' Mapa para almacenar el estado de logging (True/False) por cada DBKey (DB1, DB2, etc.).
|
|
Public SQLiteLoggingStatusByDB As Map
|
|
' Bandera global que indica si AL MENOS una base de datos tiene los logs habilitados.
|
|
Public IsAnySQLiteLoggingEnabled As Boolean
|
|
|
|
' Tipo para encapsular el resultado de la validación de parámetros.
|
|
Type ParameterValidationResult ( _
|
|
Success As Boolean, _
|
|
ErrorMessage As String, _
|
|
ParamsToExecute As List _ ' La lista de parámetros final a usar en la ejecución SQL
|
|
)
|
|
End Sub
|
|
|
|
Sub AppStart (Args() As String)
|
|
' --- Subrutina principal que se ejecuta al iniciar la aplicación ---
|
|
|
|
bc.Initialize("BC")
|
|
|
|
' 1. Inicializa la base de datos local de usuarios (SQLite) y la tabla de logs.
|
|
InitializeSQLiteDatabase
|
|
|
|
' 2. Inicializa los mapas globales definidos en GlobalParameters.bas.
|
|
GlobalParameters.mpLogs.Initialize
|
|
GlobalParameters.mpTotalRequests.Initialize
|
|
GlobalParameters.mpTotalConnections.Initialize
|
|
GlobalParameters.mpBlockConnection.Initialize
|
|
|
|
' Aseguramos que el mapa de conteo de peticiones activas sea thread-safe.
|
|
GlobalParameters.ActiveRequestsCountByDB = srvr.CreateThreadSafeMap
|
|
|
|
' 3. Inicializa las estructuras principales del servidor HTTP.
|
|
listaDeCP.Initialize
|
|
srvr.Initialize("")
|
|
Connectors = srvr.CreateThreadSafeMap
|
|
commandsMap.Initialize
|
|
|
|
' NUEVO: Inicializar el mapa de estado de logs granular
|
|
SQLiteLoggingStatusByDB.Initialize
|
|
|
|
' Creamos una instancia de ReentrantLock para proteger Main.Connectors.
|
|
MainConnectorsLock.InitializeNewInstance("java.util.concurrent.locks.ReentrantLock", Null)
|
|
|
|
|
|
' === 4. INICIALIZACIÓN DEL CONECTOR PARA LA BASE DE DATOS PRINCIPAL (DB1) ===
|
|
|
|
Try
|
|
Dim con1 As RDCConnector
|
|
con1.Initialize("DB1")
|
|
Connectors.Put("DB1", con1)
|
|
srvr.Port = con1.serverPort
|
|
listaDeCP.Add("DB1")
|
|
Log($"Main.AppStart: Conector 'DB1' inicializado exitosamente en puerto: ${srvr.Port}"$)
|
|
|
|
' Lógica de Logs para DB1 (Fuente principal de configuración)
|
|
Dim enableLogsSetting As Int = con1.config.GetDefault("enableSQLiteLogs", 1).As(Int)
|
|
Dim isEnabled As Boolean = (enableLogsSetting = 1)
|
|
SQLiteLoggingStatusByDB.Put("DB1", isEnabled) ' Guardar el estado
|
|
|
|
Catch
|
|
Dim ErrorMsg As String = $"Main.AppStart: ERROR CRÍTICO al inicializar conector 'DB1': ${LastException.Message}"$
|
|
Log(ErrorMsg)
|
|
LogServerError("ERROR", "Main.AppStart", ErrorMsg, "DB1", Null, Null)
|
|
ExitApplication
|
|
End Try
|
|
|
|
' === 5. DETECCIÓN E INICIALIZACIÓN DE BASES DE DATOS ADICIONALES (DB2, DB3, DB4) ===
|
|
|
|
cpFiles = File.ListFiles("./")
|
|
If cpFiles.Size > 0 Then
|
|
For i = 0 To cpFiles.Size - 1
|
|
|
|
' Procesa 'config.DB2.properties'
|
|
If cpFiles.Get(i) = "config.DB2.properties" Then
|
|
Try
|
|
Dim con2 As RDCConnector
|
|
con2.Initialize("DB2")
|
|
Connectors.Put("DB2", con2)
|
|
listaDeCP.Add("DB2")
|
|
Log("Main.AppStart: Conector 'DB2' inicializado exitosamente.")
|
|
|
|
' Lógica de Logs para DB2
|
|
Dim enableLogsSetting As Int = con2.config.GetDefault("enableSQLiteLogs", 0).As(Int)
|
|
Dim isEnabled As Boolean = (enableLogsSetting = 1)
|
|
SQLiteLoggingStatusByDB.Put("DB2", isEnabled) ' Guardar el estado
|
|
|
|
Catch
|
|
Dim ErrorMsg As String = $"Main.AppStart: ERROR al inicializar conector 'DB2': ${LastException.Message}"$
|
|
Log(ErrorMsg)
|
|
LogServerError("ERROR", "Main.AppStart", ErrorMsg, "DB2", Null, Null)
|
|
End Try
|
|
End If
|
|
|
|
' Procesa 'config.DB3.properties'
|
|
If cpFiles.Get(i) = "config.DB3.properties" Then
|
|
Try
|
|
Dim con3 As RDCConnector
|
|
con3.Initialize("DB3")
|
|
Connectors.Put("DB3", con3)
|
|
listaDeCP.Add("DB3")
|
|
Log("Main.AppStart: Conector 'DB3' inicializado exitosamente.")
|
|
|
|
' Lógica de Logs para DB3
|
|
Dim enableLogsSetting As Int = con3.config.GetDefault("enableSQLiteLogs", 0).As(Int)
|
|
Dim isEnabled As Boolean = (enableLogsSetting = 1)
|
|
SQLiteLoggingStatusByDB.Put("DB3", isEnabled) ' Guardar el estado
|
|
|
|
Catch
|
|
Dim ErrorMsg As String = $"Main.AppStart: ERROR al inicializar conector 'DB3': ${LastException.Message}"$
|
|
Log(ErrorMsg)
|
|
LogServerError("ERROR", "Main.AppStart", ErrorMsg, "DB3", Null, Null)
|
|
End Try
|
|
End If
|
|
|
|
' Procesa 'config.DB4.properties'
|
|
If cpFiles.Get(i) = "config.DB4.properties" Then
|
|
Try
|
|
Dim con4 As RDCConnector
|
|
con4.Initialize("DB4")
|
|
Connectors.Put("DB4", con4)
|
|
listaDeCP.Add("DB4")
|
|
Log("Main.AppStart: Conector 'DB4' inicializado exitosamente.")
|
|
|
|
' Lógica de Logs para DB4
|
|
Dim enableLogsSetting As Int = con4.config.GetDefault("enableSQLiteLogs", 0).As(Int)
|
|
Dim isEnabled As Boolean = (enableLogsSetting = 1)
|
|
SQLiteLoggingStatusByDB.Put("DB4", isEnabled) ' Guardar el estado
|
|
|
|
Catch
|
|
Dim ErrorMsg As String = $"Main.AppStart: ERROR al inicializar conector 'DB4': ${LastException.Message}"$
|
|
Log(ErrorMsg)
|
|
LogServerError("ERROR", "Main.AppStart", ErrorMsg, "DB4", Null, Null)
|
|
End Try
|
|
End If
|
|
|
|
Next
|
|
Else
|
|
Log("Main.AppStart: No se encontraron archivos de configuración adicionales (config.DBx.properties).")
|
|
End If
|
|
|
|
' Log final de las bases de datos que el servidor está gestionando.
|
|
Dim sbListaDeCP_Log As StringBuilder
|
|
sbListaDeCP_Log.Initialize
|
|
For Each item As String In listaDeCP
|
|
sbListaDeCP_Log.Append(item).Append(", ")
|
|
Next
|
|
If sbListaDeCP_Log.Length > 0 Then
|
|
sbListaDeCP_Log.Remove(sbListaDeCP_Log.Length - 2, sbListaDeCP_Log.Length)
|
|
End If
|
|
Log($"Main.AppStart: Bases de datos configuradas y listas: [${sbListaDeCP_Log.ToString}]"$)
|
|
|
|
' <<<< Bloque de inicialización del Timer para la limpieza de logs >>>>
|
|
|
|
' Inicialización INCONDICIONAL del Timer (Garantiza que el objeto exista y prevenga el IllegalStateException)
|
|
timerLogs.Initialize("TimerLogs", 600000) ' 10 minutos = 600 * 1000 = 600000 ms
|
|
|
|
' CONTROL CONDICIONAL BASADO EN EL ESTADO GRANULAR
|
|
IsAnySQLiteLoggingEnabled = False
|
|
For Each dbStatus As Boolean In SQLiteLoggingStatusByDB.Values
|
|
If dbStatus Then
|
|
IsAnySQLiteLoggingEnabled = True
|
|
Exit ' Si uno está activo, es suficiente para encender el Timer
|
|
End If
|
|
Next
|
|
|
|
If IsAnySQLiteLoggingEnabled Then
|
|
timerLogs.Enabled = True
|
|
Log("Main.AppStart: Timer de limpieza de logs ACTIVADO (al menos una DB requiere logs).")
|
|
Else
|
|
timerLogs.Enabled = False
|
|
Log("Main.AppStart: Timer de limpieza de logs DESHABILITADO (ninguna DB requiere logs).")
|
|
End If
|
|
|
|
' <<<< Fin del bloque del Timer >>>>
|
|
|
|
' === 6. REGISTRO DE HANDLERS HTTP PARA EL SERVIDOR ===
|
|
srvr.AddHandler("/ping", "ping", False)
|
|
srvr.AddHandler("/test", "TestHandler", False)
|
|
srvr.AddHandler("/login", "LoginHandler", False)
|
|
srvr.AddHandler("/dologin", "DoLoginHandler", False)
|
|
srvr.AddHandler("/logout", "LogoutHandler", False)
|
|
srvr.AddHandler("/changepass", "ChangePassHandler", False)
|
|
srvr.AddHandler("/manager", "Manager", False)
|
|
srvr.AddHandler("/DBJ", "DBHandlerJSON", False)
|
|
srvr.AddHandler("/dbrquery", "DBHandlerJSON", False)
|
|
srvr.AddHandler("/favicon.ico", "faviconHandler", False)
|
|
srvr.AddHandler("/*", "DBHandlerB4X", False)
|
|
|
|
' 7. Inicia el servidor HTTP.
|
|
srvr.Start
|
|
Log("===========================================================")
|
|
Log($"-=== jRDC está funcionando en el puerto: ${srvr.Port} (versión = $1.2{VERSION}) ===-"$)
|
|
Log("===========================================================")
|
|
|
|
' 8. Inicia el bucle de mensajes de B4J.
|
|
StartMessageLoop
|
|
End Sub
|
|
|
|
' --- Subrutina para inicializar la base de datos de usuarios local (SQLite) ---
|
|
|
|
Sub InitializeSQLiteDatabase
|
|
Dim dbFileName As String = "users.db"
|
|
|
|
If File.Exists(File.DirApp, dbFileName) = False Then
|
|
Log("Creando nueva base de datos de usuarios: " & dbFileName)
|
|
SQL1.InitializeSQLite(File.DirApp, dbFileName, True)
|
|
|
|
' Crear tabla 'users'
|
|
Dim createUserTable As String = "CREATE TABLE users (username TEXT PRIMARY KEY, password_hash TEXT NOT NULL)"
|
|
SQL1.ExecNonQuery(createUserTable)
|
|
|
|
' Crear tabla 'query_logs'
|
|
Log("Creando tabla 'query_logs' con columnas de rendimiento.")
|
|
Dim createQueryLogsTable As String = "CREATE TABLE query_logs (id INTEGER PRIMARY KEY AUTOINCREMENT, query_name TEXT, duration_ms INTEGER, timestamp INTEGER, db_key TEXT, client_ip TEXT, busy_connections INTEGER, handler_active_requests INTEGER)"
|
|
SQL1.ExecNonQuery(createQueryLogsTable)
|
|
|
|
' Insertar usuario por defecto
|
|
Dim defaultUser As String = "admin"
|
|
Dim defaultPass As String = "12345"
|
|
Dim hashedPass As String = bc.hashpw(defaultPass, bc.gensalt)
|
|
SQL1.ExecNonQuery2("INSERT INTO users (username, password_hash) VALUES (?, ?)", Array As Object(defaultUser, hashedPass))
|
|
Log($"Usuario por defecto creado -> user: ${defaultUser}, pass: ${defaultPass}"$)
|
|
|
|
' Crear tabla 'errores'
|
|
Log("Creando tabla 'errores' para registrar eventos.")
|
|
Dim createErrorsTable As String = "CREATE TABLE errores (id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER, type TEXT, source TEXT, message TEXT, db_key TEXT, command_name TEXT, client_ip TEXT)"
|
|
SQL1.ExecNonQuery(createErrorsTable)
|
|
|
|
Else
|
|
SQL1.InitializeSQLite(File.DirApp, dbFileName, True)
|
|
Log("Base de datos de usuarios cargada.")
|
|
|
|
' >>> INICIO: Lógica de migración (ALTER TABLE) si la DB ya existía <<<
|
|
Log("Verificando y migrando tabla 'query_logs' si es necesario.")
|
|
|
|
If SQL1.ExecQuerySingleResult("SELECT name FROM sqlite_master WHERE type='table' AND name='query_logs'") = Null Then
|
|
|
|
Log("Tabla 'query_logs' no encontrada, creándola con columnas de rendimiento.")
|
|
|
|
Dim createQueryLogsTable As String = "CREATE TABLE query_logs (id INTEGER PRIMARY KEY AUTOINCREMENT, query_name TEXT, duration_ms INTEGER, timestamp INTEGER, db_key TEXT, client_ip TEXT, busy_connections INTEGER, handler_active_requests INTEGER)"
|
|
|
|
SQL1.ExecNonQuery(createQueryLogsTable)
|
|
|
|
Else
|
|
|
|
' Si la tabla query_logs ya existe, entonces verificamos y añadimos las columnas faltantes (busy_connections, handler_active_requests).
|
|
Dim columnExists As Boolean
|
|
Dim rs As ResultSet
|
|
|
|
' --- VERIFICAR Y AÑADIR busy_connections ---
|
|
columnExists = False
|
|
rs = SQL1.ExecQuery("PRAGMA table_info(query_logs)")
|
|
|
|
Do While rs.NextRow
|
|
If rs.GetString("name").EqualsIgnoreCase("busy_connections") Then
|
|
columnExists = True
|
|
Exit ' La columna ya existe, salimos del bucle.
|
|
End If
|
|
Loop
|
|
rs.Close
|
|
|
|
If columnExists = False Then
|
|
Log("Añadiendo columna 'busy_connections' a query_logs.")
|
|
SQL1.ExecNonQuery("ALTER TABLE query_logs ADD COLUMN busy_connections INTEGER DEFAULT 0")
|
|
End If
|
|
|
|
' --- VERIFICAR Y AÑADIR handler_active_requests ---
|
|
columnExists = False
|
|
rs = SQL1.ExecQuery("PRAGMA table_info(query_logs)")
|
|
|
|
Do While rs.NextRow
|
|
If rs.GetString("name").EqualsIgnoreCase("handler_active_requests") Then
|
|
columnExists = True
|
|
Exit ' La columna ya existe, salimos del bucle.
|
|
End If
|
|
Loop
|
|
rs.Close
|
|
|
|
If columnExists = False Then
|
|
Log("Añadiendo columna 'handler_active_requests' a query_logs.")
|
|
SQL1.ExecNonQuery("ALTER TABLE query_logs ADD COLUMN handler_active_requests INTEGER DEFAULT 0")
|
|
End If
|
|
|
|
|
|
' >>> INICIO: Lógica de migración para 'errores' si la DB ya existía <<<
|
|
Log("Verificando y migrando tabla 'errores' si es necesario.")
|
|
|
|
If SQL1.ExecQuerySingleResult("SELECT name FROM sqlite_master WHERE type='table' AND name='errores'") = Null Then
|
|
Log("Tabla 'errores' no encontrada, creándola.")
|
|
Dim createErrorsTable As String = "CREATE TABLE errores (id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER, type TEXT, source TEXT, message TEXT, db_key TEXT, command_name TEXT, client_ip TEXT)"
|
|
SQL1.ExecNonQuery(createErrorsTable)
|
|
Else
|
|
Log("Tabla 'errores' ya existe.")
|
|
End If
|
|
' >>> FIN: Lógica de migración para 'errores' <<<
|
|
|
|
End If
|
|
' >>> FIN: Lógica de migración (ALTER TABLE) <<<
|
|
|
|
End If
|
|
End Sub
|
|
|
|
' --- Subrutina para registrar las métricas de rendimiento de las queries en la tabla 'query_logs'. ---
|
|
' ¡MODIFICADA PARA USAR FILTRADO GRANULAR POR DBKEY!
|
|
Public Sub LogQueryPerformance(QueryName As String, DurationMs As Long, DbKey As String, ClientIp As String, HandlerActiveRequests As Int, PoolBusyConnections As Int)
|
|
|
|
' Obtener el estado de logging para esta DBKey. Usar False si la DBKey no existe en el mapa.
|
|
Dim isEnabled As Boolean = SQLiteLoggingStatusByDB.GetDefault(DbKey, False)
|
|
|
|
If isEnabled Then
|
|
Try
|
|
SQL1.ExecNonQuery2("INSERT INTO query_logs (query_name, duration_ms, timestamp, db_key, client_ip, busy_connections, handler_active_requests) VALUES (?, ?, ?, ?, ?, ?, ?)", _
|
|
Array As Object(QueryName, DurationMs, DateTime.Now, DbKey, ClientIp, PoolBusyConnections, HandlerActiveRequests))
|
|
Catch
|
|
Log("Error al guardar log de query en SQLite (Main.LogQueryPerformance): " & LastException.Message)
|
|
End Try
|
|
End If
|
|
End Sub
|
|
|
|
' --- Subrutina para registrar errores y advertencias en la tabla 'errores'. ---
|
|
' ¡MODIFICADA PARA USAR FILTRADO GRANULAR POR DBKEY!
|
|
Public Sub LogServerError(Type0 As String, Source As String, Message As String, DBKey As String, CommandName As String, ClientIp As String)
|
|
|
|
' Obtener el estado de logging para esta DBKey. Usar False si la DBKey es Null o no está en el mapa.
|
|
Dim isEnabled As Boolean = SQLiteLoggingStatusByDB.GetDefault(DBKey, False)
|
|
|
|
If isEnabled Then
|
|
Try
|
|
SQL1.ExecNonQuery2("INSERT INTO errores (timestamp, type, source, message, db_key, command_name, client_ip) VALUES (?, ?, ?, ?, ?, ?, ?)", _
|
|
Array As Object(DateTime.Now, Type0, Source, Message, DBKey, CommandName, ClientIp))
|
|
Catch
|
|
Log("ERROR CRÍTICO: Fallo al guardar el log de error/advertencia en SQLite (Main.LogServerError): " & LastException.Message)
|
|
End Try
|
|
End If
|
|
End Sub
|
|
|
|
' --- Subrutina de evento para el Timer 'timerLogs'. ---
|
|
' El estado 'Enabled' del Timer ya está controlado por IsAnySQLiteLoggingEnabled en AppStart y Manager.
|
|
Sub TimerLogs_Tick
|
|
Try
|
|
borraArribaDe15000Logs
|
|
Catch
|
|
Dim ErrorMsg As String = "ERROR en TimerLogs_Tick al intentar borrar logs: " & LastException.Message
|
|
Log(ErrorMsg)
|
|
LogServerError("ERROR", "Main.TimerLogs_Tick", ErrorMsg, Null, "log_cleanup", Null)
|
|
End Try
|
|
End Sub
|
|
|
|
' --- Borra los registros más antiguos de la tabla 'query_logs' y hace VACUUM. ---
|
|
' ¡MODIFICADA PARA USAR FILTRADO GLOBAL!
|
|
Sub borraArribaDe15000Logs 'ignore
|
|
|
|
If IsAnySQLiteLoggingEnabled Then ' Solo ejecutar si al menos una DB requiere logs.
|
|
Log("Recortando la tabla de 'query_logs', límite de 15,000 registros.")
|
|
SQL1.ExecNonQuery("DELETE FROM query_logs WHERE timestamp NOT in (SELECT timestamp FROM query_logs ORDER BY timestamp desc LIMIT 15000 )")
|
|
SQL1.ExecNonQuery("vacuum;")
|
|
Else
|
|
' Si IsAnySQLiteLoggingEnabled es False, el Timer no debería estar activo.
|
|
Log("AVISO: Tarea de limpieza de logs omitida. El logging global de SQLite está deshabilitado.")
|
|
End If
|
|
End Sub |