¿Los informes de progreso / información de registro pertenecen a stderr o stdout?

75

¿Existe una directriz oficial de POSIX, GNU u otra sobre dónde se deben imprimir los informes de progreso y la información de registro (cosas como "Hacer foo; foo hecho")? Personalmente, tiendo a escribirlos en stderr para poder redirigir stdout y obtener solo la salida real del programa. Recientemente me dijeron que esto no es una buena práctica ya que los informes de progreso no son en realidad errores y solo los mensajes de error deben imprimirse en stderr.

Ambas posiciones tienen sentido y, por supuesto, puede elegir una u otra según los detalles de lo que está haciendo, pero me gustaría saber si hay un estándar comúnmente aceptado para esto. No he podido encontrar ninguna regla específica en POSIX, los estándares de codificación GNU o cualquier otra lista de mejores prácticas ampliamente aceptada.

Tenemos algunas preguntas similares, pero no abordan este problema exacto:

Entonces, ¿hay alguna regla oficial sobre dónde deben imprimirse los informes de progreso y otros mensajes informativos (que no son parte del resultado real del programa)?

terdon
fuente
26
Imprimir hiladores y similares stdoutjunto con los resultados es una forma segura de hacer que los resultados sean inútiles. Si alguna vez necesita canalizar los resultados a otro programa, dicho programa necesitaría separar los resultados de los hilanderos. Además, si redirige la salida a un archivo, no podrá ver los hilanderos. EN MI HUMILDE OPINIÓN.
Satō Katsura
2
@SatoKatsura sí, esa es mi opinión también y es por eso que imprimo tal en stderr. Sin embargo, el CTO de la compañía para la que trabajo considera que imprimir en stderr es una indicación de que algo salió mal. Hice la afirmación, bastante audaz, de que POSIX Way® está imprimiendo en stderr y él me llamó. Dado que tiene 20 años de experiencia en mí, me gustaría ver si puedo encontrar algún tipo de guía "oficial".
terdon
lo mismo que dijo Sato Katsura, stdoutes en realidad una forma segura y correcta de lanzar hilanderos y otros mensajes informativos, pero como muchos programadores dicen 'El silencio es dorado. No emite nada si todo está bien. de hecho, stderr siempre se usa para hacer eso debido a la definición vaga y también stdout puede romper la secuencia de la tubería. para guía oficial
Se ve
66
@ Siete creo que entendiste mal; Sato dice que usar stdout no es seguro ("forma segura de hacer que los resultados sean inútiles").
Stephen Kitt
1
Una posible solución única para todos sería usar solo stderrpara informar mensajes de error, excepto cuando --verbosese usa un indicador, en cuyo punto también se incluyen informes de progreso.
Gaurav

Respuestas:

27

Posix define las secuencias estándar de la siguiente manera :

Al inicio del programa, tres flujos deben estar predefinidos y no necesitan abrirse explícitamente: entrada estándar (para leer la entrada convencional), salida estándar (para escribir la salida convencional) y error estándar (para escribir la salida de diagnóstico). Cuando se abre, el flujo de error estándar no está completamente protegido; las secuencias de entrada y salida estándar están completamente almacenadas si solo se puede determinar que la secuencia no se refiere a un dispositivo interactivo.

La Biblioteca GNU C describe los flujos estándar de manera similar:

Variable: FILE * stdout
La secuencia de salida estándar, que se utiliza para la salida normal del programa.

Variable: FILE * stderr
El flujo de error estándar, que se utiliza para mensajes de error y diagnósticos emitidos por el programa.

Por lo tanto, las definiciones estándar tienen poca guía para el uso de la transmisión más allá de "salida convencional / normal" y "salida de diagnóstico / error". En la práctica, es común redirigir una o ambas de estas secuencias a archivos y tuberías, donde los indicadores de progreso serán un problema . Algunos sistemas incluso monitorean la stderr salida y la consideran una señal de problemas. Por lo tanto, la información de progreso puramente auxiliar es problemática en cualquier flujo.

En lugar de enviar indicadores de progreso incondicionalmente a cualquiera de las transmisiones estándar, es importante reconocer que la salida de progreso solo es apropiada para transmisiones interactivas . Con eso en mente, recomiendo escribir contadores de progreso solo después de verificar si la secuencia es interactiva (por ejemplo, con isatty()) o cuando está explícitamente habilitada por una opción de línea de comandos. Esto es especialmente importante para que los medidores de progreso que dependen del comportamiento de actualización de la terminal tengan sentido, como las barras de% completado.

Para ciertos mensajes de progreso muy simples ("Iniciando X" ... "Hecho con X") es más razonable incluir la salida incluso para transmisiones no interactivas. En ese caso, considere cómo los usuarios podrían interactuar con las transmisiones, como buscar con, greppaginar lesso monitorear con tail -f. Si tiene sentido ver los mensajes de progreso en esos contextos, será mucho más fácil consumirlos stdout.

