Логирование в Docker и Sentry

Философия логирования процессов в Docker. Установка Monolog. Вывод логов для функциональных тестов. Подключение сервиса Sentry.IO для уведомлений об ошибках.

  • 00:00:32 Неудобства отсутствия логов
  • 00:04:16 Философия логирования в Docker
  • 00:08:47 Запись в stdout и stderr
  • 00:09:58 Логирование в готовых образах
  • 00:11:27 Дублирование данных контейнера в файлах
  • 00:14:15 Удаление логов консольных команд
  • 00:15:44 Постановка задачи
  • 00:17:05 PSR-3 Logger Interface
  • 00:18:30 Библиотека Monolog Logger
  • 00:20:43 Установка и настройка Monolog
  • 00:23:59 Права доступа к папке logs
  • 00:26:18 Перемещение кэшей линтеров и тестов
  • 00:26:56 Права на папки в Dockerfile для production
  • 00:27:51 Подмена логирования в Slim ErrorHandler
  • 00:30:00 Перенос ErrorMidleware в DI-контейнер
  • 00:35:49 Написание своего LogErrorHandler
  • 00:39:33 Необходимость оповещения об ошибках
  • 00:41:15 Сервис Sentry
  • 00:42:46 Подключение и настройка Sentry
  • 00:50:41 Декоратор Sentry для ErrorHandler
  • 00:54:23 Обзор результата
Скрытый контент (код, слайды, ...) для подписчиков. Открыть →
Дмитрий Елисеев
elisdn.ru
Комментарии (21)
Arunas

спасибо.

Ответить
fedot

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

Ответить
Дмитрий Елисеев

Многим кажется, что с Docker нужно больше работы. Но если подумать, то и без него тоже приходится писать те же конфигурационные файлы nginx.conf для хостов и переопределения для php.ini. И также на продакшене запускать composer install и npm run build вручную или деплоить через Deployer или Capistrano. Также подключать Lets Encrypt, устанавливать софт, настраивать репликации, хранить пароли. То есть всё равно приходится делать то же самое, что делалось вручную или готовыми и самописными скриптами.

В итоге с внедрением Docker число конфигурационных файлов и скриптов не поменялось. Просто сейчас эти же горы скриптов и конфигураций положили в Git-репозиторий рядом с кодом.

Это сейчас требует больше квалификации от разработчика просто потому, что раньше этим всем незаметно занимались отдельные сисадмины, а теперь всё собрано вместе.

Ответить
Дмитрий Елисеев

Мелким вебстудиям, которые делают одноразовые сайты-визитки на Wordpress, это всё обычно не нужно. Они могут хоть заливать по FTP и даже не пользоваться Git-ом. Сделал, сдал и забыл. Или если один делаешь свой проект по несколько пушей в день, то можешь всё проверить и задеплоить вручную.

Автоматизация сильно интересна именно компаниям, активно разрабатывающим большие и долгосрочные сервисы для себя. Если 5 программистов пишут проект полгода по ~100 коммитов в день, то автоматизация тестирования и деплоя экономит кучу времени и усилий.

Docker интересен здесь именно тем, что с ним проще поднимать сервисы и с ним не захламляются серверы. Чтобы обновить версию PHP достаточно поменять Dockerfile и заменить старый контейнер новым. Не приходится каждый раз вычищать систему от мусора, оставшегося от старого софта.

Ответить
Роман

заменить старый контейнер новым

Дмитрий, я правильно понимаю что сервер практически не захламляется, по той причине (возможно основной, - поправьте, если ошибаюсь), что выполняется команда поднятия/рестарта контейнеров с флагом очистки служебной инфы --rm, которую хранил докер в прошлых контейнерах, например: docker-compose run --rm {service_name}? Если так, то в этом эпизоде мы намеренно отключаем в Makefile данный флаг, чтобы не удалять старые директории в целях логирования. В данном случае при загрузке новых версии образов и поднятия контейнеров на проде, некая захламленность будет присутствовать или нет?

И ещё вопрос про загрузку новых версии приложения. На прод сервер постоянно пушатся, а там формируются новые образы в registry (с новым числом - версией). Там в реестре хранятся не только новые версии, но и возможное множество старых тегов, которые, скорее всего, тоже захламляют сейчас прод сервер, верно? Или может быть сейчас пушить только одну версию образов и она там будет постоянно перезаписываться и, как следствие, контейнеры на продакшене будут постоянно подниматься с обновлениями и реестр будет содержать один тег? Или может быть старые версии можно как-то подчищать с помощью консольной команды?

Ответить
Дмитрий Елисеев

Некая захламленность будет присутствовать или нет?

Будут оставаться папки с логами в /var/lib/docker/containers. Чтобы их время от времени чистить мы через Ansible добавили cron-команду с docker system prune ... для удаления элементов месячной давности.

Ответить
Дмитрий Елисеев

Или может быть старые версии можно как-то подчищать с помощью консольной команды?

Да, в реестре всё накапливается и нужно либо чистить вручную через API или в консоли и потом запускать garbage collector, либо подключить к реестру стороннее безлимитное хранилище.

Ответить
fedot

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

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

