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

К примеру:

package log
import (
    "io/ioutil"
    "log"
    "os"
)

var (
    Trace = log.New(ioutil.Discard, "TRACE ", log.LstdFlags)
    Debug = log.New(os.Stdout, "DEBUG ", log.LstdFlags)
    // etc
)

В то время как пакет glog от Google предоставляет следующие уровни логирования:

  1. Info

  2. Warn

  3. Error

  4. Fatal

Посмотрим теперь на другую библиотеку, loggo, которую разработали Juju, предоставляет следующие уровни:

  1. Trace

  2. Debug

  3. Info

  4. Warn

  5. Error

  6. Critical

Loggo также предоставляет возможность настроить детализацию ведения журнала для каждого пакета.

Итак, вот два примера, на которые явно повлияли другие библиотеки ведения журналов на других языках. На самом деле их родословная восходит к syslog(3), а может быть, даже раньше. И я думаю, что они ошибаются.

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

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

Итак давайте поговорим про Warnings

Начнем с самого простого. Уровень логирования предупреждение по сути никому не нужен.

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

Кроме того, если вы используете какое-то уровневое ведение логов, то зачем вам устанавливать уровень предупреждение? Вы бы установили уровень на информирование или ошибки. Установка уровня предупреждения является признанием того, что вы, вероятно, обрабатываете ошибки на уровне предупреждения.

Уберите уровень предупреждение, это либо информационное сообщение, либо состояние ошибки.

Дальше у нас уровень Fatal

Fatal уровень фактически обрабатывает сообщение, а затем вызывает os.Exit(1). В принципе это означает:

  1. Операторы defer в других горутинах не выполняются.

  2. буферы не сбрасываются.

  3. временные файлы и каталоги не удаляются.

По сути, log.Fatal является менее подробным, чем panic, но семантически эквивалентен ему.

Принято считать, что библиотеки не должны использовать panic, но если вызов log.Fatal имеет тот же эффект, то, безусловно, это тоже должно быть запрещено.

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

Не логируйтесь на фатальном уровне, предпочитайте вместо этого возвращать вызывающему коду ошибку. Если ошибка всплывает вплоть до main.main, то это подходящее место для обработки любых действий по очистке перед выходом.

Так дальше у нас уровень error

Обработка ошибки и ведение логов тесно связаны между собой, поэтому, на первый взгляд, ведение логирования на уровне error должно быть легко оправдано. Я с этим не согласен.

В Go, если вызов функции или метода возвращает значение ошибки, в реальности у вас есть два варианта решения:

  1. обработать ошибку.

  2. вернуть ошибку вызывающему абоненту. Вы можете упаковать ошибку в подарочную упаковку, но это не важно.

Если вы решите обработать ошибку, записав ее в лог, по определению это больше не ошибка — вы ее обработали. Акт обработки ошибки обрабатывает ошибку, поэтому больше не следует обрабатывать ее как ошибку.

Позвольте мне попытаться убедить вас с помощью этого фрагмента кода:

err := someFunc()
if err != nil {
  log.Error("Error",err)
  return err
}

Вы никогда не должны обрабатывать что-либо на уровне ошибки, потому что вы должны либо обработать ошибку, либо передать ее обратно вызывающему.

Чтобы было ясно, я не говорю, что вы не должны обрабатывать возникновение условия.

if err := someFunc(); err != nil {
        log.Infof("Info: %v", err)
        someOperation()
}

но на самом деле log.Info и log.Error имеют одну и ту же цель.

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

Что дальше?

Мы исключили предупреждения, заявили, что ничего не должно обрабатыватся на уровне ошибок, и показали, что только верхний уровень приложения должен вести себя как log.Fatal. Что осталось?

Я считаю, что есть только две вещи, которые вы должны обрабатывать:

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

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

Очевидно, что это отладочный и информационный уровни соответственно.

log.Info должен просто записать эту строку в вывод лога. Не должно быть возможности отключить его, поскольку пользователю следует сообщать только то, что полезно для него. Если возникает ошибка, которую невозможно обработать, она должна всплыть в main.main, где программа завершается. Незначительное неудобство, связанное с необходимостью вставлять префикс fatal перед окончательным сообщением логироыания или писать непосредственно в os.Stderr с помощью fmt.Fprintf, не является достаточным оправданием для пакета ведения лога, расширяющего метод log.Fatal.

