All logs are not going to file when file logging enabled - java

I am trying to configure log4j2 programmatically and i am facing issue with logs coming from my cluster.
Here is the case, when user enable file logging (by passing log path as parameter in this case) all logs should go to File, no console logs. When use disable file logging, all logging should go to console. So I am trying in this:
public static void initializeLogging(
boolean vNewVerboseDebugLogging, String vLoggingPath, String vNewWarehouseQueriesLogPath,
boolean vNoConsoleLogging, boolean vIsEmbeddedHive, boolean isTestSubmission, boolean YarnLogs, boolean debugLogs) throws IOException
{
String[] packageGrp = {"org.apache","hive.ql","com.cdcb.cstone"};// this i am using to turn off logging from other packages/classes
if(vLoggingPath!=null) {
ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
RootLoggerComponentBuilder rootLogger = builder.newRootLogger(debugLogs?Level.DEBUG:Level.INFO).addAttribute("additivity", true);
LayoutComponentBuilder layoutComponentBuilder = builder.newLayout("PatternLayout").addAttribute("pattern",
(isTestSubmission)?"%-5p [%t]: %m%n":"%d %-5p [%t]: %m%n");
AppenderComponentBuilder fileAppenderBuilder;
fileAppenderBuilder = builder.newAppender("LogToRollingFile", "RollingFile")
.addAttribute("fileName", vLoggingPath)
.addAttribute("filePattern", vLoggingPath + "-%d{MM-dd-yy-HH}.log")
.add(layoutComponentBuilder)
.addComponent(builder.newComponent("Policies")
.addComponent(builder.newComponent("TimeBasedTriggeringPolicy").addAttribute("interval", "1")));
/*builder.newLogger("com.cdcb.idn.HadoopCluster", (vVerboseDebugLogging)?Level.DEBUG:Level.INFO)
.add(builder.newAppenderRef("LogToRollingFile"))
.addAttribute("additivity", false);*/
for(String packNm: packageGrp)
addNewLoggerComponent(builder,packNm,builder.newAppenderRef("LogToRollingFile"),Level.OFF);
builder.add(fileAppenderBuilder);
rootLogger.add(builder.newAppenderRef("LogToRollingFile"));
builder.add(rootLogger);
Configurator.initialize(builder.build()).updateLoggers();
} else {
ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
RootLoggerComponentBuilder rootLogger = builder.newRootLogger(debugLogs?Level.DEBUG:Level.INFO);
LayoutComponentBuilder layoutComponentBuilder = builder.newLayout("PatternLayout").addAttribute("pattern",
(isTestSubmission)?"%-5p [%t]: %m%n":"%d %-5p [%t]: %m%n");
AppenderComponentBuilder vConsoleInfo;
AppenderComponentBuilder vConsoleProblems;
if (!vIsEmbeddedHive){
vConsoleProblems = builder.newAppender("consoleProb", "CONSOLE")
.addAttribute("target", ConsoleAppender.Target.SYSTEM_ERR)
.add(layoutComponentBuilder);
builder.newLogger("com.cdcb.idn.HadoopCluster", (vVerboseDebugLogging)?Level.DEBUG:Level.INFO)
.add(builder.newAppenderRef("consoleProb"))
.addAttribute("additivity", false);
for(String packNm: packageGrp)
addNewLoggerComponent(builder,packNm,builder.newAppenderRef("consoleProb"),Level.OFF);
builder.add(vConsoleProblems);
rootLogger.add(builder.newAppenderRef("consoleProb"));
builder.add(rootLogger);
}
vConsoleInfo = builder.newAppender("consoleInfo", "CONSOLE")
.addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT)
.add(layoutComponentBuilder);
/*builder.newLogger("com.cdcb.idn.HadoopCluster", (vVerboseDebugLogging)?Level.DEBUG:Level.INFO)
.add(builder.newAppenderRef("consoleInfo"))
.addAttribute("additivity", false);*/
for(String packNm: packageGrp)
addNewLoggerComponent(builder,packNm,builder.newAppenderRef("consoleInfo"),Level.OFF);
builder.add(vConsoleInfo);
rootLogger.add(builder.newAppenderRef("consoleInfo"));
builder.add(rootLogger);
Configurator.initialize(builder.build()).updateLoggers();
}
LOGGER = LogManager.getLogger(HadoopClusterLogging.class);
}
public static ConfigurationBuilder addNewLoggerComponent(ConfigurationBuilder builder, String name, AppenderRefComponentBuilder appenderReferences, Level level) {
return builder.add(builder.newLogger(name, level)
.add(appenderReferences)
.addAttribute("additivity", false));
}
but the issue here is, when file logging enabled, not all logs going to File, some going to console(for example, logs coming from hadoop cluster). What am i doing wrong here and how can i capture all logs to file when file logging enabled? can come one please help?
One more thing is, how can i disable transitive dependencies logging. Meaning, my logger should log my application logs only, not from from my dependencies.
Thank you!