Bradd Szonye
fuente
Gracias, la directriz GNU es el tipo de cosas que busco. Sin embargo, me doy cuenta de que mi pregunta fue un poco engañosa. Cuando mencioné "informes de progreso" estaba pensando en cosas como N% doney cosas como doing fooy foo done. Este último siempre debe mantenerse, ya que se utilizan para la depuración cuando se redirige a un archivo. Por lo tanto, su sugerencia de verificar si la transmisión es interactiva no es aplicable (aunque generalmente es una muy buena idea).
terdon
Ah, gracias por la aclaración, eso es un poco diferente de cosas como "% completado" y barras de progreso de marcas hash que ves en software como curly yum. En ese caso, me gustaría pensar acerca de si y cómo el usuario desea interactuar con la salida a través de grepo lesso herramientas similares.
Bradd Szonye
Respuesta actualizada para incorporar las aclaraciones anteriores.
Bradd Szonye
71

POSIX define el error estándar como

para escribir salida de diagnóstico

Esto no limita su uso solo a mensajes de error. Consideraría la información de progreso como salida de diagnóstico, por lo que pertenece al error estándar.

Stephen Kitt
fuente
8
FWIW, en Python, stdouttiene un buffer de línea por defecto, mientras que no stderrtiene buffer, por lo que stderres la opción natural para escribir texto / barras / spinners de progreso que no contienen una nueva línea. (Si escribe ese texto stdout, debe abarrotar sus llamadas de salida de progreso stdout.flush()para que sea visible).
PM 2Ring
12
@ PM2Ring que no es específico de Python, POSIX define las transmisiones de esa manera.
Stephen Kitt
44
@ PM2Ring: Al escribir en stdout, es necesario eliminar incluso si su texto no contiene un salto de línea si desea que sus informes de progreso para mostrar realmente en tiempo real cuando redirigida.
@Hurkyl Ah, buen punto. No estaba considerando la redirección.
PM 2Ring
1
@Wtower, ¿eh? No. Ansible se traga el texto stderr si el estado de salida es 0. Ese reclamo es simplemente falso.
Charles Duffy
10

POSIX es un poco más concreto sobre "información de diagnóstico" en Shell y Utilidades , 1.4: Valores predeterminados de descripción de la utilidad (énfasis mío):

STDERR

La sección STDERR describe la salida de error estándar de la utilidad. Solo se describen los mensajes que la utilidad envía a propósito. El uso de un terminal para error estándar puede hacer que cualquiera de las utilidades estándar que escriben la salida de error estándar se detenga cuando se usa en segundo plano. Por esta razón, las aplicaciones no deben usar funciones interactivas en los scripts que se colocarán en segundo plano.

El formato de los mensajes de diagnóstico para la mayoría de las utilidades no está especificado, pero el lenguaje y las convenciones culturales de los mensajes de diagnóstico e informativos cuyo formato no está especificado en este volumen de POSIX.1-2008 deberían verse afectados por la configuración de LC_MESSAGES y [XSI] [Opción Inicio ] NLSPATH. [Opción final]

La salida de error estándar especificada de las utilidades estándar no dependerá de la existencia o el valor de las variables de entorno definidas en este volumen de POSIX.1-2008, excepto lo dispuesto por este volumen de POSIX.1-2008.

Comportamiento predeterminado : cuando esta sección se enumera como "El error estándar se usará solo para mensajes de diagnóstico", significa que, a menos que se indique lo contrario, los mensajes de diagnóstico se enviarán al error estándar solo cuando el estado de salida indique que hay un error ocurrió y la utilidad se utiliza como se describe en este volumen de POSIX.1-2008.

Cuando esta sección aparece como "No utilizada", significa que el error estándar no se utilizará cuando la utilidad se utilice como se describe en este volumen de POSIX.1-2008.

IANASL, pero interpreto que significa que stderr solo tendrá salida si la utilidad devolverá un código de salida de error. Dado que este no debería ser el curso normal de los eventos para una ejecución exitosa, una utilidad POSIX no debería imprimir información de progreso a menos que ocurra un error (a menos que, por supuesto, se especifique lo contrario, etc.).

muru
fuente
Entiendo que esto describe el significado de la sección "STDERR" dada en las especificaciones de cada utilidad POSIX, no como una definición general para el uso de error estándar. No creo que terdon esté escribiendo una utilidad POSIX estándar aquí ;-).
Stephen Kitt
1
@StephenKitt tampoco. Pero está debatiendo con su CTO, quien dice que la salida de stderr es una indicación de que algo va mal, y el estándar respalda su afirmación como el comportamiento predeterminado.
muru
1
Solo admite el reclamo como el comportamiento predeterminado para las utilidades POSIX , e incluso entonces solo en casos específicos (utilidades que usan la frase mencionada). Esta parte de POSIX no es normativa (AIUI), es una plantilla: le dice cómo leer las especificaciones de la utilidad, no especifica el comportamiento de las utilidades. Específicamente, define el significado de las frases "El error estándar se utilizará solo para mensajes de diagnóstico". y "No utilizado". en las secciones "STDERR" de las especificaciones de la utilidad. Cada utilidad especifica su comportamiento, y puede usar esas frases como abreviatura.
Stephen Kitt
@StephenKitt que no cambia mi punto. Las utilidades POSIX: a) no se envían a stderr, b) se usan solo para mensajes de diagnóstico si algo sale mal, c) se usan solo para mensajes de diagnóstico incluso si nada sale mal yd) se usan para otra cosa. Dije que solo lo usan para mensajes de diagnóstico si algo sale mal (a, b), a menos que se indique lo contrario (c, d). Ahora, mi reclamo es que este es el valor predeterminado, que claramente lo es, ya que es por eso que es una plantilla.
muru
2
Bueno, yo diría que "a menos que se especifique lo contrario" es una advertencia bastante significativa: una utilidad POSIX podría muy bien especificar que genera información de progreso en su error estándar, y sería compatible con los estándares. Tiene razón, es interesante que el "comportamiento predeterminado" (que aún requiere una mención específica en la sección correspondiente) es usar solo el error estándar si el código de salida también indica un error; Pero no es limitante.
Stephen Kitt
7

Por el principio de exclusión, solo puede ir a stderr. Sí, sé que preguntaste sobre una especificación oficial, que no puedo presentarte más allá del enlace a la especificación POSIX, dada por Stephen Kitt, que establece que stderr es para fines de diagnóstico.

El punto más importante es que stdin y stdout tienen una función que no permite imprimir informes de progreso en stdout: por supuesto, forman la secuencia de tuberías que en los comandos de shell de Unix no es solo un efecto secundario, sino el núcleo del poderoso enfoque de canalización .

Entonces. Nada excepto la verdadera "carga útil" de su programa pertenece a stdout. Si su programa no tiene salida, entonces nada debería ir a stdout. Esto deja stderr para todo lo demás , incluidos los informes de progreso.

De acuerdo, esto deja un agujero: probablemente sería bueno tener un "stdfluff" o algo así que no sea para resultados ni errores, sino informes de progreso, depuración y algo así. De hecho, nada le impide hacerlo, es decir, puede imprimir su progreso en el descriptor de archivo 3. Ejemplo:

$ perl -e 'open($fd, ">", "/dev/fd/3"); print $fd "hello\n"'

Esto no produce salida. (*)

$ perl -e 'open($fd, ">", "/dev/fd/3"); print $fd "hello\n"'  3>&1
hello

Esto se imprime en fd-3, que se redirige a stdout.

(*) El primer ejemplo no produce resultados pero sigue siendo un poco exagerado; el openfalla y $!lo contendría no such file or directory; solo tome esto como un ejemplo, por supuesto no es para ser utilizado de esta manera en serio. En un programa real, si desea seguir esta ruta, puede probar si /dev/fd/3es utilizable y tomar esto como una pista de si activar sus informes de progreso; tendrías que hacerlo bastante temprano para que no te confundan tus propios openarchivos reales y tal ...

AnoE
fuente
¿Qué es fd-3? El tercer disquete?
Peter Mortensen
descriptor de archivo 3, @PeterMortensen
AnoE
-1

El mensaje de uso debe ir a stdout si el usuario lo ha invocado --helpy stderr si ha cometido un error. Imprimirlo en stderr incondicionalmente es desagradable porque hace que sea más difícil verlo con un buscapersonas / grep / etc.

Además, puedo sugerir una tercera forma: abrir / dev / tty para informes de progreso / spinners / etc.

Aleatorio832
fuente
66
Lo siento, pero esto no responde la pregunta. Pedí específicamente pautas oficiales , no opiniones. En cualquier caso, incluso si hubiera pedido una opinión, está respondiendo una pregunta diferente. No estoy hablando --helpo mensajes de ayuda en absoluto. Por favor, vuelva a leer la pregunta.
terdon
Usted mencionó "mensaje de uso", pensé que era parte de su pregunta y no solo el título de la otra pregunta que vinculó. No entiendo por qué crees que existen "pautas oficiales" para esto. ¿Quién tendría la autoridad para hacerlos?
Random832
3
No sé si lo hacen, por eso pregunto. Y en cuanto al oficial, el estándar POSIX tiene especificaciones para varios detalles minuciosos de cómo debe comportarse un programa. Incluyendo, como Stephen señaló en su respuesta, una vaga sugerencia de lo que debería ir a stderr. El estándar de codificación GNU también podría tener algo similar. Básicamente, cualquier grupo que esté activo y produzca código para el ecosistema * nix podría tener un estándar en el que estaría interesado.
terdon
@terdon ¿estaría bien con ejemplos de lo que hacen los programas existentes? curl, wget y pv usan stderr, con wget y pv lo que lo condiciona a que sea un tty y curl lo condiciona a que stdout no sea el tty.
Random832
44
Además, parece que su CTO cree que un programa de llamada debería reaccionar ante la presencia de datos en stderr, lo que significa que se ha producido un error, en lugar de mirar el estado de salida. Esta es definitivamente una mala práctica (y también más difícil de escribir que verificar el estado de salida) y podría ser un mejor ángulo para convencerlo.
Random832