I'm logging to syslog with a syslog appender as shown below:
<appender name="SYSLOG" class="ch.qos.logback.classic.net.SyslogAppender">
<syslogHost>localhost</syslogHost>
<facility>LOCAL6</facility>
<suffixPattern>app: %logger{20} %msg</suffixPattern>
</appender>
But I've got a new requirement where I want to send some logs to the "LOCAL5" facility instead of LOCAL6. I've read the logback configuration documentation http://logback.qos.ch/manual/configuration.html but I'm still not sure how to do this.
You can use two syslog appenders one for LOCAL6 and other for LOCAL5
<appender name="SYSLOG" class="ch.qos.logback.classic.net.SyslogAppender">
<syslogHost>localhost</syslogHost>
<facility>LOCAL6</facility>
<suffixPattern>app: %logger{20} %msg</suffixPattern>
</appender>
<appender name="SYSLOG1" class="ch.qos.logback.classic.net.SyslogAppender">
<syslogHost>localhost</syslogHost>
<facility>LOCAL5</facility>
<suffixPattern>app: %logger{20} %msg</suffixPattern>
</appender>
Advantage is that you a customize the logs( some logs) using filters, pattern, logger names etc. And SyslogAppender extends UnsyncronizedAppender.
Reason being you cannot use single appender is that method facilityStringToint(String facilityStr) in class SyslogAppender.java accepts String which then compares which standard facility using equals.
Example
if ("KERN".equalsIgnoreCase(facilityStr)) {
return SyslogConstants.LOG_KERN;
}
Related
logback:
timestamp INFO msg...
timestamp WARN msg...
timestamp INFO msg...
classic java logging (JUL):
timestamp INFO msg...
timestamp WARNING msg...
timestamp INFO msg...
I prefer the WARNING level to be longer than INFO, so I can easily distinguish it visually when scanning log output.
You could specify different logback patterns to achieve what you want - you can send info level logging to an appender which uses a standard layout and then warn to a different appender which uses the word WARNING instead:
<configuration debug="true">
<appender name="info" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>DENY</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>
%d{"ISO8601", UTC} %p %m%n
</pattern>
</encoder>
</appender>
<appender name="warn" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>
%d{"ISO8601", UTC} WARNING %m%n
</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="info"/>
<appender-ref ref="warn"/>
</root>
</configuration>
The %p parameter is substituted with the original message log level so we keep that for the info pattern, for the warn pattern we don't use %p but rather use the constant WARNING.
This config would sit in your logback.xml file in resources root.
EDIT
Changed xml config to use filters and only have one root logger
The idea here is to filter out everything EXCEPT warn level for the first appender, and then on the second only accept warn level and override the log to show WARNING
sample output:
2018-11-08 10:52:40,460 WARNING Exception calculating properties for model(...)
2018-11-08 10:52:40,757 INFO Generating unique operation named: ...
I have the following logback setup
<appender name="TEST-SIFT" class="ch.qos.logback.classic.sift.SiftingAppender">
<discriminator class="..."/>
<sift>
<appender name="ROLL-${fileName}" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>../log/${fileName}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>../log/${fileName}%i.log</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>10</maxIndex>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>5MB</maxFileSize>
</triggeringPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{36} - %msg%n</pattern>
</encoder>
</appender>
</sift>
</appender>
The discriminator class returns a value by parsing the loggerName. The key is defined as "fileName".
The logs rollover fine when I test just the RollingFileAppender (after replacing the variable references of ${fileName} with a static value) but when I have it nested under SiftingAppender, the logs do not roll over. I tested the sifting appender with "FileAppender" and it is able to create the right file name based on the discriminator.
I also tested the same configuration by using the discriminator as
<discriminator>
<key>fileName</key>
<defaultValue>appname</defaultValue>
</discriminator>
and removing the class tag. This creates appname.log but does not roll over.
Setting debug="true" did not write any additional information to the log file.
Am I missing something here? How do I implement RollingFileAppender inside a SiftingAppender?
I figured out the issue with my setup. My logback.xml has to two RollingFileAppenders (one nested in the sifter and one outside). Appender A was writing to application.log and Appender B in some circumstances was writing to application.log as well (i.e. ${fileName} evaluated to application). So if I remove appender A or rename Appender A's fileName, the logs roll over as configured. This probably means Appender A or B could not close and rename the file because the other appender still has a lock on it?
To test this I used an AsyncAppender as follows:
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE" />
</appender>
where "FILE" is the name of Appender A. Using this configuration works but I see some strange behavior where the files do not rollover at the exact size specified and in some cases, the files are renamed with index 10 and get deleted automatically. Since this behavior is not very reliable, for now I got rid of Appender A.
I would like to define 1 single Appender in my log4j2.xml configuration file, and using the magic of the Properties Substitution of Log4J2, be able to somehow log into 2 different files.
I imagine the Appender would look something like:
<RollingFile name="Rolling-${filename}" fileName="${filename}" filePattern="${filename}.%i.log.gz">
<PatternLayout>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</PatternLayout>
<SizeBasedTriggeringPolicy size="500" />
</RollingFile>
Is there a way for a Logger to use this appender and to pass the filename property?
Or is there a way to pass it when we fetch the Logger with LogManager.getLogger?
Note that those logger may or may not be in the same Thread, it has to support both cases, so I don't think it's possible to use ThreadContext nor System properties.
The closest thing I can think of is RoutingAppender. RoutingAppender allows the log file to be dynamically selected based on values in some lookup. A popular built-in lookup is the ThreadContext map (see the example on the FAQ page), but you can create a custom lookup. Example code:
ThreadContext.put("ROUTINGKEY", "foo");
logger.debug("This message gets sent to route foo");
// Do some work, including logging by various loggers.
// All logging done in this thread is sent to foo.
// Other threads can also log to foo at the same time by setting ROUTINGKEY=foo.
logger.debug("... and we are done");
ThreadContext.remove("ROUTINGKEY"); // this thread no longer logs to foo
Example config that creates log files on the fly:
<Routing name="Routing">
<Routes pattern="$${ctx:ROUTINGKEY}">
<!-- This route is chosen if ThreadContext has a value for ROUTINGKEY.
The value dynamically determines the name of the log file. -->
<Route>
<RollingFile name="Rolling-${ctx:ROUTINGKEY}" fileName="logs/other-${ctx:ROUTINGKEY}.log"
filePattern="./logs/${date:yyyy-MM}/${ctx:ROUTINGKEY}-other-%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout>
<pattern>%d{ISO8601} [%t] %p %c{3} - %m%n</pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy interval="6" modulate="true" />
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
</RollingFile>
</Route>
</Routes>
<!-- This route is chosen if ThreadContext has no value for key ROUTINGKEY. -->
<Route key="$${ctx:ROUTINGKEY}">
<RollingFile name="Rolling-default" fileName="logs/default.log"
filePattern="./logs/${date:yyyy-MM}/default-%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout>
<pattern>%d{ISO8601} [%t] %p %c{3} - %m%n</pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy interval="6" modulate="true" />
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
</RollingFile>
</Route>
</Routing>
An alternative is to configure multiple loggers, each pointing to a separate appender (with additivity="false"). This allows your application to control the destination file by obtaining a logger by its name. However, in that case you would need to configure separate appenders so this does not fulfill your requirement, I mention it for completeness.
I am using the logger name to pass arguments to the appender.
It's hacky but it works:
LogManager.getLogger("com.company.test.Test.logto.xyz.log")
A custom StrLookup is necessary to extract the filename from the logger name.
I would like to create a custom LogBack Appender for InfluxDB.
For that, I want to define many series and use the power of logback
<appender name="INFLUXDB" class="org.labaix.logback.InfluxDbAppender">
<series>
<serie>
<id>SensorTemperatureMonthly</id>
<name>machine.%X{machine}.type.%X{type} temperature_${byMonth}</name>
<timeUnit>MILLISECONDS</timeUnit>
</serie>
<serie>
<id>SensorTemperatureDaily</id>
<name>machine.%X{machine}.type.%X{type} temperature_${day}</name>
<timeUnit>MILLISECONDS</timeUnit>
</serie>
</series>
</appender>
Therefore I don't know how to map list of series.
Any ideas ? It is not in documentation so I wonder if it possible.
Thanks. Best regards
Nicolas
Rather than this approach I would prefer to use xml and use JAXB object to load data. You can pass the configuration file xml path as an parameter
<appender name="INFLUXDB" class="org.labaix.logback.InfluxDbAppender">
<configFilePath>configFilePath.xml</configFilePath>
</appender>
The configuration file
<root>
<series>
<serie>
<id>SensorTemperatureMonthly</id>
<name>machine.%X{machine}.type.%X{type} temperature_${byMonth}</name>
<timeUnit>MILLISECONDS</timeUnit>
</serie>
<serie>
<id>SensorTemperatureDaily</id>
<name>machine.%X{machine}.type.%X{type} temperature_${day}</name>
<timeUnit>MILLISECONDS</timeUnit>
</serie>
</series>
</root>
I hit the same problem. I found the answer in ch.qos.logback.core.joran.util.beans.BeanDescription
/**
* Lightweight pendant to the java.beans.BeanInfo class. An instance of this
* class encapsulates the properties of a certain class. The properties are the
* public setters and getters. In addition the 'add-er'-methods are included,
* which are the public methods which start with the prefix 'add'.
*
* #author urechm
*
*/
In this case you could use an addSerie method that adds to a mutable list
I want to configure Logback to fire an email whenever any warnings are found on server.
Right now it is already configure for error level we are getting mails when any error occurred. However same code with changing root level to warn doesn't work.
All sender, receiver, host etc. details are same for which use in error SMTP appender so it's not a server issue. Below is my code.
<appender name="EMAILWARN" class="ch.qos.logback.classic.net.SMTPAppender">
<smtpHost>XXXX</smtpHost>
<to>XXXX</to>
<!-- additional destinations are possible -->
<from>XXXX</from>
<!--
<discriminator class="ch.qos.logback.classic.sift.MDCBasedDiscriminator">
<key>req.remoteHost</key> visit http://logback.qos.ch/manual/mdc.html#mis for different key values
<defaultValue>default</defaultValue>
</discriminator>
-->
<!-- <subject>RCM-Error: ${HOSTNAME} %X{req.remoteHost} %logger - %m</subject> -->
<subject>Error: ${HOSTNAME} - %m %logger</subject>
<!-- <layout class="ch.qos.logback.classic.PatternLayout"> -->
<layout class="ch.qos.logback.classic.html.HTMLLayout">
<pattern>%date%X{REMOTE_ADDR}%X{USER_NAME}%level%logger%message</pattern>
</layout>
<cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTrackerImpl">
<bufferSize>20</bufferSize> <!-- set number of log entry to send per email -->
</cyclicBufferTracker>
</appender>
<root level="warning">
<appender-ref ref="EMAILWARN" />
</root>
ch.qos.logback.classic.net.SMTPAppender use an evaluator to trigger the email send procedure. The default one triggers at ERROR level.
So what you need is an evaluator that tiggers at WARN level (and above)
<appender ... class="ch.qos.logback.classic.net.SMTPAppender">
...
<evaluator class="ch.qos.logback.classic.boolex.JaninoEventEvaluator">
<expression>return level >= WARN;</expression>
</evaluator>
...
</appender>
I'm pretty sure that warning is not a valid logback level.
Try changing your root logger level to warn:
<root level="warn">
<appender-ref ref="EMAILWARN" />
</root>
You can use filters as below, which will select log levels error and warn
<appender name="EMAILWARN" class="ch.qos.logback.classic.net.SMTPAppender">
<!-- rest of your configurations -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
</appender>