Avoiding Multiple Logging of Same Message Due to Default behaviour in Log4j - java

I am working in Grails application and want to log messages in different files. I want to log exceptions, normal and API logs in different files. But according to Log4j general roles, If we set logger level to 'Info' then warn and error messages will also start logging in this file while I want to log error messages in different file. So, thus my error messages will be logged twicely in error file and in info file too. While I want that 'info' logger log just 'info' level messages not 'error' level messages too. And 'error' logger just log error messages.
Below is my Log4j Configuration:
log4j = {
def layoutPattern = new PatternLayout("[%d{ISO8601}] %m \r\n")
def dailyRollingInfoFile = new DailyRollingFileAppender(
name:"rollingInfoFileAppender",
layout: layoutPattern,
//Path of the Log File
fileName:"C:\\MS-Logs\\Application\\MSLogs.log",
datePattern: "'.'dd-MM-yyyy")
def dailyRollingExceptionFile = new DailyRollingFileAppender(
name:"rollingExceptionFileAppender",
layout: layoutPattern,
//Path of the Log File
fileName:"C:\\MS-Logs\\Exceptions\\ExceptionLogs.log",
datePattern: "'.'dd-MM-yyyy")
def dailyRollingExceptionAPIFile = new DailyRollingFileAppender(
name:"rollingAPIFileAppender",
layout: layoutPattern,
//Path of the Log File
fileName:"C:\\MS-Logs\\API\\MS-NotificationsLogs.log",
datePattern: "'.'dd-MM-yyyy")
//For logging exceptions stack trace
appenders {
appender dailyRollingInfoFile
appender dailyRollingExceptionFile
appender dailyRollingExceptionAPIFile
}
root {
info 'rollingInfoFileAppender', additivity: false
debug 'rollingAPIFileAppender', additivity: false
error 'rollingExceptionFileAppender'
}
}
And Now, this is how I add filters:
dailyRollingExceptionFile.addFilter(new org.apache.log4j.varia.LevelMatchFilter(levelToMatch:'ERROR', acceptOnMatch: true))
dailyRollingExceptionFile.addFilter(new org.apache.log4j.varia.DenyAllFilter())
//To make it sure that It will just Log, Messages by Info Logger
dailyRollingInfoFile.addFilter(new org.apache.log4j.varia.LevelMatchFilter(levelToMatch:'INFO', acceptOnMatch: true))
dailyRollingInfoFile.addFilter(new org.apache.log4j.varia.DenyAllFilter())
//To make it sure that It will just Log, Messages by API Logger
dailyRollingAPIFile.addFilter(new org.apache.log4j.varia.LevelMatchFilter(levelToMatch:'DEBUG', acceptOnMatch: true))
dailyRollingAPIFile.addFilter(new org.apache.log4j.varia.DenyAllFilter())
How, It may be possible to avoid same message being logged twicely in different files ? How can we log messages in different files without being repeating it in other file ?
Thanks for your Time :)

I believe Log4j's LevelMatchFilter allows you to do what you're after:
def dailyRollingInfoFile = new DailyRollingFileAppender(...)
dailyRollingInfoFile.addFilter(new org.apache.log4j.varia.LevelMatchFilter(levelToMatch:'INFO', acceptOnMatch: true))
dailyRollingInfoFile.addFilter(new org.apache.log4j.varia.DenyAllFilter())
The DenyAllFilter drops the messages that the LevelMatchFilter does not match (ie. everything other than level INFO)

Related

java.util.logging - How to force all Loggers to obey given format from within the app's runtime? (HSQLDB)

