Borrar log periódicamente

Iniciado por Becerra, 16 Mayo 2019, 13:02 PM

0 Miembros y 1 Visitante están viendo este tema.

Becerra

Hola

Estoy con un programa que va guardando un log en la base de datos de algunas operaciones que va haciendo. Quiero que de ese log se vayan limpiando los registros más antiguos, son datos que pasado un tiempo ya no me valen de nada.

Habrá días que se guarden varias entradas en el log y otros ninguna. Mi idea es al iniciar el programa hacer un DELETE de los registros que tengan más de un mes de antiguedad.

Es lo más sencillo, habrá días que se borre uno, ninguno o varios, no sé si es lo más óptimo o como suelen hacerse estas cosas.

¿Alguna otra consideración?

Un saludo
Buenas preguntas obtienen mejores respuestas

animanegra

#1
¿Has probado el Logrotate?

EDIT: Soy subnormal, no me fijé que era la sección de programación. ^^ Lo siento y un abrazo.

42
No contesto mensajes por privado, si tienes alguna pregunta, consulta o petición plantéala en el foro para que se aproveche toda la comunidad.

Serapis

#2
Hay dos formas básicamente de hacerlo (con ficheros, si no recurres a una base de datos):
Considera la cosa como te enumero:
Ayer creaste 20 registros, hoy creas 10 registros, mañana creas 30 registros... total 60.
Ahora pongamos que llega el momento de borrar los de ayer... sucede que están al comienzo del fichero, luego eliminar los registros, básicamente se limita a copiar a un nuevo fichero los registros vigentes... y luego eliminar el viejo fichero, y renombrar el nuevo con el nombre del viejo...

Ahora bien, puede optimizarse?.  Si, claro...
Considera el log, como un array, una lista, donde siempre se borra del comienzo x (un número indeterminado de registros), lo que se hace de forma más eficiente, es 'subir' todos los registros por debajo, justamente 'x' registros hacia arriba... y casi está listo.
Tan solo resta saber que es preciso el mantenimiento de algunos datos para tener informada dichas condiciones...

Ahora pasemos a un punto más cercano al código que la propia prosa que lo describe:

// Cabecera de fichero...
Estructura LogFile
  int Ultima      //  Es la posición de escritura de la siguiente línea.
  int Entradas   // cantidad de entradas (días) que tiene actualmente el log.
fin estructura

Estructura LogData
  int MesYdia   // (mes * 100) + día , o de tipo fecha si prefieres...
  int LogsHoy      // cantidad de logs alojados para el mes y día x
  // Nota si todos los días se escriben registro posiblemente pueda omitirse el mes.
  array string LogTxt     // los datos a almacenar...
Fin Estructura

logData  Logs()   // un array de 'logdata'
logData Log   /// un log temporal


* La primera estructura sería la cabecera del fichero, simplemente se sobrescriben los datos 'ultima' y 'Entradas'.
--- Entradas: Contiene la cantidad de entradas (días) que contiene el fichero.
--- Ultima: Es el puntero de escritura, es importante, porque al borrar entradas, entradas viejas quedan en el fichero (no importa se sobrescribirán cuando proceda), pero es preciso saber donde escribir las nuevas entradas...

* La estructura logData contiene los datos del log de un día concreto... Hay tantas como señala 'Entradas'
--- MesYDía contiene la fecha relativa al día y mes de esa entrada.
--- Logshoy, señala cuantas líneas de log se han añadido, es decir el tamaño del campo LogTxt, que son almacenadas un día en concreto...

Al abrir el programa lo primero es leer la cabecera, verificar si tiene una o más entradas y en tal caso leer la primera, y verificar si su fecha ha sobrepasado el plazo previsto (30 días por ejemplo)...
sugiero transformar la fecha en un entero para hacer comparaciones sencillas, mediante la fórmula: f = (mes * 100) + dia
.... donde mes va del rango 1 al 12 y dia del 1 al 31, así tendrías guardadas como fechas valores de ejemplo:
 Enero 1= 101
 Enero 15 = 115
 Enero 22 = 122
 Abril 19= 419
  Mayo 19 = 519
 Diciembre 25= 1225
La comparación será fácil si el mes actual es mayor que el previo, pero hay que considerar también el caso opuesto, por ejemplo que la primera entrada sea de diciembre y hoy sea enero... En esos casos cuando el mes actual es menor que la primera entrada, basta sumar a hoy (12 * 100), antes de comparar las fechas...
buleano = Funcion Eliminable(int entrada, int hoy)
     Si (entrada > hoy)
         entrada + = 1200
     fin si
      // + 100 porque es la diferencia entre el día de un mes y el mismo día sel siguiente mes.
      // a propósito puse en el ejemplo 19 de abril y 19 de mayo, míralo otra vez...
     Si (entrada + 100 <= hoy) 
         devolver TRUE
     fin si
fin funcion


