Menyimpan output dari suatu perintah ke dalam buffer cincin


16

Saya punya perintah lama yang menghasilkan banyak output di stdout. Saya ingin dapat mempertahankan, misalnya, hanya tiga hari terakhir atau gibibyte terakhir (menghindari memotong garis di tengah), dan, jika mungkin, dalam potongan file tidak lebih besar dari 20 MiB. Setiap potongan file diberi nama dengan sufiks numerik atau cap waktu.

Sesuatu seperti:

my-cmd | magic-command --output-file-template=my-cmd-%t \
                       --keep-bytes=1G \
                       --keep-time=3d \
                       --max-chunk-size=20M \
                       --compress=xz

Akan menulis:

my-cmd-2014-09-05T10:04:23Z

Ketika mencapai 20 juta, itu akan memampatkannya dan membuka yang baru, dan seterusnya, dan setelah beberapa saat akan mulai menghapus file tertua.

Apakah ada perintah seperti itu?

Saya mengetahui logrotatedan kemampuannya untuk mengelola file yang ditulis oleh aplikasi lain, tetapi saya mencari sesuatu yang lebih sederhana yang tidak melibatkan harus mengatur tugas cron, menentukan aturan, menunda proses, dll.


Apa itu "gibibyte"?
Peter Mortensen

@PeterMortensen Wikipedia: Gibibyte
jw013

Jawaban:


6

Anda dapat memperoleh sebagian dari apa yang Anda inginkan melalui pipelog , yang "memungkinkan untuk memutar atau menghapus log dari proses yang sedang berjalan dengan memiparnya melalui perantara yang merespons sinyal eksternal", misalnya:

spewstuff | pipelog spew.log -p /tmp/spewpipe.pid -x "gzip spew.log.1"

Anda kemudian bisa mendapatkan pid dari /tmp/spewpipe.pid, dan:

kill -s USR1 $(</tmp/spewpipe.pid)

Tetapi Anda harus mengatur dengan cron atau sesuatu. Namun, ada satu tangkapan untuk ini. Perhatikan I gzip spew.log.1- ini karena -xperintah dijalankan setelah log diputar. Jadi, Anda memiliki masalah lebih lanjut tentang menimpa spew.log.1.gzsetiap kali kecuali Anda menulis skrip pendek untuk melakukan gzip dan memindahkan file sesudahnya, dan menggunakannya sebagai -xperintah.

Pengungkapan penuh: Saya menulis ini, jadi tentu saja berfungsi dengan baik . ;) Saya akan tetap mengingat opsi kompres, atau sesuatu yang memfasilitasi dengan lebih baik, untuk versi 0.2 (tujuan yang dimaksudkan -xagak berbeda, tetapi akan berfungsi seperti di atas). Rollover otomatis juga merupakan ide yang bagus ... versi pertama sengaja minimal karena saya menahan godaan untuk menambahkan fitur yang tidak perlu (lagipula tidak sulit untuk mengatur pekerjaan cron untuk ini).

Perhatikan bahwa ini dimaksudkan untuk output teks ; jika ada potensi byte nol, Anda harus menggunakan -z- yang menggantikan nol dengan yang lain. Ini adalah tradeoff untuk menyederhanakan implementasi.


Terima kasih. Saya menantikan pipelog-0.3;-). Saya juga menemukan metacpan.org/release/File-Write-Rotate . Perhatikan bahwa tugas cron tidak akan banyak membantu untuk memutar berdasarkan ukuran file.
Stéphane Chazelas

Rotasi berdasarkan ukuran!?! Itu membuat output tetap memerah, sehingga Anda bisa membuat stat file pada interval ...
goldilocks

Anda tidak dapat mempertahankan ukuran di bawah 20 juta (seperti dalam persyaratan pertanyaan saya) dengan andal seperti itu.
Stéphane Chazelas

Hal lainnya adalah cukup banyak teks saja (saya menambahkan paragraf terakhir tentang itu).
goldilocks

4

Dan Bernstein multilog tampaknya dapat melakukan hal ini - atau mungkin sebagian besar, sementara menyediakan outlet melalui file descriptor untuk prosesor! Untuk membuat perbedaan yang Anda suka - meskipun 20M / 1G spesifikasi ukuran mungkin mengambil beberapa finagling karena tampaknya 16M adalah yang batas luar per log. Berikut ini adalah, sebagian besar, pilihan salin + rekat dari tautan di atas, meskipun tautan juga merinci opsi lain seperti cap waktu per baris, mempertahankan [an] file lain [s] yang hanya berisi pola pencocokan baris terbaru dan lainnya .

Antarmuka

 multilog script

... skrip terdiri dari sejumlah argumen. Setiap argumen menentukan satu tindakan. Tindakan dilakukan agar setiap jalur input.

Memilih garis

Setiap baris pada awalnya dipilih. Tindakan...

-pattern

... batal memilih garis jika polanya cocok dengan garis. Tindakan...

+pattern

memilih garis jika pola cocok dengan garis.

