Как я могу получить тег из журналов системного журнала, которые отправляются в Logstash?

Я настроил свой демон Docker так, чтобы журналы всех моих контейнеров перенаправлялись в приложение Logstash, прослушивающее порт 5000, используя следующую конфигурацию для daemon.json :

{
  "log-driver": "syslog",
  "log-opts": {
    "syslog-address": "udp://localhost:5000",
    "syslog-format": "rfc3164",
    "tag": "{{.Name}}"
  },

  "hosts": [
    "tcp://0.0.0.0:2375",
    "unix:///var/run/docker.sock"
  ]
}

Поскольку множество разных контейнеров создают журналы одновременно, я хотел бы иметь возможность фильтровать имена контейнеров, когда я визуализирую их журналы в своем стеке ELK. Однако я не уверен, как я могу получить в Logstash «тег», который я установил как часть «log-opts» в конфигурации демона Docker выше.

Я попытался просто получить его как переменную и перенаправить в поле в конфигурации Logstash, но он просто сохраняет текст «% {tag}» в виде строки. Можно ли получить тег исходного контейнера в конфигурации Logstash?

logstash.conf:

input {
  udp {
    port => 5000
    type => syslog
  }
}
output {
  elasticsearch {
    hosts => ["elasticsearch"]
  }
}

filter {
  if [type] == "syslog" {
    if [message] =~ "^<\d+>\s*\w+\s+\d+\s\d+:\d+:\d+\s\S+\s\w+(\/\S+|)\[\d+\]:.*$" {
      grok {
        match => {
          "message" => "%{SYSLOGTIMESTAMP:timestamp} %{SYSLOGHOST:hostname} %{DATA:container_hash}(?:\[%{POSINT}\])?: %{GREEDYDATA:real_message}"
        }
        remove_field => ["message"]
      }
      mutate {
        add_field => {
          "tag" => "%{tag}"
        }
      }
    }
  }
}

Редактировать: если я не удалю поле message, как в конфигурации logstash, то поле message будет выглядеть примерно так, когда я просматриваю журналы в Kibana:

<30>May 15 15:13:23 devlocal e9713f013ebb[1284]: 192.168.56.110 - - [15/May/2019:15:13:23 +0200] "GET /server/status HTTP/1.0" 200 54 0.003 "-" "GuzzleHttp/6.3.3 curl/7.64.0 PHP/7.2.17" "172.30.0.2"

Итак, tag, который я ищу, не является частью message; поэтому я не знаю, откуда я могу его получить.


person Bruno Pérel    schedule 15.05.2019    source источник
comment
@baudsp Какой JSON вы имеете в виду? Разве системный журнал не передает строки журнала как простые строки?   -  person Bruno Pérel    schedule 16.05.2019
comment
Извините, я неправильно понял ваш вопрос. Не могли бы вы опубликовать один или два примера строк из ваших журналов?   -  person baudsp    schedule 16.05.2019
comment
Также при выполнении add_field => {"tag" => "%{tag}"} вы добавляете новое поле, называемое тегом, со значением уже существующего поля, здесь тег; поэтому, если тег поля ранее не существовал, он просто поместит в него %{tag}. Вам придется отредактировать шаблон grok, чтобы он извлекал значение тега.   -  person baudsp    schedule 16.05.2019
comment
@baudsp Я отредактировал вопрос, указав пример строки журнала, отправленной системным журналом. Как видите, tag, который я ищу, не является его частью.   -  person Bruno Pérel    schedule 16.05.2019
comment
Ваш процесс демона выглядит так, как будто он уже добавляет тег — вам не нужно делать это в конвейере logstash. Вы можете фильтровать на основе тега с помощью условного, например. if "tagName" in [tags]   -  person Adam    schedule 16.05.2019
comment
@Adam Вы имеете в виду, что, например, когда я смотрю журналы в Kibana, я должен видеть имя контейнера в поле tags? Это не так: у меня есть поле tags, но это либо пустая строка, либо строка _grokparsefailure   -  person Bruno Pérel    schedule 16.05.2019
comment
Можете ли вы попробовать изменить драйвер журнала на gelfвместо syslog? docs.docker.com/config/containers/logging/gelf/#examples< /а>   -  person Adam    schedule 16.05.2019
comment
@Adam Как мне получить имя исходного контейнера в logstash после этого изменения? Я до сих пор не вижу этого в Кибане   -  person Bruno Pérel    schedule 16.05.2019


Ответы (1)


Похоже, проблема может быть связана с выбранным вами драйвером журнала. Изменение драйвера журнала на gelf должно дать вам доступ к тегам и множеству других полей, например. ниже

    {
  "_index": "logstash-2017.04.27",
  "_type": "docker",
  "_id": "AVuuiZbeYg9q2vv-JShe",
  "_score": null,
  "_source": {
    "source_host": "172.18.0.1",
    "level": 6,
    "created": "2017-04-27T08:24:45.69023959Z",
    "message": "My Message Thu Apr 27 08:31:44 UTC 2017",
    "type": "docker",
    "version": "1.1",
    "command": "/bin/sh -c while true; do echo My Message `date`; sleep 1; done;",
    "image_name": "alpine",
    "@timestamp": "2017-04-27T08:31:44.338Z",
    "container_name": "squarescaleweb_plop_1",
    "host": "plop-xps",
    "@version": "1",
    "tag": "staging",
    "image_id": "sha256:4a415e3663882fbc554ee830889c68a33b3585503892cc718a4698e91ef2a526",
    "container_id": "12b7bcd3f2f54e017680090d01330f542e629a4528f558323e33f7894ec6be53"
  },
  "fields": {
    "created": [
      1493281485690
    ],
    "@timestamp": [
      1493281904338
    ]
  },
  "sort": [
    1493281904338
  ]
}

пример из: https://gist.github.com/eunomie/e7a183602b8734c47058d277700fdc2d

Вам также нужно будет отправлять свои журналы через UDP вместо TCP. Вы можете изменить свой daemon.json для чтения

{
  "log-driver": "syslog",
  "log-opts": {
    "gelf-address": "udp://localhost:<PORT>"
    "tag": "{{.Name}}"
  },

  "hosts": [
    "tcp://0.0.0.0:2375",
    "unix:///var/run/docker.sock"
  ]
}

Я не уверен, какой порт вы настроили в logstash для получения пакетов UDP, но для GELF кажется, что 12201 является значением по умолчанию для logstash.

После отправки сообщений в logstash вы можете создать конвейер для извлечения полей по вашему выбору. например [container_name]

person Adam    schedule 17.05.2019
comment
Спасибо! Мне потребовалось некоторое время, чтобы понять, что syslog просто ничего не знает о том, из каких контейнеров приходят строки журнала, а gelf знает. Всего несколько замечаний к вашему ответу, если вы хотите его отредактировать: 1) Я уже отправлял журналы по UDP (см. Мой daemon.json), но мне пришлось заменить gelf-address на syslog-address. 2) Порт, который я настроил для Logstash, показан в конфигурации logstash.conf, которой я поделился: это порт 5000. - person Bruno Pérel; 17.05.2019