21 апреля в 19:39

slit — новое слово в мире PAGERов, либо как тратить меньше времени на просмотр логов

Так уж вышло, что мне регулярно приходится просматривать много логов. Одно радует, не так много как у людей работающих вместе со мной у которых порой это основная работа. Логи эти не лежат в в какой либо централизованной системе, а хранятся в s3 и смотрим мы их скачивая с перенаправлением вывода в less.

less установлен у всех, все привыкли с ним работать, знают о базовых вещах, как поиск вперед-назад, фильтрация по &, переход в конец(G) файла, переход в начало(g) и так далее.

А так же, все уже смирились с тем, что в любой момент, при добавлении фильтра less может подвиснуть на неопределенный срок, выводить по строчке в 5 секунд и так далее. В конечном счете, особенно при считывании логов с stdin — приходится быть аккуратным. Фильтр может сработать, а может и не сработать.

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

Под катом демо (gif 2.2mb) и немного истории.

Демо (2.2mb):


Основных претензий к less было 3:

1) Фильтр может подвести в любой момент;
2) Фильтр в принципе работает достаточно медленно, особенно с stdin, особенно при логах > 5MB;
3) Невозможно добавлять несколько фильтров.

Поискав на просторах сети — понял что ничего нет. Есть один «лог навигатор» — но, не интуитивен, много лишнего, а то что нужно очень неудобно.

Приступив к написанию своего PAGER-a на Go — в первую очередь принялся сравнивать различные подходы.

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

Все оказалось не так банально, на 50мб файл, с построчным его разбиением, распознованием контрольных символов для отделения текста от цвета, выделением памяти под получившиеся данные(отдельно информация о цветах, отдельно текст для быстрого поиска в тексте) — уходило больше времени, чем если просто все считывать, разбивать, искать, но не выделять память под хранение.

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

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

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

В целом, поиск, фильтрация, в том числе многоуровневая — получилось намного быстрее, чем в less-е и намного стабильнее. Примерно раза в 4 простой поиск, разница в фильтрации достигает бесконечности, так как less может просто повиснуть. Но даже если нет — то там уже на порядок

К слову о киллер-фичах


Многоуровневые фильтры

  • & — пересечение с предыдущей выборкой. Т.е то же самое что в less, но с учетом всех предыдущих фильтров
  • + Добавить совпадения к выборке
  • — Исключить совпадения из выборки

Последовательность этих фильтров поможет быстро оставить на экране то что нужно.

Также, для более детального изучения активно помогут:

  • U(shift+u) — убрать последний фильтр
  • = — убрать все фильтры
  • C(shift+c, Context) — временно отключить все фильтры, позволяет увидеть все что было после данной строки, данной строкой считается первая на экране

Еще одна полезная возможность:

Shift+K — Keep. Позволяет указать кол-во символов с начала строки, которые будут отображаться при горизонтальном сдвиге экрана. Таким образом можно зафиксировать время, hash коммита итд
Можно либо ввести кол-во, либо стрелками вверх-вниз корректировать кол-во зафиксированных символов.

— В основном горячие клавиши следуют less-у
— Поиск-фильтры сохраняют истории между сессиями. Пока что нет поиска по ctrl+r, это в планах.
— Файлы (пока-что) можно просматривать только по одному либо с stdin-a
— Если slit запущен с перенаправлением вывода — то входящий поток будет попросту перенаправлен, без какой либо логики, аналогично cat и less
— Активно протестировано на linux, osx, немного на windows, совсем не тестировалось на freebsd.

Собрать под него собрал, но проверить не на чем. По идеи должно работать

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

Есть еще ряд планов:

— Добавить переключение чувствительности к регистру. На данный момент только регистро-зависимый поиск;
— Добавить переключение типа поиска (regex/plain/extended glob);
— Добавить меню фильтров, для обзора того что есть на данный момент с выборочным удалением-отключением;
— Добавить поддержку нескольких файлов. Для начала с переключением между ними как в less;
— CTRL+R поиск по истории;
— Удаление подстроки из каждой строки, для удаления шума, без удаления самих строк;
— Прямой вывод в терминал если текст меньше экрана(аналог флага -F в less-e), пожалуй с поддержкой -F из переменной окружения LESS.

Что под вопросом:
— Считывать весь stdin либо нет? Лично мне это здорово помогает, что он весь считывается еще до того, как я решил что мне это нужно. Но обычно PAGER-ы этого не делают.
— неХитрые возможности по работе с временем, т.е распозновать timestamp-ы и давать возможность по ним фильтровать. Не знаю нужно ли это кому либо в логах

Что обязано остаться несмотря на добавление возможностей:
— Забирать не больше одной строчки с терминала
— На открытие файла не должно тратиться больше времени, чем в случае с less-ом

И немного о Go


Это мой второй проект на Go, первый был тут.

