Ведение журнала AWS Elastic Beanstalk с помощью python (django)

Как вы управляете журналами своих приложений в AWS эластичный бобовый стебель? Я имею в виду, вы пишете журналы приложений в какой файл? Я использую следующую конфигурацию ведения журнала в своей среде разработки, но она не работает при развертывании в AWS.

Заранее спасибо!

DEBUG_LOG_DIR = BASE_DIR + "/django_debug.log"
LOGGING = {
    'version': 1,
    'disable_existing_loggers': True,
    # How to format the output
    'formatters': {
        'standard': {
            'format' : "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s",
            'datefmt' : "%d/%b/%Y %H:%M:%S"
        },
    },
    # Log handlers (where to go)
    'handlers': {
        'null': {
            'level':'DEBUG',
            'class':'django.utils.log.NullHandler',
        },
        'log_file': {
            'level':'DEBUG',
            'class':'logging.handlers.RotatingFileHandler',
            'filename': DEBUG_LOG_DIR,
            'maxBytes': 50000,
            'backupCount': 2,
            'formatter': 'standard',
        },
        'console':{
            'level':'INFO',
            'class':'logging.StreamHandler',
            'formatter': 'standard'
        },
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler',
        },
    },
    # Loggers (where does the log come from)
    'loggers': {
        'repackager': {
            'handlers': ['console', 'log_file'],
            'level': 'DEBUG',
            'propagate': True,
        },
        'django': {
            'handlers':['console'],
            'propagate': True,
            'level':'WARN',
        },
        'django.db.backends': {
            'handlers': ['console', 'log_file'],
            'level': 'WARN',
            'propagate': False,
        },
        '': {
            'handlers': ['console', 'log_file'],
            'level': 'DEBUG',
        },
    }
}

10 ответов

Решение

Хорошо, я нашел способ сделать это.

Сначала я подключился через ssh к машине ec2, затем я создал папку в /var/log с именем app_logs с пользователем root:

mkdir /var/log/app_logs

После этого я сделал следующее:

cd /var/log/
chmod g+s app_logs/
setfacl -d -m g::rw app_logs/
chown wsgi:wsgi app_logs/

Это гарантирует, что все файлы, созданные в этой папке, будут иметь владельца wsgi и будут доступны для записи для группы, к которой принадлежит файл. Мне пришлось это сделать, потому что я заметил, что файл журнала, созданный приложением django, имел root как владельца и группу владельцев, но приложение запускается через пользователя wsgi.

Наконец я изменил DEBUG_LOG_DIR на /var/log/app_logs/django_debug.log

У меня была похожая проблема, но на Elastic Beanstalk, поэтому я создал файл конфигурации (например, applogs.config) в .ebextensions папка приложения. Это создает папку app-logs, если ее там еще нет, и устанавливает права доступа к файлу и владельца, чтобы приложение могло записывать туда свои журналы.

commands:
  00_create_dir:
    command: mkdir -p /var/log/app-logs
  01_change_permissions:
    command: chmod g+s /var/log/app-logs
  02_change_owner:
    command: chown wsgi:wsgi /var/log/app-logs

Наконец, в ваших настройках Django:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'file': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',
            'filename': '/var/log/app-logs/django.log',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['file'],
            'level': 'DEBUG',
            'propagate': True,
        },
    },
}

Кроме того, если вы хотите, чтобы ваш журнал был доступен из журналов beanstalk с помощью Интернета, добавьте его в свой файл в.ebextensions

files:
  "/opt/elasticbeanstalk/tasks/taillogs.d/django.conf":
    mode: "000755"
    owner: root
    group: root
    content: |
      /var/log/app-logs/django.log

Есть простой способ, который не требует никакой конфигурации beanstalk.

В ваших настройках django в разделе LOGGING установите обработчик, направленный в файл '/ opt / python / log / {log_file_name}'. Затем к журналам можно получить доступ через меню среды beanstalk в разделе "Журналы".

LOGGING = {
    ...,
    'handlers': {
        'logfile': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': '/opt/python/log/{log_file_name}',
        },
    },
    'loggers': {
        'debugger': {
            'level': 'DEBUG',
            'handlers': ['logfile'],
        'propagate': False,
    },
}

Это местоположение указано в документации здесь:

https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features.logging.html

--редактировать--

Этот ответ был первоначально написан для Amazon Linux AMI. На Amazon Linux AMI удобно использовать/opt/python/log, потому что все файлы журналов в /opt/python/logпапка автоматически включается, когда вы запрашиваете журналы из Elastic Beanstalk. Это связано с тем, что конфигурация по умолчанию содержит задачу, расположенную в/opt/elasticbeanstalk/tasks, который включает все файлы в /opt/python/log. Официальный образец приложения AWS Python для AMI Amazon Linux также использует/opt/python/log для регистрации.

