- cout apunta a la salida estándar STDOUT (texto de resultado esperado de un programa);
- cerr y clog apuntan a STDERR (salida de errores y cualquier otra porquería).
#include <iostream>Al ejecutarlo, obtenemos por pantalla las tres líneas:
using namespace std;
int main()
{
cout << "A\n";
cerr << "B\n";
clog << "C\n";
return 0;
}
test.exe [ENTER]Pero resulta interesante saber que podemos redireccionar el STDOUT a un archivo y el STDERR a otro. Ejemplo:
A
B
C
test.exe 1>stdout.txt 2>stderr.txt¿Qué demonios es 1 y 2? Los archivos tienen un descriptor que los identifica, 1 es para la STDOUT, y 2 para STDERR. El signo mayor (>) significa que "quiero redireccionar toda la salida de texto que vaya para este descriptor a este archivo". En el anterior ejemplo logramos obtener dos archivos distintos, stdout.txt que contiene una línea (A), y stderr.txt que contiene dos líneas (B y C).
Generalmente, los logs van a un archivo, no a la pantalla. Aunque por defecto clog mande todo a STDERR, resulta útil redireccionar este stream a un archivo propio (por ejemplo, test.log). De esta forma, podemos hacer uso de clog para "loguear" todo lo que nuestro programa hace.
¿Cómo se redirecciona clog? Básicamente los streams de C++ tienen un streambuf asociado, y éste es el realmente encargado de leer y escribir datos (en la pantalla, en un archivo, en un string en memoria, etc.). Por lo tanto, si creamos un fstream y le colocamos su propio streambuf a clog, podemos usar clog como un "alias" del fstream original (clog va a estar compartiendo el mismo streambuf que el fstream). El código resultante es bastante sencillo:
#include <iostream>Y listo, ahora podemos hacer lo mismo que antes:
#include <fstream>
using namespace std;
int main()
{
// Creamos un archivo de salida para logging.
ofstream test_log;
test_log.open("test.log");
// Obtenemos el streambuf actual de clog (esto
// lo usaremos luego para restaurar el streambuf
// a su valor original, por si las moscas).
streambuf* old_rdbuf = clog.rdbuf();
// Reemplazamos el streambuf de clog con el del archivo.
// Ahora ambos streams utilizarán el mismo streambuf (es
// decir, escriben en el archivo test.log).
clog.rdbuf(test_log.rdbuf());
// Hacemos lo mismo que el ejemplo original.
cout << "A\n";
cerr << "B\n";
clog << "C\n";
// Restauramos el viejo streambuf de clog.
clog.rdbuf(old_rdbuf);
// Cerramos el archivo.
test_log.close();
return 0;
}
test.exe 1>stdout.txt 2>stderr.txtCon lo cual obtenemos tres archivos:
- stdout.txt con la línea A.
- stderr.txt con la línea B.
- test.log con la línea C.