In my app, I would like some way of formatting.
For that purpose, I wrote a SingleLineFormatter extends Formatter.
Now I am trying to set all Loggers to use it, but can't figure that out.
LogManager.getLogManager().readConfiguration((InputStream) configIS);
Collections.list(LogManager.getLogManager().getLoggerNames()).forEach(
loggerName -> {
List<Handler> handlers = Arrays.asList(Logger.getLogger(loggerName).getHandlers());
System.out.println(" * Logger " + loggerName + ": " + handlers.size());
handlers.forEach(handler -> System.out.println(" HF: " + handler.getFormatter()));
//handlers.forEach(handler -> handler.setFormatter(new SingleLineFormatter()));
}
);/**/
log.info("Logging test");
This reads the config, applies it to all handlers that are found.
Oct 02, 2018 10:42:10 PM cz.dynawest.logging.LoggingUtils initLogging
INFO: Log config file not found: #/logging.properties Using LoggingUtils' default.
* Logger cz.dynawest.csvcruncher.App: 0
* Logger global: 0
* Logger cz.dynawest.logging.LoggingUtils: 0
2018-10-02 22:42:10 INFO cz.dynawest.logging.LoggingUtils initLogging: Logging test
* Logger : 2
HF: cz.dynawest.logging.SingleLineFormatter#34c45dca
HF: cz.dynawest.logging.SingleLineFormatter#52cc8049
However the rest of the Loggers still use whatever they were configured with. Probably just JUL's default.
Oct 02, 2018 10:42:10 PM org.hsqldb.persist.Logger logInfoEvent
INFO: checkpointClose start
I know I can manage this from JUL's logging.properties within my JVM.
But I want to distribute the app, and want all the log messages to be formatted the same way.
How can I force all messages going to JUL to be formatted with my Formatter?
There is -Djava.util.logging.config.file=/path/to/app.properties, but that's out of scope for my particular case. (And doesn't work anyway.)
Update: It looks like the third party logging doesn't go through JUL. So the question is - if that's true, how do I configure the other frameworks?
Here is the file that's being loaded to LogManager. There are quite some experiments so not everythign is correct.
# Handlers
handlers = java.util.logging.ConsoleHandler java.util.logging.FileHandler
# Console
# The logging of the app actually reacts to this line.
java.util.logging.ConsoleHandler.formatter = cz.dynawest.logging.SingleLineFormatter
#java.util.logging.ConsoleHandler.formatter = cz.dynawest.logging.SimplestFormatter
java.util.logging.ConsoleHandler.level = ALL
# File
java.util.logging.FileHandler.level = ALL
java.util.logging.FileHandler.pattern = app.log
java.util.logging.FileHandler.formatter = cz.dynawest.logging.SingleLineFormatter
java.util.logging.FileHandler.limit = 0
java.util.logging.FileHandler.append = true
# Default global logging level.
.formatter = cz.dynawest.logging.SimplestFormatter
.level = INFO
#global.formatter = cz.dynawest.logging.SimplestFormatter
#root.formatter = cz.dynawest.logging.SimplestFormatter
#cz.dynawest.csvcruncher.App.formatter = cz.dynawest.logging.SimplestFormatter
#cz.dynawest.csvcruncher.App.handlers = java.util.logging.ConsoleHandler
#.useParentHandlers = false
# Various customizations.
org.apache.commons.beanutils.converters.level=INFO
In my app, I would like some way of formatting. For that purpose, I wrote a >SingleLineFormatter extends Formatter
Since JDK 7 the java.util.logging.SimpleFormatter supports a one line format.
This reads the config, applies it to all handlers that are found.
JUL will only load handlers when the logger is demanded by code. It is therefore possible to miss handlers because the loggers themselves haven't been created yet.
How can I force all messages going to JUL to be formatted with my Formatter?
There is -Djava.util.logging.config.file=/path/to/app.properties, but that's out of scope for my particular case. (And doesn't work anyway.)
You are already accessing the LogManager so you can set properties from Java like so:
private static void loadProperties() {
Properties props = new Properties();
props.put("java.util.logging.ConsoleHandler.formatter", "cz.dynawest.logging.SingleLineFormatter");
props.put("org.apache.commons.beanutils.converters.level", "INFO");
try(ByteArrayOutputStream out = new ByteArrayOutputStream()) {
props.store(out, "");
LogManager.getLogManager().readConfiguration(new ByteArrayInputStream(out.toByteArray()));
} catch (IOException ioe) {
throw new AssertionError(ioe);
}
}
If you are running JDK 9 or newer then you should use LogManager.updateConfiguration(java.util.function.Function) instead.
It looks like the third party logging doesn't go through JUL. So the question is - if that's true, how do I configure the other frameworks?
You'll have to determine if the frameworks are routing to one another. You should only have to change the format of the framework that is publishing records to a output source.
In attempts to conform to what the lib might want me to use for logging, I switched to SLF4J and Logback. Didn't help.
So I looked at the particular library that causes the logging issues - HSQLDB.
The problem is that it does some attempts to master all common frameworks and bypasses my attempts to configure it externally. Here is an example: FrameworkLogger
Then I found in the HSQLDB manual:
HyperSQL also supports log4J and JDK logging. The same event information that is passed to the internal log, is passed to external logging frameworks. These frameworks are typically configured outside HyperSQL. The log messages include the string "hsqldb.db." followed by the unique id (a 16 character string) of the database that generated the message, so they can be identified in a multi-database server context.
As the default JDK logging framework has several shortcomings, HyperSQL configures this logging framework for better operation. If you do not want HyperSQL to configure the JDK logging framework, you should include the system level property hsqldb.reconfig_logging=false in your environment.
I tried setting the hsqldb.db. Logger but that didn't work.
So I guess I'll stick with JUL, and turn off the hsqldb.reconfig_logging=false.
By the way, here is a good review of JUL config.
One way is to a static String across application such as
private static Logger logger = Logger.getLogger("some_value");

