如何从头开始以编程方式configurationlog4net(无configuration)
这是一个糟糕的想法,我知道,但是…我想configurationlog4net编程从头开始没有configuration文件。 我正在为我和我的团队开发一个简单的日志logging应用程序,用于我们负责的一些相对较小的部门应用程序。 我希望他们都login到同一个数据库。 日志logging应用程序只是预先configuration了AdoNetAppender的log4net的一个包装。
所有这些应用程序都是ClickOnce部署的,这在部署configuration文件时出现了一个小问题。 如果configuration文件是核心项目的一部分,我可以将其属性设置为使用程序集进行部署。 但它是一个链接应用程序的一部分,所以我没有select与主应用程序部署。 (如果不是这样,有人请让我知道)。
可能是因为这是一个糟糕的想法,似乎没有太多的示例代码可用于编程从头开始configurationlog4net。 这是我迄今为止。
Dim apndr As New AdoNetAppender() apndr.CommandText = "INSERT INTO LOG_ENTRY (LOG_DTM, LOG_LEVEL, LOGGER, MESSAGE, PROGRAM, USER_ID, MACHINE, EXCEPTION) VALUES (@log_date, @log_level, @logger, @message, @program, @user, @machine, @exception)" apndr.ConnectionString = connectionString apndr.ConnectionType = "System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" apndr.CommandType = CommandType.Text Dim logDate As New AdoNetAppenderParameter() logDate.ParameterName = "@log_date" logDate.DbType = DbType.DateTime logDate.Layout = New RawTimeStampLayout() apndr.AddParameter(logDate) Dim logLevel As New AdoNetAppenderParameter() logLevel.ParameterName = "@log_level" 'And so forth...
在configuration好apndr
所有参数apndr
,我起初尝试了这个…
Dim hier As Hierarchy = DirectCast(LogManager.GetRepository(), Hierarchy) hier.Root.AddAppender(apndr)
它没有工作。 然后,作为一个黑暗中的镜头,我尝试了这个。
BasicConfigurator.Configure(apndr)
那也行不通。 有没有人有任何好的参考如何configurationlog4net编程从头开始没有configuration文件?
我过去做过的一种方法是将configuration文件作为embedded式资源,并使用log4net.Config.Configure(Stream) 。
这样,我可以使用我熟悉的configuration语法,而不必担心部署文件。
下面是一个完全在代码中创buildlog4netconfiguration的示例类。 我应该提到,通过静态方法创build一个logging器通常被认为是不好的,但在我的情况下,这是我想要的。 无论如何,你可以分割代码来满足你的需求。
using log4net; using log4net.Repository.Hierarchy; using log4net.Core; using log4net.Appender; using log4net.Layout; namespace dnservices.logging { public class Logger { private PatternLayout _layout = new PatternLayout(); private const string LOG_PATTERN = "%d [%t] %-5p %m%n"; public string DefaultPattern { get { return LOG_PATTERN; } } public Logger() { _layout.ConversionPattern = DefaultPattern; _layout.ActivateOptions(); } public PatternLayout DefaultLayout { get { return _layout; } } public void AddAppender(IAppender appender) { Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository(); hierarchy.Root.AddAppender(appender); } static Logger() { Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository(); TraceAppender tracer = new TraceAppender(); PatternLayout patternLayout = new PatternLayout(); patternLayout.ConversionPattern = LOG_PATTERN; patternLayout.ActivateOptions(); tracer.Layout = patternLayout; tracer.ActivateOptions(); hierarchy.Root.AddAppender(tracer); RollingFileAppender roller = new RollingFileAppender(); roller.Layout = patternLayout; roller.AppendToFile = true; roller.RollingStyle = RollingFileAppender.RollingMode.Size; roller.MaxSizeRollBackups = 4; roller.MaximumFileSize = "100KB"; roller.StaticLogFileName = true; roller.File = "dnservices.txt"; roller.ActivateOptions(); hierarchy.Root.AddAppender(roller); hierarchy.Root.Level = Level.All; hierarchy.Configured = true; } public static ILog Create() { return LogManager.GetLogger("dnservices"); } }
}
更简洁的解决scheme:
var layout = new PatternLayout("%-4timestamp [%thread] %-5level %logger %ndc - %message%newline"); var appender = new RollingFileAppender { File = "my.log", Layout = layout }; layout.ActivateOptions(); appender.ActivateOptions(); BasicConfigurator.Configure(appender);
不要忘记调用ActivateOptions方法:
在设置configuration属性后,必须在此对象上调用ActivateOptions方法。 在调用ActivateOptions之前,该对象处于未定义状态,不能使用。
正如乔纳森所说,使用资源是一个很好的解决scheme。
embedded的资源内容在编译时会被固定,这是有点限制的。 我有一个日志logging组件,使用基本的Log4Netconfiguration生成一个XmlDocument,使用定义为appSettings的variables(例如RollingFileAppender的文件名,默认日志logging级别,如果您想使用AdoNetAppender,可能是连接string名称)。 然后我调用log4net.Config.XmlConfigurator.Configure
来使用生成的XmlDocument的根元素来configurationLog4Net。
然后pipe理员可以通过修改一些appSettings(通常是level,filename,…)来定制“标准”configuration,或者指定一个外部configuration文件来获得更多的控制。
我不能告诉问题的代码片段,如果“等等…”包括非常重要的apndr.ActivateOptions(),这是在托德斯托特的答案中指出。 没有ActivateOptions()Appender是不活动的,不会做任何事情可以解释为什么它失败。
Netjes博士有这个设置连接string编程:
// Get the Hierarchy object that organizes the loggers log4net.Repository.Hierarchy.Hierarchy hier = log4net.LogManager.GetLoggerRepository() as log4net.Repository.Hierarchy.Hierarchy; if (hier != null) { //get ADONetAppender log4net.Appender.ADONetAppender adoAppender = (log4net.Appender.ADONetAppender)hier.GetLogger("MyProject", hier.LoggerFactory).GetAppender("ADONetAppender"); if (adoAppender != null) { adoAppender.ConnectionString = System.Configuration.ConfigurationSettings.AppSettings["MyConnectionString"]; adoAppender.ActivateOptions(); //refresh settings of appender } }
晚会有点晚了 但是,这是一个最小的configuration,为我工作。
示例类
public class Bar { private readonly ILog log = LogManager.GetLogger(typeof(Bar)); public void DoBar() { log.Info("Logged"); } }
最小的log4net跟踪configuration(在NUnittesting中)
[Test] public void Foo() { var tracer = new TraceAppender(); var hierarchy = (Hierarchy)LogManager.GetRepository(); hierarchy.Root.AddAppender(tracer); var patternLayout = new PatternLayout {ConversionPattern = "%m%n"}; tracer.Layout = patternLayout; hierarchy.Configured = true; var bar = new Bar(); bar.DoBar(); }
打印到跟踪侦听器
Namespace+Bar: Logged
//我已经embedded了三个configuration文件作为embedded式资源,并像这样访问它们:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Resources; using System.IO; namespace Loader { class Program { private static log4net.ILog CustomerLog = log4net.LogManager.GetLogger("CustomerLogging"); private static log4net.ILog OrderLog = log4net.LogManager.GetLogger("OrderLogging"); private static log4net.ILog DetailsLog = log4net.LogManager.GetLogger("OrderDetailLogging"); static void Main(string[] args) { // array of embedded log4net config files string[] configs = { "Customer.config", "Order.config", "Detail.config"}; foreach (var config in configs) { // build path to assembly config StringBuilder sb = new StringBuilder(); sb.Append(System.Reflection.Assembly.GetExecutingAssembly().GetName().Name); sb.Append("."); sb.Append(config); // convert to a stream Stream configStream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(sb.ToString()); // configure logger with ocnfig stream log4net.Config.XmlConfigurator.Configure(configStream); // test logging CustomerLog.Info("Begin logging with: " + config); OrderLog.Info("Begin logging with: " + config); DetailsLog.Info("Begin logging with: " + config); for (int iX = 0; iX < 10; iX++) { CustomerLog.Info("iX=" + iX); OrderLog.Info("iX=" + iX); DetailsLog.Info("iX=" + iX); } CustomerLog.Info("Ending logging with: " + config); OrderLog.Info("Ending logging with: " + config); DetailsLog.Info("Ending logging with: " + config); } } } }
BasicConfigurator.Configure(apndr)
不起作用是奇怪的。 在我的情况下,它做了它的工作…但是,无论如何,这里的答案是 – 你应该写hier.Configured = true;
(C#代码)完成所有设置后。
我结束了使用这个:
http://www.mikebevers.be/blog/2010/09/log4net-custom-adonetappender/
4个小时后摆弄configuration,逐渐变得更加沮丧。
希望它可以帮助别人。
下面是一个简单的例子,说明如何完全在代码中创build和使用AdoNetAdapter
,完全没有任何App.config
文件(甚至没有Common.Logging
)。 继续,删除它!
在新的命名约定下,这对于更新具有更强的适应能力,现在程序集名称反映了版本。 ( Common.Logging.Log4Net1213
等)
[SQL]
CREATE TABLE [Log]( [Id] [int] IDENTITY(1,1) NOT NULL, [Date] [datetime] NOT NULL, [Thread] [varchar](255) NOT NULL, [Level] [varchar](20) NOT NULL, [Source] [varchar](255) NOT NULL, [Message] [varchar](max) NOT NULL, [Exception] [varchar](max) NOT NULL )
[主要]
Imports log4net Imports log4net.Core Imports log4net.Layout Imports log4net.Config Imports log4net.Appender Module Main Sub Main() Dim oLogger As ILog Dim sInput As String Dim iOops As Integer BasicConfigurator.Configure(New DbAppender) oLogger = LogManager.GetLogger(GetType(Main)) Console.Write("Command: ") Do Try sInput = Console.ReadLine.Trim Select Case sInput.ToUpper Case "QUIT" : Exit Do Case "OOPS" : iOops = String.Empty Case Else : oLogger.Info(sInput) End Select Catch ex As Exception oLogger.Error(ex.Message, ex) End Try Console.Clear() Console.Write("Command: ") Loop End Sub End Module
[DbAppender]
Imports log4net Imports log4net.Core Imports log4net.Layout Imports log4net.Appender Imports log4net.Repository.Hierarchy Public Class DbAppender Inherits AdoNetAppender Public Sub New() MyBase.BufferSize = 1 MyBase.CommandText = Me.CommandText Me.Parameters.ForEach(Sub(Parameter As DbParameter) MyBase.AddParameter(Parameter) End Sub) Me.ActivateOptions() End Sub Protected Overrides Function CreateConnection(ConnectionType As Type, ConnectionString As String) As IDbConnection Return MyBase.CreateConnection(GetType(System.Data.SqlClient.SqlConnection), "Data Source=(local);Initial Catalog=Logger;Persist Security Info=True;User ID=username;Password=password") End Function Private Overloads ReadOnly Property CommandText As String Get Dim _ sColumns, sValues As String sColumns = Join(Me.Parameters.Select(Function(P As DbParameter) P.DbColumn).ToArray, ",") sValues = Join(Me.Parameters.Select(Function(P As DbParameter) P.ParameterName).ToArray, ",") Return String.Format(COMMAND_TEXT, sColumns, sValues) End Get End Property Private ReadOnly Property Parameters As List(Of DbParameter) Get Parameters = New List(Of DbParameter) Parameters.Add(Me.LogDate) Parameters.Add(Me.Thread) Parameters.Add(Me.Level) Parameters.Add(Me.Source) Parameters.Add(Me.Message) Parameters.Add(Me.Exception) End Get End Property Private ReadOnly Property LogDate As DbParameter Get Return New DbParameter("Date", DbType.Date, 0, New DbPatternLayout("%date{yyyy-MM-dd HH:mm:ss.fff}")) End Get End Property Private ReadOnly Property Thread As DbParameter Get Return New DbParameter("Thread", DbType.String, 255, New DbPatternLayout("%thread")) End Get End Property Private ReadOnly Property Level As DbParameter Get Return New DbParameter("Level", DbType.String, 50, New DbPatternLayout("%level")) End Get End Property Private ReadOnly Property Source As DbParameter Get Return New DbParameter("Source", DbType.String, 255, New DbPatternLayout("%logger.%M()")) End Get End Property Private ReadOnly Property Message As DbParameter Get Return New DbParameter("Message", DbType.String, 4000, New DbPatternLayout("%message")) End Get End Property Private ReadOnly Property Exception As DbParameter Get Return New DbParameter("Exception", DbType.String, 2000, New DbExceptionLayout) End Get End Property Private Const COMMAND_TEXT As String = "INSERT INTO Log ({0}) VALUES ({1})" End Class
[的DbParameter]
Imports log4net Imports log4net.Core Imports log4net.Layout Imports log4net.Appender Imports log4net.Repository.Hierarchy Public Class DbParameter Inherits AdoNetAppenderParameter Private ReadOnly Name As String Public Sub New(Name As String, Type As DbType, Size As Integer, Layout As ILayout) With New RawLayoutConverter Me.Layout = .ConvertFrom(Layout) End With Me.Name = Name.Replace("@", String.Empty) Me.ParameterName = String.Format("@{0}", Me.Name) Me.DbType = Type Me.Size = Size End Sub Public ReadOnly Property DbColumn As String Get Return String.Format("[{0}]", Me.Name) End Get End Property End Class
[DbPatternLayout]
Imports log4net Imports log4net.Core Imports log4net.Layout Imports log4net.Appender Imports log4net.Repository.Hierarchy Public Class DbPatternLayout Inherits PatternLayout Public Sub New(Pattern As String) Me.ConversionPattern = Pattern Me.ActivateOptions() End Sub End Class
[DbExceptionLayout]
Imports log4net Imports log4net.Core Imports log4net.Layout Imports log4net.Appender Imports log4net.Repository.Hierarchy Public Class DbExceptionLayout Inherits ExceptionLayout Public Sub New() Me.ActivateOptions() End Sub End Class