Custom log level issue in log4j2 - java

Root logger is configured to be a synchronous logger at INFO level. I also have a couple of Async loggers. One of the Async logger is configured at a customized higher log level TOAST (789). This is higher than the TRACE level (600).
The reason for doing this is to have a log level that can be used for special events to be logged via Async logger and their own appenders.
We dont want the TOAST events to be going to the Synchronous Root loggers or other loggers.. but only to the Async TOAST logger and its corresponding appenders .. is it possible?
<?xml version="1.0" encoding="UTF-8"?>
<Configuration monitorInterval="120" packages=“com.pack.toast”>
<CustomLevels>
<CustomLevel name=“TOAST” intLevel=“789” />
</CustomLevels>
<Appenders>
<RollingFile fileName="${sys:catalina.base}/logs/packiu.log"
append="true" name="DRFILE"
filePattern="${sys:catalina.base}/logs/packiu-%d{yyyy-MM-dd}-%i.log">
<PatternLayout>
<Pattern>%d [%t] %c %M - %p: %m%n</Pattern>
</PatternLayout>
<Policies>
<OnStartupTriggeringPolicy />
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
<DefaultRolloverStrategy max="30" />
</RollingFile>
<RollingFile name="RollingFile" fileName="/Users/toasty/logs/roll_file_app.log"
filePattern="logs/app-%d{MM-dd-yyyy}.log.gz" immediateFlush="true" >
<PatternLayout>
<pattern>%m%n</pattern>
</PatternLayout>
<TimeBasedTriggeringPolicy />
</RollingFile>
<Rewrite name="Rewrite" ignoreExceptions = "true" >
<ToastAppenderPolicy toastNeeded="true">
</ToastAppenderPolicy>
<AppenderRef ref="RollingFile"/>
</Rewrite>
</Appenders>
<Loggers>
<Logger name="net.rubyeye" level="off" />
<Logger name="com.google.code" level="off" />
<AsyncLogger name="com.pack.toast.ToastLoggerImpl" level=“TOAST” includeLocation="true">
<AppenderRef ref="Rewrite" />
</AsyncLogger>
<Root level="info">
<AppenderRef ref="DRFILE" />
</Root>
</Loggers>
</Configuration>

It sounds to me like you really want a named logger not a custom level because you only ever want your messages to go to one logger and its appenders. Perhaps you should use something more like:
<AsyncLogger name="TOAST_LOGGER" level=“INFO” includeLocation="true">
<AppenderRef ref="Rewrite" />
</AsyncLogger>
and then in your code
private static final Logger TOAST_LOGGER = LogManager.getLogger("TOAST_LOGGER");
...
TOAST_LOGGER.info("Toast message");
...
Otherwise, if you must use a custom log level then you can accomplish what you want by filtering with a Threshold Filter.

Related

Java log4j2.xml : Different log patterns for different base packages in same rolling log file

