Как стать автором
Обновить

Комментарии 20

Идея отличная.

Согласен, идея интересная

Про vector слышали?

Там все это можно организовать его средствами.

На мой взгляд основная проблема большого количества данных это не оптимальный способ передачи и хранения этой инфы. Сейчас логи это обычные строки. Причём с очень большим дублированием. Есть очевидный и очень простой способ значительно повысить производительность работы с логам и снизить затраты на хранение - заменить неизменяемые части шаблонами, а изменяемые хранить не в виде строк, а в виде бинарных данных, параметров этого шаблона. Например лог вида "Service Abc is started." сейчас занимает 23 байта при передаче в utf8 и в 2 раза больше в памяти. Если использовать шаблон "Service _ is started." То при хранении и передаче это будет какой то ID шаблона например 2 байта + параметр: строка Abc - 3 байта в utf8. Всего 5 байт. Шаблон может включать сам текст и метаданные для того что бы склеить их в привычные строки только перед их просмотром. Профит - меньше памяти, меньше трафика, быстрее поиск.

Кажется технологии работы с логам застряли где-то в 90х прошлого столетия.

Проблему с очень большим дублированием решает gzip. Если использовать logrotate, то сжатие будет буквально из коробки, при этом будут доступны все привычные способы анализа текстовых файлов. Хранением логов в бинарной форме занимается journald и мне совершенно не кажется, что он быстрее.

Лог вида "Service Abc is started." можно заменить на "h" и получить всего 1 байт, но потеряется основное преимущество лог файла - человекочитаемость. Анализатор логов от одной серии железяк неудобен и со скрипом работает под win11, от другой - размещен в web, а на третьей пакет логов шифруется и может быть разобран только производителем. Туда же идут нечитаемые timestamp и ошибки вида "error 38".

Помимо дублирующейся информации логи хранят ещё и обычную. В этом случае это название сервиса Abc. Так что не понятна ваша мысль.

Если хотите можно хранить логи в денормализованном виде для лёгкости чтения. Но собирать и передавать их так нет большого смысла.

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

Если вы предлагаете выносить это в библиотеку/обработчик - это попытка изобрести zip.

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

Zstandard  (zstd) сжатие позволяет заранее создать словарь. при этом сохраняется возможность писать маленькими кусочками.

??? Создать словарь на основе чего? На основе записей которых ещё нет? Или как-то предугадать то что будет?

Генерируется эталонный лог-файл какой-то программы (без сжатия). На основе его мы создаем словарь (посмотрите документацию по zstd сжатию). После этого мы можем эффективно сжимать новые логи (словарь постоянно хранится на диске и может не меняться). Если новая строка совсем не проходит по словарю она всё равно будет сохранена, просто коэффициент сжатия будет поменьше, вместо 1:8 к примеру 1:3.

То что вы описываете называется структурным логированием. Поддерживается тем же ELK-ом и очень удобно для использования.

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

В Монологе есть хендлер, который реализует подобный подход.

Есть такая пословица "Кабы знал, где упадёшь, соломки бы подстелил". Так вот предложенное решение - это как раз та соломка, которую надо заранее стелить там, где упадёшь (вернее где упадёт приложение). Хотя решение довольно интересное, и на практике иногда действительно знаешь, где упадёшь, так что иногда вполне может пригодиться.

Ещё одна проблема - не факт что Dispose вообще будет вызван (UB, краш, забыли).

Идея интересная, но как мне кажется Sentry делает то же самое

Предположим, что мы смогли реализовать подобный функционал и решили проблему с порядком дат. Также, представим ситуацию, что произошла ошибка, программа стала собирать батч и пришел OOM Killer / ошибка сегментации / админ, случайно нажавший kill -9, тогда получается логов программы нет. В лучшем случае будет неконсистентность данных или упустим что то важное.

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

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

В общем, идея автора интересная, но не жизнеспособная как по мне.

На детальных уровнях логгирования приложение может медленно работать из-за фрагментов типа

if (_log.IsDebugEnabled)
{
   _log.Debug("Input data: " + string.Join(...));
}

А тут автор предлагает по сути всё время держать уровень DEBUG

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

по моему самый спорный момент. Потому что самая плохая ошибка внезапно всё крашит.

Предлагаю несколько другой подход. Мы пишем одновременно в три лога.

1-й лог файл самый подробный и содержит в себе debug, info, warning и error события.

2-й info и выше

3-й warning и выше

А теперь самое интересное: мы устанавливаем максимальный размер каждого лога. К примеру 1-е логи в сумме 50 мегабайт (при достижении 10 мегабайт мы начинаем новый log файл, самый старый стираем, что бы не превышать лимит размера). Аналогично задаем лимиты для 2-го и 3-го лога.

Разумеется, можно сделать 4 лога и в каждый писать только свой уровень (это уменьшит размер, но усложнит анализ логов).

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории