Привет, Хабр!
Недавно возникла необходимость сделать простой и расширяемый монитор использования системы для сервера на Debian. Хотелось строить диаграммы и наблюдать в реальном времени использование памяти, дисков и тп. Нашел много готовых решений, но в итоге сделал скрипт на python + Flask + psutil. Получилось очень просто и функционально. Можно легко добавлять новые модули.

UPDATE: статья исправлена и дополнена с учетом замечаний в комментариях.
Сначала сделаем небольшой файл конфигурации для настройки.
Напишем монитор, который будет по таймеру собирать нужные нам данные.
В примере — свободное место на дисках и доступная память.
И саму модель, которая реализует модули. Сюда можно добавлять любой функционал, позже я добавил еще доступность сервисов в интранет (пинг).
Для построения временных графиков берем данные из монитора (см выше).
Переходим к созданию веб-сервера и делаем шаблон для отображения страницы, который будет использовать данные из модели.
Наконец, добавим скрипт запуска сервера на Flask по адресу из настроек.
Вот и все. Запустив скрипт, можно посмотреть графики и диаграммы.
Весь код, как обычно, на github.
Проверено на windows и linux.
Любые улучшения и пожелания приветствуются.
Недавно возникла необходимость сделать простой и расширяемый монитор использования системы для сервера на Debian. Хотелось строить диаграммы и наблюдать в реальном времени использование памяти, дисков и тп. Нашел много готовых решений, но в итоге сделал скрипт на python + Flask + psutil. Получилось очень просто и функционально. Можно легко добавлять новые модули.