I have an application where there are some custom jars added. One of the jars expects logging to be in a different pattern from the entire application's common logging pattern.
(We are using log4j2.xml way)
Now it is pretty straightforward to do it in Console logs by adding multiple appenders, with different patterns and associating them with the corresponding logger name (base package of the custom jar)
But is there a way to do it in the RollingFile Appenders in the same file ?
Consider the example below
Base application having base log pattern has Logger name = com.legacysystem.base
Custom jar within the application needing custom log pattern has logger name = com.legacysystem.custom
Log pattern for base and custom jar is defined in properties with variable names log-pattern and log-pattern
please ignore the fact that proper pattern value is not added, as i want to keep it hidden (assume log4j2-pattern.xml is present with proper log format)
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="log4j2-pattern.xml">
<xi:fallback >
<Properties>
<Property name="log-pattern">base_log_pattern</Property>
<Property name="custom-log-pattern">custom_log_pattern</Property>
</Properties>
</xi:fallback>
</xi:include>
<Appenders>
<Console name="ConsoleBaseAppender">
<PatternLayout pattern="${log-pattern}"/>
</Console>
<Console name="ConsoleCustomAppender">
<PatternLayout pattern="${custom-log-pattern}"/>
</Console>
<RollingFile name="FILE" fileName="commonFileName.log" filePattern="commonFileName-%d{yyyy-MM-dd-HH}-%i.log.gz">
<PatternLayout pattern="${log-pattern}"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="25MB"/>
</Policies>
<DefaultRolloverStrategy max="20"/>
</RollingFile>
<RollingFile name="CUSTOM_FILE" fileName="commonFileName.log" filePattern="commonFileName-%d{yyyy-MM-dd-HH}-%i.log.gz">
<PatternLayout pattern="${custom-log-pattern}"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="25MB"/>
</Policies>
<DefaultRolloverStrategy max="20"/>
</RollingFile>
</Appenders>
<Loggers>
<Logger name = "com.legacysystem.custom" level="INFO" additivity="false">
<AppenderRef ref="CUSTOM_FILE" />
<AppenderRef ref="ConsoleCustomAppender" />
</Logger>
<Logger name="com.legacysystem.base" level="INFO" additivity="false">
<AppenderRef ref="FILE" />
<AppenderRef ref="ConsoleBaseAppender" />
</Logger>
<Root level="INFO">
<AppenderRef ref="FILE" />
<AppenderRef ref="ConsoleBaseAppender" />
</Root>
</Loggers>
</Configuration>
In the above example, I have succeeded in getting different log patterns in the console, but log files isn't working.
Also, is there a better way to do it without defining two rolling file appenders pointing to same file name ?

Save custom level logs into file in Spring Boot

I want to save the infos of the logins that have succeded into a log file, I thought of creating a new level of logging and save into the log file only the logs with that specific level.
This is how I tried but I can't have it work properly:
log4j2-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout
pattern="%style{%d{ISO8601}}{white} %highlight{%-5level }[%style{%t}{bright,blue}] %style{%C{1.}}{bright,yellow}: %msg%n%throwable" />
</Console>
<RollingFile name="RollingFile"
fileName="./logs/historicLog.log"
filePattern="./logs/$${date:yyyy-MM}/spring-boot-logger-log4j2-%d{-dd-MMMM-yyyy}-%i.log.gz">
<PatternLayout>
<pattern>%d %p %C{1.} [%t] %m%n</pattern>
</PatternLayout>
<Policies>
<OnStartupTriggeringPolicy />
<SizeBasedTriggeringPolicy
size="10 MB" />
<TimeBasedTriggeringPolicy />
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console" />
<AppenderRef ref="RollingFile" />
</Root>
<Logger name="login" level="info">
<AppenderRef ref="RollingFile" />
</Logger>
</Loggers>
</Configuration>
build.gradle dependencies:
dependencies {
implementation 'org.springframework.cloud:spring-cloud-config-server:3.0.5'
implementation 'org.springframework.boot:spring-boot-starter-web:2.6.1'
implementation 'org.springframework.boot:spring-boot-starter-log4j2'
implementation 'org.springframework.boot:spring-boot-starter-actuator:2.6.1'
testImplementation 'org.springframework.boot:spring-boot-starter-test:2.6.1'
}
configurations.implementation {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
}
AuthenticationService.java
private static final org.apache.logging.log4j.Logger logger = LogManager.getLogger(AuthenticationServiceApplication.class);
....
logger.log(Level.forName("login", 850), user.getUsername() + " logged in as admin");
Thank you in advance.
Your root logger is still set on INFO, and your com.authenticationservice logger is on TRACE, both have level IDs lower then 850, so any log statements with a higher level will not be written.
However, i would suggest to not use a custom log level, but rather a specific logger name and configure that one then. E.g. like this:
In your AuthenticationService.java:
private static final org.apache.logging.log4j.Logger logger = LogManager.getLogger("login");
In your log4j2-spring.xml:
<Logger name="login" level="info"> // Note, that you should have the same level configured than what you use in the code to log the messages
<AppenderRef ref="RollingFile" />
</Logger>
This would write all login related logs in the log file configured at RollingFile. With that solution you are a lot more flexible than with using a custom level, since you can redirect this to separate files, combine the statements with other loggers etc.

