Astuce
|
private static readonly ILog log = LogManager.GetLogger(typeof(Program));
|
Logging Levels
- FATAL
- ERROR
- WARN
- INFO
- DEBUG
 |
The default value for the root logger is DEBUG. |
Layout
|
<layout type="log4net.Layout.XMLLayout" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date - %location%newline%message%newline%exception%newline" />
</layout>
|
XMLLayout et LocationInfo
Par défaut XMLLayout ne logue pas les LocationInfo.
|
var xmlLayout = new XMLLayout(true);
public class RollingFileAppenderXmlLayoutLocation : RollingFileAppender
{
public RollingFileAppenderXmlLayoutLocation() : base()
{
Layout = new XmlLayout(true);
}
}
|
Pattern
|
Exemple
|
%date |
2014-01-15 12:00:00,000
|
%date{ABSOLUTE} |
12:00:00,000
|
%date{DATE} |
15 Jan 2014 12:00:00,000
|
%date{ISO8601} |
2014-01-15 12:00:00,000
|
%date{MMMM dd, yyyy HH:mm:ss, fff} |
January 15, 2014 12:00:00,000
|
%level |
DEBUG
|
%location |
Namespace.Class.Method(c:\chemin\vers\le\fichier.cs:ligne)
|
%message |
Le message à loguer.
|
%exception |
Le message de l'exception suivit de la stack trace.
|
%exception{message} |
Le message de l'exception.
|
%newline |
saut de ligne
|
 |
Il ne peut y avoir qu'un Conversion Patterns par appender. Pour pouvoir appliquer un Conversion Patterns par level, il faut créer plusieurs Conversion Patterns et ajouter des filters. |
Filter
|
<appender ...
<!-- match un level particulier -->
<filter type="log4net.Filter.LevelMatchFilter">
<levelToMatch value="ERROR"/>
</filter>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMax value="FATAL"/>
<levelMin value="ERROR"/>
</filter>
|
Logger
|
<logger name="MyLogger" additivity="false">
<level value="ALL" />
<appender-ref ref="MyAppender" />
</logger>
<appender name="MyAppender" type="log4net.Appender.ColoredConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message%newline"/>
</layout>
</appender>
|
Si Additivity à false, pas d'héritage des appenders parents.
|
ILog log = LogManager.GetLogger("MyLogger");
log.Error("Message");
|
Par défaut les logueurs ont le paramètre additivity à true, ils héritent donc de root et de leurs parents.
Ainsi l'appel au logueur loggerName1.loggerName2, fera aussi appel au logueur loggerName1 et à tous les logeurs définis dans root, si additivity est non-définis ou à true.
%property{}
|
<file type="log4net.Util.PatternString" value="%property{logFilePath}" />
|
|
ThreadContext.Properties["logFilePath"] = "MonFichierDeLog.log";
XmlConfigurator.Configure();
|
Scope
|
Type
|
Description
|
Global |
log4net.GlobalContext |
The global context is shared by all threads in the current AppDomain. This context is thread safe for use by multiple threads concurrently.
|
Thread |
log4net.ThreadContext |
The thread context is visible only to the current managed thread.
|
Logical Thread |
log4net.ThreadLogicalContext |
The logical thread context is visible to a logical thread. Logical threads can jump from one managed thread to another. For more details see the .NET API System.Runtime.Remoting.Messaging.CallContext.
|
Event |
log4net.Core.LoggingEvent |
Each event captures the current contextual state at the time the event is generated. Contextual data can be set on the event itself. This context is only visible to the code generating the event itself.
|
Class Library et Console Application
Console Application
- Référence à log4net
- AssemblyInfo.cs →
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
- App.config → log4net XML configuration
Class Library
Appenders
Exemple: ColoredConsoleAppender
 |
configSections doit être le premier sous-noeud de configuration |
App.config
|
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, Log4net"/>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<log4net>
<root>
<level value="INFO" />
<appender-ref ref="ColoredConsoleAppender" />
<appender-ref ref="ColoredConsoleAppenderError" />
</root>
<appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender" >
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message%newline"/>
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMax value="WARN"/>
<levelMin value="DEBUG"/>
</filter>
<mapping>
<level value="WARN" />
<foreColor value="Yellow" />
</mapping>
<mapping>
<level value="INFO" />
<foreColor value="Green" />
</mapping>
</appender>
<appender name="ColoredConsoleAppenderError" type="log4net.Appender.ColoredConsoleAppender" >
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date{ISO8601} %level%newline %location%newline %message%newline"/>
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMax value="FATAL"/>
<levelMin value="ERROR"/>
</filter>
<mapping>
<level value="ERROR" />
<foreColor value="Red" />
</mapping>
<mapping>
<level value="FATAL" />
<foreColor value="Red, HighIntensity" />
</mapping>
</appender>
</log4net>
</configuration>
|
AssemblyInfo.cs
|
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
|
Program.cs
|
using log4net;
using log4net.Config;
namespace MonNamespace
{
class Program
{
private static readonly ILog log = LogManager.GetLogger(typeof(Program));
static void Main(string[] args)
{
XmlConfigurator.Configure();
log.Debug("DEBUG");
log.Info("INFO");
log.Warn("WARN");
log.Error("ERROR");
log.Fatal("FATAL");
}
}
}
|
|
<appender name="MonAppender" type="MyNamespace.MyAppender, MyAssembly">
|
 |
Il faut spécifier l'assemblage si l'appender se trouve dans un assemblage différent. |
 |
