mirror of
https://github.com/odoo/runbot.git
synced 2025-03-15 15:35:46 +07:00
[IMP] runbot: also use module name when fingerprinting
When build logs are scanned, only the message is used for the fingerprint. When a message is too generic, the created build error use the first module name it finds but links all other builds with the same message to this build error. It's preferable to create more build errors when they occur in different modules. With this commit, the module name is taken into account when computing the fingerprint.
This commit is contained in:
parent
3ae3f6dff3
commit
1d98bfafa5
@ -1183,8 +1183,7 @@ class BuildResult(models.Model):
|
||||
def _parse_logs(self):
|
||||
""" Parse build logs to classify errors """
|
||||
BuildError = self.env['runbot.build.error']
|
||||
# only parse logs from builds in error and not already scanned
|
||||
builds_to_scan = self.search([('id', 'in', self.ids), ('local_result', 'in', ('ko', 'killed', 'warn')), ('build_error_link_ids', '=', False)])
|
||||
builds_to_scan = self.search([('id', 'in', self.ids), ('local_result', 'in', ('ko', 'killed', 'warn'))])
|
||||
ir_logs = self.env['ir.logging'].search([('level', 'in', ('ERROR', 'WARNING', 'CRITICAL')), ('type', '=', 'server'), ('build_id', 'in', builds_to_scan.ids)])
|
||||
return BuildError._parse_logs(ir_logs)
|
||||
|
||||
|
@ -96,7 +96,7 @@ class BuildError(models.Model):
|
||||
cleaned_content = cleaners._r_sub(content)
|
||||
vals.update({
|
||||
'cleaned_content': cleaned_content,
|
||||
'fingerprint': self._digest(cleaned_content)
|
||||
'fingerprint': self._digest(cleaned_content, vals.get('module_name'))
|
||||
})
|
||||
records = super().create(vals_list)
|
||||
records.action_assign()
|
||||
@ -112,8 +112,9 @@ class BuildError(models.Model):
|
||||
if not vals['active'] and build_error.last_seen_date + relativedelta(days=1) > fields.Datetime.now():
|
||||
raise UserError("This error broke less than one day ago can only be deactivated by admin")
|
||||
if 'cleaned_content' in vals:
|
||||
vals.update({'fingerprint': self._digest(vals['cleaned_content'])})
|
||||
result = super(BuildError, self).write(vals)
|
||||
module_name = vals.get('module_name', self.module_name)
|
||||
vals.update({'fingerprint': self._digest(vals['cleaned_content'], module_name)})
|
||||
result = super().write(vals)
|
||||
if vals.get('parent_id'):
|
||||
for build_error in self:
|
||||
parent = build_error.parent_id
|
||||
@ -202,11 +203,15 @@ class BuildError(models.Model):
|
||||
error.error_history_ids = self.search([('fingerprint', 'in', fingerprints), ('active', '=', False), ('id', '!=', error.id or False)])
|
||||
|
||||
@api.model
|
||||
def _digest(self, s):
|
||||
def _digest(self, s, module_name=''):
|
||||
"""compute a sha256 digest of a string combined with a module_name
|
||||
|
||||
:param str s: a cleaned error
|
||||
:param str module_name: a module name
|
||||
:return str: a sha256 digest
|
||||
"""
|
||||
return a hash 256 digest of the string s
|
||||
"""
|
||||
return hashlib.sha256(s.encode()).hexdigest()
|
||||
to_fingerprint = f"{module_name}\n{s}"
|
||||
return hashlib.sha256(to_fingerprint.encode()).hexdigest()
|
||||
|
||||
@api.model
|
||||
def _parse_logs(self, ir_logs):
|
||||
@ -220,7 +225,7 @@ class BuildError(models.Model):
|
||||
for log in ir_logs:
|
||||
if search_regs._r_search(log.message):
|
||||
continue
|
||||
fingerprint = self._digest(cleaning_regs._r_sub(log.message))
|
||||
fingerprint = self._digest(cleaning_regs._r_sub(log.message), log.name)
|
||||
hash_dict[fingerprint] |= log
|
||||
|
||||
build_errors = self.env['runbot.build.error']
|
||||
|
@ -59,7 +59,7 @@ class IrLogging(models.Model):
|
||||
for ir_logging in self:
|
||||
ir_logging.error_id = False
|
||||
if ir_logging.level in ('ERROR', 'CRITICAL', 'WARNING') and ir_logging.type == 'server':
|
||||
fingerprints[self.env['runbot.build.error']._digest(cleaning_regexes._r_sub(ir_logging.message))].append(ir_logging)
|
||||
fingerprints[self.env['runbot.build.error']._digest(cleaning_regexes._r_sub(ir_logging.message), ir_logging.name)].append(ir_logging)
|
||||
for build_error in self.env['runbot.build.error'].search([('fingerprint', 'in', list(fingerprints.keys()))], order='active asc'):
|
||||
for ir_logging in fingerprints[build_error.fingerprint]:
|
||||
ir_logging.error_id = build_error.id
|
||||
|
Loading…
Reference in New Issue
Block a user