I'm trying to get log4j2 work within a fatjar.
When running in intellij every works fine, but when building my fatjar an running it like
java -jar dx.jar
only errors are logged to console, and nothing to the rollingfile. It seams ignoring my config.
Configuration:
String logFile = logPath + "dxpos.log";
String logFilePattern = logPath + "dxpos-%d{yyyy-MM-dd}.log";
LogManager.shutdown();
var builder = ConfigurationBuilderFactory.newConfigurationBuilder();
var layout = builder.newLayout("PatternLayout")
.addAttribute("pattern", "%d{yyyy-MM-dd HH:mm:ss} %-5p [%t] %c: %m%n");
var console = builder.newAppender("console", "Console")
.addAttribute("target", "SYSTEM_OUT")
.addAttribute("immediateFlush", true)
.add(layout);
var triggeringPolicy = builder.newComponent("Policies")
.addComponent(builder.newComponent("TimeBasedTriggeringPolicy"))
.addComponent(builder.newComponent("SizeBasedTriggeringPolicy").addAttribute("size", "100M"));
var rollingFile = builder.newAppender("rollingFile", "RollingFile")
.addAttribute("fileName", logFile)
.addAttribute("filePattern", logFilePattern)
.addAttribute("immediateFlush", true)
.addAttribute("append", true)
.addComponent(triggeringPolicy)
.add(layout);
var rootLogger = builder.newRootLogger(Level.INFO)
.add(builder.newAppenderRef("console"))
.add(builder.newAppenderRef("rollingFile"));
builder.add(console);
builder.add(rollingFile);
builder.add(rootLogger);
Configurator.initialize(builder.build());
After searching a file I a switch from programmatically config method to XML
To getting it to work you have to declare the logger
public static Logger logger = null;
Add some variables like that
MDC.put("logFile", logFile);
MDC.put("LogFilePattern", logFilePattern);
And create the logger
logger = LoggerFactory.getLogger(MainForm.class);
Related
i want to use Rewrite Policy for some condition in logging like masking, and then I found the solution but in log4j2.xml, however we use log4j2.properties for base config, I already try to config but the rewrite still not working.
here other config compare to my config
Other Config :
<Configuration status="warn" name="MyApp" packages="">
<Properties>
<Property name="LOG_DIR">/logs</Property>
</Properties>
<Appenders>
<RollingFile
name="rollingFile"
fileName="D:/logs/omnichannel/application.log"
filePattern="D:/logs/omnichannel/application.%i.log.gz"
ignoreExceptions="false">
<PatternLayout>
<Pattern>%d{yyyy-MM-dd HH:mm:ss} %-5p %m%n</Pattern>
</PatternLayout>
<Policies>
<SizeBasedTriggeringPolicy size="10MB" />
</Policies>
<DefaultRolloverStrategy max="5">
<Delete basePath="D:/logs/" maxDepth="2">
<IfFileName glob="*/app-*.log.gz" />
<IfLastModified age="P30D" />
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
<Console name="STDOUT" target="SYSTEM_OUT" ignoreExceptions="false">
<PatternLayout pattern="%m%n"/>
</Console>
<Rewrite name="Rewrite">
<LogInterceptor />
<AppenderRef ref="rollingFile"/>
</Rewrite>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Rewrite"/>
</Root>
</Loggers>
</Configuration>
And my config here :
status = warn
name= PropertiesConfig
# Give directory path where log files should get stored
property.basePath = D://logs//
appenders = rolling, console, Rewrite
appender.Rewrite.type = Rewrite
appender.Rewrite.name = Rewrite
appender.Rewrite.layout.type = LogInterceptor
appender.Rewrite.layout.RewriteAppender = fileLogger
# ConsoleAppender will print logs on console
appender.console.type = Console
appender.console.name = consoleLogger
appender.console.target = SYSTEM_OUT
appender.console.layout.type = PatternLayout
# Specify the pattern of the logs
appender.console.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %highlight{[%-5level]}{TRACE=magenta} %mask %logger{36}.%M(%L) : %msg%n%throwable
appender.console.layout.disableAnsi=false
# RollingFileAppender will print logs in file which can be rotated based on time or size
appender.rolling.type = RollingFile
appender.rolling.name = fileLogger
appender.rolling.fileName = ${basePath}${hostName}.log
appender.rolling.filePattern = ${basePath}${hostName}_%d{yyyy-MM-dd}-%i.log.gz
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.pattern = %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%-5level] %logger{36}.%M(%L) : %msg%n%throwable
appender.rolling.policies.type = Policies
# Rotate log file each day and keep 30 days worth
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.rolling.policies.time.interval = 1
appender.rolling.strategy.type = DefaultRolloverStrategy
appender.rolling.strategy.action.type = Delete
appender.rolling.strategy.action.basePath = ${basePath}
appender.rolling.strategy.action.maxDepth = 1
appender.rolling.strategy.action.ifLastModified.type = IfLastModified
appender.rolling.strategy.fileIndex = nomax
# For hibernate tracing query parameter, make this default not opened
#loggers = application, hibernate
loggers = application, httpclient, Client
# Mention package name here. Classes in this package or sub packages will use ConsoleAppender and RollingFileAppender for logging
logger.application.name = com.project
logger.application.level = info
logger.application.appenderRefs = rolling
logger.application.appenderRef.rolling.ref = fileLogger
logger.httpclient.name = org.apache.http
logger.httpclient.level = info
logger.httpclient.appenderRefs = rolling
logger.httpclient.appenderRef.rolling.ref = fileLogger
logger.Client.name = com.sun.jersey.api
logger.Client.level = info
logger.Client.appenderRefs = rolling
logger.Client.appenderRef.rolling.ref = fileLogger
# For hibernate tracing query parameter, make this default not opened
#logger.hibernate.name = org.hibernate.type
#logger.hibernate.level = trace
#Logger.hibernate.Additivity = false
# Configure root logger for logging error logs in classes which are in package other than above specified package
rootLogger.level = info
rootLogger.appenderRefs = Rewrite
rootLogger.appenderRef.Rewrite.ref = Rewrite
my function rewrite :
#Plugin(name = "LogInterceptor", category = "Core", elementType = "rewritePolicy", printObject = true)
public class LoggingMaskingConverter implements RewritePolicy {
protected static final Logger log = LogManager.getLogger(LoggingMaskingConverter.class);
private static final List<String> loggingSetting = Arrays.asList("pin,password".split(","));
private static final String loggingMasking = "1";
private static final List<String> excludePath = Collections.emptyList();
private static final String STR_BODY = "body=[";
Properties prop = new Properties();
#PluginFactory
public static LoggingMaskingConverter createPolicy() {
return new LoggingMaskingConverter();
}
#Override
public LogEvent rewrite(LogEvent event) {
if (event.getLoggerName().contains("com.project")) {
Message outputMessage = logInfoMasking(event.getMessage());
return new Log4jLogEvent.Builder(event).setMessage(outputMessage).build();
} else {
return new Log4jLogEvent.Builder(event).build();
}
}
public Message logInfoMasking(Message message) {
StringBuilder stringBuilder = new StringBuilder();
try {
String body = message.getFormattedMessage();
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
if (StringUtils.isNotBlank(loggingMasking) && loggingMasking.equalsIgnoreCase("1")) {
if (body != null) {
Collection<String> whitelist = loggingSetting;
Collection<String> excludeKeys = excludePath;
JsonMasker masker = new JsonMasker(whitelist, excludeKeys);
JsonNode jsonNode = new ObjectMapper().readTree(body);
JsonNode masked = masker.mask(jsonNode);
stringBuilder.append(STR_BODY + masked.toString() + "]");
}
} else {
String json = ow.writeValueAsString(body);
stringBuilder.append(STR_BODY + json + "]");
}
} catch (JsonProcessingException e) {
log.error(e, e);
}
return new ObjectMessage(stringBuilder.toString());
}
}
i spend my time around one day to solve this. until this day. the rewrite still not working in logs file but in my function rewrite going well
The general format to configure a Log4j2 component via properties is:
<parent_component_prefix>.<arbitrary_id>.type = ComponentType
<parent_component_prefix>.<arbitrary_id>.property1 = value1
...
So in your case you need:
appender.$0.type = Rewrite
appender.$0.name = Rewrite
appender.$0.$1.type = LogInterceptor
appender.$0.$2.type = AppenderRef
appender.$0.$2.ref = fileLogger
I'm using log4j2.
I want to create a RollingFileAppender which rotates the log file on a daily basis.
The name of the logfile is unknown until the application has started (the logfile name is assembled from the application config).
That is why I need to add a RollingFileAppender at runtime.
I have the following code:
public static final ConfigurationBuilder<BuiltConfiguration> BUILDER = ConfigurationBuilderFactory.newConfigurationBuilder
public void initFileLoggerWithFilePattern(final String pattern) {
final LoggerComponentBuilder logger = BUILDER.newLogger("FileLogger", Level.DEBUG);
final AppenderComponentBuilder appender = createFileAppenderWithFilePattern(pattern);
BUILDER.add(appender);
logger.add(BUILDER.newAppenderRef("RollingFileAppender"));
BUILDER.add(logger);
Configurator.initialize(BUILDER.build());
}
public AppenderComponentBuilder createFileAppenderWithFilePattern(final String pattern) {
final AppenderComponentBuilder acb = BUILDER.newAppender("RollingFileAppender", "RollingFile");
acb.addAttribute("fileName", pattern);
acb.addAttribute("filePattern", pattern);
acb.addComponent(createPatternLayout());
acb.addComponent(createTimeBasedTriggeringPolicy());
return acb;
}
public LayoutComponentBuilder createPatternLayout() {
final LayoutComponentBuilder lcb = BUILDER.newLayout("PatternLayout");
lcb.addAttribute("pattern", "%d{yyyy-MM-dd HH:mm:ss.SSS}{GMT}Z %m");
return lcb;
}
public ComponentBuilder createTimeBasedTriggeringPolicy() {
final ComponentBuilder policies = BUILDER.newComponent("Policies");
final ComponentBuilder policy = BUILDER.newComponent("TimeBasedTriggeringPolicy");
policies.addComponent(policy);
return policies;
}
The problem is that this code changes absolutely nothing. No appender as well as no Logger is being added to the configuration. The "FileLogger" that was created programmatically is not available.
I used this code to print the loggers and Appenders after executing the code above.
private void printLog4jConfig() {
final LoggerContext context = (LoggerContext) LogManager.getContext(false);
final Configuration config = context.getConfiguration();
// Print appenders
for(Appender app : config.getAppenders().values()) {
System.out.println(app.getName());
}
// Print Loggers and their Appenders
for(LoggerConfig lc : config.getLoggers().values()) {
System.out.println(lc);
for(Appender app : lc.getAppenders().values()) {
System.out.println(" " + app);
}
}
}
Output:
Appenders
-------------
STDOUT
Loggers
-------------
root
STDOUT
Console
STDOUT
My Question:
What is wrong with my code? Why is my Appender as well as my Logger not added? Respectively why is the configuration not being refreshed / updated ?
How can I add a RollingFileAppender as well as a logger to the log4j2 configuration during runtime?
I found the solution to my problem.
Instead using
Configurator.initialize(BUILDER.build())
I had to use
Configurator.reconfigure(BUILDER.build());
This reloaded the configuration and i was able to see and use my appender and logger.
i have a question regarding log4j2 with version 2.9.
Basically I want to do the same as described here (log4j), only with 2.9:
Sample log4j v1.x
I need a logger that can be called in any method in the class. This is to collect all subsequent logs recursively from a certain starting point. The collection should be able to be read out in any form later on.
Logger logger = LogManager.getLogger();
public void meth1(){
StringWriter/ List/ String or whatever
logger.add(Collector);
logger.info("Start");
this.meth2();
this.meht3();
logger.info("Stop");
=> do something with the collected logs
}
public void meht2(){
logger.info("meth2: add Collection");
}
public void meth3(){
logger.info("meth3: add Collection");
}
public void meht4(){
logger.info("foo");
}
as soon as the end is set in a form, the following logs should be included in the collection:
Start
meth2: add Collection
meth3: add Collection
Stop
thanks for your help
After a while, I came up with the following solution which works for me using Log4J 2.8. I've added some comments to the code to explain the different steps necessary.
It's important that the logger is requested with the same name (line marked with /* 1 */ as for which the configuration is stored (line marked with /* 2 */. This implies, that the class name cannot be used to get the logger, or that MyClass.class.getName() should be used at /*2*/.
public class LoggingTest {
public static void main(String[] args) {
// define the logger, could also be static in class
final String loggerName = "myCollectingLogger";
Logger logger = LogManager.getLogger(loggerName); /* 1 */
// the log message collector
StringWriter writer = new StringWriter();
// start adapting the logger configuration
LoggerContext ctx = LoggerContext.getContext(false);
Configuration config = ctx.getConfiguration();
// create our appender
PatternLayout layout = PatternLayout.newBuilder().withPattern("%d{yyyy-MM-dd HH:mm:ss.SSS} %level [%t] [%c] [%M] [%l] - %msg%n").build();
WriterAppender writerAppender = WriterAppender.newBuilder().setName("writerAppender").setTarget(writer).setLayout(layout).build();
// add the appender to a LoggerConfig
AppenderRef ref = AppenderRef.createAppenderRef("writerAppender", null, null);
AppenderRef[] refs = new AppenderRef[] { ref };
LoggerConfig loggerConfig = LoggerConfig.createLogger(false, Level.INFO, "example", null, refs, null, config, null);
loggerConfig.addAppender(writerAppender, null, null);
// enable the LoggerConfig in the LoggerContext
config.addLogger(loggerName, loggerConfig); /* 2 */
ctx.updateLoggers();
// use the logger:
logger.info("Start");
logger.warn("foo bar");
logger.error("relax, it's just a test");
logger.info("Stop");
System.out.println("--- the collected log messages: ---");
System.out.println(writer.toString());
}
}
thanks, I've adjusted it to my needs:
public static StringWriter createStringWriter(String classname){
StringWriter stringWriter = new StringWriter();
final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
final Configuration config = ctx.getConfiguration();
PatternLayout layout = PatternLayout.newBuilder()
.withPattern("%d{yyyy-MM-dd HH:mm:ss.SSS} %level [%t] [%c] [%M] [%l] - %msg%n").build();
WriterAppender writerAppender = WriterAppender.newBuilder()
.setName(classname + "writeLogger")
.setTarget(stringWriter)
.setLayout(layout)
.build();
writerAppender.start();
config.addAppender(writerAppender);
LoggerConfig loggerConfig = config.getLoggerConfig(classname);
loggerConfig.addAppender(writerAppender, null, null);
ctx.updateLoggers();
return stringWriter;
}
public static void removeStringWriter(String classname){
final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
final Configuration config = ctx.getConfiguration();
LoggerConfig loggerConfig = config.getLoggerConfig(classname);
loggerConfig.removeAppender(classname + "writeLogger");
ctx.updateLoggers();
}
I want to write logs in separate files Programmatically,
public class ProgLoggerMultipaleFiles {
HashMap<LogCategory, Logger> myLogHashMap = new HashMap<LogCategory, Logger>();
public ProgLoggerMultipaleFiles() {
JLogger jlog = new JLogger();
jlog.startFileLog("mylog");
jlog.startFileLog("HC");
jlog.startFileLog("MC");
jlog.startFileLog("DC");
myLogHashMap.put(LogCategory.mylog, Logger.getLogger("mylog"));
myLogHashMap.put(LogCategory.HC, Logger.getLogger("HC"));
myLogHashMap.put(LogCategory.MC, Logger.getLogger("MC"));
myLogHashMap.put(LogCategory.DC, Logger.getLogger("DC"));
String parameter = "Hello";
log(LogCategory.mylog,Priority.DEBUG,"This is debug : " + parameter);
log(LogCategory.mylog,Priority.INFO,"This is info : " + parameter);
log(LogCategory.mylog,Priority.WARN,"This is warn : " + parameter);
log(LogCategory.mylog,Priority.ERROR,"This is error : " + parameter);
log(LogCategory.mylog,Priority.FATAL,"This is fatal : " + parameter);
log(LogCategory.HC,Priority.FATAL,"HC");
log(LogCategory.MC,Priority.FATAL,"MC");
log(LogCategory.DC,Priority.FATAL,"DC");
}
public void log(LogCategory category,Priority priority,String msg){
myLogHashMap.get(category).log(priority, msg);
}
public enum LogCategory{
mylog,HC,MC,DC
}
public static void main(String[] args) {
ProgLoggerMultipaleFiles plog = new ProgLoggerMultipaleFiles();
}
}
And I initialize loggers and Appenders in this class,
public class JLogger {
public JLogger() {
startConsolLog();
}
public void startConsolLog(){
ConsoleAppender console = new ConsoleAppender(); //create appender
//configure the appender
String PATTERN = "%d [%p|%c|%C{1}] %m%n";
console.setLayout(new PatternLayout(PATTERN));
console.setThreshold(Level.FATAL);
console.activateOptions();
//add appender to any Logger (here is root)
Logger.getRootLogger().addAppender(console);
}
public void startFileLog(String fileName){
FileAppender fa = new FileAppender();
fa.setName(fileName);
fa.setFile(fileName+".log");
fa.setLayout(new PatternLayout("%d %-5p [%c{1}] %m%n"));
fa.setThreshold(Level.DEBUG);
fa.setAppend(true);
fa.activateOptions();
//add appender to any Logger (here is root)
Logger.getRootLogger().setAdditivity(false);
Logger.getRootLogger().addAppender(fa);
//repeat with all other desired appenders
}
}
When I run this code creates 4 diff files but all messages are logged into all files.
Thanks in advance.
Log4j Loggers work like a tree. When you get Loggers like LogManager.getLogger(MyClass.class) and MyClass is in org.my.company namespace, log4j will traverse the configuration and look for "org.my.company.MyClass" then "org.my.company" and so on until it finds one. If not it uses the rootlogger.
So you can "tap" that tree with appenders. For example you want all classes in "org.my.company.api" to log into a special file: Configure a logger named "org.my.company.api" , add that fileappender to it and get the Loggers with *.class.
In your case it's a bit different. You get Loggers with a specific name that is probably not in the namespace tree. So if there is no logger with that special name, the root logger is used. Thus all messages go everywhere.
So what you have to do is configure not only appenders, but also Loggers with those specific names - "mylog" for example and add the respective appender to only that logger.
Your tree:
root ← Appender Console, mylog, HC, MC, ...
but you need actually:
root ← Appender Console
|- mylog ← Appender for mylog.log
|- MC ← Appender for MC.log
|- ...
Try:
public void startFileLog(String fileName){
FileAppender fa = new FileAppender();
fa.setName(fileName);
fa.setFile(fileName+".log");
fa.setLayout(new PatternLayout("%d %-5p [%c{1}] %m%n"));
fa.setThreshold(Level.DEBUG);
fa.setAppend(true);
fa.activateOptions();
//add appender to any Logger (here is NOT root)
Logger.getLogger(fileName).setAdditivity(false); // messages will not go to root logger anymore!
Logger.getLogger(fileName).addAppender(fa);
//repeat with all other desired appenders
}
Where log4j2.xml should be placed for use in applet? Can it log both to Java Console and to files on user computer?
I placed in applet resources conf/log4j2.xml and read it from applet. Applet loads it incorrectly, so i fix the fields from the applet code:
public static Logger getLogger(Class className) {
//get logger configuration
LoggerContext loggerContext = Configurator.initialize("client", className.getClassLoader(), className.getClassLoader().getResource("conf/log4j2.xml").getFile());
Configuration configuration = loggerContext.getConfiguration();
//set root logger to desired level
LoggerConfig loggerConfig = configuration.getLoggerConfig("");
loggerConfig.setLevel(Level.INFO);
//obtain appender
Appender appender = obtainAppender(configuration);
//get logger for required class
org.apache.logging.log4j.core.Logger loggerForClass = loggerContext.getLogger(className.getName());
//associate logger for required class with just created appender
configuration.addLoggerAppender(loggerForClass, appender);
return loggerForClass;
}
private static Appender obtainAppender(Configuration configuration) {
//create appender
TriggeringPolicy[] triggeringPolicies = {OnStartupTriggeringPolicy.createPolicy(), TimeBasedTriggeringPolicy.createPolicy("5", "true"), SizeBasedTriggeringPolicy.createPolicy("5 MB")};
TriggeringPolicy triggeringPolicy = CompositeTriggeringPolicy.createPolicy(triggeringPolicies);
return RollingFileAppender.createAppender(CLIENT_LOG_PATH + FileUtils.FILE_SEPARATOR + "my_client.log",
CLIENT_LOG_PATH + FileUtils.FILE_SEPARATOR + "/$${date:yyyy-MM}/my_client-%d{MM-dd-yyyy-HH-mm}-%i.log",
"", APPLET_APPENDER,
"true", "true",
triggeringPolicy, null,
PatternLayout.createLayout("%d{dd/MM/yyyy HH:mm:ss} %-5p [%t] [%c{1}] %m%n", configuration, null, "UTF-8"),
null, "true", configuration);
}