L'assembly des custom appender doit se trouver dans le même dossier que l’exécutable, sinon il ne sera pas chargé. |
Appender pour WPF
Logging Display and WPF
|
public class NotifyAppender : AppenderSkeleton, INotifyPropertyChanged
{
private static string _notification;
public string Notification
{
get
{
return _notification; ;
}
set
{
if (_notification != value)
{
_notification = value;
OnPropertyChanged("Notification");
}
}
}
protected override void Append(LoggingEvent loggingEvent)
{
var writer = new StringWriter(CultureInfo.InvariantCulture);
Layout.Format(writer, loggingEvent);
Notification += writer.ToString();
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
|
ViewModel.cs
|
public NotifyAppender Appender
{
get
{
return LogManager.GetRepository().GetAppenders().FirstOrDefault(a => a is NotifyAppender) as NotifyAppender;
}
}
|
View.xaml
|
<GroupBox Header="Log">
<ScrollViewer>
<TextBlock Text="{Binding Path=Appender.Notification}" />
</ScrollViewer>
</GroupBox>
|
App.config
|
<appender name="NotifyAppender" type="MyNamespace.NotifyAppender, MyAssembly">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date - %location%newline%message%newline%exception%newline" />
</layout>
</appender>
|
EventLogAppender
|
<appender name="EventLogAppender" type="log4net.Appender.EventLogAppender" >
<param name="ApplicationName" value="My Windows EventLog Source" />
<param name="EventId" value="1000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date - %location%newline%message" />
</layout>
</appender>
|
 |
Si «My Windows EventLog Source» n'existe pas, log4net va tenter de le créer. Pour cela il lui faut les droits d'administration, dans le cas contraire rien ne sera logué. Il faut donc créer la source à la main avec les droits d'administration.
|
new-eventlog -LogName Application -source "My Windows EventLog Source"
remove-eventlog -source "My Windows EventLog Source"
Get-EventLog -LogName Application | Where-Object {$_.Source -eq "My Windows EventLog Source"} | Select-Object Source -first 1
|
|
if(!EventLog.SourceExists("My Windows EventLog Source"))
{
// Création de la source "My Windows EventLog Source" dans le log Application
EventLog.CreateEventSource("My Windows EventLog Source", "Application");
|
|
eventcreate /ID 1000 /L APPLICATION /T INFORMATION /SO "My Windows EventLog Source" /D "Un message"
| |
 |
Par défaut, log4net fixe l'EventId à 0, ce qui pose problème. Il faut donc fixer l'EventId entre 1 et 1000. |
|
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="Application.log" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="-1" />
<maximumFileSize value="5MB" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date - %location%newline%message%newline%exception%newline" />
</layout>
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<appendToFile value="true" />
<countDirection value="1"/>
<staticLogFileName value="true" />
</appender>
|
ColoredConsoleAppender
|
<appender name="MonColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
<mapping>
<level value="ALL" />
<foreColor value="Yellow" />
<backColor value="Red, HighIntensity" />
</mapping>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%location%newline%message%newline%newline" />
</layout>
</appender>
|
ColoredConsoleAppender Class
AdoNetAppender
|
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<bufferSize value="100" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<connectionString value="My connection string" />
<commandText value="INSERT INTO [dbo].[ReportCreator_Log] ([Date],[Level],[Location],[Message],[Exception]) VALUES (@log_date, @log_level, @location, @message, @exception)" />
<parameter>
<parameterName value="@log_date" />
<dbType value="DateTime" />
<layout type="log4net.Layout.RawTimeStampLayout" />
</parameter>
<parameter>
<parameterName value="@log_level" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level" />
</layout>
</parameter>
<parameter>
<parameterName value="@location" />
<dbType value="String" />
<size value="2000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%location" />
</layout>
</parameter>
<parameter>
<parameterName value="@message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message" />
</layout>
</parameter>
<parameter>
<parameterName value="@exception" />
<dbType value="String" />
<size value="2000" />
<layout type="log4net.Layout.ExceptionLayout" />
</parameter>
</appender>
|
|
CREATE TABLE [mon_schema].[ma_table_de_log] (
[Id] [int] IDENTITY (1, 1) NOT NULL,
[Date] [datetime] NOT NULL,
[Level] [varchar] (50) NOT NULL,
[Location] [varchar] (2000) NULL,
[Message] [varchar] (4000) NOT NULL,
[Exception] [varchar] (2000) NULL
);
|
ErrorFlagAppender
App.config
|
<logger name="MonLogger">
<appender-ref ref="ErrorFlagAppender" />
</logger>
<appender name="ErrorFlagAppender" type="MonNamespace.ErrorFlagAppender,MonAssembly">
</appender>
|
ErrorFlagAppender.cs
|
namespace MonNamespace
{
class ErrorFlagAppender : AppenderSkeleton
{
public bool ErrorOccurred { get; set; }
public bool WarningOccured { get; set; }
protected override void Append(LoggingEvent loggingEvent)
{
if (loggingEvent.Level == Level.Error || loggingEvent.Level == Level.Fatal)
{
ErrorOccurred = true;
}
else if (loggingEvent.Level == Level.Warn)
{
WarningOccured = true;
}
}
}
}
|
|
var errorFlagAppender = LogManager.GetRepository().GetAppenders().OfType<ErrorFlagAppender>();
if (errorFlagAppender.Any(e => e.ErrorOccurred))
{ }
else if (errorFlagAppender.Any(e => e.WarningOccured))
{ }
|
App.config
|
<appSettings>
<add key="log4net.Internal.Debug" value="true"/>
</appSettings>
<system.diagnostics>
<trace autoflush="true">
<listeners>
<add name="textWriterTraceListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="log4net.log" />
</listeners>
</trace>
</system.diagnostics>
|
Permet d'afficher la location de l'appelant plutôt que celle du wrapper.
|
public class MyLogWrapper
{
private static readonly ILog log = LogManager.GetLogger("MyLogger");
public void LogMessage(string message)
{
log.Error(message);
log.Logger.Log(typeof(MyLogWrapper), Level.Error, message, null);
}
}
class Program
{
static void Main(string[] args)
{
var mlw = new MyLogWrapper();
mlw.LogMessage("test");
|
Config comme Embedded Resource
Créer un fichier log4net.config, le définir comme Embedded Resource.
log4net.config
|
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
...
</log4net>
|
|
var assembly = Assembly.GetExecutingAssembly();
var resourceName = "MonNamespace.log4net.config";
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
{
XmlConfigurator.Configure(stream);
}
|
Configuration dans le code
|
var appender = new RollingFileAppender();
var layout = new PatternLayout(@"%date %-5level %message%newline");
appender.Layout = layout;
appender.File = "c:\log.txt";
appender.AppendToFile = true;
appender.MaximumFileSize = "1MB";
appender.MaxSizeRollBackups = 0;
appender.Threshold = Level.Error;
appender.ActivateOptions();
log4net.Config.BasicConfigurator.Configure(appender);
|
Permet d'avoir une autre configuration pour une sous-partie de l'application comme un module.
|
ILoggerRepository repository = LogManager.CreateRepository("MonRepository");
XmlConfigurator.Configure(repository, new FileInfo("C:\Folder\otherConfig.config"));
var log = LogManager.GetLogger("MonRepository", typeof(Program));
|
 |
La création de repository ne peut se faire que via le code. |
Installation
Déploiement avec NuGet:
click-droit sur References → Manage NuGet Packages... → Online