เก็บเอาต์พุตของคำสั่งลงในริงบัฟเฟอร์


16

ฉันมีคำสั่งที่ใช้เวลานานซึ่งสร้างเอาต์พุตจำนวนมากบน stdout ฉันต้องการเก็บตัวอย่างเช่นสามวันสุดท้ายหรือ gibibyte ล่าสุด (หลีกเลี่ยงการตัดเส้นตรงกลาง) และถ้าเป็นไปได้ในไฟล์ไฟล์ไม่เกิน 20 MiB แต่ละอันถูกตั้งชื่อด้วยส่วนต่อท้ายที่เป็นตัวเลขหรือเวลาประทับ

สิ่งที่ต้องการ:

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

จะเขียน:

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

เมื่อถึง 20M มันจะบีบอัดและเปิดไฟล์ใหม่และอื่น ๆ หลังจากนั้นสักครู่มันจะเริ่มลบไฟล์ที่เก่าที่สุด

คำสั่งดังกล่าวมีอยู่จริงหรือไม่?

ฉันรู้logrotateและความสามารถในการจัดการไฟล์ที่เขียนโดยแอปพลิเคชั่นอื่น แต่ฉันกำลังมองหาสิ่งที่ง่ายกว่าที่ไม่เกี่ยวข้องกับการตั้งค่างาน cron ระบุกฎระงับกระบวนการ ฯลฯ


"gibibyte" คืออะไร?
Peter Mortensen

@PeterMortensen Wikipedia: Gibibyte
jw013

คำตอบ:


6

คุณสามารถรับบางสิ่งที่คุณต้องการผ่านpipelogซึ่ง "อนุญาตให้หมุนหรือล้างบันทึกของกระบวนการที่กำลังทำงานอยู่โดยการส่งผ่านตัวกลางที่ตอบสนองต่อสัญญาณภายนอก" เช่น:

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

จากนั้นคุณสามารถรับ pid จาก/tmp/spewpipe.pidและ:

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

แต่คุณจะต้องติดตั้ง cron หรืออะไรซักอย่าง อย่างไรก็ตามมีสิ่งหนึ่งที่จับต้องได้ แจ้งให้ทราบฉันgzip spew.log.1- นี่เป็นเพราะ-xคำสั่งจะถูกดำเนินการหลังจากที่มีการหมุนบันทึก ดังนั้นคุณมีปัญหาเพิ่มเติมของการเขียนทับspew.log.1.gzแต่ละครั้งยกเว้นว่าคุณเขียนสคริปต์สั้น ๆ เพื่อทำ gzip และย้ายไฟล์หลังจากนั้นและใช้-xคำสั่งนั้นเป็นคำสั่ง

การเปิดเผยข้อมูลเต็มรูปแบบ: ผมเขียนนี้จึงแน่นอนทำงานได้อย่างสมบูรณ์แบบ ;) ฉันจะจำตัวเลือกการบีบอัดไว้หรือสิ่งที่อำนวยความสะดวกได้ดีกว่าสำหรับเวอร์ชั่น 0.2 (วัตถุประสงค์ที่ตั้งใจไว้-xจะแตกต่างกันบ้าง แต่จะใช้งานได้ตามด้านบน) นอกจากนี้การวางเมาส์อัตโนมัติยังเป็นความคิดที่ดี ... รุ่นแรกนั้นมีความตั้งใจน้อยที่สุดเนื่องจากฉันต่อต้านการทดลองที่จะเพิ่มฟีเจอร์ที่ไม่จำเป็น

โปรดทราบว่ามันมีไว้สำหรับการส่งข้อความ ; หากมีค่า null ที่อาจเกิดขึ้นคุณควรใช้-z- ซึ่งจะแทนที่ค่าศูนย์ด้วยอย่างอื่น นี่เป็นการแลกเปลี่ยนเพื่อทำให้การใช้งานง่ายขึ้น


ขอบคุณ ฉันรอคอยที่จะpipelog-0.3;-) ฉันเจอกับmetacpan.org/release/File-Write-Rotateด้วย โปรดทราบว่างาน cron จะไม่ช่วยให้มากสำหรับการหมุนขึ้นอยู่กับขนาดไฟล์
Stéphane Chazelas

การหมุนขึ้นอยู่กับขนาด!?! มันจะให้ผลลัพธ์ล้างเพื่อให้คุณสามารถ stat ไฟล์ที่ช่วงเวลา ...
Goldilocks

คุณไม่สามารถรักษาขนาดให้ต่ำกว่า 20M (ตามที่ฉันต้องการ) ได้อย่างน่าเชื่อถือ
Stéphane Chazelas

อีกอย่างคือมันเป็นข้อความที่ค่อนข้างสวยเท่านั้น (ฉันเพิ่มย่อหน้าสุดท้ายเกี่ยวกับเรื่องนั้น)
goldilocks

4

Multilogของ Dan Bernstein สามารถทำสิ่งนี้ได้ - หรืออาจเป็นเรื่องส่วนใหญ่ในขณะเดียวกันก็มีทางออกผ่าน file descriptors ถึง! processorเพื่อสร้างความแตกต่างตามที่คุณต้องการ - ถึงแม้ว่าขนาดของ 20M / 1G นั้นอาจใช้เวลานานกว่าเดิม นอกขีด จำกัด ต่อบันทึก สิ่งที่ตามมาคือในส่วนใหญ่สำเนา + วางเลือกจากการเชื่อมโยงดังกล่าวข้างต้นแม้ว่าการเชื่อมโยงไปยังรายละเอียดตัวเลือกอื่น ๆ เช่น Timestamping ต่อบรรทัดรักษา [an] ไฟล์อื่น ๆ [s] ที่มีเพียงมากที่สุดการจับคู่สายที่ผ่านมารูปแบบและอื่น ๆ .

อินเตอร์เฟซ

 multilog script

... สคริปต์ประกอบด้วยอาร์กิวเมนต์จำนวนเท่าใดก็ได้ แต่ละอาร์กิวเมนต์ระบุหนึ่งการกระทำ การดำเนินการจะดำเนินการตามลำดับสำหรับอินพุตแต่ละบรรทัด

การเลือกเส้น

แต่ละบรรทัดจะถูกเลือกในขั้นต้น การกระทำ ...

-pattern

... ยกเลิกการเลือกบรรทัดหากรูปแบบตรงกับบรรทัด การกระทำ ...

+pattern

เลือกบรรทัดหากรูปแบบตรงกับบรรทัด

... patternเป็นชุดของดาวและไม่ใช่ดาว มันตรงกับการต่อกันของสตริงที่จับคู่โดยดาวทั้งหมดและไม่ใช่ดาวในลำดับเดียวกัน ดาวที่ไม่ตรงกับตัวเอง ดาวก่อนส่วนท้ายของรูปแบบจะจับคู่สตริงที่ไม่มีอักขระถัดไปในรูปแบบ ดาวที่ส่วนท้ายของรูปแบบตรงกับสตริงใด ๆ

บันทึกการหมุนโดยอัตโนมัติ

หากdirเริ่มต้นด้วยจุดหรือสแลชแล้วการกระทำ ...

 dir

... ผนวกบรรทัดที่เลือกแต่ละคนที่จะเข้าสู่ระบบการตั้งชื่อdir หากไม่มีdirให้multilogสร้างขึ้น

รูปแบบบันทึกมีดังนี้:

  1. dirเป็นไดเรกทอรีที่มีไฟล์บันทึกเก่าจำนวนหนึ่งไฟล์บันทึกชื่อปัจจุบันและไฟล์อื่น ๆmultilogเพื่อติดตามการดำเนินการ

  2. ไฟล์บันทึกเก่าแต่ละไฟล์มีชื่อขึ้นต้นด้วย@ดำเนินการต่อด้วยการประทับเวลาที่แม่นยำที่แสดงเมื่อไฟล์เสร็จสิ้นและลงท้ายด้วยหนึ่งในรหัสต่อไปนี้:

    • .s : ไฟล์นี้ได้รับการประมวลผลอย่างสมบูรณ์และเขียนลงดิสก์อย่างปลอดภัย
    • .u : ไฟล์นี้ถูกสร้างขึ้นในขณะที่ไฟดับ มันอาจถูกตัดทอน มันยังไม่ได้รับการประมวลผล

