mirror of
https://github.com/KeymonSoft/jRDC-Multi.git
synced 2026-04-17 21:06:24 +00:00
- VERSION 5.09.16.2
- feat(logs): Implementación de Cacheo y Escritura Transaccional en Lotes - Implementa la funcionalidad de cacheo de logs en memoria y escritura transaccional para reducir el overhead de E/S de disco en SQLite [1, 2]. - Cambios principales: 1. Refactorización de LogQueryPerformance y LogServerError para que solo almacenen logs en las cachés globales (QueryLogCache y ErrorLogCache) [3]. 2. Introducción de WriteQueryLogsBatch y WriteErrorLogsBatch, que vacían las cachés y realizan la inserción a SQLite dentro de una única transacción atómica (`BeginTransaction`/`TransactionSuccessful`), disparada por umbral (`LOG_CACHE_THRESHOLD`) o periódicamente por `TimerLogs_Tick` [4-7]. 3. Corrección del manejo de objetos List en las rutinas de lote (Write*LogsBatch): Se implementó la copia explícita de contenido (`List.AddAll`) dentro del bloqueo (`MainConnectorsLock`) para asegurar que el lote mantenga sus registros, resolviendo el problema de tamaño cero causado por la asignación de referencias.
This commit is contained in:
14
Cambios.bas
14
Cambios.bas
@@ -26,6 +26,20 @@ Sub Process_Globals
|
|||||||
' - Que en el reporte de "Queries lentos" se pueda especificar de cuanto tiempo, ahorita esta de la ultima hora, pero que se pueda seleccionar desde una
|
' - Que en el reporte de "Queries lentos" se pueda especificar de cuanto tiempo, ahorita esta de la ultima hora, pero que se pueda seleccionar desde una
|
||||||
' lista, por ejemplo 15, 30, 45 y 60 minutos antes.
|
' lista, por ejemplo 15, 30, 45 y 60 minutos antes.
|
||||||
|
|
||||||
|
' - VERSION 5.09.16.2
|
||||||
|
' - feat(logs): Implementación de Cacheo y Escritura Transaccional en Lotes
|
||||||
|
'
|
||||||
|
' - Implementa la funcionalidad de cacheo de logs en memoria y escritura transaccional para reducir el overhead de E/S de disco en SQLite [1, 2].
|
||||||
|
'
|
||||||
|
' - Cambios principales:
|
||||||
|
' 1. Refactorización de LogQueryPerformance y LogServerError para que solo almacenen logs en las cachés globales (QueryLogCache y ErrorLogCache) [3].
|
||||||
|
' 2. Introducción de WriteQueryLogsBatch y WriteErrorLogsBatch, que vacían las cachés y realizan la inserción a SQLite dentro de una única transacción atómica (`BeginTransaction`/`TransactionSuccessful`), disparada por umbral (`LOG_CACHE_THRESHOLD`) o periódicamente por `TimerLogs_Tick` [4-7].
|
||||||
|
' 3. Corrección del manejo de objetos List en las rutinas de lote (Write*LogsBatch): Se implementó la copia explícita de contenido (`List.AddAll`) dentro del bloqueo (`MainConnectorsLock`) para asegurar que el lote mantenga sus registros, resolviendo el problema de tamaño cero causado por la asignación de referencias.
|
||||||
|
|
||||||
|
' - VERSION 5.09.16.1
|
||||||
|
' 1. Detalle de Comandos Batch: Se modificó DBHandlerB4X.bas (ExecuteBatch V1 y ExecuteBatch2 V2) para que, en lotes de tamaño 1, el Log retorne el nombre específico del comando (queryName) en lugar del genérico "batch (size=1)". Esto asegura que el query_logs registre la query exacta junto a su dbKey.
|
||||||
|
' 2. Timestamp Legible en SQLite: Se añade la columna timestamp_text_local a la tabla query_logs (incluyendo la lógica de migración en Main.InitializeSQLiteDatabase) y se actualiza Main.LogQueryPerformance para calcular e insertar el tiempo en formato yyyy/mm/dd HH:mm:ss.sss. Esto permite la inspección directa de la base de datos Sin necesidad de conversiones, mejorando la usabilidad para el análisis de rendimiento.
|
||||||
|
|
||||||
' - Versión: 5.09.16
|
' - Versión: 5.09.16
|
||||||
' - feat: Implementa control de logs de SQLite granular por DBKey y corrige la concurrencia del Timer en Hot-Swap.
|
' - 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.).
|
' - 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.).
|
||||||
|
|||||||
@@ -408,7 +408,17 @@ Private Sub ExecuteBatch2(DB As String, con As SQL, in As InputStream, resp As S
|
|||||||
resp.OutputStream.WriteBytes(data, 0, data.Length)
|
resp.OutputStream.WriteBytes(data, 0, data.Length)
|
||||||
|
|
||||||
' Devuelve un resumen para el log.
|
' Devuelve un resumen para el log.
|
||||||
Return $"batch (size=${commands.Size})"$
|
' Return $"batch (size=${commands.Size})"$
|
||||||
|
|
||||||
|
' Devuelve un resumen para el log, incluyendo el nombre de la query si es un lote de tamaño 1.
|
||||||
|
If commands.Size = 1 Then
|
||||||
|
' Obtenemos el único comando en el lote.
|
||||||
|
Dim cmd As DBCommand = commands.Get(0)
|
||||||
|
Return $"batch (size=1) - query: ${cmd.Name}"$
|
||||||
|
Else
|
||||||
|
' Si el lote es de tamaño > 1, mantenemos el resumen por tamaño.
|
||||||
|
Return $"batch (size=${commands.Size})"$
|
||||||
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
' --- Subrutinas para manejar la ejecución de queries y batches (Protocolo V1 - Compilación Condicional) ---
|
' --- Subrutinas para manejar la ejecución de queries y batches (Protocolo V1 - Compilación Condicional) ---
|
||||||
@@ -422,6 +432,7 @@ Private Sub ExecuteBatch(DB As String, con As SQL, in As InputStream, resp As Se
|
|||||||
' Lee cuántos comandos vienen en el lote.
|
' Lee cuántos comandos vienen en el lote.
|
||||||
Dim numberOfStatements As Int = ReadInt(in)
|
Dim numberOfStatements As Int = ReadInt(in)
|
||||||
Dim res(numberOfStatements) As Int ' Array para resultados (aunque no se usa).
|
Dim res(numberOfStatements) As Int ' Array para resultados (aunque no se usa).
|
||||||
|
Dim singleQueryName As String = ""
|
||||||
|
|
||||||
Try
|
Try
|
||||||
con.BeginTransaction
|
con.BeginTransaction
|
||||||
@@ -430,6 +441,9 @@ Private Sub ExecuteBatch(DB As String, con As SQL, in As InputStream, resp As Se
|
|||||||
' Lee el nombre del comando y la lista de parámetros usando el deserializador V1.
|
' Lee el nombre del comando y la lista de parámetros usando el deserializador V1.
|
||||||
Dim queryName As String = ReadObject(in)
|
Dim queryName As String = ReadObject(in)
|
||||||
Dim params As List = ReadList(in)
|
Dim params As List = ReadList(in)
|
||||||
|
If numberOfStatements = 1 Then
|
||||||
|
singleQueryName = queryName 'Capturamos el nombre del query.
|
||||||
|
End If
|
||||||
Dim sqlCommand As String = Connector.GetCommand(DB, queryName)
|
Dim sqlCommand As String = Connector.GetCommand(DB, queryName)
|
||||||
|
|
||||||
' <<< INICIO NUEVA VALIDACIÓN: VERIFICAR SI EL COMANDO EXISTE (V1) >>>
|
' <<< INICIO NUEVA VALIDACIÓN: VERIFICAR SI EL COMANDO EXISTE (V1) >>>
|
||||||
@@ -475,7 +489,12 @@ Private Sub ExecuteBatch(DB As String, con As SQL, in As InputStream, resp As Se
|
|||||||
SendPlainTextError(resp, 500, LastException.Message)
|
SendPlainTextError(resp, 500, LastException.Message)
|
||||||
End Try
|
End Try
|
||||||
|
|
||||||
Return $"batch (size=${numberOfStatements})"$
|
' Return $"batch (size=${numberOfStatements})"$
|
||||||
|
If numberOfStatements = 1 And singleQueryName <> "" Then
|
||||||
|
Return $"batch (size=1) - query: ${singleQueryName}"$
|
||||||
|
Else
|
||||||
|
Return $"batch (size=${numberOfStatements})"$
|
||||||
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
' Ejecuta una consulta única usando el protocolo V1.
|
' Ejecuta una consulta única usando el protocolo V1.
|
||||||
|
|||||||
@@ -11,13 +11,18 @@ DriverClass=oracle.jdbc.driver.OracleDriver
|
|||||||
#GOHAN ---> server
|
#GOHAN ---> server
|
||||||
#JdbcUrl=jdbc:oracle:thin:@//10.0.0.205:1521/DBKMT
|
#JdbcUrl=jdbc:oracle:thin:@//10.0.0.205:1521/DBKMT
|
||||||
#JdbcUrl=jdbc:oracle:thin:@//10.0.0.236:1521/DBKMT
|
#JdbcUrl=jdbc:oracle:thin:@//10.0.0.236:1521/DBKMT
|
||||||
JdbcUrl=jdbc:oracle:thin:@//192.168.101.13:1521/DBKMT?v$session.program=jRDC_MultiSALMA
|
JdbcUrl=jdbc:oracle:thin:@//192.168.101.13:1521/DBKMT?v$session.program=jRDC_Pruebas_Salma2
|
||||||
|
|
||||||
# Configuración del pool de conexiones
|
# Define el número de conexiones que se intentarán crear al iniciar el pool.
|
||||||
InitialPoolSize=3
|
InitialPoolSize=1
|
||||||
MinPoolSize=2
|
# Fija el número mínimo de conexiones que el pool mantendrá abiertas.
|
||||||
MaxPoolSize=15
|
MinPoolSize=1
|
||||||
AcquireIncrement=2
|
# Define el número máximo de conexiones simultáneas.
|
||||||
|
MaxPoolSize=2
|
||||||
|
# Cuántas conexiones nuevas se añaden en lote si el pool se queda sin disponibles.
|
||||||
|
AcquireIncrement=1
|
||||||
|
# Tiempo máximo de inactividad de una conexión antes de cerrarse (segundos).
|
||||||
|
MaxConnectionAge=60
|
||||||
|
|
||||||
# Configuración de tolerancia de parámetros:
|
# Configuración de tolerancia de parámetros:
|
||||||
# 1 = Habilita la tolerancia a parámetros de más (se recortarán los excesivos).
|
# 1 = Habilita la tolerancia a parámetros de más (se recortarán los excesivos).
|
||||||
@@ -25,6 +30,12 @@ AcquireIncrement=2
|
|||||||
# Por defecto, si no se especifica o el valor es diferente de 1, la tolerancia estará DESHABILITADA (modo estricto).
|
# Por defecto, si no se especifica o el valor es diferente de 1, la tolerancia estará DESHABILITADA (modo estricto).
|
||||||
parameterTolerance=1
|
parameterTolerance=1
|
||||||
|
|
||||||
|
# Configuración de los logs de SQLite:
|
||||||
|
# 1 = Habilita el registro de logs de queries y errores en la base de datos SQLite (users.db).
|
||||||
|
# 0 = Deshabilita el registro de logs de queries y errores en SQLite para optimizar el rendimiento.
|
||||||
|
# Por defecto, si no se especifica o el valor es diferente de 1, los logs estarán DESHABILITADOS.
|
||||||
|
enableSQLiteLogs=1
|
||||||
|
|
||||||
# SVR-KEYMON-PRODUCCION--> Usuario
|
# SVR-KEYMON-PRODUCCION--> Usuario
|
||||||
User=SALMA
|
User=SALMA
|
||||||
Password=SALMAD2016M
|
Password=SALMAD2016M
|
||||||
|
|||||||
@@ -11,13 +11,30 @@ DriverClass=oracle.jdbc.driver.OracleDriver
|
|||||||
#GOHAN ---> server
|
#GOHAN ---> server
|
||||||
#JdbcUrl=jdbc:oracle:thin:@//10.0.0.205:1521/DBKMT
|
#JdbcUrl=jdbc:oracle:thin:@//10.0.0.205:1521/DBKMT
|
||||||
#JdbcUrl=jdbc:oracle:thin:@//10.0.0.236:1521/DBKMT
|
#JdbcUrl=jdbc:oracle:thin:@//10.0.0.236:1521/DBKMT
|
||||||
JdbcUrl=jdbc:oracle:thin:@//192.168.101.13:1521/DBKMT?v$session.program=jRDC_MultiSALMA
|
JdbcUrl=jdbc:oracle:thin:@//192.168.101.13:1521/DBKMT?v$session.program=jRDC_Pruebas_Salma3
|
||||||
|
|
||||||
# Configuración del pool de conexiones
|
# Define el número de conexiones que se intentarán crear al iniciar el pool.
|
||||||
InitialPoolSize=3
|
InitialPoolSize=1
|
||||||
MinPoolSize=2
|
# Fija el número mínimo de conexiones que el pool mantendrá abiertas.
|
||||||
MaxPoolSize=15
|
MinPoolSize=1
|
||||||
AcquireIncrement=2
|
# Define el número máximo de conexiones simultáneas.
|
||||||
|
MaxPoolSize=2
|
||||||
|
# Cuántas conexiones nuevas se añaden en lote si el pool se queda sin disponibles.
|
||||||
|
AcquireIncrement=1
|
||||||
|
# Tiempo máximo de inactividad de una conexión antes de cerrarse (segundos).
|
||||||
|
MaxConnectionAge=60
|
||||||
|
|
||||||
|
# Configuración de tolerancia de parámetros:
|
||||||
|
# 1 = Habilita la tolerancia a parámetros de más (se recortarán los excesivos).
|
||||||
|
# 0 = Deshabilita la tolerancia (el servidor será estricto y lanzará un error si hay parámetros de más).
|
||||||
|
# Por defecto, si no se especifica o el valor es diferente de 1, la tolerancia estará DESHABILITADA (modo estricto).
|
||||||
|
parameterTolerance=1
|
||||||
|
|
||||||
|
# Configuración de los logs de SQLite:
|
||||||
|
# 1 = Habilita el registro de logs de queries y errores en la base de datos SQLite (users.db).
|
||||||
|
# 0 = Deshabilita el registro de logs de queries y errores en SQLite para optimizar el rendimiento.
|
||||||
|
# Por defecto, si no se especifica o el valor es diferente de 1, los logs estarán DESHABILITADOS.
|
||||||
|
enableSQLiteLogs=0
|
||||||
|
|
||||||
# SVR-KEYMON-PRODUCCION--> Usuario
|
# SVR-KEYMON-PRODUCCION--> Usuario
|
||||||
User=SALMA
|
User=SALMA
|
||||||
|
|||||||
@@ -11,13 +11,30 @@ DriverClass=oracle.jdbc.driver.OracleDriver
|
|||||||
#GOHAN ---> server
|
#GOHAN ---> server
|
||||||
#JdbcUrl=jdbc:oracle:thin:@//10.0.0.205:1521/DBKMT
|
#JdbcUrl=jdbc:oracle:thin:@//10.0.0.205:1521/DBKMT
|
||||||
#JdbcUrl=jdbc:oracle:thin:@//10.0.0.236:1521/DBKMT
|
#JdbcUrl=jdbc:oracle:thin:@//10.0.0.236:1521/DBKMT
|
||||||
JdbcUrl=jdbc:oracle:thin:@//192.168.101.13:1521/DBKMT?v$session.program=jRDC_MultiSALMA
|
JdbcUrl=jdbc:oracle:thin:@//192.168.101.13:1521/DBKMT?v$session.program=jRDC_Pruebas_Salma4
|
||||||
|
|
||||||
# Configuración del pool de conexiones
|
# Define el número de conexiones que se intentarán crear al iniciar el pool.
|
||||||
InitialPoolSize=3
|
InitialPoolSize=1
|
||||||
MinPoolSize=2
|
# Fija el número mínimo de conexiones que el pool mantendrá abiertas.
|
||||||
MaxPoolSize=15
|
MinPoolSize=1
|
||||||
AcquireIncrement=2
|
# Define el número máximo de conexiones simultáneas.
|
||||||
|
MaxPoolSize=2
|
||||||
|
# Cuántas conexiones nuevas se añaden en lote si el pool se queda sin disponibles.
|
||||||
|
AcquireIncrement=1
|
||||||
|
# Tiempo máximo de inactividad de una conexión antes de cerrarse (segundos).
|
||||||
|
MaxConnectionAge=60
|
||||||
|
|
||||||
|
# Configuración de tolerancia de parámetros:
|
||||||
|
# 1 = Habilita la tolerancia a parámetros de más (se recortarán los excesivos).
|
||||||
|
# 0 = Deshabilita la tolerancia (el servidor será estricto y lanzará un error si hay parámetros de más).
|
||||||
|
# Por defecto, si no se especifica o el valor es diferente de 1, la tolerancia estará DESHABILITADA (modo estricto).
|
||||||
|
parameterTolerance=1
|
||||||
|
|
||||||
|
# Configuración de los logs de SQLite:
|
||||||
|
# 1 = Habilita el registro de logs de queries y errores en la base de datos SQLite (users.db).
|
||||||
|
# 0 = Deshabilita el registro de logs de queries y errores en SQLite para optimizar el rendimiento.
|
||||||
|
# Por defecto, si no se especifica o el valor es diferente de 1, los logs estarán DESHABILITADOS.
|
||||||
|
enableSQLiteLogs=0
|
||||||
|
|
||||||
# SVR-KEYMON-PRODUCCION--> Usuario
|
# SVR-KEYMON-PRODUCCION--> Usuario
|
||||||
User=SALMA
|
User=SALMA
|
||||||
|
|||||||
@@ -11,13 +11,18 @@ DriverClass=oracle.jdbc.driver.OracleDriver
|
|||||||
#GOHAN ---> server
|
#GOHAN ---> server
|
||||||
#JdbcUrl=jdbc:oracle:thin:@//10.0.0.205:1521/DBKMT
|
#JdbcUrl=jdbc:oracle:thin:@//10.0.0.205:1521/DBKMT
|
||||||
#JdbcUrl=jdbc:oracle:thin:@//10.0.0.236:1521/DBKMT
|
#JdbcUrl=jdbc:oracle:thin:@//10.0.0.236:1521/DBKMT
|
||||||
JdbcUrl=jdbc:oracle:thin:@//192.168.101.10:1521/DBKMT?v$session.program=jRDC_Multi
|
JdbcUrl=jdbc:oracle:thin:@//192.168.101.10:1521/DBKMT?v$session.program=jRDC_Pruebas_Guna1
|
||||||
|
|
||||||
# Configuración del pool de conexiones
|
# Define el número de conexiones que se intentarán crear al iniciar el pool.
|
||||||
InitialPoolSize=3
|
InitialPoolSize=1
|
||||||
MinPoolSize=2
|
# Fija el número mínimo de conexiones que el pool mantendrá abiertas.
|
||||||
MaxPoolSize=15
|
MinPoolSize=1
|
||||||
AcquireIncrement=2
|
# Define el número máximo de conexiones simultáneas.
|
||||||
|
MaxPoolSize=2
|
||||||
|
# Cuántas conexiones nuevas se añaden en lote si el pool se queda sin disponibles.
|
||||||
|
AcquireIncrement=1
|
||||||
|
# Tiempo máximo de inactividad de una conexión antes de cerrarse (segundos).
|
||||||
|
MaxConnectionAge=60
|
||||||
|
|
||||||
# Configuración de tolerancia de parámetros:
|
# Configuración de tolerancia de parámetros:
|
||||||
# 1 = Habilita la tolerancia a parámetros de más (se recortarán los excesivos).
|
# 1 = Habilita la tolerancia a parámetros de más (se recortarán los excesivos).
|
||||||
@@ -25,6 +30,12 @@ AcquireIncrement=2
|
|||||||
# Por defecto, si no se especifica o el valor es diferente de 1, la tolerancia estará DESHABILITADA (modo estricto).
|
# Por defecto, si no se especifica o el valor es diferente de 1, la tolerancia estará DESHABILITADA (modo estricto).
|
||||||
parameterTolerance=1
|
parameterTolerance=1
|
||||||
|
|
||||||
|
# Configuración de los logs de SQLite:
|
||||||
|
# 1 = Habilita el registro de logs de queries y errores en la base de datos SQLite (users.db).
|
||||||
|
# 0 = Deshabilita el registro de logs de queries y errores en SQLite para optimizar el rendimiento.
|
||||||
|
# Por defecto, si no se especifica o el valor es diferente de 1, los logs estarán DESHABILITADOS.
|
||||||
|
enableSQLiteLogs=0
|
||||||
|
|
||||||
# SVR-KEYMON-PRODUCCION--> Usuario
|
# SVR-KEYMON-PRODUCCION--> Usuario
|
||||||
User=GUNA
|
User=GUNA
|
||||||
Password=GUNAD2015M
|
Password=GUNAD2015M
|
||||||
|
|||||||
259
jRDC_Multi.b4j
259
jRDC_Multi.b4j
@@ -55,7 +55,7 @@ Version=10.3
|
|||||||
|
|
||||||
#CommandLineArgs:
|
#CommandLineArgs:
|
||||||
#MergeLibraries: True
|
#MergeLibraries: True
|
||||||
' VERSION 5.09.16
|
' VERSION 5.09.16.2
|
||||||
'###########################################################################################################
|
'###########################################################################################################
|
||||||
'###################### PULL #############################################################
|
'###################### PULL #############################################################
|
||||||
'Ctrl + click ide://run?file=%WINDIR%\System32\cmd.exe&Args=/c&Args=git&Args=pull
|
'Ctrl + click ide://run?file=%WINDIR%\System32\cmd.exe&Args=/c&Args=git&Args=pull
|
||||||
@@ -112,6 +112,7 @@ Sub Process_Globals
|
|||||||
' NUEVAS VARIABLES para control granular de logs
|
' NUEVAS VARIABLES para control granular de logs
|
||||||
' Mapa para almacenar el estado de logging (True/False) por cada DBKey (DB1, DB2, etc.).
|
' Mapa para almacenar el estado de logging (True/False) por cada DBKey (DB1, DB2, etc.).
|
||||||
Public SQLiteLoggingStatusByDB As Map
|
Public SQLiteLoggingStatusByDB As Map
|
||||||
|
|
||||||
' Bandera global que indica si AL MENOS una base de datos tiene los logs habilitados.
|
' Bandera global que indica si AL MENOS una base de datos tiene los logs habilitados.
|
||||||
Public IsAnySQLiteLoggingEnabled As Boolean
|
Public IsAnySQLiteLoggingEnabled As Boolean
|
||||||
|
|
||||||
@@ -121,12 +122,25 @@ Sub Process_Globals
|
|||||||
ErrorMessage As String, _
|
ErrorMessage As String, _
|
||||||
ParamsToExecute As List _ ' La lista de parámetros final a usar en la ejecución SQL
|
ParamsToExecute As List _ ' La lista de parámetros final a usar en la ejecución SQL
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Public QueryLogCache As List ' Cache para los logs de rendimiento (query_logs)
|
||||||
|
Public ErrorLogCache As List ' Cache para los logs de errores y advertencias
|
||||||
|
Public Const LOG_CACHE_THRESHOLD As Int = 10 ' Umbral de registros para forzar la escritura
|
||||||
|
|
||||||
|
Dim logger As Boolean
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
Sub AppStart (Args() As String)
|
Sub AppStart (Args() As String)
|
||||||
|
#if DEBUG
|
||||||
|
logger = True
|
||||||
|
#else
|
||||||
|
logger = False
|
||||||
|
#End If
|
||||||
' --- Subrutina principal que se ejecuta al iniciar la aplicación ---
|
' --- Subrutina principal que se ejecuta al iniciar la aplicación ---
|
||||||
|
|
||||||
bc.Initialize("BC")
|
bc.Initialize("BC")
|
||||||
|
QueryLogCache.Initialize
|
||||||
|
ErrorLogCache.Initialize
|
||||||
|
|
||||||
' 1. Inicializa la base de datos local de usuarios (SQLite) y la tabla de logs.
|
' 1. Inicializa la base de datos local de usuarios (SQLite) y la tabla de logs.
|
||||||
InitializeSQLiteDatabase
|
InitializeSQLiteDatabase
|
||||||
@@ -276,10 +290,10 @@ Sub AppStart (Args() As String)
|
|||||||
|
|
||||||
If IsAnySQLiteLoggingEnabled Then
|
If IsAnySQLiteLoggingEnabled Then
|
||||||
timerLogs.Enabled = True
|
timerLogs.Enabled = True
|
||||||
Log("Main.AppStart: Timer de limpieza de logs ACTIVADO (al menos una DB requiere logs).")
|
If logger Then Log("Main.AppStart: Timer de limpieza de logs ACTIVADO (al menos una DB requiere logs).")
|
||||||
Else
|
Else
|
||||||
timerLogs.Enabled = False
|
timerLogs.Enabled = False
|
||||||
Log("Main.AppStart: Timer de limpieza de logs DESHABILITADO (ninguna DB requiere logs).")
|
If logger Then Log("Main.AppStart: Timer de limpieza de logs DESHABILITADO (ninguna DB requiere logs).")
|
||||||
End If
|
End If
|
||||||
|
|
||||||
' <<<< Fin del bloque del Timer >>>>
|
' <<<< Fin del bloque del Timer >>>>
|
||||||
@@ -321,7 +335,7 @@ Sub InitializeSQLiteDatabase
|
|||||||
SQL1.ExecNonQuery(createUserTable)
|
SQL1.ExecNonQuery(createUserTable)
|
||||||
|
|
||||||
' Crear tabla 'query_logs'
|
' Crear tabla 'query_logs'
|
||||||
Log("Creando tabla 'query_logs' con columnas de rendimiento.")
|
If logger Then 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)"
|
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)
|
SQL1.ExecNonQuery(createQueryLogsTable)
|
||||||
|
|
||||||
@@ -342,11 +356,11 @@ Sub InitializeSQLiteDatabase
|
|||||||
Log("Base de datos de usuarios cargada.")
|
Log("Base de datos de usuarios cargada.")
|
||||||
|
|
||||||
' >>> INICIO: Lógica de migración (ALTER TABLE) si la DB ya existía <<<
|
' >>> 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 logger Then 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
|
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.")
|
If logger 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)"
|
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)"
|
||||||
|
|
||||||
@@ -371,7 +385,7 @@ Sub InitializeSQLiteDatabase
|
|||||||
rs.Close
|
rs.Close
|
||||||
|
|
||||||
If columnExists = False Then
|
If columnExists = False Then
|
||||||
Log("Añadiendo columna 'busy_connections' a query_logs.")
|
If logger Then Log("Añadiendo columna 'busy_connections' a query_logs.")
|
||||||
SQL1.ExecNonQuery("ALTER TABLE query_logs ADD COLUMN busy_connections INTEGER DEFAULT 0")
|
SQL1.ExecNonQuery("ALTER TABLE query_logs ADD COLUMN busy_connections INTEGER DEFAULT 0")
|
||||||
End If
|
End If
|
||||||
|
|
||||||
@@ -388,20 +402,34 @@ Sub InitializeSQLiteDatabase
|
|||||||
rs.Close
|
rs.Close
|
||||||
|
|
||||||
If columnExists = False Then
|
If columnExists = False Then
|
||||||
Log("Añadiendo columna 'handler_active_requests' a query_logs.")
|
If logger 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")
|
SQL1.ExecNonQuery("ALTER TABLE query_logs ADD COLUMN handler_active_requests INTEGER DEFAULT 0")
|
||||||
End If
|
End If
|
||||||
|
columnExists = False
|
||||||
|
rs = SQL1.ExecQuery("PRAGMA table_info(query_logs)")
|
||||||
|
Do While rs.NextRow
|
||||||
|
If rs.GetString("name").EqualsIgnoreCase("timestamp_text_local") Then
|
||||||
|
columnExists = True
|
||||||
|
Exit ' La columna ya existe, salimos del bucle.
|
||||||
|
End If
|
||||||
|
Loop
|
||||||
|
rs.Close
|
||||||
|
|
||||||
|
If columnExists = False Then
|
||||||
|
If logger Then Log("Añadiendo columna 'timestamp_text_local' a query_logs.")
|
||||||
|
' Usamos 'TEXT' para almacenar la cadena de fecha/hora formateada.
|
||||||
|
SQL1.ExecNonQuery("ALTER TABLE query_logs ADD COLUMN timestamp_text_local TEXT")
|
||||||
|
End If
|
||||||
|
|
||||||
' >>> INICIO: Lógica de migración para 'errores' si la DB ya existía <<<
|
' >>> INICIO: Lógica de migración para 'errores' si la DB ya existía <<<
|
||||||
Log("Verificando y migrando tabla 'errores' si es necesario.")
|
If logger Then 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
|
If SQL1.ExecQuerySingleResult("SELECT name FROM sqlite_master WHERE type='table' AND name='errores'") = Null Then
|
||||||
Log("Tabla 'errores' no encontrada, creándola.")
|
If logger 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)"
|
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)
|
SQL1.ExecNonQuery(createErrorsTable)
|
||||||
Else
|
Else
|
||||||
Log("Tabla 'errores' ya existe.")
|
If logger Then Log("Tabla 'errores' ya existe.")
|
||||||
End If
|
End If
|
||||||
' >>> FIN: Lógica de migración para 'errores' <<<
|
' >>> FIN: Lógica de migración para 'errores' <<<
|
||||||
|
|
||||||
@@ -411,45 +439,155 @@ Sub InitializeSQLiteDatabase
|
|||||||
End If
|
End If
|
||||||
End Sub
|
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)
|
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)
|
Dim isEnabled As Boolean = SQLiteLoggingStatusByDB.GetDefault(DbKey, False)
|
||||||
|
|
||||||
If isEnabled Then
|
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 (?, ?, ?, ?, ?, ?, ?)", _
|
' Formato de tiempo necesario para la columna timestamp_text_local
|
||||||
Array As Object(QueryName, DurationMs, DateTime.Now, DbKey, ClientIp, PoolBusyConnections, HandlerActiveRequests))
|
DateTime.DateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
|
||||||
Catch
|
Dim formattedTimestamp As String = DateTime.Date(DateTime.Now)
|
||||||
Log("Error al guardar log de query en SQLite (Main.LogQueryPerformance): " & LastException.Message)
|
|
||||||
End Try
|
' 1. Crear el mapa de datos (log entry)
|
||||||
|
Dim logEntry As Map = CreateMap("query_name": QueryName, "duration_ms": DurationMs, "timestamp": DateTime.Now, _
|
||||||
|
"db_key": DbKey, "client_ip": ClientIp, "busy_connections": PoolBusyConnections, _
|
||||||
|
"handler_active_requests": HandlerActiveRequests, "timestamp_text_local": formattedTimestamp)
|
||||||
|
|
||||||
|
' 2. Zona Crítica: Añadir a la caché y verificar el umbral
|
||||||
|
Dim shouldWriteBatch As Boolean = False
|
||||||
|
|
||||||
|
' Usamos el lock global para garantizar que la adición y la verificación del tamaño sean atómicas.
|
||||||
|
MainConnectorsLock.RunMethod("lock", Null)
|
||||||
|
|
||||||
|
QueryLogCache.Add(logEntry)
|
||||||
|
|
||||||
|
If QueryLogCache.Size >= LOG_CACHE_THRESHOLD Then
|
||||||
|
shouldWriteBatch = True
|
||||||
|
End If
|
||||||
|
|
||||||
|
MainConnectorsLock.RunMethod("unlock", Null)
|
||||||
|
|
||||||
|
' 3. Si se alcanzó el umbral, disparamos la escritura.
|
||||||
|
' NO DEBE HACERSE CON EL LOCK PUESTO.
|
||||||
|
If shouldWriteBatch Then
|
||||||
|
CallSub(Me, "WriteQueryLogsBatch")
|
||||||
|
End If
|
||||||
|
|
||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
' --- Subrutina para registrar errores y advertencias en la tabla 'errores'. ---
|
' --- 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)
|
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)
|
Dim isEnabled As Boolean = SQLiteLoggingStatusByDB.GetDefault(DBKey, False)
|
||||||
|
|
||||||
If isEnabled Then
|
If isEnabled Then
|
||||||
Try
|
|
||||||
SQL1.ExecNonQuery2("INSERT INTO errores (timestamp, type, source, message, db_key, command_name, client_ip) VALUES (?, ?, ?, ?, ?, ?, ?)", _
|
' Log($"[DEBUG CACHE] Se recibió log de error/advertencia para: ${CommandName}"$) '<--- Nuevo Log 1
|
||||||
Array As Object(DateTime.Now, Type0, Source, Message, DBKey, CommandName, ClientIp))
|
|
||||||
Catch
|
Dim logEntry As Map = CreateMap("timestamp": DateTime.Now, "type": Type0, "source": Source, "message": Message, _
|
||||||
Log("ERROR CRÍTICO: Fallo al guardar el log de error/advertencia en SQLite (Main.LogServerError): " & LastException.Message)
|
"db_key": DBKey, "command_name": CommandName, "client_ip": ClientIp)
|
||||||
End Try
|
|
||||||
|
Dim shouldWriteBatch As Boolean = False
|
||||||
|
|
||||||
|
' 1. Zona Crítica: Añadir a la caché y verificar el umbral
|
||||||
|
|
||||||
|
' Usamos el lock para Thread Safety
|
||||||
|
MainConnectorsLock.RunMethod("lock", Null)
|
||||||
|
' Log($"[DEBUG CACHE] Lock adquirido. Tamaño actual de ErrorLogCache: ${ErrorLogCache.Size}"$) '<--- Nuevo Log 2
|
||||||
|
|
||||||
|
ErrorLogCache.Add(logEntry)
|
||||||
|
|
||||||
|
' Log($"[DEBUG CACHE] Log añadido. Nuevo tamaño: ${ErrorLogCache.Size}. Umbral: ${LOG_CACHE_THRESHOLD}"$) '<--- Nuevo Log 3
|
||||||
|
|
||||||
|
If ErrorLogCache.Size >= LOG_CACHE_THRESHOLD Then
|
||||||
|
shouldWriteBatch = True
|
||||||
|
' Log(">>> [DEBUG CACHE] UMBRAL ALCANZADO. DISPARANDO ESCRITURA BATCH. <<<") '<--- Nuevo Log 4
|
||||||
|
End If
|
||||||
|
|
||||||
|
MainConnectorsLock.RunMethod("unlock", Null)
|
||||||
|
' Log($"[DEBUG CACHE] Lock liberado."$) '<--- Nuevo Log 5
|
||||||
|
|
||||||
|
' 2. Si se alcanzó el umbral (o si el timer lo llama), disparamos la escritura.
|
||||||
|
If shouldWriteBatch Then
|
||||||
|
CallSub(Me, "WriteErrorLogsBatch")
|
||||||
|
End If
|
||||||
|
|
||||||
|
Else
|
||||||
|
' Log($"[DEBUG CACHE] Logging deshabilitado para DBKey: ${DBKey}. Log de error omitido."$)
|
||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
|
Public Sub WriteQueryLogsBatch
|
||||||
|
Dim logsToWrite As List
|
||||||
|
logsToWrite.Initialize ' 1. Inicializar la lista local (CRÍTICO)
|
||||||
|
|
||||||
|
' === PASO 1: Intercambio Atómico de Caché (Protegido por ReentrantLock) ===
|
||||||
|
|
||||||
|
MainConnectorsLock.RunMethod("lock", Null)
|
||||||
|
|
||||||
|
If QueryLogCache.Size = 0 Then
|
||||||
|
MainConnectorsLock.RunMethod("unlock", Null)
|
||||||
|
' Log("[DEBUG BATCH-Q] Saliendo: Caché de rendimiento vacía.")
|
||||||
|
Return
|
||||||
|
End If
|
||||||
|
|
||||||
|
' *** CORRECCIÓN CRÍTICA: Copia de contenido (AddAll) en lugar de referencia. ***
|
||||||
|
logsToWrite.AddAll(QueryLogCache)
|
||||||
|
|
||||||
|
Dim batchSize As Int = logsToWrite.Size
|
||||||
|
|
||||||
|
' Vaciamos la caché global. logsToWrite ahora contiene la copia de los elementos.
|
||||||
|
QueryLogCache.Initialize
|
||||||
|
|
||||||
|
MainConnectorsLock.RunMethod("unlock", Null)
|
||||||
|
|
||||||
|
If logger Then Log($"[LOG BATCH] Iniciando escritura transaccional de ${batchSize} logs de rendimiento. Logs copiados: ${logsToWrite.Size}"$)
|
||||||
|
|
||||||
|
' === PASO 2: Escritura Transaccional a SQLite ===
|
||||||
|
|
||||||
|
Try
|
||||||
|
' 1. Iniciar la transacción: Todo lo que siga es una única operación de disco.
|
||||||
|
SQL1.BeginTransaction
|
||||||
|
|
||||||
|
For Each logEntry As Map In logsToWrite
|
||||||
|
SQL1.ExecNonQuery2("INSERT INTO query_logs (query_name, duration_ms, timestamp, db_key, client_ip, busy_connections, handler_active_requests, timestamp_text_local) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", _
|
||||||
|
Array As Object(logEntry.Get("query_name"), logEntry.Get("duration_ms"), logEntry.Get("timestamp"), logEntry.Get("db_key"), _
|
||||||
|
logEntry.Get("client_ip"), logEntry.Get("busy_connections"), logEntry.Get("handler_active_requests"), _
|
||||||
|
logEntry.Get("timestamp_text_local")))
|
||||||
|
Next
|
||||||
|
|
||||||
|
' 2. Finalizar la transacción: Escritura eficiente a disco.
|
||||||
|
SQL1.TransactionSuccessful
|
||||||
|
|
||||||
|
if logger then Log($"[LOG BATCH] Lote de ${batchSize} logs de rendimiento escrito exitosamente."$)
|
||||||
|
|
||||||
|
Catch
|
||||||
|
' Si falla, deshacemos todos los logs del lote y registramos el fallo.
|
||||||
|
SQL1.Rollback
|
||||||
|
Dim ErrorMsg As String = "ERROR CRÍTICO: Fallo al escribir lote de logs de rendimiento en SQLite: " & LastException.Message
|
||||||
|
Log(ErrorMsg)
|
||||||
|
|
||||||
|
' Usamos LogServerError para que el fallo quede registrado en la tabla 'errores' si el logging está habilitado.
|
||||||
|
LogServerError("ERROR", "Main.WriteQueryLogsBatch", ErrorMsg, Null, "log_batch_write_performance", Null)
|
||||||
|
End Try
|
||||||
|
|
||||||
|
End Sub
|
||||||
|
|
||||||
' --- Subrutina de evento para el Timer 'timerLogs'. ---
|
' --- Subrutina de evento para el Timer 'timerLogs'. ---
|
||||||
' El estado 'Enabled' del Timer ya está controlado por IsAnySQLiteLoggingEnabled en AppStart y Manager.
|
' El estado 'Enabled' del Timer ya está controlado por IsAnySQLiteLoggingEnabled en AppStart y Manager.
|
||||||
Sub TimerLogs_Tick
|
Sub TimerLogs_Tick
|
||||||
Try
|
Try
|
||||||
|
' 1. Vaciado de logs de rendimiento (asumiendo que WriteQueryLogsBatch también fue implementado)
|
||||||
|
WriteQueryLogsBatch
|
||||||
|
|
||||||
|
' 2. Vaciado de logs de errores
|
||||||
|
WriteErrorLogsBatch
|
||||||
|
|
||||||
|
' 3. Limpieza y VACUUM (esto ya verifica IsAnySQLiteLoggingEnabled [8])
|
||||||
borraArribaDe15000Logs
|
borraArribaDe15000Logs
|
||||||
|
|
||||||
Catch
|
Catch
|
||||||
Dim ErrorMsg As String = "ERROR en TimerLogs_Tick al intentar borrar logs: " & LastException.Message
|
Dim ErrorMsg As String = "ERROR en TimerLogs_Tick al intentar borrar logs: " & LastException.Message
|
||||||
Log(ErrorMsg)
|
Log(ErrorMsg)
|
||||||
@@ -457,16 +595,77 @@ Sub TimerLogs_Tick
|
|||||||
End Try
|
End Try
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
|
Public Sub WriteErrorLogsBatch
|
||||||
|
Dim logsToWrite As List
|
||||||
|
logsToWrite.Initialize ' *** Aseguramos que logsToWrite sea una LISTA NUEVA y no dependa de la referencia.
|
||||||
|
|
||||||
|
' === PASO 1: Intercambio Atómico de Caché (Protegido por ReentrantLock) ===
|
||||||
|
|
||||||
|
MainConnectorsLock.RunMethod("lock", Null) ' Adquirimos el bloqueo.
|
||||||
|
|
||||||
|
' Log($"[DEBUG BATCH] Lock adquirido en WriteErrorLogsBatch. Caché Size: ${ErrorLogCache.Size}"$)
|
||||||
|
|
||||||
|
If ErrorLogCache.Size = 0 Then
|
||||||
|
MainConnectorsLock.RunMethod("unlock", Null)
|
||||||
|
' Log("[DEBUG BATCH] Saliendo: Caché vacía.")
|
||||||
|
Return
|
||||||
|
End If
|
||||||
|
|
||||||
|
' *** CORRECCIÓN CRÍTICA: Copiamos el CONTENIDO de forma atómica. ***
|
||||||
|
logsToWrite.AddAll(ErrorLogCache) ' <--- ESTO PASA LOS 10 REGISTROS A LA NUEVA LISTA
|
||||||
|
|
||||||
|
' Vaciamos la caché global. logsToWrite AHORA ES INDEPENDIENTE.
|
||||||
|
ErrorLogCache.Initialize
|
||||||
|
|
||||||
|
MainConnectorsLock.RunMethod("unlock", Null) ' Liberamos el bloqueo.
|
||||||
|
|
||||||
|
' Usamos el tamaño de la lista *copiada*.
|
||||||
|
Dim batchSize As Int = logsToWrite.Size
|
||||||
|
|
||||||
|
If logger Then Log($"[LOG BATCH] Iniciando escritura transaccional de ${batchSize} logs de ERRORES a SQLite. Logs copiados: ${logsToWrite.Size}"$)
|
||||||
|
|
||||||
|
' === PASO 2: Escritura Transaccional a SQLite (Usa logsToWrite) ===
|
||||||
|
|
||||||
|
If batchSize = 0 Then
|
||||||
|
Log("ADVERTENCIA: Fallo en la copia de la lista. logsToWrite está vacía. Abortando escritura.")
|
||||||
|
Return
|
||||||
|
End If
|
||||||
|
|
||||||
|
Try
|
||||||
|
' 1. Iniciar la transacción.
|
||||||
|
SQL1.BeginTransaction
|
||||||
|
|
||||||
|
For Each logEntry As Map In logsToWrite
|
||||||
|
' ... (Tu lógica de SQL1.ExecNonQuery2 aquí) ...
|
||||||
|
SQL1.ExecNonQuery2("INSERT INTO errores (timestamp, type, source, message, db_key, command_name, client_ip) VALUES (?, ?, ?, ?, ?, ?, ?)", _
|
||||||
|
Array As Object(logEntry.Get("timestamp"), logEntry.Get("type"), logEntry.Get("source"), logEntry.Get("message"), _
|
||||||
|
logEntry.Get("db_key"), logEntry.Get("command_name"), logEntry.Get("client_ip")))
|
||||||
|
Next
|
||||||
|
|
||||||
|
' 2. Confirmar la transacción.
|
||||||
|
SQL1.TransactionSuccessful
|
||||||
|
|
||||||
|
If logger Then Log($"[LOG BATCH] Lote de ${logsToWrite.Size} logs de ERRORES escrito exitosamente."$)
|
||||||
|
|
||||||
|
Catch
|
||||||
|
' 3. Rollback si falla.
|
||||||
|
SQL1.Rollback
|
||||||
|
Dim ErrorMsg As String = "ERROR CRÍTICO: Fallo al escribir lote de logs de ERRORES en SQLite: " & LastException.Message
|
||||||
|
Log(ErrorMsg)
|
||||||
|
End Try
|
||||||
|
|
||||||
|
End Sub
|
||||||
|
|
||||||
' --- Borra los registros más antiguos de la tabla 'query_logs' y hace VACUUM. ---
|
' --- Borra los registros más antiguos de la tabla 'query_logs' y hace VACUUM. ---
|
||||||
' ¡MODIFICADA PARA USAR FILTRADO GLOBAL!
|
' ¡MODIFICADA PARA USAR FILTRADO GLOBAL!
|
||||||
Sub borraArribaDe15000Logs 'ignore
|
Sub borraArribaDe15000Logs 'ignore
|
||||||
|
|
||||||
If IsAnySQLiteLoggingEnabled Then ' Solo ejecutar si al menos una DB requiere logs.
|
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.")
|
If logger Then 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("DELETE FROM query_logs WHERE timestamp NOT in (SELECT timestamp FROM query_logs ORDER BY timestamp desc LIMIT 15000 )")
|
||||||
SQL1.ExecNonQuery("vacuum;")
|
SQL1.ExecNonQuery("vacuum;")
|
||||||
Else
|
Else
|
||||||
' Si IsAnySQLiteLoggingEnabled es False, el Timer no debería estar activo.
|
' 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.")
|
If logger Then Log("AVISO: Tarea de limpieza de logs omitida. El logging global de SQLite está deshabilitado.")
|
||||||
End If
|
End If
|
||||||
End Sub
|
End Sub
|
||||||
@@ -43,6 +43,6 @@ ModuleClosedNodes6=
|
|||||||
ModuleClosedNodes7=
|
ModuleClosedNodes7=
|
||||||
ModuleClosedNodes8=
|
ModuleClosedNodes8=
|
||||||
ModuleClosedNodes9=
|
ModuleClosedNodes9=
|
||||||
NavigationStack=DBHandlerB4X,CleanupAndLog,198,0,DBHandlerJSON,CleanupAndLog,223,0,ParameterValidationUtils,ValidateAndAdjustParameters,45,0,Main,Process_Globals,53,0,Main,AppStart,186,0,Main,LogQueryPerformance,367,0,Main,LogServerError,384,6,Manager,Handle,164,6,Main,borraArribaDe15000Logs,412,0,Cambios,Process_Globals,25,6
|
NavigationStack=Main,TimerLogs_Tick,533,0,Main,LogQueryPerformance,414,5,Main,LogServerError,459,0,Main,AppStart,244,0,Main,WriteQueryLogsBatch,512,1,Main,borraArribaDe15000Logs,617,0,Main,WriteErrorLogsBatch,602,1,Main,InitializeSQLiteDatabase,365,0,Main,Process_Globals,76,4,Cambios,Process_Globals,22,6
|
||||||
SelectedBuild=0
|
SelectedBuild=0
|
||||||
VisibleModules=3,4,13,1,10,11,14,2
|
VisibleModules=3,4,13,1,10,11,14,2
|
||||||
|
|||||||
Reference in New Issue
Block a user