Browse Source

new addon: server_monitoring

This module allows in-database logging of some statistics in order to monitor
the health of an openerp instance.

Database indicators are logged (number of rows, table size, number of reads,
number of updates...), with a cron running each week by default. This cron
needs to be activated after the module is installed.

Some process indicators are logged (cpu time, memory) together with information
about the different XMLRPC calls made to the server (user, model, method).

Two crons are provided to cleanup old logs from the database.

The logs are available through the menu Reporting -> Server Monitoring.
pull/39/head
unknown 11 years ago
committed by Alexandre Fayolle
parent
commit
2e1b50a3a4
  1. 86
      server_monitoring/README.rst
  2. 21
      server_monitoring/__init__.py
  3. 63
      server_monitoring/__openerp__.py
  4. 47
      server_monitoring/data/ir_cron.xml
  5. 445
      server_monitoring/i18n/server_monitoring.pot
  6. 26
      server_monitoring/models/__init__.py
  7. 30
      server_monitoring/models/field_types.py
  8. 38
      server_monitoring/models/ir_cron.py
  9. 213
      server_monitoring/models/server_monitor_database.py
  10. 244
      server_monitoring/models/server_monitor_process.py
  11. 8
      server_monitoring/security/ir.model.access.csv
  12. 64
      server_monitoring/tests/test_monitor_database.yml
  13. 28
      server_monitoring/tests/test_monitor_process.yml
  14. 11
      server_monitoring/views/menu.xml
  15. 92
      server_monitoring/views/server_monitor_database.xml
  16. 91
      server_monitoring/views/server_monitor_database_table_activity.xml
  17. 43
      server_monitoring/views/server_monitor_model_row_count.xml
  18. 44
      server_monitoring/views/server_monitor_model_table_size.xml
  19. 92
      server_monitoring/views/server_monitor_process.xml

86
server_monitoring/README.rst