Related

How to configure SmtpAppender programmatically in log4j2

Following is the code, I am working on :
Purpose is to configure SmtpAppender programmatically. Along with the SmtpAppender, I also need to add RollingFileAppender as well as Console appender programmatically.
package vish;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.appender.SmtpAppender;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
import org.apache.logging.log4j.core.config.builder.api.LayoutComponentBuilder;
import org.apache.logging.log4j.core.config.builder.api.RootLoggerComponentBuilder;
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
public class SmtpAppenderBuilder {
public static void main(String[] args) {
String pattern = "%d{MM-dd#HH\\:mm\\:ss}%-4r %-5p [%t] %37c %3x - %m%n";
ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
LayoutComponentBuilder layoutBuilder = builder.newLayout("PatternLayout").addAttribute("pattern", pattern);
RootLoggerComponentBuilder rootLogger = builder.newRootLogger(Level.DEBUG);
builder.setStatusLevel(Level.DEBUG);
org.apache.logging.log4j.core.appender.SmtpAppender.Builder smtpBuilder = SmtpAppender.newBuilder();
smtpBuilder.setName("emailAppender");
smtpBuilder.setSmtpUsername("test1#gmail.com");
smtpBuilder.setSmtpPassword("###YpSv1925");
smtpBuilder.setSmtpProtocol("https");
smtpBuilder.setSmtpHost("smtp.gmail.com");
smtpBuilder.setBufferSize(512);
smtpBuilder.setTo("test2#gmail.com");
smtpBuilder.setSubject("testing");
}
}
How should I add the smtpAppender to the configutation or the rootLogger ?
You are mixing up two APIs:
the ConfigurationBuilder API, which is the closest code equivalent to the configuration files. It only creates definitions of the actual logging components, the real ones are created when Configuration#initialize() is called on the configuration object. You can create the definition of an SMTPAppender like this:
private Configuration createConfig() {
ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder()//
.setStatusLevel(Level.DEBUG);
LayoutComponentBuilder layoutBuilder = builder.newLayout("PatternLayout")//
.addAttribute("pattern", "%d{MM-dd#HH\\:mm\\:ss}%-4r %-5p [%t] %37c %3x - %m%n");
AppenderComponentBuilder appenderBuilder = builder.newAppender("emailAppender", "SMTP")//
.addAttribute("smtpUsername", "test1#gmail.com")
.addAttribute("smtpPassword", "###YpSv1925")
.addAttribute("smtpProtocol", "smtps")
.addAttribute("smtpHost", "smtp.gmail.com")
.addAttribute("to", "test2#gmail.com")
.addAttribute("subject", "testing")
.add(layoutBuilder);
AppenderRefComponentBuilder appenderRefBuilder = builder.newAppenderRef("emailAppender");
RootLoggerComponentBuilder rootLoggerBuilder = builder.newRootLogger(Level.DEBUG)//
.add(appenderRefBuilder);
return builder.add(appenderBuilder)//
.add(rootLoggerBuilder)
.build();
}
the actual builders of Log4j 2.x components, which are called by reflection by Configuration#initialize using the definitions above. You can also use them directly:
private static Configuration createConfig2() {
return new AbstractConfiguration(null, ConfigurationSource.NULL_SOURCE) {
#Override
protected void doConfigure() {
Layout<String> layout = PatternLayout.newBuilder()//
.withPattern("%d{MM-dd#HH\\:mm\\:ss}%-4r %-5p [%t] %37c %3x - %m%n")
.withConfiguration(this)
.build();
Appender appender = SmtpAppender.newBuilder()//
.setName("emailAppender")
.setSmtpUsername("test1#gmail.com")
.setSmtpPassword("###YpSv1925")
.setSmtpProtocol("smtps")
.setTo("test2#gmail.com")
.setSubject("testing")
.setLayout(layout)
.setConfiguration(this)
.build();
LoggerConfig rootLogger = getRootLogger();
rootLogger.setLevel(Level.DEBUG);
rootLogger.addAppender(appender, null, null);
}
};
}
Both Configurations are equivalent and you can apply them on the current context with:
Configurator.reconfigure(config);
However they will be lost upon Configurator.reconfigure(), unless you define your own ConfigurationFactory.

How to read property from application.properties when using ConfigurationFactory (Log4j's Programmatic Configuration)?

I am using programmatic configuration for log4j as shown in the following link: http://logging.apache.org/log4j/2.x/manual/customconfig.html.
#Plugin(name = "CustomConfigurationFactory", category = ConfigurationFactory.CATEGORY)
#Order(50)
public class CustomConfigurationFactory extends ConfigurationFactory {
static Configuration createConfiguration(final String name, ConfigurationBuilder<BuiltConfiguration> builder) {
builder.setConfigurationName(name);
builder.setStatusLevel(Level.ERROR);
builder.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.NEUTRAL).
addAttribute("level", Level.DEBUG));
AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE").
addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
appenderBuilder.add(builder.newLayout("PatternLayout").
addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable"));
appenderBuilder.add(builder.newFilter("MarkerFilter", Filter.Result.DENY,
Filter.Result.NEUTRAL).addAttribute("marker", "FLOW"));
builder.add(appenderBuilder);
builder.add(builder.newLogger("org.apache.logging.log4j", Level.DEBUG).
add(builder.newAppenderRef("Stdout")).
addAttribute("additivity", false));
builder.add(builder.newRootLogger(Level.ERROR).add(builder.newAppenderRef("Stdout")));
return builder.build();
}
#Override
public Configuration getConfiguration(final LoggerContext loggerContext, final ConfigurationSource source) {
return getConfiguration(loggerContext, source.toString(), null);
}
#Override
public Configuration getConfiguration(final LoggerContext loggerContext, final String name, final URI configLocation) {
ConfigurationBuilder<BuiltConfiguration> builder = newConfigurationBuilder();
return createConfiguration(name, builder);
}
#Override
protected String[] getSupportedTypes() {
return new String[] {"*"};
}
}
I wish to choose the appender based on application.properties
I have tried all answers shared on How to access a value defined in the application.properties file in Spring Boot. But none of them work, giving errors like Spring Boot - Environment #Autowired throws NullPointerException. The solutions mentioned in the above link also fail to work.

Log4j2 logs are not directing to correct log file

I am facing an issue with configuring log4j2 logs programmatically.
Please see the below code, I am creating 2 objects of the class App3, and I want to create 2 debug log files(a log file per App3 object), thereafter each object should be able to log to corresponding log file.
But my code is logging all the logs to the second log file after 2nd log is created. Can someone help on this.
Output of the program
file Name: app3_logger1.log_debug.log
2020-06-16 16:19:31,100 DEBUG app3_logger1.log [main] Hello from Log4j 2app3_logger1
file Name: app3_logger2.log_debug.log
2020-06-16 16:19:31,211 DEBUG app3_logger2.log [main] Hello from Log4j 2app3_logger2
2020-06-16 16:19:31,216 DEBUG app3_logger2.log [main] Hello from Log4j 2app3_logger2
2020-06-16 16:19:31,216 DEBUG app3_logger1.log [main] Hello from Log4j 2app3_logger1
2020-06-16 16:19:31,216 DEBUG app3_logger1.log [main] Hello from Log4j 2app3_logger1
2020-06-16 16:19:31,217 DEBUG app3_logger2.log [main] Hello from Log4j 2app3_logger2
Java Class - you just need to add log4j2 dependencies to compile
public class App3 {
public Logger logger;
public static void main(String[] args) {
App3 app1 = new App3();
app1.initializeYourLogger("app3_logger1.log", "%d %p %c [%t] %m%n");
app1.testProg("app3_logger1");
App3 app2 = new App3();
app2.initializeYourLogger("app3_logger2.log", "%d %p %c [%t] %m%n");
app2.testProg("app3_logger2");
app2.testProg("app3_logger2");
app1.testProg("app3_logger1");
app1.testProg("app3_logger1");
app2.testProg("app3_logger2");
}
public void testProg(String s) {
logger.debug("Hello from Log4j 2" + s);
}
public void initializeYourLogger(String fileName, String pattern) {
this.logger = LogManager.getLogger(fileName);
ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
builder.setStatusLevel(Level.DEBUG);
builder.setConfigurationName(fileName);
AppenderComponentBuilder componentBuilder = builder.newAppender("log", "File");
componentBuilder.add(builder.newLayout("PatternLayout").addAttribute("pattern", pattern));
RootLoggerComponentBuilder rootLogger = builder.newRootLogger(Level.DEBUG);
LayoutComponentBuilder layoutBuilder = builder.newLayout("PatternLayout").addAttribute("pattern", pattern);
ComponentBuilder triggeringPolicy = builder.newComponent("Policies")
.addComponent(builder.newComponent("SizeBasedTriggeringPolicy").addAttribute("size", "10MB"));
componentBuilder = builder.newAppender("LogToRollingErrorFile", "RollingFile")
.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.DENY)
.addAttribute("level", Level.ERROR))
.addAttribute("fileName", fileName + "_error.log")
.addAttribute("filePattern", fileName + "-%d{MM-dd-yy-HH-mm-ss}_error.log").add(layoutBuilder)
.addComponent(triggeringPolicy);
builder.add(componentBuilder);
componentBuilder = builder.newAppender("LogToRollingDebugFile", "RollingFile")
.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.DENY)
.addAttribute("level", Level.DEBUG))
.addAttribute("fileName", fileName + "_debug.log")
.addAttribute("filePattern", fileName + "-%d{MM-dd-yy-HH-mm-ss}_debug.log").add(layoutBuilder)
.addComponent(triggeringPolicy);
builder.add(componentBuilder);
AppenderRefComponentBuilder rollingError = rootLogger.getBuilder().newAppenderRef("LogToRollingErrorFile");
AppenderRefComponentBuilder rollingDebug = rootLogger.getBuilder().newAppenderRef("LogToRollingDebugFile");
rootLogger.add(rollingError);
rootLogger.add(rollingDebug);
builder.add(rootLogger);
Configurator.reconfigure(builder.build());
}
}
This is exactly what I want to do in log4j older version, I am still struggling with log4j2,
private void initLogger(String serviceName, String instance) throws IOException {
String loggerName = serviceName+"_"+instance;
this.logger = Logger.getLogger(loggerName);
this.logger.removeAllAppenders();
PatternLayout layout = new PatternLayout();
layout.setConversionPattern("%d: %m%n");
String loggingFolder = this.properties.getLoggingFolder();
String debugFileName = loggingFolder+"/"+loggerName+"_debug.log";
String errorFileName = loggingFolder+"/"+loggerName+"_error.log";
RollingFileAppender debugAppender = new RollingFileAppender(layout, debugFileName, true);
debugAppender.setThreshold(Level.DEBUG);
debugAppender.setMaxFileSize("10000000");
debugAppender.setMaxBackupIndex(49);
logger.addAppender(debugAppender);
RollingFileAppender errorAppender = new RollingFileAppender(layout, errorFileName, true);
errorAppender.setThreshold(Level.ERROR);
errorAppender.setMaxFileSize("10000000");
errorAppender.setMaxBackupIndex(49);
logger.addAppender(debugAppender);
}
Actually, I am quite sure your Logger is being updated correctly. The problem is that both application instances are going to use the same Logging configuration.
If you look at Log4j's architecture you will see that the Loggers and the configuration are anchored in the LoggerContext. By default, Log4j uses the ClassLoaderContextSelector, which means that every ClassLoader can have its own LoggerContext. Your sample application only has a single ClassLoader and so will only have a single LoggerContext and, therefore, only a single Configuration.
So when you reconfigured the second time you simply replaced the prior configuration with the new one. Since the root logger is handling all log events it will route the events from both Loggers you have created to the file created in the second configuration.
If you want logs to end up in two different files then create a configuration with both files and figure out a way to route them to the correct file, either via logger names or filters.
As per observation, your logger is updated with the last initialization so after app2.initializeYourLogger() your object-level logger object updated with App2 configuration.
You need to return the logger object from initializeYourLogger() and also create separate Logger object.

