Comment configurer log4net par programmation à partir de zéro (pas de configuration)

C’est une mauvaise idée, je sais, mais … Je veux configurer log4net par programmation à partir de zéro sans fichier de configuration. Je travaille sur une application de journalisation simple que mon équipe et moi-même pouvons utiliser pour un ensemble d’applications départementales relativement petites dont nous sums responsables. Je veux qu’ils se connectent tous à la même firebase database. L’application de journalisation est juste une enveloppe autour de log4net avec la préconfiguration d’AdoNetAppender.

ClickOnce déploie toutes les applications, ce qui pose un petit problème avec le déploiement du fichier de configuration. Si le fichier de configuration faisait partie du projet principal, je pourrais définir ses propriétés à déployer avec l’assembly. Mais cela fait partie d’une application liée, donc je n’ai pas la possibilité de la déployer avec l’application principale. (Si ce n’est pas vrai, quelqu’un peut me le faire savoir).

Probablement parce que c’est une mauvaise idée, il ne semble pas y avoir beaucoup de code disponible pour la configuration par programmation de log4net à partir de zéro. Voici ce que j’ai jusqu’ici.

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.ConnectionSsortingng = connectionSsortingng 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... 

Après avoir configuré tous les parameters pour apndr , j’ai d’abord essayé ceci …

 Dim hier As Hierarchy = DirectCast(LogManager.GetRepository(), Hierarchy) hier.Root.AddAppender(apndr) 

Ça n’a pas marché. Puis, comme un tir dans le noir, j’ai essayé à la place.

 BasicConfigurator.Configure(apndr) 

Cela n’a pas fonctionné non plus. Quelqu’un at-il de bonnes références sur la façon de configurer log4net par programmation à partir de zéro sans fichier de configuration?

Une des façons dont j’ai fait cela dans le passé est d’inclure le fichier de configuration en tant que ressource intégrée, et d’utiliser simplement log4net.Config.Configure (Stream) .

De cette façon, je pouvais utiliser la syntaxe de configuration que je connaissais et ne pas avoir à me soucier de déployer un fichier.

Voici un exemple de classe qui crée complètement la configuration log4net dans le code. Je devrais mentionner que la création d’un enregistreur via une méthode statique est généralement considérée comme mauvaise, mais dans mon contexte, c’est ce que je voulais. Peu importe, vous pouvez découper le code pour répondre à vos besoins.

 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 ssortingng LOG_PATTERN = "%d [%t] %-5p %m%n"; public ssortingng 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"); } } 

}

Solution plus concise:

 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); 

N’oubliez pas d’appeler la méthode ActivateOptions :

La méthode ActivateOptions doit être appelée sur cet object une fois les propriétés de configuration définies. Tant que ActivateOptions n’est pas appelée, cet object est dans un état indéfini et ne doit pas être utilisé.

Comme le dit Jonathan , utiliser une ressource est une bonne solution.

C’est un peu ressortingctif dans la mesure où le contenu des ressources incorporées sera fixé au moment de la compilation. J’ai un composant de journalisation qui génère un XmlDocument avec une configuration Log4Net de base, utilisant des variables définies comme appSettings (par exemple, nom de fichier pour un RollingFileAppender, niveau de consignation par défaut, éventuellement nom de chaîne de connexion si vous souhaitez utiliser AdoNetAppender). Et puis j’appelle log4net.Config.XmlConfigurator.Configure pour configurer Log4Net en utilisant l’élément racine du XmlDocument généré.

Les administrateurs peuvent ensuite personnaliser la configuration “standard” en modifiant quelques parameters appSettings (généralement level, filename, …) ou en spécifiant un fichier de configuration externe pour obtenir plus de contrôle.

Je ne peux pas dire dans l’extrait de code de la question si le “‘Et ainsi de suite …” inclut le très important apndr.ActivateOptions () qui est indiqué dans la réponse de Todd Stout. Sans ActivateOptions (), le Appender est inactif et ne fera rien qui puisse expliquer pourquoi il échoue.

Dr. Netjes a ceci pour configurer la chaîne de connexion par programmation:

 // 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.ConnectionSsortingng = System.Configuration.ConfigurationSettings.AppSettings["MyConnectionSsortingng"]; adoAppender.ActivateOptions(); //refresh settings of appender } } 

Un peu en retard pour la fête. Mais voici une configuration minimale qui a fonctionné pour moi.

Classe d’échantillon

 public class Bar { private readonly ILog log = LogManager.GetLogger(typeof(Bar)); public void DoBar() { log.Info("Logged"); } } 

Configuration minimale de trace log4net (dans le test 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(); } 

Imprime à l’auditeur de trace

 Namespace+Bar: Logged 

// J’ai intégré trois fichiers de configuration en tant que ressource intégrée et y accéder comme ceci:

 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(ssortingng[] args) { // array of embedded log4net config files ssortingng[] configs = { "Customer.config", "Order.config", "Detail.config"}; foreach (var config in configs) { // build path to assembly config SsortingngBuilder sb = new SsortingngBuilder(); 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.ToSsortingng()); // 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); } } } } 

Il est étrange que BasicConfigurator.Configure(apndr) ne fonctionne pas. Dans mon cas, il a fait son travail … Mais, de toute façon, voici la réponse – vous auriez dû écrire hier.Configured = true; (code c #) une fois que vous avez terminé toute la configuration.

J’ai fini par utiliser ceci:

http://www.mikebevers.be/blog/2010/09/log4net-custom-adonetappender/

Après 4 heures de sortingpotage avec la config et de plus en plus frustré.

J’espère que ça aide quelqu’un.

Voici un exemple de la façon dont vous pouvez créer et utiliser un AdoNetAdapter entièrement en code, complètement en l’absence de tout fichier App.config (même pour Common.Logging ). Allez-y, supprimez-le!

Cela présente l’avantage supplémentaire de résister aux mises à jour sous les nouvelles conventions de dénomination , où le nom de l’assembly reflète désormais la version. ( Common.Logging.Log4Net1213 , etc.)

[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 ) 

[Principale]

 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 Ssortingng 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 = Ssortingng.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, ConnectionSsortingng As Ssortingng) 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 Ssortingng Get Dim _ sColumns, sValues As Ssortingng 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 Ssortingng.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.Ssortingng, 255, New DbPatternLayout("%thread")) End Get End Property Private ReadOnly Property Level As DbParameter Get Return New DbParameter("Level", DbType.Ssortingng, 50, New DbPatternLayout("%level")) End Get End Property Private ReadOnly Property Source As DbParameter Get Return New DbParameter("Source", DbType.Ssortingng, 255, New DbPatternLayout("%logger.%M()")) End Get End Property Private ReadOnly Property Message As DbParameter Get Return New DbParameter("Message", DbType.Ssortingng, 4000, New DbPatternLayout("%message")) End Get End Property Private ReadOnly Property Exception As DbParameter Get Return New DbParameter("Exception", DbType.Ssortingng, 2000, New DbExceptionLayout) End Get End Property Private Const COMMAND_TEXT As Ssortingng = "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 Ssortingng Public Sub New(Name As Ssortingng, Type As DbType, Size As Integer, Layout As ILayout) With New RawLayoutConverter Me.Layout = .ConvertFrom(Layout) End With Me.Name = Name.Replace("@", Ssortingng.Empty) Me.ParameterName = Ssortingng.Format("@{0}", Me.Name) Me.DbType = Type Me.Size = Size End Sub Public ReadOnly Property DbColumn As Ssortingng Get Return Ssortingng.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 Ssortingng) 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