Переименование процессов в Python

    Когда пишешь многопроцессное приложение на питоне хочется иметь какой-то максимально простой способ мониторинга за работой отдельных процессов. Я сейчас не говорю про детальные аналитические отчеты на 10 страницах, а про получение минимальной информации о здоровьи и работе каждого процесса: чем он сейчас занят, насколько грузит систему, сколько памяти отожрал и т.п. Примерно как nginx или postgres сообщают о себе: одного взгляда в top либо ps достаточно, чтобы понять что и как делает каждый процесс.
    Осталось разобраться как это можно сделать в питоне на ОС Linux (на примере Debian и FC).


    В поисках решения:
    Увы, решить проблему «одним наскоком» не удалось — какого-то готового решения не существовало. Это было для меня странно: такой развитый язык, огромное коммунити, первые сообщения об успешном запуске в космос переименовании процесса датированы чуть ли не 2003 годом. И вот спустя пять лет еще нет хорошего готового решения. Были ссылки на умершие проекты, рецепты, разнозненные куски кода. Кроме того, выяснилось, что top и ps, которые мне всегда казались братьями-близнецами, имеют разные взгляды на то, откуда надо брать название процесса для показа. А значит, по-хорошему, надо для каждого из них проводить отдельное переименование.

    Анализ исходников показал: чтобы успешно переименовать процесс нужно сделать два действия — заменить его название в argv[0], а так же сделать системный вызов с новым именем. Сделать такое на C — как два байта переслать, а вот на питоне это становится задачкой со звездочкой. К счастью, питон хорошо интегрируется с C и нам нужно сделать библиотечный вызов. Увы, со стандартными средствами типа dl дело не заладилось — оказалось, что эта библиотека стандартна только для 32-битного дебиана, а в 64-битном ее нет даже в расширенных пакетах. Нашелся такой пакет для сусяшки (suse), но, пардон, варить жуткую кашу из разнородных пакетов на своей системе совсем не хочется. Альтернативная либа ctypes (само название которой говорит само за себя), увы, тоже не помогла. Из экзотики могу еще отметить решение на PyInline — компиляция куска С-шного кода в питоновский модуль по ходу выполнения программы с загрузкой этого модуля. Но от такого «интерпретируемого С» волосы встают дыбом! И, как оказалось, не зря — программа захворала. Примерно в половине случаев запуск заканчивался выпадением даже не в traceback, а сразу в кору с вываливанием кишок стека на 3 экрана. Может дело было и не в самом инлайне — просто в объемной программе всегда есть коктейль из модулей, с которыми он мог конфликтовать, а в жизни есть более интересные и важные задачи, чем разгребание этих конфликтов.

    Решение:
    В конце концов меня утомили эти заигрывания С-шным кодом. Если уже и так понятно, что надо писать главную рабочую часть на Сях, то нафик эти костыли и прокладки! Лучше сразу сделать честый С-шный код и дать ему интерфейсы к питону — то бишь сделать такой модуль.

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

    Спасибо, Гвидо! Где можно записаться в армию твоих фанатов? :)

    В итоге все получилось просто и красиво: исходный код ровно на 1 страницу + коротенький Makefile для сборки. После компиляции получается so-файл размером около 7К.

    Использование
    Проще простого:
    >>> import procname
    >>> procname.getprocname() # получить текущее имя процесса
    'python'
    >>> procname.setprocname('Bla-bla test') # дать новое имя процесса — проверьте в top и ps!
    # снова можно посмотреть имя процесса
    >>> procname.getprocname()
    'Bla-bla test'


    Где взять и как собрать?
    Я выложил проект на гугль-код: code.google.com/p/procname
    Скачайте исходники во временную папку, а дальше как обычно:
    $ tar -zxf procname-XX.tar.gz
    $ cd procname-XX
    $ make

    После этого у вас в текущей папке должен оказаться файл procname.so — скопируйте его в папку своей программы либо, если хотите, чтобы либу можно было использовать в любой программе, то в папку /usr/lib/python2.5/site-packages
    Если вместо файла выдаются какие-то ошибки, проверьте есть ли у вас все необходимое. Для сборки потребуется пакет python-devel, make (тот который gnu) и, конечно, компилятор gcc :)
    Скорее всего проблема будет в неверном указании местонахождения заголовочных файлов Python.h и sys/prctl.h. Найдите их поиском и укажите папку в файле Makefile. Если не поможет — пишите сюда будем разбираться вместе.

    Отказ от ответственности:
    Как обычно в таких случаях, данная библиотека предоставляется «как есть». Я не гарантирую ничего: в т.ч. что она у вас заработает, будет работать правильно, или хотя бы соберется. А так же то, что ваш сервер не превратится в Большой Андронный Коллайдер и не поглотит все в радиусе 100 миль.
    От себя добавлю, что либа протестирована на Debian (32- и 64-bit), FedoraCore (все с ядрами ветки 2.6). Я использую либу почти месяц на «боевом» сервере.

    Как насчет других *nix?
    В других unix-ах организовано немного по-другому. В частности во FreeBSD есть специальный системный вызов setproctitle, позволяющий задать имя процесса для отображения в ps. Там же, кстати, указывается на его нестандартность. Впрочем аналог есть в AltLinux. В Debian ситуация непонятная, хотя вроде как Дмитрий из Альтов портировал свою либу, но я не смог ее обнаружить в etch и lenny.

    Как я это использую на практике?
    В моей программе каждый процесс в один момент времени обрабатывает одну задачу. При запуске он первым делом переименовывается, ставя себе в имя нечто вроде номер задачи и статус, примерно так: 'ICd: 7562 — starting'. Далее при каждом важном событии (напрмиер, смена статуса, новая задача, получение сигнала от ОС и т.п.) он снова переименовывается. В итоге я вижу ход обработки каждой задачи, могу своевременно обнаруживать аномалии в потреблении ресурсов, замедлении обработки, повторах и т.п. и вовремя на них реагировать.

    Вывод
    Мониторинг процессов стал приятным занятием — запускаешь top, откидываешься в кресле и наблюдаешь как твои «питошки» радостно вгрызаются в данные :)

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


    Буду рад любым замечаниям, предложениям, идеям.

    P.S. Большое спасибо всем, кто помог в подготовке данной статьи к публикации на Хабре. Без вас она была бы невозможна!
    Метки:
    Поделиться публикацией
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 16
    • +2
      Копирование строки в argv[0] это не самый гуманный вариант изменения имени процесса - можно запросто затереть энвайронмент.
      Для линуксов позже 2.6.9 лучше использовать prctl

      #include <sys/prctl.h>

      prctl(PR_SET_NAME, "hello world");


      Для FreeBSD есть setproctitle.
      • 0
        Спасибо.
        Да писать много в argv[0] не хорошо.
        Сейчас я использую оба метода - и argv[0] и prctl - дело в том, что одного не достаточно, т.к. top и ps берут инфу из разных мест. Выходит, что в одном переименовано, а в другом нет.
        • 0
          Не подскажете во FreeBSD есть метод получения имени процесса?
          В том же линуксовом prctl есть PR_GET_NAME.
          Не хочется ради совместимости выкидывать функцию получения имени.
        • +1
          Вот, хороший пример отличной статьи. Спасибо, даже не смотря на то, что мне пока такая библиотека не нужна, читать было интересно и позновательно — в избранное.
          • 0
            Спасибо за добрый отзыв!
            Но может, есть какие-то пожелания к будущим статьям? Делать акцент на каких-то определенных аспектах?
          • 0
            Сказать просто нечего :)
            • +1
              Предложили перенести в тематический блог.
              • 0
                Вопрос автору: а почему сырой make, а не стандартные distutils?
                • 0
                  Пока все немного сыровато, и для большей гибкости сборки я решил использовать низкоуровневые средства, где я могу четко контролировать процесс сборки, какие инклуды берутся, опции компилятора и т.п. Конечно, это не универсально, для установки пользователям практически наверняка придется править Makefile.
                  В дальнейшем, когда библиотека окончательно созреет, я думаю перейти на использование distutils, чтобы пользователю на любой системе было легко и удобно ее ставить.
                • 0
                  Все намного проще ./my_script.py
                  • 0
                    Пробовали так запускать?
                    Не везде будет выглядеть как my_script, где-то будет просто написано python.
                    А как быть с процессами-потомками? Если, например, у меня многопроцессный демон, то всего процессы будут называться одинаково.

                    Кроме того, основной упор в статье на динамическое переименование — т. е. в процессе выполнения. Я это использую как очень простое и наглядное средство мониторинга.
                    • 0
                      Всегда так запускаю, все видно.
                      Согласен треды не видны, но если я не ошибаюсь их вообще не видно как отдельные процессы.
                      • 0
                        Я именно про процессы, а не потоки.
                        У меня это выглядит примерно так:
                        ~$ ps
                        owner 28813  0.0  1.4  18808  7660 ?      S    Oct07   0:54 XXd: master process
                        owner 28924  0.0  0.0    150   0 ?        S    13:07   0:00 XXd: task 150 
                        owner 28928  0.0  0.0      0   0 ?        Z    13:07   0:00 [XXd: sync] <defunct>
                        owner 28929  0.0  0.0    200   0 ?        S    13:07   0:00 XXd: task 839 
                        
                  • 0
                    code.google.com/p/py-setproctitle/

                    более-менее кроссбраузерно, под маком меняет имя в ps, в top остаётся прежним python
                    • 0
                      кроссплатформенно, блин.
                      • 0
                        Спасибо. Интересная вещь.

                        Да, в BSD есть некоторые особенности. Я поэтому не стал делать версию под BSD и мак, т.к. в наличии не было их.

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