@@ -272,7 +272,7 @@ def __extract_ps_base_file(self) -> Generator[dict, None, None]:
272272 module = self .module_name ,
273273 data = {'source' : entity_type , 'uid' : uid , 'pid' : pid , 'ppid' : ppid , 'ppname' : ppname }
274274 )
275- if self .add_if_full_command_is_not_in_set (ps_event .message , ps_event .datetime , uid ):
275+ if self .add_if_full_command_is_not_in_set (ps_event .message , ps_event .datetime , uid , pid , ppname ):
276276 yield ps_event .to_dict ()
277277 except Exception as e :
278278 logger .exception (f"ERROR while extracting { entity_type } file. { e } " )
@@ -297,7 +297,7 @@ def __extract_ps_thread_file(self) -> Generator[dict, None, None]:
297297 module = self .module_name ,
298298 data = {'source' : entity_type , 'uid' : uid , 'pid' : pid , 'ppid' : ppid , 'ppname' : ppname }
299299 )
300- if self .add_if_full_command_is_not_in_set (ps_event .message , ps_event .datetime , uid ):
300+ if self .add_if_full_command_is_not_in_set (ps_event .message , ps_event .datetime , uid , pid , ppname ):
301301 yield ps_event .to_dict ()
302302 except Exception as e :
303303 logger .exception (f"ERROR while extracting { entity_type } file. { e } " )
@@ -322,7 +322,7 @@ def __extract_ps_spindump_nosymbols_file(self) -> Generator[dict, None, None]:
322322 # Spindump has a direct 'parent' field with the parent process name
323323 ppname = p .get ('parent' )
324324
325- if self .add_if_full_command_is_not_in_set (self ._strip_flags (process_name ), event_datetime , uid ):
325+ if self .add_if_full_command_is_not_in_set (self ._strip_flags (process_name ), event_datetime , uid , pid , ppname ):
326326 yield Event (
327327 datetime = event_datetime ,
328328 message = self ._strip_flags (process_name ),
@@ -334,7 +334,7 @@ def __extract_ps_spindump_nosymbols_file(self) -> Generator[dict, None, None]:
334334 for t in p ['threads' ]:
335335 try :
336336 thread_name = f"{ self ._strip_flags (process_name )} ::{ t ['thread_name' ]} "
337- if self .add_if_full_command_is_not_in_set (thread_name , event_datetime , uid ):
337+ if self .add_if_full_command_is_not_in_set (thread_name , event_datetime , uid , pid , ppname ):
338338 yield Event (
339339 datetime = event_datetime ,
340340 message = self ._strip_flags (thread_name ),
@@ -391,7 +391,7 @@ def __extract_ps_logarchive(self) -> Generator[dict, None, None]:
391391 # Handle the case where extracted_process is a list of paths
392392 if isinstance (extracted_process , list ):
393393 for proc_path in extracted_process :
394- if self .add_if_full_command_is_not_in_set (self ._strip_flags (proc_path ), p_datetime , None ):
394+ if self .add_if_full_command_is_not_in_set (self ._strip_flags (proc_path ), p_datetime , None , None , None ):
395395 yield Event (
396396 p_datetime ,
397397 message = self ._strip_flags (proc_path ),
@@ -401,7 +401,7 @@ def __extract_ps_logarchive(self) -> Generator[dict, None, None]:
401401 ).to_dict ()
402402 else :
403403 # Handle the case where it's a single string
404- if self .add_if_full_command_is_not_in_set (self ._strip_flags (extracted_process ), p_datetime , None ):
404+ if self .add_if_full_command_is_not_in_set (self ._strip_flags (extracted_process ), p_datetime , None , None , None ):
405405 yield Event (
406406 datetime = p_datetime ,
407407 message = self ._strip_flags (extracted_process ),
@@ -411,7 +411,7 @@ def __extract_ps_logarchive(self) -> Generator[dict, None, None]:
411411 ).to_dict ()
412412
413413 # Process the original process name
414- if self .add_if_full_command_is_not_in_set (self ._strip_flags (p ['data' ]['process' ]), p_datetime , euid ):
414+ if self .add_if_full_command_is_not_in_set (self ._strip_flags (p ['data' ]['process' ]), p_datetime , euid , pid , None ):
415415 yield Event (
416416 datetime = p_datetime ,
417417 message = self ._strip_flags (p ['data' ]['process' ]),
@@ -431,7 +431,7 @@ def __extract_ps_uuid2path(self) -> Generator[dict, None, None]:
431431 entity_type = 'uuid2path'
432432 try :
433433 for p in UUID2PathParser (self .config , self .case_id ).get_result ().values ():
434- if self .add_if_full_command_is_not_in_set (self ._strip_flags (p ), self .sysdiagnose_creation_datetime , None ):
434+ if self .add_if_full_command_is_not_in_set (self ._strip_flags (p ), self .sysdiagnose_creation_datetime , None , None , None ):
435435 yield Event (
436436 datetime = self .sysdiagnose_creation_datetime ,
437437 message = self ._strip_flags (p ),
@@ -456,7 +456,7 @@ def __extract_ps_taskinfo(self) -> Generator[dict, None, None]:
456456
457457 p_datetime = datetime .fromisoformat (p ['datetime' ])
458458 pid = p ['data' ].get ('pid' )
459- if self .add_if_full_path_is_not_in_set (self ._strip_flags (p ['data' ]['name' ]), p_datetime , None ):
459+ if self .add_if_full_path_is_not_in_set (self ._strip_flags (p ['data' ]['name' ]), p_datetime , None , pid , None ):
460460 yield Event (
461461 datetime = p_datetime ,
462462 message = self ._strip_flags (p ['data' ]['name' ]),
@@ -468,7 +468,7 @@ def __extract_ps_taskinfo(self) -> Generator[dict, None, None]:
468468 for t in p ['data' ]['threads' ]:
469469 try :
470470 thread_name = f"{ self ._strip_flags (p ['data' ]['name' ])} ::{ t ['thread name' ]} "
471- if self .add_if_full_path_is_not_in_set (thread_name , p_datetime , None ):
471+ if self .add_if_full_path_is_not_in_set (thread_name , p_datetime , None , pid , None ):
472472 yield Event (
473473 p_datetime ,
474474 message = thread_name ,
@@ -492,7 +492,7 @@ def __extract_ps_remotectl_dumpstate(self) -> Generator[dict, None, None]:
492492 remotectl_dumpstate_json = RemotectlDumpstateParser (self .config , self .case_id ).get_result ()
493493 if remotectl_dumpstate_json :
494494 for p in remotectl_dumpstate_json ['Local device' ]['Services' ]:
495- if self .add_if_full_path_is_not_in_set (self ._strip_flags (p ), self .sysdiagnose_creation_datetime , None ):
495+ if self .add_if_full_path_is_not_in_set (self ._strip_flags (p ), self .sysdiagnose_creation_datetime , None , None , None ):
496496 yield Event (
497497 datetime = self .sysdiagnose_creation_datetime ,
498498 message = self ._strip_flags (p ),
@@ -513,7 +513,7 @@ def __extract_ps_logdata_statistics(self) -> Generator[dict, None, None]:
513513 try :
514514 for p in LogDataStatisticsParser (self .config , self .case_id ).get_result ():
515515 p_datetime = datetime .fromisoformat (p ['datetime' ])
516- if self .add_if_full_command_is_not_in_set (self ._strip_flags (p ['data' ]['process' ]), p_datetime , None ):
516+ if self .add_if_full_command_is_not_in_set (self ._strip_flags (p ['data' ]['process' ]), p_datetime , None , None , None ):
517517 yield Event (
518518 datetime = p_datetime ,
519519 message = self ._strip_flags (p ['data' ]['process' ]),
@@ -535,7 +535,7 @@ def __extract_ps_logdata_statistics_txt(self) -> Generator[dict, None, None]:
535535 try :
536536 for p in LogDataStatisticsTxtParser (self .config , self .case_id ).get_result ():
537537 p_datetime = datetime .fromisoformat (p ['datetime' ])
538- if self .add_if_full_path_is_not_in_set (self ._strip_flags (p ['data' ]['process' ]), p_datetime , None ):
538+ if self .add_if_full_path_is_not_in_set (self ._strip_flags (p ['data' ]['process' ]), p_datetime , None , None , None ):
539539 yield Event (
540540 datetime = p_datetime ,
541541 message = self ._strip_flags (p ['data' ]['process' ]),
@@ -547,19 +547,21 @@ def __extract_ps_logdata_statistics_txt(self) -> Generator[dict, None, None]:
547547 except Exception as e :
548548 logger .exception (f"ERROR while extracting { entity_type } . { e } " )
549549
550- def add_if_full_path_is_not_in_set (self , name : str , timestamp : Optional [datetime ] = None , uid : Optional [int ] = None ) -> bool :
550+ def add_if_full_path_is_not_in_set (self , name : str , timestamp : Optional [datetime ] = None , uid : Optional [int ] = None , pid : Optional [ int ] = None , ppname : Optional [ str ] = None ) -> bool :
551551 """
552552 Ensures that a process path is unique before adding it to the shared set,
553553 with time-based deduplication: only keep duplicates if they occur more than 1 hour apart.
554- UID is considered part of the uniqueness - same process with different UID is treated as separate.
554+ UID, PID, and PPNAME are considered part of the uniqueness - same process with different values is treated as separate.
555555
556556 :param name: Process path name
557557 :param timestamp: Timestamp of the process occurrence (optional, for time-based deduplication)
558558 :param uid: User ID of the process (optional, considered in uniqueness check)
559+ :param pid: Process ID (optional, considered in uniqueness check)
560+ :param ppname: Parent process name (optional, considered in uniqueness check)
559561 :return: True if the process was not in the set or last seen > 1 hour ago, False otherwise.
560562 """
561- # Create a unique key that includes both name and UID
562- unique_key = f"{ name } |uid:{ uid } "
563+ # Create a unique key that includes name, UID, PID, and PPNAME
564+ unique_key = f"{ name } |uid:{ uid } |pid: { pid } |ppname: { ppname } "
563565
564566 # If no timestamp provided, use old behavior (always check for duplicates)
565567 if timestamp is None :
@@ -585,19 +587,21 @@ def add_if_full_path_is_not_in_set(self, name: str, timestamp: Optional[datetime
585587 self .process_last_seen [unique_key ] = timestamp
586588 return True
587589
588- def add_if_full_command_is_not_in_set (self , name : str , timestamp : Optional [datetime ] = None , uid : Optional [int ] = None ) -> bool :
590+ def add_if_full_command_is_not_in_set (self , name : str , timestamp : Optional [datetime ] = None , uid : Optional [int ] = None , pid : Optional [ int ] = None , ppname : Optional [ str ] = None ) -> bool :
589591 """
590592 Ensures that a process command is unique before adding it to the shared set,
591593 with time-based deduplication: only keep duplicates if they occur more than 1 hour apart.
592- UID is considered part of the uniqueness - same process with different UID is treated as separate.
594+ UID, PID, and PPNAME are considered part of the uniqueness - same process with different values is treated as separate.
593595
594596 :param name: Process command name
595597 :param timestamp: Timestamp of the process occurrence (optional, for time-based deduplication)
596598 :param uid: User ID of the process (optional, considered in uniqueness check)
599+ :param pid: Process ID (optional, considered in uniqueness check)
600+ :param ppname: Parent process name (optional, considered in uniqueness check)
597601 :return: True if the process was not in the set or last seen > 1 hour ago, False otherwise.
598602 """
599- # Create a unique key that includes both name and UID
600- unique_key = f"{ name } |uid:{ uid } "
603+ # Create a unique key that includes name, UID, PID, and PPNAME
604+ unique_key = f"{ name } |uid:{ uid } |pid: { pid } |ppname: { ppname } "
601605
602606 # If no timestamp provided, use old behavior (always check for duplicates)
603607 if timestamp is None :
0 commit comments