@ -0,0 +1,86 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:alt: License: AGPL-3
=================
server monitoring
=================
This module allows in-database logging of some statistics in order to monitor
the health of an openerp instance.
Database indicators are logged (number of rows, table size, number of reads,
number of updates...), with a cron running each week by default. This cron
needs to be activated after the module is installed.
Some process indicators are logged (cpu time, memory) together with information
about the different XMLRPC calls made to the server (user, model, method).
Two crons are provided to cleanup old logs from the database.
Configuration
=============
To configure this module, you need to:
* Settings -> Scheduled Actions and tune the cron tasks
Usage
=====
Just install the addon in your instance. You will be able to access the logs
under Reporting -> Server Monitoring.
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/149/7.0
For further information, please visit:
* https://www.odoo.com/forum/help-1
Known issues / Roadmap
======================
* Not tested under other platforms than Linux
TODO / WISH list:
* visualization
* export
* check if we can / wish to log session id
* check if we can log pooler state (whatever that is...)
* check if we can log HTTP status
* enhance group by for process logs.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/server-tools/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed feedback
`here <https://github.com/OCA/server-tools/issues/new?body=module:%20server_monitoring%0Aversion:%207.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Credits
=======
Contributors
------------
* Alexandre Fayolle <alexandre.fayolle@camptocamp.com>
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit http://odoo-community.org.

21
server_monitoring/__init__.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Alexandre Fayolle
# Copyright 2014 Camptocamp SA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import models

63
server_monitoring/__openerp__.py

@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Alexandre Fayolle
# Copyright 2014 Camptocamp SA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
{
'name': 'Server Monitoring',
'version': '0.1',
'category': 'Tools',
'depends': ['base',
],
'author': 'Camptocamp, Odoo Community Association (OCA)',
'license': 'AGPL-3',
'description': """
Server Monitoring
=================
This module allows in-database logging of some statistics in order to monitor
the health of an openerp instance.
Database indicators are logged (number of rows, table size, number of reads,
number of updates...), with a cron running each week by default. This cron
needs to be activated after the module is installed.
Some process indicators are logged (cpu time, memory) together with information
about the different XMLRPC calls made to the server (user, model, method).
Two crons are provided to cleanup old logs from the database.
The logs are available through the menu Reporting -> Server Monitoring.
""",
'data': [
'views/menu.xml',
'views/server_monitor_database_table_activity.xml',
'views/server_monitor_database.xml',
'views/server_monitor_model_row_count.xml',
'views/server_monitor_model_table_size.xml',
'views/server_monitor_process.xml',
'data/ir_cron.xml',
'security/ir.model.access.csv',
],
'test': [
'tests/test_monitor_process.yml',
'tests/test_monitor_database.yml',
],
'installable': True,
}

47
server_monitoring/data/ir_cron.xml

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<record forcecreate="True" id="ir_cron_monitoring_action" model="ir.cron">
<field name="name">Database monitoring</field>
<field eval="False" name="active"/>
<field name="user_id" ref="base.user_root"/>
<field name="interval_number">7</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall"/>
<field eval="'server.monitor.database'" name="model"/>
<field eval="'log_measure'" name="function"/>
<field eval="'()'" name="args"/>
<field name="priority" eval='100'/>
</record>
<record forcecreate="True" id="ir_cron_monitoring_process_cleanup_action" model="ir.cron">
<field name="name">Process monitoring cleanup</field>
<field eval="True" name="active"/>
<field name="user_id" ref="base.user_root"/>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall"/>
<field eval="'server.monitor.process'" name="model"/>
<field eval="'cleanup'" name="function"/>
<field eval="'(30,)'" name="args"/>
<field name="priority" eval='500'/>
</record>
<record forcecreate="True" id="ir_cron_monitoring_database_cleanup_action" model="ir.cron">
<field name="name">Database monitoring cleanup</field>
<field eval="True" name="active"/>
<field name="user_id" ref="base.user_root"/>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall"/>
<field eval="'server.monitor.database'" name="model"/>
<field eval="'cleanup'" name="function"/>
<field eval="'(365,)'" name="args"/>
<field name="priority" eval='500'/>
</record>
</data>
</openerp>

445
server_monitoring/i18n/server_monitoring.pot

@ -0,0 +1,445 @@
# Translation of OpenERP Server.
# This file contains the translation of the following modules:
# * server_monitoring
#
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 7.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-04-10 10:31+0000\n"
"PO-Revision-Date: 2014-04-10 12:33+0200\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_process_cpu_time
#: field:server.monitor.process,cpu_time:0
msgid "CPU time"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_table_activity_read_cache_reads
#: field:server.monitor.model.table.activity.read,cache_reads:0
msgid "Cache reads"
msgstr ""
#. module: server_monitoring
#: view:server.monitor.process:0
msgid "Class count"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_process_class_count_ids
#: field:server.monitor.process,class_count_ids:0
msgid "Class counts"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_class_instance_count_name
#: field:server.monitor.class.instance.count,name:0
msgid "Class name"
msgstr ""
#. module: server_monitoring
#: model:ir.ui.menu,name:server_monitoring.server_monitor_database_table_activity_read_menu
msgid "DB Reads"
msgstr ""
#. module: server_monitoring
#: model:ir.actions.act_window,name:server_monitoring.server_monitor_database_table_activity_read
#: model:ir.actions.act_window,name:server_monitoring.server_monitor_database_table_rows
#: model:ir.actions.act_window,name:server_monitoring.server_monitor_database_table_size
#: model:ir.ui.menu,name:server_monitoring.server_monitor_database_table_activity_update_menu
#: model:ir.ui.menu,name:server_monitoring.server_monitor_database_table_rows_menu
msgid "DB Rows"
msgstr ""
#. module: server_monitoring
#: model:ir.ui.menu,name:server_monitoring.server_monitor_database_table_size_menu
msgid "DB Table Size"
msgstr ""
#. module: server_monitoring
#: model:ir.actions.act_window,name:server_monitoring.server_monitor_database_table_activity_update
msgid "DB Updates"
msgstr ""
#. module: server_monitoring
#: model:ir.actions.act_window,name:server_monitoring.server_monitor_database_info
#: model:ir.ui.menu,name:server_monitoring.server_monitor_database_menu
msgid "Database Info"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_table_activity_update_num_delete
#: field:server.monitor.model.table.activity.update,num_delete:0
msgid "Deletes"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_table_activity_read_disk_reads
#: field:server.monitor.model.table.activity.read,disk_reads:0
msgid "Disk reads (heap blocks)"
msgstr ""
#. module: server_monitoring
#: view:server.monitor.model.row.count:0
#: view:server.monitor.model.table.activity.read:0
#: view:server.monitor.model.table.activity.update:0
#: view:server.monitor.model.table.size:0
#: view:server.monitor.process:0
msgid "Group By..."
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_table_activity_update_idx_scan
#: field:server.monitor.model.table.activity.update,idx_scan:0
msgid "Idx scans"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_database_info
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_process_info
#: view:server.monitor.database:0
#: field:server.monitor.database,info:0
#: view:server.monitor.process:0
#: field:server.monitor.process,info:0
msgid "Information"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_table_activity_update_num_insert
#: field:server.monitor.model.table.activity.update,num_insert:0
msgid "Inserts"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_class_instance_count_count
#: field:server.monitor.class.instance.count,count:0
msgid "Instance count"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_class_instance_count_measure_id
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_row_count_measure_id
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_table_activity_read_measure_id
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_table_activity_update_measure_id
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_table_size_measure_id
#: field:server.monitor.class.instance.count,measure_id:0
#: field:server.monitor.model.row.count,measure_id:0
#: field:server.monitor.model.table.activity.read,measure_id:0
#: field:server.monitor.model.table.activity.update,measure_id:0
#: field:server.monitor.model.table.size,measure_id:0
msgid "Measure"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_process_memory
#: field:server.monitor.process,memory:0
msgid "Memory"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_process_method
#: field:server.monitor.process,method:0
msgid "Method"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_process_model
#: field:server.monitor.process,model:0
msgid "Model"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_database_table_nb_row_ids
#: field:server.monitor.database,table_nb_row_ids:0
msgid "Model row counts"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_database_table_activity_read_ids
#: field:server.monitor.database,table_activity_read_ids:0
msgid "Model table read activity"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_database_table_size_ids
#: field:server.monitor.database,table_size_ids:0
msgid "Model table size"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_database_table_activity_update_ids
#: field:server.monitor.database,table_activity_update_ids:0
msgid "Model table update activity"
msgstr ""
#. module: server_monitoring
#: view:server.monitor.database:0
msgid "Nb rows"
msgstr ""
#. module: server_monitoring
#: view:server.monitor.process:0
msgid "PID"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_process_pid
#: field:server.monitor.process,pid:0
msgid "Process ID"
msgstr ""
#. module: server_monitoring
#: model:ir.actions.act_window,name:server_monitoring.server_monitor_process_info
#: model:ir.ui.menu,name:server_monitoring.server_monitor_process_menu
msgid "Process Info"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_process_status
#: field:server.monitor.process,status:0
msgid "RPC status"
msgstr ""
#. module: server_monitoring
#: view:server.monitor.model.row.count:0
#: view:server.monitor.process:0
msgid "Search Server Monitor Process"
msgstr ""
#. module: server_monitoring
#: view:server.monitor.model.table.activity.read:0
#: view:server.monitor.model.table.activity.update:0
msgid "Search Server Monitor Table Actitivty"
msgstr ""
#. module: server_monitoring
#: view:server.monitor.model.table.size:0
msgid "Search Server Monitor Table Size"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_table_activity_update_seq_scan
#: field:server.monitor.model.table.activity.update,seq_scan:0
msgid "Seq scans"
msgstr ""
#. module: server_monitoring
#: view:server.monitor.database:0
#: view:server.monitor.process:0
msgid "Server Monitor"
msgstr ""
#. module: server_monitoring
#: view:server.monitor.model.table.activity.read:0
#: view:server.monitor.model.table.activity.update:0
#: view:server.monitor.model.table.size:0
msgid "Server Monitor DB Table size"
msgstr ""
#. module: server_monitoring
#: view:server.monitor.model.row.count:0
#: view:server.monitor.process:0
msgid "Server Monitor Process"
msgstr ""
#. module: server_monitoring
#: model:ir.ui.menu,name:server_monitoring.server_monitoring
msgid "Server Monitoring"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_process_sessionid
#: field:server.monitor.process,sessionid:0
msgid "Session ID"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_table_size_hsize
#: field:server.monitor.model.table.size,hsize:0
msgid "Size"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_table_size_size
#: field:server.monitor.model.table.size,size:0
msgid "Size (bytes)"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_row_count_name
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_table_activity_read_name
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_table_activity_update_name
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_table_size_name
#: field:server.monitor.model.row.count,name:0
#: field:server.monitor.model.table.activity.read,name:0
#: field:server.monitor.model.table.activity.update,name:0
#: field:server.monitor.model.table.size,name:0
msgid "Table name"
msgstr ""
#. module: server_monitoring
#: view:server.monitor.database:0
msgid "Table reads"
msgstr ""
#. module: server_monitoring
#: view:server.monitor.database:0
msgid "Table size"
msgstr ""
#. module: server_monitoring
#: view:server.monitor.database:0
msgid "Table updates"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_process_thread
#: field:server.monitor.process,thread:0
msgid "Thread ID"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_database_name
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_process_name
#: field:server.monitor.database,name:0
#: field:server.monitor.process,name:0
msgid "Timestamp"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_table_activity_update_lines_read_total
#: field:server.monitor.model.table.activity.update,lines_read_total:0
msgid "Tot lines read"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_table_activity_read_total_reads
#: field:server.monitor.model.table.activity.read,total_reads:0
msgid "Total reads"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_table_activity_update_num_update
#: field:server.monitor.model.table.activity.update,num_update:0
msgid "Updates"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_process_uid
#: field:server.monitor.process,uid:0
msgid "User"
msgstr ""
#. module: server_monitoring
#: view:server.monitor.process:0
msgid "call information"
msgstr ""
#. module: server_monitoring
#: view:server.monitor.process:0
msgid "date"
msgstr ""
#. module: server_monitoring
#: code:_description:0
#: model:ir.model,name:server_monitoring.model_ir_cron
#, python-format
msgid "ir.cron"
msgstr ""
#. module: server_monitoring
#: view:server.monitor.process:0
msgid "method"
msgstr ""
#. module: server_monitoring
#: view:server.monitor.process:0
msgid "model"
msgstr ""
#. module: server_monitoring
#: view:server.monitor.model.row.count:0
#: view:server.monitor.model.table.activity.read:0
#: view:server.monitor.model.table.activity.update:0
#: view:server.monitor.model.table.size:0
msgid "name"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_row_count_count
#: field:server.monitor.model.row.count,count:0
msgid "row count"
msgstr ""
#. module: server_monitoring
#: code:_description:0
#: model:ir.model,name:server_monitoring.model_server_monitor_class_instance_count
#, python-format
msgid "server.monitor.class.instance.count"
msgstr ""
#. module: server_monitoring
#: code:_description:0
#: model:ir.model,name:server_monitoring.model_server_monitor_database
#, python-format
msgid "server.monitor.database"
msgstr ""
#. module: server_monitoring
#: code:_description:0
#: model:ir.model,name:server_monitoring.model_server_monitor_model_row_count
#, python-format
msgid "server.monitor.model.row.count"
msgstr ""
#. module: server_monitoring
#: code:_description:0
#: model:ir.model,name:server_monitoring.model_server_monitor_model_table_activity_read
#, python-format
msgid "server.monitor.model.table.activity.read"
msgstr ""
#. module: server_monitoring
#: code:_description:0
#: model:ir.model,name:server_monitoring.model_server_monitor_model_table_activity_update
#, python-format
msgid "server.monitor.model.table.activity.update"
msgstr ""
#. module: server_monitoring
#: code:_description:0
#: model:ir.model,name:server_monitoring.model_server_monitor_model_table_size
#, python-format
msgid "server.monitor.model.table.size"
msgstr ""
#. module: server_monitoring
#: code:_description:0
#: model:ir.model,name:server_monitoring.model_server_monitor_process
#, python-format
msgid "server.monitor.process"
msgstr ""
#. module: server_monitoring
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_row_count_timestamp
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_table_activity_read_timestamp
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_table_activity_update_timestamp
#: model:ir.model.fields,field_description:server_monitoring.field_server_monitor_model_table_size_timestamp
#: view:server.monitor.model.row.count:0
#: field:server.monitor.model.row.count,timestamp:0
#: view:server.monitor.model.table.activity.read:0
#: field:server.monitor.model.table.activity.read,timestamp:0
#: view:server.monitor.model.table.activity.update:0
#: field:server.monitor.model.table.activity.update,timestamp:0
#: view:server.monitor.model.table.size:0
#: field:server.monitor.model.table.size,timestamp:0
msgid "timestamp"
msgstr ""

26
server_monitoring/models/__init__.py

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Alexandre Fayolle
# Copyright 2014 Camptocamp SA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import field_types
from . import ir_cron
from . import server_monitor_process
from . import server_monitor_database

30
server_monitoring/models/field_types.py

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Alexandre Fayolle
# Copyright 2014 Camptocamp SA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.osv import orm, fields
class bigint(fields.integer):
_type = 'int8'
fields.bigint = bigint
orm.FIELDS_TO_PGTYPES[bigint] = 'int8'

38
server_monitoring/models/ir_cron.py

@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Alexandre Fayolle
# Copyright 2014 Camptocamp SA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.osv import orm
class IrCron(orm.Model):
_inherit = 'ir.cron'
def _callback(self, cr, uid, model_name, method_name, args, job_id):
super(IrCron, self)._callback(cr, uid,
model_name,
method_name,
args,
job_id)
monitor_obj = self.pool['server.monitor.process']
context = {}
monitor_obj.log_measure(cr, uid,
model_name, method_name,
'cron job',
False, False, context)

213
server_monitoring/models/server_monitor_database.py

@ -0,0 +1,213 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Alexandre Fayolle
# Copyright 2014 Camptocamp SA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import logging
import datetime
from openerp.osv import orm, fields
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
_logger = logging.getLogger(__name__)
class ModelRowCount(orm.Model):
_name = 'server.monitor.model.row.count'
_columns = {
'name': fields.text('Table name', readonly=True),
'count': fields.bigint('row count', readonly=True),
'measure_id': fields.many2one('server.monitor.database',
'Measure',
ondelete='cascade',
readonly=True),
'timestamp': fields.related('measure_id', 'name',
string='timestamp',
type='datetime',
store=True),
}
_order = 'timestamp DESC, count DESC'
class ModelTableSize(orm.Model):
_name = 'server.monitor.model.table.size'
_columns = {
'name': fields.text('Table name', readonly=True),
'size': fields.bigint('Size (bytes)', readonly=True),
'hsize': fields.text('Size', readonly=True),
'measure_id': fields.many2one('server.monitor.database',
'Measure',
ondelete='cascade', readonly=True),
'timestamp': fields.related('measure_id', 'name',
string='timestamp',
type='datetime',
store=True),
}
_order = 'timestamp DESC, size DESC'
class ModelTableActivityRead(orm.Model):
_name = 'server.monitor.model.table.activity.read'
_columns = {
'name': fields.text('Table name'),
'disk_reads': fields.bigint('Disk reads (heap blocks)', readonly=True),
'cache_reads': fields.bigint('Cache reads', readonly=True),
'total_reads': fields.bigint('Total reads', readonly=True),
'measure_id': fields.many2one('server.monitor.database',
'Measure',
ondelete='cascade', readonly=True),
'timestamp': fields.related('measure_id', 'name',
string='timestamp',
type='datetime',
store=True),
}
_order = 'timestamp DESC, total_reads DESC'
class ModelTableActivityUpdate(orm.Model):
_name = 'server.monitor.model.table.activity.update'
_columns = {
'name': fields.text('Table name', readonly=True),
'seq_scan': fields.bigint('Seq scans', readonly=True),
'idx_scan': fields.bigint('Idx scans', readonly=True),
'lines_read_total': fields.bigint('Tot lines read', readonly=True),
'num_insert': fields.bigint('Inserts', readonly=True),
'num_update': fields.bigint('Updates', readonly=True),
'num_delete': fields.bigint('Deletes', readonly=True),
'measure_id': fields.many2one('server.monitor.database',
'Measure',
ondelete='cascade',
readonly=True),
'timestamp': fields.related('measure_id', 'name',
string='timestamp',
type='datetime',
store=True),
}
_order = 'timestamp DESC, num_update DESC'
class ServerMonitorDatabase(orm.Model):
_name = 'server.monitor.database'
_columns = {
'name': fields.datetime('Timestamp', readonly=True),
'info': fields.text('Information'),
'table_nb_row_ids': fields.one2many('server.monitor.model.row.count',
'measure_id',
'Model row counts',
readonly=True),
'table_size_ids': fields.one2many('server.monitor.model.table.size',
'measure_id',
'Model table size',
readonly=True),
'table_activity_read_ids': fields.one2many(
'server.monitor.model.table.activity.read',
'measure_id',
'Model table read activity',
readonly=True),
'table_activity_update_ids': fields.one2many(
'server.monitor.model.table.activity.update',
'measure_id',
'Model table update activity',
readonly=True),
}
_order = 'name DESC'
def _model_row_count(self, cr, uid, context):
res = []
query = ("SELECT schemaname || '.' || relname as name, "
" n_live_tup as count "
"FROM pg_stat_user_tables "
"ORDER BY n_live_tup DESC")
cr.execute(query)
for val in cr.dictfetchall():
res.append((0, 0, val))
return res
def _model_table_size(self, cr, uid, context):
res = []
query = (
"SELECT nspname || '.' || relname AS name, "
" pg_size_pretty(pg_total_relation_size(C.oid)) AS hsize, "
" pg_total_relation_size(C.oid) AS size "
"FROM pg_class C LEFT JOIN pg_namespace N "
" ON (N.oid = C.relnamespace) "
"WHERE nspname NOT IN ('pg_catalog', 'information_schema') "
" AND C.relkind <> 'i' "
" AND nspname !~ '^pg_toast' "
"ORDER BY pg_total_relation_size(C.oid) DESC"
)
cr.execute(query)
for val in cr.dictfetchall():
res.append((0, 0, val))
return res
def _model_table_activity_read(self, cr, uid, context):
res = []
query = ("SELECT schemaname || '.' || relname as name, "
" heap_blks_read as disk_reads, "
" heap_blks_hit as cache_reads, "
" heap_blks_read + heap_blks_hit as total_reads "
"FROM pg_statio_user_tables "
"ORDER BY heap_blks_read + heap_blks_hit DESC"
)
cr.execute(query)
for val in cr.dictfetchall():
res.append((0, 0, val))
return res
def _model_table_activity_update(self, cr, uid, context):
res = []
query = ("SELECT schemaname || '.' || relname as name, "
" seq_scan, "
" idx_scan, "
" idx_tup_fetch + seq_tup_read as lines_read_total, "
" n_tup_ins as num_insert, "
" n_tup_upd as num_update, "
" n_tup_del as num_delete "
"FROM pg_stat_user_tables "
"ORDER BY n_tup_upd + n_tup_ins + n_tup_del desc")
cr.execute(query)
for val in cr.dictfetchall():
res.append((0, 0, val))
return res
_defaults = {
'name': fields.datetime.now,
'table_nb_row_ids': _model_row_count,
'table_size_ids': _model_table_size,
'table_activity_read_ids': _model_table_activity_read,
'table_activity_update_ids': _model_table_activity_update,
}
def log_measure(self, cr, uid, context=None):
fields = self._defaults.keys()
defaults = self.default_get(cr, uid, fields, context=context)
self.create(cr, uid, defaults, context=context)
return True
def cleanup(self, cr, uid, age, context=None):
now = datetime.datetime.now()
delta = datetime.timedelta(days=age)
when = (now - delta).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
ids = self.search(cr, uid,
[('name', '<', when)],
context=context)
_logger.debug('Database monitor cleanup: removing %d records',
len(ids))
self.unlink(cr, uid, ids, context=context)

244
server_monitoring/models/server_monitor_process.py

@ -0,0 +1,244 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Alexandre Fayolle
# Copyright 2014 Camptocamp SA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
"""
Monitor openerp instance.
The measures are stored in database.
cleanup cron (2 different for db and process monitoring)
* database monitoring:
cron for capturing data
add timestamp
* process monitoring
TODO: log process start / end
cron log
RPC request log
"""
import logging
import gc
from operator import itemgetter
import types
import os
import threading
import datetime
# ugly hack to avoid a WARNING message when importing stdlib resource module
_logger = logging.getLogger('openerp.modules.module')
_saved_log_level = _logger.getEffectiveLevel()
_logger.setLevel(logging.ERROR)
import resource
_logger.setLevel(_saved_log_level)
import psutil
from openerp.osv import orm, fields, osv
from openerp import pooler
from openerp import SUPERUSER_ID
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
_logger = logging.getLogger(__name__)
BLACKLIST = (
type, tuple, dict, list, set, frozenset,
property,
classmethod,
staticmethod,
types.FunctionType,
types.ClassType,
types.ModuleType, types.FunctionType, types.MethodType,
types.MemberDescriptorType, types.GetSetDescriptorType,
)
class ClassInstanceCount(orm.Model):
_name = 'server.monitor.class.instance.count'
_columns = {
'name': fields.text('Class name', readonly=True),
'count': fields.bigint('Instance count', readonly=True),
'measure_id': fields.many2one('server.monitor.process',
'Measure',
readonly=True,
ondelete='cascade'),
}
def _monkey_patch_object_proxy_execute():
orig_execute_cr = osv.object_proxy.execute_cr
def execute_cr(self, cr, uid, obj, method, *args, **kw):
result = orig_execute_cr(self, cr, uid, obj, method, *args, **kw)
monitor_obj = pooler.get_pool(cr.dbname)['server.monitor.process']
context = {}
monitor_obj.log_measure(cr, uid, obj, method, 'rpc call',
False, False, context)
return result
osv.object_proxy.execute_cr = execute_cr
class ServerMonitorProcess(orm.Model):
def __init__(self, pool, cr):
super(ServerMonitorProcess, self).__init__(pool, cr)
_monkey_patch_object_proxy_execute()
_name = 'server.monitor.process'
_columns = {
'name': fields.datetime('Timestamp', readonly=True),
'pid': fields.integer('Process ID', readonly=True,
group_operator='count'),
'thread': fields.text('Thread ID', readonly=True),
'cpu_time': fields.float(
'CPU time', readonly=True,
group_operator='max',
help='CPU time consumed by the current server process'),
'memory': fields.float(
'Memory', readonly=True,
group_operator='max',
help='Memory consumed by the current server process'),
'uid': fields.many2one('res.users', 'User',
readonly=True,
select=True),
'model': fields.many2one('ir.model', 'Model',
readonly=True,
select=True),
'method': fields.text('Method', readonly=True),
'status': fields.text('RPC status', readonly=True),
'sessionid': fields.text('Session ID', readonly=True),
'info': fields.text('Information'),
'class_count_ids': fields.one2many(
'server.monitor.class.instance.count',
'measure_id',
'Class counts',
readonly=True),
}
_order = 'name DESC'
def _default_pid(self, cr, uid, context):
return os.getpid()
def _default_cpu_time(self, cr, uid, context):
r = resource.getrusage(resource.RUSAGE_SELF)
cpu_time = r.ru_utime + r.ru_stime
return cpu_time
def _default_memory(self, cr, uid, context):
try:
rss, vms = psutil.Process(os.getpid()).get_memory_info()
except AttributeError:
# happens on travis
vms = 0
return vms
def _default_uid(self, cr, uid, context):
return uid
def _default_thread(self, cr, uid, context):
return threading.current_thread().name
def _class_count(self, cr, uid, context):
counts = {}
if context.get('_x_no_class_count'):
return []
if context.get('_x_no_gc_collect'):
gc.collect()
gc.collect()
for obj in gc.get_objects():
if isinstance(obj, BLACKLIST):
continue
try:
cls = obj.__class__
except:
if isinstance(obj, types.ClassType):
cls = types.ClassType
else:
_logger.warning('unknown object type for %r (%s)',
obj, type(obj))
continue
name = '%s.%s' % (cls.__module__, cls.__name__)
try:
counts[name] += 1
except KeyError:
counts[name] = 1
info = []
for name, count in sorted(counts.items(),
key=itemgetter(1),
reverse=True):
if count < 2:
break
info.append({'name': name, 'count': count})
return [(0, 0, val) for val in info]
_defaults = {
'name': fields.datetime.now,
'class_count_ids': _class_count,
'pid': _default_pid,
'cpu_time': _default_cpu_time,
'memory': _default_memory,
'uid': _default_uid,
'thread': _default_thread,
}
def log_measure(self, cr, uid,
model_name, method_name, info,
with_class_count=True,
gc_collect=True,
context=None):
if context is None:
context = {}
ctx = context.copy()
ctx.update({
'_x_no_class_count': not with_class_count,
'_x_no_gc_collect': not gc_collect,
})
fields = self._defaults.keys()
defaults = self.default_get(cr, uid, fields, context=ctx)
model_obj = self.pool['ir.model']
model_id = model_obj.search(cr, uid,
[('name', '=', model_name)],
context=context)
if model_id:
model_id = model_id[0]
else:
model_id = 0
values = {'model': model_id,
'method': method_name,
'info': info,
}
defaults.update(values)
id = self.create(cr, SUPERUSER_ID, defaults, context=context)
return id
def cleanup(self, cr, uid, age, context=None):
now = datetime.datetime.now()
delta = datetime.timedelta(days=age)
when = (now - delta).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
ids = self.search(cr, uid,
[('name', '<', when)],
context=context)
_logger.debug('Process monitor cleanup: removing %d records', len(ids))
self.unlink(cr, uid, ids, context=context)

8
server_monitoring/security/ir.model.access.csv

@ -0,0 +1,8 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_server_monitor_class_instance_count,access_server_monitor_class_instance_count,model_server_monitor_class_instance_count,base.group_no_one,1,0,1,0
access_server_monitor_process,access_server_monitor_process,model_server_monitor_process,base.group_no_one,1,0,1,0
access_server_monitor_model_row_count,access_server_monitor_model_row_count,model_server_monitor_model_row_count,base.group_no_one,1,0,1,0
access_server_monitor_model_table_size,access_server_monitor_model_table_size,model_server_monitor_model_table_size,base.group_no_one,1,0,1,0
access_server_monitor_model_table_activity_read,access_server_monitor_model_table_activity_read,model_server_monitor_model_table_activity_read,base.group_no_one,1,0,1,0
access_server_monitor_model_table_activity_update,access_server_monitor_model_table_activity_update,model_server_monitor_model_table_activity_update,base.group_no_one,1,0,1,0
access_server_monitor_database,access_server_monitor_database,model_server_monitor_database,base.group_no_one,1,0,1,0

64
server_monitoring/tests/test_monitor_database.yml

@ -0,0 +1,64 @@
-
I record a process log
-
!python {model: server.monitor.database}: |
id = self.log_measure(cr, uid, context=context)
-
there should be some server.monitor.model.row.count in database
-
!python {model: server.monitor.model.row.count}: |
ids = self.search(cr, uid, [], context=context)
assert ids, 'No server.monitor.model.row.count instance count recorded'
-
there should be some server.monitor.model.table.size in database
-
!python {model: server.monitor.model.table.size}: |
ids = self.search(cr, uid, [], context=context)
assert ids, 'No server.monitor.model.table.size recorded'
-
there should be some server.monitor.model.table.activity.read in database
-
!python {model: server.monitor.model.table.activity.read}: |
ids = self.search(cr, uid, [], context=context)
assert ids, 'No server.monitor.model.table.activity.read recorded'
-
there should be some server.monitor.model.table.activity.update in database
-
!python {model: server.monitor.model.table.activity.update}: |
ids = self.search(cr, uid, [], context=context)
assert ids, 'No server.monitor.model.table.activity.update recorded'
-
I cleanup the database logs
-
!python {model: server.monitor.database}: |
id = self.cleanup(cr, uid, -1, context=context)
-
there should be no server.monitor.model.row.count in database
-
!python {model: server.monitor.model.row.count}: |
ids = self.search(cr, uid, [], context=context)
assert not ids, 'server.monitor.model.row.count still present'
-
there should be no server.monitor.model.table.size in database
-
!python {model: server.monitor.model.table.size}: |
ids = self.search(cr, uid, [], context=context)
assert not ids, 'server.monitor.model.table.size still present'
-
there should be no server.monitor.model.table.activity.read in database
-
!python {model: server.monitor.model.table.activity.read}: |
ids = self.search(cr, uid, [], context=context)
assert not ids, 'server.monitor.model.table.activity.read still present'
-
there should be no server.monitor.model.table.activity.update in database
-
!python {model: server.monitor.model.table.activity.update}: |
ids = self.search(cr, uid, [], context=context)
assert not ids, 'server.monitor.model.table.activity.update still present'
-
there should be no server.monitor.database in database
-
!python {model: server.monitor.database}: |
ids = self.search(cr, uid, [], context=context)
assert not ids, 'server.monitor.database still present'

28
server_monitoring/tests/test_monitor_process.yml

@ -0,0 +1,28 @@
-
I record a process log
-
!python {model: server.monitor.process}: |
id = self.log_measure(cr, uid, None, None, 'test', context=context)
-
there should be some class instance counts in database
-
!python {model: server.monitor.class.instance.count}: |
ids = self.search(cr, uid, [], context=context)
assert ids, 'No class instance count recorded'
-
I cleanup the process logs
-
!python {model: server.monitor.process}: |
id = self.cleanup(cr, uid, -1, context=context)
-
there should be no class instance count in database
-
!python {model: server.monitor.class.instance.count}: |
ids = self.search(cr, uid, [], context=context)
assert not ids, 'Class instance count still present'
-
there should be no monitor process in database
-
!python {model: server.monitor.process}: |
ids = self.search(cr, uid, [], context=context)
assert not ids, 'server monitor process still present'

11
server_monitoring/views/menu.xml

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<menuitem groups="base.group_no_one"
id="server_monitoring"
name="Server Monitoring"
parent="base.menu_reporting"
sequence="100"/>
</data>
</openerp>

92
server_monitoring/views/server_monitor_database.xml

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record model="ir.ui.view" id="server_monitor_database_tree_view">
<field name="name">Server Monitor Database form view</field>
<field name="model">server.monitor.database</field>
<field name="arch" type="xml">
<tree string="Server Monitor" version="7.0">
<field name='name'/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="server_monitor_database_form_view">
<field name="name">Server Monitor Database tree view</field>
<field name="model">server.monitor.database</field>
<field name="arch" type="xml">
<form string="Server Monitor" version="7.0">
<sheet>
<field name="name"/>
<notebook>
<page string="Nb rows">
<group>
<field name='table_nb_row_ids' nolabel="1">
<tree>
<field name='name'/>
<field name='count'/>
</tree>
</field>
</group>
</page>
<page string="Table size">
<group>
<field name='table_size_ids' nolabel="1">
<tree>
<field name='name'/>
<field name='hsize'/>
</tree>
</field>
</group>
</page>
<page string="Table reads">
<group>
<field name='table_activity_read_ids' nolabel="1">
<tree>
<field name='name'/>
<field name='disk_reads'/>
<field name='cache_reads'/>
<field name='total_reads'/>
</tree>
</field>
</group>
</page>
<page string="Table updates">
<group>
<field name='table_activity_update_ids' nolabel="1">
<tree>
<field name='name'/>
<field name='seq_scan'/>
<field name='idx_scan'/>
<field name='lines_read_total'/>
<field name='num_insert'/>
<field name='num_update'/>
<field name='num_delete'/>
</tree>
</field>
</group>
</page>
</notebook>
<group>
<field name='info' string="Information"/>
</group>
</sheet>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="server_monitor_database_info">
<field name="name">Database Info</field>
<field name="res_model">server.monitor.database</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem name="Database Info"
parent="server_monitoring"
id="server_monitor_database_menu"
action="server_monitor_database_info"
sequence="20"/>
</data>
</openerp>

91
server_monitoring/views/server_monitor_database_table_activity.xml

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record model="ir.ui.view" id="server_monitor_model_table_activity_read_search_view">
<field name="name">Server Monitor table activity updates search view</field>
<field name="model">server.monitor.model.table.activity.read</field>
<field name="arch" type="xml">
<search string="Search Server Monitor Table Activity read" version="7.0">
<field name="timestamp"/>
<field name="name"/>
<group expand="0" string="Group By...">
<filter string="timestamp" domain="[]" context="{'group_by': 'timestamp'}"/>
<filter string="name" domain="[]" context="{'group_by': 'name'}"/>
</group>
</search>
</field>
</record>
<record model="ir.ui.view" id="server_monitor_model_table_activity_read_tree_view">
<field name="name">Server Monitor table activity tree view</field>
<field name="model">server.monitor.model.table.activity.read</field>
<field name="arch" type="xml">
<tree string="Server Monitor DB Table activity" version="7.0">
<field name='timestamp'/>
<field name='name'/>
<field name='disk_reads'/>
<field name='cache_reads'/>
<field name='total_reads'/>
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="server_monitor_database_table_activity_read">
<field name="name">DB Reads</field>
<field name="res_model">server.monitor.model.table.activity.read</field>
<field name="view_mode">tree</field>
</record>
<menuitem name="DB Reads"
parent="server_monitoring"
id="server_monitor_database_table_activity_read_menu"
action="server_monitor_database_table_activity_read"
sequence="50"/>
<record model="ir.ui.view" id="server_monitor_model_table_activity_update_search_view">
<field name="name">Server Monitor table activity updates search view</field>
<field name="model">server.monitor.model.table.activity.update</field>
<field name="arch" type="xml">
<search string="Search Server Monitor Table Activity updates" version="7.0">
<field name="timestamp"/>
<field name="name"/>
<group expand="0" string="Group By...">
<filter string="timestamp" domain="[]" context="{'group_by': 'timestamp'}"/>
<filter string="name" domain="[]" context="{'group_by': 'name'}"/>
</group>
</search>
</field>
</record>
<record model="ir.ui.view" id="server_monitor_model_table_activity_update_tree_view">
<field name="name">Server Monitor table activity updates tree view</field>
<field name="model">server.monitor.model.table.activity.update</field>
<field name="arch" type="xml">
<tree string="Server Monitor DB Table size" version="7.0">
<field name='timestamp'/>
<field name='name'/>
<field name='seq_scan'/>
<field name='idx_scan'/>
<field name='lines_read_total'/>
<field name='num_insert'/>
<field name='num_update'/>
<field name='num_delete'/>
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="server_monitor_database_table_activity_update">
<field name="name">DB Updates</field>
<field name="res_model">server.monitor.model.table.activity.update</field>
<field name="view_mode">tree</field>
</record>
<menuitem name="DB Updates"
parent="server_monitoring"
id="server_monitor_database_table_activity_update_menu"
action="server_monitor_database_table_activity_update"
sequence="60"/>
</data>
</openerp>

43
server_monitoring/views/server_monitor_model_row_count.xml

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record model="ir.ui.view" id="server_monitor_model_row_count_search_view">
<field name="name">Server Monitor model row count search view</field>
<field name="model">server.monitor.model.row.count</field>
<field name="arch" type="xml">
<search string="Search Server Monitor Process" version="7.0">
<field name="timestamp"/>
<field name="name"/>
<field name="count"/>
<group expand="0" string="Group By...">
<filter string="timestamp" domain="[]" context="{'group_by': 'timestamp'}"/>
<filter string="name" domain="[]" context="{'group_by': 'name'}"/>
</group>
</search>
</field>
</record>
<record model="ir.ui.view" id="server_monitor_model_row_count_tree_view">
<field name="name">Server Monitor model row count tree view</field>
<field name="model">server.monitor.model.row.count</field>
<field name="arch" type="xml">
<tree string="Server Monitor Process" version="7.0">
<field name='timestamp'/>
<field name='name'/>
<field name='count'/>
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="server_monitor_database_table_rows">
<field name="name">DB Rows</field>
<field name="res_model">server.monitor.model.row.count</field>
<field name="view_mode">tree</field>
</record>
<menuitem name="DB Rows"
parent="server_monitoring"
id="server_monitor_database_table_rows_menu"
action="server_monitor_database_table_rows" sequence="30"/>
</data>
</openerp>

44
server_monitoring/views/server_monitor_model_table_size.xml

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record model="ir.ui.view" id="server_monitor_model_table_size_search_view">
<field name="name">Server Monitor model table size search view</field>
<field name="model">server.monitor.model.table.size</field>
<field name="arch" type="xml">
<search string="Search Server Monitor Table Row Count" version="7.0">
<field name="timestamp"/>
<field name="name"/>
<group expand="0" string="Group By...">
<filter string="timestamp" domain="[]" context="{'group_by': 'timestamp'}"/>
<filter string="name" domain="[]" context="{'group_by': 'name'}"/>
</group>
</search>
</field>
</record>
<record model="ir.ui.view" id="server_monitor_model_table_size_tree_view">
<field name="name">Server Monitor model table size tree view</field>
<field name="model">server.monitor.model.table.size</field>
<field name="arch" type="xml">
<tree string="Server Monitor DB Table Row Count" version="7.0">
<field name='timestamp'/>
<field name='name'/>
<field name='hsize'/>
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="server_monitor_database_table_size">
<field name="name">DB Table Size</field>
<field name="res_model">server.monitor.model.table.size</field>
<field name="view_mode">tree</field>
</record>
<menuitem name="DB Table Size"
parent="server_monitoring"
id="server_monitor_database_table_size_menu"
action="server_monitor_database_table_size"
sequence="40"/>
</data>
</openerp>

92
server_monitoring/views/server_monitor_process.xml

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record model="ir.ui.view" id="server_monitor_process_search_view">
<field name="name">Server Monitor Process search view</field>
<field name="model">server.monitor.process</field>
<field name="arch" type="xml">
<search string="Search Server Monitor Process" version="7.0">
<field name="model"/>
<field name="method"/>
<field name="uid"/>
<group expand="0" string="Group By...">
<filter string="date" domain="[]" context="{'group_by': 'name'}"/>
<filter string="PID" domain="[]" context="{'group_by': 'pid'}"/>
<filter string="model" domain="[]" context="{'group_by': 'model'}"/>
<filter string="method" domain="[]" context="{'group_by': 'method'}"/>
</group>
</search>
</field>
</record>
<record model="ir.ui.view" id="server_monitor_process_tree_view">
<field name="name">Server Monitor Process tree view</field>
<field name="model">server.monitor.process</field>
<field name="arch" type="xml">
<tree string="Server Monitor Process" version="7.0">
<field name='name'/>
<field name='pid'/>
<field name='cpu_time'/>
<field name='memory'/>
<field name='uid'/>
<field name='model'/>
<field name='method'/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="server_monitor_process_form_view">
<field name="name">Server Monitor Process form view</field>
<field name="model">server.monitor.process</field>
<field name="arch" type="xml">
<form string="Server Monitor" version="7.0">
<sheet>
<field name="name"/>
<notebook>
<page string='call information'>
<group>
<field name='pid'/>
<field name='thread'/>
<field name='cpu_time'/>
<field name='memory'/>
<field name='uid'/>
<field name='model'/>
<field name='method'/>
<field name='status'/>
<field name='sessionid'/>
</group>
</page>
<page string="Class count">
<group>
<field name='class_count_ids' nolabel="1">
<tree>
<field name='name'/>
<field name='count'/>
</tree>
</field>
</group>
</page>
</notebook>
<group>
<field name='info' string="Information"/>
</group>
</sheet>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="server_monitor_process_info">
<field name="name">Process Info</field>
<field name="res_model">server.monitor.process</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem name="Process Info"
parent="server_monitoring"
id="server_monitor_process_menu"
action="server_monitor_process_info"
sequence="10"/>
</data>
</openerp>
Loading…
Cancel
Save