log.Debug, совсем другое дело. Это должен контролировать разработчик или инженер службы поддержки. Во время разработки отладочные операторы должны быть многочисленными, не прибегая к уровню трассировки или 2 уровня отладки. Пакет логирования должен поддерживать детальное управление для включения или отключения отладки и только отладки операторов в пакете или, возможно, еще более тонкой области.

В итоге что мы получаем

Если бы это был опрос, я бы попросил вас выбрать между:

  1. ведение логов важно

  2. ведение логов сложно

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

Что вы думаете?

Комментарии (45)


  1. gecube
    08.01.2022 23:20
    +4

    перевод ужасный.

    автор несет чушь.

    Чтобы было ясно, я не говорю, что вы не должны обрабатывать возникновение условия.

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

    Мое мнение - я счастлив, что во многих системах есть возможность детализации уровня логов. Это позволяет проводить более эффективно отладку и расследование инцидентов. И отбирать этот инструмент... ну, такое себе решение


    1. rustler2000
      09.01.2022 00:10

      Статья 2015 года. Лог до сих пор интерфейса не имеет то. Не помню чтобы даже proposal был.


      1. creker
        09.01.2022 01:40
        +1

        Есть https://github.com/golang/go/issues/13182 Вроде бы руководство не против, но очевидная проблема, которую эта статья и затрагивает - нет консенсуса о функционале этого интерфейса. Если его добавлять, то это окажет сильный эффект на экосистему и многие начнут подстраиваться под него. Люди хотят уровни, разные варианты вывода, структурированный логгинг, минимум аллокаций и т.д. и т.п. Я так понимаю JUL в мире Java как раз стал жертвой этой проблемы. Люди пытались стандартизировать логирование, но в итоге его никто не использует по куче разных причин.


    1. creker
      09.01.2022 01:30
      +1

      Давненько тоже читал этот пост и тоже с ним не согласен. С одной стороны, количество уровней во многих библиотеках действительно зашкаливает. Мне вот очень нравится zerolog и в нем 7 уровней логирования. Это ну совсем избыточно. С другой, если оставить только info и debug, то непонятно как вообще это парсить.


      1. nin-jin
        09.01.2022 08:40
        +1

        А что за сложности с парсингом?


        1. creker
          09.01.2022 13:46

          Например, уровни логирования позволяют настроить простейший алертинг. Если приложение написано нормально, то error уровень означает что-то, что требует внимания. Если все логируется с уровнем info, то непонятно, как оттуда вытаскивать что-то полезное. Читать эту стену текста никто не будет. Парсить - заранее не знаешь, какого формата сообщение возникнет, если это не твое приложение. Вот и получится, читать это все только постфактум, когда уже все сломалось.


          1. nin-jin
            09.01.2022 14:24

            То есть вам нужны не "уровни логирования", а флаг "требует реагирования". То есть и "не ответили вовремя", и "упали при ответе", и "заканчивается квота" и "вам перевели особо крупную сумму" - все тоебуют реагирования, хотя обычно относятся к совершено разным уровням.


            1. creker
              09.01.2022 14:32

              Мне достаточно двух уровней логирования - ошибка и все остальное. Первое привлечет мое внимание. Второе будет являться контекстом для расследования причин первого. Если прямо хочется, то можно добавить debug, который повысит детализацию второго. Хотя это скорее verbosity, чем дополнительный уровень.

              Я ниже описал мое мнение про warn - это не более чем еще один вариант info. Он не содержит полезной и важной информации, на практике высирается стабильно и много. Тоже самое с разделением error, fatal, critical - это все ошибки. Разделение на кучу уровней не делает их полезнее, зато вносит непонятную путаницу.


      1. fougasse
        09.01.2022 13:16

        В чём избыточность 7 уровней логирования?


        1. creker
          09.01.2022 13:56

          В моей практике я не нашел большинству из них применения. Я пользуюсь только info, error и fatal уровнями. Debug как-то пробовал, но оказалось, что очень сильно мусорит код, а толку для отладки все равно мало. Зачем в библиотеке одновременно trace и debug мне непонятно - пул реквест не содержит нормальных аргументов https://github.com/rs/zerolog/pull/158 Зачем нужен warn тоже непонятно - это либо какая-то ошибка, которую код обработал, то юзеру на нее надо посмотреть, либо это информационное сообщение, которое вроде бы важное, а вроде не говорит о том, что что-то плохо работает. Если это первое, то для этого есть error. Если второе, то, опять же, никто это читать не будет. Частенько warn сообщения летят постоянно даже при нормальной работе, что нивелирует их ценность.

          Собственно, поэтому слишком много уровней это плохо. Непонятно что использовать, сложно разработать лучшие практики, которым все следуют. В итоге получается, что пользуются большинство одним двумя уровнями, но работать с этим все равно не удобно, потому что кто-то однозначно захочет использовать все 7 уровней. Лучше меньше, но с пользой.


          1. fougasse
            09.01.2022 14:31

            Я пользуюсь, как минимум, 7. Удобно включать совсем детальное логирование(CONSOLEMIN/MAX/DETAILED), когда нужно глянуть чуть ли не каждый пакет данных, приходящих в систему. Плюс в релизных билдах ограничивается уровнем INFO, SERVICE, WARN, ERROR. INFO показывает примерный flow логики. FATAL автоматически в ассертах перед "смертью" процесса пишется.

            Как в сложной системе можно обойтись одним уровнем INFO для рабочего логирования мне непонятно.

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


            1. creker
              09.01.2022 14:59

              Я бы сказал логи в сложной системе имеют сомнительную ценность. Метрики - вот главный инструмент диагностики сегодня. Весь алертинг делается именно здесь в нормальных сложных системах. Дальше идет трейсинг - это как бы логи, но намного мощнее, т.к. содержат контекст. А вот уже потом в самом конце логи, которые обычно складываются в систему индексирования и забываются. Авось когда-нибудь понадобится.

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

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


              1. leventov
                09.01.2022 16:36

                Логирование это более локальный, но зато, потенциально, более полный вариант трассировки. Но если у вас программка которая крутится локально и общается с внешним миром через stdout и stderr, она не может и не должна посылать трассировки на специальный сервер. Тут работает логирование. С другой стороны, обычно можно позволить логировать гораздо больше событий/запросов на локальный диск (часто -- все), чем посылать трассировок на сервер. В системах, где индивидуальные события важны (финансы, е-коммерс, и т. д.) это может быть необходимостью.


                1. gecube
                  09.01.2022 17:43

                  Логирование это более локальный, но зато, потенциально, более полный вариант трассировки

                  Это сейчас такая шутка была? Сейчас во время контейнеров и микросервисов логирование отражает поток выполнения только лишь единого сервиса. А разработчику или devops'у нужен весь стек вызовов между всеми сервисами, участвующими в обработке запроса пользователя. Логирование "починить" можно тем, чтобы сваливать все логи в единую систему и придумать какой-то request id или user Id корелляцию. Ой, мы только что изобрели трейсинг на коленке и лучше бы взяли что-то готовое и уже стандартное (jaeger? Opentracing?)

                  В системах, где индивидуальные события важны (финансы, е-коммерс, и т. д.) это может быть необходимостью.

                  Не лукавьте. Это не логи. А события. Это очень большая разница. Логи Вы можете потерять. А события нет. И в случае финансов, е-Коммерс и прочего - если событие не может быть зафиксировано, пользователю будет возвращена ошибка и будет предложено повторить операцию. А в случае логов... нет. Я уж не говорю о том, что схема доставки логов, которая будет надежная и производительная, запросто по цене может превысить стоимость самого решения, которое мы хотим залогировать. Весь вопрос в количестве данных. Логов всегда много )))


                  1. leventov
                    09.01.2022 20:35
                    +1

                    Это сейчас такая шутка была? Сейчас во время контейнеров и микросервисов логирование отражает поток выполнения только лишь единого сервиса.

                    Не все в мире крутится в облаке на бэкенде. Есть встраиваемые устройства, есть фронтэнд логи (хотя это не про Го :)


                    1. gecube
                      09.01.2022 21:15

                      Не все в мире крутится в облаке на бэкенде

                      несомненно.

                      есть фронтэнд логи (хотя это не про Го :)

                      sentry, из платного - dynatrace. Работает как - в js на клиентской стороне инжектится модуль отправки телеметрии в централизованную консоль... где она вся агрегируется


                1. creker
                  09.01.2022 22:20
                  +1

                  Безусловно, когда речь об обычной программке, то там конечно некуда трейсы посылать. Собственно, там некуда наверное и метрики посылать. Но это уже сложно квалифицировать "сложной системой". Последнее в моем понимании это распределенная система, где логи локальны для конкретного сервиса и его экземпляра, что существенно снижает их ценность. Там правят метрики.

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


          1. nin-jin
            09.01.2022 14:33

            Варнинги позваляют отличать сообщения, накоторые должен реагировать владелец кода (ошибка), от сообщений, на которые должен/может реагировать его пользователь (нештатная ситуация).


            1. creker
              09.01.2022 14:51
              +1

              На практике оно так не работает. warn сыпет бесполезной информацией. Частенько о том, что что-то где-то не выключено, не настроено. Как упомянутый esxi - зачем мне warn, что у меня не настроен file service. Я знаю, мне он не нужен. Это можно свалить на vmware и их неграмотных программистов, но скорее это показатель, что экосистема логирования это помойка, в которой нет лучших практик и понимания как что делать. Это повсеместная проблема. И 100500 уровней логирования никак не улучшают ситуацию. ELK же не случайно стал так популярен. Если бы уровни работали как задумано, то можно было бы одни взглядом на warn и error логи все понять. На практике же люди суют весь этот поток сознания в ELK и парсят полнотекстовым поиском.

              Сообщения, на которые должен реагировать владелец кода, это то, что влияет на работоспособность системы и ее потребительские характеристики. В этом плане с потребителем софта они едины. Если все работает прекрасно, то никто в эти логи не смотрит. Когда что-то ломается, т.е. происходит ошибка, которую можно залогировать как error, то вот тогда можно читать эту стену логов. И в этой ситуации фильтровать warn нет никакого смысла - все равно нужен полный контекст.

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


              1. nin-jin
                09.01.2022 16:10
                +1

                Простой пример из практики..

                У меня есть модуль для виртуализированного рисования HTML. И этот модуль поддерживает лишь ограниченный набор тегов. Тем не менее ничто не мешает пользователю засунуть туда неподдерживаемые теги и удивляться, что они не будут отображаться. Чтобы подсказать ему в чём дело, я вывожу варнинги типа "этот тег не отображён, так как ещё не поддерживается, добавить поддержку можно воон там".


                1. creker
                  09.01.2022 22:37

                  Я не вижу причин, почему это нельзя отображать как ошибку. Человек засунул в модуль тег, он не отображается. Очевидно, что-то работает некорректно. Это не фатальная ошибка, которая кладет приложения, но все равно ошибка. А вообще, такое можно и фатальной ошибкой сделать и переложить на пользователя заботу о том, чтобы все теги были поддерживаемые.


                  1. nin-jin
                    09.01.2022 23:17

                    можно и фатальной ошибкой сделать

                    А давайте не будем заставлять пользователя страдать за ваши религиозные убеждения?


              1. Borz
                09.01.2022 19:39

                зачем мне warn, что у меня не настроен file service

                Это проблема другого уровня. Должна быть настройка, которая укажет системе, что-то типа "file-service.enabled = false" и тогда никаких warning не должно сыпаться. Либо сыпаться, если какой-то модуль системы хочет таки использовать file service, которого нет и вот тут надо разбираться - почему он хочет то, что отключено, так как возможно этот модуль недонастроен или настроен неверно


                1. creker
                  09.01.2022 22:43

                  Сервис этот отключен по-умолчанию, и я его не включал. Но по какой-то причине система продолжает делать какие-то health чеки и натыкается на это. Тоже самое с ipv6 - система постоянно делает health чеки и рапортует уже прямо ошибку с исключением в питоновском скрипте, что что-то не работает, потому что ipv6 нет. Правильно, потому что я его отключил в настройках гипервизора.

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


  1. Borz
    09.01.2022 10:20

    error выводить как info, что в итоге приведёт к выводу ошибок не в stderr, а в stdout. Норм, да.

    WARN сделал для того, чтобы можно было обратить внимание на ситуацию. Да, может быть в них никто и не "сммоттрит". Но можно повесить метрику и при накоплении критической массы начать разбор ситуаций

    DEBUG/TRACE хороши тем, что выводят "избыточную" информацию, но которая нужна не всегда. Например, если боевой сервис выдал ошибку, то можно такой же входящий запрос перенаправить на отладочный сервис и получить в логах полную картину.


    1. gecube
      09.01.2022 13:46

      Но можно повесить метрику и при накоплении критической массы начать разбор ситуаций

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

      Окей. Возможен кейс, когда у нас стороннее решение, которое мы не можем доработать - там такой подход (логи -> метрики или логи -> алерты) оправдан. Но я вспоминаю каждый раз эти регекспы для парсинга логов и меня просто начинает трясти )))


      1. fougasse
        09.01.2022 14:34

        В стране розовых пони, наверное, всё написано "нормально". Но есть приложения, где никакие метрики из-вне снять нельзя, т.к. они крутятся без доступа "наружу", кроме как через иногда подключающийся клиент. А ресурсов держать внутри окружение для метрик нет. Вот и приходится парсить логи, с чистыми руками и ртом, конечно же.


        1. gecube
          09.01.2022 14:55

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

          Касательно закрытых периметров - ну, никто не мешает в закрытом периметре прокси для метрик держать. Забикс, прометеус все так умеют. Не вижу проблемы.


          1. fougasse
            09.01.2022 19:04

            Я говорю про реальность, когда разве что snmp будет, кроме проприетарного протокола. Клиент заббикса на таргет никто не собирает, да и ресурсов на него не хватит, особенно оперативной памяти и CPU. Никаких терабайтов логов тоже нет, а анализировать нужно.


            1. gecube
              09.01.2022 19:08

              Давайте конкретику. Iot? Метрики собираем. Я такое делал. Что там ещё?

              Клиент заббикса на таргет никто не собирает, да и ресурсов на него не хватит, особенно оперативной памяти и CPU.

              Какой-то ембед?


              1. fougasse
                09.01.2022 20:38

                ARM V7 как часть Stratix 10. Даже IP не всегда есть, не то, что интернет и сервера с Заббиксом.


                1. gecube
                  09.01.2022 21:16

                  ну, это вообще какой-то терминальный кейс :-) Не уверен, что там у вас на стратиксе вообще место под логи будут, кроме как слать их в какой-нибудь сериальный порт ))) Поэтому давайте вернемся в обычный мир розовых поней с голангом )))


      1. nin-jin
        09.01.2022 14:38

        Вас перестанет трясти как только начнёте выводить структурированные логи.


        1. gecube
          09.01.2022 14:50

          Это не решение. Тем более Вам критику по формату tree отгружали. С тем же успехом Вы можете сериализировать логи в любой бинарный формат, раз к нему нужен свой просмотровщик. Ой, мы только что сделали то же самое, что и редхат в journald... На самом деле - если логи - это события, то их и надо обрабатывать как события. С чёткой схемой и типизацией. А если это рандомный поток текста (как это обычно бывает), то все равно ничего толком не сделаешь.


          1. nin-jin
            09.01.2022 16:14
            -1

            Формат tree прекрасно читается и без каких-либо просмотрщиков.


        1. creker
          09.01.2022 15:12

          Не перестанет. От того, что логи летят в JSON или любом другом schema-less формате, не делает их более ясными. Поля все равно произвольные и неизвестные. Т.е. это как бы упрощает работу ELK, который умеет динамически обновлять схему индекса и искать по полям, но мало полезно для оператора, для которого это все равно рандомный поток текста. Можно точно так же создать и сохранить какой-то запрос поиска по этим полям, но завтра выйдет новый релиз софта и запрос сломается, потому что поля другие стали. Еще хуже, этот запрос теперь фильтрует что-то, что может быть нам полезно, но мы этого больше не видим. Т.е. мы вернулись к тем же самым регуляркам.

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


          1. nin-jin
            09.01.2022 16:25

            К любому schema-less легко прикручиваются схемы, если в ниих есть потребность. Давайте не выдумывать несуществующих проблем.

            А вот в schema-full, особенно, если это бинарный формат, вкорячить дополнительные данные порой невозможно.


            1. gecube
              09.01.2022 17:47

              А вот в schema-full, особенно, если это бинарный формат, вкорячить дополнительные данные порой невозможно.

              Не проблема. И в результате мы имеем json с метаданными. В нем поле msg, которое мы сформировали в нашем приложении. И в нем внутри вложенный json.


            1. creker
              09.01.2022 22:29

              К любому schema-less легко прикручиваются схемы,

              Тут люди выше говорят о следовании правилам. Давайте, где есть какой-то стандарт, которому следует большое количество людей, которой стандартизирует схему JSON логов. Я таких не знаю. Ниодна библиотека логирования мне такого не советует.

              Так что проблема есть. В экосистеме логирования нет правил. Поэтому какие бы ни были структурированные логи, это все равно рандомный текст для меня. Мне все равно приходится для каждого приложения писать свои правила обработки. Вещи вроде logstash и fluentd не случайно были придуманы.

              Я поэтому journald упомянул. Там это есть хотя бы в каком-то базовом виде. Это есть в syslog, хотя даже там у меня проблемы были, когда система генерирует syslog сообщения в каком-то кривом формате и на месте имени процесса у меня оказывается кусок даты. В итоге я опять плюнул и стал трактовать все как рандомный текст.


              1. nin-jin
                09.01.2022 23:22

                Вы, похоже, не различаете структурированный, но нестандартизированный, и неструктурированный вывод, что очень меня печалит. Трансляция схем и одного стандарта в другой - плёвая операция.


          1. gecube
            09.01.2022 17:49

            с эластиком все хуже. Вот мы, предположим, поменяли тип старого поля. Все. Ластик перестаёт эти логи принимать, пока мы индекс не пересоздадим. Так что мы в таком решении легко ещё и можем потерять кучу данных и не узнать об этом (!!!). Конечно, когда узнаём - поставим это все на мониторинг. Но в результате выясняется, что под тот же эластик надо выделять целую команду инженеров на поддержку, иначе оно ехать не будет.


            1. creker
              09.01.2022 22:30

              Да, про эту его фишку совсем забыл. С этим мы тоже сталкивались. А про поддержку... Я зарекся ставить в новые проекты ELK/EFK стек. Все новое буду пилить на loki.


    1. creker
      09.01.2022 14:21

      Проблема с warn в том, что очень часто его используют как еще один info уровень. Сообщения не содержат никакой важной информации, система работает. Более того, она так работает из коробки. Такие сообщения либо должны быть error, либо info. Алертинг на это не настроишь, потому оно сыпется постоянно. Система по таймеру делает проверку и каждый раз срет этими логами. Их можно фильтровать, но это костыль, который точно сломается на следующем релизе. Нормальное решение, если бы каждый такой лог можно было скрыть, но такого я тоже не видел.

      Как пример, esxi. Постоянно срабатывает какой-то таймер, который высирает сотню строчек, чтобы сказать, что в кластере все ок. У меня одна нода в кластере за 6 часов выдала 700 warn сообщений - все это дубликаты. Даже error уровень содержит тонну мусора, который говорит о том, что у меня ipv6 выключен. Вот спасибо.


  1. pyra
    09.01.2022 13:10
    +2

    https://github.com/uber-go/zap - это structured logging можно настроить так что каждая строка лога это JSON, тогда например можно фильтровать логи по пользователю или веб запросу, например UserID == "robin", XRay ="$UUID"

    + github.com/lestrrat-go/file-rotatelogs


    1. gecube
      09.01.2022 13:44
      -1

      лучше сразу tracing прикручивать, имхо. Как минимум - Sentry (но это не совсем то), а лучше - Jaeger. Из платных - Dynatrace, Appdynamics. Если один раз попробовал - потом слезть тяжело.