Browse Source
new addon: server_monitoring
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
19 changed files with 1686 additions and 0 deletions
-
86server_monitoring/README.rst
-
21server_monitoring/__init__.py
-
63server_monitoring/__openerp__.py
-
47server_monitoring/data/ir_cron.xml
-
445server_monitoring/i18n/server_monitoring.pot
-
26server_monitoring/models/__init__.py
-
30server_monitoring/models/field_types.py
-
38server_monitoring/models/ir_cron.py
-
213server_monitoring/models/server_monitor_database.py
-
244server_monitoring/models/server_monitor_process.py
-
8server_monitoring/security/ir.model.access.csv
-
64server_monitoring/tests/test_monitor_database.yml
-
28server_monitoring/tests/test_monitor_process.yml
-
11server_monitoring/views/menu.xml
-
92server_monitoring/views/server_monitor_database.xml
-
91server_monitoring/views/server_monitor_database_table_activity.xml
-
43server_monitoring/views/server_monitor_model_row_count.xml
-
44server_monitoring/views/server_monitor_model_table_size.xml
-
92server_monitoring/views/server_monitor_process.xml
@ -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. |
@ -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 |
@ -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, |
|||
} |
@ -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> |
@ -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 "" |
|||
|
@ -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 |
@ -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' |
@ -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) |
@ -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) |
@ -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) |
@ -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 |
@ -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' |
@ -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' |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue