@@ -492,6 +492,7 @@ pub async fn insert_error_entries(
492492 project_id : Uuid ,
493493 data_entry_id : Uuid ,
494494 data : ErrorTracking ,
495+ identity_key : Option < String > ,
495496 tracking_ctx : Option < TrackingContext > ,
496497) -> Result < ( ) , HandlerResponse > {
497498 let mut error_rows = Vec :: new ( ) ;
@@ -517,6 +518,7 @@ pub async fn insert_error_entries(
517518 count : occurrence_count,
518519 data_entry_id,
519520 session_id : data. session_id . clone ( ) ,
521+ identity_key,
520522 build_id : data. build_id . clone ( ) ,
521523 created_at,
522524 } ;
@@ -537,6 +539,20 @@ pub async fn insert_error_entries(
537539 Ok ( ( ) )
538540}
539541
542+ pub fn resolve_identity_key (
543+ session_id : Option < & str > ,
544+ fallback_identifier : Option < & str > ,
545+ ) -> Option < String > {
546+ session_id
547+ . filter ( |value| !value. is_empty ( ) )
548+ . map ( str:: to_string)
549+ . or_else ( || {
550+ fallback_identifier
551+ . filter ( |value| !value. is_empty ( ) )
552+ . map ( str:: to_string)
553+ } )
554+ }
555+
540556pub async fn process_failed_request (
541557 batch_queue : & BatchQueue ,
542558 pool : & sqlx:: PgPool ,
@@ -565,7 +581,7 @@ async fn process_collect_request(
565581 id,
566582 mut data,
567583 errors,
568- session_id : _ ,
584+ session_id,
569585 } = req;
570586
571587 let server_id = id
@@ -598,12 +614,21 @@ async fn process_collect_request(
598614 if ctx. error_tracking_enabled
599615 && let Some ( errors) = errors
600616 {
601- for error in errors {
617+ let fallback_identity = server_id. to_string ( ) ;
618+ for mut error in errors {
619+ if error. session_id . is_none ( ) {
620+ error. session_id = session_id. clone ( ) ;
621+ }
622+ let identity_key = resolve_identity_key (
623+ error. session_id . as_deref ( ) ,
624+ Some ( fallback_identity. as_str ( ) ) ,
625+ ) ;
602626 insert_error_entries (
603627 batch_queue,
604628 ctx. project_id ,
605629 data_entry_id,
606630 error,
631+ identity_key,
607632 Some ( tracking_ctx. clone ( ) ) ,
608633 )
609634 . await
@@ -694,6 +719,7 @@ async fn process_web_request(
694719 token : token. into ( ) ,
695720 organization_id : ctx. organization_id . as_deref ( ) . map ( Into :: into) ,
696721 } ;
722+ let fallback_identity = resolved_user_id. to_string ( ) ;
697723
698724 let data_entry_id = insert_web_event (
699725 batch_queue,
@@ -714,11 +740,19 @@ async fn process_web_request(
714740 if error. session_id . is_none ( ) {
715741 error. session_id = parsed. session_id . clone ( ) ;
716742 }
743+ if error. build_id . is_none ( ) {
744+ error. build_id = parsed. build_id . clone ( ) ;
745+ }
746+ let identity_key = resolve_identity_key (
747+ error. session_id . as_deref ( ) ,
748+ Some ( fallback_identity. as_str ( ) ) ,
749+ ) ;
717750 insert_error_entries (
718751 batch_queue,
719752 ctx. project_id ,
720753 data_entry_id,
721754 error,
755+ identity_key,
722756 Some ( tracking_ctx. clone ( ) ) ,
723757 )
724758 . await
@@ -1102,4 +1136,29 @@ mod tests {
11021136 ) ;
11031137 }
11041138 }
1139+
1140+ mod identity_resolution {
1141+ use super :: * ;
1142+
1143+ #[ test]
1144+ fn prefers_session_id_when_present ( ) {
1145+ assert_eq ! (
1146+ resolve_identity_key( Some ( "session-1" ) , Some ( "fallback-1" ) ) ,
1147+ Some ( "session-1" . to_string( ) )
1148+ ) ;
1149+ }
1150+
1151+ #[ test]
1152+ fn falls_back_when_session_missing ( ) {
1153+ assert_eq ! (
1154+ resolve_identity_key( None , Some ( "fallback-1" ) ) ,
1155+ Some ( "fallback-1" . to_string( ) )
1156+ ) ;
1157+ }
1158+
1159+ #[ test]
1160+ fn ignores_empty_values ( ) {
1161+ assert_eq ! ( resolve_identity_key( Some ( "" ) , Some ( "" ) ) , None ) ;
1162+ }
1163+ }
11051164}
0 commit comments