Jak ograniczyć rozmiar pliku dziennika za pomocą >>

24

Jak mogę ograniczyć rozmiar zapisanego pliku dziennika >>do 200 MB?

$ run_program >> myprogram.log
David
źródło
1
Czy chcesz zabić program po 200 MB? A może chcesz ostatnie 200 MB ze wszystkim starszym w segmencie bitów?
Aaron D. Marasco,
nie, proces nie może się zatrzymać, dopóki nie zostanie ręcznie zabity
David
Postanowiłem pójść na Logrotate, dziękuję wszystkim za cenne wkłady
David

Odpowiedzi:

9

Jeśli twoja aplikacja (tj. run_program) Nie obsługuje ograniczania rozmiaru pliku dziennika, możesz okresowo sprawdzać rozmiar pliku w pętli za pomocą zewnętrznej aplikacji lub skryptu.

Możesz także użyć logrotate(8)do obracania dzienników, ma sizeparametr, którego możesz użyć do swoich celów:

Dzięki temu plik dziennika jest obracany po osiągnięciu określonego rozmiaru. Rozmiar można określić w bajtach (domyślnie), kilobajtach (sizek) lub megabajtach (sizem).

Emre Yazici
źródło
1
+1 Pliki logów z powtarzającymi się informacjami często mogą zostać skompresowane w rzędach wielkości.
użytkownik nieznany
Czy logrotate obcina pliki, czy po prostu kopiuje je lub przenosi? Ponieważ zadziała to tylko wtedy, gdy plik powiązany z fd zostanie obcięty. Jeśli jest to plik mv'd, plik będzie się powiększał, jeśli zostanie odłączony, pozostanie otwarty i będzie się rozwijał aż do zakończenia procesu ... IIRC logrotuje kopie, odłącza i tworzy nowy plik, dlatego często trzeba wysyłać SIGHUP do dæmons, gdy ich dzienniki zostały obrócone.
Michael Trausch
Zauważ, że nawet jeśli jest on obcięty, istnieje problem, jeśli plik nie został otwarty w trybie dołączania (pliki dziennika powinny zawsze być otwierane w trybie dołączania, ale z mojego doświadczenia często tak nie jest)
Random832
Logrotate może się obracać, gdy plik osiągnie określony rozmiar, codziennie, co tydzień itp. Może również kompresować, a także możesz użyć postscriptopcji, aby konfiguracja logrotate została wysłana SIGHUPdo programu.
laebshade
12

Jeśli twój program nie musi zapisywać INNYCH plików, które byłyby większe niż ten limit, możesz poinformować jądro o tym limicie za pomocą ulimit. Przed uruchomieniem polecenia uruchom to, aby ustawić limit wielkości pliku 200 MB dla wszystkich procesów uruchomionych w bieżącej sesji powłoki:

ulimit -f $((200*1024))

To ochroni twój system, ale może być niebezpieczne dla programu zapisującego plik. Jak sugeruje eyazici , rozważ skonfigurowanie logrotateplików dziennika do przycinania, gdy osiągną określony rozmiar lub wiek. Możesz odrzucić stare dane lub zarchiwizować je na pewien czas w szeregu skompresowanych plików.

Caleb
źródło
ogranicza to rozmiar każdego pliku zapisanego przez program
Kim
Prawdziwe. Jeśli program miał uzasadnioną potrzebę napisania innych dużych plików, potrzebne byłoby inne rozwiązanie.
Caleb
6

Możesz utworzyć nowy obraz systemu plików, zamontować go za pomocą urządzenia pętli i umieścić plik dziennika w tym systemie plików:

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

Możesz również użyć tmpfszamiast pliku, jeśli masz wystarczającą ilość pamięci.

alex
źródło
Kreatywny pomysł ... który pozostawia programowi, co zrobić, gdy się skończy.
Aaron D. Marasco,
6

Możesz obciąć dane wyjściowe za pomocą head:

size=$((200*1024*1024-$(stat -c %s myprogram.log)))
run_program | head -c ${size} >> myprogram.log
smoking
źródło
Bardzo kreatywne. Tylko uwaga, że ​​zadziałałoby to tylko w celu ograniczenia NOWYCH danych zapisywanych do pliku, nie wziąłby pod uwagę, jak duży lub mały był już plik.
Caleb
2
Należy pamiętać, że prawdopodobnie spowoduje to zabicie programu (za pomocą SIGPIPE) po osiągnięciu limitu rozmiaru, zamiast odrzucania danych.
Random832
1
Myślałem podobnie z pewną ddmagią, ale tak @ Random832 ma rację, dostaniesz SIGPIPEas head/ dd/ whateverupuszcza.
Aaron D. Marasco,
A co z ignorowaniem go za pomocą trap '' SIGPIPE?
smoking
Lub zamiast tego potokuj { head -c "$size" >> log; cat > /dev/null; }.
Stéphane Chazelas
5

W pakiecie apache2-utilsznajduje się narzędzie o nazwie rotatelogs, może być dla Ciebie pomocne.

Streszczenie:

rotatelogs [-l] [-L linkname ] [-p program ] [-f] [-t] [-v] [-e] [-c] [-n liczba plików ] czas rotacji pliku dziennika | rozmiar pliku (B | K | M | G) [ offset ]

Przykład:

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

Pełny podręcznik można przeczytać pod tym linkiem .

PRIHLOP
źródło
Link nie istnieje.
Alexander Gonchiy,
1

Jestem pewien, że oryginalny plakat znalazł rozwiązanie. Oto kolejny dla innych, którzy mogą przeczytać ten wątek ...

Curtail ogranicza rozmiar danych wyjściowych programu i zachowuje ostatnie 200 MB danych wyjściowych za pomocą następującego polecenia:

$ run_program | curtail -s 200M myprogram.log

Referencje

UWAGA: Jestem opiekunem powyższego repozytorium. Po prostu udostępniam rozwiązanie ...

Dave Wolaver
źródło
Podoba mi się pomysł ograniczenia. Nie znam się tak dobrze na C, więc czy jest szansa na dostarczenie pliku binarnego? lub przynajmniej szczegółowe instrukcje, jak to zainstalować?
Felipe
0

Ponieważ jest to tekst, napisałbym skrypt w twoim ulubionym języku i dopasowałem go do tego. Niech poradzi sobie z plikiem I / O (lub zachowa to wszystko w pamięci, a następnie zrzuci na SIGHUPlub podobne). W tym celu zamiast 200 MB pomyślałbym o „rozsądnej” liczbie wierszy do śledzenia.

Aaron D. Marasco
źródło
Przechowywanie 200 MB danych dziennika w pamięci bez żadnego innego powodu niż możliwość obcięcia nie jest zbyt dobrym wykorzystaniem zasobów systemowych. Nie robi też liczenia linii na dużym pliku dziennika. Polecam korzystanie z narzędzi zbudowanych w tym celu, takich jak syslogi logrotate.
Caleb,
0

Poniższy skrypt powinien wykonać zadanie.

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

Ma kilka oczywistych skrótów, ale ogólnie robi to, o co prosiłeś. Podzielą dziennik na kawałki o ograniczonym rozmiarze, a ilość kawałków jest również ograniczona. Wszystkie można określić za pomocą argumentów wiersza polecenia. Plik dziennika jest również określany za pomocą wiersza polecenia.

Zwróć uwagę na małą gotcha, jeśli używasz jej z demonem, który rozwidla się w tle. Użycie potoku uniemożliwi przejście demona w tło. W tym przypadku istnieje składnia (prawdopodobnie specyficzna dla bash), aby uniknąć problemu:

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

Zwróć uwagę, że <&0choć pozornie zbędne, nie będzie działać bez tego.

stsp
źródło