我可以将 C DLL 的输出重定向到我的 c# log4net 输出吗
Can I redirect output from a C DLL into my c# log4net output
我有一个 C# 应用程序,它依次加载 C 或 C++ dll(依次加载其他 C/C++ dll)。在 C# 应用程序中,我使用 log4net 记录器将所有输出捕获到一系列日志文件中。我的应用程序作为 windows 服务运行,因此没有 console/output window 用于正常的 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, 等等)
我有一个 C# 应用程序,它依次加载 C 或 C++ dll(依次加载其他 C/C++ dll)。在 C# 应用程序中,我使用 log4net 记录器将所有输出捕获到一系列日志文件中。我的应用程序作为 windows 服务运行,因此没有 console/output window 用于正常的 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, 等等)