LINUX.ORG.RU
ФорумAdmin

Выделить access логи от одного ip в отдельный файл в nginx

 , , ,


2

1

Есть nginx.x86_64 1:1.14.1-9.0.1.module+el8.0.0+5347+9282027e Основной конфиг по умолчанию. Для веб сервера заведен отдельный файл с конфигом в /etc/nginx/conf.d/ со следующим содержимым:

upstream websrv{ 
    ip_hash;
    server 127.0.0.1:8002;
}
server {.
    listen 80; server_name wserv.domain;
    # Перенаправление на HTTPS
    location / { return 301 https://$server_name$request_uri;
    }
}
server {
    listen 443 ssl; server_name wserv.domain;
    # Путь к сертификату и ключу
    ssl_certificate /etc/nginx/ssl/wserv.crt;
    ssl_certificate_key /etc/nginx/ssl/wserv.key;

    access_log /var/log/nginx/access.log main;
    error_log /var/log/nginx/error.log main;
...
}

С одного IP адреса идет большое количество запросов и хотелось бы access_log с него выделить в отдельный файл. В этом случае основной файл access_log был бы существенно меньше и было бы намного проще его анализировать.

В интернете находил варианты с geo и map, но при одном варианте лог файлы вообще не создаются, в других паралельно записываются в два файла все логи. Прошу подсказать как решить такую задачу.

Прмеры которые пробовал(ip адреса здесь только для примера): В файле /etc/nginx/nginx.conf в блок http

map $remote_addr $log_file {
    default "main";      # Для всех остальных IP
    10.10.10.17 "group1";  # 10.10.10.17 → access_group1.log
    10.10.10.18 "group1";  # 10.10.10.18 → access_group1.log
    10.10.10.19 "group2";  # 10.10.10.19 → access_group2.log
}

В файле /etc/nginx/conf.d/wsrv.conf в блок server

# Лог для остальных IP
access_log /var/log/nginx/access.log combined if=$log_file=main;

# Лог для 10.10.10.17 и 10.10.10.18
access_log /var/log/nginx/access_group1.log combined if=$log_file=group1;

# Лог для 10.10.10.19
access_log /var/log/nginx/access_group2.log combined if=$log_file=group2;

С чего ты взял, что «if» может что-то сравнивать?

The if parameter (1.7.0) enables conditional logging. A request will not be logged if the condition evaluates to “0” or an empty string.

Можно использовать переменные (через map) в имени файла. Типа

access_log /var/log/nginx/access-$log_file.log combined

vel ★★★★★
()

Попробовал воспроизвести вашу проблему, и у меня сложилось впечатление что в access_log всегда будет «дублироваться» запись

Если решения не найдете совсем то вот костыль:

  1. устанавливаете модуль lua-nginx-module или openresty

  2. при помощи https://github.com/cloudflare/lua-resty-logger-socket перенаправляете access_log в syslog

2a. на стороне syslog сервера пишите что-нибудь (пример для syslog-ng)

destination d_local {
    file("/var/log/remote/nginx/127.0.0.1.log");
};

destination d_all {
    file("/var/log/remote/nginx/all.log");
};

filter f_local {
    message("127.0.0.1");
};

filter f_all {
    not filter(f_local);
};

log {
    source(s_network); 
    filter(f_local);
    destination(d_local);
};

log {
    source(s_network);
    filter(f_all);
    destination(d_all);
};

2б. syslog server -> clickhouse/opensearch/logstash/vector.dev и строить дашборды

gagarin0
()
Ответ на: комментарий от vel

Спасибо за подсказку! Получилось так:

map $remote_addr $log_file {
        10.10.10.17 'access.wsrv.group1.log';
        10.10.10.18 'access.wsrv.group1.log';
        10.10.10.19 'access.wsrv.group2.log';
        default 'access.wsrv.log';
    }

и access_log /var/log/nginx/$log_file main;

Хотелось бы еще и выбирать для разных ip(или лог файлов) свой формат. Пробовал добавлять в переменную:

map $remote_addr $log_file {
        10.10.10.17 'access.wsrv.group1.log main';
...
}

и соответственно:

access_log /var/log/nginx/$log_file;

Пробовал заводить отдельную переменную:

map $remote_addr $log_mode {
        10.10.10.17 'main';
...
}

и соответственно:

    access_log /var/log/nginx/$log_file $log_mode;

Но ни так ни так не работает. Может подскажете как задавать форматы для разных лог файлов?

Sinclair
() автор топика
Ответ на: комментарий от Sinclair

IMHO формат лога не может быть переменной.
Попробуй

map $remote_addr $log_main {
        10.10.10.17 '1';
...
}
map $log_main $log_other {
        1       0;
        0       1;
}


access_log /var/log/nginx/$log_file main if=$log_main;
access_log /var/log/nginx/$log_file custom if=$log_other;

vel ★★★★★
()