55import math
66import re
77from time import time
8+ from typing import TypedDict
89from uuid import UUID
910from xml .etree import ElementTree
1011from flask import current_app , g
12+ from cassandra .util import uuid_from_time
1113from argus .backend .db import ScyllaCluster
1214from argus .backend .models .github_issue import GithubIssue , IssueLink
1315from argus .backend .models .web import ArgusEventTypes , ErrorEventEmbeddings , CriticalEventEmbeddings
@@ -78,6 +80,10 @@ class EventSubmitRequest:
7880 nemesis_status : str | None = None
7981
8082
83+ class CoredumpLink (TypedDict ):
84+ log_name : str
85+ log_link : str
86+
8187
8288class SCTService :
8389
@@ -413,8 +419,8 @@ def finalize_nemesis(run_id: str, nemesis_details: dict) -> str:
413419 return "updated"
414420
415421
416- @staticmethod
417- def submit_event (run_id : str , raw_event : RawEventPayload ):
422+ @classmethod
423+ def submit_event (cls , run_id : str , raw_event : RawEventPayload ):
418424 req = EventSubmitRequest (** raw_event )
419425
420426 event = SCTEvent ()
@@ -438,7 +444,13 @@ def submit_event(run_id: str, raw_event: RawEventPayload):
438444 event .known_issue = req .known_issue
439445
440446 event .save ()
441-
447+ try :
448+ if event .event_type .lower () == "coredumpevent" and (link := cls .create_coredump_link (event .message , event .ts )):
449+ run : SCTTestRun = SCTTestRun .get (id = event .run_id )
450+ run .submit_logs ([link ])
451+ run .save ()
452+ except Exception :
453+ LOGGER .warning ("Unable to parse event for coredump links." , exc_info = True )
442454 # Add to unprocessed events queue for ERROR and CRITICAL events
443455 if event .severity in (SCTEventSeverity .ERROR .value , SCTEventSeverity .CRITICAL .value ):
444456 try :
@@ -490,41 +502,56 @@ def submit_events(run_id: str, events: list[dict]) -> str:
490502
491503 return "added"
492504
493- @staticmethod
494- def locate_coredumps (run : SCTTestRun , events : list [EventsBySeverity ]) -> list [dict ]:
505+ @classmethod
506+ def locate_coredumps (cls , run : SCTTestRun , events : list [EventsBySeverity ]) -> list [CoredumpLink ]:
495507 flat_messages : list [str ] = []
496508 links = []
497509 for es in events :
498510 flat_messages .extend (es .last_events )
499511 coredump_events = filter (lambda v : "coredumpevent" in v .lower (), flat_messages )
500- for idx , event in enumerate (coredump_events ):
501- core_pattern = r"corefile_url=(?P<url>.+)$"
502- ts_pattern = r"^(?P<ts>\d{4}-\d{2}-\d{2} ([\d:]*)\.\d{3})"
503- node_name_pattern = r"node=(?P<name>.+)$"
504- core_url_match = re .search (core_pattern , event , re .MULTILINE )
505- node_name_match = re .search (node_name_pattern , event , re .MULTILINE )
506- ts_match = re .search (ts_pattern , event )
507- if core_url_match :
508- node_name = node_name_match .group ("name" ) if node_name_match else f"unknown-node-{ idx } "
509- split_name = node_name .split (" " )
510- node_name = split_name [1 ] if len (split_name ) >= 2 else node_name
511- url = core_url_match .group ("url" )
512- ext = url .rsplit ("." , maxsplit = 1 )[- 1 ]
513- ext = ext if len (ext ) <= 5 else "zst" # Default to .zst if URL doesn't conform
514- timestamp_component = ""
515- if ts_match :
516- try :
517- timestamp = datetime .fromisoformat (ts_match .group ("ts" ))
518- timestamp_component = timestamp .strftime ("-%Y-%m-%d_%H-%M-%S" )
519- except ValueError :
520- pass
521- log_link = {
522- "log_name" : f"core.scylla-{ node_name } { timestamp_component } .{ ext } " ,
523- "log_link" : url
524- }
525- links .append (log_link )
512+ for event in coredump_events :
513+ if link := cls .create_coredump_link (event ):
514+ links .append (link )
526515 return links
527516
517+ @staticmethod
518+ def create_coredump_link (event_message : str , event_ts : datetime | None = None ) -> CoredumpLink | None :
519+ core_pattern = r"corefile_url=(?P<url>.+)$"
520+ ts_pattern = r"^(?P<ts>\d{4}-\d{2}-\d{2} ([\d:]*)\.\d{3})"
521+ node_name_pattern = r"node=(?P<name>.+)$"
522+ core_url_match = re .search (core_pattern , event_message , re .MULTILINE )
523+ node_name_match = re .search (node_name_pattern , event_message , re .MULTILINE )
524+ ts_match = re .search (ts_pattern , event_message )
525+ timestamp = datetime .now (UTC )
526+ if core_url_match :
527+ url = core_url_match .group ("url" )
528+ ext = url .rsplit ("." , maxsplit = 1 )[- 1 ]
529+ ext = ext if len (ext ) <= 5 else "zst" # Default to .zst if URL doesn't conform
530+ timestamp_component = ""
531+ if event_ts :
532+ timestamp_component = event_ts .strftime ("-%Y-%m-%d_%H-%M-%S" )
533+ elif ts_match :
534+ try :
535+ timestamp = datetime .fromisoformat (ts_match .group ("ts" ))
536+ timestamp_component = timestamp .strftime ("-%Y-%m-%d_%H-%M-%S" )
537+ except ValueError :
538+ pass
539+ else :
540+ timestamp_component = timestamp .strftime ("-%Y-%m-%d_%H-%M-%S" )
541+ node_name = (
542+ node_name_match .group ("name" )
543+ if node_name_match
544+ else f"unknown-node-{ uuid_from_time (event_ts or timestamp , node = 1000 , clock_seq = 128 )} "
545+ )
546+ split_name = node_name .split (" " )
547+ node_name = split_name [1 ] if len (split_name ) >= 2 else node_name
548+ log_link = {
549+ "log_name" : f"core.scylla-{ node_name } { timestamp_component } .{ ext } " ,
550+ "log_link" : url
551+ }
552+ return log_link
553+ return None
554+
528555 @staticmethod
529556 def get_similar_events (run_id : str ) -> list [dict ]:
530557 """Get similar events for each event in a test run
0 commit comments