How to change log4jlogger configure method below to use log4j2 - spring

while ( appenders.hasMoreElements() ) {
final Appender appender = ( Appender ) appenders.nextElement();
if ( appender instanceof FileAppender ) {
Logger.getRootLogger().removeAppender( appender );
final FileAppender fileAppender = ( FileAppender ) appender;
String filePath = fileAppender.getFile();
filePath = logOutputDir + "/" + filePath;
fileAppender.setFile( filePath );
Logger.getRootLogger().addAppender( appender );
} // end if
}

Related

Spring Boot MessageSource retrieves message from localized properties file, even when locale not matching

I've found a strange behavior of my spring boot (2.7.5) application.
I added i18n.
My configuration class (annotated with #Configuration and implements WebMvcConfigurer):
#Bean
public LocaleResolver localeResolver ( ) {
SessionLocaleResolver resolver = new SessionLocaleResolver ( );
resolver.setDefaultLocale ( Locale.GERMAN );
return resolver;
}
#Bean
public LocaleChangeInterceptor localeChangeInterceptor ( ) {
LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor ( );
interceptor.setParamName ( "lang" );
return interceptor;
}
#Bean
public MessageSource messageSource ( ) {
ReloadableResourceBundleMessageSource source = new ReloadableResourceBundleMessageSource ( );
source.setBasename ( "classpath:/lang/messages" );
source.setDefaultEncoding ( "UTF-8" );
source.setCacheSeconds ( 600 );
return source;
}
#Override
public void addInterceptors ( InterceptorRegistry registry ) {
registry.addInterceptor ( localeChangeInterceptor ( ) );
}
Added 3 message.properties files under resources/lang with "lang.test" as reference
messages.properties -> lang.test = test default
messages_en_US.properties -> lang.test = test german
messages_en_DE.properties -> lang.test = test usa
Also I created a test method which iterates over all locales.
public void test ( ) {
String defaultMessage = "NOT FOUND";
for ( Locale locale : Locale.getAvailableLocales ( ) ) {
String testMessage = messenger.getMessage ( "lang.test", null, defaultMessage, locale );
System.out.println ( "test message: " + testMessage + " for locale " + locale );
}
}
I would expect to have just 2 outputs. One for en_US with "test usa" and another with "test german" for de_DE.
But the output looks like:
test message: test german for locale
test message: test german for locale he
test message: test german for locale th_TH_#Thai
test message: test german for locale nds
test message: test german for locale tk_TM_#Latn
test message: test german for locale ti_ET
test message: test german for locale ta_SG
test message: test german for locale lv
test message: test german for locale en_NU
...
Why do I get the output of messages_de_DE.properties for all locales?

Spring thymeleaf template engine cannot find the template file

I'm trying to send an inline email using spring boot and thymeleaf. I have added new template file "test-email.html"
And I have following bean configurations
#Qualifier("emailSender")
#Autowired
private val templateEngine: SpringTemplateEngine? = null
#Bean(name = ["emailSender"])
fun springTemplateEngine(): SpringTemplateEngine? {
val templateEngine = SpringTemplateEngine()
templateEngine.addTemplateResolver(htmlTemplateResolver())
return templateEngine
}
#Bean
fun htmlTemplateResolver(): SpringResourceTemplateResolver? {
val emailTemplateResolver = SpringResourceTemplateResolver()
emailTemplateResolver.prefix = "/templates/email/"
emailTemplateResolver.suffix = ".html"
emailTemplateResolver.templateMode = TemplateMode.HTML
emailTemplateResolver.characterEncoding = StandardCharsets.UTF_8.name()
return emailTemplateResolver
}
Following functions is used to send the resolve template and send email.
fun sendTemplateMessage(to: String, subject: String, text: String) {
val mimeMessage: MimeMessage? = emailSender?.createMimeMessage()
val helper = mimeMessage?.let { MimeMessageHelper(it, "utf-8") }
val context = Context()
context.setVariable("msg", "This is test message")
val htmlMsg = templateEngine!!.process("test-email", context)
helper?.setText(htmlMsg, true)
helper?.setTo(to)
helper?.setSubject(subject)
emailSender?.send(mimeMessage)
}
But this gives a FileNotFound exception.
Caused by: java.io.FileNotFoundException: ReactiveWebContext resource [/templates/email/test-email.html] cannot be opened because it does not exist
How can I provide template file path to the templating engine?
Add classpath: as prefix of your file path. The reason behind is that it will take the relative path from where the jar is deployed otherwise it will consider the given path as an absolute path.
So change your code as below:
#Bean
fun htmlTemplateResolver(): SpringResourceTemplateResolver? {
val emailTemplateResolver = SpringResourceTemplateResolver()
emailTemplateResolver.prefix = "classpath:/templates/email/"
emailTemplateResolver.suffix = ".html"
emailTemplateResolver.templateMode = TemplateMode.HTML
emailTemplateResolver.characterEncoding = StandardCharsets.UTF_8.name()
return emailTemplateResolver
}

Issue Spring Boot Redis Multiple Applications Consuming Data

I have two applications for which I am using Spring Boot and Redis.
From both the applications I am producing data to Redis.
ISSUE The data produced by Spring Boot Redis Application 1 is not available for Redis Application 2 and vice versa.
Redis is running locally.
Application YAML for both the applications is same -
spring:
redis:
host: localhost
port: 6379
Model Class-
#RedisHash(timeToLive = 300,value = "alerts")
#Data
#NoArgsConstructor
#AllArgsConstructor
public class RedisModel {
#Id
private String id;
private String message;
public RedisModel(String message) {
this.message = message;
}
#Override
public String toString() {
return "RedisModel{" +
"id='" + id + '\'' +
", message='" + message + '\'' +
'}';
}
}
Is there some parameters that are missed??
Please let me know in case of any queries.
Spring Boot - 2.2.0 Version.
I think RedisConfiguration created by spring boot will namespace those cache keys with your application name. Therefore they won't be visible to each other. To get around this, you will have to do your own RedisConfiguration and disable the prefix via disableKeyPrefix() and then set your own prefix with computePrefixWith(...). Here is an example:
#Bean
public RedisCacheManager cacheManager( RedisConnectionFactory redisConnectionFactory,
ResourceLoader resourceLoader ) {
RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager
.builder( redisConnectionFactory )
.cacheDefaults( determineConfiguration( resourceLoader.getClassLoader() ) );
List<String> cacheNames = this.cacheProperties.getCacheNames();
if ( !cacheNames.isEmpty() ) {
builder.initialCacheNames( new LinkedHashSet<>( cacheNames ) );
}
return builder.build();
}
private RedisCacheConfiguration determineConfiguration(
ClassLoader classLoader ) {
if ( this.redisCacheConfiguration != null ) {
return this.redisCacheConfiguration;
}
CacheProperties.Redis redisProperties = this.cacheProperties.getRedis();
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
ObjectMapper mapper = new Jackson2ObjectMapperBuilder()
.modulesToInstall( new SimpleModule().addSerializer( new NullValueSerializer( null ) ) )
.failOnEmptyBeans( false )
.build();
mapper.enableDefaultTyping( ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY );
ObjectMapper mapper = new Jackson2ObjectMapperBuilder()
.modulesToInstall( new SimpleModule().addSerializer( new NullValueSerializer( null ) ) )
.failOnEmptyBeans( false )
.build();
mapper.enableDefaultTyping( ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY );
GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer( mapper );
//get the mapper b/c they registered some internal modules
config = config.serializeValuesWith( RedisSerializationContext.SerializationPair.fromSerializer( serializer ) );
if ( redisProperties.getTimeToLive() != null ) {
config = config.entryTtl( redisProperties.getTimeToLive() );
}
if ( redisProperties.getKeyPrefix() != null ) {
config = config.prefixKeysWith( redisProperties.getKeyPrefix() );
}
if ( !redisProperties.isCacheNullValues() ) {
config = config.disableCachingNullValues();
}
if ( !redisProperties.isUseKeyPrefix() ) {
config = config.disableKeyPrefix();
config = config.computePrefixWith( cacheName -> cacheName + "::" );
}
return config;
}
Actually, Redis is not very suitable for such a situation. A better solution would be using Infinispan

Configure RollingFileAppender programatically Not able to write logs to the specific folder using logback in my spring boot application

I have this Loggerutils class which returns me the logger object.
public class Loggerutils {
public static Logger createLoggerFor(String string, String file) {
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
PatternLayoutEncoder ple = new PatternLayoutEncoder();
ple.setPattern("%date %level [%thread] %logger{10} [%file:%line] %msg%n");
ple.setContext(lc);
ple.start();
RollingFileAppender<ILoggingEvent> rollingFileAppender = new RollingFileAppender<ILoggingEvent>();
FixedWindowRollingPolicy rollingPolicy = new FixedWindowRollingPolicy();
rollingPolicy.setFileNamePattern("pilogs.%i.log.zip");
rollingPolicy.setMinIndex(1);
rollingPolicy.setMaxIndex(3);
rollingPolicy.setContext(lc);
rollingFileAppender.setFile(file);
rollingFileAppender.setEncoder(ple);
rollingFileAppender.setContext(lc);
rollingFileAppender.setRollingPolicy(rollingPolicy);
rollingFileAppender.start();
Logger logger = (Logger) LoggerFactory.getLogger(string);
logger.addAppender(rollingFileAppender);
logger.setLevel(Level.ALL);
logger.setAdditive(false); /* set to true if root should log too */
return logger;
}
}
I use below lines of code to instantiate logger
Logger logger = Loggerutils.createLoggerFor("UserController", "UserControllerFile");
logger.info("Inside User controller..........");
and in application.properties I configured
logging.path=E:/LOGS/WebAPI
but in the given location only one file is being created and that is spring.log. My requirement is I want my log files to be created at specified location.
I don't have logback.xml in my resources folder
You should mention the full path of the log file instead of just the filename. Try this
public class Loggerutils {
public static Logger createLoggerFor(String string, String file) {
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
PatternLayoutEncoder ple = new PatternLayoutEncoder();
ple.setPattern("%date %level [%thread] %logger{10} [%file:%line] %msg%n");
ple.setContext(lc);
ple.start();
RollingFileAppender<ILoggingEvent> rollingFileAppender = new RollingFileAppender<ILoggingEvent>();
FixedWindowRollingPolicy rollingPolicy = new FixedWindowRollingPolicy();
rollingPolicy.setFileNamePattern("pilogs.%i.log.zip");
rollingPolicy.setMinIndex(1);
rollingPolicy.setMaxIndex(3);
rollingPolicy.setContext(lc);
rollingPolicy.start();
rollingFileAppender.setFile("E:/LOGS/WebAPI/" + file);
rollingFileAppender.setEncoder(ple);
rollingFileAppender.setContext(lc);
rollingFileAppender.setRollingPolicy(rollingPolicy);
rollingFileAppender.start();
Logger logger = (Logger) LoggerFactory.getLogger(string);
logger.addAppender(rollingFileAppender);
logger.setLevel(Level.ALL);
logger.setAdditive(false); /* set to true if root should log too */
return logger;
}
}
Made some changes to createLoggerFor() method. And now it works.
#Component
public class Loggerutils {
private static String logDirectory;
#Value("${logging.path}")
public void setLogDirectory(String path){
logDirectory = path;
}
public static Logger createLoggerFor(String loggerName, String fileName) {
Logger rootLogger = (Logger) LoggerFactory.getLogger(loggerName);
LoggerContext loggerContext = rootLogger.getLoggerContext();
loggerContext.reset();
RollingFileAppender<ILoggingEvent> rfAppender = new RollingFileAppender<ILoggingEvent>();
rfAppender.setContext(loggerContext);
rfAppender.setFile(logDirectory+loggerName+"\\"+fileName);
FixedWindowRollingPolicy fwRollingPolicy = new FixedWindowRollingPolicy();
fwRollingPolicy.setContext(loggerContext);
fwRollingPolicy.setFileNamePattern(logDirectory+loggerName+"\\"+"pilogs.%i.log.zip");
fwRollingPolicy.setParent(rfAppender);
fwRollingPolicy.start();
SizeBasedTriggeringPolicy<ILoggingEvent> triggeringPolicy = new SizeBasedTriggeringPolicy<ILoggingEvent>();
triggeringPolicy.setMaxFileSize("10MB");
triggeringPolicy.start();
PatternLayoutEncoder encoder = new PatternLayoutEncoder();
encoder.setContext(loggerContext);
encoder.setPattern("%date %level [%thread] %logger{10} [%file:%line] %msg%n");
encoder.start();
rfAppender.setEncoder(encoder);
rfAppender.setRollingPolicy(fwRollingPolicy);
rfAppender.setTriggeringPolicy(triggeringPolicy);
rfAppender.start();
rootLogger.addAppender(rfAppender);
return rootLogger;
}
}
and logging.path in my application.properties is,
logging.path=E:\\LOGS\\WebAPI\\
Hope this will help :)

