@@ -3204,7 +3204,28 @@ async def compose_up(compose: PodmanCompose, args: argparse.Namespace) -> int |
32043204
32053205 max_service_length = 0
32063206 for cnt in compose .containers :
3207- curr_length = len (cnt ["_service" ])
3207+ # Saltar contenedores excluidos
3208+ if cnt ["_service" ] in excluded :
3209+ continue
3210+
3211+ service_name = cnt ["_service" ]
3212+ container_name = cnt ["name" ]
3213+
3214+ if getattr (args , 'names' , False ):
3215+ # Con -n: mostrar solo servicio_numero (sin prefijo de proyecto)
3216+ expected_name = compose .format_name (service_name , str (cnt ["num" ]))
3217+
3218+ if container_name == expected_name :
3219+ # Es un nombre generado automáticamente, mostrar solo servicio_numero
3220+ display_name = compose .join_name_parts (service_name , str (cnt ["num" ]))
3221+ else :
3222+ # Es un container_name personalizado, usarlo tal como está
3223+ display_name = container_name
3224+ else :
3225+ # Sin -n: mostrar nombre completo del contenedor (comportamiento por defecto)
3226+ display_name = container_name
3227+
3228+ curr_length = len (display_name )
32083229 max_service_length = curr_length if curr_length > max_service_length else max_service_length
32093230
32103231 tasks : set [asyncio .Task ] = set ()
@@ -3226,11 +3247,33 @@ async def handle_sigint() -> None:
32263247 loop .add_signal_handler (signal .SIGINT , lambda : asyncio .create_task (handle_sigint ()))
32273248
32283249 for i , cnt in enumerate (compose .containers ):
3229- # Add colored service prefix to output by piping output through sed
3250+ # Add colored service prefix to output like docker-compose
32303251 color_idx = i % len (compose .console_colors )
32313252 color = compose .console_colors [color_idx ]
3232- space_suffix = " " * (max_service_length - len (cnt ["_service" ]) + 1 )
3233- log_formatter = "{}[{}]{}|\x1b [0m" .format (color , cnt ["_service" ], space_suffix )
3253+
3254+ # Determinar el nombre a mostrar
3255+ service_name = cnt ["_service" ]
3256+ container_name = cnt ["name" ]
3257+
3258+ if getattr (args , 'names' , False ):
3259+ # Con -n: mostrar solo servicio_numero (sin prefijo de proyecto)
3260+ expected_name = compose .format_name (service_name , str (cnt ["num" ]))
3261+
3262+ if container_name == expected_name :
3263+ # Es un nombre generado automáticamente, mostrar solo servicio_numero
3264+ display_name = compose .join_name_parts (service_name , str (cnt ["num" ]))
3265+ else :
3266+ # Es un container_name personalizado, usarlo tal como está
3267+ display_name = container_name
3268+ else :
3269+ # Sin -n: mostrar nombre completo del contenedor (comportamiento por defecto)
3270+ display_name = container_name
3271+
3272+ # Calcular espacios para alinear el | exactamente
3273+ # max_service_length + 1 espacio, menos la longitud del display_name actual
3274+ space_suffix = " " * (max_service_length + 1 - len (display_name ))
3275+ log_formatter = "{}{}{}|\x1b [0m" .format (color , display_name , space_suffix )
3276+
32343277 if cnt ["_service" ] in excluded :
32353278 log .debug ("** skipping: %s" , cnt ["name" ])
32363279 continue
@@ -3585,29 +3628,149 @@ async def compose_logs(compose: PodmanCompose, args: argparse.Namespace) -> None
35853628 if not args .services and not args .latest :
35863629 args .services = container_names_by_service .keys ()
35873630 compose .assert_services (args .services )
3631+
35883632 targets = []
3633+ service_by_container = {}
3634+
35893635 for service in args .services :
3590- targets .extend (container_names_by_service [service ])
3591- podman_args = []
3592- if args .follow :
3593- podman_args .append ("-f" )
3594- if args .latest :
3595- podman_args .append ("-l" )
3596- if args .names :
3597- podman_args .append ("-n" )
3598- if args .since :
3599- podman_args .extend (["--since" , args .since ])
3600- # the default value is to print all logs which is in podman = 0 and not
3601- # needed to be passed
3602- if args .tail and args .tail != "all" :
3603- podman_args .extend (["--tail" , args .tail ])
3604- if args .timestamps :
3605- podman_args .append ("-t" )
3606- if args .until :
3607- podman_args .extend (["--until" , args .until ])
3608- for target in targets :
3609- podman_args .append (target )
3610- await compose .podman .run ([], "logs" , podman_args )
3636+ containers = container_names_by_service [service ]
3637+ targets .extend (containers )
3638+ for container in containers :
3639+ service_by_container [container ] = service
3640+
3641+ should_use_colors = (
3642+ (len (args .services ) > 1 or args .names )
3643+ and not args .latest
3644+ and sys .stdout .isatty ()
3645+ and not getattr (args , "no_color" , False )
3646+ )
3647+
3648+ if should_use_colors :
3649+ # Calcular la longitud máxima para alineación, igual que en compose_up
3650+ max_service_length = 0
3651+ for target in targets :
3652+ cnt = compose .container_by_name [target ]
3653+ service_name = cnt ["_service" ]
3654+ container_name = cnt ["name" ]
3655+
3656+ if getattr (args , 'names' , False ):
3657+ # Con -n: mostrar solo servicio_numero (sin prefijo de proyecto)
3658+ expected_name = compose .format_name (service_name , str (cnt ["num" ]))
3659+
3660+ if container_name == expected_name :
3661+ # Es un nombre generado automáticamente, mostrar solo servicio_numero
3662+ display_name = compose .join_name_parts (service_name , str (cnt ["num" ]))
3663+ else :
3664+ # Es un container_name personalizado, usarlo tal como está
3665+ display_name = container_name
3666+ else :
3667+ # Sin -n: mostrar nombre completo del contenedor (comportamiento por defecto)
3668+ display_name = container_name
3669+
3670+ curr_length = len (display_name )
3671+ max_service_length = (
3672+ curr_length if curr_length > max_service_length else max_service_length
3673+ )
3674+
3675+ tasks = []
3676+ service_colors = {}
3677+
3678+ for target in targets :
3679+ cnt = compose .container_by_name [target ]
3680+ service_name = cnt ["_service" ]
3681+ container_name = cnt ["name" ]
3682+
3683+ # Aplicar la misma lógica de display_name que en compose_up
3684+ if getattr (args , 'names' , False ):
3685+ # Con -n: mostrar solo servicio_numero (sin prefijo de proyecto)
3686+ expected_name = compose .format_name (service_name , str (cnt ["num" ]))
3687+
3688+ if container_name == expected_name :
3689+ # Es un nombre generado automáticamente, mostrar solo servicio_numero
3690+ display_name = compose .join_name_parts (service_name , str (cnt ["num" ]))
3691+ else :
3692+ # Es un container_name personalizado, usarlo tal como está
3693+ display_name = container_name
3694+ else :
3695+ # Sin -n: mostrar nombre completo del contenedor (comportamiento por defecto)
3696+ display_name = container_name
3697+
3698+ # Asignar color por servicio (no por contenedor individual)
3699+ if service_name not in service_colors :
3700+ color_idx = len (service_colors ) % len (compose .console_colors )
3701+ service_colors [service_name ] = compose .console_colors [color_idx ]
3702+
3703+ color = service_colors [service_name ]
3704+
3705+ # Calcular espacios para alinear el | exactamente, igual que en compose_up
3706+ # max_service_length + 1 espacio, menos la longitud del display_name actual
3707+ space_suffix = " " * (max_service_length + 1 - len (display_name ))
3708+ log_formatter = "{}{}{}|\x1b [0m" .format (color , display_name , space_suffix )
3709+
3710+ podman_args = []
3711+ if args .follow :
3712+ podman_args .append ("-f" )
3713+ if args .names :
3714+ podman_args .append ("-n" )
3715+ if args .since :
3716+ podman_args .extend (["--since" , args .since ])
3717+ if args .tail and args .tail != "all" :
3718+ podman_args .extend (["--tail" , args .tail ])
3719+ if args .timestamps :
3720+ podman_args .append ("-t" )
3721+ if args .until :
3722+ podman_args .extend (["--until" , args .until ])
3723+ podman_args .append (target )
3724+
3725+ task = asyncio .create_task (
3726+ compose .podman .run ([], "logs" , podman_args , log_formatter = log_formatter ),
3727+ name = f"logs-{ service_name } -{ target } " ,
3728+ )
3729+ tasks .append (task )
3730+
3731+ async def handle_sigint () -> None :
3732+ log .info ("Caught SIGINT or Ctrl+C, stopping log streaming..." )
3733+ for task in tasks :
3734+ if not task .done ():
3735+ task .cancel ()
3736+
3737+ if sys .platform != 'win32' :
3738+ loop = asyncio .get_event_loop ()
3739+ loop .add_signal_handler (signal .SIGINT , lambda : asyncio .create_task (handle_sigint ()))
3740+
3741+ try :
3742+ await asyncio .gather (* tasks )
3743+ except KeyboardInterrupt :
3744+ for task in tasks :
3745+ if not task .done ():
3746+ task .cancel ()
3747+ await asyncio .gather (* tasks , return_exceptions = True )
3748+ except Exception as e :
3749+ log .error ("Error in logs command: %s" , e )
3750+ for task in tasks :
3751+ if not task .done ():
3752+ task .cancel ()
3753+ await asyncio .gather (* tasks , return_exceptions = True )
3754+ raise
3755+ else :
3756+ podman_args = []
3757+ if args .follow :
3758+ podman_args .append ("-f" )
3759+ if args .latest :
3760+ podman_args .append ("-l" )
3761+ if args .names :
3762+ podman_args .append ("-n" )
3763+ if args .since :
3764+ podman_args .extend (["--since" , args .since ])
3765+ if args .tail and args .tail != "all" :
3766+ podman_args .extend (["--tail" , args .tail ])
3767+ if args .timestamps :
3768+ podman_args .append ("-t" )
3769+ if args .until :
3770+ podman_args .extend (["--until" , args .until ])
3771+ for target in targets :
3772+ podman_args .append (target )
3773+ await compose .podman .run ([], "logs" , podman_args )
36113774
36123775
36133776@cmd_run (podman_compose , "config" , "displays the compose file" )
@@ -3866,6 +4029,12 @@ def compose_up_parse(parser: argparse.ArgumentParser) -> None:
38664029 help = "Return the exit code of the selected service container. "
38674030 "Implies --abort-on-container-exit." ,
38684031 )
4032+ parser .add_argument (
4033+ "-n" ,
4034+ "--names" ,
4035+ action = "store_true" ,
4036+ help = "Show short service names instead of full container names in logs" ,
4037+ )
38694038
38704039
38714040@cmd_parse (podman_compose , "down" )
0 commit comments