Tengo un programa cuya salida redirijo a un archivo de registro:
./my_app > log
Me gustaría borrar (es decir, vaciar) el registro de vez en cuando (a pedido) y probé varias cosas como
cat "" > log
Sin embargo, siempre parece que la tubería original se interrumpe y el programa ya no redirige su salida al archivo de registro.
¿Hay alguna forma de hacer eso?
Actualizar
Tenga en cuenta que no puedo modificar la aplicación que produce la salida. Simplemente lo escupe en stdout y quiero guardarlo en un registro para poder inspeccionarlo cuando lo necesite y borrarlo cuando lo desee. Sin embargo, no debería necesitar reiniciar la aplicación.
bash
io-redirection
bangnab
fuente
fuente
syslogd
ologrotate
./my_app >> log
(para forzar la adición) ycp /dev/null log
para truncarlo?cat "" > log
no es uncat
comando válido ya que no se llama ningún archivo""
.Respuestas:
Otra forma de este problema ocurre con aplicaciones de larga ejecución cuyos registros se rotan periódicamente. Incluso si mueve el registro original (por ejemplo,
mv log.txt log.1
) y lo reemplaza inmediatamente con un archivo con el mismo nombre antes de que ocurra un registro real, si el proceso mantiene el archivo abierto, terminará escribiendo enlog.1
(porque aún puede ser el inodo abierto) o para nada.Una forma común de lidiar con esto (el registrador del sistema funciona de esta manera) es implementar un controlador de señal en el proceso que cerrará y volverá a abrir sus registros. Luego, cuando quiera mover o borrar (borrando) el registro, envíe esa señal al proceso inmediatamente después.
Aquí hay una demostración simple de bash: perdona mis habilidades de shell (pero si vas a editar esto para las mejores prácticas, etc., asegúrate de comprender primero la funcionalidad y prueba tu revisión antes de editar):
Comience bifurcando en el fondo:
Observe que informa su PID al terminal y luego comienza a iniciar sesión
log.txt
. Ahora tienes 2 minutos para jugar. Espere unos segundos e intente:Simplemente
kill -2 12356
puede funcionar para usted aquí también. La señal 2 es SIGINT (también es lo que hace Ctrl-C, por lo que puede probar esto en primer plano y mover o eliminar el archivo de registro de otro terminal), quetrap
debería atrapar. Verificar;Ahora veamos si todavía está escribiendo en un
log.txt
archivo aunque lo hayamos movido:Observe que siguió yendo justo donde lo dejó. Si no desea mantener el registro, simplemente borre el registro eliminándolo
Cheque:
Sigue yendo
Desafortunadamente, no puede hacer esto en un script de shell para un subproceso ejecutado, porque si está en primer plano, los manejadores de señal de bash
trap
están suspendidos, y si lo bifurca en segundo plano, no puede reasignar su salida. Es decir, esto es algo que debes implementar en tu aplicación.Sin embargo...
Si no puede modificar la aplicación (por ejemplo, porque no la escribió), tengo una utilidad CLI que puede usar como intermediario. También podría implementar una versión simple de esto en un script que sirva como canalización al registro:
Llamemos esto
pipetrap.sh
. Ahora necesitamos un programa separado para probar, imitando la aplicación que desea iniciar sesión:Eso será
test.sh
:Estos son dos procesos separados con PID separados. Para borrar
test.sh
la salida, que se está canalizando a través depipetrap.sh
:Cheque:
15858,
test.sh
todavía se está ejecutando y su salida se está registrando. En este caso, no se necesitan modificaciones en la aplicación.fuente
TL; DR
Abra su archivo de registro en modo agregar :
Luego, puede truncarlo con seguridad con:
Detalles
Con un shell tipo Bourne, hay 3 formas principales en que un archivo se puede abrir para escribir. En modo de solo escritura (
>
), lectura + escritura (<>
) o anexar (y solo de escritura>>
).En los primeros dos, el kernel recuerda la posición actual en la que usted (quiero decir, la descripción del archivo abierto , compartida por todos los descriptores de archivo que lo han duplicado o heredado al bifurcar desde el que abrió el archivo) está en archivo.
Cuando tu lo hagas:
log
está abierto en modo de solo escritura por el shell para el stdout decmd
.cmd
(su proceso inicial generado por el shell y todos los hijos posibles) al escribir en su stdout, escriba en la posición actual del cursor que mantiene la descripción del archivo abierto que comparten en ese archivo.Por ejemplo, si
cmd
inicialmente escribezzz
, la posición estará en el byte offset 4 en el archivo, y la próxima vez quecmd
sus hijos escriban en el archivo, allí es donde se escribirán los datos independientemente de si el archivo ha crecido o disminuido en el intervalo .Si el archivo se ha reducido, por ejemplo, si se ha truncado con un
y
cmd
escribexx
, esosxx
se escribirán en offset4
, y los primeros 3 caracteres serán reemplazados por caracteres NUL.Eso significa que no puede truncar un archivo que se ha abierto en modo de solo escritura (y eso es lo mismo para leer + escribir ) como si lo hiciera, los procesos que tenían descriptores de archivo abiertos en el archivo, dejarán caracteres NUL al comienzo del archivo (aquellos, excepto en OS / X, generalmente no ocupan espacio en el disco, se convierten en archivos dispersos).
En cambio (y notará que la mayoría de las aplicaciones lo hacen cuando escriben en archivos de registro), debe abrir el archivo en modo de adición :
o
si quieres comenzar en un archivo vacío.
En el modo de agregar, todas las escrituras se realizan al final del archivo, independientemente de dónde fue la última escritura:
Eso también es más seguro, ya que si dos procesos han abierto (de esa manera) el archivo por error (como, por ejemplo, si ha iniciado dos instancias del mismo demonio), su salida no se sobrescribirá entre sí.
En las versiones recientes de Linux, puede verificar la posición actual y si se ha abierto un descriptor de archivo en modo de agregado mirando
/proc/<pid>/fdinfo/<fd>
:O con:
Esos indicadores corresponden a los indicadores O ..._ pasados a la
open
llamada al sistema.(
O_APPEND
es 0x400 u octal 02000)Entonces, el shell
>>
abre el archivo conO_WRONLY|O_APPEND
(y 0100000 aquí es O_LARGEFILE que no es relevante para esta pregunta) mientras>
esO_WRONLY
solo (y<>
esO_RDWR
solo).Si haces un:
para buscar archivos abiertos
O_APPEND
, encontrará la mayoría de los archivos de registro actualmente abiertos para escribir en su sistema.fuente
:
(colon) en: >
?:
. Sin un comando, el comportamiento varía entre conchas.Si lo entiendo correctamente,
tee
parece un enfoque razonable:fuente
Como solución rápida, puede usar un registro con rotación (rotación diaria, por ejemplo):
y redirigir el inicio de sesión
./my_app >> log$date.log
fuente
Este es un problema que se ha resuelto durante mucho tiempo con syslog (en todas sus variantes), pero hay dos herramientas que resolverían su problema particular con un mínimo de esfuerzo.
La primera solución más portátil pero menos versátil es el registrador (imprescindible para cualquier caja de herramientas de administrador). Es una utilidad simple que copia la entrada estándar a syslog. (pasando el dinero y haciendo que la rotación de archivos sea el problema de logrotate y syslog)
La segunda solución, más elegante pero menos portátil, es syslog-ng, que además de aceptar mensajes de registro de los sockets estándar de syslog puede ejecutar programas cuya salida se filtra a través del registrador. (Todavía no he usado esta función, pero se ve perfecta para lo que quieres hacer).
fuente