Change PDFBox logging level using logback - spring-boot

I have a java app that is running on spring boot.
I'm using tika which in turn uses pdfbox.
I'm using logback as my logging implementation with slf4j.
I know that pdfbox uses apache commons logging.
I'm trying to disable the change the logging level to FATAL like so
<logger name="org.apache.pdfbox" level="FATAL"/>
The problem is that it still doesn't change the level.
I've run this with a debugger. I'm inspecting the logger that pdfbox uses and the results are
result = SLF4JLocationAwareLog
name = org.apache.pdfbox.util.PDFStreamEngine
logger.level = null
logger.loggerContext = ch.qos.logback.classic.LoggerContext[default]
By logger context, I understand that it is indeed using logback, but the configs are not present.

I'll answer my own question and hope that someone will find it useful.
The reason that the logger.level was null is because I didn't specify anything, so it got it from the parent logger. The FATAL didn't work because the highest level is not FATAL but ERROR.
http://logback.qos.ch/apidocs/ch/qos/logback/classic/Level.html
When I changed it to error everything worked as expected.

Related

log4j2 the logger get by Slf4j LoggerFactory.getILoggerFactory can only read default log4j.xml without profile

Use log4j2 in SpringBoot project with test profile,
org.slf4j.LoggerFactory.getLogger("xxx") can get test profile LoggerContext and read configuration from log4j2-test.xml.
But
org.slf4j.LoggerFactory.getILoggerFactory().getLogger("xxx") can only get current LoggerContext and read configuration from log4j2.xml.
LoggerFactory.getLogger("xxx"); // log4j2-test.xml
LoggerFactory.getILoggerFactory().getLogger("xxx"); // log4j2.xml
Is it a bug of log4j2?
I tested LoggerFactory.getILoggerFactory().getLogger("xxx") with Logback, Logback can choose log4j2-test.xml properly.
SpringBoot version: 2.4.5
Add some background to help more people: ParSeq framework prints logs by LoggerFactory.getILoggerFactory().getLogger("xxx").
No, this would not be a bug in Log4j. Log4j knows nothing about Spring profiles and does not incorporate them in its logic of locating a configuration file.
The methods in LoggerFactory that you are calling are static. That means they are implemented by SLF4J. The SLF4J source shows that getLogger("XXX") does
public static Logger getLogger(String name) {
ILoggerFactory iLoggerFactory = getILoggerFactory();
return iLoggerFactory.getLogger(name);
}
which is exactly the same as what you are manually doing in your second call, so I cannot see how there could be any difference between them.
I also doubt that Logback can choose log4j2-test.xml properly since that would be an invalid configuration file for Logback.
It should be a bug of log4j2:
JIRA_LOG4J2-3083

How to use Spring environment values from config server in Logstash Encoder of Logback

