[IMP] runbot: add an error log model based on a SQL view

With this commit, a new model is introduced to facilitate the tracking
of the build errors.

Its based on an SQL view (Thanks @Xavier-Do), that way, there is no new
table in DB and this view is also useful from the PSQL CLI.

In the UI, the search for errors easier than manipulate the ir_logging
view because the builds informations can be used in search and filters.
This commit is contained in:
Christophe Monniez 2019-08-28 14:58:17 +02:00 committed by Xavier-Do
parent 7382aa6b79
commit c49e422a25
5 changed files with 207 additions and 2 deletions

View File

@ -18,6 +18,7 @@
'views/build_views.xml',
'views/host_views.xml',
'views/build_error_views.xml',
'views/error_log_views.xml',
'views/config_views.xml',
'views/res_config_settings_views.xml',
'templates/frontend.xml',

View File

@ -33,6 +33,7 @@ def make_selection(array):
class runbot_build(models.Model):
_name = "runbot.build"
_order = 'id desc'
_rec_name = 'id'
branch_id = fields.Many2one('runbot.branch', 'Branch', required=True, ondelete='cascade', index=True)
repo_id = fields.Many2one(related='branch_id.repo_id', readonly=True, store=True)

View File

@ -2,7 +2,7 @@
import logging
from odoo import models, fields, api
from odoo import models, fields, api, tools
_logger = logging.getLogger(__name__)
@ -47,3 +47,100 @@ CREATE TRIGGER runbot_new_logging BEFORE INSERT ON ir_logging
FOR EACH ROW EXECUTE PROCEDURE runbot_set_logging_build();
""")
class RunbotErrorLog(models.Model):
_name = "runbot.error.log"
_auto = False
_order = 'id desc'
id = fields.Many2one('ir.logging', string='Log', readonly=True)
name = fields.Char(string='Module', readonly=True)
message = fields.Text(string='Message', readonly=True)
summary = fields.Text(string='Summary', readonly=True)
log_type = fields.Char(string='Type', readonly=True)
log_create_date = fields.Datetime(string='Log create date', readonly=True)
func = fields.Char(string='Method', readonly=True)
path = fields.Char(string='Path', readonly=True)
line = fields.Char(string='Line', readonly=True)
build_id = fields.Many2one('runbot.build', string='Build', readonly=True)
bu_name = fields.Char(String='Build name', readonly=True)
dest = fields.Char(String='Build dest', readonly=True)
local_state = fields.Char(string='Local state', readonly=True)
local_result = fields.Char(string='Local result', readonly=True)
global_state = fields.Char(string='Global state', readonly=True)
global_result = fields.Char(string='Global result', readonly=True)
bu_create_date = fields.Datetime(string='Build create date', readonly=True)
committer = fields.Char(string='committer', readonly=True)
author = fields.Char(string='Author', readonly=True)
host = fields.Char(string='Host', readonly=True)
config_id = fields.Many2one('runbot.build.config', string='Config', readonly=True)
parent_id = fields.Many2one('runbot.build', string='Parent build', readonly=True)
hidden = fields.Boolean(string='Hidden', readonly=True)
branch_id = fields.Many2one('runbot.branch', string='Branch', readonly=True)
branch_name = fields.Char(string='Branch name', readonly=True)
repo_id = fields.Many2one('runbot.repo', string='Repo', readonly=True)
repo_name = fields.Char(string='Repo name', readonly=True)
repo_short_name = fields.Char(compute='_compute_repo_short_name', readonly=True)
build_url = fields.Char(compute='_compute_build_url', readonly=True)
def _compute_repo_short_name(self):
for l in self:
l.repo_short_name = '/'.join(l.repo_id.base.split('/')[-2:])
def _compute_build_url(self):
for l in self:
l.build_url = '/runbot/build/%s' % l.build_id.id
def action_goto_build(self):
self.ensure_one()
return {
"type": "ir.actions.act_url",
"url": "runbot/build/%s" % self.build_id.id,
"target": "new",
}
@api.model_cr
def init(self):
""" Create an SQL view for ir.logging """
tools.drop_view_if_exists(self._cr, 'runbot_error_log')
self._cr.execute(""" CREATE VIEW runbot_error_log AS (
SELECT
l.id AS id,
l.name AS name,
l.message AS message,
left(l.message, 50) as summary,
l.type AS log_type,
l.create_date AS log_create_date,
l.func AS func,
l.path AS path,
l.line AS line,
bu.id AS build_id,
bu.name AS bu_name,
bu.dest AS dest,
bu.local_state AS local_state,
bu.local_result AS local_result,
bu.global_state AS global_state,
bu.global_result AS global_result,
bu.create_date AS bu_create_date,
bu.committer AS committer,
bu.author AS author,
bu.host AS host,
bu.config_id AS config_id,
bu.parent_id AS parent_id,
bu.hidden AS hidden,
br.id AS branch_id,
br.branch_name AS branch_name,
re.id AS repo_id,
re.name AS repo_name
FROM
ir_logging AS l
JOIN
runbot_build bu ON l.build_id = bu.id
JOIN
runbot_branch br ON br.id = bu.branch_id
JOIN
runbot_repo re ON br.repo_id = re.id
WHERE
l.level = 'ERROR'
)""")

View File

@ -27,4 +27,7 @@ access_runbot_error_regex_user,runbot_error_regex_user,runbot.model_runbot_error
access_runbot_error_regex_manager,runbot_error_regex_manager,runbot.model_runbot_error_regex,runbot.group_runbot_admin,1,1,1,1
access_runbot_host_user,runbot_host_user,runbot.model_runbot_host,group_user,1,0,0,0
access_runbot_host_manager,runbot_host_manager,runbot.model_runbot_host,runbot.group_runbot_admin,1,1,1,1
access_runbot_host_manager,runbot_host_manager,runbot.model_runbot_host,runbot.group_runbot_admin,1,1,1,1
access_runbot_error_log_user,runbot_error_log_user,runbot.model_runbot_error_log,group_user,1,0,0,0
access_runbot_error_log_manager,runbot_error_log_manager,runbot.model_runbot_error_log,runbot.group_runbot_admin,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
27
28
29
30
31
32
33

View File

@ -0,0 +1,103 @@
<odoo>
<data>
<record id="runbot_error_log_form_view" model="ir.ui.view">
<field name="name">Runbot Error Log form view</field>
<field name="model">runbot.error.log</field>
<field name="arch" type="xml">
<form string="Build Error">
<header>
</header>
<sheet>
<div class="oe_button_box" name="button_box" groups="base.group_user">
</div>
<div class="oe_title">
<h1><field name="build_id"/></h1>
<field name="build_url" widget="url"/>
</div>
<group>
<group>
<field name="repo_short_name"/>
<field name="branch_name"/>
<field name="log_type"/>
</group>
<group>
<field name="name"/>
<field name="func"/>
<field name="path"/>
</group>
</group>
<notebook>
<page string="Log message" name="log_message">
<group>
<field name="message"/>
</group>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="runbot_error_log_tree_view" model="ir.ui.view">
<field name="name">Runbot Error Log tree view</field>
<field name="model">runbot.error.log</field>
<field name="arch" type="xml">
<tree string="Build Errors">
<button name="action_goto_build" type="object" icon="fa-external-link "/>
<field name="build_id"/>
<field name="log_create_date"/>
<field name="repo_short_name"/>
<field name="branch_name"/>
<field name="name"/>
<field name="func"/>
<field name="path"/>
<field name="summary"/>
<field name="log_type"/>
</tree>
</field>
</record>
<record id="runbot_logs_search_view" model="ir.ui.view">
<field name="name">runbot.error.log.filter</field>
<field name="model">runbot.error.log</field>
<field name="arch" type="xml">
<search string="Search master">
<field name="message"/>
<field name="name" string="Module"/>
<field name="func"/>
<field name="branch_name"/>
<field name="repo_name"/>
<field name="build_id"/>
<filter string="Failed builds" name="failed_builds" domain="[('global_state', '=', 'done'), ('global_result', '=', 'ko')]"/>
<separator/>
<filter string="Master branches" name="master_branches" domain="[('branch_name', '=', 'master')]"/>
</search>
</field>
</record>
<record id="open_view_error_log_tree" model="ir.actions.act_window">
<field name="name">Error Logs</field>
<field name="res_model">runbot.error.log</field>
<field name="view_mode">tree,form</field>
<field name="context">{'search_default_master_branches': True, 'search_default_failed_builds': True}</field>
</record>
<menuitem
id="runbot_log_menu"
name="Logs"
parent="runbot_menu_root"
sequence="50"
/>
<menuitem
name="Error Logs"
id="runbot_menu_error_logs"
parent="runbot_log_menu"
sequence="20"
action="open_view_error_log_tree"
/>
</data>
</odoo>