I have a multi-threaded C# application that use log4net for logging capabilities. Mainly the RollingFileAppender.
我有一个多线程C#应用程序,它使用log4net进行日志记录功能。主要是RollingFileAppender。
I want to offer the capability for the user to view the activity of the application in an "application log" window. This will consist of a listview (details mode), a grid or something similar.
我想为用户提供在“应用程序日志”窗口中查看应用程序活动的功能。这将包括列表视图(详细信息模式),网格或类似的东西。
I'm looking for best ways to do it. The only solution I have so far is to setup an UDP appender and create a special thread that will listen and foward all messages to the UI.
我正在寻找最佳方法。到目前为止,我唯一的解决方案是设置UDP appender并创建一个特殊的线程,该线程将监听并向UI发送所有消息。
I also examined the possibility to create a "wrapper" that both write to the UI, the log the message using log4net... hum.
我还研究了创建一个“包装器”的可能性,它既可以写入UI,也可以使用log4net ...来记录消息。
Thanks a lot in advance for your help.
非常感谢您的帮助。
5 个解决方案
#1
If you're happy to rely on another program you can use dbgview from Sysinternals. This will display anything that is logged with Debug.WriteLine() method. I think that the OutputDebugStringAppender will do this, but I've not used Log4Net so I can't be sure.
如果您乐于依赖其他程序,可以使用Sysinternals的dbgview。这将显示使用Debug.WriteLine()方法记录的任何内容。我认为OutputDebugStringAppender会这样做,但我没有使用Log4Net所以我不能确定。
#2
Do you require viewing the persisted log data in this window? If so, I would recommend logging to a database. Then log4net can work undisturbed by the client which can read the log data from the database in a non-locking manner.
您是否需要在此窗口中查看持久性日志数据?如果是这样,我建议记录到数据库。然后log4net可以不受客户端的干扰而工作,客户端可以非锁定的方式从数据库中读取日志数据。
You could use SQL Server Compact edition if you don't want/have an Express or full server going.
如果您不希望/拥有Express或完整服务器,则可以使用SQL Server Compact版本。
Logging to database is done with the built-in log4net AdoNetAdapter.
使用内置的log4net AdoNetAdapter完成对数据库的记录。
#3
I agree with Peter Lillevold. Here is a simple example of how to log to a db from a console app by dynamically setting the verbosity of the logging
我同意Peter Lillevold的观点。下面是一个简单的示例,说明如何通过动态设置日志记录的详细程度从控制台应用程序登录到数据库
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using log4net;
using log4net.Config;
using NUnit.Framework;
namespace ExampleConsoleApplication
{
[TestFixture]
class TestClass
{
//private static readonly ILog logger =
// LogManager.GetLogger ( typeof ( TestClass ) );
private static readonly log4net.ILog logger = log4net.LogManager.GetLogger ( System.Reflection.MethodBase.GetCurrentMethod ().DeclaringType );
static void Main ( string[] args )
{
Console.WriteLine ( " START " );
#region LoggerUsage
DOMConfigurator.Configure (); //tis configures the logger
logger.Debug ( "Here is a debug log." );
logger.Info ( "... and an Info log." );
logger.Warn ( "... and a warning." );
logger.Error ( "... and an error." );
logger.Fatal ( "... and a fatal error." );
#endregion LoggerUsage
TestClass objTestClass = new TestClass();
objTestClass.TestMethodNameOK ();
objTestClass.TestMethodNameNOK ();
Console.WriteLine ( " END HIT A KEY TO EXIT " );
Console.ReadLine ();
} //eof method
[SetUp]
protected void SetUp ()
{
//Add Here the Initialization of the objects
}
[Test ( Description = "Add here the description of this test method " )]
protected void TestMethodNameOK ()
{
//build ok use case scenario here - e.g. no exception should be raced '
//Vegetable newCarrot = pool.GetItemByPropertyValue<Vegetable> ( "WriongByPurpose", "Orange" );
//Assert.IsInstanceOfType ( typeof ( Vegetable ), newCarrot );
//Assert.AreSame ( newCarrot, carrot );
//logger.Info ( " I got the newCarrot which is " + newCarrot.Color );
} //eof method
[Test ( Description = "Add here the description of this test method " )]
protected void TestMethodNameNOK () //e.g. the one that should raze Exception
{
//build ok use case scenario here - e.g. no exception should be raced '
//Vegetable newCarrot = pool.GetItemByPropertyValue<Vegetable> ( "WriongByPurpose", "Orange" );
//Assert.IsInstanceOfType ( typeof ( Vegetable ), newCarrot );
//Assert.AreSame ( newCarrot, carrot );
//logger.Info ( " I got the newCarrot which is " + newCarrot.Color );
} //eof method
} //eof class
} //eof namespace
#region TheAppConfig
/*
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net"
type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<appender name="LogFileAppender" type="log4net.Appender.FileAppender">
<param name="File" value="Program.log" />
<param name="AppendToFile" value="true" />
<layout type="log4net.Layout.PatternLayout">
<!--<param name="Header" value="======================================" />
<param name="Footer" value="======================================" />-->
<param name="ConversionPattern" value="%d [%t] %-5p - %m%n" />
</layout>
</appender>
<appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
<mapping>
<level value="ERROR" />
<foreColor value="Red" />
</mapping>
<mapping>
<level value="DEBUG" />
<foreColor value="HighIntensity" />
</mapping>
<mapping>
<level value="INFO" />
<foreColor value="Green" />
</mapping>
<mapping>
<level value="WARN" />
<foreColor value="Yellow" />
</mapping>
<mapping>
<level value="FATAL" />
<foreColor value="White" />
<backColor value="Red" />
</mapping>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.2.10.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<connectionString value="data source=ysg;initial catalog=DBGA_DEV;integrated security=true;persist security info=True;" />
<commandText value="INSERT INTO [DBGA_DEV].[ga].[tb_Data_Log] ([Date],[Thread],[Level],[Logger],[Message]) VALUES (@log_date, @thread, @log_level, @logger, @message)" />
<parameter>
<parameterName value="@log_date" />
<dbType value="DateTime" />
<layout type="log4net.Layout.PatternLayout" value="%date{yyyy'.'MM'.'dd HH':'mm':'ss'.'fff}" />
</parameter>
<parameter>
<parameterName value="@thread" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout" value="%thread" />
</parameter>
<parameter>
<parameterName value="@domainName" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout" value="%user" />
</parameter>
<parameter>
<parameterName value="@log_level" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout" value="%level" />
</parameter>
<parameter>
<parameterName value="@logger" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout" value="%logger" />
</parameter>
<parameter>
<parameterName value="@message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout" value="%message" />
</parameter>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="LogFileAppender" />
<appender-ref ref="AdoNetAppender" />
<appender-ref ref="ColoredConsoleAppender" />
</root>
</log4net>
</configuration>
*/
#endregion TheAppconfig
//this is the xml added replace here your log4net and Nunit paths
//<Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821, processorArchitecture=MSIL">
// <SpecificVersion>False</SpecificVersion>
// <HintPath>..\..\..\Log4Net\log4net-1.2.10\bin\net\2.0\release\log4net.dll</HintPath>
//</Reference>
//<Reference Include="nunit.framework, Version=2.4.8.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL" />
#4
What about writing your own appender that will fire an event when something happens? You can obtain it's instance by examining log4net repository.
编写自己的appender会在发生事件时触发事件怎么样?您可以通过检查log4net存储库来获取它的实例。
#5
you could try the log4net viewer. See Ayende's blog here: http://ayende.com/Blog/archive/2006/08/22/WatchingTheLogsRunWithLog4net.aspx
你可以试试log4net查看器。请参阅Ayende的博客:http://ayende.com/Blog/archive/2006/08/22/WatchingTheLogsRunWithLog4net.aspx
#1
If you're happy to rely on another program you can use dbgview from Sysinternals. This will display anything that is logged with Debug.WriteLine() method. I think that the OutputDebugStringAppender will do this, but I've not used Log4Net so I can't be sure.
如果您乐于依赖其他程序,可以使用Sysinternals的dbgview。这将显示使用Debug.WriteLine()方法记录的任何内容。我认为OutputDebugStringAppender会这样做,但我没有使用Log4Net所以我不能确定。
#2
Do you require viewing the persisted log data in this window? If so, I would recommend logging to a database. Then log4net can work undisturbed by the client which can read the log data from the database in a non-locking manner.
您是否需要在此窗口中查看持久性日志数据?如果是这样,我建议记录到数据库。然后log4net可以不受客户端的干扰而工作,客户端可以非锁定的方式从数据库中读取日志数据。
You could use SQL Server Compact edition if you don't want/have an Express or full server going.
如果您不希望/拥有Express或完整服务器,则可以使用SQL Server Compact版本。
Logging to database is done with the built-in log4net AdoNetAdapter.
使用内置的log4net AdoNetAdapter完成对数据库的记录。
#3
I agree with Peter Lillevold. Here is a simple example of how to log to a db from a console app by dynamically setting the verbosity of the logging
我同意Peter Lillevold的观点。下面是一个简单的示例,说明如何通过动态设置日志记录的详细程度从控制台应用程序登录到数据库
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using log4net;
using log4net.Config;
using NUnit.Framework;
namespace ExampleConsoleApplication
{
[TestFixture]
class TestClass
{
//private static readonly ILog logger =
// LogManager.GetLogger ( typeof ( TestClass ) );
private static readonly log4net.ILog logger = log4net.LogManager.GetLogger ( System.Reflection.MethodBase.GetCurrentMethod ().DeclaringType );
static void Main ( string[] args )
{
Console.WriteLine ( " START " );
#region LoggerUsage
DOMConfigurator.Configure (); //tis configures the logger
logger.Debug ( "Here is a debug log." );
logger.Info ( "... and an Info log." );
logger.Warn ( "... and a warning." );
logger.Error ( "... and an error." );
logger.Fatal ( "... and a fatal error." );
#endregion LoggerUsage
TestClass objTestClass = new TestClass();
objTestClass.TestMethodNameOK ();
objTestClass.TestMethodNameNOK ();
Console.WriteLine ( " END HIT A KEY TO EXIT " );
Console.ReadLine ();
} //eof method
[SetUp]
protected void SetUp ()
{
//Add Here the Initialization of the objects
}
[Test ( Description = "Add here the description of this test method " )]
protected void TestMethodNameOK ()
{
//build ok use case scenario here - e.g. no exception should be raced '
//Vegetable newCarrot = pool.GetItemByPropertyValue<Vegetable> ( "WriongByPurpose", "Orange" );
//Assert.IsInstanceOfType ( typeof ( Vegetable ), newCarrot );
//Assert.AreSame ( newCarrot, carrot );
//logger.Info ( " I got the newCarrot which is " + newCarrot.Color );
} //eof method
[Test ( Description = "Add here the description of this test method " )]
protected void TestMethodNameNOK () //e.g. the one that should raze Exception
{
//build ok use case scenario here - e.g. no exception should be raced '
//Vegetable newCarrot = pool.GetItemByPropertyValue<Vegetable> ( "WriongByPurpose", "Orange" );
//Assert.IsInstanceOfType ( typeof ( Vegetable ), newCarrot );
//Assert.AreSame ( newCarrot, carrot );
//logger.Info ( " I got the newCarrot which is " + newCarrot.Color );
} //eof method
} //eof class
} //eof namespace
#region TheAppConfig
/*
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net"
type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<appender name="LogFileAppender" type="log4net.Appender.FileAppender">
<param name="File" value="Program.log" />
<param name="AppendToFile" value="true" />
<layout type="log4net.Layout.PatternLayout">
<!--<param name="Header" value="======================================" />
<param name="Footer" value="======================================" />-->
<param name="ConversionPattern" value="%d [%t] %-5p - %m%n" />
</layout>
</appender>
<appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
<mapping>
<level value="ERROR" />
<foreColor value="Red" />
</mapping>
<mapping>
<level value="DEBUG" />
<foreColor value="HighIntensity" />
</mapping>
<mapping>
<level value="INFO" />
<foreColor value="Green" />
</mapping>
<mapping>
<level value="WARN" />
<foreColor value="Yellow" />
</mapping>
<mapping>
<level value="FATAL" />
<foreColor value="White" />
<backColor value="Red" />
</mapping>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.2.10.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<connectionString value="data source=ysg;initial catalog=DBGA_DEV;integrated security=true;persist security info=True;" />
<commandText value="INSERT INTO [DBGA_DEV].[ga].[tb_Data_Log] ([Date],[Thread],[Level],[Logger],[Message]) VALUES (@log_date, @thread, @log_level, @logger, @message)" />
<parameter>
<parameterName value="@log_date" />
<dbType value="DateTime" />
<layout type="log4net.Layout.PatternLayout" value="%date{yyyy'.'MM'.'dd HH':'mm':'ss'.'fff}" />
</parameter>
<parameter>
<parameterName value="@thread" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout" value="%thread" />
</parameter>
<parameter>
<parameterName value="@domainName" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout" value="%user" />
</parameter>
<parameter>
<parameterName value="@log_level" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout" value="%level" />
</parameter>
<parameter>
<parameterName value="@logger" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout" value="%logger" />
</parameter>
<parameter>
<parameterName value="@message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout" value="%message" />
</parameter>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="LogFileAppender" />
<appender-ref ref="AdoNetAppender" />
<appender-ref ref="ColoredConsoleAppender" />
</root>
</log4net>
</configuration>
*/
#endregion TheAppconfig
//this is the xml added replace here your log4net and Nunit paths
//<Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821, processorArchitecture=MSIL">
// <SpecificVersion>False</SpecificVersion>
// <HintPath>..\..\..\Log4Net\log4net-1.2.10\bin\net\2.0\release\log4net.dll</HintPath>
//</Reference>
//<Reference Include="nunit.framework, Version=2.4.8.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL" />
#4
What about writing your own appender that will fire an event when something happens? You can obtain it's instance by examining log4net repository.
编写自己的appender会在发生事件时触发事件怎么样?您可以通过检查log4net存储库来获取它的实例。
#5
you could try the log4net viewer. See Ayende's blog here: http://ayende.com/Blog/archive/2006/08/22/WatchingTheLogsRunWithLog4net.aspx
你可以试试log4net查看器。请参阅Ayende的博客:http://ayende.com/Blog/archive/2006/08/22/WatchingTheLogsRunWithLog4net.aspx