Отсутствие различного функционала, вроде пресловутых generic-ов, порой необходимость реализовывать казалось бы банальные вещи (atomic boolean) — иногда расстраивает. На python я пишу намного больше, но каждый раз притрагиваясь к go я на самом деле радуюсь ограничениям которые на меня наложили :)

Но больше всего меня радует экосистема. О ней почему то часто забывают должным образом упомянуть, сравнивая либо ругая язык. Возможно язык замедляет написание, до момента нажатия кнопки «run» первый раз. После нее go стремительно вырывается вперед.

1) go build/run/install --race
Приложение будет бежать в режима поиска race condition, обращения к данным из разных потоков без синхронизации. Это на самом деле очень здорово помогает отловить баги, которые достаточно сложно отловить. И порой понять, что зря решил пойти легким путем и передать указатель, а не добавить дополнительный уровень общения между частями приложения через потоки

2) net/http/pprof — это прекрасно. Простой импорт, регистрация локального порта и при возникновении дедлока можно зайти через браузер на выбранный порт и посмотреть всю информацию о goroutine-ах которые сейчас бегут

3) Кросс-компиляция. Об этом сказано конечно больше, но каждый раз не перестает радовать. Что не нужно танцевать с бубном, ставить дополнительные зависимости — оно просто работает

4) Goglang, тут спасибо Jetbrains, что собрали все воедино, опять таки, не нужно танцевать с бубном, а также как и в случае с Pycharm, продолжаю работать в схожей среде, с vim mode, автоимпортом, авто go get, объявлением методов и так далее.

Перед очередным выбором языка, сравнил как обстоят дела у некоторых других восходящих языков и стало очевидно, им еще есть куда расти…

И о главном, где брать:

Если у вас уже настроено окружение Go, то лучше всего просто собрать:

go get github.com/tigrawap/slit

Если предпочитаете готовые бинарники, то со странички релизов.

И вопрос в студию, хотелось бы как то уведомлять пользователей о том, что есть более новая версия. Неприятно, в случае если я делаю релиз, вдруг замечаю ошибку, через 5 минут выпускаю новый релиз, но тот уже скачали. Какие есть варианты о ненавязчивом но понятном уведомлении?

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

