Ketika tee
berakhir, perintah yang memberinya makan akan terus berjalan, hingga mencoba menulis lebih banyak keluaran. Kemudian akan mendapatkan SIGPIPE (13 pada sebagian besar sistem) untuk mencoba menulis ke pipa tanpa pembaca.
Jika Anda memodifikasi skrip Anda untuk menjebak SIGPIPE dan mengambil beberapa tindakan yang sesuai (seperti, berhenti menulis keluaran), maka Anda seharusnya dapat melanjutkannya setelah tee diakhiri.
Lebih baik lagi, daripada membunuh tee
sama sekali, gunakan logrotate
dengan copytruncate
pilihan untuk kemudahan.
Mengutip logrotate(8)
:
copytruncate
Potong file log asli di tempat setelah membuat salinan, alih-alih memindahkan file log lama dan secara opsional membuat yang baru. Ini dapat digunakan ketika beberapa program tidak dapat diminta untuk menutup file lognya dan dengan demikian mungkin terus menulis (menambahkan) ke file log sebelumnya selamanya. Perhatikan bahwa ada waktu yang sangat singkat antara menyalin file dan memotongnya, sehingga beberapa data logging mungkin hilang. Saat opsi ini digunakan, opsi buat tidak akan berpengaruh, karena file log lama tetap di tempatnya.
Menjelaskan "Mengapa"
Singkatnya:Jika penulisan gagal tidak menyebabkan program keluar (secara default), kita akan mengalami kekacauan. Pertimbangkan find . | head -n 10
-- Anda tidak ingin find
untuk terus berjalan, memindai sisa hard drive Anda, setelah head
telah mengambil 10 baris yang diperlukan dan melanjutkan.
Melakukannya Lebih Baik:Putar Di Dalam Logger Anda
Pertimbangkan yang berikut ini, yang tidak menggunakan tee
sama sekali, sebagai contoh demonstratif:
#!/usr/bin/env bash
file=${1:-debug.log} # filename as 1st argument
max_size=${2:-100000} # max size as 2nd argument
size=$(stat --format=%s -- "$file") || exit # Use GNU stat to retrieve size
exec >>"$file" # Open file for append
while IFS= read -r line; do # read a line from stdin
size=$(( size + ${#line} + 1 )) # add line's length + 1 to our counter
if (( size > max_size )); then # and if it exceeds our maximum...
mv -- "$file" "$file.old" # ...rename the file away...
exec >"$file" # ...and reopen a new file as stdout
size=0 # ...resetting our size counter
fi
printf '%s\n' "$line" # regardless, append to our current stdout
done
Jika dijalankan sebagai:
/mnt/apps/start.sh 2>&1 | above-script /tmp/nginx/debug_log
... ini akan dimulai dengan menambahkan /tmp/nginx/debug_log
, mengganti nama file menjadi /tmp/nginx/debug_log.old
ketika lebih dari 100KB konten hadir. Karena logger itu sendiri yang melakukan rotasi, tidak ada pipa yang rusak, tidak ada kesalahan, dan tidak ada jendela kehilangan data saat rotasi berlangsung -- setiap baris akan ditulis ke satu file atau lainnya.
Tentu saja, menerapkan ini di bash asli tidak efisien, tetapi di atas adalah contoh ilustratif. Ada banyak program yang tersedia yang akan mengimplementasikan logika di atas untuk Anda. Pertimbangkan:
svlogd
, pencatat layanan dari rangkaian Runit.s6-log
, alternatif yang dipelihara secara aktif dari skanet suite.multilog
dari DJB Daemontools, nenek moyang keluarga alat pengawasan dan pemantauan proses ini.