Different Log4j file paths for each webapp

I'm trying to use different logs for each webapp. I've multiples applications in the same server and I need to load this directory from a properties file.
Each web app loads a property file with this keys/values (X it's the app's name, different for all):
app=APP.X
logPath=C://logs
I have added a log4j.properties file in each webapp project with all parameters that I need except the log's path (log4j.properties)
# Root logger option
log4j.rootLogger=INFO, stdout, file
# Redirect log messages to console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c:%M:%L - %m%n
# Redirect log messages to a log file, support file rolling.
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.encoding=UTF-8
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c:%M:%L - %m%n
#log4j.appender.file.MaxBackupIndex=8
log4j.appender.file.DatePattern='.'yyyy-MM
I have created a Java class in my util jar that implements ApplicationListener and adds the key log4j.appender.file.File (Log4jContextListener.java)
public class Log4jContextListener implements ApplicationListener<ContextStartedEvent>
{
#Value("${rutaLogs}")
private String rutaLogs;
#Value("${app}")
private String app;
private Logger log = Logger.getLogger(getClass());
#Override
public void onApplicationEvent(ContextStartedEvent arg0)
{
Properties props = new Properties();
InputStream strm = null;
try
{
System.out.println("LOADING APP: " + app);
strm = Log4jContextListener.class.getClassLoader().getResourceAsStream("log4j.properties");
props.load(strm);
if (props != null)
log.info("PROP: " + props.getProperty("log4j.appender.file.layout"));
props.put("log4j.appender.file.File", logPath+ app + File.separator + app + ".log");
}
catch (IOException propsLoadIOE)
{
throw new Error("can't load logging config file", propsLoadIOE);
}
finally
{
try
{
strm.close();
}
catch (IOException configCloseIOE)
{
throw new Error("error closing logging config file", configCloseIOE);
}
}
// props.put("webAppRoot", event.getServletContext().getRealPath("/"));
PropertyConfigurator.configure(props);
}
}
And each web app adds a bean with this declaration in the applicationContext.xml
<!-- Listener to initialize LOG4J -->
<bean id="log4jConfigurationListener" class="com.framework.listeners.Log4jContextListener" />
The log's folders and files are creating right but the log traces are mixed, each webapp use only the latest location loaded.
How can I do diferent in each wepapp context?
PD: I have to do it reading from properties, I can't use environment vars.
Hi I manage to set log location per webapp context with the following:
package ...
import org.apache.log4j.Logger;
import org.apache.log4j.lf5.LogLevel;
import org.springframework.web.WebApplicationInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import java.io.InputStream;
import java.util.Properties;
import java.util.TimeZone;
public class SystemPropertyDefaultsInitializer implements WebApplicationInitializer {
private static final Logger LOG = Logger.getLogger(SystemPropertyDefaultsInitializer.class);
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
String warName = new File(servletContext.getRealPath("/")).getName();
InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream("log4j.properties");
Properties properties = PropertiesHelper.loadApplicationProperties(resourceAsStream);
String logLocation = "/var/log/tomcat7/" + warName + ".log";
File file = new File(logLocation);
if (!file.exists()) {
FileOutputStream fos = new FileOutputStream(file);
fos.close();
}
if (!file.canWrite()) {
throw new IOException("Write permission denied for file \"" + logLocation + "\"");
}
LOG.info("Log location set to: \"" + logLocation + "\"");
properties.setProperty("log4j.appender.FILE.File", logLocation);
PropertyConfigurator.configure(properties);
}
}

Resources