実行中のプロセス `python something.py 2>&1 | tee .log` のログ ファイルを誤って削除しました。tmux ペインに出力を保存する方法はありますか?

実行中のプロセス `python something.py 2>&1 | tee .log` のログ ファイルを誤って削除しました。tmux ペインに出力を保存する方法はありますか?

実行中のプロセスのログ ファイルを誤って削除しましたpython something.py 2>&1 | tee .log。スクリプトは zsh の tmux ペインで実行されています。プロセスはまだ実行されていますが、ログは記録されていません。出力自体が tmux-scrollback-buffer をオーバーフローしています。何らかの方法で (管理者/sudo 権限で) プロセスを再起動せずにログ記録プロセスを再開できますか?

通常、私の試みは問題なく機能し、コードは安全性や何らかの生産には関係なく、単に複雑な数学的計算です。したがって、この試みは常に十分でした。

私の現在のケースでは、プロセスを再起動せずに再びログ記録を開始できれば素晴らしいと思います。

答え1

プロセスが開いているファイル記述子を保持している限り、ファイルは存在し続けtee、すべてがそこに記録されます。 /proc を介してコピーすることで、現在の内容を回復できます。

  1. 「tee」プロセスの PID を見つけます。

  2. lsfd -p <PID>または をlsof -p <PID>使用してls -l /proc/<PID>/fd、開いているファイルに対応するファイル記述子番号を検索します。(ファイル名の横に「(削除済み)」と表示されます。)

    「tee」などの単純なプログラムでは、開かれる最初のファイルはほぼ常に FD #3 になるため、この投稿のすべての例で3もこれを使用します。

  3. ファイルの内容を次の方法で新しいファイルにコピーします/proc:

    cp /proc/<TEE_PID>/fd/3 old.log
    

    (/proc/PID/fd 内のシンボリック リンクは特別です。シンボリック リンクが壊れているように見えたり、実際のファイルではないものを指し示していたり​​する場合でも、シンボリック リンクを開くと正しいファイルに解決されます。)

'tee' に新しいファイルへの書き込みを開始させることも可能です:

  1. gdbデバッガーをプロセスに接続します。

    $ sudo gdb -p <TEE_PID>
    

    これにより、'tee' が一時停止します。パイプ バッファーを満たすのに十分なログ出力を生成すると、Python プログラムも一時停止される可能性があります (それ以外の場合は認識されません)。

  2. まだ行っていない場合は、/proc トリックを使用して古いログ ファイルを復元します (gdb 内からではなく、別のシェルから)。

    $ cp /proc/<TEE_PID>/fd/3 old.log
    

    こうすることでgdb がアタッチされている間 (つまり、'tee' が中断されている間)、'cp' と open() の間のギャップ中にメッセージが失われるのを防ぐことができます。

  3. ここで、gdb を使用して 'tee' を閉じて、ファイルを再度開きます。

    (gdb) p (int) close(3)
    $1 = 0
    
    (gdb) p (int) open("new.log", 01|0100|02000, 0666)
    $2 = 3
    
    (gdb) q
    Detach? y
    

    (値01|0100|02000O_WRONLY|O_CREAT|O_APPENDfcntl.hこれにより、open() 呼び出しは>>シェル演算子のように動作します。

    'tee' のような単純なケースでは、open() が元の #3 以外のファイル記述子を返す可能性は極めて低いです。これは、これが最も小さい空き FD だからです。しかし、より複雑なプログラムの場合 (番号のギャップがある場合)、呼び出してdup2($2, 3)close($2)新しく開いたファイルを手動で目的の FD に移動する必要があるかもしれません。

  4. 古いファイルは完全に消えます(削除されたため)そして最後のファイル ハンドルが閉じられた場合など)、'tee' は何も気付かずに新しいファイルに書き込みます。

注: 新しいファイルを開く代わりに、5月何も中断せずに元のログ ファイルを作成するために使用できる可能性がありますlinkat()が、まだテストしていません。(編集: 残念ながら、linkat() のドキュメントによると、これは完全にリンク解除されたファイルでは機能しません。)

関連情報