UPDATE: статья исправлена и дополнена с учетом замечаний в комментариях.
Сначала сделаем небольшой файл конфигурации для настройки.
Несколько настроек для монитора
# configuration for server monitor #general info version = 1.0 # web server info server_name = "monitor" server_port = 10000 server_host = "localhost" #monitoring time_step = 1 #s max_items_count = 100 #display fig_hw = 3
Напишем монитор, который будет по таймеру собирать нужные нам данные.
В примере — свободное место на дисках и доступная память.
import threading import time import psutil from conf import config as cfg import datetime mem_info = list() disk_usage = list() def timer_thread(): while True: time.sleep(cfg.time_step) mi = psutil.virtual_memory() if mem_info.__len__() >= cfg.max_items_count: mem_info.pop(0) if disk_usage.__len__() >= cfg.max_items_count: disk_usage.pop(0) di = list() for dp in psutil.disk_partitions(): try: du = psutil.disk_usage(dp.mountpoint) except: continue di.append(du.free / 1024 / 1024) mem_info.append([mi.available / 1024 / 1024]) disk_usage.append(di) def start(): t = threading.Thread(target=timer_thread, name="Monitor", args=(), daemon=True) t.start()
И саму модель, которая реализует модули. Сюда можно добавлять любой функционал, позже я добавил еще доступность сервисов в интранет (пинг).
Для построения временных графиков берем данные из монитора (см выше).
Отображение модулей на странице
import matplotlib matplotlib.use('agg') import psutil, datetime import mpld3 from jinja2 import Markup from conf import config as cfg import platform from matplotlib import pyplot as plt import numpy from lib import timemon from operator import itemgetter def get_blocks(): blocks = list() get_mem_info(blocks) get_disks_usage(blocks) return blocks def get_mem_info(blocks): fig = plt.figure(figsize=(2 * cfg.fig_hw, cfg.fig_hw)) plt.subplot(121) mem = psutil.virtual_memory() labels = ['Available', 'Used', 'Free'] fracs = [mem.available, mem.used, mem.free] lines = list() lines.append(str.format('Avaliable memory: {0} MB',mem.available)) lines.append(str.format('Used memory: {0} MB', mem.used)) lines.append( str.format('Free memory: {0} MB', mem.free)) if psutil.LINUX: labels = numpy.hstack((labels, ['Active', 'Inactive', 'Cached', 'Buffers', 'Shared'])) fracs = numpy.hstack((fracs, [mem.active, mem.inactive, mem.cached, mem.buffers, mem.shared])) lines.append(str.format('Active memory: {0} MB', mem.active)) lines.append(str.format('Inactive memory: {0} MB', mem.inactive)) lines.append(str.format('Cached memory: {0} MB', mem.cached)) lines.append(str.format('Buffers memory: {0} MB', mem.buffers)) lines.append(str.format('Shared memory: {0} MB', mem.shared)) plt.pie(fracs, labels=labels, shadow=True, autopct='%1.1f%%') plt.subplot(122) plt.plot(timemon.mem_info) plt.ylabel('MBs') plt.xlabel(str.format('Interval {0} s', cfg.time_step)) plt.title('Avaliable memory') plt.tight_layout() graph = mpld3.fig_to_html(fig) blocks.append({ 'title': 'Memory info', 'graph': Markup(graph), 'data': { 'primary' : str.format("Total memory: {0} MB", mem.total / 1024 / 1024), 'lines' : lines } }) print( blocks) def get_disks_usage(blocks): num = 0 for dp in psutil.disk_partitions(): fig = plt.figure(figsize=(2 * cfg.fig_hw, cfg.fig_hw)) plt.subplot(121) try: di = psutil.disk_usage(dp.mountpoint) # gets error on Windows, just continue anyway except: continue labels = ['Free', 'Used', ] fracs = [di.free, di.used] plt.pie(fracs, labels=labels, shadow=True, autopct='%1.1f%%') plt.subplot(122) plt.plot(list(map(itemgetter(num), timemon.disk_usage))) plt.ylabel('MBs') plt.xlabel(str.format('Interval {0} s', cfg.time_step)) plt.title('Disk available space') plt.tight_layout() graph = mpld3.fig_to_html(fig) blocks.append({ 'title': str.format('Disk {0} info', dp.mountpoint), 'graph': Markup(graph), 'data': { 'primary': '', 'lines': [ str.format('Free memory: {0} MB', di.free / 1024 / 1024), str.format('Used memory: {0} MB', di.used / 1024 / 1024) ] } }) num = num + 1
Переходим к созданию веб-сервера и делаем шаблон для отображения страницы, который будет использовать данные из модели.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> <title> Server monitor v. {{ script_version }} </title> </head> <body> <div class="container"> <H1> Server information </H1> <H3> <span class="label label-success"> Active since {{ active_since }} ({{ days_active }} days) </span> </H3> <p class="text-info"> {{ system }} {{ release }} {{ version }} </p> </div> {% for block in blocks %} <div class="container"> <H2> {{ block.title }} </H2> <div class="panel panel-default"> <div class="panel-body"> <table> <tr> <td> {{ block.graph }} </td> <td> <div class = "container"> <p class="text-primary"> {{ block.data.primary }} </p> {% for line in block.data.lines %} <p class="text-info"> {{ line }} </p> {% endfor %} </div> </td> </tr> </table> </div> </div> </div> {% endfor %} </body> </html>
Наконец, добавим скрипт запуска сервера на Flask по адресу из настроек.
#!/usr/bin/python3 from flask import * from conf import config as cfg from lib import timemon as tm from lib import info import psutil import datetime import platform # server health monitoring tool app = Flask(cfg.server_name) @app.route('/') def index(): active_since = datetime.datetime.fromtimestamp(psutil.boot_time()) return render_template("index.html", script_version=cfg.version, active_since=active_since, days_active=(datetime.datetime.now() - active_since).days, system=platform.system(), release=platform.release(), version=platform.version(), blocks=info.get_blocks()) print("Starting time monitor for", cfg.time_step, "s period") tm.start() print("Starting web server", cfg.server_name, "at", cfg.server_host, ":", cfg.server_port) app.run(port=cfg.server_port, host=cfg.server_host)
Вот и все. Запустив скрипт, можно посмотреть графики и диаграммы.
Весь код, как обычно, на github.
Проверено на windows и linux.
Любые улучшения и пожелания приветствуются.