Однако в Amazon Linux 2 нет/opt/python/logпапка (как указано @Oded в комментариях). Итак, что нам теперь делать?

Официальный образец приложения AWS Python для Amazon linux 2 использует /tmp папка для ведения журнала, но пользовательские файлы журнала добавляются в /tmpявляются не включается автоматически при запросе журналов из Elastic Beanstalk. В примере приложения теперь используются настраиваемые задачи ведения журнала, расположенные в/opt/elasticbeanstalk/tasksвложенные папки. См. Инструкции в документации. В примере источника приложения показано, как это достигается с помощью.ebextensions:

files:
  "/opt/elasticbeanstalk/tasks/bundlelogs.d/01-sample-app.conf":
    content: |
      /tmp/sample-app*

  "/opt/elasticbeanstalk/tasks/taillogs.d/01-sample-app.conf":
    content: |
      /tmp/sample-app.log

Отсюда следует, что удобство использования /opt/python/logбез необходимости настраивать конфигурацию, теряется. Тем не менее, некоторые проблемы с разрешениями, описанные в исходном ответе ниже, все еще могут возникнуть.

Права доступа к файлам по умолчанию для /tmp/sample-app.log, на тестовом экземпляре, на котором запущен пример приложения Python по умолчанию в Amazon Linux 2, со всеми настройками по умолчанию, следующие:

-rw-r--r-- 1 webapp webapp 0 Aug 7 14:24 sample-app.log

Обратите внимание, что владелец и группа теперь называются webapp.

Обратите внимание, что само приложение теперь можно найти в /var/app/current.

Дополнительную информацию см. В документации по миграции AWS Linux 2 и расширении платформ EB Linux.

--оригинал -

Резюме

На мой взгляд, самое простое решение - войти в /opt/python/logпапка, как было предложено bewestphal и @thierry-j (в соответствии с ответом Стива-Данлопа).

То же самое и в официальном примере приложения AWS EB Python: см.python-v1.zip источник

Затем файл журнала будет включен автоматически, когда вы запросите журналы у EB.

Это решение работает "из коробки", без каких-либо изменений .ebextensions, пока ты не позвонишьdjango-admin.py (или другой код django) в вашем .ebextensions.

Тем не менее, большинство приложений делают необходимость вызоваdjango-admin.py в .ebextensions, например, чтобы migrate. Это приведет к преждевременному созданию файла журнала сroot владелец и rootгруппа. Это приводит к ошибкам разрешений, потому что приложение работает какwsgi:wsgi.

Это можно исправить, добавив новую команду в конце вашегоcontainer_commands, чтобы удалить "преждевременный" файл журнала, например:

container_commands:
  ...
  9999_remove_root_log_file:
    command: rm /opt/python/log/django.log
    ignoreErrors: true

Подробности ниже.

Задний план

На стандартной предварительно настроенной платформе Amazon Linux/Python, которая использует Apache с mod_wsgi (см. Документацию по платформе AWS),WSGIDaemonProcess для приложения Django запускается как пользователь wsgi и группа wsgi (видеть /etc/httpd/conf.d/wsgi.conf на вашем экземпляре EC2).

Кроме того, права доступа к папке по умолчанию для/opt/python/log папка (в моем стандартном экземпляре EC2): drwxrwxr-x 3 root wsgi 4096 Mar 5 14:08 .

Это wsgi группа имеет все разрешения (rwx), поэтому приложение Django (группа wsgi) может создавать там файлы журналов.

Это работает "из коробки", как демонстрирует официальный пример приложения AWS EB Python ( python-v1.zip).

Однако если вы сделаете что-нибудь в своем .ebextensions что вызывает logging файл-обработчик для инициализации (например, вызов django-admin.py), он сломается.

Проблемы с разрешениями

Вот как использовать django-admin.py в .ebextensions нарушает права доступа к файлу журнала:

Эластичный бобовый стебель container_commands, в .ebextensions, выполняются как rootпользователь (см. документацию по AWS).

Если вы позвоните django-admin.py в любом из container_commands, например, с collectstatic или migrate, что приведет к инициализации обработчиков файлов журналов. Если указанный файл журнала еще не существует, в это время он будет создан сroot владелец и root группа.

Это означает, что приложение Django работает как часть wsgi группа, не будет иметь разрешения на запись в файл журнала (который принадлежит root группа).

Это приводит к ошибкам прав доступа, например: PermissionError: [Errno 13] Permission denied: '/opt/python/log/django.log'

Как воспроизвести

В следующем фрагменте кода показана проблема с разрешениями и показано, как ее исправить.

Чтобы воспроизвести проблему, добавьте эти container_commandsв чистый проект (например, следуя руководству AWS EB Django), настройте Djangosettings.py войти в /opt/python/log/django.log, разверните в AWS EB, затем проверьте eb-activity.log чтобы увидеть вывод команд контейнера.

...

container_commands:
  0100_show_current_user:
    # show that we are running as root user
    command: whoami
  0200_try_to_remove_log_file:
    # we need a clean slate for this example (make sure no log file owned by wsgi is present)
    command: rm /opt/python/log/django.log
    ignoreErrors: true
  0300_break_log_file_permissions:
    # this causes a new log file to be created, owned by root:root (instead of wsgi:wsgi)
    command: django-admin.py
  0400_show_log_file_permissions:
    # prove that a log file was created by root, and show folder permissions
    command: ls -la /opt/python/log
  0500_fix_by_removing_log_file_after_all_django_admin_calls:
    # remove the log file created by django-admin.py, to ensure that a new log file will  
    # be created when the server starts, owned by wsgi:wsgi
    command: rm /opt/python/log/django.log
    ignoreErrors: true

СУХОЙ раствор

Таким образом, нет необходимости явно связываться с разрешениями файлов / папок.

Если вы не вызываете код django в .ebextensions, вход в /opt/python/log работает прямо из коробки.

Если вы вызываете код django в .ebextensions, например django-admin.py collectstatic, просто удалите файл журнала в конце вашегоcontainer_commands раздел.

Вот пример СУХОЙ:

В .ebextensions config:

option_settings:
  # create EB environment property for the log file path
  aws:elasticbeanstalk:application:environment:
    LOG_FILE_PATH: /opt/python/log/django.log
...

container_commands:
  ...
  # django code called here, e.g. "django-admin.py collectstatic"
  ...
  9999_remove_any_existing_django_log_files:
    command: rm $LOG_FILE_PATH      
    ignoreErrors: true

И в settings.py:

...
# get log path from environment variable, with fallback for local development
log_file_path = os.getenv('LOG_FILE_PATH', 'local.log')
# use this as 'filename' for the file handler, as described in the other answers
...

Этот ответ относится только к Amazon Linux 2 . Для тех, кто еще не выполнил миграцию , см. Мой старый ответ для Amazon Linux AMI.

Задний план

Официальное AWS Python выборки приложения для Amazon Linux 2 использует папку для регистрации.

Однако пользовательские файлы журналов добавлены в /tmpявляются не включается автоматически при запросе журналов из Elastic Beanstalk. Чтобы включить пользовательские файлы журнала, нам нужно создать задачи ведения журнала в подпапках /opt/elasticbeanstalk/tasksна экземпляре EC2. См. Инструкции в документации.

Пример приложения ( источник ) выполняет это с помощью .ebextensions. Однако в документации по миграции AWS Linux 2 предлагается использовать .platform вместо этого крючки:

Мы рекомендуем использовать обработчики платформы для запуска пользовательского кода в экземплярах вашей среды. Вы по-прежнему можете использовать команды и команды контейнера в файлах конфигурации .ebextensions, но с ними не так просто работать. Например, написание командных сценариев внутри файла YAML может быть обременительным и трудным для тестирования.

Это имеет дополнительное преимущество, заключающееся в том, что выходные данные хуков платформы собираются в отдельном файле журнала, а именно. /var/log/eb-hooks.log, что немного упрощает отладку.

Настройка DRY logging для базового приложения Django в Amazon Linux 2

Уровень журнала и путь к журналу определяются в одном месте, как свойства среды Elastic Beanstalk, например, в .ebextensions/options.config:

      option_settings:
  aws:elasticbeanstalk:application:environment:
    LOG_LEVEL: INFO
    LOG_FILE_PATH: /tmp/django-app.log
    ...

Свойство environment теперь можно использовать в хуке платформы для создания задач журналирования:

.platform/hooks/postdeploy/00_create_logging_tasks.sh

      #!/bin/bash
TASKS_DIR=/opt/elasticbeanstalk/tasks
# include all app log files in bundle logs (replaces ".log" by "*")
echo "${LOG_FILE_PATH//.log/*}" > "$TASKS_DIR/bundlelogs.d/01-app-log.conf"
# include current app log file in tail logs
echo $LOG_FILE_PATH > "$TASKS_DIR/taillogs.d/01-app-log.conf"

Обратите внимание, что для крючков платформы требуется разрешение на выполнение, например chmod +x 00_create_logging_tasks.sh. В окнах вы можете использовать gitкак описано здесь .

Мы также используем LOG_LEVEL и LOG_FILE_PATH свойства среды в нашем Django settings.py:

      ...
# basic logging with file rotation ()
log_level = os.getenv('LOG_LEVEL', 'INFO')
handlers = dict(file={'class': 'logging.handlers.TimedRotatingFileHandler',
                      'filename': os.getenv('LOG_FILE_PATH'),
                      'when': 'midnight',
                      'interval': 1,
                      'backupCount': 1,
                      'encoding': 'utf-8'})
loggers = dict(django=dict(level=log_level, handlers=['file']),
               myapp=dict(level=log_level, handlers=['file']))
LOGGING = dict(version=1,
               disable_existing_loggers=False,
               handlers=handlers,
               loggers=loggers)
...

Некоторые примечания:

  • Обычно мы указываем заказ formatters также, но я оставил их для ясности.

  • Само приложение теперь можно найти на экземпляре EC2 в /var/app/current. Также см. Дополнительные сведения о расширении платформ EB Linux .

  • Приложение теперь работает как с группой.

  • твой друг. См. Документы .

  • Мы также используем хуки платформы для запуска Django's migrate и collectstaticкоманды, как описано здесь . Мы еще не наблюдали проблем с правами доступа к файлам журнала.

РЕДАКТИРОВАТЬ:

Как указывает @hax0 в комментариях, проблемы с правами доступа к файлам могут возникнуть, если вы попытаетесь запустить команды на экземпляре EC2, используя SSH, после развертывания.

Например, при использовании eb ssh, вы вошли в систему как, но файл журнала принадлежит пользователю, и по умолчанию только владелец имеет разрешение на запись ( 644). Таким образом, при запуске python manage.py в виде ec2-user, вы получите сообщение об ошибке, в котором говорится, что он не может настроить обработчик файла журнала из-за отказа в разрешении.

Быстрый и грязный обходной путь - временно изменить права доступа к файлам , например, используя

      sudo chmod 646 /tmp/django-app.log

Другой обходной путь - запустить manage.py как webapp user, например так:

      sudo su - webapp <<'EOF'
source $(find /var/app/venv/*/bin/activate)
export $(/opt/elasticbeanstalk/bin/get-config --output YAML environment | 
         sed -r 's/: /=/' | xargs)
python3 /var/app/current/manage.py showmigrations
EOF

Как новичку в области разрешений в Linux, мне потребовалось некоторое время, чтобы заставить его работать. Обобщая приведенные выше ответы, у меня наконец сработало следующее:

logging.config

commands:
  00_create_dir:
    command: mkdir -p /var/log/app-logs
  01_change_permissions:
    command: chmod g+s /var/log/app-logs
  02_change_default_owner:
    command: setfacl -d -m g::rw /var/log/app-logs
  03_change_owner:
    command: chown wsgi:wsgi /var/log/app-logs

settings.py

LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
    'file': {
        'level': 'DEBUG',
        'class': 'logging.FileHandler',
        'filename': '/var/log/app-logs/django.log',
    },
},
'loggers': {
    'django': {
        'handlers': ['file'],
        'level': 'DEBUG',
        'propagate': True,
    },
},
}

При этом я могу видеть журналы как отдельный раздел, используя "журналы eb", или в среде Beanstalk, раздел "журналы".

Если вы используетеgunicorn, то вы можете использовать этот флаг:

      gunicorn --access-logfile=- 

Ни одно из упомянутых решений не помогло мне, поскольку я запускаю свой сервер на Amazon Linux 2.

Проблема была не в самой конфигурации ведения журнала, а в .log права доступа к файлам.

Это мой родственный logger.config файл в формате.ebextensions:

commands:
  01_create_log_file:
    command: 'touch /var/log/django.log'
  02_change_log_file_permissions:
    command: 'sudo chmod ugo+rwx /var/log/django.log'

Как видите, мне пришлось решить проблему с разрешениями, просто предоставив все разрешения всем пользователям.

Это моя конфигурация регистратора Django:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'file': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',
            'filename': '/var/log/django.log',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['file'],
            'level': 'DEBUG',
            'propagate': True,
        },
    },
}

Вот мое решение для 64-битной Amazon Linux 2023/4.0.2.

      commands:
  00_create_dir:
    command: mkdir -p /var/log/app-logs
  01_change_permissions:
    command: chmod g+s /var/log/app-logs
  02_change_owner:
    command: chown webapp:webapp /var/log/app-logs

и настройка файла журнала в Django,

      'handlers': {
    'console': {
        'level': 'INFO',
        'class': 'logging.StreamHandler',
    },
    'logfile': {
        'level': 'INFO',
        'class': 'logging.handlers.RotatingFileHandler',
        'filename': "/var/log/app-logs/django.log",
        'formatter': 'standard',
    },
},
'loggers': {
    '': {
        'handlers': ['console', 'logfile'],
        'level': 'INFO',
    },
}

Убедитесь, что файл журнала имеет правильную конфигурацию владельца и группы, владельцем и группой должен быть webapp:wehapp, как показано ниже.

      [ec2-user@ip-171-11-1-8 app-logs]$ ll django.log
-rw-r--r--. 1 webapp webapp 1120 Jul 29 01:08 django.log

По умолчанию в asticbeanstalk вы можете увидеть журналы ошибок django здесь.

/var/log/httpd/error_log