การกระทำ ...

 ssize

... กำหนดขนาดไฟล์สูงสุดสำหรับการกระทำdir ที่ตามมา multilogจะตัดสินว่ากระแสมีขนาดใหญ่พอถ้ากระแสมีขนาดเป็นไบต์ ( multilogจะตัดสินว่ากระแสนั้นมีขนาดใหญ่พอที่จะเห็นบรรทัดใหม่ภายใน 2,000 ไบต์ของขนาดไฟล์สูงสุดมันจะพยายามจบไฟล์บันทึกที่ขอบเขตของบรรทัด) ขนาดต้องอยู่ระหว่าง 4096 ถึง 16777215 ขนาดไฟล์สูงสุดเริ่มต้นคือ 99999

ในรุ่น 0.75 ขึ้นไป: หากmultilogได้รับสัญญาณALRMจะตัดสินทันทีว่ากระแสไฟฟ้ามีขนาดใหญ่พอหากกระแสไฟฟ้าไม่เพียงพอ

(หมายเหตุ: ฉันสงสัยว่าzsh schedulebuiltin สามารถโน้มน้าวใจได้อย่างง่ายดายเพื่อส่งALRMตามช่วงเวลาที่กำหนดหากจำเป็น)

การกระทำ ...

 nnum

... กำหนดจำนวนไฟล์บันทึกสำหรับการกระทำdir ที่ตามมา หลังจากเปลี่ยนชื่อปัจจุบันถ้าmultilogเห็นNUMหรือไฟล์บันทึกเก่ามากขึ้นก็เอาแฟ้มบันทึกเก่าที่มีการประทับเวลาที่น้อยที่สุด NUMต้องมีอย่างน้อย 2 หมายเลขเริ่มต้นของแฟ้มบันทึกคือ 10

การกระทำ ...

 !processor

... ตั้งค่าตัวประมวลผลสำหรับการกระทำdir ที่ตามมา multilogจะเลี้ยงในปัจจุบันผ่านการประมวลผลและบันทึกการส่งออกเป็นไฟล์บันทึกเก่าแทนปัจจุบัน multilogจะบันทึกเอาต์พุตใด ๆ ที่ตัวประมวลผลเขียนไปยัง descriptor 5 และทำให้เอาต์พุตนั้นสามารถอ่านได้บน descriptor 4 เมื่อรันตัวประมวลผลในไฟล์บันทึกถัดไป เพื่อความน่าเชื่อถือโปรเซสเซอร์ต้องออกจากศูนย์ถ้ามีปัญหาในการสร้างผลลัพธ์ multilogจะเรียกใช้อีกครั้ง โปรดทราบว่าการทำงานประมวลผลอาจปิดกั้นการป้อนโปรแกรมการให้อาหารใด ๆ multilogที่จะ


2

สิ่งที่ดีที่สุดที่ฉันสามารถพบได้ในขณะที่การประมาณที่ไม่เกี่ยวข้องกับการเขียนโค้ดขนาดใหญ่ก็คือ zshโค้ด :

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

นี่คือการแยกและหมุนเป็นไฟล์ขนาดใหญ่ที่สุดที่ 20MiB 51


บางที ... loopmounts? นอกจากนี้ยังสามารถติดตั้งได้กับbtrfs compress-force=zlib
mikeserv

2

นี่คือสคริปต์ python ที่แฮ็กขึ้นเพื่อทำสิ่งที่คุณต้องการ:

#!/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
มีเหตุผลที่จะให้มันเป็นเชลล์สคริปต์ที่execไพ ธ อนเป็นสิ่งแรกแทนที่จะใช้pythonหรือenv pythonhashbang?
เตอร์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.