Skip to content

Commit

Permalink
added appenders doc
Browse files Browse the repository at this point in the history
  • Loading branch information
FreeAndNil committed Dec 30, 2024
1 parent 86ba43f commit 9f0c9f3
Show file tree
Hide file tree
Showing 5 changed files with 2,392 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/site/antora/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@
* xref:download.adoc[]
* xref:development.adoc[]
* xref:manual/index.adoc[]
** xref:manual/appenders.adoc[]
** xref:manual/configuration.adoc[]
*** xref:manual/configuration-examples.adoc[]
** xref:manual/filters.adoc[]
** xref:manual/layouts.adoc[]
* xref:features.adoc[]
* xref:release-notes.adoc[]
* {logging-services-url}/support.html[Support]
Expand Down
85 changes: 85 additions & 0 deletions src/site/antora/modules/ROOT/pages/manual/appenders.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
////
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
////
[#appenders]
= Appenders
Appenders are responsible for delivering log events to their destination.
Every Appender must implement the `IAppender` interface.
While not strictly required by the log4net architecture, most appenders inherit from `AppenderSkeleton` and:
* delegate the filtering of log events to an implementation of `IFilter`.
See xref:manual/filters.adoc[] for more information.
* delegate the formatting of log events to an implementation of `ILayout`.
See xref:manual/layouts.adoc[] for more information.
* only directly handle the writing of log event data to the target destination.
Appenders always have a name so that they can be referenced from a
xref:manual/configuration.adoc#configuring-loggers[logger configuration].
[#file-appenders]
== File appenders
File appenders write logs to the filesystem.
They can be further split into:
Single file appenders:::
//See xref:manual/appenders/file.adoc[] for details.
Rolling file appenders:::
//See xref:manual/appenders/rolling-file.adoc[] for details.
[#database-appenders]
=== Database appenders
The appenders write log events directly to a database.
//xref:manual/appenders/database.adoc#JdbcAppender[JDBC appender]::
Sends log events to a JDBC driver
//xref:manual/appenders/database.adoc#NoSqlAppender[NoSQL appender]::
Store log events to a document-oriented database
//See xref:manual/appenders/database.adoc[] for details.
[#network-appenders]
=== Network appenders
These appenders use simple network protocols to transmit log events to a remote host.
The supported network protocols are:
`UDP`::
`TCP`::
//These are handled by the xref:manual/appenders/network.adoc#SocketAppender[Socket Appender].
`HTTP`::
//This is handled by the xref:manual/appenders/network.adoc#HttpAppender[HTTP Appender].
`SMTP`::
//This is handled by the xref:manual/appenders/network.adoc#HttpAppender[SMTP Appender].
//See xref:manual/appenders/network.adoc[] for details.
[#delegating-appenders]
=== Delegating appenders
Delegating appenders are intended to decorate other appenders:
//xref:manual/appenders/delegating.adoc#RoutingAppender[Routing appender]::
Dynamically choose a different appender for each log event
// See xref:manual/appenders/delegating.adoc[] for details.
234 changes: 234 additions & 0 deletions src/site/antora/modules/ROOT/pages/manual/configuration-examples.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
////
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
////
[#configuration]
= Configuration
Using a configuration file is the most popular and recommended approach for configuring log4net.
In this page we will examine the composition of a configuration file and how log4net uses it.
[source,csharp]
----
using Animals.Carnivora;
// Import log4net classes.
using log4net;
using log4net.Config;
namespace SampleApp;
private static class MyApp
{
// Define a static logger variable so that it references the Logger instance named "MyApp".
private static readonly ILog logger = LogManager.GetLogger(typeof(MyApp));
private static void Main(string[] args)
{
// Set up a simple configuration that logs on the console.
BasicConfigurator.Configure();
logger.Info("Entering application.");
Dog dog = new();
bar.Bark();
logger.Info("Exiting application.");
}
}
----
MyApp begins by importing log4net related namespaces.
It then defines a static logger variable with the name MyApp which happens to be the fully qualified name of the class.
MyApp uses the following Dog class:
[source,csharp]
----
// Import log4net classes
using log4net;
namespace Animals.Carnivora;
internal sealed class Dog
{
private static readonly ILog logger = LogManager.GetLogger(typeof(Dog));
internal void Bark() => logger.Debug("Woof!");
}
----
The invocation of the BasicConfigurator.Configure() method creates a rather simple log4net setup.
This method is hardwired to add to the root logger a ConsoleAppender.
The output will be formatted using a PatternLayout set to the following pattern:
[source,log]
----
%timestamp [%thread] %level %logger %ndc - %message%newline
----
Note that by default, the root logger is assigned to Level.DEBUG.
The output of MyApp is:
[source,log]
----
2024-12-21 14:07:41,508 [main] INFO SampleApp.MyApp - Entering application.
2024-12-21 14:07:41,517 [main] DEBUG Animals.Carnivora.Dog - Woof!
2024-12-21 14:07:41,529 [main] INFO SampleApp.MyApp - Exiting application.
----
As a side note, let me mention that in log4net child loggers link only to their existing ancestors.
In particular, the logger named Animals.Carnivora.Dog is linked directly to the root logger, thereby circumventing the unused Animals or Animals.Carnivora loggers.
This significantly increases performance and reduces log4net's memory footprint.
The MyApp class configures log4net by invoking BasicConfigurator.Configure() method.
Other classes only need to import the log4net namespace, retrieve the loggers they wish to use, and log away.
The previous example always outputs the same log information.
Fortunately, it is easy to modify MyApp so that the log output can be controlled at run-time.
Here is a slightly modified version.
[source,csharp]
----
using Animals.Carnivora;
// Import log4net classes.
using log4net;
using log4net.Config;
namespace SampleApp;
private static class MyApp
{
private static readonly ILog logger = LogManager.GetLogger(typeof(MyApp));
private static void Main(string[] args)
{
// BasicConfigurator replaced with XmlConfigurator.
XmlConfigurator.Configure();
logger.Info("Entering application.");
Dog dog = new();
bar.Bark();
logger.Info("Exiting application.");
}
}
----
This version of MyApp instructs the XmlConfigurator to parse a configuration file and set up logging accordingly.
Here is a sample configuration file that results in exactly same output as the previous BasicConfigurator based example.
[source,xml]
----
<log4net>
<!-- ConsoleAppender is set to be a ConsoleAppender -->
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<!-- ConsoleAppender uses PatternLayout -->
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-4timestamp [%thread] %-5level %logger %ndc - %message%newline" />
</layout>
</appender>
<!-- Set root logger level to DEBUG and its only appender to ConsoleAppender -->
<root>
<level value="DEBUG" />
<appender-ref ref="ConsoleAppender" />
</root>
</log4net>
----
Suppose we are no longer interested in seeing the output of any component belonging to the Animals.Carnivora namespace.
The following configuration file shows one possible way of achieving this.
[source,xml]
----
<log4net>
<!-- ConsoleAppender is set to be a ConsoleAppender -->
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<!-- ConsoleAppender uses PatternLayout -->
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-4timestamp [%thread] %-5level %logger %ndc - %message%newline" />
</layout>
</appender>
<!-- Set root logger level to DEBUG and its only appender to ConsoleAppender -->
<root>
<level value="DEBUG" />
<appender-ref ref="ConsoleAppender" />
</root>
<!-- Print only messages of level WARN or above in the namespace Animals.Carnivora -->
<logger name="Animals.Carnivora">
<level value="WARN" />
</logger>
</log4net>
----
The output of MyApp configured with this file is shown below.
[source,log]
----
2024-12-21 14:07:41,508 [main] INFO SampleApp.MyApp - Entering application.
2024-12-21 14:07:41,529 [main] INFO SampleApp.MyApp - Exiting application.
----
As the logger Animals.Carnivora.Dog does not have an assigned level, it inherits its level from Animals.Carnivora, which was set to WARN in the configuration file.
The log statement from the Dog.Bark method has the level DEBUG, lower than the logger level WARN.
Consequently, Bark() method's log request is suppressed.
Here is another configuration file that uses multiple appenders.
[source,xml]
----
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<!-- Pattern to output the caller's file name and line number -->
<conversionPattern value="%5level [%thread] (%file:%line) - %message%newline" />
</layout>
</appender>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="example.log" />
<appendToFile value="true" />
<maximumFileSize value="100KB" />
<maxSizeRollBackups value="2" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level %thread %logger - %message%newline" />
</layout>
</appender>
<!-- Set root logger level to DEBUG and its only appender to ConsoleAppender -->
<root>
<level value="DEBUG" />
<appender-ref ref="ConsoleAppender" />
<appender-ref ref="RollingFile" />
</root>
</log4net>
----
Calling the enhanced MyApp with the this configuration file will output the following on the console.
[source,log]
----
INFO [main] (MyApp.cs:17) - Entering application.
DEBUG [main] (Dog.cs:10) - Woof!
INFO [main] (MyApp.cs:20) - Exiting application.
----
In addition, as the root logger has been allocated a second appender, output will also be directed to the example.log file.
This file will be rolled over when it reaches 100KB.
When roll-over occurs, the old version of example.log is automatically moved to example.log.1.
Note that to obtain these different logging behaviors we did not need to recompile code.
We could just as easily have logged to an email address or redirected all Animals.Carnivora output to an remote syslog server.
For more examples of configuring appenders using the XmlConfigurator see the Example Appender Configuration #TODO document.
Loading

0 comments on commit 9f0c9f3

Please sign in to comment.