@@ -3215,7 +3215,28 @@ async def compose_up(compose: PodmanCompose, args: argparse.Namespace) -> int |
32153215
32163216 max_service_length = 0
32173217 for cnt in compose .containers :
3218- curr_length = len (cnt ["_service" ])
3218+ # Saltar contenedores excluidos
3219+ if cnt ["_service" ] in excluded :
3220+ continue
3221+
3222+ service_name = cnt ["_service" ]
3223+ container_name = cnt ["name" ]
3224+
3225+ if getattr (args , 'names' , False ):
3226+ # Con -n: mostrar solo servicio_numero (sin prefijo de proyecto)
3227+ expected_name = compose .format_name (service_name , str (cnt ["num" ]))
3228+
3229+ if container_name == expected_name :
3230+ # Es un nombre generado automáticamente, mostrar solo servicio_numero
3231+ display_name = compose .join_name_parts (service_name , str (cnt ["num" ]))
3232+ else :
3233+ # Es un container_name personalizado, usarlo tal como está
3234+ display_name = container_name
3235+ else :
3236+ # Sin -n: mostrar nombre completo del contenedor (comportamiento por defecto)
3237+ display_name = container_name
3238+
3239+ curr_length = len (display_name )
32193240 max_service_length = curr_length if curr_length > max_service_length else max_service_length
32203241
32213242 tasks : set [asyncio .Task ] = set ()
@@ -3237,11 +3258,33 @@ async def handle_sigint() -> None:
32373258 loop .add_signal_handler (signal .SIGINT , lambda : asyncio .create_task (handle_sigint ()))
32383259
32393260 for i , cnt in enumerate (compose .containers ):
3240- # Add colored service prefix to output by piping output through sed
3261+ # Add colored service prefix to output like docker-compose
32413262 color_idx = i % len (compose .console_colors )
32423263 color = compose .console_colors [color_idx ]
3243- space_suffix = " " * (max_service_length - len (cnt ["_service" ]) + 1 )
3244- log_formatter = "{}[{}]{}|\x1b [0m" .format (color , cnt ["_service" ], space_suffix )
3264+
3265+ # Determinar el nombre a mostrar
3266+ service_name = cnt ["_service" ]
3267+ container_name = cnt ["name" ]
3268+
3269+ if getattr (args , 'names' , False ):
3270+ # Con -n: mostrar solo servicio_numero (sin prefijo de proyecto)
3271+ expected_name = compose .format_name (service_name , str (cnt ["num" ]))
3272+
3273+ if container_name == expected_name :
3274+ # Es un nombre generado automáticamente, mostrar solo servicio_numero
3275+ display_name = compose .join_name_parts (service_name , str (cnt ["num" ]))
3276+ else :
3277+ # Es un container_name personalizado, usarlo tal como está
3278+ display_name = container_name
3279+ else :
3280+ # Sin -n: mostrar nombre completo del contenedor (comportamiento por defecto)
3281+ display_name = container_name
3282+
3283+ # Calcular espacios para alinear el | exactamente
3284+ # max_service_length + 1 espacio, menos la longitud del display_name actual
3285+ space_suffix = " " * (max_service_length + 1 - len (display_name ))
3286+ log_formatter = "{}{}{}|\x1b [0m" .format (color , display_name , space_suffix )
3287+
32453288 if cnt ["_service" ] in excluded :
32463289 log .debug ("** skipping: %s" , cnt ["name" ])
32473290 continue
@@ -3596,29 +3639,149 @@ async def compose_logs(compose: PodmanCompose, args: argparse.Namespace) -> None
35963639 if not args .services and not args .latest :
35973640 args .services = container_names_by_service .keys ()
35983641 compose .assert_services (args .services )
3642+
35993643 targets = []
3644+ service_by_container = {}
3645+
36003646 for service in args .services :
3601- targets .extend (container_names_by_service [service ])
3602- podman_args = []
3603- if args .follow :
3604- podman_args .append ("-f" )
3605- if args .latest :
3606- podman_args .append ("-l" )
3607- if args .names :
3608- podman_args .append ("-n" )
3609- if args .since :
3610- podman_args .extend (["--since" , args .since ])
3611- # the default value is to print all logs which is in podman = 0 and not
3612- # needed to be passed
3613- if args .tail and args .tail != "all" :
3614- podman_args .extend (["--tail" , args .tail ])
3615- if args .timestamps :
3616- podman_args .append ("-t" )
3617- if args .until :
3618- podman_args .extend (["--until" , args .until ])
3619- for target in targets :
3620- podman_args .append (target )
3621- await compose .podman .run ([], "logs" , podman_args )
3647+ containers = container_names_by_service [service ]
3648+ targets .extend (containers )
3649+ for container in containers :
3650+ service_by_container [container ] = service
3651+
3652+ should_use_colors = (
3653+ (len (args .services ) > 1 or args .names )
3654+ and not args .latest
3655+ and sys .stdout .isatty ()
3656+ and not getattr (args , "no_color" , False )
3657+ )
3658+
3659+ if should_use_colors :
3660+ # Calcular la longitud máxima para alineación, igual que en compose_up
3661+ max_service_length = 0
3662+ for target in targets :
3663+ cnt = compose .container_by_name [target ]
3664+ service_name = cnt ["_service" ]
3665+ container_name = cnt ["name" ]
3666+
3667+ if getattr (args , 'names' , False ):
3668+ # Con -n: mostrar solo servicio_numero (sin prefijo de proyecto)
3669+ expected_name = compose .format_name (service_name , str (cnt ["num" ]))
3670+
3671+ if container_name == expected_name :
3672+ # Es un nombre generado automáticamente, mostrar solo servicio_numero
3673+ display_name = compose .join_name_parts (service_name , str (cnt ["num" ]))
3674+ else :
3675+ # Es un container_name personalizado, usarlo tal como está
3676+ display_name = container_name
3677+ else :
3678+ # Sin -n: mostrar nombre completo del contenedor (comportamiento por defecto)
3679+ display_name = container_name
3680+
3681+ curr_length = len (display_name )
3682+ max_service_length = (
3683+ curr_length if curr_length > max_service_length else max_service_length
3684+ )
3685+
3686+ tasks = []
3687+ service_colors = {}
3688+
3689+ for target in targets :
3690+ cnt = compose .container_by_name [target ]
3691+ service_name = cnt ["_service" ]
3692+ container_name = cnt ["name" ]
3693+
3694+ # Aplicar la misma lógica de display_name que en compose_up
3695+ if getattr (args , 'names' , False ):
3696+ # Con -n: mostrar solo servicio_numero (sin prefijo de proyecto)
3697+ expected_name = compose .format_name (service_name , str (cnt ["num" ]))
3698+
3699+ if container_name == expected_name :
3700+ # Es un nombre generado automáticamente, mostrar solo servicio_numero
3701+ display_name = compose .join_name_parts (service_name , str (cnt ["num" ]))
3702+ else :
3703+ # Es un container_name personalizado, usarlo tal como está
3704+ display_name = container_name
3705+ else :
3706+ # Sin -n: mostrar nombre completo del contenedor (comportamiento por defecto)
3707+ display_name = container_name
3708+
3709+ # Asignar color por servicio (no por contenedor individual)
3710+ if service_name not in service_colors :
3711+ color_idx = len (service_colors ) % len (compose .console_colors )
3712+ service_colors [service_name ] = compose .console_colors [color_idx ]
3713+
3714+ color = service_colors [service_name ]
3715+
3716+ # Calcular espacios para alinear el | exactamente, igual que en compose_up
3717+ # max_service_length + 1 espacio, menos la longitud del display_name actual
3718+ space_suffix = " " * (max_service_length + 1 - len (display_name ))
3719+ log_formatter = "{}{}{}|\x1b [0m" .format (color , display_name , space_suffix )
3720+
3721+ podman_args = []
3722+ if args .follow :
3723+ podman_args .append ("-f" )
3724+ if args .names :
3725+ podman_args .append ("-n" )
3726+ if args .since :
3727+ podman_args .extend (["--since" , args .since ])
3728+ if args .tail and args .tail != "all" :
3729+ podman_args .extend (["--tail" , args .tail ])
3730+ if args .timestamps :
3731+ podman_args .append ("-t" )
3732+ if args .until :
3733+ podman_args .extend (["--until" , args .until ])
3734+ podman_args .append (target )
3735+
3736+ task = asyncio .create_task (
3737+ compose .podman .run ([], "logs" , podman_args , log_formatter = log_formatter ),
3738+ name = f"logs-{ service_name } -{ target } " ,
3739+ )
3740+ tasks .append (task )
3741+
3742+ async def handle_sigint () -> None :
3743+ log .info ("Caught SIGINT or Ctrl+C, stopping log streaming..." )
3744+ for task in tasks :
3745+ if not task .done ():
3746+ task .cancel ()
3747+
3748+ if sys .platform != 'win32' :
3749+ loop = asyncio .get_event_loop ()
3750+ loop .add_signal_handler (signal .SIGINT , lambda : asyncio .create_task (handle_sigint ()))
3751+
3752+ try :
3753+ await asyncio .gather (* tasks )
3754+ except KeyboardInterrupt :
3755+ for task in tasks :
3756+ if not task .done ():
3757+ task .cancel ()
3758+ await asyncio .gather (* tasks , return_exceptions = True )
3759+ except Exception as e :
3760+ log .error ("Error in logs command: %s" , e )
3761+ for task in tasks :
3762+ if not task .done ():
3763+ task .cancel ()
3764+ await asyncio .gather (* tasks , return_exceptions = True )
3765+ raise
3766+ else :
3767+ podman_args = []
3768+ if args .follow :
3769+ podman_args .append ("-f" )
3770+ if args .latest :
3771+ podman_args .append ("-l" )
3772+ if args .names :
3773+ podman_args .append ("-n" )
3774+ if args .since :
3775+ podman_args .extend (["--since" , args .since ])
3776+ if args .tail and args .tail != "all" :
3777+ podman_args .extend (["--tail" , args .tail ])
3778+ if args .timestamps :
3779+ podman_args .append ("-t" )
3780+ if args .until :
3781+ podman_args .extend (["--until" , args .until ])
3782+ for target in targets :
3783+ podman_args .append (target )
3784+ await compose .podman .run ([], "logs" , podman_args )
36223785
36233786
36243787@cmd_run (podman_compose , "config" , "displays the compose file" )
@@ -3877,6 +4040,12 @@ def compose_up_parse(parser: argparse.ArgumentParser) -> None:
38774040 help = "Return the exit code of the selected service container. "
38784041 "Implies --abort-on-container-exit." ,
38794042 )
4043+ parser .add_argument (
4044+ "-n" ,
4045+ "--names" ,
4046+ action = "store_true" ,
4047+ help = "Show short service names instead of full container names in logs" ,
4048+ )
38804049
38814050
38824051@cmd_parse (podman_compose , "down" )
0 commit comments