openerp-community-reviewer team mailing list archive
-
openerp-community-reviewer team
-
Mailing list archive
-
Message #05845
[Merge] lp:~camptocamp/server-env-tools/7.0-monitoring into lp:server-env-tools
Alexandre Fayolle - camptocamp has proposed merging lp:~camptocamp/server-env-tools/7.0-monitoring into lp:server-env-tools.
Requested reviews:
Server Environment And Tools Core Editors (server-env-tools-core-editors)
For more details, see:
https://code.launchpad.net/~camptocamp/server-env-tools/7.0-monitoring/+merge/215138
new addon: server_monitoring
This addon logs information in the OpenERP database, which can be used to monitor the health of the instance:
* database information (table size, number of reads, inserts, updates, deletes...)
* process information (cpu time, memory, rpc calls...)
--
https://code.launchpad.net/~camptocamp/server-env-tools/7.0-monitoring/+merge/215138
Your team Server Environment And Tools Core Editors is requested to review the proposed merge of lp:~camptocamp/server-env-tools/7.0-monitoring into lp:server-env-tools.
=== added directory 'server_monitoring'
=== added file 'server_monitoring/__init__.py'
--- server_monitoring/__init__.py 1970-01-01 00:00:00 +0000
+++ server_monitoring/__init__.py 2014-04-10 10:25:03 +0000
@@ -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 server_monitoring
=== added file 'server_monitoring/__openerp__.py'
--- server_monitoring/__openerp__.py 1970-01-01 00:00:00 +0000
+++ server_monitoring/__openerp__.py 2014-04-10 10:25:03 +0000
@@ -0,0 +1,53 @@
+# -*- 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': 'Connector',
+ 'depends': ['base',
+ ],
+ 'author': 'Camptocamp',
+ '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.
+
+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.
+""",
+ 'data': [
+ 'server_monitoring_view.xml',
+ 'server_monitoring_data.xml',
+ 'security/ir.model.access.csv',
+ ],
+ 'test':[],
+ 'installable': True,
+ 'application': False,
+}
+
=== added directory 'server_monitoring/security'
=== added file 'server_monitoring/security/ir.model.access.csv'
--- server_monitoring/security/ir.model.access.csv 1970-01-01 00:00:00 +0000
+++ server_monitoring/security/ir.model.access.csv 2014-04-10 10:25:03 +0000
@@ -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
=== added file 'server_monitoring/server_monitoring.py'
--- server_monitoring/server_monitoring.py 1970-01-01 00:00:00 +0000
+++ server_monitoring/server_monitoring.py 2014-04-10 10:25:03 +0000
@@ -0,0 +1,408 @@
+# -*- 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
+
+ -> to log: timestamp, pid, database, cpu time, memory, uid, model, method, return state, pooler state(?), session id (?)
+
+TODO: visualize
+TODO: export
+
+"""
+
+import logging
+import gc
+from operator import itemgetter
+import types
+import os
+import threading
+import resource
+import datetime
+
+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__)
+
+
+class bigint(fields.integer):
+ _type = 'int8'
+
+fields.bigint = bigint
+orm.FIELDS_TO_PGTYPES[bigint] = 'int8'
+
+
+BLACKLIST = (
+ type, tuple, dict, list, set, frozenset,
+ property,
+ classmethod,
+ staticmethod,
+ types.FunctionType,
+ types.ClassType,
+ types.ModuleType, types.FunctionType, types.MethodType,
+ types.MemberDescriptorType, types.GetSetDescriptorType,
+ )
+
+## COUNTED = frozenset((
+## column_info, LRUNode,
+## browse_record,
+
+## ))
+
+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'),
+ 'memory': fields.float('Memory', readonly=True, group_operator='max'),
+ 'uid': fields.many2one('res.users', 'User', readonly=True),
+ 'model': fields.many2one('ir.model', 'Model', readonly=True),
+ 'method': fields.text('Method', readonly=True),
+ 'status': fields.text('RPC status', readonly=True),
+ #'pooler_state(?)': fields.XXX('Pooler state', 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):
+ rss, vms = psutil.Process(os.getpid()).get_memory_info()
+ 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:
+ print obj, type(obj)
+ 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)
+
+ self.create(cr, SUPERUSER_ID, defaults, context=context)
+ return True
+
+ def cleanup(self, cr, uid, age, context=None):
+ now = datetime.datetime.now()
+ delta = datetime.timedelta(days=age)
+ ids = self.search(cr, uid,
+ [('name', '<', (now - delta).strftime(DEFAULT_SERVER_DATETIME_FORMAT))],
+ context=context)
+ _logger.debug('Process monitor cleanup: removing %d records', len(ids))
+ self.unlink(cr, uid, ids, context=context)
+
+
+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)
+
+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)
+ ids = self.search(cr, uid,
+ [('name', '<', (now - delta).strftime(DEFAULT_SERVER_DATETIME_FORMAT))],
+ context=context)
+ _logger.debug('Database monitor cleanup: removing %d records', len(ids))
+ self.unlink(cr, uid, ids, context=context)
=== added file 'server_monitoring/server_monitoring_data.xml'
--- server_monitoring/server_monitoring_data.xml 1970-01-01 00:00:00 +0000
+++ server_monitoring/server_monitoring_data.xml 2014-04-10 10:25:03 +0000
@@ -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>
=== added file 'server_monitoring/server_monitoring_view.xml'
--- server_monitoring/server_monitoring_view.xml 1970-01-01 00:00:00 +0000
+++ server_monitoring/server_monitoring_view.xml 2014-04-10 10:25:03 +0000
@@ -0,0 +1,342 @@
+<?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"/>
+
+ <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.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"/>
+
+ <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"/>
+
+
+ <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"/>
+
+
+ <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 Rows</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"/>
+
+ <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 Rows</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 Rows"
+ parent="server_monitoring"
+ id="server_monitor_database_table_activity_update_menu"
+ action="server_monitor_database_table_activity_update"
+ sequence="60"/>
+
+
+ </data>
+</openerp>
Follow ups
-
Re: [Merge] lp:~camptocamp/server-env-tools/7.0-monitoring into lp:~server-env-tools-core-editors/server-env-tools/7.0
From: Sandy Carter (http://www.savoirfairelinux.com), 2014-08-08
-
Re: [Merge] lp:~camptocamp/server-env-tools/7.0-monitoring into lp:server-env-tools
From: Alexandre Fayolle - camptocamp, 2014-05-12
-
[Merge] lp:~camptocamp/server-env-tools/7.0-monitoring into lp:server-env-tools
From: Alexandre Fayolle - camptocamp, 2014-05-12
-
Re: [Merge] lp:~camptocamp/server-env-tools/7.0-monitoring into lp:server-env-tools
From: Daniel Reis, 2014-05-02
-
Re: [Merge] lp:~camptocamp/server-env-tools/7.0-monitoring into lp:server-env-tools
From: Nicolas Bessi - Camptocamp, 2014-05-01
-
Re: [Merge] lp:~camptocamp/server-env-tools/7.0-monitoring into lp:server-env-tools
From: Daniel Reis, 2014-04-23
-
Re: [Merge] lp:~camptocamp/server-env-tools/7.0-monitoring into lp:server-env-tools
From: Daniel Reis, 2014-04-23
-
Re: [Merge] lp:~camptocamp/server-env-tools/7.0-monitoring into lp:server-env-tools
From: Nicolas Bessi - Camptocamp, 2014-04-10
-
Re: [Merge] lp:~camptocamp/server-env-tools/7.0-monitoring into lp:server-env-tools
From: Alexandre Fayolle - camptocamp, 2014-04-10
-
Re: [Merge] lp:~camptocamp/server-env-tools/7.0-monitoring into lp:server-env-tools
From: Nicolas Bessi - Camptocamp, 2014-04-10