Getting a Java 8 application to log to catalina.out with log4j2 - java-8

This is a personal project and I just want this to work.
I have a Java 8 application that is using Log4j 2 and all I want to do is get it to log to one of the general Tomcat 9 logs like catalina.out or localhost or the tomcat stdout log. Nothing I do seems to work.
Log4J is included in the war file, I only need it to work for this one application under Tomcat 9. I do not want to move to another logging library. This is my log4j.properties file.
log4j.rootCategory=debug,console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.target=System.out
log4j.appender.console.immediateFlush=true
log4j.appender.console.encoding=UTF-8
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.conversionPattern=%d [%t] %-5p %c - %m%n
This is an example of how I'm using this in my code:
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
public final class DataController {
private static Logger LOG = LogManager.getLogger(DataController.class);
public void exampleMethod() {
LOG.info("Log something");
}
}
Nothing shows up in any log. Tomcat 9 is a stock install and has a stock logging.properties file. This is NOT a Spring application. It is pure Java Servlets and POJO. For further context, I did originally use a file appender and logged to a custom file. That didn't work either. By the way, although I know some of the terminology, I am a complete noob at Java.

I was using a log4j 1.2 properties file. This sample properties file worked.
status = debug
name = PropertiesConfig
filters = threshold
filter.threshold.type = ThresholdFilter
filter.threshold.level = debug
appenders = console
appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
rootLogger.level = debug
rootLogger.appenderRefs = stdout
rootLogger.appenderRef.stdout.ref = STDOUT

Related

External Log4j.properties in not printing logs - spring boot 2.2.1

Develop a spring boot application in 2.2.1 RELEASE.Everything is working fine except Loging using log4j.properties.
In apoplication.properies, added logging.config as given below
logging.config =${external.config}/log4j.properties.
Pom.xml file,excluded spring-boot-starter-logging and added spring-boot-starter-log4j as given below
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
log4j.properties
log4j.rootLogger=error,Service
# Direct log messages to a log file
log4j.appender.Service=org.apache.log4j.RollingFileAppender
log4j.appender.Service.File=C:/log/Service.log
log4j.appender.Service.MaxFileSize=1MB
log4j.appender.Service.MaxBackupIndex=1
log4j.appender.Service.layout=org.apache.log4j.PatternLayout
log4j.appender.Service.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - [%X{AUDIT_USER}] %m%n
i referred following links in stack
1.Logger not printing with log4j.properties within Spring Boot 1.5.7
2.Spring boot logging with log4.properties file in not working
Edit 1
As Andy Wilkinson comments, i modified log4j.properties file content and file name, file name should be log4j2.properties.
I tried to log some string to log file as given below
public class ServiceMain {
private static final Logger logger = LogManager.getLogger(ServiceMain.class);
public static void main(String[] args) {
SpringApplication.run(ServiceMain.class, args);
logger.debug("----------------------Stating spring booot----------------------");
}
}
debug log "----------------------Stating spring booot----------------------" wont write to c:/log/service.log
Log file
2019-11-22 05:20:14,631 INFO o.s.b.StartupInfoLogger [main] Starting ServiceMain v7.0.0.0 on host-4 with PID 119176 (D:\Service\target\Service-1.0.jar started by Administrator in D:\Service\target)
2019-11-22 05:20:14,634 DEBUG o.s.b.StartupInfoLogger [main] Running with Spring Boot v2.2.1.RELEASE, Spring v5.2.1.RELEASE
2019-11-22 05:20:14,635 INFO o.s.b.SpringApplication [main] The following profiles are active: Service
2019-11-22 05:20:24,898 INFO o.s.b.StartupInfoLogger [main] Started ServiceMain in 12.312 seconds (JVM running for 14.189)
Did i miss any log4j2.properties configuration?
You are using Log4j 2 (which you should be as version 1 is no longer supported) but appear to be configuring it using a Log4j 1 configuration file.
You can learn more about Log4j 2’s configuration properties in its documentation. It includes this example:
status = error
dest = err
name = PropertiesConfig
property.filename = target/rolling/rollingtest.log
filter.threshold.type = ThresholdFilter
filter.threshold.level = debug
appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %m%n
appender.console.filter.threshold.type = ThresholdFilter
appender.console.filter.threshold.level = error
appender.rolling.type = RollingFile
appender.rolling.name = RollingFile
appender.rolling.fileName = ${filename}
appender.rolling.filePattern = target/rolling2/test1-%d{MM-dd-yy-HH-mm-ss}-%i.log.gz
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.pattern = %d %p %C{1.} [%t] %m%n
appender.rolling.policies.type = Policies
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.rolling.policies.time.interval = 2
appender.rolling.policies.time.modulate = true
appender.rolling.policies.size.type = SizeBasedTriggeringPolicy
appender.rolling.policies.size.size=100MB
appender.rolling.strategy.type = DefaultRolloverStrategy
appender.rolling.strategy.max = 5
logger.rolling.name = com.example.my.app
logger.rolling.level = debug
logger.rolling.additivity = false
logger.rolling.appenderRef.rolling.ref = RollingFile
rootLogger.level = info
rootLogger.appenderRef.stdout.ref = STDOUT

Spring boot application with embedded tomcat, send access logs to syslog

I have a spring boot application, which runs on AWS EC2 instances.
The deployable is just a jar that has tomcat embedded in it.
I am trying to get the application to send its access log to syslog so that I can use AWS CloudWatch to collect logs from different EC2 instances.
I have tried https://logback.qos.ch/access.html, but it does not work with syslog due to this issue: https://jira.qos.ch/browse/LOGBACK-317
Then I tried CommonsRequestLoggingFilter, this does not seem to send its logs to syslog.
I guess trying to send logs to syslog with Spring boot application is not a rare desire.
Is there any comprehensive way to do this?
I just implemented this in my application. (For Spring boot 1.5.6)
Make sure your tomcat access logging is on, below is the way access logging is enabled in application.yml -
server:
tomcat:
accesslog:
enabled: true
pattern: "<APPNAME> %h %l %u %t \"%r\" %s %b %D"
prefix: "localhost_access_log"
suffix: .txt
basedir: /opt/tomcat
The above will output the access logs in your instances.
Now have your logging defined. For example in application.yml file
logging:
level:
org.springframework.web: INFO
com.project.path : DEBUG
config: <path to your config xxml>/logback-springboot.xml
The above will get your logback config file from the desired location.
Now, in your code, you need to define your own tomcat access config. For example -
#Configuration
public class AccessValveConfig extends WebMvcConfigurerAdapter implements
EmbeddedServletContainerCustomizer {
private static XLogger logger = XLoggerFactory
.getXLogger(AccessValveConfig.class);
#Override
public void customize(ConfigurableEmbeddedServletContainer container) {
if (container instanceof TomcatEmbeddedServletContainerFactory) {
TomcatEmbeddedServletContainerFactory factory =
(TomcatEmbeddedServletContainerFactory) container;
AbstractAccessLogValve accessLogValve = new ApiAccessLogValve();
accessLogValve.setPattern("common");
factory.addContextValves(accessLogValve);
} else {
logger.error("WARNING! this customizer does not support your
configured container");
}
}
}
public class ApiAccessLogValve extends AbstractAccessLogValve {
private static XLogger logger = XLoggerFactory
.getXLogger(ApiAccessLogValve.class);
public ApiAccessLogValve(){
super();
}
#Override
protected void log(CharArrayWriter message) {
synchronized (this) {
logger.info(message.toString());
}
}
}
Now make the necessary configs in your logback xml.
<!--This will print app logs in user facility-->
<appender name="SYSLOG" class="ch.qos.logback.classic.net.SyslogAppender">
<syslogHost><<your host name>></syslogHost>
<port>514</port>
<facility>USER</facility>
<suffixPattern><<your pattern>></suffixPattern>
</appender>
<!-- This will print your access logs in local0 facility-->
<appender name="LOCAL0" class="ch.qos.logback.classic.net.SyslogAppender">
<syslogHost><<your host name>></syslogHost>
<port>514</port>
<facility>LOCAL0</facility>
<suffixPattern><<pattern>></suffixPattern>
</appender>
<Logger name="package path to ApiAccessLogValve" level="INFO"
additivity="false">
<appender-ref ref="LOCAL0" />
</Logger>
Now you are all set.

How to get Environment properties from application.properties into logback.groovy in Spring Boot project?

Trying to inject properties defined in application.properties/application.yml into logback.groovy script in Spring Boot project.
I cannot Inject Environment or ApplicationContext into groovy scripts.
Are there any workarounds?
I am not looking for solutions like System.getProperty('spring.profiles.active')
src/main/resources/logback.groovy
import org.springframework.core.env.Environment
#Inject private Environment env; //this is not working. how to get env here?
println "spring.profiles.active : ${env.getProperty('spring.profiles.active')}"
appender("STDOUT", ConsoleAppender) {
encoder(PatternLayoutEncoder) {
pattern = "%green(%d{HH:mm:ss.SSS}) [%thread] %highlight(%-5level) %cyan(%logger{36}) - %msg%n"
}
}
if(System.getProperty("spring.profiles.active")?.equalsIgnoreCase("prod")) {
root INFO, ["STDOUT", "FILE"]
} else {
root INFO, ["STDOUT"]
}
src/main/resources/application.yml
---
spring:
profiles:
active: development
logback.groovy needs to be evaluated very early because otherwise the code for loading the spring configuration, instantiating beans, etc. could not log anything. That's why #Inject can't work.
I see 2 options:
You could easily load application.properties in logback.groovy, but it's far from trivial to take all the configuration override mechanisms that spring provides into account
Create a spring bean that changes the logback configuration programmaticaly
when initialized
A different approach is to externalize the logback configuration on production with -Dlogback.configurationFile=/path/to/config.groovy. Putting the config file in a well known location (like /etc/my-app) makes it easy to change log levels in production without re-deploying (or even re-starting).
Sorry to resurrect this thread but while since this is thread is what I found while looking for a solution, I wanted to share a workaround.
I have used a Custom converter and conversion rule to pull out properties in classpath resource (i.e. application.properties):
In logback.groovy:
conversionRule('springApplicationName', CustomSpringApplicationNameConverter)
def patternExpression = '%green([%d{YYYY-MM-dd HH:mm:ss.SSS}]) [%t] %highlight(%-5level) %magenta([%springApplicationName]) - %cyan(%logger{36}) -- %msg%n'
and then 'patternExpression' used in desired appender
and my custom converter class (in groovy):
class CustomSpringApplicationNameConverter extends ClassicConverter {
#Override
String convert(ILoggingEvent event) {
ClassPathResource classPathResource = new ClassPathResource('application.properties')
Properties applicationProperties = new Properties()
applicationProperties.load(classPathResource.inputStream)
String springApplicationName = applicationProperties.getProperty('spring.application.name')
if (!springApplicationName) {
System.err.println('Could not find entry for \'spring.application.name\' in \'application.properties\'')
}
springApplicationName
}
}

Spring 4, JPA, Turn off console debug messages

I have a basic Spring 4 JPA application. I use all Java configurations (no XML at all). I want to turn off the console debug messages. I have seen many questions on this and tried the solutions but still I see all the messages.
The console messages look like this:
14:58:29.301 [main] DEBUG o.h.loader.entity.plan.EntityLoader....
14:58:29.328 [main] INFO o.h.tool.hbm2ddl.SchemaUpdate....
....
14:58:29.905 [main] DEBUG o.h.h.i.ast.QueryTranslatorImpl - --- HQL AST ---
\-[QUERY] Node: 'query'
\-[SELECT_FROM] Node: 'SELECT_FROM'
+-[FROM] Node: 'from'
| \-[RANGE] Node: 'RANGE'
| +-[DOT] Node: '.'
| | +-[IDENT] Node: 'hello'
| | \-[IDENT] Node: 'Customer'
| \-[ALIAS] Node: 'generatedAlias0'
\-[SELECT] Node: 'select'
\-[IDENT] Node: 'generatedAlias0'
....
Hundreds of lines more....
I tried to set show_sql both in the HibernateJpaVendorAdapter and in the LocalContainerEntityManagerFactoryBean as shown below:
#Bean
public EntityManagerFactory entityManagerFactory() throws SQLException {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
vendorAdapter.setShowSql(false);
LocalContainerEntityManagerFactoryBean factory = new
LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("hello");
factory.setDataSource(dataSource());
Properties jpaProperties = new Properties();
jpaProperties.put( "hibernate.dialect", "org.hibernate.dialect.MySQLDialect" );
jpaProperties.put( "hibernate.show_sql", false );
jpaProperties.put( "show_sql", false );
jpaProperties.put( "hibernate.generate_statistics", false );
factory.setJpaProperties(jpaProperties);
factory.afterPropertiesSet();
return factory.getObject();
}
Thank you for any ideas on this!
-- Edit -- more info
What I do is create a Spring Starter Project with Spring Tools Suite and just select JPA. I then add MySQL to my pom.xml.
As a test I have a basic Customer and CustomerRepository class and the JPA configuration I noted above.
My Application class:
#Configuration
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
AbstractApplicationContext context = new
AnnotationConfigApplicationContext(JPAConfiguration.class);
CustomerRepository repository = context.getBean(CustomerRepository.class);
//use the repository.....
((AbstractApplicationContext) context).close();
context.close();
}
}
So that is it -- a very basic JPA Spring Starter Project created with Spring Tools Suite. If I could figure out how to deal with logging in that I could translate that info to my actual project.
-- Edit -- even more info -- and it's fixed!
OK this is interesting...
I changed my Application class and the problem goes away.
So using the this Application (vs. the one posted above) and the logging problem is now OK -- anyone who could comment why this works like this?
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context =
SpringApplication.run(Application.class);
CustomerRepository repository = context.getBean(CustomerRepository.class);
//use the repository.....
context.close();
}
}
Note the solution provided below by Alan Hay also works great regardless of how I do the Application class!
Note with either way you can still set setJpaProperties as shown my configuration (see Bean above) to control if you want to see Hibernate's SQL, etc.
I encountered the same issue recently. It appears Spring 4 uses the logback library for logging and my app only had a log4j config file. Adding an additional logging configuration file for logback solved the issue.
If you have an existing log4j config file there is a tool to convert this to logback format here:
http://logback.qos.ch/translator/
If not try adding a file named logback.xml to the root of your classpath:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="A1" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{dd MMM yyyy HH:mm:ss} %-4r [%t] %-5p %c %x - %m%n</pattern>
</encoder>
</appender>
<logger name="org.springframework" level="ERROR"/>
<logger name="org.hibernate" level="ERROR"/>
<root level="DEBUG">
<appender-ref ref="A1"/>
</root>
</configuration>