I would like to use Spring environment values as custom fields in the Logstash encoder of a Logback appender.
There is a general configuration tag to use properties
<property resource="logstash.properties" />
And there is a special configuration tag from Spring for this purpose
<springProperty name="appEnv" source="environment"/>
The properties of both tags can then be used in the custom fields of the Logstash encoder
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<customFields>{"application.environment":"${appEnv}"</customFields>
</encoder>
Problem is, as far as I understand, that this only works under certain circumstances. The problem is probably that Logback has already finished configuring when the Spring environment is built.
It seems to work when
The property is local and static (available on configuration time)
The property is in bootstrap.properties
It seems NOT to work when
The property is dynamic as when retrieved from Spring config server
My property values delivered from config server are null when Logback is configured and therefore the log shows them as appEnv_IS_UNDEFINED for a property called appEnv.
Because most examples just use the spring.application.name this seems to be mostly unnoticed.
To solve the timing problem, I searched for a way to reload the Logback configuration onApplicationEvent. I found this answer that confirms my problem and offers a skeleton solution.
I found other solutions where the Logback appender that uses the Logstash encoder is completely programmatically built and added to the LoggerContext.
However, I wonder if there is also a way to stick with the XML configuration of the appender and "just reload" the config programmatically when the Spring environment is ready. How would I do this?
I found this answer to do the reload, but it does not work for my case. The appEnv_IS_UNDEFINED continue to appear in the log file.
I was able to solve my problem by implementing a Spring ApplicationContextInitializer.
In the called initialize method I can access my Logback Appender and Encoder via RootLogger.
Logger rootLogger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
RollingFileAppender jsonFileAppender = (RollingFileAppender) rootLogger.getAppender(LOGSTASH_APPENDER_NAME);
LogstashEncoder encoder = (LogstashEncoder) jsonFileAppender.getEncoder();
From the LogstashEncoder, I can get the customFields
String customFields = encoder.getCustomFields();
And there I found the unresolved properties in the JSON String as expected
{"application.environment":"appEnv_IS_UNDEFINED"}
Since I can get the built Spring Environment from the passed ApplicationContext
springEnvironment = applicationContext.getEnvironment();
I can match unresolved properties with the Regex (\w+)_IS_UNDEFINED and replace them with the real value from the Spring Environment.
Surprisingly, I do not need to reload or restart anything. It is sufficent to just set the fixed customFields on the Encoder. Immediately after, the Log messages contain the correct values.
encoder.setCustomFields(fixedCustomFields);
With this Initializer in place, I can fully configure my appender and the LogstashEncoder in logback-spring.xml or an included file.

How to change the logging levels in log4j in runtime without restarting jetty server?

Many answers around with option of .setlevel() option,which isn't working in my case because of the below .
Scenario:
log4j.xml file under resources is kept with ERROR mode while jetty startup.
Code:
private static Logger logger = Logger.getLogger(test.class);
private static final boolean DEBUG = logger.isDebugEnabled();
if(DEBUG){ //DEBUG will be false as the logging level is set to ERROR
logger.debug("This should print,but it will not print as DEBUG will be set as false during startup");
}
Thanks in advance for your suggestions .
2 solutions:
1. Correct one
Change your mode to the desired one. You should not change the logging level at runtime like that. On test platforms, your log level should be DEBUG. On production, INFO.
2. Dirty one
see Dynamically add appender with slf4j and log4j2. It should be your latest solution.

Changing application context path leads to using different (unknown) logging configuration

Setup:
Tomcat 6.0.16
Struts 2.1.6
Apache Commons Logging 1.0.4
Log4J 1.2.17
What I did:
Change in server.xml:
<Context path="/" .../></Context>
to
<Context path="/shop" .../></Context>
The issues:
Everything in the application is working fine (on the first glance). All links are correct and working etc.
Now I discovered that the Loggers using Commons Logging (with Log4J) (usually the Loggers in Spring, Struts and OGNL) are using a different logger configuration than the default used before. Loggers using Log4J directly in the application are working fine with this configuration.
For debugging purpose I have a JSP listing all the loggers with:
Logger.getRootLogger().getLoggerRepository( ).getCurrentLoggers()
But the "commons logging logger" are not listed anymore, although I could verify that they exist if I debug the code.
The question:
How do I find the other configuration/root logger?
Do I have to change anything in the struts configuration (or somewhere else) in relation to the context path change?
Any ideas what the issue might be here?
Edit: I'm getting closer:
The platform I am using is loading a minimal logging at start up. Before changing the context the advanced logging was loaded right afterwards and everything was fine. For some reason the listener of the web.xml (Spring initialization, etc.) is now running before the advanced logging is loaded. These classes are using the apache commons logging api and get loggers assigned basing on the simple root logger. Right afterwards the root logger is replace by the platform but the commons loggers are not updated with the new configuration.
New question:
As I stated below, changing anything in the platform is no option. So why did the listener run earlier when I change the context and how can I prevent this.
For the sake of the moment Apache Tomcat uses JDK logging. If you didn't place commons-logging.properties file to your source dir the default logger using commons logging will be log4j. Anyway the Tomcat will not use that logging because it needs a special configuration to tell it to use log4j.
The root logger is what you use in the log4j configuration. For example
log4j.rootLogger=ERROR,Console
Changing context path is nothing related to the logging used by application.
I didn't see any issue with logging rather that in recent releases regarding implementation priority.
The logging creates a dependency between multiple tomcat web application and due this fact requires a specific order of loading this modules. Renaming the context to "/shop" leads to an other order as StandardContext.filterDefs is a simple HashMap and does not preserve the order of the server.xml.
I could fix my issues in running the required steps in a listener.
web.xml
<listener>
<listener-class>com.[...].InitListener</listener-class>
</listener>
InitListener.java
package com.[...];
public class InitListener
{
static
{
// init Log4J, etc.
}
}
{code}
(Btw. Listener order should be identical to the web.xml)

How do I turn debug logging off, in log4j, for docx4j

I receive the following message when I deploy my maven/spring application on jboss as7 and attempt to upload a docx file. The message is displayed within the body of the uploaded file when I view it in the app's WYSIWIG editor. The message does not display when I run the app locally on jetty. I included the log4j and docx4j property files. I'm not sure what property would allow me to toggle the debug logging for the docx4j class mentioned in the error and so far I've come up empty on web searches. BTW, my app is not using a log4j/docx4j xml file and from what I've read it's an either or setup. If I should switch to xml, then please let me know and please inform me of which property needs to be adjusted so I can clear this message.
TY
TO HIDE THESE MESSAGES, TURN OFF log4j debug level logging for org.docx4j.convert.out.html.HtmlExporterNG2
log4j.properties
log4j.rootLogger=ERROR,stdout
#Console Appender
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%5p] [%t %d{hh:mm:ss}] (%F:%M:%L) %m%n
#Custom assignments
log4j.logger.Controllers=DEBUG,stdout
log4j.logger.Entities=DEBUG,stdout
log4j.logger.Models=DEBUG,stdout
#Disable additivity
log4j.additivity.Controllers=false
log4j.additivity.Entities=false
log4j.additivity.Models=false
docx4j.properties
# Page size: use a value from org.docx4j.model.structure.PageSizePaper enum
# eg A4, LETTER
docx4j.PageSize=LETTER
# Page size: use a value from org.docx4j.model.structure.MarginsWellKnown enum
docx4j.PageMargins=NORMAL
docx4j.PageOrientationLandscape=false
# Page size: use a value from org.pptx4j.model.SlideSizesWellKnown enum
# eg A4, LETTER
pptx4j.PageSize=LETTER
pptx4j.PageOrientationLandscape=false
# These will be injected into docProps/app.xml
# if App.Write=true
docx4j.App.write=true
docx4j.Application=docx4j
docx4j.AppVersion=2.7
# of the form XX.YYYY where X and Y represent numerical values
# These will be injected into docProps/core.xml
docx4j.dc.write=true
docx4j.dc.creator.value=docx4j
docx4j.dc.lastModifiedBy.value=docx4j
#
#docx4j.McPreprocessor=true
# If you haven't configured log4j yourself
# docx4j will autoconfigure it. Set this to true to disable that
docx4j.Log4j.Configurator.disabled=true
We had a similar issue while using docx4j with Spring Boot.
Since spring-boot-starter-logging auto-configures logback-classic which is used as implementation for loggers, it comes to just setting correct level for package. In our case we didn't need any logging from docx4j therefore adding below line to application.properties disabled whole output from 'docx4j':
logging.level.org.docx4j=OFF
If you specifically need to disable console print of document, then you need to set turn off log level on this particular file:
logging.level.org.docx4j.model.datastorage.migration.VariablePrepare=OFF
EDIT: I know this topic is old but there are very limited sources targeting this topic while using spring boot. I hope this helps someone in future.
I'm not sure how docx4j configures log4j, but you could try changing the docx4j.Log4j.Configurator.disabled=true to false instead.
If that doesn't work you might want to try excluding the servers log4j implementation. You can add a jboss-deployment-structure.xml that excludes log4j.
change the rootCategory Level from DEBUG to OFF in your log4j.properties or log4j.xml file
log4j.rootCategory=OFF, SymbolicNameForAppender
I was able to disable the logging output with the following (using docx4j 2.8.1):
Docx4jProperties.getProperties().setProperty(
"docx4j.Log4j.Configurator.disabled", "true");
Log4jConfigurator.configure();
Note that without the second statement, the logging was not suppressed.
Use following code:
Docx4jProperties.getProperties().setProperty("docx4j.Log4j.Configurator.disabled", "true");
Log4jConfigurator.configure();
org.docx4j.convert.out.pdf.viaXSLFO.Conversion.log.setLevel(Level.OFF);
Use this:
LogManager.getLogger("org.docx4j").setLevel(Level.OFF);

Resources