Using Logger in Domino Java Agent

I want to get away from using a string buffer and System.out.println in Java agents.
I want to use java.util.Logger.
When I log using
logger.info("logger started")
output in the Domino Server Console
[0FDC:000D-1258] 06/07/2018 03:13:57 PM Agent Manager: Agent error: Jun 07, 2018 3:13:57 PM TransferDocsToServerNSF NotesMain INFO: logger started.
Notice the Domino platform added "Agent error" before the output when using Level.INFO
I then tried using .logp with Level.FINE and no output shows up.
logger.setLevel(Level.ALL); or logger.setLevel(Level.FINE);
logger.logp(Level.FINE,this.getClass().getSimpleName(),"main","logger started.");
output: No output. Anything lower than Level.INFO does not print.
How can I target the Domino logging to show Level.FINE?
And, what can I do for INFO for Domino not to consider all Level.INFO to be errors?
I was able to print logging at different levels after editing this file on the server:
(server install) IBM/Domino/jvm/lib/logging.properties
# Default global logging level.
# This specifies which kinds of events are logged across
# all loggers. For any given facility this global level
# can be overriden by a facility specific level
# Note that the ConsoleHandler also has a separate level
# setting to limit messages printed to the console.
.level= FINEST
# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = FINEST
Testing Java code
logger = Logger.getLogger("com.xpagesbeast");
logger.setUseParentHandlers(false); //do not use the global logger (avoid two outputs per log)
create a custom handler if one does not exist, watch our here, you can create more than one the JVM will track.
if(logger.getHandlers().length == 0){
System.out.println("Adding a new handler");
consoleHandler = new ConsoleHandler();
logger.addHandler(consoleHandler);
}
logger.getHandlers()[0].setLevel(Level.INFO);
logger.severe("test severe logging " + logger.getName());
logger.warning("test warning logging " + logger.getName());
logger.info("test info logging " + logger.getName());
logger.finer("test finer logging " + logger.getName());
logger.finest("test finest logging " + logger.getName());
Now I can set a debug flag in a Database or environment variable and assign the logging level as detailed as I want.
For example, if I want to debug the application, I can set a value in a database that is read by the application that determines what logging level that handler will use.

Logging errors to two appenders

I'm trying to configure Logback (in Grails using Groovy configuration) so that:
any errors (from anywhere) are logged to a rolling file and send an email
all debug output from my classes is sent to the rolling file
This is what I have so far:
appender("ROLLING", RollingFileAppender) { ... }
appender("EMAIL", SMTPAppender) { ... }
logger("my.package", DEBUG, ["ROLLING"], false)
root(ERROR, ["ROLLING", "EMAIL"])
It seems that the rolling file gets what I expect (debug from my package at least) but the EMAIL appender gets nothing.
How can I send the errors to the EMAIL appender?

How to get rid of fine log messages for specific package on Glassfish

