Law*_*vil 5 c c# c++ dll log4net
我有一个C#应用程序,该应用程序反过来加载C或C ++ dll(反过来加载其他C / C ++ dll)。在C#应用程序中,我使用log4net记录器将所有输出捕获到一系列日志文件中。我的应用程序作为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行。无论哪种情况,谷歌似乎都认为这些行只是在缓冲而不是重定向到log4net。
我假设我需要某种函数重写,以阻止控制台写入(从另一种语言的已加载DLL中写入)并将其转换为mLog.InfoFormat("{0}", consoleString);各种调用。我是C#的新手,甚至不确定要找到什么替代字词(如果可能的话)对Google使用什么术语。
不知道这是否会使问题复杂化,但是我的C#应用程序是多线程的,某些DLL也具有多个线程。我假设这只是意味着我需要在处理控制台输出并将其写入log4net框架(也许)的方法内部需要某种类型的锁,或者正常的log4net序列化将为我处理它。
事实证明,一旦我弄清楚如何使用它们,它们就成功了。我设置了两个命名管道(或同一管道的两端?)。我连接到标准输出并让它在 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.");
}
Run Code Online (Sandbox Code Playgroud)
还有一个函数可以将所有这些推送到另一个线程,这样当它遇到各种阻塞调用时,它就不会阻塞我的主线程。
internal static void RedirectConsole()
{
mLog.Info("RedirectConsole called.");
ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(InfoLogWriter));
// TODO enqueue and item for error messages too.
}
Run Code Online (Sandbox Code Playgroud)
我在断开连接时遇到问题,必须重新连接管道,但我会找到重新连接的解决方案。我猜当 DLL 被换回内存不足时或者当我需要读取但当前没有任何内容可供读取时,就会发生这种情况?我还必须设置另一对来捕获 stderr 并重定向它,并使用该错误日志。可能想要摆脱幻数(-11)并使用普通枚举(STD_ERROR_HANDLE等)