Stop Debug Statements from publishing in log

I have the following log.properties file in my Java project:
handlers= java.util.logging.ConsoleHandler
.level= INFO
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format=[%1$tF %1$tT] [%4$s] %5$s %n
I am declaring the Logger as follows in one file which generates most of the log:
public static final Logger logger = LogManager.getLogger();
The log4j2.xml file is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval ="5">
<Properties>
<Property name="log-path">${LOGDIR}</Property>
</Properties>
<Appenders>
<RollingFile name="RollingFile"
fileName="workerApplication.log"
filePattern="workerApplication-%d{yyyy-MM-dd}-%i.log">
<PatternLayout>
<Pattern>%d %p %c [%t] %m%n</Pattern>
</PatternLayout>
<Policies>
<SizeBasedTriggeringPolicy size="20 MB" />
</Policies>
<!-- <DefaultRolloverStrategy max="4" /> -->
</RollingFile>
</Appenders>
<Loggers>
<Logger name="root" level="warn" additivity="false">
<appender-ref ref="RollingFile" />
</Logger>
<Root level="debug" additivity="false">
<AppenderRef ref="RollingFile" />
</Root>
</Loggers>
</Configuration>
In my workerApplication.log, I am still getting the debug statements too that are in my code. I only want INFO and above level. I have changed in both places the level of the log but it is not working. Can anyone point out what am I doing wrong? The project is being deployed as an RPM in Linux
You set the loglevel for each logger in log4j2.xml. Since you only have one logger you can change the loglevel for that logger to only get logging for level info and higher.
Please change
<Root level="debug" additivity="false">
<AppenderRef ref="RollingFile" />
</Root>
to
<Root level="info" additivity="false">
<AppenderRef ref="RollingFile" />
</Root>

Log4j set a different logging level for each appender

I'm using Log4j 2 to log the events of my application. However I'm stuck at the following problem.
Currently all logging messages are being written to two different appenders. One has RollingFile type, while the other has Console type.
What I want is for the RollingFile appender to log messages with an INFO level or higher (ERROR, FATAL), and for the Console appender to log messages with an ERROR level or higher (FATAL).
Inside my log4j2.xml file I seem to be only able to declare the logging level for an entire logger (including all of its appenders). Here is my log4j2.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration monitorInterval="30">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout>
<Pattern>%d %level %msg%n</Pattern>
</PatternLayout>
</Console>
<RollingFile name="Log" fileName="log/Log.log" filePattern="log/Log-%d{yyyy-MM-dd}-%i.log" append="false">
<PatternLayout>
<Pattern>%d %level %msg%n</Pattern>
</PatternLayout>
<Policies>
<SizeBasedTriggeringPolicy size="1 MB" />
</Policies>
<DefaultRolloverStrategy max="10"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console" />
<AppenderRef ref="Log" />
</Root>
</Loggers>
</Configuration>
Is there an easy way of doing so? I searched log4j documentation but couldn't find what I was looking for (Maybe I missed it?). If it's possible I would really prefer for the solution to be applicable on any appenders' types; not specific for RollingFile and Console.
EDIT:
I saw many questions where it was asked to write ONLY the messages from a certain level to a file, while writing the messages from a different level to a different file. In my case I need the messages with a certain level of HIGHER to be written to different files. For example in the case I provided messages with level ERROR or FATAL will be written to both the RollingFile and Console, while messages with level INFO will be written to RollingFile only.
To limit logging level on specific appender in log4j2 you should use ThresholdFilter element of an appender.
In your case log4j2.xml file will look like:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration monitorInterval="30">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout>
<Pattern>%d %level %msg%n</Pattern>
</PatternLayout>
</Console>
<RollingFile name="Log" fileName="log/Log.log" filePattern="log/Log-%d{yyyy-MM-dd}-%i.log" append="false">
<ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout>
<Pattern>%d %level %msg%n</Pattern>
</PatternLayout>
<Policies>
<SizeBasedTriggeringPolicy size="1 MB" />
</Policies>
<DefaultRolloverStrategy max="10"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console" />
<AppenderRef ref="Log" />
</Root>
</Loggers>
</Configuration>
Here is a simple test:
public class Log4jTest {
private static final Logger logger = LogManager.getLogger(Log4jTest.class);
public static void main(String[] args) {
logger.debug("Debug");
logger.info("Info");
logger.warn("Warning");
logger.error("Error");
logger.fatal("Fatal");
}
}
Console output:
2020-02-25 12:33:50,587 ERROR Error
2020-02-25 12:33:50,589 FATAL Fatal
Log.log contents:
2020-02-25 12:33:50,585 INFO Info
2020-02-25 12:33:50,587 WARN Warning
2020-02-25 12:33:50,587 ERROR Error
2020-02-25 12:33:50,589 FATAL Fatal
In first version of log4j it was Threshold property of appender. On how to solve the same in log4j see the answer on question.
With aid of filters Log4j2 allows to configure the output to a specific appender much more flexible then log4j.
This should do the trick.
<Loggers>
<Root level="debug" additivity="false">
<AppenderRef ref="Console"/>
</Root>
<Logger name="com.project.package" level="info" additivity="false">
<AppenderRef ref="Log" />
</Logger>
</Loggers>
Alternatively, you could do it like this - Different level of logs in different log files
BTW, this is explained very nicely in the Log4j2 documentation. See - https://logging.apache.org/log4j/2.x/manual/configuration.html