I was playing arround with the log file, somehow I disabled all the log related information but this javax.enterprise.system.core.security remains displaying FINE level of log, is there any way to change this one to level WARN and reset rest of the log level to default. I have to scroll too much to find my exceptions.
[#|2014-07-28T14:02:42.181+0500|FINE|glassfish3.1.2|javax.enterprise.system.core.security.com.sun.enterprise.iiop.security|_ThreadID=42;_ThreadName=Thread-2;ClassName=com.sun.enterprise.iiop.security.SecClientRequestInterceptor;MethodName=send_request;|Security context is null (nothing to add to service context)|#]
[#|2014-07-28T14:02:42.182+0500|FINE|glassfish3.1.2|javax.enterprise.system.core.security.com.sun.enterprise.iiop.security|_ThreadID=42;_ThreadName=Thread-2;ClassName=com.sun.enterprise.iiop.security.SecServerRequestInterceptor;MethodName=receive_request;|++++ Entered SecServerRequestInterceptor::receive_request|#]
[#|2014-07-28T14:02:42.182+0500|FINE|glassfish3.1.2|javax.enterprise.system.core.security.com.sun.enterprise.iiop.security|_ThreadID=42;_ThreadName=Thread-2;ClassName=com.sun.enterprise.iiop.security.SecServerRequestInterceptor;MethodName=handle_null_service_context;|No SAS context element found in service context list for operation: _is_a|#]
[#|2014-07-28T14:02:42.183+0500|FINE|glassfish3.1.2|javax.enterprise.system.core.security.com.sun.enterprise.iiop.security|_ThreadID=42;_ThreadName=Thread-2;ClassName=com.sun.enterprise.iiop.security.SecurityContextUtil;MethodName=setSecurityContext;|ABOUT TO EVALUATE TRUST|#]
[#|2014-07-28T14:02:42.183+0500|FINE|glassfish3.1.2|javax.enterprise.system.core.security.com.sun.enterprise.iiop.security|_ThreadID=42;_ThreadName=Thread-2;ClassName=com.sun.enterprise.iiop.security.SecClientRequestInterceptor;MethodName=receive_reply;|++++ Entered SecClientRequestInterceptor::receive_reply|#]
[#|2014-07-28T14:02:42.184+0500|FINE|glassfish3.1.2|javax.enterprise.system.core.security.com.sun.enterprise.iiop.security|_ThreadID=42;_ThreadName=Thread-2;ClassName=com.sun.enterprise.iiop.security.SecClientRequestInterceptor;MethodName=handle_null_service_context;|No SAS context element found in service context list|#]
[#|2014-07-28T14:02:42.184+0500|FINE|glassfish3.1.2|javax.enterprise.system.core.security.com.sun.enterprise.iiop.security|_ThreadID=42;_ThreadName=Thread-2;ClassName=com.sun.enterprise.iiop.security.SecClientRequestInterceptor;MethodName=setreplyStatus;|Status to be set : 0|#]
[#|2014-07-28T14:02:42.185+0500|FINE|glassfish3.1.2|javax.enterprise.system.core.security.com.sun.enterprise.iiop.security|_ThreadID=42;_ThreadName=Thread-2;ClassName=com.sun.enterprise.iiop.security.SecurityContextUtil;MethodName=receivedReply;|Passed status|#]
[#|2014-07-28T14:02:42.185+0500|FINE|glassfish3.1.2|javax.enterprise.system.core.security.com.sun.enterprise.iiop.security|_ThreadID=42;_ThreadName=Thread-2;ClassName=com.sun.enterprise.iiop.security.SecClientRequestInterceptor;MethodName=setreplyStatus;|Invoked receivedReply()|#]
If you are using log4j, you can create log4j categories and subsequent appenders to control logging.
E.g: Category:
log4j.category.javax.enterprise.system.core.security=WARN, S
Appender:
log4j.appender.S=org.apache.log4j.RollingFileAppender
log4j.appender.S.File=${myWebapp-instance-root}/log/External.log
log4j.appender.S.MaxFileSize=1MB
log4j.appender.S.MaxBackupIndex=10
log4j.appender.S.layout=org.apache.log4j.PatternLayout
log4j.appender.S.layout.ConversionPattern=%d %p %t %c - %m%n

Is it possible to log only one level messages with Log4J

If I set the log level to DEBUG, All messages with log level >= DEBUG will be logged/printed.
But can I set log level to only DEBUG, such that messages with log level only with DEBUG will be printed. Or can give a range like print all messages whose log level is >=DEBUG but < ERROR?
Maybe you can use a LevelMatchFilter?
At some situation, You have to write logs to different outputs according to the level. how can it be done by simply configuration of Log4j? There are some methods below.
http://wiki.apache.org/logging-log4j/LogToAppenderByLevel
As said Jarle you have to use LevelMatchFilter.
I will demonstrate it with one simple exam:
log4j.rootLogger = WARN, admin
log4j.appender.admin=org.apache.log4j.rolling.RollingFileAppender
log4j.appender.admin.rollingPolicy = org.apache.log4j.rolling.TimeBasedRollingPolicy
log4j.appender.admin.rollingPolicy.FileNamePattern = Files\\TestLevels-%d{dd-MM-yyy}.txt
log4j.appender.admin.layout = org.apache.log4j.PatternLayout
log4j.appender.admin.layout.ConversionPattern = Date: %d{dd-MM-yyyy} Time: %d{HH:mm:ss} Message [%m]%n
log4j.appender.admin.filter.01=org.apache.log4j.varia.LevelMatchFilter
log4j.appender.admin.filter.01.LevelToMatch=FATAL
log4j.appender.admin.filter.01.AcceptOnMatch=false
log4j.appender.admin.filter.02=org.apache.log4j.varia.LevelMatchFilter
log4j.appender.admin.filter.02.LevelToMatch=ERROR
log4j.appender.admin.filter.02.AcceptOnMatch=true
log4j.appender.admin.filter.03=org.apache.log4j.varia.LevelMatchFilter
log4j.appender.admin.filter.03.LevelToMatch=WARN
log4j.appender.admin.filter.03.AcceptOnMatch=false
In my source I append only ERROR messages to file with name TestLevels.txt

Categories

Resources