Если использовать docker swarm, docker отдаёт json с полями log, container_id и container_name. В Graylog, Kibana если нужно получить лог по определённому контейнеру, то приходится фильтровать по container_name. Но при рестарте сервиса имя контейнера меняется и query превращается в тыкву. Да и каждый раз нужно искать новое имя контейнера.
Показываю, как вытащить имя сервиса из container_name с помощью filter в fluentd. И добавить отдельным полем, по которому можно будет нормально фильтровать.
Сделаем простой docker-compose для теста:
version: '3'
services:
nginx:
image: nginx
ports:
- "80:80"
logging:
driver: "fluentd"
options:
fluentd-async-connect: "true"
fluentd-sub-second-precision: "true"
Конфиг fluentd для дебага. Собирает всё, что ему шлёт наш сервис и отсылает в свой лог
# Source from docker
<source>
@type forward
port 24224
tag docker
</source>
# Forward to stdout
<match docker>
@type stdout
</match>
Отправляем запрос curl’ом и смотрим лог
tail -f /var/log/td-agent/td-agent.log
2022-12-09 16:20:46.897530693 +0000 docker: {"source":"stdout","log":"10.0.0.2 - - [09/Dec/2022:16:20:46 +0000] \"GET / HTTP/1.1\" 200 615 \"-\" \"curl/7.68.0\" \"-\"","container_id":"8e800da34b65b5cf5f883a7367e844131b40d64fccc62f62d802a92199e4bf3c","container_name":"/nginx_nginx.1.cfl93fy7a9qiupzlhs89ee0uk"}
Имя сервиса можно извлечь из container_name. Для этого будем использовать filter с плагином record_transformer, с помощью которого можно добавить в логи ещё одно поле.
В документации показано, что из “tag” можно вытащить один элемент tag_parts[N]. Но у нас это не tag, а строка. Со строкой можно работать с помощью функций Ruby.
Нам нужно вытащить nginx_nginx
из /nginx_nginx.1.cfl93fy7a9qiupzlhs89ee0uk
Добавляем filter
# Add Service name
<filter docker>
@type record_transformer
enable_ruby true
<record>
service_name ${ s = record["container_name"][1..-1].split("\.")[0]}
</record>
</filter>
enable_ruby true
- эта строка добавляет возможность использования функций Rubyrecord["container_name"]
- так забираем строку из другого поля- С помощью
[1..-1]
удаляем первый символ в строке “/”. Нафиг он вообще там нужен? split("\.")[0]
- с помощью этой функции делаем как бы массив из строки и берём нулевое значение
Получаем такой конфиг
# Source from docker
<source>
@type forward
port 24224
tag docker
</source>
# Add Service name
<filter docker>
@type record_transformer
enable_ruby true
<record>
service_name ${ s = record["container_name"][1..-1].split("\.")[0]}
</record>
</filter>
# Forward to stdout
<match docker>
@type stdout
</match>
Перезапускаем агент, отправляем запрос и получаем:
2022-12-09 16:33:30.860224690 +0000 docker: {"container_name":"/nginx_nginx.1.cfl93fy7a9qiupzlhs89ee0uk","source":"stdout","log":"10.0.0.2 - - [09/Dec/2022:16:33:30 +0000] \"GET / HTTP/1.1\" 200 615 \"-\" \"curl/7.68.0\" \"-\"","container_id":"8e800da34b65b5cf5f883a7367e844131b40d64fccc62f62d802a92199e4bf3c","service_name":"nginx_nginx"}
Получили дополнительное поле "service_name":"nginx_nginx"
, по которому теперь можно нормально фильтровать логи.
Мой телеграм-канал .