[БЕЗ_ЗВУКА] В этом видео мы поговорим про логирование. Логирование — это очень важная часть любой программы, которая делает что-либо важное. Потому что логирование — это признаки жизни программы. Конечно, можно сказать, что вот если программа ест prods, то она работает. Однако это не всегда так. Она может уйти в какой-нибудь вечный цикл или еще что-то, и не понятно будет, действительно она работает или не зависла. Также без логов вы не сможете понимать, правильно работает ваша программа, либо же там постоянно какие-то ошибки, а все запросы, которые туда приходят, оканчиваются неудачей. В этом видео мы поговорим про несколько подходов к логированию. Мы рассмотрим стандартную библиотеку, что является для логирования. Мы рассмотрим логгер под названием ZAP и логгер под названием Logrus. Для начала есть fmt, пакет Printf, при помощи которого можно что-то вывести. Однако для логирования он не то чтобы очень подходит, потому что по умолчанию все выводит в std out. То есть логировать через fmt допустимо на этапе отладки либо в учебных примерах, как у меня. Для более-менее уже продакшн-логирования стандартная библиотека предоставляет пакет log. Он в стандартной библиотеке. Это, в общем-то, обертка от Printf, однако вы можете направить его вывод в другое место. По умолчанию это stdr. И писать ему туда какую-нибудь дополнительную информацию. Например, время, строчку и что-то еще. Также его можно завернуть в syslog — тоже из коробки. ZAP. ZAP — это логгер, который был разработан в Google. У него нет логгера по умолчанию, его нужно создавать. Он отличается структурным логированием. Что это значит? Это значит, что там нельзя написать %s, вот как в Printf'е, и он там быстро что-то преобразует. Нет, вы должны четко указывать, какого типа параметры вы хотите туда передавать. За счет этого в ZAP'е нет аллокации памяти во время выполнения, нет пустых интерфейсов, которые есть в Printf'е. Потому что вы туда передаете любые значения, и он должен это уметь обрабатывать. И Logrus. Logrus вроде как тоже имеет структурное логирование, но на самом деле это структурное логирование — это map[string]interface, то есть как говорится, те же яйца, только в профиль. Но у Logrus'а есть другие достоинства. Для начала посмотрим, как вообще выводить. Ну, fmt Printf — понятно. ZAP. В ZAP можно добавить соответственно дополнительные параметры и вывести какую-то строчку. В Logrus можно тоже дополнительно добавить дополнительные структурные поля и вывести info, либо любой другой уровень логирования. Рассмотрим, как этим пользоваться на примере access лога. Вот я сделал у себя структуру AccessLogger, там целых три логгера в ней: стандартный, ZAP и Logger. Так, я начинаю создавать свои логгеры. Так, логирование. Я создаю новое логирование, мне он пишет в stdout с каким-то префиксом. Время оно будет писать в utc и будет добавлять строчку, на которой была ошибка. Это очень удобно во время отладки, например, однако довольно дорого, потому что нам придется пройтись в рантайме по стэку. Если логов у вас будет очень много, это грузит программу. Так. Логгер ZAP, я создаю, собственно, отдельный логгер Sugar. Sugar — ну это отдельная такая надстройка над ZAP'ом, которая позволяет выводить какие-то данные вроде Printf. И Logrus. Logrus я тоже создаю, я сразу указываю, что Logrus у меня будет форматировать все в JSON. Ну и оборачиваю все свои запросы в метод accessLog. Метод — это структура. Обратите внимание, раньше у меня в виде Middleware выступали просто отдельные функции, которые были полностью автономной вещью в себе. Однако в данном случае я оборачиваю уже в метод структуры, соответственно, из этого метода я могу обращаться к каким-то отдельным полям структуры, чем я и воспользуюсь, потому что в AccessLogOut у меня аж три логгера, я напомню. Итак, для вывода. Я могу вывести все просто через Printf все, что мне надо. Это очень просто делается, в одну строчку и красиво. Однако все эти значения будут приведены к пустому интерфейсу, что будет создавать понемножку локаций. Через лог, в общем-то то же самое через Printf, но тут добавится уже то, что я хочу сам. Через std logger — это тот логгер, который я указал в моей структуре, то есть там добавится мой префикс, там добавится время запросов в utc и строчка. ZAP. Я логгирую Path, и все мои параметры я привожу к конкретному типу данных. За счет этого нет локаций. Мой Logrus, в котором я тоже передаю вроде бы то же самое, однако аллокации там есть. Ну теперь это стоит запустить. Вот строчка, которая была выведена стандартным абсолютно логгером, который идет прямо стандартный для пакета. Далее, ZAP. Обратите внимание, у нас уже все выведено в виде красивого JSON'а, который очень удобно парсить какими-либо средствами, внешними программами. И Logrus. По умолчанию он выводит не в JSON'е. Теперь я хочу получить какой-то запрос, отправить какой-то запрос на сервер. Например, вот так. И мне выдалось много всякого. Смотрим. Вот стандартный логгер. То есть префикс мой std, мы на 36-й строчке, то есть указалась строчка, где все это происходит, этот тип get запрос, порт, метод, и одна миллисекунда заняла. Далее выводит ZAP, лог ZAP тоже уже побольше, но в целом ровно та же самая информация. И в конце выводит Logrus. Вроде бы ZAP и Logrus они похожи, они выводят тоже оба много информации. В чем между ними разница? Когда использовать один, когда другой? Начнем с Logrus'а. Logrus медленный, однако у него очень много приемников, точнее модулей, которые отправляют в нужный приемник в нужном формате. Соответственно, если вы хотите слать логи в разные места, например, тут есть Fluentd, есть Slack даже, если вы хотите слать в разные места, то, возможно, логгер вам подойдет. Однако Logrus не очень производительный. Вот бич марки ZAP'а, Logrus медленнее ZAP'а в восемь раз, а локаций там почти в 30 раз больше. Поэтому если у вас логов очень-очень много и вы хотите их просто в какое-то одно место писать, и вам важна производительность, то, возможно, логгер ZAP будет хорошим выбором для этих целей. Ну, а если вам все равно, то, конечно же, вы можете использовать стандартный лог из стандартной библиотеки и не заморачиваться.