Ответить
Алексей

Спасибо за уроки, немного не по теме, дальше будет еще и JS, и было бы здорово показать как сделать чат на сокетах и при этом сохраняя его (как на ютубе на стримах, что после стрима чат можно прочитать уже в видео), через наше приложение в бд, спасибо!

Ответить
Роман

У меня возникала ошибка Fatal error: Type of App\ErrorHandler\LogErrorHandler::$logger must not be defined (as in class Slim\Handlers\ErrorHandler) in /app/src/ErrorHandler/LogErrorHandler.php on line при попытке стукнуться к бэкенду localhost:8081, после коммита Added logged error handler ElisDN 11.03.2020, 14:58. Решением для меня было удалить приватное свойство в классе LogErrorHandler::$logger, так как оно есть в родительском ErrorHandler. Странно почему не работало, наверное slim поднял версию и там что-то изменилось немного.

Ответить
Дмитрий Елисеев

Да, они теперь сами добавили $logger в ErrorMiddleware как сделано у нас. Теперь наш LogErrorHandler можно упростить.

Ответить
Arunas

в Dev режиме не создает logg файл в случае ошибки адреса.
в тестовом режиме все нормально.
(на Linux-овом компьютере логи все нормально)
ошибка:

Fatal error: Uncaught UnexpectedValueException: There is no existing directory at "/app/config/dev/../../var/log/fpm-fcgi" and its not buildable: Permission denied in /app/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php on line 171
( ! ) UnexpectedValueException: There is no existing directory at "/app/config/dev/../../var/log/fpm-fcgi" and its not buildable: Permission denied in /app/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php on

как решить?

Ответить
Дмитрий Елисеев

Permission denied. Не может записать в папку var/log. Решить исправлением прав через chmod.

Ответить
Arunas

Спасибо.

Ответить
Сергей

Дмитрий, в ErrorMiddleware:

/** @var CallableResolverInterface $callableResolver */
$callableResolver = $container->get(CallableResolverInterface::class);
/** @var ResponseFactoryInterface $responseFactory */
$responseFactory = $container->get(ResponseFactoryInterface::class);

Не может зарезолвить CallableResolverInterface и ResponseFactoryInterface, выкидывает ошибку

Fatal error: Uncaught DI\Definition\Exception\InvalidDefinition: Entry "Slim\Interfaces\CallableResolverInterface" cannot be resolved: the class is not instantiable Full definition: Object ( class = #NOT INSTANTIABLE# Slim\Interfaces\CallableResolverInterface lazy = false ) in /app/vendor/php-di/php-di/src/Definition/Exception/InvalidDefinition.php on line 18

DI\Definition\Exception\InvalidDefinition: Entry "Slim\Interfaces\CallableResolverInterface" cannot be resolved: the class is not instantiable Full definition: Object ( class = #NOT INSTANTIABLE# Slim\Interfaces\CallableResolverInterface lazy = false ) in /app/vendor/php-di/php-di/src/Definition/Exception/InvalidDefinition.php on line 18

Что делать в этом случае? Писать фабрики для них? Когда заменяю на реализацию:

/** @var CallableResolverInterface $callableResolver */
$callableResolver = $container->get(\Slim\CallableResolver::class);
/** @var ResponseFactoryInterface $responseFactory */
$responseFactory = $container->get(\Slim\Psr7\Factory\ResponseFactory::class);

ошибка исчезает

Ответить
Дмитрий Елисеев

Не упомянул, что они зарегистрированы в файлах config/http.php:

use Psr\Http\Message\ResponseFactoryInterface;
use Slim\Psr7\Factory\ResponseFactory;

return [
    ResponseFactoryInterface::class => static function (): ResponseFactoryInterface {
        return new ResponseFactory();
    },
];

и config/slim.php:

use Psr\Container\ContainerInterface;
use Slim\CallableResolver;
use Slim\Interfaces\CallableResolverInterface;

return [
    CallableResolverInterface::class => static function (ContainerInterface $container): CallableResolverInterface {
        return new CallableResolver($container);
    },
];
Ответить
Сергей

Спасибо, Дмитрий! Собирался в принципе сделать то же самое

Ответить
Владимир

Похоже видео раза в 1,5 ускорено. довольно тяжело усваивать сходу

Ответить
Юлия Елисеева

Видео как-то специально не ускоряю, а вот паузу между предложениями уменьшаю. Поэтому может возникнуть такое ощущение.

Ответить
Ruslan

Правильно лия понял, что если нам понадобится больше данных для какого-то майл сервиса, то нам придется на каждый параметр создавать Frontend...TwigExtension ? (К примеру мы вышлем Промо товаров нашему подписчику обращаясь при этом к нему по имени )

За курс отдельное спасибо. И извиняюсь, что не пишу это под каждым видео, потому что жалею всех тех, кто идет за мной и будет читать не вопросы которые возникли, а "Спасибо" :)

Ответить
Дмитрий Елисеев

Просто достанем данные подписчика и передадим их в render(...) как передаём токен.

Ответить
Зарегистрируйтесь или войдите чтобы оставить комментарий

Или войти через:

Yandex
MailRu
GitHub
Google