Назад | Перейти на главную страницу

Вывод журналов JSON на Elastic Beanstalk с Amazon Linux 2

Мы пытаемся перенести наши Java-приложения с текущих платформ Elastic Beanstalk JDK 8 на новые, на которых работает Corretto 11 в Amazon Linux 2. Приложение работает хорошо, но способ обработки журналов изменился. Выходные данные веб-процесса теперь хранятся в /var/log/web.stdout.log и каждая строка имеет префикс с меткой времени и именем процесса, то есть:

May 20 17:00:00 ip-10-48-41-129 web: {"timestamp":"2020-05-20T17:00:00.035Z","message":"...","logger":"...","thread":"MessageBroker-2","level":"INFO"}

Как избавиться от приставки? Эти журналы передаются в CloudWatch, и мы выводим их на стандартный вывод в формате JSON, чтобы позже можно было запросить их с помощью Logs Insights. Но с префиксом Insights не «видит» JSON и просто рассматривает всю строку как текстовый blob.

Я не могу найти на AWS никакой документации по этому поводу. Практически вся документация Elastic Beanstalk относится к первой версии Amazon Linux.

Я нашел решение, которое работает достаточно хорошо, поэтому отправлю его здесь для потомков. Если кто-то может предложить лучший вариант, пожалуйста.

Elastic Beanstalk в Amazon Linux 2 использует rsyslog для обработки и вывода логов. Есть файл на /opt/elasticbeanstalk/config/private/rsyslog.conf что во время развертывания копируется в /etc/rsyslog.d/web.conf и это тот, который направляет весь вывод из web приложение к /var/log/web.stdout.log.

В файле нет настраиваемого шаблона. Он полагается на rsyslogшаблон по умолчанию с префиксом любого %msg% с отметкой времени и $programname (который web в таком случае).

Я попытался заменить этот файл через .ebextensions config, но это не сработало, потому что Elastic Beanstalk, похоже, перезаписывает этот файл после .ebextensions запустить. Итак, я добавил дополнительный крюк платформы который удаляет файл, сохраняя добавленный мной пользовательский.

Вот .ebextensions/logs.config файл:

files:
  "/etc/rsyslog.d/web-files.conf":
    mode: "000644"
    owner: root
    group: root
    content: |
      template(name="WebTemplate" type="string" string="%msg%\n")

      if $programname == 'web' then {
        *.=warning;*.=err;*.=crit;*.=alert;*.=emerg; /var/log/web.stderr.log;WebTemplate
        *.=info;*.=notice /var/log/web.stdout.log;WebTemplate
      }

commands:
  remove-.bak-rsyslog:
    command: rm -f *.bak
    cwd: /etc/rsyslog.d

и .platform/hooks/predeploy/remove-default-rsyslog-conf.sh (убедись, что ты chmod +x вот этот):

#!/bin/sh
rm /etc/rsyslog.d/web.conf
systemctl restart rsyslog.service

Я собираюсь изложить здесь свое решение, хотя это немного другая проблема, чем op - это примерно та же идея и, надеюсь, ответит на некоторые другие вопросы комментаторов о nodejs.

Это для Amazon Linux 2 под управлением Node.js 12.x

ПроблемаЖурналы stdout: nodejs смешаны с журналами nginx в разделе "web" и плохо отформатированы.

Ранее в Amazon Linux 1 под управлением Nodejs эти журналы разделялись на /var/log/nodejs/nodejs.log и /var/log/nginx/access.log. Объединение их с префиксом IP-адреса просто превращает их в полный беспорядок.

Я следил за предложенными решениями и немного их модифицировал.

  1. Конфигурация .ebextension, которая изменяет rsyslog.conf для разделения журналов на два разных файла. Я выполняю фильтрацию по шаблону, который видел в своих файлах журнала, но вы можете использовать любое регулярное выражение, совместимое с RainerScript.

Я не уверен, хотят ли они, чтобы вы редактировали этот файл, как указал другой комментатор, поскольку i является частным. Если вам это не нравится, я бы порекомендовал писать в свои собственные файлы журнала, а не в стандартный вывод. Так у вас будет больше контроля.

files:
  "/opt/elasticbeanstalk/config/private/rsyslog.conf" :
    mode: "000755"
    owner: root
    group: root
    content: |
        template(name="WebTemplate" type="string" string="%msg%\n")

        if $programname  == 'web' and $msg startswith '#033[' then {
            *.=warning;*.=err;*.=crit;*.=alert;*.=emerg; /var/log/web.stderr.log
            *.=info;*.=notice /var/log/web.stderr.log;
        } else if( $programname == 'web') then /var/log/node/nodejs.log;WebTemplate

  1. Теперь, когда у меня есть новый файл журнала, более или менее похожий на стандартный вывод узла, который необходимо передать в cloudwatch, а также включить в пакет журнала. Эти конфигурации задокументированы (но не обновлены для Amazon Linux 2). Конфиги здесь не перезаписываются, просто добавляются новые конфигурации.
files:
  "/opt/elasticbeanstalk/config/private/logtasks/bundle/node.conf" :
    mode: "000755"
    owner: root
    group: root
    content: |
      /var/log/node/nodejs.log

files:
  "/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d/node.json" :
    mode: "000755"
    owner: root
    group: root
    content: |
        {
            "logs": {
                "logs_collected": {
                    "files": {
                        "collect_list": [
                           
                            {
                                "file_path": "/var/log/node/nodejs.log",
                                "log_group_name": "/aws/elasticbeanstalk/[environment_name]/var/log/node/nodejs.log",
                                "log_stream_name": "{instance_id}"
                            }
                        ]
                    }
                }
            }
        }

commands:
    append_and_restart:
        command: /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a append-config -m ec2 -c file:/opt/aws/amazon-cloudwatch-agent/etc/node.json -s