4444""" 
4545_METRICS  =  dict ()
4646
47+ # Global container socket and runtime information for telemetry 
48+ # This persists across context boundaries to ensure accurate telemetry reporting 
49+ _CONTAINER_RUNTIME_INFO : Dict [str , Optional [str ]] =  {"container_socket_path" : None , "admin_preference" : None }
50+ 
4751
4852@dataclass  
4953class  ProjectDetails :
@@ -241,9 +245,8 @@ def _send_command_run_metrics(ctx: Context, duration: int, exit_reason: str, exi
241245    # Add container engine information for all command runs 
242246    metric_specific_attributes ["containerEngine" ] =  metric ._get_container_host ()
243247
244-     # Add admin container preference (None if not set) 
245-     admin_pref  =  getattr (ctx , "admin_container_preference" , None )
246-     metric_specific_attributes ["adminContainerPreference" ] =  admin_pref 
248+     # Add admin container preference from global storage (set by container client factory) 
249+     metric_specific_attributes ["adminContainerPreference" ] =  metric ._get_container_admin_preference ()
247250
248251    metric .add_data ("metricSpecificAttributes" , metric_specific_attributes )
249252    # Metric about command's execution characteristics 
@@ -404,6 +407,37 @@ def emit_all_metrics():
404407        emit_metric (key )
405408
406409
410+ def  set_container_socket_host_telemetry (
411+     container_socket_path : Optional [str ] =  None , admin_preference : Optional [str ] =  None 
412+ ):
413+     """ 
414+     Set container socket path and admin preference for telemetry collection. 
415+ 
416+     This function stores container socket information globally to ensure it persists 
417+     across context boundaries and is available during telemetry collection. 
418+ 
419+     Args: 
420+         container_socket_path: The socket path being used (e.g., "unix:///var/run/docker.sock", "unix://~/.finch/finch.sock") 
421+         admin_preference: The administrator's container preference (e.g., "finch", "docker", None) 
422+     """ 
423+     if  container_socket_path  is  not   None :
424+         _CONTAINER_RUNTIME_INFO ["container_socket_path" ] =  container_socket_path 
425+         LOG .debug (f"Set global container socket path: container_socket_path={ container_socket_path }  " )
426+     if  admin_preference  is  not   None :
427+         _CONTAINER_RUNTIME_INFO ["admin_preference" ] =  admin_preference 
428+         LOG .debug (f"Set global container runtime info: admin_preference={ admin_preference }  " )
429+ 
430+ 
431+ def  get_container_runtime_telemetry_info () ->  Dict [str , Optional [str ]]:
432+     """ 
433+     Get container socket path and runtime information for telemetry collection. 
434+ 
435+     Returns: 
436+         Dict containing container_socket_path and admin_preference 
437+     """ 
438+     return  _CONTAINER_RUNTIME_INFO 
439+ 
440+ 
407441class  Metric :
408442    """ 
409443    Metric class to store metric data and adding common attributes 
@@ -487,35 +521,31 @@ def _get_execution_environment(self) -> str:
487521
488522    def  _get_container_host (self ) ->  str :
489523        """ 
490-         Returns the container engine being used with context-first  detection: 
491-         1. If actual runtime type is stored in context, use that (for native SAM CLI clients like Finch ) 
524+         Returns the container engine being used with socket path  detection: 
525+         1. Check global container socket path (set by container client factory ) 
492526        2. Otherwise, fall back to DOCKER_HOST environment variable detection (for custom configurations) 
493527        """ 
494-         try :
495-             # First, try to get the actual runtime type from context (same pattern as admin_container_preference) 
496-             ctx  =  Context .get_current_context ()
497-             if  ctx :
498-                 actual_runtime  =  getattr (ctx , "actual_container_runtime" , None )
499-                 if  actual_runtime :
500-                     return  str (actual_runtime )
501-         except  (RuntimeError , ImportError ):
502-             # No Click context available 
503-             pass 
528+         # First, check global container socket path (set by container client factory) 
529+         global_runtime_info  =  get_container_runtime_telemetry_info ()
530+         if  global_runtime_info ["container_socket_path" ]:
531+             LOG .debug (f"Using global container socket path: { global_runtime_info ['container_socket_path' ]}  " )
532+             return  self ._get_container_engine_from_socket_path (global_runtime_info ["container_socket_path" ])
504533
505534        # Fall back to environment variable detection for custom DOCKER_HOST configurations 
506-         LOG .debug ("No container runtime in context, falling back to DOCKER_HOST detection" )
507-         return  self ._get_container_host_from_env ()
535+         docker_host  =  os .environ .get ("DOCKER_HOST" , "" )
536+         LOG .debug (f"No container socket path in global storage, falling back to DOCKER_HOST detection: { docker_host }  " )
537+         return  self ._get_container_engine_from_socket_path (docker_host )
508538
509-     def  _get_container_host_from_env (self ) ->  str :
539+     def  _get_container_engine_from_socket_path (self ,  socket_path :  str ) ->  str :
510540        """ 
511-         Detect container engine from environment variables for custom DOCKER_HOST configurations . 
512-         This handles cases where customers manually set DOCKER_HOST to non-native runtimes . 
541+         Detect container engine from socket path . 
542+         This handles detection for any socket path, whether from stored telemetry or environment . 
513543
514544        Translation: 
515545            Value                                          Final Value 
516546
517-             # Case 1: Not set  
518-             - (unset)	                                 -> docker-default 
547+             # Case 1: Empty/None  
548+             - ""                                         -> docker-default 
519549
520550            # Case 2: Check Path-specific 
521551            - unix://~/.colima/default/docker.sock	    -> colima 
@@ -536,38 +566,45 @@ def _get_container_host_from_env(self) -> str:
536566            # Case 5: Other 
537567            - other value	                            -> unknown 
538568        """ 
539-         # Read current DOCKER_HOST directly from environment instead of cached value 
540-         docker_host  =  os .environ .get ("DOCKER_HOST" , "" )
541- 
542-         if  not  docker_host :
569+         if  not  socket_path :
543570            return  "docker-default" 
544571
545-         docker_host  =  docker_host .lower ()
572+         socket_path_lower  =  socket_path .lower ()
546573
547574        # Path-specific mappings (checked first for specificity) 
548575        path_map  =  {".colima/" : "colima" , ".lima/" : "lima" , ".orbstack/" : "orbstack" , ".rd/" : "rancher-desktop" }
549576
550577        # Check path-specific patterns first 
551578        for  path , engine  in  path_map .items ():
552-             if  path  in  docker_host  and  docker_host .endswith ("docker.sock" ):
579+             if  path  in  socket_path_lower  and  socket_path_lower .endswith ("docker.sock" ):
553580                return  engine 
554581
555582        # Socket mappings 
556583        socket_map  =  {"docker.sock" : "docker" , "finch.sock" : "finch" , "podman.sock" : "podman" }
557584
558585        # Check socket patterns 
559586        for  sock , engine  in  socket_map .items ():
560-             if  docker_host .endswith (sock ):
587+             if  socket_path_lower .endswith (sock ):
561588                return  engine 
562589
563590        # TCP patterns 
564-         if  docker_host .startswith ("tcp://" ):
591+         if  socket_path_lower .startswith ("tcp://" ):
565592            local_hosts  =  ["localhost:" , "127.0.0.1:" ]
566-             is_local  =  any (host  in  docker_host  for  host  in  local_hosts )
593+             is_local  =  any (host  in  socket_path_lower  for  host  in  local_hosts )
567594            return  "tcp-local"  if  is_local  else  "tcp-remote" 
568595
569596        return  "unknown" 
570597
598+     def  _get_container_admin_preference (self ) ->  Optional [str ]:
599+         """ 
600+         Get the administrator's container preference from global storage. 
601+ 
602+         Returns: 
603+             Optional[str]: Admin preference value ("finch", "docker", "other", or None) 
604+         """ 
605+         global_runtime_info  =  get_container_runtime_telemetry_info ()
606+         return  global_runtime_info ["admin_preference" ]
607+ 
571608
572609class  MetricDataNotList (Exception ):
573610    pass 
0 commit comments