Log4j 1.2 is not logging into RollingFileAppender

I have a problem with Log4J (version 1.2.17) configuration .properties file in my Spring (3.2.5) standalone application.
This is my configuration file, logging to a consoles works fine but RollingFileAppender doesn't append messages into logs/application_log.file. I have tried to change almost everything - file name, ConversionPattern, create the file manually and set filesystem rights (OS X Mavericks) for writing to all but nothing works.
log4j.rootLogger=INFO,CA,FA
#Console Appender
log4j.appender.CA=org.apache.log4j.ConsoleAppender
log4j.appender.CA.layout=org.apache.log4j.PatternLayout
log4j.appender.CA.layout.ConversionPattern=%d{ISO8601} %-5p [%c:%L] - %m%n
#Rolling File Appender
log4j.appender.FA=org.apache.log4j.RollingFileAppender
log4j.appender.FA.File=logs/application_log.log
log4j.appender.FA.MaxFileSize=50MB
log4j.appender.FA.layout.ConversionPattern=%d{ISO8601} %-5p [%c:%L] - %m%n
log4j.appender.FA.Append=true
log4j.appender.FA.MaxBackupIndex=10
log4j.appender.FA.layout=org.apache.log4j.PatternLayout
What am I doing wrong? Do you see something wrong what I don't see?
It looks like you're using wrong class for your appender. You should use org.apache.log4j.DailyRollingFileAppender (you're missing word Daily).
But personally I prefer using log4j.xml instead of log4j.properties. For example:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration debug="true" xmlns:log4j='http://jakarta.apache.org/log4j/'>
<appender name="log-app" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="C:/Temp/my-log.log"/>
<param name="DatePattern" value="'.'yyyy-MM-dd"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n"/>
</layout>
</appender>
<root>
<level value="debug"/>
<appender-ref ref="log-app"/>
</root>
</log4j:configuration>
jUnit test:
import org.apache.log4j.Logger;
import org.junit.Test;
public class FakeTest {
private final static Logger log = Logger.getLogger(FakeTest.class);
#Test
public void testTestMe() throws Exception {
log.debug("Debug message");
log.error("Error message");
}
}
Result in my-app.log:
2013-12-20 09:40:40,589 [main] DEBUG my.package.FakeTest - Debug message
2013-12-20 09:40:40,589 [main] ERROR my.package.FakeTest - Error message

Resources