Так же рад идеям что стоит улучшить-добавить. Но все не обещаю :)
Anton Bykov @TigraSan
карма
19,0
рейтинг 0,0
Пользователь
Похожие публикации
Самое читаемое Разработка

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

  • 0
    Понравилось. Поставил дежурным пейджером. Хочется man.
    • 0
      Спасибо
      man — точно, забыл поставить первым местом в списке планов :)
      Но оно там есть
  • 0
    а может ли он работать как less в режиме tail?
    в less активируется нажатием F
    • 0

      Пока нет, повторное нажатие G подгрузит все новое с учётом фильтров

    • 0
      Добавлена поддержка флага запуска -f, чуть позже добавлю и опцию включить после запуска
      • 0
        Надо будет посмотреть
        Спасибо!
  • 0

    Идея хорошая, мне тоже приходится смотреть логи. Но ваше приложение, при попытке открыть лог размером 7 Гб (это всего за 3 часа работы), начало кушать 100% CPU и отъело кучу памяти, пока не было убито. У less же навигация по такому логу не вызывает затруднений.

    • 0

      Просто при попытке открытия? Посмотрю, несколько странно, но в любом случае, фильтры на 7gb без расхода памяти и нагрузки cpu это мистика, поэтому я пока не брал в расчёт очень большие файлы, обычно всюду логротейт


      Но виснуть на старте это баг. Буду смотреть

      • 0

        Нет, не просто. Еще нужно стрелочку вниз или page down нажать.

        • +2
          Сравнил только что 7GB файл less и slit

          Оба открывают мгновенно :)
          Но у меня с небольшой задержкой после чтения начинается считывания файла до конца (by design)

          И оно блокирует. (not by design, издержки борьбы с тем что понаподсказывал race detector)
          В любом случае, что происходит — считывается файл до конца.

          Для перехода в конец less тоже считывает до конца.
          В этом плане — если цель перейти в конец файла, то на 7ГБ файле у меня получилось 2 минуты с less, 25 секунд с slit

          То что навигация вышла блокируемая во время разметки файла — это бага. Буду править

          Но после загрузки такого большого файла, если начать фильтровать и оставить скажем 100 записей из 7GB файла — там все же будут очень существенные(некомфортные) задержки
          Но передвигаться поиском — все же значительно быстрее чем с less

          Тут еще свою лепту (в плане потребления памяти) может внести средний размер строки, так как храню оффсет каждой строки. То есть как минимум 2 x int * num_of_lines (map)

          Так же, сравнил 64bit и 32bit сборки (на 64 bit системе, другие еще живы?) — 64bit работает намного стабильней с большими файлами.
          Я бинарники собирал только 32bit, так как они меньше и предполагал(неверно, почему не совсем понимаю) что будут потреблять меньше памяти.

          Я сейчас добавлю на github сборку 64bit, скажите как файлик себя ведет. Я ожидаю задержку секунд 20-60 (в зависимости от cpu, диска) — но потом вполне шустрая навигация

          Кстати, на какой это платформе и какая в среднем длинна строки? Либо кол-во строк :)

          • 0
            добавил linux/amd64 и darwin/amd64
          • +1
            А зачем считывать все при перемещении в конец? Если речь про обычный файл, то делаем lseek на -n байт от конца и парсим строки. Если недостаточно — еще откатываемся назад. Это сложнее, конечно, но быстрее работает. Меня в less это убивает — очень долго в конец переходит…
            • 0
              Я это уже изменил в последнем релизе, переход мгновенный, строчки считаются независимо
            • 0
              Меня в less это убивает — очень долго в конец переходит…

              Переходит-то он шустро, а потом считает строки. Долго считает, т. к. для того, чтобы посчитать количество строк в файле его надо пройти целиком.


              Но ctrl+c позволяет остановить этот процесс.

              • 0
                К слову делает он это крайне неэффективно…

                У меня вышло примерно 7 секунд на 1GB лог против ~20 с less-ом. И как уже писал выше — теперь это необязательно и не нужно нажимать отмену, считает себе и считает :)
  • 0
    Скажите пожалуйста, а вы не рассматривали возможность агрегации логов? Думаю Вам и Вашей команде было бы намного удобнее работать в браузере, через какой-нибудь ELK.
    • 0
      Рассматривали, «скачивать» с s3 звучит сложнее чем на самом деле
      Обычно это как — есть тест (который может бежать 2-120 часов на 10-очень много машин).
      Он генерирует n-ое колво логов. Десятка два по каждой машине, несколько файлов от основного процесса теста. Очень редко нужно смотреть одновременно несколько файлов, переключаться да — для этого есть свой интерфейс навигации логов по ID теста(в консоли), при открытии идет в пейджер
      В сам этот интерфейс попадают по клику на линк в Jira. Ну либо в ручную простую команду запустить. В целом у нас все консоль предпочитают :)

      Держать огромный кластер elasticsearch это просто расточительно, особенно когда совершенно не нужно искать по всем тестам сразу. А так в s3 и быстро, и дешево и надежно, без дополнительной головной боли поддержки.
  • 0

    Вчера на Reddit про него прочитал :-)


    А если по существу, у Log Navigator есть одно главное преимущество: аггрегация нескольких логов.
    Например, с нескольких машин в кластере.
    И при этом он ещё умеет тот самый "логротейт" распаковывать автоматически.

    • 0
      Я специально не стал в этом посте комментировать свое видение имени, чтобы не замыливать взгляд хаброжителей и посмотреть на местную реакцию :)

      Я не сомневаюсь что весь навороченный функционал который там есть кому то нужен
      Но мне как то попроще хотелось, чтоб «как less, только лучше». Плюс именно то, что хотел — там нет (удобного управления фильтрами. Там убрать фильтр это как увидевшему vim первый раз выйти из него )

      Несколько файлов однозначно будет, и видимо прийдется в нескольких режимах.
      1) как в less — переключение
      2) Как в навигаторе — аггрегация.
  • 0
    Скажите пожалуйста, а Вы не рассматривали возможность агрегации логов? Думаю Вам и Вашей команде было бы намного удобнее работать в браузере, через какой-нибудь ELK.
  • 0

    Какие именно варианты вы рассматривали и почему они не подошли?

  • 0
    peco?
    • 0
      Интересная утилитка, но для логов подходит слабо
  • +3
    Правильно ли я понял, что slit загружает весь файл в память? У меня типичный размер логов от сотни мегабайт до нескольких гигабайт. При этом часто пользуюсь less на продакшене и хорошо себя чувствую (как и сервер). Но использую только поиск по regexp. Переход в конец файла — достаточно быстрый (не знаю, где вы вычитали, что для это less загружает весь файл), тормозит только подсчёт количества строк который отменяется по ctrl-с.
    Для фильтрации мне всегда было удобнее использовать cat | grep или специализированные средства вроде graylog.
    • 0
      Про весь файл — нет, не так
      Он весь считывается, но не хранится. Хранятся оффсеты по номеру строки.
      Но видимо буду менять это поведение и прыгать в конец не зная какая это строка, попутно в фоне считая сколько же их есть на самом деле. Подход который сейчас удобен для файлов этак до 200м, все что выше — уже не комильфо. Как по начальному времени перехода в конец, так и отжираемой памяти

      " cat | grep или специализированные средства вроде graylog"
      Цель как раз в том что бы сделать это самое специализированное средство, но в консоли. Само собой всегда будут use case-ы когда какое либо решение основанное на БД подходит лучше. БД нужно настроить. она должна хранить в себе терабайты памяти, все это нужно поддерживать, а любой лог который пришел с нового источника сам по себе мгновенно там не появится
      cat/grep — это боль, хотелось менять фильтры не отходя от кассы. Боль через которую и сам прошел, вместо прямого открытия из stdina — сохранял в файл, потом греп-лесс, поменять греп-лесс, итд
      Но само собой, если вы не ощущаете необходимости, значит оно вам и не надо :)

      На самом деле, должен сказать, что я удивлен что это достаточно частое явление — хранение гигабайтных логов. Всегда полагал что общепринятая практика — ограничивать каждый файл этак по 50-100 мб размером
      • +1
        На самом деле, должен сказать, что я удивлен что это достаточно частое явление — хранение гигабайтных логов. Всегда полагал что общепринятая практика — ограничивать каждый файл этак по 50-100 мб размером

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

      • 0
        Спасибо за разъяснение. Файлы от сотен МБ и несколько ГБ — это лог за один день, при этом ещё не всегда самые подробный. Всё зависит от нагрузки.
        Из консоли мне часто не хватает (или я не умею) следующего — искать в диапазоне времени (например от 10 часов до 11) и часто ещё с подзапросом. На больших файлах получается большой оверхед на поиск по всему файлу несколько раз. Наверно тоже однажды соберусь и напишу свой велосипед.
  • +1

    Уберите своё "небольшое" демо под кат. То, что картинка в спойлере не значит, что она не грузится. А мобильный интернет не очень рад таким картинкам.

    • 0
      Был уверен что не грузится, убираю
  • +2
    Пока что думаю лезть в сеть не раньше, чем раз в час и при запуске, пока не будет произведено какое либо действие показывать сообщение в навигационной панеле. Может будут более элегантные идеи.
    Так же рад идеям что стоит улучшить-добавить. Но все не обещаю :)

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

  • 0
    Простите я бы хотел попробовать ваш тул. Но пока мы логим в CloudWatch только и смотрим там ( Хватает, но те кто привыкли к копаться в логах недовольны...)
    Не посоветуете что-то не тормозящее что может выкичивать из CloudWatch напрямую или переброс в S3 это стандартных подход к вопросу? Если да то как это делают?

    • 0
      А родной aws cli сильно тормозит? Через него можно получить логи в json формате, на ходу можно pipe-ить в читалку json-a и оттуда уже пайпить в slit либо куда душа пожелает

      Плюс есть куча всяких сервисов, предоставляющие syslog service, к ним можно направлять логи напрямую если речь идет о ECS и смотреть уже там.
      Дороговато они только выходят, если данных много, но например — papertrail
      • 0
        А родной aws cli сильно тормозит? Через него можно получить логи в json формате, на ходу можно pipe-ить в читалку json-a и оттуда уже пайпить в slit либо куда душа пожелает

        Месяца 3 назад бегло пробовал. Да тормозило сильно…
        Но можно посерьезнее постмотреть и хитро пайпить… это верно.

        papertrail

        да именно к нему присмариваюсь в часном проекте… Но на фирме там разные сложные констрейны с банковскими клиентами. так просто уйти в следующий клауд сервис да еще с логами не реально пока ;))
  • 0

    Про multitail не слышали?

    • 0
      дикий интерфейс, и это как бы tail. По описанию фич может показаться что там все ок. Но нет :)
  • –1
    У меня лажа з запуском. Тоесть с ехе, ни 64, ни 86, не запускается, вылетает командное окно, и все, гейм овер. Не понимаю в чем проблема…
    • +1
      Это не навигатор файлов, нужно работать в консоли
      либо slit logfile.log, либо pipe из другой команды
      • 0
        Либо я не понял вопроса :)
        • 0
          Ааааааа, я понял, теперь понял. Спасибо за помощь.
  • +1
    Залил новый релиз
    — улучшена работа с большими файлами
    — Так же с большими файлами теперь нормально должна работать и x86 и amd64 версия
    — Счетчик линий теперь не блокирует, переход в конец мгновенный
    Карту оффсетов больше не храню, потребление памяти должно быть минимально

    Но в любом случае, если фильтры должны найти 300 строчек из 7ГБ — это не будет быстро… Но в плане того, что поиск блокируем — планирую улучшить, чтоб хоть отменить неудачный фильтр можно было и не ждать
    • 0
      Случайно залил с дебаг-пакетами, релиз убрал, через минуту обновлю.
  • +1
    Обновил, 1.1.0 (не фанат версий начинающихся с 0.0000)

    — Добавлена поддержка RegEx, переключение между режимами поиска по CTRL + /
    — И добавлен флаг запуска --version, для грамотных багрепортов

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