Перенаправление потока cerr
От: as90  
Дата: 27.01.13 15:54
Оценка:
Есть желание логировать все сообщения в программе в файл определено складывая данные.
Если данные записываются в cerr с помощью потоков std::cerr<<
тут решение я нашел можно у потока cerr сменить буфер и делать с сообщениями что угодно.
Но у меня есть проблема в том что есть некоторые библиотеки собранные другим компилятором, то есть Runtime у этой либы свой и такой прием не работает.
в nix можно перенаправить поток ошибок с помощью функции dup2, но хотелось бы иметь возможность еще форматировать этот вывод, то есть лучше всего иметь функцию которая вызывается при записи данных в cerr.
в nix опыть же можно использовать pipe и fork для отлова таких сообщений, в винде fork нету, так что этот способ не работает.
Нет ли более изящного способа и чтоб работал и под linux и под windows с компилятором mingw?
Re: Перенаправление потока cerr
От: jazzer Россия Skype: enerjazzer
Дата: 27.01.13 16:10
Оценка: 1 (1) +1
Здравствуйте, as90, Вы писали:

A>Есть желание логировать все сообщения в программе в файл определено складывая данные.

A>Если данные записываются в cerr с помощью потоков std::cerr<<
A>Нет ли более изящного способа и чтоб работал и под linux и под windows с компилятором mingw?

Имхо, самое простое и правильное — это запускать программу скриптом, который выполнит перенаправление куда надо.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: Перенаправление потока cerr
От: vitcpp Россия http://vdavydov.ru
Дата: 27.01.13 18:18
Оценка:
A>>Есть желание логировать все сообщения в программе в файл определено складывая данные.
A>>Если данные записываются в cerr с помощью потоков std::cerr<<
A>>Нет ли более изящного способа и чтоб работал и под linux и под windows с компилятором mingw?

J>Имхо, самое простое и правильное — это запускать программу скриптом, который выполнит перенаправление куда надо.


Я в свое время написал тривиальную программу под linux на C, которая перенаправляла стандартные потоки в указанные при запуске пайпы, а потом делала exec без форка. Для моего случая этот подход оказался лучше, чем применение скриптов, так как в этом случае не требуется запуска еще одного процесса — скриптового интерпретатора.
Re[3]: Перенаправление потока cerr
От: jazzer Россия Skype: enerjazzer
Дата: 27.01.13 18:24
Оценка: 1 (1) +2
Здравствуйте, vitcpp, Вы писали:

A>>>Есть желание логировать все сообщения в программе в файл определено складывая данные.

A>>>Если данные записываются в cerr с помощью потоков std::cerr<<
A>>>Нет ли более изящного способа и чтоб работал и под linux и под windows с компилятором mingw?

J>>Имхо, самое простое и правильное — это запускать программу скриптом, который выполнит перенаправление куда надо.


V>Я в свое время написал тривиальную программу под linux на C, которая перенаправляла стандартные потоки в указанные при запуске пайпы, а потом делала exec без форка. Для моего случая этот подход оказался лучше, чем применение скриптов, так как в этом случае не требуется запуска еще одного процесса — скриптового интерпретатора.


Так все равно надо настраивать окружение для программы, чтоб она корректно работала... Можно, конечно, через конфиг-файлы (хотя как ты какой-нть нужный для старта LD_LIBRARY_PATH в конфиг засунешь), но мне как-то привычнее нарулить все настройки в стартовом скрипте (потому что скрипт — это программа, а не просто куча настроек, как в конфиг-файле, т.е. эти настройки в скрипте можно как-то хитро генерить и т.п.). Ну и там же можно выполнить (опционально) любое перенаправление, запустить программу (опционально) под отладчиком и прочая и прочая. Удобно и гибко.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re: Перенаправление потока cerr
От: pzhy  
Дата: 27.01.13 18:44
Оценка:
Здравствуйте, as90, Вы писали:

A>Есть желание логировать все сообщения в программе в файл определено складывая данные.

A>Если данные записываются в cerr с помощью потоков std::cerr<<
A>тут решение я нашел можно у потока cerr сменить буфер и делать с сообщениями что угодно.
A>Но у меня есть проблема в том что есть некоторые библиотеки собранные другим компилятором, то есть Runtime у этой либы свой и такой прием не работает.
A>в nix можно перенаправить поток ошибок с помощью функции dup2, но хотелось бы иметь возможность еще форматировать этот вывод, то есть лучше всего иметь функцию которая вызывается при записи данных в cerr.
A>в nix опыть же можно использовать pipe и fork для отлова таких сообщений, в винде fork нету, так что этот способ не работает.
A>Нет ли более изящного способа и чтоб работал и под linux и под windows с компилятором mingw?

Для вин возможно использовать cygwin? Думаю для вин можно сделать тоже самое с помощью Psh. Сделать скрипт.
Можно использовать freopen (если она есть в вин):
freopen("my.log","w",stderr);
Re[4]: Перенаправление потока cerr
От: vitcpp Россия http://vdavydov.ru
Дата: 27.01.13 19:18
Оценка:
J>Так все равно надо настраивать окружение для программы, чтоб она корректно работала... Можно, конечно, через конфиг-файлы (хотя как ты какой-нть нужный для старта LD_LIBRARY_PATH в конфиг засунешь), но мне как-то привычнее нарулить все настройки в стартовом скрипте (потому что скрипт — это программа, а не просто куча настроек, как в конфиг-файле, т.е. эти настройки в скрипте можно как-то хитро генерить и т.п.). Ну и там же можно выполнить (опционально) любое перенаправление, запустить программу (опционально) под отладчиком и прочая и прочая. Удобно и гибко.

