Как настроить log4net программно с нуля (без конфигурации)
Это плохая идея, я знаю, но... Я хочу настроить log4net программно с нуля без файла конфигурации. Я работаю над простым приложением для ведения журнала для меня и моей команды, чтобы использовать для кучки относительно небольших ведомственных приложений, за которые мы отвечаем. Я хочу, чтобы все они вошли в одну базу данных. Приложение для ведения журнала-это просто оболочка вокруг log4net с предварительно настроенным AdoNetAppender.
все приложения, развернутые с помощью ClickOnce, которая представлена небольшая проблема с развертыванием конфигурационного файла. Если файл конфигурации был частью основного проекта, я мог бы установить его свойства для развертывания со сборкой. Но это часть связанного приложения, поэтому у меня нет возможности развернуть его с основным приложением. (Если это не так, кто-нибудь, пожалуйста, дайте мне знать).
вероятно, потому что это плохая идея, похоже, что не так много примеров кода доступно для программной настройки log4net с нуля. Вот что у меня так далеко.
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...
после настройки всех параметров для apndr
, Я сначала попробовал это...
Dim hier As Hierarchy = DirectCast(LogManager.GetRepository(), Hierarchy)
hier.Root.AddAppender(apndr)
это не сработало. Затем, как выстрел в темноте, я попытался это.
BasicConfigurator.Configure(apndr)
это тоже не сработало. У кого-нибудь есть хорошие ссылки на то, как настроить log4net программно с нуля без файла конфигурации?
12 ответов:
один из способов, которым я сделал это в прошлом, - это включить файл конфигурации в качестве встроенного ресурса и просто использовать log4net.Конфиг.Настройка (Поток).
таким образом, я мог использовать синтаксис конфигурации, с которым я был знаком, и мне не нужно было беспокоиться о развертывании файла.
вот пример класса, который создает log4net config полностью в коде. Я должен упомянуть, что создание регистратора с помощью статического метода обычно рассматривается как плохое, но в моем контексте это то, что я хотел. Несмотря на это, вы можете вырезать код для удовлетворения ваших потребностей.
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"); } }
}
более лаконичное решение:
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 способ:
метод ActivateOptions должен быть вызван для этого объекта после установки свойств конфигурации. Пока ActivateOptions не вызван этот объект находится в неопределенном состоянии и не должен использоваться.
Как Джонатан говорит, что использование ресурса является хорошим решением.
это немного ограничительно в том, что содержимое встроенного ресурса будет исправлено во время компиляции. У меня есть компонент ведения журнала, который генерирует XmlDocument с базовой конфигурацией Log4Net, используя переменные, определенные как appSettings (например, имя файла для RollingFileAppender, уровень ведения журнала по умолчанию, возможно, имя строки подключения, если вы хотите использовать AdoNetAppender). А потом я звоню
log4net.Config.XmlConfigurator.Configure
настройка Такой как log4net, используя корневой элемент созданный объект XmlDocument.затем администраторы могут настроить" стандартную " конфигурацию, изменив несколько наборов приложений (обычно уровень, имя файла, ...) или можно указать внешний файл конфигурации, чтобы получить больше контроля.
Я не могу сказать В фрагмент кода в вопрос, если "и так далее..."включает в себя очень важный apndr.ActivateOptions (), который указан в ответе Тодда Стаута. Без ActivateOptions () приложение неактивно и не будет делать ничего, что могло бы объяснить, почему он терпит неудачу.
Доктор Netjes имеет это для установки connectionstring программно:
// 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 } }
немного поздно для вечеринки. Но вот минимальная конфигурация, которая работала для меня.
образец класс
public class Bar { private readonly ILog log = LogManager.GetLogger(typeof(Bar)); public void DoBar() { log.Info("Logged"); } }
минимальная конфигурация трассировки log4net (внутри теста NUnit)
[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
// я встроил три конфигурационных файла в качестве встроенного ресурса и получил к ним доступ следующим образом:
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 часов возиться с конфигурацией и становится все более разочарованным.
надеюсь, что это поможет кому-то.
вот пример супа к орехам, как вы можете создать и использовать
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 )
[Main]
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
решение для Vb.Net
Private Shared EscanerLog As log4net.ILog = log4net.LogManager.GetLogger("Log4Net.Config") Public Sub New(ByVal sIDSesion As String) Dim sStream As Stream Dim JsText As String Using reader As New StreamReader((GetType(ClsGestorLogsTraza).Assembly).GetManifestResourceStream("Comun.Log4Net.Config")) JsText = reader.ReadToEnd() sStream = GenerateStreamFromString(JsText) log4net.Config.XmlConfigurator.Configure(sStream) End Using End Sub Public Function GenerateStreamFromString(ByVal s As String) As Stream Dim stream = New MemoryStream() Dim writer = New StreamWriter(stream) writer.Write(s) writer.Flush() stream.Position = 0 Return stream End Function Public Function StreamFromResource(ByVal sFilename As String) As Stream Dim nAssembly As System.Reflection.Assembly = System.Reflection.Assembly.GetExecutingAssembly() Dim s As Stream = nAssembly.GetManifestResourceStream(System.Reflection.MethodBase.GetCurrentMethod.DeclaringType, sFilename) Return s End Function