diff --git a/runbot/models/build.py b/runbot/models/build.py index e546125d..16b96421 100644 --- a/runbot/models/build.py +++ b/runbot/models/build.py @@ -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) diff --git a/runbot/models/build_error.py b/runbot/models/build_error.py index b25240e1..1088aace 100644 --- a/runbot/models/build_error.py +++ b/runbot/models/build_error.py @@ -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'] diff --git a/runbot/models/ir_logging.py b/runbot/models/ir_logging.py index 5063dcc9..f6409cb6 100644 --- a/runbot/models/ir_logging.py +++ b/runbot/models/ir_logging.py @@ -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