Si devuelve TRUE se invoca una función para 'EliminarLogDia' (que ya sabes que a pesar de su nombre no elimina nada, solo mueve datos... baja los logs de arriba, exactamente la cantidad que ocupa los datos de la entrada del log del día a eliminar...

Se puede optimizar más?. Posiblemente sí... Si resulta que el tamaño de los logs se hacen de tamaño fijo (todas iguales), entonces el fichero log se puede repartir en dos (es más fácil de amntener y calcular/procesar), uno sería el 'logcontrol.txt' y otro el 'logdata.txt'...
El de control tendría la cabecera y otra estructura simplificada a solo los datos indicativos del log de cada día:
estructura LogDia
    int MesYdia       // (mes * 100) + día , o de tipo fecha si prefieres...
    int LogsHoy      // número de entradas para el mes y día x
fin estructura


Ahora cuando haya que borrar la entrada de un día, directamente se puede sobrecribir las entradas en este fichero sin más complicaciones:

funcion EliminarPrimera
  logdia ld
  int k, n, sizeLogdia, ...
  int puntero

  puntero = size(estructura logfile)
  sizelogdia= size(estructura logdia)
 
  Bucle para k desde 1 hasta cabecera.Entradas -1
      ld = leerRegistro(puntero + sizelogdia)
       // aquí irá más código como señalaré más abajo..
       // ...
       //
      escribirRegistro(puntero, ld)
      puntero + = sizelogdia
  Siguiente

  cabecera.Entradas -=1
  cabecera.Ultima = n // 'n' se calcula después de hacer lo propio sobre el otro fichero...
fin funcion


Como se ve el mantenimiento de este fichero será extramadamente sencillo, eliminar el log de un día es un bucle para bajar todos los registros entrados un registro más abajo...

El fichero, que contiene el texto, al ser entradas de tamaño fijo (cada log), aunque varíe el número de líneas que tenga cada día, simplemente se trata de saber cuantas líneas contiene ese día, multiplicarlo por el largo fijo de cada log, y por tanto en un bucle (en realidad el mismo que se acaba de describir, porque puede ir en la misma función (aunque rerquiere un segundo bucle anidado), recorrer desde la primera línea de la segunda entrada hasta la última línea de la ultima entrada aceptada en el fichero.

El primer bucle recorre los días, el segundo las líneas que tenga cada día, y básicamente dentro de ese segundo bucle lo que se hace es leer la línea y voverla a escribir desplazado la cantidad precalculada hacia abajo. El bucle externo (que en realidad sirve el mismo puesto en la función previa, antes de moverlo-escribirlo, para utilizar sus datos), simplemente toma cuenta de cuantas líneas tiene que leer y escribir el segundo bucle...
Al final de ambos bucles la posición del siguiente registro que se fuera a escribir, será el valor a asignar en cabecera.Ultima


Solo restan dos cosas por aclarar:
- Cada nueva entrada se añade al final de las entradas (no del fichero). Con cada entrada se actualiza la cabecera el número de entradas y con cada línea de log a la entrada de un día, el número de líneas para ese día y la posición de escritura d ela siguiente (donde acaba la última escrita)
- El fichero así... puede ser más largo de lo requerido en un día preciso, pero no importa, se supone que pueda tener algunas líneas más de las precisas porque un día se borraron por ejemplo 120 líneas y luego ese día se escribieron 20, siguen quedando 100 al final (sin uso, sucias, pero no computadas), sigue sin importar, puede que dentro de unos días solo borrees 30 y luego escribas 90... considera que de forma absoluta el ficheor no ocupará (se supone) un tamaño mayor de cierto tolerable...
tamaño)... dicho de otro modo, ambos ficheros al tener una estructura fija se comportan como una pila, donde solo importan los x datos del comienzo, sin importar los datos que residan detrás...

Y con esto creo que debiera quedarte todo bastante claro. Naturalmente se entiende que tu pregunta odbedece a que no usar una base de datos si no que lo manejas tu mismo... La copción de escribir un nuevo fichero copiando lo que proceda, eliminar el viejo y renombrar el nuevo, es si cabe más sencilla de 'entender' y quizás de abordar, pero esta otra solución es más óptima a considerar sobretodo si el tamaño de los logs es fijo, tu decides cual usar...

Becerra

Hola

Bueno, esta es una solución un poquito más elaborada de la que yo tengo  :rolleyes:

Ahora mismo lo que hago es guardar en una tabla de la base de datos y cada vez que se inicia el programa hago un DELETE a esa tabla, lo que no me acaba de gustar, pero bueno. Creo que ahora mismo lo voy a dejar así, ya que me urge terminarlo.

Y en cuanto pueda haré algo más elaborado.

Logrotate no lo conocía, pero por lo que vi, ahora mismo no me vale por que los datos del log están junto a otros en la base de datos. Además, se va a instalar en varios ordenadores que usan windows.

Muchas gracias!!
Buenas preguntas obtienen mejores respuestas

Serapis

Las soluciones que yo te propuse son para operar directamente con ficheros...

...y aclaraba que si usas una base de datos, resulta superfluo, simplemente usa una única tabla y añade registros, cada día simplemente al abrir el programa simplemente haces un: "delete all from tblLog where ((fecha < (hoy-30dias))" y listo, la BD borra cada registro anterior a la fecha dada, en apenas un simple línea de código...