
Archivo de registro eliminado accidentalmente del proceso en ejecución python something.py 2>&1 | tee .log
. El script se ejecuta en un panel tmux en zsh. El proceso aún se está ejecutando pero no se registra. La salida en sí desborda el búfer tmux-scrollback. ¿Puedo de alguna manera (derechos de administrador/sudo) iniciar el proceso de registro nuevamente sin reiniciar el proceso?
Normalmente mi intento funciona sin problemas y el código no es relevante para la seguridad ni para ningún tipo de producción, sino simplemente cálculos matemáticos complejos. Por tanto, este intento siempre ha sido suficiente.
En mi caso actual, sería fantástico poder iniciar sesión nuevamente sin reiniciar el proceso.
Respuesta1
El archivo continúa existiendo mientras el tee
proceso tenga un descriptor de archivo abierto y todo se siga registrando allí. Puedes recuperar su contenido actual copiándolos a través de /proc:
Encuentre el PID del proceso en 'T'.
Utilice
lsfd -p <PID>
olsof -p <PID>
ols -l /proc/<PID>/fd
para encontrar el número del descriptor de archivo correspondiente al archivo abierto. (Incluso estará marcado como "(eliminado)" junto al nombre del archivo).Con programas simples como 'tee', el primer archivo abierto casi siempre será FD #3, por lo que todos los ejemplos de esta publicación
3
también se utilizarán.Copie el contenido del archivo a un archivo nuevo a través de
/proc
:cp /proc/<TEE_PID>/fd/3 old.log
(Los enlaces simbólicos en /proc/PID/fd son especiales: abrirlos aún se resuelve en el archivo correcto, incluso si el enlace simbólico parece roto o incluso si apunta a algo que ni siquiera es un archivo real).
También es posible hacer que 'tee' comience a escribir en un archivo nuevo:
Adjunte el
gdb
depurador al proceso:$ sudo gdb -p <TEE_PID>
Esto detendrá el 'tee'. El programa Python también podría pausarse si produce suficiente salida de registro para llenar el búfer de canalización (de lo contrario, no se dará cuenta).
Si aún no lo ha hecho, use el truco /proc para recuperar el archivo de registro antiguo (a través de otro shell, no desde gdb):
$ cp /proc/<TEE_PID>/fd/3 old.log
Al hacer estodespuésgdb está adjunto (es decir, mientras 'tee' está suspendido), puede evitar perder mensajes durante el intervalo entre 'cp' y open().
Ahora use gdb para cerrar 'tee' y volver a abrir el archivo:
(gdb) p (int) close(3) $1 = 0 (gdb) p (int) open("new.log", 01|0100|02000, 0666) $2 = 3 (gdb) q Detach? y
(Los valores
01|0100|02000
son iguales aO_WRONLY|O_CREAT|O_APPEND
desdefcntl.h, lo que hace que la llamada open() se comporte como el>>
operador de shell).Para casos simples como 'tee', es extremadamente improbable que open() le proporcione cualquier otro descriptor de archivo que no sea el #3 original, ya que ese es el FD gratuito más bajo. Pero en algunas situaciones con programas más complejos (si hay una brecha en la numeración) puede ser necesario llamar
dup2($2, 3)
yclose($2)
mover manualmente el archivo recién abierto al FD deseado.El archivo antiguo ahora desaparecerá por completo (ya que se eliminóyel último identificador de archivo se cerró), pero 'tee' escribirá en el nuevo archivo sin notar nada.
Nota: en lugar de abrir un archivo nuevo,puedeSe podrá utilizar linkat()
para crear el archivo de registro original sin interrumpir nada, pero aún no lo he probado. (Editar: Desafortunadamente, según la documentación de linkat(), esto específicamente no funciona para archivos que se han desvinculado por completo).