Мне вот интересно, а смысл засорения? Насколько я могу судить, clog - это то же самое, что и cerr, но с буферизацией, поэтому он более эффективен. Обычно stderr совпадает с stdout, поэтому clog совпадает с cout. Мне это кажется довольно неуместным, поэтому я полагаю, что неправильно это понимаю. Если у меня есть сообщения журнала, отправляемые в то же место, куда поступают сообщения об ошибках (возможно, что-то в / var / log / messages), то я, вероятно, не пишу слишком много (поэтому не так много потеряно, если использовать non -буферизованный cerr). По моему опыту, я хочу, чтобы мои сообщения журнала были актуальными (не буферизованными), чтобы я мог помочь найти сбой (поэтому я не хочу использовать буферизованный засор). По-видимому, я всегда должен использовать cerr.
Я хотел бы иметь возможность перенаправлять засорение внутри моей программы. Было бы полезно перенаправить cerr, чтобы при вызове библиотечной процедуры я мог контролировать, куда переходят cerr и clog. Могут ли некоторые компиляторы это поддерживать? Я только что проверил DJGPP, и stdout определяется как адрес структуры FILE, поэтому делать что-то вроде "stdout = freopen (...)" незаконно.
@AndreHolzner Это также верно во всех средах DOS / Windows, 2> действителен в командной строке Windows 7, например, как способ перенаправления stderr.





Is it possible to redirect clog, cerr, cout, stdin, stdout, and/or stderr?
ofstream ofs("logfile");
cout.rdbuf(ofs.rdbuf());
cout << "Goes to file." << endl;
Is the only difference between clog and cerr the buffering?
Насколько я знаю, да.
Дополнительную информацию можно найти на stackoverflow.com/questions/33601886/….
Закройте и сбросьте cout после записи или получите segfault: ofs.close(); cout.rdbuf(nullptr);
@ micah94 Поток закрывается автоматически в конце области видимости, нет необходимости делать это вручную. Но хороший момент по поводу сброса буфера cout.
Просто проверка: если после того, как вы сделаете этот rdbuf, вы попытаетесь писать в ofs и cout одновременно из двух разных потоков, вы получите гонку данных и неопределенное поведение, верно? (Но это нормально, если вы никогда не пишете через ofs, или если вы явно синхронизируете свои записи с мьютексом или чем-то еще.)
@Quuxplusone Хороший вопрос. Я не знаю, в какой момент синхронизируются выходные потоки, но вы, вероятно, правы.
Если вы находитесь в среде оболочки posix (я действительно думаю о bash), вы можете перенаправить любой файловый дескриптор в любой другой файловый дескриптор, поэтому для перенаправления вы можете просто:
$ myprogram 2>&5
для перенаправления stderr в файл, представленный fd = 5.
Обновлено: если подумать, мне больше нравится ответ @Konrad Rudolph о перенаправлении. rdbuf () - более последовательный и переносимый способ сделать это.
Что касается ведения журнала, ну ... Я начинаю с библиотеки Boost для всего C++, которой нет в библиотеке std. Вот: Boost Logging v2
Редактировать: ведение журнала ускорения является частью нет библиотек ускорения; он был рассмотрен, но не принят.
Редактировать: 2 года спустя, еще в мае 2010 года, Boost действительно принял библиотеку журналирования, которая теперь называется Boost.Log.
Конечно, есть альтернативы:
Также есть регистратор событий Windows.
И пара статей, которые могут пригодиться:
Следует отметить, что «Boost Logging v2» не является частью ускорения, а является предлагаемой библиотекой, которая может быть принята или не принята при рассмотрении.
Хорошая точка зрения. Библиотека была проверена 2/4 / 2008-2 / 13/2008 и, по-видимому, отклонена. Он может быть пересмотрен повторно. Вероятно, лучше всего подходят log4cxx или log4cpp.
Или используйте простое линейное решение std::cerr.
Я также настоятельно рекомендую Google GLog (code.google.com/p/google-glog), особенно за его краткие макросы assert с информативными сообщениями об ошибках.
#define myerr(e) {CriticalSectionLocker crit; std::cerr << e << std::endl;}
Используется как myerr("ERR: " << message); или myerr("WARN: " << message << code << etc);
Очень эффективно.
Затем сделайте:
./programname.exe 2> ./stderr.log
perl parsestderr.pl stderr.log
или просто проанализируйте stderr.log вручную
Я признаю, что это не для кода, критичного для производительности очень сильно. Но кто все равно это пишет.
#defines не типизированы, и большинство их использования в C++ не рекомендуется.
определения по-прежнему необходимы, если вы хотите автоматический захват _ФАЙЛ_ и _ЛИНИЯ_, что делает большинство людей.
@SpacenJasset Если вы не используете std :: source_location (присутствует в C++ 20 и новее).
Поскольку здесь есть несколько ответов о перенаправлении, я добавлю эта красивая жемчужина, о котором я недавно наткнулся, о перенаправлении:
#include <fstream>
#include <iostream>
class redirecter
{
public:
redirecter(std::ostream & dst, std::ostream & src)
: src(src), sbuf(src.rdbuf(dst.rdbuf())) {}
~redirecter() { src.rdbuf(sbuf); }
private:
std::ostream & src;
std::streambuf * const sbuf;
};
void hello_world()
{
std::cout << "Hello, world!\n";
}
int main()
{
std::ofstream log("hello-world.log");
redirecter redirect(log, std::cout);
hello_world();
return 0;
}
По сути, это класс перенаправления, который позволяет вам перенаправить любые два потока и восстановить его, когда вы закончите.
RAII FTW !!!!! 11
Один маленький момент о классе перенаправителя. Его нужно уничтожить как следует, и только один раз. Деструктор гарантирует, что это произойдет, если функция, в которой он объявлен, действительно возвращается, а сам объект никогда не копируется.
Чтобы гарантировать невозможность копирования, укажите операторы частного копирования и присваивания:
class redirecter
{
public:
redirecter(std::ostream & src, std::ostream & dst)
: src_(src), sbuf(src.rdbuf(dst.rdbuf())) {}
~redirecter() { src.rdbuf(sbuf); }
private:
std::ostream & src_;
std::streambuf * const sbuf_;
// Prevent copying.
redirecter( const redirecter& );
redirecter& operator=( const redirecter& );
};
Я использую эту технику, перенаправляя std :: clog в файл журнала в main (). Чтобы гарантировать, что main () действительно вернется, я помещаю внутренности main () в блок try / catch. Затем в другом месте моей программы, где я мог бы вызвать exit (), вместо этого я генерирую исключение. Это возвращает управление в main (), которая затем может выполнить оператор return.
Разве стандарт C++ не предпочитает =delete вместо частных конструкторов?
@DynamicSquid Я не уверен, что предпочитает стандарт как таковой, но это вещь. Однако OP и / или ответчик должны использовать C++ 11 или новее (что, я думаю, большинство людей сейчас использует).
Usually stderr is the same as stdoutопределенно неверен для Unix и его вариантов. Их можно, например, перенаправить отдельно.