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>
-- Mailing list: https://launchpad.net/~openerp-community-reviewer Post to : openerp-community-reviewer@lists.launchpad.net Unsubscribe : https://launchpad.net/~openerp-community-reviewer More help : https://help.launchpad.net/ListHelp