How to use JMSAppender log4j2 JAVA

I'm trying to push logs to an ActiveMqueue using JMS in log4j2.
I have done this in my log4j2.properites
<?xml version="1.0" encoding="UTF-8"?>
<Configuration monitorInterval="5">
<Appenders>
<RollingFile name="fishLogstash"
fileName="E:/xxx/log/xxx.server/xxxLogstash.log" append="false"
immediateFlush="false" bufferSize="1000"
filePattern="/soft/log/xxx.server/xxxx-%i.log">
<PatternLayout pattern="%-d{yyyy-MM-dd HH:mm:ss.SSS} %5p %c{1} - %m%n" />
<Policies>
<SizeBasedTriggeringPolicy size="100M" />
</Policies>
<DefaultRolloverStrategy max="10" />
</RollingFile>
<JMS name="jmsQueue" destinationBindingName="logQueue"
factoryName="org.apache.activemq.jndi.ActiveMQInitialContextFactory"
factoryBindingName="ConnectionFactory"
providerURL="tcp://localhost:61616">
<PatternLayout pattern="%-d{yyyy-MM-dd HH:mm:ss.SSS} %5p %c{1} - %m%n" />
</JMS>
</Appenders>
<Loggers>
<Root level="warn">
<AppenderRef ref="fish" />
</Root>
</Loggers>
</Configuration>
After this, I wonder how to use the JMS appender to log in my java code? How to retrieve this specific appender, is there somthing like
Logger log = Logger.getAppender("jmsQueue") ?
Thanks in advance.
1.
In your property file, there are xml content. So I am assuming you are trying to use xml style property file. If so, rename your property file to have .xml extension. E.g. log4j2.xml. Remember to write log4j2 supported xml. Examples can be found here.
2.
Mention name value of your defined appenders as AppenderRef in Loggers section of property file. Based on your Appenders section, Loggers section can be
<Loggers>
<Logger name="jmsLogger" level="warn">
<AppenderRef ref="jmsQueue" />
</Logger>
<Root level="warn">
<AppenderRef ref="fishLogstash" />
</Root>
</Loggers>
3.
In your code, get JMS logger as follows:
Logger log = LogManager.getLogger("jmsLogger");
You can log whatever by using log variable. E.g.
log.info("some message");
Hope, this answer would help you.

Categories

Resources