Reading Logback documentation notes -- appendix configuration of Logback

Posted by grafnic1732 on Thu, 09 Dec 2021 18:32:29 +0100

Logback refers to the component that performs log event output as an Appender, and the implemented Appender must inherit ch.qos.logback.core.Appender Interface

The interfaces are as follows:

   package ch.qos.logback.core;  
   import ch.qos.logback.core.spi.ContextAware;  
   import ch.qos.logback.core.spi.FilterAttachable;  
   import ch.qos.logback.core.spi.LifeCycle;  
   public interface Appender<E> extends LifeCycle, ContextAware, FilterAttachable {  
     public String getName();  
     public void setName(String name);  
     void doAppend(E event);  
   }  

The real type of the template parameter of the doAppend (E event) method depends on the logback module. In the logback classic, E is ILoggingEvent, while in the logback access module, E is AcessEvent. doAppend is the most important part of the logback framework. It is responsible for outputting logs to the specified device in a certain format.

The appender will eventually be responsible for outputting the log, but they may also leave the log formatting to the Layout or Encoder object. Each Layout and Encoder belongs to only one appender. Some Appenders have built-in fixed log formats, so layout/encoder declarations are not required. For example, SockerAppender simply serializes log events and then transmits them over the network.

AppenderBase( ch.qos.logback.core.AppenderBase )

AppenderBase is an abstract class inherited from the appender interface. It is the parent class of all Appenders currently provided by Logback. Although it is an abstract class, it actually implements the doAppender () method.

Let's take a look at the implementation of its doAppender method

   public    synchronized void doAppend(E eventObject) {  
     // prevent re-entry.  
     if (guard) {  
       return;  
     }  
     try {  
       guard = true;  
       if (   !this.started) {  
         if (statusRepeatCount++ < ALLOWED_REPEATS) {  
           addStatus(new WarnStatus(  
               "Attempted to append to non started appender [" + name + "].",this));  
         }  
         return;  
       }  
       if (getFilterChainDecision(eventObject) == FilterReply.DENY) {  
         return;  
       }  
       // ok, we now invoke the derived class's implementation of append  
       this.append(eventObject);  
     } finally {  
       guard = false;  
     }  
   }  

As you can see, the doAppend method is declared as a synchronization level. This makes it safe for different threads to use the same appender. When the doAppend method is accessed by a thread, subsequent doAppend () calls cannot be executed until the thread exits the method.

Because synchronization is not applicable to all situations, logback also provides an asynchronous implementation ch.qos.logback.core.UnsynchronizedAppenderBase

The implementation of asynchronous doAppend is discussed below. See the hyperlink for the source code:

  1. First, judge whether the guard is true. If it is true, exit immediately. If it is not true, it will be assigned to true in the next step. This is to prevent the same appender from outputting other logs before calling the append () method, resulting in repeated recursion. private ThreadLocal<Boolean> guard = new ThreadLocal<Boolean>(); The type of guard is a thread exclusive object
  2. Then, judge whether started is true. If false, output warning information and return. After completing the configuration, the start () method is called to detect the related attribute configuration, and the appender is activated without any exception. If the appender has any exceptions, a warning message will be recorded in the logback internal state management.
  3. After a series of filtering by the filter filter bound to it, the log event can be rejected and returned, or it can be received to enter the next step.
  4. Call append()
  5. Set guard=false to allow subsequent doAppend() function calls.

Down there! Let's talk about the Appender implementation of Logback.

OutputStreamAppender

OutputStreamAppender Attach log events to Java io. In OutputStream. This class is the parent class of ConsoleAppender and FileAppender, where FileAppender is the parent class of RollingFileAppender. But generally speaking, you can't instantiate this Appender.

First: ConsoleAppender

Like its name, this Appender outputs the log to the console, more accurately system Out or system err.

It contains the following parameters:

Property Name

Type

Description

encoder

Encoder

Determines the manner in which an event is written to the underlying OutputStreamAppender. Encoders are described in a dedicated chapter.

target

String

Specify the output destination. Optional value: system Out or system err. Default: system out

withJansi

boolean

Whether ANSI color codes (similar to the output string color control code of shell script in linux) are supported. The default is false. If set to true. For example: [31m stands for setting the foreground color to red. In windows, you need to provide "org.fusesource.jansi:jansi:1.9", which is supported by default in linux, mac os x. In the Eclipse IDE, you can try ANSI in Eclipse Console plug-in.

Look at a simple example

   <configuration>  
     <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">  
       <!-- encoders are assigned the type  
           ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->  
       <encoder>  
         <pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>  
       </encoder>  
     </appender>  
     <root level="DEBUG">  
       <appender-ref ref="STDOUT" />  
     </root>  
   </configuration>  

Second: FileAppender

Output the log to a file. The target file depends on the file attribute. Whether to append the output depends on the append attribute.

Property Name

Type

Description

append

boolean

Whether to output in append mode. The default is true.

encoder

Encoder

See OutputStreamAppender properties.

file

String

Specify the file name. Note that in windows, the backslash \ needs to be escaped or can be used directly. For example, C: / temp / test.logger or c:\temp\test.log can be used. There is no default value. If the upper directory does not exist, FileAppender will be created automatically.

prudent

boolean

Whether it works in cautious mode. In cautious mode, FileAppender will safely write logs to the specified file, even if there is another same FileAppender instance in different virtual machine JVMs. Default: false Set to true, which means that append will be automatically set to true The student depends on the file exclusive lock. Experiments show that using the file lock will increase the log writing consumption by three times. For example, when the student mode is off, it takes only 10 milliseconds to write a log to the file, but if the student mode is true, it will be close to 30 milliseconds. The student mode actually serializes I/O requests. Therefore, when the number of I / OS is large, such as 100 times / s or more, the delay will be obvious, so it should be avoided. In the networked file system, this consumption will be greater, which may lead to deadlock.

By default, each log event will be immediately flushed to the output stream. This default method is relatively safe for data and can avoid the risk of log loss in the buffer due to the abnormal exit of the application. However, in order to increase the log throughput, you can also set the immediateFulsh property in the Encoder to false. The Encoder will be described in the next article Explained in the blog post.

Here is a simple example:

   <configuration>  
     <appender name="FILE" class="ch.qos.logback.core.FileAppender">  
       <file>testFile.log</file>  
       <append>true</append>  
       <!-- encoders are assigned the type  
           ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->  
       <encoder>  
         <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>  
       </encoder>  
     </appender>  
     <root level="DEBUG">  
       <appender-ref ref="FILE" />  
     </root>  
   </configuration>  

We just use the < timestamp > tag to get the application startup time and use it as the file name of the new log file.

   <configuration>  
     <!-- Insert the current time formatted as "yyyyMMdd'T'HHmmss" under  
         the key "bySecond" into the logger context. This value will be  
         available to all subsequent configuration elements. -->  
 <timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/> 
     <appender name="FILE" class="ch.qos.logback.core.FileAppender">  
       <!-- use the previously created timestamp to create a uniquely  
           named log file -->  
       <file>log-${bySecond}.txt</file>  
       <encoder>  
         <pattern>%logger{35} - %msg%n</pattern>  
       </encoder>  
     </appender>  
     <root level="DEBUG">  
       <appender-ref ref="FILE" />  
     </root>  
   </configuration>  

The < timestamp > tag contains two necessary attributes: key and datePattern, and an optional attribute: timeReference.

  • key is the name of the attribute as the name of the variable
  • datePattern needs to conform to the Convention in SimpleDateFormat
  • timeReference can reference the values of other variables
   <configuration>  
     <timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"   
 
               timeReference="contextBirth"/>  
     ...  
   </configuration>  

Third: RollingFileAppender

RollingFileAppender inherits from FileAppender and provides the function of automatic switching of log target files. For example, date can be used as the condition for log segmentation.

RollingFileAppender has two important properties. RollingPolicy is responsible for how to switch logs and triggingpolicy is responsible for when to switch logs. In order for RollingFileAppender to work, these two properties must be set. However, if the implementation class of RollingPolicy also implements the triggingpolicy interface, only RollingPolicy can be set.

Here are its parameters:

Property Name

Type

Description

file

String

Specify the file name. Note that in windows, the backslash \ needs to be escaped or can be used directly. For example, C: / temp / test.logger or c:\temp\test.log can be used. There is no default value. If the upper directory does not exist, FileAppender will be created automatically.

append

boolean

Whether to output in append mode. The default is true.

encoder

Encoder

See OutputStreamAppender properties.

rollingPolicy

RollingPolicy

The switching behavior of RollingFileAppender when log switching occurs. For example, log file name modification

triggeringPolicy

TriggeringPolicy

Determine when log switching occurs, such as the date, and when the log file size reaches a certain value

prudent

boolean

FixedWindowRollingPolicy Student mode is not supported. TimeBasedRollingPolicy supports the student mode, but the following two constraints need to be met: In the student mode, the compression of log files is not allowed or supported. The file property cannot be set.

  1. In the student mode, the compression of log files is not allowed or supported.
  2. The file property cannot be set.

Let's take a look at what RollingPolicy is:

RollingPolicy is actually responsible for switching and renaming log files.

The interfaces are as follows:

   package ch.qos.logback.core.rolling;   
 
   import ch.qos.logback.core.FileAppender;  
   import ch.qos.logback.core.spi.LifeCycle;  
   public interface RollingPolicy extends LifeCycle {  
     /*rollover Method to complete the archiving of the current log file */  
     public void rollover() throws RolloverFailure;  
     /*getActiveFileName Method is responsible for calculating the new log file name*/  
     public String getActiveFileName();  
     /*getCompressionMode Method is responsible for the compression mode*/   
 
     public CompressionMode getCompressionMode();  
     /*Set parent appender*/   
 
     public void setParent(FileAppender appender);  
   }  

RollingPolicy has several common implementation classes:

TimeBasedRollingPolicy

TimeBasedRollingPolicy Perhaps the most popular log scrolling strategy. Its rolling strategy is time-based, for example, according to days and months.

Timebasedlollingpolicy inherits the RollingPolicy and triggingpolicy interfaces.

It contains a required attribute: fileNamePattern and several optional attributes.

Property Name

Type

Description

fileNamePattern

String

This required attribute determines the naming policy of archive logs when logs are scrolled. It consists of a file name and a% d transition character.% n D {} the curly brackets need to contain the time format conforming to the SimpleDateFormat convention. If it is not specified, it is% d directly, which is equivalent to% d {yyyy MM DD} by default. It should be noted that in the parent node of the RollingPolicy node, the value of the < File > node can be declared or ignored. If you declare the file attribute, you can separate the currently valid log files and archive log files. When set to, the name of the current valid log file will always be the value specified by the file attribute. When log scrolling occurs, change the name of the archive log according to the value of fileNamePattern, and then create a new valid log file named the value specified by the file attribute. If not specified, the currently valid log file name changes according to fileNamePattern. It should also be noted that in% d {}, both "/" and "\" are considered file separators. Multiple% d transitions: The value of fileNamePaatern allows multiple% D, but only one% d is used as the reference value for the main log rolling cycle. The remaining non primary% D needs to contain an "aux" parameter. For example: <fileNamePattern>/var/log/%d{yyyy/MM, aux}/myapplication.%d{yyyy-MM-dd}.log</fileNamePattern> Divide the directory according to the month and year, and then store the archive logs named according to the date and days of the corresponding month in the same month folder. This attribute value determines that log switching occurs at 0 o'clock every day. Time zone issues: You can convert the date to the time in the corresponding time zone. for example aFolder/test.%d{yyyy-MM-dd-HH, UTC}.log / / World coordinated time aFolder/test.%d{yyyy-MM-dd-HH, GMT}.log / / Greenwich mean time

maxHistory

int

Optional parameter to declare the maximum retention time of archive logs. If you scroll the log based on month, when maxHisory is 6, the log will be kept for 6 months. Those older than 6 months will be deleted. The directory where the log exists will also be deleted appropriately.

totalSizeCap

int

Optional parameter to declare the maximum storage capacity of archived logs. When this value is exceeded, the oldest archived log file will also be deleted.

cleanHistoryOnStart

boolean

Optional parameter. The default value is false. If set to true, all archived log files will be deleted when the appender starts.

Here are some common fileNamePattern values:

fileNamePattern

Rollover schedule

Example

/wombat/foo.%d

Rolling log at midnight every day, unspecified, the default is% d{yyyy-MM-dd}

If the file attribute is not set: on July 17, 2016, the log will be output to / wombat / foo In the log file on July 17, 2016, at midnight, the currently valid log file will be converted to / wombat / foo 2016-07-18 The file property is set to / wombat / foo Txt: on July 17, 2016, the log will be output to / wombat / foo Txt log file. At 24:00 midnight, the log file is archived and renamed / wombat / foo On July 18, 2016, the currently valid log file was recreated and named / wombat / foo txt

/wombat/%d{yyyy/MM}/foo.txt

One watch per month

If the file attribute is not set: in July 2016, the log is output to / wombat / 2016 / 07 / foo txt. At 24 midnight on July 31, the log is redirected and output to / wombat / 2016 / 08 / foo txt. The file property is set to / wombat / foo Txt: the current valid log file is the value specified by file. At 24:00 at the end of the month, archive the log, recreate the file specified by file, and redirect the log output stream to this new file.

/wombat/foo.%d{yyyy-ww}.log

It should be noted that the first day of each week is related to the regional setting

Similar to above

/wombat/foo%d{yyyy-MM-dd_HH}.log

One watch per hour

Similar to above

/wombat/foo%d{yyyy-MM-dd_HH-mm}.log

One watch per minute

Similar to above

/wombat/foo%d{yyyy-MM-dd_HH-mm, UTC}.log

One watch per minute and UTC time

Similar to above, except that the time is formatted as UTC time

/foo/%d{yyyy-MM,aux}/%d.log

One watch a day

Contains two% d, the first contains aux, which indicates that it is not the main scroll parameter, but is mainly used for folder segmentation. In other words, daily logs are stored in different paths by month

TimeBaseRollingPolicy supports automatic compression of log files by setting the value of fileNamePattern gz or Open at the end of zip.

fileNamePattern

Rollover schedule

Example

/wombat/foo.%d.gz

Automatically compress and archive log files every day

When the file attribute is not set: on July 17, 2016, the log is output to / wombat / foo On July 17, 2016, at 24 midnight, the log file will be compressed and renamed / wombat / foo 2016-07-17. gz. The log is then redirected to / wombat / foo 2016-07-18 The file attribute is set to / wombat / foo Txt: the current valid log file name will never change. Scroll the log at 0 o'clock every day and compress the log.

For many reasons, log scrolling is not clock driven, but depends on incoming log events. If fileNamePattern is set to YYY MM DD, if the first log event request occurs at 00:30 after 24:00, the real log rolling event occurs at 00:30. However, the implementation of this delay can be ignored.

The following is a simple configuration example:

   <configuration>  
     <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">  
       <file>logFile.log</file>  
       <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
         <!-- daily rollover -->  
         <fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>  
         <!-- keep 30 days' worth of history capped at 3GB total size -->  
         <maxHistory>30</maxHistory>  
         <totalSizeCap>3GB</totalSizeCap>  
       </rollingPolicy>  
       <encoder>  
         <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>  
       </encoder>  
     </appender>   
 
     <root level="DEBUG">  
       <appender-ref ref="FILE" />  
     </root>  
   </configuration>  

SizeAndTimeBasedRollingPolicy

Sometimes you not only want to specify the scrolling strategy by time, but also want to limit the size of each log file at the same time. The TimeBasedRoolingPolicy already provides the function of limiting the size of the total log file, while SizeAndTimeBasedRollingPolicy provides a more powerful ability to limit the size of a single log file.

Take a small example:

   <configuration>  
     <appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">  
       <file>mylog.txt</file>  
 <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> 
         <!-- rollover daily -->  
         <fileNamePattern>mylog-%d{yyyy-MM-dd}.%i.txt</fileNamePattern>  
         <!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->  
 <maxFileSize>100MB</maxFileSize> 
 
         <maxHistory>60</maxHistory>  
         <totalSizeCap>20GB</totalSizeCap>  
       </rollingPolicy>  
       <encoder>  
         <pattern>%msg%n</pattern>  
       </encoder>  
     </appender>  
     <root level="DEBUG">  
       <appender-ref ref="ROLLING" />  
     </root>  
   </configuration>  

It should be noted that in this example, fileNamePattern contains not only% d but also% i, both of which are necessary identifiers.% n i stands for log index number. Today's log has been expanded to a few copies, starting with 0.

In 1.1 Before version 7, SizeAndTimeBasedFNATP was used, and then SizeAndTimeBasedRollingPolicy was adopted. SizeAndTimeBasedRollingPolicy inherited SizeAndTimeBasedFNATP.

FixedWindowRollingPolicy the log rollingpolicy for fixed windows

FixedWindowRollingPolicy

Look at the following parameters first:

Property Name

Type

Description

minIndex

int

This parameter specifies the minimum value of the window index

maxIndex

int

This parameter specifies the maximum value of the window index

fileNamePattern

String

This parameter is no different from the previous fileNamePattern. The only thing to note is that it must contain the% i identifier, which is used to indicate the value of the current window index. For example, set fileNamePattern to“ MyLogFile%i ", minIndex is 1 and maxIndex is 3, the MyLogFile1.log, MyLogFile2.log and MyLogFile3.log. These three archive log files.

Take a small example:

   <configuration>  
     <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">  
       <file>test.log</file>  
 <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> 
 <fileNamePattern>tests.%i.log.zip</fileNamePattern> 
       <minIndex>1</minIndex> 
       <maxIndex>3</maxIndex> 
       </rollingPolicy>  
 <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> 
 <maxFileSize>5MB</maxFileSize> 
       </triggeringPolicy>  
       <encoder>  
         <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>  
       </encoder>  
     </appender>  
     <root level="DEBUG">  
       <appender-ref ref="FILE" />  
     </root>  
   </configuration>  

Next, let's look at the interface of triggering policies

TriggeringPolicy Responsible for when RollingFileAppender logs roll

Interface Description:

   package ch.qos.logback.core.rolling;  
   import java.io.File;  
   import ch.qos.logback.core.spi.LifeCycle;  
   public interface TriggeringPolicy<E> extends LifeCycle {  
       /*This method determines whether log scrolling occurs*/  
     public boolean isTriggeringEvent(final File activeFile, final <E> event);  
   }  

SizeBasedTriggeringPolicy

SizeBasedTriggeringPolicy Check the size of the current active log file. When it reaches a certain capacity, start log scrolling.

Sizebasedtriggingpolicy only receives one parameter, maxFileSize. The default value is 10MB

Acceptable B, KB, MB, GB

SocketAppender and SSLSocketAppender

So far, the appender we talked about can only output logs to local resources. In contrast, SocketAppender is designed to output logs to remote instances. SocketAppender outputs logs in clear text, while SSLSocketAppender transmits logs in encryption.

The type of log event being serialized is LoggingEventVO Inherits the ILoggingEvent interface. Remote logging is not intrusive. After deserialization reception, log events can be processed as if they were generated locally. Multiple sockerappenders can send logs to the same log server. SocketAppender does not need to be associated with a Layout because it just sends serialized log events to the remote log server. The sending operation of SocketAppender is based on TCP protocol. Therefore, if the remote server is reachable, the log will be processed by it. If the remote server is down or unreachable, the log will be discarded. When the remote server comes back to life, log sending will restart transparently. This transparent reconnection is achieved by a "connection" thread periodically trying to connect to the remote server.

Logging events is automatically buffered by TCP protocol. This means that if the network speed is faster than the generation speed of log requests, the network speed will not affect the application. However, if the network speed is too slow, the network speed will become a limit. In extreme cases, if the remote log server is unreachable, the application will eventually block. However, if the server can reach But the server is down. In this case, the application will not block, but just lose some log events.

It should be noted that even if the SocketAppender is not linked by the logger, it will not be recycled by gc because it still has references in the connector thread. A connector thread will exit only when the network is unreachable. In order to prevent this problem of garbage collection, we should display a statement to close the SocketAppender. It will survive for a long time and create / destroy a large number of SOCS The application of the SocketAppender instance should pay more attention to this problem. However, most applications can ignore this problem. If the JVM exits the SocketAppender before it is closed, or it is garbage collected, it may lead to the loss of some log data waiting in the pipeline that has not been transmitted. In order to prevent log loss, it is often a reliable way to call socket The close method of the appender or the stop method of LoggerContext is called before exiting the application.

Let's take a look at the properties of SocketAppender:

Property Name

Type

Description

includeCallerData

boolean

Include caller information If it is true, the following log output?:? Will be replaced with the caller's file name and line number. If it is false, it is a question mark. 2006-11-06 17:37:30,968 DEBUG [Thread-0] [?:?] chapters.appenders.socket.SocketClient2 - Hi

port

int

Port number

reconnectionDelay

Duration

If the reconnection delay is set to "10 seconds", it will wait 10 seconds after the connection u weapon fails before connecting. The default value is "30 seconds". If it is set to 0, the reconnection function will be turned off.

queueSize

int

Set the number of buffered logs. If it is set to 0, the log sending is synchronous. If it is set to a value greater than 0, the logs will be put into the queue. The queue length reaches the specified value and sent uniformly. You can increase the service throughput.

eventDelayLimit

Duration

Set the log timeout Discard time. When a value similar to "10 seconds" is set, if the log queue is full and the server is too late to receive for a long time, the log will be discarded when the retention time exceeds 10 seconds. Default: 100 milliseconds

remoteHost

String

IP address of remote log server

ssl

SSLConfiguration

This attribute node is only included in SSLSocketAppender. SSL configuration is provided. For details, see Using SSL

The standard Logback Classic contains four receivers that can be used to receive logging evnets from SocketAppender.

  • ServerSocketReceiver, and the SSL enabled replica SSLSeverSocketReceiver. See the detailed configuration Receivers
  • Simplessocketserver, and SimpleSSLSocketServer, which allows SSL replicas.

Use SimpleSocketServer on the server side

SimpleSocketServer requires two command line parameters, port and configFile path.

   java ch.qos.logback.classic.net.SimpleSocketServer 6000 \ src/main/java/chapters/appenders/socket/server1.xml 

Simple configuration example of SocketAppender on the client:

 <configuration> 
   <appender name="SOCKET" class="ch.qos.logback.classic.net.SocketAppender"> 
     <remoteHost>192.168.0.101</remoteHost> 
     <port>8888</port> 
     <reconnectionDelay>10000</reconnectionDelay> 
     <includeCallerData>true</includeCallerData> 
   </appender> 
   <root level="DEBUG"> 
     <appender-ref ref="SOCKET" /> 
   </root> 
 </configuration> 

Use simplesssockets server on the server side

   java -Djavax.net.ssl.keyStore=src/main/java/chapters/appenders/socket/ssl/keystore.jks \ -Djavax.net.ssl.keyStorePassword=changeit \ ch.qos.logback.classic.net.SimpleSSLSocketServer 6000 \ src/main/java/chapters/appenders/socket/ssl/server.xml 

SSLSocketAppender configuration

   <configuration debug="true">  
     <appender name="SOCKET" class="ch.qos.logback.classic.net.SSLSocketAppender">  
       <remoteHost>${host}</remoteHost>  
       <port>${port}</port>  
       <reconnectionDelay>10000</reconnectionDelay>  
       <ssl>  
         <trustStore>  
           <location>${truststore}</location>  
           <password>${password}</password>  
         </trustStore>  
       </ssl>  
     </appender>  
     <root level="DEBUG">  
       <appender-ref ref="SOCKET" />  
     </root>   
 
   </configuration>  

ServerSocketAppender and SSLSeverSocketAppender

The design concept of SocketAppender and SSLSockertAppender mentioned above is to let applications actively connect to the remote log server. However, sometimes it may be inconvenient or unscientific to let applications connect to the log server during initialization. Therefore, Logback also provides ServerSocketAppender and sslserverssocketappender. SocketAppender and ServerSocketAppender serialize Logging event uses the same method. The serialized objects are ILoggingEvent. The only difference is the master-slave conversion of connection initialization. SocketAppender is the active party to establish a connection with the log server, while ServerSocketAppender is passive. It listens to connection requests from the client.

ServerSocketAppender property sheet:

Property Name

Type

Description

address

String

Specify the address of the local network interface that the appender listens to. If not specified, it listens to all network interfaces

includeCallerData

boolean

If true, the caller data will be transferred to the remote host. It is not transferred by default

port

int

Listen to that port

ssl

SSLConfiguration

This attribute is only supported by SSLServerSocketAppender and provides SSL configuration

Take a small example:

   <configuration debug="true">  
     <appender name="SERVER"   
 
       class="ch.qos.logback.classic.net.server.ServerSocketAppender">  
       <port>${port}</port>  
       <includeCallerData>${includeCallerData}</includeCallerData>  
     </appender>  
     <root level="debug">  
       <appender-ref ref="SERVER" />  
     </root>   
 
   </configuration>  

The main difference between this configuration and the previous SocketAppender configuration is that the < remotehost > attribute is missing, because the ServerSocketAppender does not actively open the connection with the log server, but passively waits for the connection request from the remote host.

The following is a configuration example of SSLSocketAppender:

   <configuration debug="true">  
     <appender name="SERVER"   
 
       class="ch.qos.logback.classic.net.server.SSLServerSocketAppender">  
       <port>${port}</port>  
       <includeCallerData>${includeCallerData}</includeCallerData>  
       <ssl>  
         <keyStore>  
           <location>${keystore}</location>  
           <password>${password}</password>  
         </keyStore>  
       </ssl>  
     </appender>  
     <root level="debug">  
       <appender-ref ref="SERVER" />  
     </root>   
 
   </configuration>  

After the Socket log output, let's take a look at the mail based log output

SMTPAppender

SMTPAppender You can store the logging event in one or more fixed size buffers, and then send the logging event of appropriate size to the operation and maintenance personnel by mail when the event specified by the user arrives.

The detailed properties are as follows:

Property Name

Type

Description

smtpHost

String

The address of the SMTP server, which must be specified. For example, the SMTP server address of Netease is SMTP 163.com

smtpPort

int

The port address of the SMTP server. Default: 25

to

String

Specify the mailbox to send to. You can set multiple < to > attributes and specify multiple destination mailboxes

from

String

Specify the sender name. If set to "Adam Smith <smith@moral.org> ”, The sender of the message will be "Adam Smith"< smith@moral.org > ”

subject

String

Specify the title of emial, which needs to meet the format requirements in PatternLayout. If set to“ Log:% logger -% MSG ", for example, when sending an email, the title is“ Log: com.foo.Bar - Hello World ". Default: "%logger{20} - %m".

discriminator

Discriminator

Through the Discriminator, SMTPAppender can distribute the incoming logging event s to different buffers according to the return value of the Discriminator. By default, the same value is always returned to achieve the purpose of using one buffer.

evaluator

IEvaluator

Specify the conditions that trigger log sending. Specify the implementation class of the EventEvaluator interface through < evaluator class =... / > by default, smtpappender uses OnErrorEvaluator, which means that when sending log requests of ERROR or higher level, mail will be sent. Logback provides several evaluators: Onerrorevaluatoronmarkerevaluatorjanineventevaluatorgeventevaluator (powerful)

cyclicBufferTracker

CyclicBufferTracker

Specify a CyclicBufferTracker to track the cyclic buffer. It is based on the implementation of discriminator. If you do not specify it, a CyclicBufferTracker will be created by default, and the default setting of the cyclic buffer size is 256. You can also manually specify the default CyclicBufferTracker and modify the number of logging event s received by the default buffer through the < buffersize > property.

username

String

Sending mail account, null by default

password

String

Send mail password, null by default

STARTTLS

boolean

If it is set to true, the appender will try to use the STARTTLS command. If the server supports it, it will convert the plaintext connection to an encrypted connection. It should be noted that the connection to the log server is unencrypted at first. Default: false

SSL

boolean

If set to true, the appender will connect to the log server using SSL. Default: false

charsetEncoding

String

Specifies the encoding format of the message information Default: UTF-8

localhost

String

If the SMTP host is not configured correctly, for example, it is not a complete address. In this case, the localhost attribute is required to provide the full path of the server (like the fully qualified name in java). For details, refer to the mail.smtp.localhost attribute in com.sun.mail.smtp

asynchronousSending

boolean

This attribute determines whether email is sent asynchronously. Default: true, send asynchronously However, in some cases, it is necessary to send the error log email to the management personnel in a synchronous manner to prevent failure to maintain the application in time.

includeCallerData

boolean

Default: false Specifies whether to include callerData in the log

sessionViaJNDI

boolean

SMTPAppender relies on javax.mail.Session to send mail. By default, sessionViaJNDI is false. The creation of javax.mail.Session instance depends on the configuration information of SMTPAppender itself. If it is set to true, the reference is obtained through JNDI during the creation of Session. This has the advantages of better code reuse and simpler configuration. It should be noted that if you use JNDI to obtain the Session object, you need to ensure that the two jar packages mail.jar and activation.jar are removed

jndiLocation

String

If sessionViaJNDI is set to true, jndiLocation specifies the resource name of JNDI. The default value is: "java:comp/env/mail/Session"

cyclicBufferTracker CyclicBufferTracker Specify a cyclicBufferTracker to track the cyclicbuffer. It is based on the implementation of discriminator. If you do not specify it, it will be created by default CyclicBufferTracker , the default setting of cyclic buffer size is 256. You can also manually specify the default CyclicBufferTracker and modify the number of logging event s received by the default buffer through the < buffersize > property. username String sends mail account, the default is null password String sends mail password, and the default is null startls Boolean. If it is set to true, the appender will Try to use the STARTTLS command. If the server supports it, the plaintext connection will be converted into an encrypted connection. Note that the connection to the log server is not encrypted at first. Default: false If SSL boolean is set to true, the appender will connect to the log server using SSL. Default: false charsetEncoding String specifies the encoding format of mail information Default: UTF-8 localhost String if the SMTP host is not configured correctly, for example, it is not a complete address. In this case, the localhost property is required to provide the full path of the server (like the fully qualified name in java). For details, see com.sun.mail.smtp The mail.smtp.localhost attribute asynchronousSending boolean in determines whether email is sent asynchronously. Default: true, send asynchronously However, in some cases, it is necessary to send the error log email to the management personnel in a synchronous manner to prevent failure to maintain the application in time. includeCallerData boolean default: false Specifies whether to include callerData in the log sessionViaJNDI Boolean SMTPAppender relies on javax.mail.Session to send mail. By default, sessionViaJNDI is false. The creation of javax.mail.Session instance depends on the configuration information of SMTPAppender itself. If it is set to true, the reference of Session is obtained through JNDI during the creation of Session. This can make your code reuse better and the configuration more concise. It should be noted that if you use JNDI to obtain the Session object, you need to ensure that the two jar packages mail.jar and activation.jar are removed jndiLocation String if sessionViaJNDI is set to true, jndiLocation specifies the resource name of JNDI. The default value is: "java:comp/env/mail/Session"

SMTPAppender only keeps the latest 256 logging events in the circular buffer. When the buffer is slow, it will start to discard the oldest logging events. Therefore, SMTPAppender can deliver up to 256 log events in a message at any time. SMTPAppender depends on JavaMail API, which in turn depends on IOC framework (dependency injection).

Original text:

You can download the JavaMail API and the JavaBeans Activation Framework from their respective websites. Make sure to place these two jar files in the classpath before trying the following examples.

Look at a small example

   <configuration>   
 
     <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">  
       <smtpHost>ADDRESS-OF-YOUR-SMTP-HOST</smtpHost>  
       <to>EMAIL-DESTINATION</to>  
       <to>ANOTHER_EMAIL_DESTINATION</to> <!-- additional destinations are possible -->  
       <from>SENDER-EMAIL</from>  
       <subject>TESTING: %logger{20} - %m</subject>  
       <layout class="ch.qos.logback.classic.PatternLayout">  
         <pattern>%date %-5level %logger{35} - %message%n</pattern>  
       </layout>   
 
     </appender>  
     <root level="DEBUG">  
       <appender-ref ref="EMAIL" />  
     </root>   
 
   </configuration>  

Custom circular buffer size: considering the default size of 256 logs, it may not be applicable, and we can also customize it.

 <configuration> 
   <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender"> 
     <smtpHost>${smtpHost}</smtpHost> 
     <to>${to}</to> 
     <from>${from}</from> 
     <subject>%logger{20} - %m</subject> 
     <layout class="ch.qos.logback.classic.html.HTMLLayout"/> 
    <cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker"> 
   <!-- send just one log entry per email -->  
       <bufferSize>1</bufferSize> 
     </cyclicBufferTracker> 
   </appender> 
   <root level="DEBUG"> 
     <appender-ref ref="EMAIL" /> 
   </root> 
 </configuration> 

Event triggering mail log sending: by default, the Evaluator specifies OnErrorEvaluator, which indicates that log sending will be triggered when an event with level error or higher occurs.

We can also write our own log trigger, as long as we inherit from the EventEvaluator interface. It mainly implements the evaluate method. Here is an example:

Function: trigger log sending request every 1024 log events.

   package chapters.appenders.mail;  
   import ch.qos.logback.core.boolex.EvaluationException;  
   import ch.qos.logback.core.boolex.EventEvaluator;  
   import ch.qos.logback.core.spi.ContextAwareBase;  
   public class CounterBasedEvaluator extends ContextAwareBase implements EventEvaluator {  
     static int LIMIT = 1024;  
     int counter = 0;  
     String name;  
     public boolean evaluate(Object event) throws NullPointerException,  
         EvaluationException {  
       counter++;  
       if (counter == LIMIT) {  
         counter = 0;  
         return true;  
       } else {  
         return false;  
       }  
     }  
     public String getName() {  
       return name;  
     }  
     public void setName(String name) {  
       this.name = name;  
     }  
   }  

Using a custom Evaluator

   <configuration>  
     <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">  
       <evaluator class="chapters.appenders.mail.CounterBasedEvaluator" />  
       <smtpHost>${smtpHost}</smtpHost>  
       <to>${to}</to>  
       <from>${from}</from>  
       <subject>%logger{20} - %m</subject>  
       <layout class="ch.qos.logback.classic.html.HTMLLayout"/>  
     </appender>  
     <root level="DEBUG">  
       <appender-ref ref="EMAIL" />  
     </root>   
 
   </configuration>  

Label based Evaluator

When we talked about the SMTPAppender attribute earlier, we talked about the implementation of several evaluators provided by logback. Let's take a look at the use examples below.

Specify the label of the log event in the code

   Marker notifyAdmin = MarkerFactory.getMarker("NOTIFY_ADMIN");  
   logger.error(notifyAdmin,  
     "This is a serious an error requiring the admin's attention",  
     new Exception("Just testing"));  

The first is the OnmarkerEvaluator

   <configuration>  
     <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">  
       <evaluator class="ch.qos.logback.classic.boolex.OnMarkerEvaluator">  
         <marker>NOTIFY_ADMIN</marker>  
         <!-- you specify add as many markers as you want -->  
         <marker>TRANSACTION_FAILURE</marker>  
       </evaluator>  
       <smtpHost>${smtpHost}</smtpHost>  
       <to>${to}</to>  
       <from>${from}</from>  
       <layout class="ch.qos.logback.classic.html.HTMLLayout"/>  
     </appender>  
     <root>  
       <level value ="debug"/>  
       <appender-ref ref="EMAIL" />  
     </root>   
 
   </configuration>  

Then JaninoEventEvaluator

   <configuration>  
     <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">  
       <evaluator class="ch.qos.logback.classic.boolex.JaninoEventEvaluator">  
         <expression>  
           (marker != null) &&  
           (marker.contains("NOTIFY_ADMIN") || marker.contains("TRANSACTION_FAILURE"))  
         </expression>  
       </evaluator>   
 
       ... same as above  
     </appender>  
   </configuration>  

Finally, take a look at GEventEvaluator, which uses "?." Security caller, whose function will be called only when the object is not empty.

   <configuration>  
     <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">  
       <evaluator class="ch.qos.logback.classic.boolex.GEventEvaluator">  
         <expression>  
           e.marker?.contains("NOTIFY_ADMIN") || e.marker?.contains("TRANSACTION_FAILURE")  
         </expression>  
       </evaluator>   
 
       ... same as aboveffdfdvc  
     </appender>  
   </configuration>  

The following SMTPAppender uses SSL

   <configuration>  
     <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">  
       <smtpHost>smtp.gmail.com</smtpHost>  
       <smtpPort>465</smtpPort>  
       <SSL>true</SSL>  
       <username>YOUR_USERNAME@gmail.com</username>  
       <password>YOUR_GMAIL_PASSWORD</password>  
       <to>EMAIL-DESTINATION</to>  
       <to>ANOTHER_EMAIL_DESTINATION</to> <!-- additional destinations are possible -->  
       <from>YOUR_USERNAME@gmail.com</from>  
       <subject>TESTING: %logger{20} - %m</subject>  
       <layout class="ch.qos.logback.classic.PatternLayout">  
         <pattern>%date %-5level %logger{35} - %message%n</pattern>  
       </layout>   
 
     </appender>  
     <root level="DEBUG">  
       <appender-ref ref="EMAIL" />  
     </root>   
 
   </configuration>  

The following SMTPAppender uses STARTTLS

   <configuration>   
 
     <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">  
       <smtpHost>smtp.gmail.com</smtpHost>  
       <smtpPort>587</smtpPort>  
       <STARTTLS>true</STARTTLS>  
       <username>YOUR_USERNAME@gmail.com</username>  
       <password>YOUR_GMAIL_xPASSWORD</password>  
       <to>EMAIL-DESTINATION</to>  
       <to>ANOTHER_EMAIL_DESTINATION</to> <!-- additional destinations are possible -->  
       <from>YOUR_USERNAME@gmail.com</from>  
       <subject>TESTING: %logger{20} - %m</subject>  
       <layout class="ch.qos.logback.classic.PatternLayout">  
         <pattern>%date %-5level %logger - %message%n</pattern>  
       </layout>   
 
     </appender>  
     <root level="DEBUG">  
       <appender-ref ref="EMAIL" />  
     </root>   
 
   </configuration>  

SMTPAppender and MDCDiscriminator

As mentioned earlier, the default Discriminator distributes logging event s to different buffers according to the return value.

The following is an implementation of the mdcddiscriminator using one of the logback discriminators to complete the function of distinguishing log buffers by remote host ip

   <configuration>   
 
     <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">  
       <smtpHost>ADDRESS-OF-YOUR-SMTP-HOST</smtpHost>  
       <to>EMAIL-DESTINATION</to>  
       <from>SENDER-EMAIL</from>  
 <discriminator class="ch.qos.logback.classic.sift.MDCBasedDiscriminator"> 
       <key>req.remoteHost</key> 
       <defaultValue>default</defaultValue> 
     </discriminator> 
       <subject>${HOSTNAME} -- %X{req.remoteHost} %msg"</subject>  
       <layout class="ch.qos.logback.classic.html.HTMLLayout">  
         <pattern>%date%level%thread%X{req.remoteHost}%X{req.requestURL}%logger%msg</pattern>  
       </layout>  
     </appender>  
     <root>  
       <level level="DEBUG"/>  
       <appender-ref ref="EMAIL" />  
     </root>   
 
   </configuration>  

How to manage circular buffers in a busy system?

If you use a custom discriminator, you may create many new circular buffers, but maxNumberOfBuffers (default: 64). Whenever the number of buffers is greater than this value, the least recently updated buffer will be discarded by the "least recently updated algorithm". For security reasons, if the buffer is not updated within 30 minutes, it will also be discarded.

In an application with large TPS (transaction volume per second), if maxNumberOfBuffer is set too small, the number of logs per message will often be small. The reason is that the buffer may be created, destroyed and recreated. This cycle leads to a low amount of logs in the final buffer.

To prevent this vacillating effect, when SMTPAppender encounters a log event labeled "FINALIZE_SESSION", it will release the corresponding buffer. In this way, we can customize the buffer recycling strategy and no longer use the least recent update algorithm. You can also set the value of maxNumberOfBuffers to a larger value, such as 5121024, etc.

DBAppender

DBAppender Log events can be inserted into 3 data tables. They are logging_event,logging_event_property,logging_event_exception. These three data tables must exist before DBAppender works. Their SQL scripts can be found in the logback classic / SRC / main / Java / CH / QoS / logback / classic / db / script folder directory. This script is valid for most SQL databases. Except for a few, a few syntax differences need to be adjusted.

The following is the support information for logback and common databases:

RDBMS

tested version(s)

tested JDBC driver version(s)

supports getGeneratedKeys() method

is a dialect provided by logback

DB2

untested

untested

unknown

NO

H2

1.2.132

-

unknown

YES

HSQL

1.8.0.7

-

NO

YES

Microsoft SQL Server

2005

2.0.1008.2 (sqljdbc.jar)

YES

YES

MySQL

5.0.22

5.0.8 (mysql-connector.jar)

YES

YES

PostgreSQL

8.x

8.4-701.jdbc4

NO

YES

Oracle

10g

10.2.0.1 (ojdbc14.jar)

YES

YES

SQLLite

3.7.4

-

unknown

YES

Sybase SQLAnywhere

10.0.1

-

unknown

YES

Let's take a look at the table structure information of the three data tables:

logging_event

Field

Type

Description

timestamp

big int

Log event creation time

formatted_message

text

Format the information of logging event The message that has been added to the logging event, after formatting with org.slf4j.impl.MessageFormatter, in case objects were passed along with the message.

logger_name

varchar

name of logger

level_string

varchar

Log event level

reference_flag

smallint

This property is used by logback to determine whether the logging event contains exception or MDC property This value is determined by ch.qos. logback. classic. db. Calculated by dbhelper. When logging event contains MDC or context attribute, it is 1; When the exception is contained, it is 2; The first two are 3.

caller_filename

varchar

The file name of the log event caller

caller_class

varchar

The class name of the log event caller

caller_method

varchar

Functions of log event callers

caller_line

char

The number of lines of code that trigger log events

event_id

int

The id of the log event in the database table. Primary key

logging_event_property

Field

Type

Description

event_id

int

The id of the log event in the database table. Primary key

mapped_key

varchar

key of MDC property

mapped_value

text

value of MDC property

logging_event_exception

Field

Type

Description

event_id

int

The id of the log event in the database table. Primary key

i

smallint

The index of the line in the full stack trace.

trace_line

varchar

The corresponding line

Next, let's look at how to configure the database connection: the experiment shows that it takes about 10 milliseconds to insert a log without using the database connection pool technology, while it takes about 1 millisecond to use the connection pool. Therefore, it is recommended to use database connection pool to obtain database connection objects. The common one is C3P0.

The following is an example of using C3P0: (recommended)

   <configuration>  
     <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">  
       <connectionSource  
         class="ch.qos.logback.core.db.DataSourceConnectionSource">  
         <dataSource  
           class="com.mchange.v2.c3p0.ComboPooledDataSource">  
           <driverClass>com.mysql.jdbc.Driver</driverClass>  
           <jdbcUrl>jdbc:mysql://${serverName}:${port}/${dbName}</jdbcUrl>  
           <user>${user}</user>  
           <password>${password}</password>  
         </dataSource>  
       </connectionSource>  
     </appender>  
     <root level="DEBUG">  
       <appender-ref ref="DB" />  
     </root>  
   </configuration>  

In addition to C3P0, you can also use the ch.qos provided by logback logback. core. db. DriverManagerConnectionSource

   <configuration  debug="true">  
     <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">  
       <connectionSource class="ch.qos.logback.core.db.DataSourceConnectionSource">  
         <dataSource class="${dataSourceClass}">  
           <!-- Joran cannot substitute variables  
           that are not attribute values. Therefore, we cannot  
           declare the next parameter like the others.  
           -->  
           <param name="${url-key:-url}" value="${url_value}"/>  
           <serverName>${serverName}</serverName>  
           <databaseName>${databaseName}</databaseName>  
         </dataSource>  
         <user>${user}</user>  
         <password>${password}</password>  
       </connectionSource>  
     </appender>  
     <root level="INFO">  
       <appender-ref ref="DB" />  
     </root>   
 
   </configuration>  

Of course, you can also use JNDI to configure the data source, and then obtain the connection object from the JNDI connection pool

   <Context docBase="/path/to/app.war" path="/myapp">  
     ...  
     <Resource name="jdbc/logging"  
                 auth="Container"  
                 type="javax.sql.DataSource"  
                 username="..."  
                 password="..."  
                 driverClassName="org.postgresql.Driver"  
                 url="jdbc:postgresql://localhost/..."  
                 maxActive="8"  
                 maxIdle="4"/>  
     ...  
   </Context>  
   <configuration debug="true">  
     <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">  
       <connectionSource class="ch.qos.logback.core.db.JNDIConnectionSource">  
         <!-- please note the "java:comp/env/" prefix -->  
         <jndiLocation>java:comp/env/jdbc/logging</jndiLocation>  
       </connectionSource>  
     </appender>  
     <root level="INFO">  
       <appender-ref ref="DB" />  
     </root>   
 
   </configuration>  

The following is the configuration of non connection pool. Just have a look:

This configuration will retrieve the database connection object every time the log is inserted.

   <configuration>  
     <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">  
       <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">  
         <driverClass>com.mysql.jdbc.Driver</driverClass>  
         <url>jdbc:mysql://host_name:3306/datebase_name</url>  
         <user>username</user>  
         <password>password</password>  
       </connectionSource>  
     </appender>  
     <root level="DEBUG" >  
       <appender-ref ref="DB" />  
     </root>  
   </configuration>  

SyslogAppender

SyslogAppender It is a very simple protocol: a syslog sender sends a small message to the syslog receiver. This receiver is usually called syslog daemon or syslog server. logback can send messages to remote receivers

Here are the configuration items

Property Name

Type

Description

syslogHost

String

Hostname of syslog server

port

String

server port, default: 514

facility

String

The facility attribute is used to identify the source of the message Must be set to KERN, USER, MAIL, DAEMON, AUTH, SYSLOG, LPR, NEWS, UUCP, CRON, AUTHPRIV, FTP, NTP, AUDIT, ALERT, CLOCK, LOCAL0, LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7. One of these strings.

suffixPattern

String

Specify the message format to send. Default value: [%thread] %logger %msg . Referenced syntax PatternLayout

stackTracePattern

String

The stackTracePattern property allows the customization of the string appearing just before each stack trace line. The default value for this property is "\t", i.e. the tab character. Any value accepted by PatternLayout is a valid value for stackTracePattern.

throwableExcluded

boolean

Setting throwableExcluded to true will cause stack trace data associated with a Throwable to be omitted. By default, throwableExcluded is set to false so that stack trace data is sent to the syslog server.

A small example

   <configuration>  
     <appender name="SYSLOG" class="ch.qos.logback.classic.net.SyslogAppender">  
       <syslogHost>remote_home</syslogHost>  
       <facility>AUTH</facility>  
       <suffixPattern>[%thread] %logger %msg</suffixPattern>  
     </appender>  
     <root level="DEBUG">  
       <appender-ref ref="SYSLOG" />  
     </root>  
   </configuration>  

When testing this example, you need to allow the remote syslog daemon to receive external request s. The default is rejected.

SiftingAppender

By name, SiftingAppender provides the function of filtering logs. You can filter the logs through the data of users' sessions, and then distribute them to different log files.

Let's take a look at an example to illustrate:

   <configuration>  
     <appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender">  
       <!-- in the absence of the class attribute, it is assumed that the  
           desired discriminator type is  
           ch.qos.logback.classic.sift.MDCBasedDiscriminator -->  
       <discriminator>  
         <key>userid</key>  
         <defaultValue>unknown</defaultValue>  
       </discriminator>  
       <sift>  
         <appender name="FILE-${userid}" class="ch.qos.logback.core.FileAppender">  
           <file>${userid}.log</file>  
           <append>false</append>  
           <layout class="ch.qos.logback.classic.PatternLayout">  
             <pattern>%d [%thread] %level %mdc %logger{35} - %msg%n</pattern>  
           </layout>  
         </appender>  
       </sift>  
     </appender>  
     <root level="DEBUG">  
       <appender-ref ref="SIFT" />  
     </root>  
   </configuration>  
   logger.debug("Application started");  
   MDC.put("userid", "Alice");  
   logger.debug("Alice says hello");  

This example stores logs with different user IDs in different log files by setting the MDC attribute.

SiftingAppender accomplishes these functions by creating a built-in appender, using < sift > < appender > < / appender > < / sift >. The SiftingAppender is responsible for managing the life cycle of these child Appenders. The SiftingAppender automatically closes and removes expired Appenders. If the built-in appender has not performed log output within the time specified by the timeout attribute, it will be considered expired.

In this example, if the discriminator is not specified, mdcbaseddediscriminator will be used by default. If the value of the specified key is null, then < DefaultValue > will be used

SitingAppender has the following two properties

Property Name

Type

Description

timeout

Duration

Set the expiration time when the built-in appender does not have log output. Default: 30 minutes

maxAppenderCount

integer

Set the maximum number of built-in Appenders that can be created. The default value is integer MAX_ VALUE

Setting an appropriate timeout and maxAppenderCount is not so easy. If it is too small, the built-in appender will be destroyed shortly after birth, and if it is too large, it will consume too many resources. Therefore, in many cases, we can also manually close the built-in appender by generating a marker to finalize_ The session log event. When the SiftingAppender sees the log event of this tag, it will end the bound appender. However, the destruction of the appender is not real-time, but wait a few seconds to prevent the loss of unprocessed logs. This is similar to the four wave process of TCP protocol.

Look at a small example

   import org.slf4j.Logger;  
   import static ch.qos.logback.classic.ClassicConstants.FINALIZE_SESSION_MARKER;  
     void job(String jobId) {  
       MDC.put("jobId", jobId);  
       logger.info("Starting job.");  
       ... do whather the job needs to do  
       // will cause the nested appender reach end-of-life. It will  
       // linger for a few seconds.  
       logger.info(FINALIZE_SESSION_MARKER, "About to end the job");  
       try {  
         .. perform clean up  
       } catch(Exception e);   
 
         // This log statement will be handled by the lingering appender.  
         // No new appender will be created.  
         logger.error("unexpected error while cleaning up", e);  
       }  
     }  

AsyncAppender

Async appender records ILoggingEvents asynchronously. It is only equivalent to an event allocator, so it needs to cooperate with other Appenders to make a difference.

Note that AsyncAppender caches event s in BlockingQueue , a worker thread created by AsyncAppender will always get events from the head of the queue and then assign them to the adder uniquely associated with AsyncAppender. By default, if 80% of the queue is full, AsyncAppender will discard the log events of TRACE, DEBUG and INFO.

When the application is closed or redeployed, the AsyncAppender must be closed to stop, recycle and reuse the worker thread, and refresh the logging events in the buffer queue. What if you close AsyncAppender? You can close all Appenders, including AsyncAppender, by closing LoggerContext. AsyncAppender will wait for worker thread to refresh all log events within the time set by maxFlushTime property. If you find that the buffered event is discarded when the LoggerContext is closed, you may need to increase the waiting time. Setting maxFlushTime to 0 means that AsyncAppender waits until the worker thread flushes out all buffered events.

According to the exit mode of the JVM, the work of the worker thread in processing the buffered events can be interrupted, resulting in the stranding of the remaining unprocessed events. The common reason for this phenomenon is when the LoggerContext is not completely closed, or when the JVM terminates those atypical control flows (unknown). In order to avoid the interruption of the working thread due to these conditions, a shutdown hook can be inserted when the JVM is running. The function of this hook is to close the LoggerContext when the JVM starts shutdown.

The following is the property sheet of AsyncAppender

Property Name

Type

Description

queueSize

int

Set the maximum capacity of the blocking queue. The default is 256 events

discardingThreshold

int

By default, when the blocking queue is occupied by more than 80%, AsyncAppender will discard log events with levels of TRACE, DEBUG and INFO. If you want to keep all levels of logs, you need to set it to 0

includeCallerData

boolean

It is expensive to extract CallerData. In order to improve performance, caller data is not provided by default. Only some data with low cost, such as thread name, will be retained. If set to true, caller data will be included

maxFlushTime

int

Sets the maximum wait for refresh events, in milliseconds. When LoggerContext is closed, AsyncAppender will wait for the worker thread to complete the flush of events within this time, and the events that are not processed after timeout will be discarded.

neverBlock

boolean

The default value is false. If the queue is filled, applications will be blocked in order to process all logs. If true, you will also choose to discard some message s in order not to block your application.

By default, the maximum capacity of event queue is 256. If the queue is full, your application will be blocked until the queue can accommodate new logging event s. Therefore, when the AsyncAppender work queue is full, it can be called pseudo synchronization.

The following four situations can easily lead to the occurrence of AsyncAppender pseudo synchronization status:

  • There are a large number of threads in the application
  • A large number of logging events are generated per second
  • Each logging event contains a large amount of data
  • High latency in child Appenders

In order to avoid pseudo synchronization, improving queueSizes is generally effective, but it consumes the available memory of the application.

Having said so much, let's take a look at a small example

   <configuration>  
     <appender name="FILE" class="ch.qos.logback.core.FileAppender">  
       <file>myapp.log</file>  
       <encoder>  
         <pattern>%logger{35} - %msg%n</pattern>  
       </encoder>  
     </appender>  
     <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">  
       <appender-ref ref="FILE" />  
     </appender>  
     <root level="DEBUG">  
       <appender-ref ref="ASYNC" />  
     </root>  
   </configuration>  

Write your own Appender

You can simply create your own appender by inheriting the parent class AppenderBase. AppenderBase has implemented support for filters, status and other functions shared by most Appenders. All we have to do is implement the append(Object evenObject) method.

Let's take an example

   package chapters.appenders;  
   import java.io.IOException;  
   import ch.qos.logback.classic.encoder.PatternLayoutEncoder;  
   import ch.qos.logback.classic.spi.ILoggingEvent;  
   import ch.qos.logback.core.AppenderBase;  
   public class CountingConsoleAppender extends AppenderBase<ILoggingEvent> {  
     static int DEFAULT_LIMIT = 10;  
     int counter = 0;  
     int limit = DEFAULT_LIMIT;  
     PatternLayoutEncoder encoder;  
     public void setLimit(int limit) {  
       this.limit = limit;  
     }  
     public int getLimit() {  
       return limit;  
     }  
     @Override  
     public void start() {  
       if (this.encoder == null) {  
         addError("No encoder set for the appender named ["+ name +"].");  
         return;  
       }  
       try {  
         encoder.init(System.out);  
       } catch (IOException e) {  
       }  
       super.start();  
     }  
     public void append(ILoggingEvent event) {  
       if (counter >= limit) {  
         return;  
       }  
       // output the events as formatted by our layout  
       try {  
         this.encoder.doEncode(event);  
       } catch (IOException e) {  
       }  
       // prepare for next event  
       counter++;  
     }  
     public PatternLayoutEncoder getEncoder() {  
       return encoder;  
     }  
     public void setEncoder(PatternLayoutEncoder encoder) {  
       this.encoder = encoder;  
     }  
   }  

This example tells us two points

  1. All properties are set transparently in the configuration file through setter/getter. The start() method will be called automatically when logback reads the configuration file configuration, and is responsible for checking whether the relevant properties are set incorrectly.
  2. AppenderBase.doAppend() will call the append() method of the subclass to complete the log output. In particular, you can also call layout to format the log in the append() method.

After talking about so many things about logbakc classic, let's take a look at logback access

Most appenders existing in logback classic have similar equivalents in logback access. Most of them are similar, except that ILogginEvent becomes AccessEvent. Let's talk about their differences

In SMTPAppender, the Evaluator attribute is used by default. URLEvaluator is used. Let's take a look at an example

   <appender name="SMTP"  
     class="ch.qos.logback.access.net.SMTPAppender">  
     <layout class="ch.qos.logback.access.html.HTMLLayout">  
       <pattern>%h%l%u%t%r%s%b</pattern>  
     </layout>  
 <Evaluator class="ch.qos.logback.access.net.URLEvaluator"> 
     <URL>url1.jsp</URL> 
     <URL>directory/url2.html</URL> 
   </Evaluator> 
     <from>sender_email@host.com</from>  
     <smtpHost>mail.domain.com</smtpHost>  
     <to>recipient_email@host.com</to>  
   </appender>  

When the current URL matches one of the paths specified by multiple < URL > tags, it will trigger the sending of an email.

In DBAppender, there are also differences. First, only two tables are used, access_event and access_event_header. Their creation sql scripts can be found in logback access / SRC / main / Java / CH / QoS / logback / access / db / script.

See the structure in the table below

access_event

Field

Type

Description

timestamp

big int

The timestamp that was valid at the access event's creation.

requestURI

varchar

The URI that was requested.

requestURL

varchar

The URL that was requested. This is a string composed of the request method, the request URI and the request protocol.

remoteHost

varchar

The name of the remote host.

remoteUser

varchar

The name of the remote user.

remoteAddr

varchar

The remote IP address.

protocol

varchar

The request protocol, like HTTP or HTTPS.

method

varchar

The request method, usually GET or POST.

serverName

varchar

The name of the server that issued the request.

event_id

int

The database id of the access event.

access_event_header

Field

Type

Description

event_id

int

The database id of the corresponding access event.

header_key

varchar

The header name, for example User-Agent.

header_value

varchar

The header value, for example Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.1) Gecko/20061010 Firefox/2.0

In DBAppender, all attributes supported in the classic module are supported in the access module, and access also provides one more attribute

Property Name

Type

Description

insertHeaders

boolean

Tells the DBAppender to populate the database with the header information of all incoming requests.

Here is an example

   <configuration>  
     <appender name="DB" class="ch.qos.logback.access.db.DBAppender">  
       <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">  
         <driverClass>com.mysql.jdbc.Driver</driverClass>  
         <url>jdbc:mysql://localhost:3306/logbackdb</url>  
         <user>logback</user>  
         <password>logback</password>  
       </connectionSource>  
       <insertHeaders>true</insertHeaders>  
     </appender>  
     <appender-ref ref="DB" />  
   </configuration>  

In the SiftingAppender, although most of them are similar, the default value of Discriminator is different. Logback access uses AccessEventDiscriminator by default instead of mdcbaseddediscriminator

The following is the Discriminator section of its configuration

   <Discriminator class="ch.qos.logback.access.sift.AccessEventDiscriminator">  
         <Key>id</Key>  
         <FieldName>SESSION_ATTRIBUTE</FieldName>  
         <AdditionalKey>username</AdditionalKey>  
         <defaultValue>NA</defaultValue>  
   </Discriminator>  

The value of < fieldname > can be set to COOKIE, REQUEST_ATTRIBUTE, SESSION_ATTRIBUTE, REMOTE_ ADDRESS, LOCAL_ PORT, REQUEST_ One of the URIs. And cookie, request_ ATTRIBUTE, SESSION_ If attribute is set to three values, the < AdditionalKey > ID must be set to get the attribute. When the value corresponding to the key set by AdditionalKey is Null, the value set by < DefaultValue > is used as the default value. The value set by < key > is equivalent to the obtained value. The key obtained in the child appender is equivalent to the key in the key value key value pair.

Here is a complete example:

   <configuration>  
     <appender name="SIFTING" class="ch.qos.logback.access.sift.SiftingAppender">  
       <Discriminator class="ch.qos.logback.access.sift.AccessEventDiscriminator">  
         <Key>id</Key>  
         <FieldName>SESSION_ATTRIBUTE</FieldName>  
         <AdditionalKey>username</AdditionalKey>  
         <defaultValue>NA</defaultValue>  
       </Discriminator>  
       <sift>  
         <appender name="ch.qos.logback:logback-site:jar:1.1.7" class="ch.qos.logback.core.FileAppender">  
           <file>byUser/ch.qos.logback:logback-site:jar:1.1.7.log</file>  
           <layout class="ch.qos.logback.access.PatternLayout">  
             <pattern>%h %l %u %t \"%r\" %s %b</pattern>  
           </layout>  
         </appender>  
       </sift>  
     </appender>  
     <appender-ref ref="SIFTING" />  
   </configuration>