Getting Log4j2 errors

My log4j2 properties file:
status = warn
name= properties_configuration
#Directory path where log files will be stored
property.basePath = ./log/
#File logger
appender.rolling.type = RollingFile
appender.rolling.name = fileLogger
appender.rolling.fileName= ${basePath}app.log
appender.rolling.filePattern= ${basePath}app_%d{yyyyMMdd}.log.gz
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %msg%n
appender.rolling.policies.type = Policies
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.rolling.policies.time.interval = 1
appender.rolling.policies.time.modulate = true
appender.rolling.strategy.type = DefaultRolloverStrategy
appender.rolling.strategy.delete.type = Delete
appender.rolling.strategy.delete.basePath = ${basePath}
appender.rolling.strategy.delete.maxDepth = 1
appender.rolling.strategy.delete.ifLastModified.type = IfLastModified
appender.rolling.strategy.delete.ifLastModified.age = 30d
#Root logger configuration
rootLogger.level = info
rootLogger.additivity = false
rootLogger.appenderRef.rolling.ref = fileLogger
I'm using Lombok #Log4j2 annotation:
#Log4j2
public class BotApplication {
public static void main(String[] args) {
ApiContextInitializer.init();
TelegramBotsApi telegram = new TelegramBotsApi();
Bot bot = new Bot();
try {
telegram.registerBot(bot);
log.info("Bot successfully connected.");
} catch (TelegramApiRequestException e) {
log.error("Can't start Bot. Error: {}", e.getMessage());
}
}
}
Application writes logs to file correctly, but always when i run my app i got errors in my console:
log4j:WARN No appenders could be found for logger (org.apache.http.client.protocol.RequestAddCookies).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Seems that these errors don't affect to the logger, but I would like to remove them somehow.
Error messages that being with "log4j:WARN" are coming from log4j 1.x. This error means you have the log4j 1.x jar in your classpath but do not have a Log4j 1.x configuration present.
If you do not want to use log4j 1 (and you shouldn't) then add the log4j-1.2-api jar from Log4j 2 to your project.

How to correctly use RoutingAppender in log4j2 programmatically?

I am creating a log4j2 logger programmatically and adding appenders to it.
I want the logger to write the messages in two different locations/files according to some parameter/criteria.
For this I found that RoutingAppender can be good option to route the messages in different locations.
And for the criteria with the help of which I want to route messages, I am using Marker as used in How to create multiple log file programatically in log4j2?
But I am enable to manage it properly.Below is my code snippet for reference :
public class Log4j2TestApplication {
private static final Marker MARKER1 = MarkerManager.getMarker("MARKER1");
private static final Marker MARKER2 = MarkerManager.getMarker("MARKER2");
public static void main(String[] args) {
String loggerName = "demoLogger";
final ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
final LoggerComponentBuilder loggerComp = builder.newLogger(loggerName, Level.ALL).addAttribute("additivity",
false);
builder.add(loggerComp);
Configuration configuration = builder.build();
LoggerContext ctx = Configurator.initialize(builder.build());
ctx.start(configuration);
ctx.updateLoggers(configuration);
Logger logger = ctx.getLogger(loggerName);
Appender csvAppender = createCsvAppender(configuration);
Appender textAppender = createTextAppender(configuration);
csvAppender.start();
textAppender.start();
logger.addAppender(csvAppender);
logger.addAppender(textAppender);
Appender routingAppender = createRoutingAppender(configuration, textAppender, csvAppender);
routingAppender.start();
logger.addAppender(routingAppender);
logger.error(MARKER1, "the text message", "testing parameter");
logger.error(MARKER2, "the csv message", "testing parameter");
csvAppender.stop();
textAppender.stop();
routingAppender.stop();
}
private static Appender createCsvAppender(final Configuration config) {
return RollingFileAppender.newBuilder().setConfiguration(config).setName("csvAppender")
.withFileName("TestFile.csv").withFilePattern("TestFile.csv")
.withPolicy(SizeBasedTriggeringPolicy.createPolicy("100M"))
.withStrategy(DefaultRolloverStrategy.newBuilder().withConfig(config).build()).withImmediateFlush(true)
.setFilter(ThresholdFilter.createFilter(Level.ALL, Result.ACCEPT, Result.DENY)).setLayout(getCsvLayout(config))
.build();
}
private static Layout<String> getCsvLayout(final Configuration config) {
return new CsvParameterLayout(config, StandardCharsets.UTF_8, CSVFormat.DEFAULT.withDelimiter(','),
"column1;coloumn2\n", null);
}
private static Appender createTextAppender(final Configuration config) {
return RollingFileAppender.newBuilder().setConfiguration(config).setName("txtAppender")
.withFileName("TestFile.txt").withFilePattern("TestFile.txt")
.withPolicy(SizeBasedTriggeringPolicy.createPolicy("100M"))
.withStrategy(DefaultRolloverStrategy.newBuilder().withConfig(config).build()).withImmediateFlush(true)
.setFilter(ThresholdFilter.createFilter(Level.ALL, Result.ACCEPT, Result.DENY)).setLayout(getTextLayout(config, "header\n"))
.build();
}
private static Layout<String> getTextLayout(final Configuration config, final String header) {
return PatternLayout.newBuilder().withConfiguration(config).withCharset(StandardCharsets.UTF_8)
.withPattern("[%d][%-5.-5p]").withHeader(header).build();
}
private static Appender createRoutingAppender(final Configuration config, Appender appender1, Appender appender2) {
Route[] routeArray = new Route[2];
routeArray[0] = Route.createRoute(appender1.getName(), "MARKER1", null);
routeArray[1] = Route.createRoute(appender2.getName(), "MARKER2", null);
Routes routes = Routes.newBuilder().withRoutes(routeArray).withPattern("marker").build();
Appender routingAppender = RoutingAppender.newBuilder().setName("routingAppender").setConfiguration(config)
.withRoutes(routes).build();
return routingAppender;
}
}
I have referenced below links also but I could not find the accurate way of RoutingAppender programmatically.
Is there a way to Route logs based on Marker with the RoutingAppender in Log4j2
Wildcard pattern for RoutingAppender of Log4j2
How to create multiple log file programatically in log4j2?

Categories

Resources