... pola adalah serangkaian bintang dan bukan bintang. Ini cocok dengan rangkaian string yang cocok dengan semua bintang dan non-bintang dalam urutan yang sama. Non-bintang cocok dengan dirinya sendiri. Bintang sebelum akhir pola cocok dengan string apa pun yang tidak menyertakan karakter berikutnya dalam pola. Bintang di akhir pola cocok dengan string apa pun.

Rotasi log secara otomatis

Jika dir dimulai dengan titik atau garis miring maka aksinya ...

 dir

... menambahkan setiap baris yang dipilih ke log yang bernama dir . Jika dir tidak ada, multilogbuatlah.

Format log adalah sebagai berikut:

  1. dir adalah direktori yang berisi beberapa file log lama, file log bernama saat ini , dan file lainnya untuk multilogmelacak tindakannya.

  2. Setiap file log lama memiliki nama yang dimulai dengan @ , dilanjutkan dengan stempel waktu yang tepat yang menunjukkan kapan file selesai, dan diakhiri dengan salah satu kode berikut:

    • .s : File ini sepenuhnya diproses dan ditulis dengan aman ke disk.
    • .u : File ini sedang dibuat pada saat pemadaman. Mungkin sudah terpotong. Itu belum diproses.

Tindakan...

 ssize

... mengatur ukuran file maksimum untuk tindakan dir berikutnya .multilogakan memutuskan bahwa arus cukup besar jika arus memiliki ukuran byte. ( multilogjuga akan memutuskan bahwa saat ini cukup besar jika melihat baris baru dalam 2000 byte dari ukuran file maksimum; ia mencoba menyelesaikan file log pada batas garis.) ukuran harus antara 4096 dan 16777215. Ukuran file maksimum default adalah 99999.

Dalam versi 0.75 dan di atasnya: Jika multilogmenerima sinyal ALRM , ia segera memutuskan bahwa arus cukup besar, jika arus tidak kosong.

(Catatan: Saya menduga zsh schedulebuiltin dapat dengan mudah dibujuk untuk mengirim ALRMpada interval yang ditentukan jika perlu.)

Tindakan...

 nnum

... mengatur jumlah file log untuk tindakan dir berikutnya . Setelah mengganti nama saat ini , jikamultilog melihat num atau lebih file log lama, itu menghapus file log lama dengan cap waktu terkecil. num harus minimal 2. Jumlah default file log adalah 10.

Tindakan...

 !processor

... mengatur prosesor untuk tindakan dir berikutnya . multilogakan memberi makan arus melalui prosesor dan menyimpan output sebagai file log lama, bukan saat ini . multilogjuga akan menyimpan output apa pun yang ditulis prosesor ke deskriptor 5, dan membuat output tersebut dapat dibaca pada deskriptor 4 saat menjalankan prosesor pada file log berikutnya. Untuk keandalan, prosesor harus keluar dari nol jika mengalami kesulitan dalam membuat outputnya; multilogkemudian akan menjalankannya lagi. Perhatikan bahwa prosesor yang berjalan dapat memblokir input program apa pun multilog.


2

Yang terbaik yang bisa saya temukan sejauh perkiraan yang tidak melibatkan penulisan kode dalam jumlah besar adalah zshkode ini :

autoload zmv
mycmd |
  while head -c20M > mycmd.log && [ -s mycmd.log ]; do
    zmv -f '(mycmd.log)(|.(<->))(|.gz)(#qnOn)' '$1.$(($3+1))$4'
    {rm -f mycmd.log.1 mycmd.log.50.gz; (gzip&) > mycmd.log.1.gz} < mycmd.log.1
  done

Di sini membelah dan memutar paling banyak menjadi 51 file 20MiB.


mungkin ... loopmounts? btrfsjuga bisa dipasang dengan compress-force=zlib.
mikeserv

2

Berikut ini adalah skrip python yang diretas untuk melakukan sesuatu seperti apa yang Anda minta:

#!/bin/sh
''':'
exec python "$0" "$@"
'''

KEEP = 10
MAX_SIZE = 1024 # bytes
LOG_BASE_NAME = 'log'

from sys import stdin
from subprocess import call

log_num = 0
log_size = 0
log_name = LOG_BASE_NAME + '.' + str(log_num)
log_fh = open(log_name, 'w', 1)

while True:
        line = stdin.readline()
        if len(line) == 0:
                log_fh.close()
                call(['gzip', '-f', log_name])
                break
        log_fh.write(line)
        log_size += len(line)
        if log_size >= MAX_SIZE:
                log_fh.close()
                call(['gzip', '-f', log_name])
                if log_num < KEEP:
                        log_num += 1
                else:
                        log_num = 0
                log_size = 0
                log_name = LOG_BASE_NAME + '.' + str(log_num)
                log_fh = open(log_name, 'w', 1)

1
Apakah ada alasan untuk memilikinya sebagai skrip shell yang execs python sebagai hal pertama daripada menggunakan pythonatau env pythonhashbang?
peterph
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.