Да, согласен. В моем случае я запускал программу из уже запущенного процесса. Так что задача конфигурации не стояла, энвайрмент наследовался.
Re[2]: Перенаправление потока cerr
От: as90  
Дата: 28.01.13 15:27
Оценка:
Здравствуйте, pzhy, Вы писали:

P>Здравствуйте, as90, Вы писали:


A>>Есть желание логировать все сообщения в программе в файл определено складывая данные.

A>>Если данные записываются в cerr с помощью потоков std::cerr<<
A>>тут решение я нашел можно у потока cerr сменить буфер и делать с сообщениями что угодно.
A>>Но у меня есть проблема в том что есть некоторые библиотеки собранные другим компилятором, то есть Runtime у этой либы свой и такой прием не работает.
A>>в nix можно перенаправить поток ошибок с помощью функции dup2, но хотелось бы иметь возможность еще форматировать этот вывод, то есть лучше всего иметь функцию которая вызывается при записи данных в cerr.
A>>в nix опыть же можно использовать pipe и fork для отлова таких сообщений, в винде fork нету, так что этот способ не работает.
A>>Нет ли более изящного способа и чтоб работал и под linux и под windows с компилятором mingw?

P>Для вин возможно использовать cygwin? Думаю для вин можно сделать тоже самое с помощью Psh. Сделать скрипт.

P>Можно использовать freopen (если она есть в вин):
P>
P>freopen("my.log","w",stderr);
P>


В mingw работает и dup2 -функция перенаправления файловых потоков, что на мой взгляд удобнее чем freopen, так как в этот же файл можно писать не только через файловый поток cerr
у такого способа есть минус невозможно как-то обравить прилетевшие данные, в текущем логере программы к всем данным прилетевшим добавляет время, когда эти сообщения пришли.
Как я позже нарыл можно все же использовать win api
BOOL WINAPI SetStdHandle(
_In_ DWORD nStdHandle,
_In_ HANDLE hHandle
);
но это платформозависимое решение.
(http://msdn.microsoft.com/en-us/library/ms686244(VS.85).aspx)
Думаю тогда воспользуюсь либо батников, который будет перенаправлять вывод в файл, либо через pipe.
Re[3]: Перенаправление потока cerr
От: watch-maker  
Дата: 28.01.13 16:27
Оценка:
A>Как я позже нарыл можно все же использовать win api
A>BOOL WINAPI SetStdHandle(
A> _In_ DWORD nStdHandle,
A> _In_ HANDLE hHandle
A>);
A>но это платформозависимое решение.
A>(http://msdn.microsoft.com/en-us/library/ms686244(VS.85).aspx)
SetStdHandle сохраняет переданный ей дескриптор в неком хранилище, откуда его можно потом прочитать функцией GetStdHandle. Всё.
То есть после вызова SetStdHandle(STD_ERROR_HANDLE, ...) у тебя cerr не начнёт писать в новый файл или пайп. Причина в том, что crt уже инициализирована, и на этапе инициализации уже был вызван GetStdHandle(STD_ERROR_HANDLE), оригинальный результат которого и используется.
Чтобы использовать новый дескриптор, установленный функцией SetStdHandle, нужно заново переотрыть все потоки std::cerr, stderr, итп. То есть нужно как-то сообщить crt о том, что нужно обновить список используемых дескрипторов. А это приводит тебя к исходной проблеме — перезапустить можно только одну crt, а не все копии расположенные в других библиотеках.

Короче говоря, SetStdHandle — это не аналог dup2, это куда более слабая функция.
dup2 меняет дескриптор у всех, не спрашивая их мнения об этом.
SetStdHandle просто сохраняет новое значение, которое никак не используется до соответствующего явного вызова GetStdHandle (которое в типичной программе после старта практически никогда не происходит).

A>Думаю тогда воспользуюсь либо батников, который будет перенаправлять вывод в файл, либо через pipe.

+1 за pipe.
Вообще, чтобы универсально перехватывать и модифицировать весь вывод в stderr, std::cerr итп, нужно чтобы уже на старте программы весь вывод был перенаправлен в необходимое место. Ведь только в этом случае все crt будут проинициализированы нужными значениями. Поэтому придётся либо написать код, который запускается сразу же при старте процесса и перед всеми инициализациями библиотек, либо перенаправить вывод ещё до старта процесса — то есть из командной оболочки (и скриптов) или из специальной программы.
В последнем случае этой программой конечно же может выступать и оригинальная копия. Так можно создать pipe и запустить себя же, но перенаправив весть вывод STD_ERROR_HANDLE в один конец пайпа, одновременно с этим передав другой конец в дочернюю копию через механизм наследования дескприторов. Тогда всё, что попадёт в stderr, можно будет достать из другого конца пайпа. Новый процесс при этом выполняет всё работу, а старый процесс для работы уже не нужен, и может спокойно завершиться (или наоборот подождать завершения дочернего процесса, если нужно вернуть, скажем, корректный код возврата).
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.