AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / server / Perguntas / 959320
Accepted
x-yuri
x-yuri
Asked: 2019-03-22 06:14:57 +0800 CST2019-03-22 06:14:57 +0800 CST 2019-03-22 06:14:57 +0800 CST

Rotações de registro ausentes

  • 772

Um dos meus servidores ficou sem espaço recentemente. Então comecei a pesquisar sobre isso. Os nginxlogs ocuparam metade da partição. Além disso, notei uma coisa estranha. Para muitos sites (60%) rotações extras quando presentes ( example.com-access.log.53.gzquando rotate 52). E a maioria dos maiores - mas não todos - tinha apenas duas rotações:

example.com-access.log
example.com-access.log.53.gz

50% das toras tinham apenas essas duas rotações. Às vezes havia apenas buracos nas rotações (30%): uma lima ou mais. *.log.1muitas vezes faltava (25%). Às vezes havia ambos *.log.1e *.log.1.gz(2 de 172).

Você pode explicar essas rotações ausentes/duplicadas? *.log+ *.log.53.gzcase me faz pensar que em algum momento não foi possível girar *.log.1para *.log.2.gz. Mas não iria parar depois de mal sucedida gzip? Então não deve haver buracos. Ou pelo menos deve estar *.log.1presente se não estiver, não deve?

Estou executando o servidor Debian, se alguma coisa.

/etc/logrotate.conf:

# see "man logrotate" for details
# rotate log files weekly
weekly

# keep 4 weeks worth of backlogs
rotate 4

# create new (empty) log files after rotating old ones
create

# uncomment this if you want your log files compressed
#compress

# packages drop log rotation information into this directory
include /etc/logrotate.d

# no packages own wtmp, or btmp -- we'll rotate them here
/var/log/wtmp {
    missingok
    monthly
    create 0664 root utmp
    rotate 1
}

/var/log/btmp {
    missingok
    monthly
    create 0660 root utmp
    rotate 1
}

# system-specific logs may be configured here

/etc/logrotate.d/nginx:

/var/log/nginx/*.log {
    weekly
    missingok
    rotate 52
    compress
    delaycompress
    notifempty
    create 0640 www-data adm
    size 50M
    sharedscripts
    prerotate
        if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
            run-parts /etc/logrotate.d/httpd-prerotate; \
        fi \
    endscript
    postrotate
        [ -s /run/nginx.pid ] && kill -USR1 `cat /run/nginx.pid`
    endscript
}

/etc/logrotate.d/httpd-prerotatenão existe.

linux
  • 1 1 respostas
  • 1320 Views

1 respostas

  • Voted
  1. Best Answer
    x-yuri
    2019-03-22T16:03:36+08:002019-03-22T16:03:36+08:00

    tl;dr Duplicatas podem ser produzidas se a compressão ( gzip) foi interrompida. Uma dessas duplicatas (if sharedscripts) faz com que eventualmente deixe apenas uma rotação gzipada (# rotate + 1).

    Aqui está uma versão simplificada do que está acontecendo nos bastidores (logset é uma entrada /path/to/dir/*.log {...}na configuração):

    for (let logSet of logSets) {
        rotateLogSet(logSet);
    }
    
    function rotateLogSet(logSet) {
        const logHasErrors = [];
        let hasErrors = false;
        for (let i = 0; i < logSet.files().length; i++) {
            findNeedRotating(log, i);
        }
        const jn = logSet['sharedscripts']
            ? 1
            : logSet.files().length;
        for (let j = 0; j < jn; j++) {
            const in = logSet['sharedscripts'] ? logSet.files().length : j + 1;
            for (let i = j; i < in; i++) {
                logHasErrors[i] ||= ! prerotateSingleLog(logSet, i);
                hasErrors ||= logHasErrors[i];
            }
            if (logSet['prerotate']
                && ( ! (
                    logSet['sharedscripts'] ? hasErrors : logHasErrors[j]
                ))
            ) {
                if ( ! runScriptMultiple(logSet['prerotate']))
                    logHasErrors[j] = hasErrors = true;
            }
            for (let i = j; i < in; i++) {
                if ( ! (
                    logSet['sharedscripts'] ? hasErrors : logHasErrors[i]
                ))
                    logHasErrors[i] ||= ! rotateSingleLog(logSet, i);
                    hasErrors ||= logHasErrors[i];
            }
            if (logSet['postrotate']
                && ( ! (
                    logSet['sharedscripts'] ? hasErrors : logHasErrors[j]
                ))
            ) {
                if ( ! runScriptMultiple(logSet['postrotate']))
                    logHasErrors[j] = hasErrors = true;
            }
            for (let i = j; i < in; i++) {
                if ( ! (
                    logSet['sharedscripts'] ? hasErrors : logHasErrors[i]
                ))
                    logHasErrors[i] ||= ! postrotateSingleLog(logSet, i);
                    hasErrors ||= logHasErrors[i];
            }
        }
    }
    
    function findNeedRotating(logSet, i) {
        const log = logSet.files()[i];
        if ( ! stat(log))
            return logSet['missingok'] && errno == ENOENT;
        log.doRotate = ...;
        return ...;
    }
    
    function prerotateSingleLog(logSet, i) {
        let hasErrors = false;
        const log = logSet.files()[i];
        if ( ! log.doRotate)
            return;
        if (stat(log))
            hasErrors = compressLogFile(log);
        for (let i = logSet['rotate']; i >= 0 && ! hasErrors; i--) {
            if ( ! rename(`${log}.${i}.gz`, `${log}.${i + 1}.gz`))
                if (errno != ENOENT)
                    hasErrors = true;
        }
        return ! hasErrors;
    }
    
    function rotateSingleLog(logSet, i) {
        let hasErrors = false;
        const log = logSet.files()[i];
        if ( ! log.doRotate)
            return;
        if ( ! rename(log, `${log}.1`))
            hasErrors = true;
        if ( ! hasErrors && logSet['create'])
            if ( ! createOutputFile(log))
                hasErrors = true;
        return ! hasErrors;
    }
    
    function postrotateSingleLog(logSet, i) {
        const log = logSet.files()[i];
        if ( ! log.doRotate)
            return;
        rm(`${log}.${logSet['rotate'] + 1}.gz`);
    }
    

    Assim, sharedscriptsnormalmente com um erro, que ocorre ao manipular um arquivo de log pertencente a um conjunto de logs, interrompe o processamento de todo o conjunto de logs. Sem ele, o processamento de apenas um arquivo de log é interrompido.

    Mas a rotação gzipada inexistente ou a 1ª rotação de um arquivo de log não conta como um erro. Como não acontece quando o próprio arquivo de log não existe se missingok(não importa no caso de um padrão). Também um erro durante prerotateSingleLog()a fase com sharedscriptsnão quebra o loop.

    Observe que fiz muitas simplificações ao compilar o código acima. Consulte o original em caso de dúvida.

    Com isso , os únicos casos em que posso ver onde pode haver arquivos ausentes ou extras é quando logrotateé interrompido. Isso pode explicar as rotate + 1rotações (rotações gzipadas foram renomeadas, mas a última não foi removida). Além disso, quando gzip é interrompido, deixa o arquivo de destino para trás. Isso explica ter ambos *.log.1e *.log.1.gzrotações. Ainda sem explicação para os buracos nas rotações.

    UPD Parece que duplicatas ( *.log.1+ *.log.1.gz) produzem um erro :

    erro: erro ao criar arquivo de saída /var/log/nginx/example.com-access.log.1.gz: O arquivo existe

    Isso interrompe o processamento após a prerotateSingleLog()fase. Nesse ponto, todas as rotações compactadas com gzip foram renomeadas. Mas renomear *.log -> *.log.1e remover *.log.${rotate + 1}.gzsão ignorados. *.logcrescem cada vez mais e, eventualmente, você fica sem espaço.

    Isso explica tudo, exceto *.log.1rotações ausentes. Mas provavelmente é tão bom quanto ele ganha.

    Portanto, cuidado com os erros na rotação de logs. Você pode identificar o problema identificando a linha "error:" na logrotatesaída (mesmo não detalhada).


    Como bônus, um script que exibe o conteúdo de um diretório de log de maneira agradável (classificação natural, com tamanhos):

    #!/usr/bin/env bash
    set -eu
    for l in /var/log/nginx/*.log; do
        du -bs "$l"* \
            | sed -E 's/(.*\.([0-9]+)(\.gz)?)$/\2 \1/; t a; s/^/0 /; :a' \
            | sort -nk1 \
            | awk '{sub(/.*\//, "", $3); printf("%12s %s\n", $2, $3)}'
    done
    

    E outro que permite verificar se você tem os problemas que encontrei:

    #!/usr/bin/env bash
    set -eu
    
    dir=/var/log/nginx
    
    i=0
    n_0_53=0
    n_53=0
    n_holes=0
    n_missing_1=0
    for f in `ls "$dir"/*.log`; do
        f=`basename -- "$f"`
        echo -- $f
        rotations=$(ls "$dir/$f"* \
            | sed -E 's/(.*\.([0-9]+)(\.gz)?)$/\2 \1/; t a; s/^/0 /; :a' \
            | sort -nk1 \
            | awk '{print $1}')
    
        duplicates=$(echo "$rotations" | uniq -c | awk '$1 != 1 {print $2}')
        if [ "$duplicates" ]; then
            echo duplicates: $duplicates
        fi
    
        if [ "$rotations" = $'0\n53' ]; then
            echo 0, 53
            (( n_0_53 += 1))
        else
            missing=
            last=$(echo "$rotations" | tail -n 1)
            for (( j = 0; j <= $last; j++ )); do
                if ! [[ "$rotations" =~ (^|$'\n')"$j"($'\n'|$) ]]; then
                    missing="$missing $j"
                fi
            done
            if [ "$missing" ]; then
                echo missing: $missing
                (( n_holes += 1 ))
            fi
            if [ "$missing" = ' 1' ]; then
                (( n_missing_1 += 1 ))
            fi
        fi
        if [[ "$rotations" =~ (^|$'\n')53($'\n'|$) ]]; then
            (( n_53 += 1 ))
        fi
        (( i += 1 ))
    done
    printf 'n_0_53: %s %s\n' "$n_0_53" "$(echo "$n_0_53 * 100 / $i" | bc)"
    printf 'n_53: %s %s\n' "$n_53" "$(echo "$n_53* 100  / $i" | bc)"
    printf 'n_holes: %s %s\n' "$n_holes" "$(echo "$n_holes * 100 / $i" | bc)"
    printf 'n_missing_1: %s %s\n' "$n_missing_1" "$(echo "$n_missing_1 * 100 / $i" | bc)"
    printf 'total: %s\n' "$i"
    
    • 1

relate perguntas

  • Como descobrir detalhes sobre hardware na máquina Linux?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Você pode passar usuário/passar para autenticação básica HTTP em parâmetros de URL?

    • 5 respostas
  • Marko Smith

    Ping uma porta específica

    • 18 respostas
  • Marko Smith

    Verifique se a porta está aberta ou fechada em um servidor Linux?

    • 7 respostas
  • Marko Smith

    Como automatizar o login SSH com senha?

    • 10 respostas
  • Marko Smith

    Como posso dizer ao Git para Windows onde encontrar minha chave RSA privada?

    • 30 respostas
  • Marko Smith

    Qual é o nome de usuário/senha de superusuário padrão para postgres após uma nova instalação?

    • 5 respostas
  • Marko Smith

    Qual porta o SFTP usa?

    • 6 respostas
  • Marko Smith

    Linha de comando para listar usuários em um grupo do Windows Active Directory?

    • 9 respostas
  • Marko Smith

    O que é um arquivo Pem e como ele difere de outros formatos de arquivo de chave gerada pelo OpenSSL?

    • 3 respostas
  • Marko Smith

    Como determinar se uma variável bash está vazia?

    • 15 respostas
  • Martin Hope
    Davie Ping uma porta específica 2009-10-09 01:57:50 +0800 CST
  • Martin Hope
    kernel O scp pode copiar diretórios recursivamente? 2011-04-29 20:24:45 +0800 CST
  • Martin Hope
    Robert ssh retorna "Proprietário incorreto ou permissões em ~/.ssh/config" 2011-03-30 10:15:48 +0800 CST
  • Martin Hope
    Eonil Como automatizar o login SSH com senha? 2011-03-02 03:07:12 +0800 CST
  • Martin Hope
    gunwin Como lidar com um servidor comprometido? 2011-01-03 13:31:27 +0800 CST
  • Martin Hope
    Tom Feiner Como posso classificar a saída du -h por tamanho 2009-02-26 05:42:42 +0800 CST
  • Martin Hope
    Noah Goodrich O que é um arquivo Pem e como ele difere de outros formatos de arquivo de chave gerada pelo OpenSSL? 2009-05-19 18:24:42 +0800 CST
  • Martin Hope
    Brent Como determinar se uma variável bash está vazia? 2009-05-13 09:54:48 +0800 CST

Hot tag

linux nginx windows networking ubuntu domain-name-system amazon-web-services active-directory apache-2.4 ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve