Пользователь
0,0
рейтинг
11 июля 2012 в 15:08

Разработка → Осовремененный Unix Way или pipe в браузер

Наверное, каждый, кому когда-нибудь приходилось следить одновременно за большим количеством окошек с логами, подумывал о переносе некоторых из них на экран планшета или телефона.
А, находясь далеко от компьютера, следить за выхлопом недавно запущенного большого и страшного сервиса?
Конечно, можно поставить ssh клиент на телефон, но это не особо удобно.
Поэтому я решил сделать мини-сервис упрощающий «удалённый» просмотр логов.




Краткое резюме


Сервис cantail.me с открытым исходным кодом, выложенным на github.
Свободный консольный клиент (github). Для простой отправки данных достаточно:
long-runnig-app | tailme

И скопировать ссылку из открывшегося окна браузера. Или можно добавить параметр -s и просто скопировать её из терминала.

Для примера сейчас запущена публикация лога nginx'а командной:
tail -f /var/log/nginx/cantailme.access.log | tailme -s


Установка клиента


В ubuntu 11.10+ приложение можно установить из ppa:
add-apt-repository ppa:nvbn-rm/ppa
apt-get update
apt-get install tailme

В других дистрибутивах можно установить через pip:
pip install -e git+https://github.com/nvbn/cantailme-client.git#egg=tailme

Либо через установочный скрипт:
git clone https://github.com/nvbn/cantailme-client.git
cd cantailme-client
python setup.py install


Под капотом




Реализация клиента очень простая — цикл читающий stdin и отправляющий на сервер новые строчки.
Для предотвращения подмены данных сервер при инициализации сессии отдаёт хеш-идентификатор и «секрет», которые в дальнейшем используются для отправки «строк».

Серверная часть немного сложнее, её можно разделить на 3 условных сущности:
  • http «сервер» занимающийся рендеренгом 2 вьюх;
  • jsonrpc api, с помощью которого консольный клиент инициализирует сессию и отправляет данные на сервер;
  • push сервер для отправки полученных через api строк клиентам в реальном времени.


Взаимодействие между частями системы проходит при помощи RabbitMQ.
Push работает через tornado-sockjs.
Для экономии ресурсов логи загружаются сразу в файл и отдаются через nginx, минуя django.
Для желающих залить /dev/urandom или большие логи раз в 5 минут запускается «суровый» скриптик.

Деплой




В данном случае он нетривиален, но я уже сталкивался с похожей ситуацией. Основные причины выбора такой схемы:
  • нередка ситуация, когда нестандартные порты порезаны, поэтому tornado и django должны висеть на одном стандартном порту;
  • заставить nginx работать нормально с WebSocket'ами проблематично;
  • HAProxy не раздаёт статику;
  • эту схему я успел погонять в продакшене на неэкспериментальных проектах =)


В случае возникновения ошибок пишите багрепорты в трекере для сервера и клиента. Либо в комментариях к этому посту =)

PS с habrastorage произошёл какой-то косяк, перезалил картинки к себе.
Яковлев Владимир @nvbn
карма
73,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

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

  • +3
    Мне нравится идея. Давно думал, что чего-то такого не хватает. Только немного боязно публиковать логи без пароля. Ведь можно случайно или-перебором открыть что-нибудь чужое. А ставить такую связку серверной части не каждый захочет.
    • +3
      Если будет пользоваться популярностью, прикручу https и запароливание.
      • 0
        Хотелось бы какое-нибудь криптование без участия сервера: один ключ указываем в tailme, другой вбиваем в браузере.
  • –10
    Эх… Версию для Windows бы… Вот как раз для nginx нужно =)
    • 0
      Попробуйте вот это завести. Только понадобится cygwin, чтобы tail был в Windows.
      • 0
        Можно отредактировать 2 строчки в tailme и заработает в винде)
  • +3
    Дико круто!
    Надо покопаться в исходниках :) Прям сразу настроение поднял, у меня как раз такая долгоиграющая пластинка запущена =)
  • 0
    Пример (лог nginx) пустой. Chrome 20.0.1132.47
    • 0
      Пробовали подождать секунд 5?
      • 0
        Пару минут ждал.
  • 0
    Спасибо вам за человеческий подход — и под убунты пакет не поленились собрать, и для пипа, и на гитхабе все разложили по полочкам.
    Просьба — впишите argparse в пип-зависимости. А то мне пришлось отдельно ставить.
  • 0
    Спасибо. Отличный сервис. Бывало использовал следующий метод для получения итоговых логов:
    some_app | sendmail -v email@gmail.com
    Но этот способ, конечно, ни в какое сравнение с вашим сервисом не идет.
  • 0
    Для тех кому интересно, могу предложить как на скорую руку это
    можно было бы сделать с помощью xinetd:

    маленький скрипт remote-log:
    #!/usr/bin/env bash tail -f /var/log/messages

    конфиг /etc/xinetd.d/log-stream
    service remote-log { socket_type = stream protocol = tcp wait = no user = root server = /home/romones/remote-log instances = 20 }

    запись в /etc/services
    remote-log 9998/tcp

    рестарт xinetd:
    #lsof -i:9998 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME xinetd 15237 root 5u IPv6 334966 0t0 TCP *:remote-log (LISTEN)

    Работает из браузера на localhost:9998 всё добавляется построчно как надо.

    Но это решение не такое гибкое и элегантное.
    • 0
      Ой, что-то у меня переносы в коде не получились. В первом скрипте tail с новой строки, и в конфиге {arg} = {val} тоже на разных строках, естественно :)
    • 0
      Этот способ пару раз использовал, но тут есть косяк. Если лог стримится минут 10, браузер обрывает соединение.
      Ну и это менее юзерфрендли и без модных вебсокетов =)
    • 0
      Наверное tail -F иначе после ротейта лога tail останется на старом файле.
  • +1
    Я вот на днях сделал pupergrep как замену supergrep от etsy. В браузере мониторит столько логов, сколько скажете (у нас овер 100).
    • 0
      Прикольно, но сложнее. А почему полинг? Для ноды sockjs как-то даже роднее, чем для торнадо.
      • 0
        Для ноды да, но всё забирается за nginx, чтобы тот следил за доступом ко всему добру, а он не умеет иначе, насколько я понял. Сам я только за ws без костылей.

        Насчет сложнее — возможно, просто у нас логи весьма подробные и зачастую нужно что-то подстветить, что-то убрать и т.д. В ясную погоду трейсы смотреть не приходится и они фильтруются, например.
        • 0
          Новый nginx умеет, но там настройка совсем не тривиальное, и вроде оно не особо стабильно.
          И пробовали заменить на haproxy с acl'ами?
          • 0
            На haproxy менять не хочется, всё будет только сложнее. Те же acl проще в node.js держать, раз уж статику ей тоже придётся раздавать за haproxy.

            Проже дождаться стабильный nginx с поддержкой ws. Вообще в планах есть раздача статики через ноду, но как-то не сейчас :)
            • 0
              Нее, совсем не стоит. Пробовали, нода совсем не очень держит статику. Самый рабочий вариант деплоя haproxy + nginx / lighttpd / sinatra (если ruby).
              И даже версии nginx с поддержкой http 1.1 ведут себя совсем не очень в продакшене. Называется пробовали-проходили =)
              • 0
                Логи — вещь для весьма ограниченного числа людей. Тут не будет 3k+ запросов в секунду, как на балансерах. К тому же, статика сразу укладывается в кеш, а при нормальной работе ws будут потреблять 90% запросов.

                Так что раздачу статики из ноды можно потерпеть для простоты деплоя и увеличения участия пользователей в разработке проекта :)
                • 0
                  ws не делает запросов как таковых, а отправить данные с сервера на клиент очень «лёгкая» операция. На «мнини-продакшене» проводил тест, веб-сокеты оказываются легче для сервера, чем статика с лайти =)
  • 0
    В dist.py (local.py) для сервера отсутствует переменная «TORNADO_PORT», с ней заработало, но не совсем, как понимаю.

    root@debi /home/prowl/cantailme-server # ./manage.py runpush
    WARNING:root:Connect error on fd 10: ECONNREFUSED
    ERROR:stormed-amqp:ERROR in on_disconnect() callback
    Traceback (most recent call last):
      File "/usr/local/lib/python2.6/dist-packages/stormed/connection.py", line 142, in on_closed_stream
        self.on_disconnect()
    TypeError: on_closed() takes exactly 2 arguments (1 given)


    Страница создается, но логи не приходят, с cantail.me все ok.
    • 0
      tornado из git?
      И от рута не стоит запускать.
      • 0
        Да, устанавливал по инструкции с помощью pip и requirements.txt, лишь «stormed» на «stormed-amqp» заменил, иначе не находил.
        • 0
          А дистрибутив какой? Я тестил только в ubuntu 10.04 и 12.04
          • 0
            Debian Squeeze, завтра попробую на 12.04.
  • 0
    Кстати говоря, при установке в virtualenv сбоит:

    (trna)gamma:trna mktums$ pip install -e git+https://github.com/nvbn/cantailme-client.git#egg=tailme
    Obtaining tailme from git+https://github.com/nvbn/cantailme-client.git#egg=tailme
      Cloning https://github.com/nvbn/cantailme-client.git to /Users/mktums/.virtualenvs/trna/src/tailme
    Unpacking objects: 100% (26/26), done.
      Running setup.py egg_info for package tailme
        
    Installing collected packages: tailme
      Running setup.py develop for tailme
        
        Creating /Users/mktums/.virtualenvs/trna/lib/python2.7/site-packages/cantailme-client.egg-link (link to .)
        Adding cantailme-client 0.1dev to easy-install.pth file
        Installing tailme script to /Users/mktums/.virtualenvs/trna/bin
        
        Installed /Users/mktums/.virtualenvs/trna/src/tailme
    Successfully installed tailme
    Cleaning up...
      Exception:
    Traceback (most recent call last):
      File "/Users/mktums/.virtualenvs/trna/lib/python2.7/site-packages/pip-1.1-py2.7.egg/pip/basecommand.py", line 104, in main
        status = self.run(options, args)
      File "/Users/mktums/.virtualenvs/trna/lib/python2.7/site-packages/pip-1.1-py2.7.egg/pip/commands/install.py", line 265, in run
        requirement_set.cleanup_files(bundle=self.bundle)
      File "/Users/mktums/.virtualenvs/trna/lib/python2.7/site-packages/pip-1.1-py2.7.egg/pip/req.py", line 1081, in cleanup_files
        rmtree(dir)
      File "/Users/mktums/.virtualenvs/trna/lib/python2.7/site-packages/pip-1.1-py2.7.egg/pip/util.py", line 29, in rmtree
        onerror=rmtree_errorhandler)
      File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/shutil.py", line 249, in rmtree
        onerror(os.remove, fullname, sys.exc_info())
      File "/Users/mktums/.virtualenvs/trna/lib/python2.7/site-packages/pip-1.1-py2.7.egg/pip/util.py", line 46, in rmtree_errorhandler
        os.chmod(path, stat.S_IWRITE)
    OSError: [Errno 1] Operation not permitted: '/Users/mktums/.virtualenvs/trna/build/pip-delete-this-directory.txt'
    
      Storing complete log in /Users/mktums/.pip/pip.log
    Traceback (most recent call last):
      File "/Users/mktums/.virtualenvs/trna/bin/pip", line 8, in <module>
        load_entry_point('pip==1.1', 'console_scripts', 'pip')()
      File "/Users/mktums/.virtualenvs/trna/lib/python2.7/site-packages/pip-1.1-py2.7.egg/pip/__init__.py", line 116, in main
        return command.main(args[1:], options)
      File "/Users/mktums/.virtualenvs/trna/lib/python2.7/site-packages/pip-1.1-py2.7.egg/pip/basecommand.py", line 141, in main
        log_fp = open_logfile(log_fn, 'w')
      File "/Users/mktums/.virtualenvs/trna/lib/python2.7/site-packages/pip-1.1-py2.7.egg/pip/basecommand.py", line 168, in open_logfile
        log_fp = open(filename, mode)
    IOError: [Errno 13] Permission denied: '/Users/mktums/.pip/pip.log'
    
    • +1
      Оно расчитано на linux'ы, судя по логам там что0то другое.
      • 0
        OS X
        • 0
          Сегодня проверял — должно работать
          И тут видно по Operation not permitted, что что-то с правами у вас не то.
          • 0
            Хм, и впрямь… На голом виртэнве все ок…
  • 0
    Есть такое решение github.com/mthenw/frontail

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