Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
390 lines (230 sloc) 9.85 KB


Table of contents


Sageo (prononced Sah-gay-oh) is a rewriting of check_mk_ multisite web GUI.

The Sageo project started with the idea of having a monitoring web GUI that is:

  • Able to browse many sites at a time
  • Easy to maintain
  • Builded with up to date technologies
  • Lightweight

Sageo reimplements one of the most powerfull features of check_mk: the views customization feature.

Sageo offers these advantages over by check_mk multisite:

  • Sageo doesn't use the deprecated apache module "mod_python".
  • Sageo is MVC oriented, that means the content and the business logic is seperated from presentation.

Sageo is compatible with all monitoring plateforms providing a livestatus interoperability like Icinga, Nagios, Shinken, etc.

The main technologies used are:

  • Flask web framework
  • MK Livestatus
  • Twitter Bootstrap
  • LESS
  • Babel



  • View editing
  • Backend multi-columns sorting
  • Frontend multi-columns sorting
  • Multi-columns grouping
  • Backend filters
  • Frontend filters
  • Columns order customizing by drag & drop
  • Layout column number customization
  • Columns linking

Views templates

  • Table aspect
  • Single dataset


  • Snapin development structure
  • Snapin localizable
  • Snapin presentation customized by drag & drop
  • Tactical overview ported


  • Languages preferences

Global application

  • Display easily external content with a framed mode.
  • Localizable
  • Easily web forms creation according to the DB model
  • Content and logic separated from presentation

Upcoming features


  • Views rights management
  • Results pagination
  • Commands execution on objects


  • Snapin preferences saving


  • User privileges
  • Login configuration

Global application

  • Tests


The view "all hosts"

Vue all hosts

The view "all services"

Vue all services

View editing

Édition de vue

Available views list

Liste des vues disponibles



$ sudo aptitude install python-virtualenv


Create you virtual environnement

$ virtualenv env
$ . env/bin/activate

Download the GIT repository

$ git clone
$ cd sageo
$ pip install -r requirements.txt

Install python modules with pip

$ pip install -r requirements.txt

Create the database

$ python


Add your broker adress

$ vim

Look at the configuration example in the file

Each time you change the sites, you must migrate the database because the site filter is an enum database field and will accept only the values it is aware of.

$ python

Compile the LESS files

You need first to install the LESS compiler (LESSC).

For Debian based distribution:

$ apt-get install node-less

Compiling stuff

$ cd app/static/css
$ lessc less/main.less main.css

Start the server

$ python

Open a browser et go to:

The default username and the default password is 'admin' and 'admin' respectively.

Technical documentation

Adding columns for views

Go to the folder "column"

$ cd app/model/columns

You will see several classes named with the prefix "column_painter" and a "" module. A column painter used to obtain a readable data to the user from the raw data from livestatus queries results. This object also stores various properties for a given column.

Look if there is already a "painter column" class that implements the type of column that you want to add. A "column painter" may be generic for multiple columns of the same type. For instance, host_state and service_state are both states and uses the same "column painter" ColumnPainterState. More "column painter" class is generic, there should be more of the parameters passed to the constructor of the class.

To implement a "painter column", look at the structure of the base class ColumnPainter. It specifies that it must be implemented in the concrete class, the (row) get_readable function. Row is the dictionary containing the raw livestatus columns that have been requested.

For columns that does not require conversion to be readable by the user like the host_name, use the "painter" ColumnPainterRaw.

Go to

$ vi columns/

In the file header, import the class "column painter" if it is not already done.


from .column_painter_raw import ColumnPainterRaw

Declare as a constant, the column name.


COL_HOST_NAME = 'host_name'

Store the "painter" in the "painters" dictionnary.


painters[COL_HOST_NAME] = ColumnPainterRaw(COL_HOST_NAME, _(u'Host name'), _(u'Host name'), ['hosts', 'services'])

Restart the server and the new columns will appears in the view related to it datasource.

Adding filters for views

The filters list is not complete yet. We invite you to sumbit some filters.

Go to the folder "filters".

$ cd app/model/filters

You will see several "filter" and a "" module classes. A filter defines a "filter" function to return the text filter for livestatus matching the query filter. A filter also defines "get_col_def" function returning the column definition for the database.

Example of columns definition:

def get_col_def(self):
    return [Column(, Enum('1', '0', '-1'), default=self.default)]

Implement a filter class if these classes are not enough. You can specify a specific form field definition to override the default field definition from WTFORMS-ALCHEMY. It is usefull especially when you some want radio fields for an Enum DB field instead a SelectField. You can see the basic type conversion here:

To override a form field definition, you must set the attribute "form_def" in the init() function. The order of the elements in the list must be the same as the column definition list.

Example of a form field field definition override (we want here to force the usage of radio fields):

self.form_def = [RadioField(choices=[('1',_(u'Yes')),('0',_(u'No')),('-1',_(u'Ignore'))], default=default)]

When you get the filter class you want. Go to

$ vi filter/

In the file head, import the filter class if it is not already done.


from app.model.filters.filter_text import FilterText

Declare as constant, the filter name.

FILTER_HOSTREGEX = 'host_regex'

Store the filter into the filters dictionnary.


filters[FILTER_HOSTREGEX] = FilterText(FILTER_HOSTREGEX, _("Hostname"), _("Search field allowing regular expressions and partial matches"), ["host_name"], OP_TILDE)

Be sure having the required display function for the filter type.

vim app/templates/views/filter_fields.html

Ensure that the templates can show filters correctly. Filters are generics, so it is the filters fields types that will determinate how filter will be displayed.

$ vim app/templates/lib/views.html

Migrating the database, that will add new filters field in the filters table. Go to the projet root directory

$ python

Restart the server and the new filters will appears in the datasource related views.

Adding snapins

A snapin consists of a folder with a python file with the same name inside. This file defines a class that inherits from the base class "SnapinBase." It defines a context method to do the processing and return an object to its use in the template of the snapin.

The template is within a "template" folder. There is an html file with the same prefix as the python file and styles.css file.

To have a multilingual snapin, it takes a translation folter within the snapin file folder. It is then the same structure as the Babel files. Howver, in snapin classn, you must define like in the SnapinAbout, a litle code to get the translation in the current language.

Restart the application, the new snapins will be automatically taken into account.

This is the common hiearchy of snapin:

  • SnapinExample
    • template
      • SnapinExample.html
      • style.css (facultatif)
    • translations
      • ...

Helping us translate Sageo

Sageo is multilanguages with the help of Babel and of FlaskBabelEx, a fork of FlaskBabel.

To contribute to translations, please look the Flask-Babel traduction documentation.

We suggest you the software Poedit to translate.