У меня есть приложение C #, которое, в свою очередь, загружает DLL C или C ++ (которое, в свою очередь, загружает другие DLL C / C ++). В приложении C # я использую log4net logger для записи всего вывода в серию файлов журнала. Мое приложение запускается как служба Windows, поэтому нет окна консоли / вывода для обычного printfs или вывода, записанного в stdout / stderr.
Есть ли способ настроить приложение C # для направления stdout / stderr (из DLL) и превратить каждую строку в выход log4net. Или в C / C ++ DLL есть какой-то способ соединить потоки stdout / stderr с выходом log4net?
Я нашел какое-то решение (здесь: http://bytes.com/topic/c-sharp/answers/822341-dllimport-stdout-gets-eaten) это указывало на то, что мне нужно сделать вызов в мою C DLL следующим образом: setvbuf(stdout, NULL, _IONBF, 0);
Хотя я не знаю, что это делает, оно не делает то, что я хочу. Я предполагаю, что мне также понадобится аналогичная строка для stderr. В любом случае, Google, кажется, думал, что эти строки просто заботятся о буферизации, а не о перенаправлении в log4net.
Я предполагаю, что мне нужно какое-то переопределение функции, которая зацепляет записи консоли (из загруженной DLL на другом языке) и преобразует их в mLog.InfoFormat("{0}", consoleString);
виды звонков. Я новичок в C # и даже не уверен, что условия Google, чтобы найти такое переопределение (если это вообще возможно).
Не уверен, усложнит ли это проблему, но мое приложение на C # является многопоточным, и некоторые библиотеки DLL также имеют несколько потоков. Я предполагаю, что это просто означает, что мне нужна какая-то блокировка внутри метода, который обрабатывает вывод консоли и записывает его в каркас log4net (возможно), или, может быть, обычная сериализация log4net справится с этим для меня.
Оказывается, те сделали свое дело, когда я понял, как их использовать. Я установил два именованных канала (или два конца одной и той же трубы?). Один я подключился к stdout, и он сделал лог-сообщение в log4net о том, что произошло через канал.
internal static void InfoLogWriter(Object threadContext)
{
mLog.Info("InfoLogWriterthread started");
int id = Process.GetCurrentProcess().Id; // make this instance unique
var serverPipe = new NamedPipeServerStream("consoleRedirect" + id, PipeDirection.In, 1);
NamedPipeClientStream clientPipe = new NamedPipeClientStream(".", "consoleRedirect" + id, PipeDirection.Out, PipeOptions.WriteThrough);
mLog.Info("Connecting Client Pipe.");
clientPipe.Connect();
mLog.Info("Connected Client Pipe, redirecting stdout");
HandleRef hr11 = new HandleRef(clientPipe, clientPipe.SafePipeHandle.DangerousGetHandle());
SetStdHandle(-11, hr11.Handle); // redirect stdout to my pipe
mLog.Info("Redirection of stdout complete.");
mLog.Info("Waiting for console connection");
serverPipe.WaitForConnection(); //blocking
mLog.Info("Console connection made.");
using (var stm = new StreamReader(serverPipe))
{
while (serverPipe.IsConnected)
{
try
{
string txt = stm.ReadLine();
if (!string.IsNullOrEmpty(txt))
mLog.InfoFormat("DLL MESSAGE : {0}", txt);
}
catch (IOException)
{
break; // normal disconnect
}
}
}
mLog.Info("Console connection broken. Thread Stopping.");
}
Также есть функция для передачи всего этого в другой поток, чтобы он не блокировал мой основной поток при попадании на различные вызовы блокировки.
internal static void RedirectConsole()
{
mLog.Info("RedirectConsole called.");
ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(InfoLogWriter));
// TODO enqueue and item for error messages too.
}
У меня проблемы с его отключением, и мне нужно снова подключить трубы, но я найду решение для повторного подключения. Я предполагаю, что это происходит, когда библиотеки DLL выгружаются из памяти или, возможно, когда мне нужно читать, но в настоящее время нет ничего готового для чтения? Я также должен настроить другую пару, чтобы поймать stderr и перенаправить ее, используя журналы ошибок для этого. Вероятно, хотите избавиться от магического числа (-11) и использовать обычные перечисления (STD_ERROR_HANDLE и т. Д.)