Cómo implementar cobertura de archivos circular usando Node.js
Esta vez, utilicé el módulo de registro al escribir un proyecto Node.js y encontré un pequeño problema.
Este es un proyecto que realiza tareas de automatización configurables de forma regular, por lo que los mensajes de salida seguirán aumentando, lo que significa que el tamaño del archivo de registro seguirá aumentando con el tiempo. Si no controla el tamaño del archivo de registro, tarde o temprano el disco del servidor estará lleno. Por lo tanto, es necesario limitar el tamaño del archivo.
El método de control ideal es borrar los primeros datos grabados cuando el tamaño del archivo excede el límite. Esto es similar a una cola de primero en entrar, primero en salir.
# Eliminar datos anteriores
- 1 xxx
......
100 abc
# Agregar datos al final del archivo
+ 101 xxxx
Desplazamiento de archivos en log4js
Cuando se trata de iniciar sesión, muchos desarrolladores de Node.js definitivamente Encuentre log4js. Primero echemos un vistazo a cómo log4js maneja este problema.
log4js se divide en muchos apéndices (que pueden entenderse como medios de registro) y la función de desplazamiento de archivos se puede configurar a través de una función.
La función de desplazamiento de archivos funciona de dos maneras: fecha y tamaño del archivo.
Para controlar el tamaño del archivo, por supuesto, elige este último.
Para probar si esta función cumple con nuestros requisitos, escriba un código de bucle para escribir registros.
const log4js = require('log4js')
//Configurar log4js
log4js.configure({
appenders: {
todo: {
tipo: 'archivo',
nombre de archivo: 'a.log',
maxLogSize: 1000, p> p>
copias de seguridad: 0
},
},
categorías: {
predeterminado: { p>
apéndices: ['todo'],
nivel: 'depurar'
}
}
}
});
const log = log4js.getLogger();
for (let i = 0; i <.41; i++) {
const str = i.toString().padStart(6, '000000');
log.debug(str);
}
Ejecutar Después de eso, generará dos archivos: a.log y a.log.1
Uno de los archivos es a.log. log.1 tiene 20 líneas de datos y el tamaño real es 1 kb, mientras que a.log tiene solo 1 línea de datos.
Aunque controla el tamaño del archivo, crea dos problemas:
Se crea un archivo de copia de seguridad adicional que ocupa un espacio total en el disco que excede el límite del archivo.
El tamaño del contenido del archivo de registro es variable y consultar el registro puede requerir consultar un archivo de copia de seguridad federado (por ejemplo, en el caso anterior, el archivo de registro tiene solo una fila de datos).
Se especula que la lógica de implementación de log4js puede ser la siguiente:
Compruebe si el archivo de registro alcanza el tamaño límite; de ser así, elimine el archivo de copia de seguridad; de lo contrario, continúe escribiendo el archivo de registro.
Cambie el nombre del archivo de registro al archivo de copia de seguridad.
Esto evidentemente no cumple del todo con los requisitos.
¿Reemplazo de cuerdas?
Es más fácil realizar la operación de cobertura del bucle en la memoria, lo que se puede lograr usando String o Buffer.
Agrega la longitud de la cadena/búfer y la intercepta si excede el tamaño.
Escribe y sobrescribe el archivo de registro.
Pero hay un gran problema: el consumo de memoria.
Por ejemplo, si limita el tamaño del archivo a 1 GB y escribe 10 archivos de registro al mismo tiempo, utilizará al menos 10 GB de espacio de memoria.
La memoria es mucho más valiosa que el espacio en disco, por lo que obviamente esta no es la mejor solución para un problema de rendimiento tan obvio.
Desplazamiento de archivos
El proceso de implementación se puede dividir en dos pasos:
Agregar los datos más recientes al final del archivo. (Existe una función para esto en el módulo fs de Node.js)
Elimina la parte del archivo que excede el límite al principio. (Node.js no proporciona una función para esto)
No hay un orden específico para estos dos pasos, pero Node.js no proporciona una API para eliminar el comienzo del archivo, solo una función para modificar la ubicación especificada del archivo.
Como no podemos eliminar el principio del archivo, cambiemos la idea y conservemos solo el final del archivo (sin exceder el límite de tamaño).
¿Qué? ¿Esto no significa lo mismo?
Ligeramente diferente~
La eliminación se realiza en el archivo original, mientras que la conservación del contenido se puede realizar con la ayuda de archivos temporales.
Entonces la idea es:
Crear un archivo temporal con el contenido del archivo de registro.
Añadir datos al archivo temporal.
Lea el contenido del archivo temporal que cumple con el límite de tamaño de archivo de atrás hacia adelante (en forma de desplazamientos) y cópielo en el archivo de registro para sobrescribirlo.
Para no ocupar espacio adicional en el disco, elimine el archivo temporal una vez completada la operación de escritura.
Hacer esto no hará que el contenido del archivo de registro esté incompleto como lo hace log4js, ni retendrá archivos temporales adicionales.
Sin embargo, las operaciones de IO aumentarán ~
Para las operaciones de escritura, puede usar el comando tail para lograrlo. El código de implementación final es el siguiente:
escritura privada (nombre: cadena, buf?: Buffer | cadena) {
// Agregar buf al archivo tmp
const tmpName = name.replace(/(. *\/)(. *$)/ , '$1 _\.$2\.tmp');
if (!existsSync(tmpName)) {
copyFileSync(nombre, tmpName);
} p>
buf && appendFileSync(tmpName, buf );
// si está ocupado, espere
if (this.stream && this.stream.readable) {
this.needUpdateLogFile[name] = true;
} else {
prueba {
execSync(`tail -c $ {limit} ${tmpName} > ${name}`);
prueba {
if (this.needUpdateLogFile[name] = true)needUpdateLogFile[name] = false;
this.write(nombre);
} else {
existeSync(tmpName) && unlinkSync(tmpName);
} p>
} captura (e) {
console.error(e);
}
}
} captura (e) {
console.error(e);
}
}
} captura (e) {
console.error(e);
}
}
} //p>
Consola . >Hay dos implicaciones para completar esta función:
La cantidad determina la calidad. Cuando la cantidad de datos aumenta, no se pueden utilizar muchos métodos de procesamiento simples, como escribir archivos. Si usa writeFile directamente, ocupará mucha memoria e incluso puede quedarse sin memoria. Por lo tanto, debemos dividirlo de manera adecuada y encontraremos varios problemas durante el proceso de división. Por ejemplo, este artículo requiere interceptar el contenido del archivo.
Aprende a aprovechar. La naturaleza de un caballero no es diferente, y las buenas acciones son mejores que las cosas. Cuando la operación no se puede completar en un solo momento, se puede lograr con la ayuda de condiciones externas. Por ejemplo, en este artículo se utilizan archivos temporales. para guardar el contenido de los datos.
Está bien,