Cara membatasi ukuran file log menggunakan >>

24

Bagaimana saya bisa membatasi ukuran file log yang ditulis dengan >>200MB?

$ run_program >> myprogram.log
David
sumber
1
Apakah Anda ingin program terbunuh setelah 200MB? Atau Anda ingin 200MB terakhir dengan semua yang lebih tua di ember bit?
Aaron D. Marasco
tidak, proses tidak dapat berhenti sampai dibunuh secara manual
david
memutuskan untuk menggunakan logrotate, terima kasih semua orang atas masukan yang berharga
david

Jawaban:

9

Jika aplikasi Anda (mis. run_program) Tidak mendukung pembatasan ukuran file log, maka Anda dapat memeriksa ukuran file secara berkala dalam satu lingkaran dengan aplikasi atau skrip eksternal.

Anda juga dapat menggunakan logrotate(8)untuk memutar log Anda, ia memiliki sizeparameter yang dapat Anda gunakan untuk tujuan Anda:

Dengan ini, file log diputar ketika ukuran yang ditentukan tercapai. Ukuran dapat ditentukan dalam bytes (default), kilobytes (sizek), atau megabytes (sizem).

Emre Yazici
sumber
1
+1 File log dengan informasi berulang sering dapat dikompresi dalam urutan besarnya.
pengguna tidak diketahui
Apakah logrotate memotong file, atau hanya menyalin atau memindahkannya? Karena ini hanya akan berfungsi jika file yang terkait dengan fd terpotong. Jika sudah mv'd, file akan terus bertambah, jika tidak ditautkan, file akan tetap terbuka dan terus bertambah sampai proses keluar ... IIRC menyalin salinan, memutus tautan, dan membuat file baru, itulah sebabnya kita sering harus mengirim SIGHUP ke demon ketika log mereka telah diputar.
Michael Trausch
Perhatikan bahwa meskipun itu terpotong, ada masalah jika file tidak dibuka dalam mode append (file log harus selalu dibuka dalam mode append, tetapi menurut pengalaman saya sering tidak)
Random832
Logrotate dapat diputar setelah file mencapai ukuran tertentu, harian, mingguan, dll. Ia juga dapat mengompres, dan Anda dapat menggunakan postscriptopsi untuk mengirim konfigurasi logrotate SIGHUPke program.
laebshade
12

Jika program Anda tidak perlu menulis file LAINNYA yang akan lebih besar dari batas ini, Anda dapat menginformasikan kernel menggunakan batas ini ulimit. Sebelum Anda menjalankan perintah Anda, jalankan ini untuk menyiapkan batas ukuran file 200MB untuk semua proses yang dijalankan di sesi shell Anda saat ini:

ulimit -f $((200*1024))

Ini akan melindungi sistem Anda, tetapi mungkin jaring untuk program yang menulis file. Seperti yang disarankan eyazici , pertimbangkan untuk mengatur logrotateuntuk memangkas file log setelah mereka mencapai ukuran atau usia tertentu. Anda dapat membuang data lama atau mengarsipkannya untuk jangka waktu tertentu dalam serangkaian file terkompresi.

Caleb
sumber
ini membatasi ukuran file apa pun yang ditulis oleh program
Kim
Benar. Jika program memiliki kebutuhan sah untuk menulis file besar lainnya, Anda akan memerlukan solusi yang berbeda.
Caleb
6

Anda dapat membuat image sistem file baru, pasang menggunakan perangkat loop dan letakkan file log pada sistem file itu:

dd if=/dev/zero of=./200mb.img bs=1024 count=200000 # create new empty 200MB file
mkfs.ext2 200mb.img # or ext3, or whatever fits your needs
mkdir logs
sudo mount -t ext2 -o loop 200mb.img logs # only root can do '-o loop' by default
run_program >>logs/myprogram.log

Anda juga dapat menggunakan tmpfssebagai ganti file, jika Anda memiliki cukup memori.

alex
sumber
Ide kreatif ... itu tergantung pada program tentang apa yang harus dilakukan ketika habis.
Aaron D. Marasco
6

Anda dapat memotong output dengan head:

size=$((200*1024*1024-$(stat -c %s myprogram.log)))
run_program | head -c ${size} >> myprogram.log
tuxce
sumber
Sangat kreatif. Hanya catatan bahwa ini hanya akan berfungsi untuk membatasi data BARU yang ditulis ke file, itu tidak akan memperhitungkan seberapa besar atau kecil file yang sudah ada.
Caleb
2
Perhatikan bahwa kemungkinan ini akan mematikan program (dengan SIGPIPE) setelah telah mencapai batas ukuran, daripada membuang data.
Random832
1
Saya sedang berpikir mirip dengan ddsihir tapi ya @ Random832 benar, Anda akan mendapatkan SIGPIPEsebagai head/ dd/ whatevermenjatuhkannya.
Aaron D. Marasco
Bagaimana dengan mengabaikannya dengan trap '' SIGPIPE?
tuxce
Atau pipa untuk { head -c "$size" >> log; cat > /dev/null; }.
Stéphane Chazelas
5

Dalam paket apache2-utilsdisebut utilitas saat ini rotatelogs, mungkin bermanfaat bagi Anda.

Ringkasan:

rotatelogs [-l] [-L linkname ] [-p program ] [-f] [-t] [-v] [-e] [-c] [-n jumlah-of-file ] logfile waktu rotasi | filesize (B | K | M | G) [ offset ]

Contoh:

your_program | rotatelogs -n 5 /var/log/logfile 1M

Manual lengkap bisa Anda baca di tautan ini .

PRIHLOP
sumber
Tautan tidak ada.
Alexander Gonchiy
1

Saya yakin poster asli telah menemukan solusi. Berikut ini satu lagi untuk orang lain yang dapat membaca utas ini ...

Curtail membatasi ukuran output program dan mempertahankan 200MB output terakhir dengan perintah berikut:

$ run_program | curtail -s 200M myprogram.log

Referensi

CATATAN: Saya adalah pengelola repo di atas. Hanya berbagi solusinya ...

Dave Wolaver
sumber
Saya suka gagasan pembatasan. Saya tidak begitu akrab dengan C, jadi apakah ada peluang untuk memberikan biner? atau setidaknya petunjuk rinci tentang cara menginstalnya?
Felipe
0

Karena ini adalah teks, saya akan menulis skrip dalam bahasa favorit Anda dan mengirimkannya ke situ. Apakah itu menangani file I / O (atau menyimpan semuanya dalam memori dan kemudian membuangnya SIGHUPatau serupa). Untuk itu, alih-alih 200MB saya akan memikirkan jumlah baris yang 'masuk akal' untuk dilacak.

Aaron D. Marasco
sumber
Menyimpan 200MB data log dalam memori tanpa alasan lain selain untuk dapat memotongnya bukanlah penggunaan sumber daya sistem yang sangat baik. Juga tidak melakukan penghitungan baris pada file log besar. Saya akan merekomendasikan menggunakan alat yang dibangun untuk ini syslogdan logrotate.
Caleb
0

Skrip berikut harus melakukan pekerjaan itu.

LOG_SIZE=500000
NUM_SEGM=2
while getopts "s:n:" opt; do
  case "$opt" in
    s)
      LOG_SIZE=$OPTARG
      ;;
    n)
      NUM_SEGM=$OPTARG
      ;;
  esac
done
shift $((OPTIND-1))
if [ $# == 0 -o -z "$1" ]; then
    echo "missing output file argument"
    exit 1
fi
OUT_FILE=$1
shift
NUM=1
while :; do
    dd bs=10 count=$(($LOG_SIZE/10)) >> $OUT_FILE 2>/dev/null
    SZ=`stat -c%s $OUT_FILE`
    if [ $SZ -eq 0 ]; then
        rm $OUT_FILE
        break
    fi
    echo -e "\nLog portion finished" >> $OUT_FILE
    mv $OUT_FILE $OUT_FILE.n$NUM
    NUM=$(($NUM + 1))
    [ $NUM -gt $NUM_SEGM ] && NUM=1
done

Ini memiliki beberapa jalan pintas yang jelas, tetapi secara keseluruhan itu melakukan apa yang Anda minta. Ini akan membagi log menjadi potongan dengan ukuran terbatas, dan jumlah potongan juga terbatas. Semua dapat ditentukan melalui argumen baris perintah. File log juga ditentukan melalui baris perintah.

Catat gotcha kecil jika Anda menggunakannya dengan daemon yang bercabang ke latar belakang. Menggunakan pipa akan mencegah daemon masuk ke latar belakang. Dalam hal ini ada sintaks (kemungkinan khusus untuk bash) untuk menghindari masalah:

my_daemon | ( logger.sh /var/log/my_log.log <&0 & )

Perhatikan <&0, meskipun tampak berlebihan, tidak akan berfungsi tanpa ini.

stsp
sumber