Есть желание логировать все сообщения в программе в файл определено складывая данные.
Если данные записываются в cerr с помощью потоков std::cerr<<
тут решение я нашел можно у потока cerr сменить буфер и делать с сообщениями что угодно.
Но у меня есть проблема в том что есть некоторые библиотеки собранные другим компилятором, то есть Runtime у этой либы свой и такой прием не работает.
в nix можно перенаправить поток ошибок с помощью функции dup2, но хотелось бы иметь возможность еще форматировать этот вывод, то есть лучше всего иметь функцию которая вызывается при записи данных в cerr.
в nix опыть же можно использовать pipe и fork для отлова таких сообщений, в винде fork нету, так что этот способ не работает.
Нет ли более изящного способа и чтоб работал и под linux и под windows с компилятором mingw?
Здравствуйте, as90, Вы писали:
A>Есть желание логировать все сообщения в программе в файл определено складывая данные. A>Если данные записываются в cerr с помощью потоков std::cerr<< A>Нет ли более изящного способа и чтоб работал и под linux и под windows с компилятором mingw?
Имхо, самое простое и правильное — это запускать программу скриптом, который выполнит перенаправление куда надо.
A>>Есть желание логировать все сообщения в программе в файл определено складывая данные. A>>Если данные записываются в cerr с помощью потоков std::cerr<< A>>Нет ли более изящного способа и чтоб работал и под linux и под windows с компилятором mingw?
J>Имхо, самое простое и правильное — это запускать программу скриптом, который выполнит перенаправление куда надо.
Я в свое время написал тривиальную программу под linux на C, которая перенаправляла стандартные потоки в указанные при запуске пайпы, а потом делала exec без форка. Для моего случая этот подход оказался лучше, чем применение скриптов, так как в этом случае не требуется запуска еще одного процесса — скриптового интерпретатора.
Здравствуйте, vitcpp, Вы писали:
A>>>Есть желание логировать все сообщения в программе в файл определено складывая данные. A>>>Если данные записываются в cerr с помощью потоков std::cerr<< A>>>Нет ли более изящного способа и чтоб работал и под linux и под windows с компилятором mingw?
J>>Имхо, самое простое и правильное — это запускать программу скриптом, который выполнит перенаправление куда надо.
V>Я в свое время написал тривиальную программу под linux на C, которая перенаправляла стандартные потоки в указанные при запуске пайпы, а потом делала exec без форка. Для моего случая этот подход оказался лучше, чем применение скриптов, так как в этом случае не требуется запуска еще одного процесса — скриптового интерпретатора.
Так все равно надо настраивать окружение для программы, чтоб она корректно работала... Можно, конечно, через конфиг-файлы (хотя как ты какой-нть нужный для старта LD_LIBRARY_PATH в конфиг засунешь), но мне как-то привычнее нарулить все настройки в стартовом скрипте (потому что скрипт — это программа, а не просто куча настроек, как в конфиг-файле, т.е. эти настройки в скрипте можно как-то хитро генерить и т.п.). Ну и там же можно выполнить (опционально) любое перенаправление, запустить программу (опционально) под отладчиком и прочая и прочая. Удобно и гибко.
Здравствуйте, 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 (если она есть в вин):
J>Так все равно надо настраивать окружение для программы, чтоб она корректно работала... Можно, конечно, через конфиг-файлы (хотя как ты какой-нть нужный для старта LD_LIBRARY_PATH в конфиг засунешь), но мне как-то привычнее нарулить все настройки в стартовом скрипте (потому что скрипт — это программа, а не просто куча настроек, как в конфиг-файле, т.е. эти настройки в скрипте можно как-то хитро генерить и т.п.). Ну и там же можно выполнить (опционально) любое перенаправление, запустить программу (опционально) под отладчиком и прочая и прочая. Удобно и гибко.
Да, согласен. В моем случае я запускал программу из уже запущенного процесса. Так что задача конфигурации не стояла, энвайрмент наследовался.
Здравствуйте, 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.
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, можно будет достать из другого конца пайпа. Новый процесс при этом выполняет всё работу, а старый процесс для работы уже не нужен, и может спокойно завершиться (или наоборот подождать завершения дочернего процесса, если нужно вернуть, скажем, корректный код возврата).