monitorar arquivos (à cauda -f) em um diretório inteiro (até mesmo novos)


53

Eu normalmente assisto muitos logs em um diretório fazendo tail -f directory/*. O problema é que um novo log é criado depois disso, não será exibido na tela (porque *já foi expandido).

Existe uma maneira de monitorar todos os arquivos em um diretório, mesmo aqueles criados após o início do processo?

Respostas:


44

Você pode ajustar vários arquivos com… multitail .

multitail -Q 1 'directory/*'

-Q 1 PATTERNsignifica verificar se há novo conteúdo em arquivos existentes ou novos que correspondem a PATTERN a cada 1 segundo. Linhas de todos os arquivos são mostradas na mesma janela, use em -qvez de -Qter janelas separadas.


10

xtailtambém é uma alternativa. Sua página do manual descreve como:

O Xtail monitora um ou mais arquivos e exibe todos os dados gravados em um arquivo desde a chamada do comando. É muito útil para monitorar vários arquivos de log simultaneamente. Se uma entrada fornecida na linha de comando for um diretório, todos os arquivos nesse diretório serão monitorados, incluindo aqueles criados após a chamada do xtail. Se uma entrada fornecida na linha de comando não existir, o xtail prestará atenção e monitorará uma vez criada. Ao alternar arquivos no visor, um banner mostrando o nome do caminho do arquivo é impresso.

Um caractere de interrupção (geralmente CTRL / C ou DEL) exibirá uma lista dos arquivos modificados mais recentes que estão sendo monitorados. Envie um sinal de encerramento (geralmente CTRL / barra invertida) para interromper o xtail.


11
Link é quebrado, mas eu acho que é o mesmo que: manpages.ubuntu.com/manpages/zesty/man1/xtail.1.html
edpaez

7

Nenhuma idéia sobre uma solução shell, mas (assumindo o Linux 1) inotifypoderia ser o caminho a seguir ... veja este exemplo imitandotail -F (usando pyinotify), talvez ele possa ser usado como base para seguir um diretório inteiro .

Em geral, inotifypode monitorar diretórios (citando man 7 inotify)

Os seguintes bits podem ser especificados na máscara ao chamar inotify_add_watch (2) e podem ser retornados no campo da máscara retornado por read (2):

IN_ACCESS         File was accessed (read) (*).
IN_ATTRIB         Metadata changed, e.g., permissions, timestamps,
                    extended attributes, link count (since Linux 2.6.25),
                    UID, GID, etc. (*).
IN_CLOSE_WRITE    File opened for writing was closed (*).
IN_CLOSE_NOWRITE  File not opened for writing was closed (*).
IN_CREATE         File/directory created in watched directory (*).
IN_DELETE         File/directory deleted from watched directory (*).
IN_DELETE_SELF    Watched file/directory was itself deleted.
IN_MODIFY         File was modified (*).
IN_MOVE_SELF      Watched file/directory was itself moved.
IN_MOVED_FROM     File moved out of watched directory (*).
IN_MOVED_TO       File moved into watched directory (*).
IN_OPEN           File was opened (*).

Ao monitorar um diretório , os eventos marcados com um asterisco (*) acima podem ocorrer para arquivos no diretório; nesse caso, o campo de nome na estrutura inotify_event retornada identifica o nome do arquivo no diretório.

(... e pyinotifysegue de perto essas opções)

1: BSDs têm uma coisa semelhante kqueue,. Talvez uma solução de plataforma cruzada é alcançável usando GIO ( ligações Python ) como camada de abstracção, uma vez que pode, ao lado inotify, também utilizarkqueue


2

Escrevi uma rápida que atende à necessidade.

#!/bin/bash
LOG_PATTERN=$1
BASE_DIR=$(dirname $LOG_PATTERN* | head -1)

run_thread (){
    echo Running thread
    tail -F $LOG_PATTERN* &
    THREAD_PID=$!
}

# When someone decides to stop the script - killall children
cleanup () {
    pgrep -P $$ | xargs -i kill {}
    exit
}

trap cleanup SIGHUP SIGINT SIGTERM

if [ $# -ne 1 ]; then
    echo "usage: $0 <directory/pattern without * in the end>"
    exit 1
fi

# Wait for the directory to be created
if [ ! -d $BASE_DIR ] ; then
    echo DIR $BASE_DIR does not exist, waiting for it...
    while [ ! -d $BASE_DIR ] ; do
        sleep 2
    done
    echo DIR $BASE_DIR is now online
fi

# count current number of files
OLD_NUM_OF_FILES=$(ls -l $LOG_PATTERN* 2>/dev/null | wc -l)

# Start Tailing
run_thread

while [ 1 ]; do
    # If files are added - retail
    NUM_FILES=$(ls -l $LOG_PATTERN* 2>/dev/null | wc -l)
    if [ $NUM_FILES -ne $OLD_NUM_OF_FILES ]; then
        OLD_NUM_OF_FILES=$NUM_FILES
        kill $THREAD_PID
        run_thread
    fi
    sleep 1
done

11
Na verdade, você pode omitir o sono 1 no loop principal, será mais ágil para obter novos arquivos. Mas eu não gosto desse tipo de ocupado espera
Itamar

Devido a sleepisso, não é uma espera ocupada, mas suave na CPU, apenas na pesquisa. Pode-se alterá-lo para sleep 0.2s(suspensão GNU) ou o que for, para torná-lo mais rápido, se necessário.
Ned64 4/10

2

Além disso, você pode assistir ao diretório com watch

watch -n0,1 "ls -lrt /directory/ | tail"

Nitpick menor: watchredesenha a tela no buffer alternativo, com as primeiras x linhas de saída do comando. Em vários arquivos sem alterações, se os arquivos anteriores não forem alterados, eles tailpoderão render a mesma coisa a cada vez, para que você não apareça entradas adicionais, pois elas são desenhadas em arquivos posteriores 'abaixo' da parte inferior do tela. Para um arquivo curto, porém, isso é bom ...
jimbobmcgee

Isso não dá uma solução para o problema original. Isso apenas gera (as últimas linhas de) uma lista de diretórios (repetidamente, sempre atual - graças a watch), em vez das últimas linhas de todos os arquivos (incluindo os novos) nesse diretório.
trs
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.