Pular para conteúdo

log-sqlite: Módulo de logger SQLite para NGINX

Instalação

Você pode instalar este módulo em qualquer distribuição baseada em RHEL, incluindo, mas não se limitando a:

  • RedHat Enterprise Linux 7, 8, 9 e 10
  • CentOS 7, 8, 9
  • AlmaLinux 8, 9
  • Rocky Linux 8, 9
  • Amazon Linux 2 e Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-log-sqlite
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-log-sqlite

Ative o módulo adicionando o seguinte no topo de /etc/nginx/nginx.conf:

load_module modules/ngx_http_sqlitelog_module.so;

Este documento descreve o nginx-module-log-sqlite v0.0.1 lançado em 14 de fevereiro de 2025.


Resumo

Este módulo utiliza o formato SQLite para logs de acesso. Fork do GitHub de https://git.serope.com/me/ngx-sqlitelog

Diretivas

sqlitelog

  • Sintaxe: sqlitelog caminho [formato] [buffer=tamanho [max=n] [flush=tempo]] [init=script] [if=condição] | off
  • Padrão: sqlitelog off
  • Contexto: http, server

Esta diretiva define um banco de dados de logging.

O parâmetro caminho é o caminho do arquivo do banco de dados. Ele deve estar localizado em um diretório onde o usuário ou grupo que possui os processos de trabalho do Nginx (definido pela diretiva user) tenha permissão de escrita para que possa criar o arquivo do banco de dados e quaisquer possíveis arquivos temporários.

O parâmetro formato é o nome de um formato de log definido pela diretiva sqlitelog_format. Se não for fornecido, o formato combinado padrão é utilizado.

O parâmetro buffer cria uma zona de memória onde as entradas de log são agrupadas e escritas no banco de dados em uma única transação BEGIN ... COMMIT. Isso melhora muito o desempenho, pois inserções agrupadas são mais rápidas do que as separadas. O buffer é comprometido quando uma das seguintes condições ocorre: seu tamanho é excedido; acumula n entradas de log; o tempo de flush expira; o Nginx é recarregado ou sai.

O parâmetro init é um caminho para um arquivo de script SQL que é executado em cada conexão ao banco de dados. Isso pode ser usado para executar comandos pragma ou para criar tabelas, visões e gatilhos adicionais para complementar a tabela de logging; tais instruções devem incluir IF NOT EXISTS, pois podem ser executadas mais de uma vez.

O parâmetro if define uma condição de logging. Assim como no padrão módulo de log, se condição avaliar para 0 ou uma string vazia, o logging é ignorado para a requisição atual.

sqlitelog_format

  • Sintaxe: sqlitelog_format tabela var1 [tipo1] var2 [tipo2] ... varN [tipoN]
  • Padrão: sqlitelog_format combined $remote_addr $remote_user $time_local $request $status $body_bytes_sent $http_referer $http_user_agent
  • Contexto: http

Esta diretiva define uma tabela de logging.

O primeiro argumento é o nome da tabela. Os argumentos restantes são variáveis com tipos de coluna opcionais. Algumas variáveis têm tipos de coluna predefinidos, caso contrário, o padrão é TEXT. Se uma variável for do tipo BLOB, seu valor é escrito como bytes não escapados.

sqlitelog_async

  • Sintaxe: sqlitelog_async pool | on | off
  • Padrão: sqlitelog_async off
  • Contexto: http

Esta diretiva habilita um pool de threads, permitindo que as gravações de arquivos SQLite ocorram sem bloqueio. O argumento pode ser um nome de pool existente, on para o pool padrão, ou off. Esta diretiva só está disponível se o Nginx for compilado com --with-threads.

Erros

Quando um erro SQLite ocorre, o módulo é desativado (equivalente a sqlitelog off) para o processo de trabalho que encontrou o erro. Isso é para evitar que o error.log seja rapidamente inundado com mensagens de erro se o banco de dados for inutilizável (por exemplo, localizado em um diretório onde os processos de trabalho não têm permissão de escrita).

  • SQLITE_ERROR (1): Este é um código de erro genérico que cobre vários casos, como erros de sintaxe SQL em um script init.
  • SQLITE_BUSY (5): Vários processos de trabalho tentaram usar o banco de dados simultaneamente e excederam o tempo limite de ocupado (1000 ms por padrão). Isso pode ser resolvido criando um buffer para acelerar as inserções ou definindo um tempo limite mais longo com PRAGMA busy_timeout em um script init.
  • SQLITE_READONLY (8): O Nginx pode abrir o banco de dados, mas não pode escrever nele. Isso é provavelmente devido a permissões de arquivo.
  • SQLITE_CANTOPEN (14): O Nginx não pode abrir ou criar o banco de dados. Isso é provavelmente devido a permissões de diretório. O usuário ou grupo que possui os processos de trabalho (definido pela diretiva user) deve ter permissão de escrita no diretório.
  • SQLITE_READONLY_DBMOVED (1032): O arquivo foi movido, renomeado ou excluído em tempo de execução. Quando isso acontece, o Nginx tenta recriar o arquivo; se for bem-sucedido, o erro é ignorado e o logging continua normalmente.

Uso

Localizações

A diretiva sqlitelog não pode ser usada em contextos de localização, mas uma condição regex pode alcançar um efeito semelhante. Neste exemplo, apenas requisições que começam com "/mylocation" são registradas.

map $request_uri $is_my_loc {
    default            0;
    ~^/mylocation.*$   1;
}

sqlitelog access.db if=$is_my_loc;

Herdabilidade

Apenas um sqlitelog é permitido por contexto, com contextos inferiores tendo prioridade. Neste exemplo, requisições para o servidor A são registradas em global.db, enquanto requisições para o servidor B são registradas em b.db.

http {
    sqlitelog global.db;
    ...

    server {
        server_name a;
        ...
    }

    server {
        server_name b;
        sqlitelog b.db;
        ....
    }

Modo WAL

O modo WAL é habilitado por PRAGMA journal_mode=wal em um script init. O checkpointing WAL ocorre quando o Nginx é recarregado ou sai.

Logrotate

O Logrotate deve ser configurado para parar o Nginx, rotacionar logs e iniciar o Nginx novamente. Dessa forma, o Nginx fecha graciosamente suas conexões com o(s) banco(s) de dados do dia anterior e abre novas conexões com o(s) banco(s) de dados do dia atual.

Abaixo está um exemplo de script para Debian (/etc/logrotate.d/nginx). Ele assume que o usuário do processo de trabalho, www-data, recebeu permissão de escrita em /var/log/nginx, que normalmente só é gravável por root.

/var/log/nginx/*.log
/var/log/nginx/*.db
{
    daily
    missingok
    rotate 52
    compress
    delaycompress
    notifempty
    create 640 www-data adm
    sharedscripts

    # Forçar o Logrotate a funcionar neste diretório, mesmo que
    # suas permissões tenham sido modificadas para permitir que um
    # usuário não-root escreva nele
    su root adm

    # Enviar um sinal de quit para o Nginx e esperar que seu arquivo PID
    # seja destruído
    firstaction
        systemctl stop nginx.service
        while [ -f /var/run/nginx.pid ]; do  
            sleep 0.1s
        done
    endscript

    # Iniciar o Nginx novamente
    lastaction
        systemctl restart nginx.service
    endscript
}

Tipos de coluna

As seguintes variáveis têm tipos de coluna predefinidos, mas podem ser substituídos se necessário.

Variável Tipo
$binary_remote_addr BLOB
$body_bytes_sent INTEGER
$bytes_sent INTEGER
$connection INTEGER
$connection_requests INTEGER
$connection_time REAL
$connections_active INTEGER
$connections_reading INTEGER
$connections_waiting INTEGER
$connections_writing INTEGER
$content_length INTEGER
$gzip_ratio REAL
$limit_rate INTEGER
$msec REAL
$pid INTEGER
$proxy_port INTEGER
$proxy_protocol_port INTEGER
$proxy_protocol_server_port INTEGER
$remote_port INTEGER
$request_time REAL
$server_port INTEGER
$status INTEGER

GitHub

Você pode encontrar dicas adicionais de configuração e documentação para este módulo no repositório do GitHub para nginx-module-log-sqlite.