java.util.logging.Logger prints the Message twice in console - java

I am running a jar file in a console and I put logger so I can trace the if there are any errors. However, the message info prints twice in the console. Can I prevent this?
My code:
public static void main(String[] args) {
Logger log = Logger.getLogger("Logger");
log.setLevel(Level.ALL);
ConsoleHandler handler = new ConsoleHandler();
handler.setFormatter(new SimpleFormatter());
handler.setLevel(Level.ALL);
log.addHandler(handler);
log.log(Level.INFO, "Reading Configuration File");
}
Console:
Jul 22, 2015 9:30:33 PM com.ouc.mv90.conversion.CSVtoMV90Converter main
INFO: Reading Configuration File
Jul 22, 2015 9:30:33 PM com.ouc.mv90.conversion.CSVtoMV90Converter main
INFO: Reading Configuration File

Get ready for a facepalm. This question is basically a duplicate of this SO question, but I am giving an answer anyway.
What is happening is that your Logger class already has a default handler which prints to the System.out console. I expect that just the following code will generate output in your console:
Logger log = Logger.getLogger("Logger");
log.setLevel(Level.ALL);
log.log(Level.INFO, "Reading Configuration File");
But you have gone above and beyond this by adding a second handler which also is directed towards the console. Remove this second handler and that should take care of duplicate messages.

I have run into this problem and in my case the solution was:
Logger logger = Logger.getLogger("Logger");
ConsoleHandler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(Level.ALL);
logger.addHandler(consoleHandler);
logger.setLevel(Level.ALL);
logger.setUseParentHandlers(false);
Notice the last line that calls to setUseParentHandlers. Without this line I get duplicate logs. I have checked at run time that in my case the number of handlers returned by logger.getHandlers() is just 1 after adding my console handler.
If I try
Logger logger = Logger.getLogger("Logger");
logger.setLevel(Level.ALL);
logger.log(Level.INFO, "Reading Configuration File");
logger.log(Level.FINE, "another message");
in this case I don't get duplicate logs but I don't get anything finer than INFO level either.

Just remove all handlers before add it to your logger, like :
for (Handler handler : logger.getHandlers()) { logger.removeHandler(handler);}

public static void main(String[] args) {
Logger log = Logger.getLogger("Logger");
log.setLevel(Level.ALL);
log.log(Level.INFO, "Reading Configuration File");
}
The above code itself is sufficient to print your log once with it's default log handler. When you add handlers, it will only print in the console using it's default handler, the logging is also directed to your all added handlers to print. Since you are adding another console handler to your logger, veerything will get printed (logged on the console) twice.

Related

Fine level messages aren't showing

My .FINE log messages aren't showing in the output.
public void playerCoinUpdate(Player player, Coin coin, GameEngine engine)
{
String update = String.format(player.getPlayerName() +" coin " + coin.getNumber() + "flipped to " + coin.getFace() + "\n");
// intermediate results logged at Level.FINE
logger.log(Level.FINE, update);
}
It should output a message to the console.
The message will not show if your logger level is higher than the message level. This can be fixed by changing the logger level:
logger.setLevel(level.FINE);
This will now log messages that are level FINE and above. So levels FINER and FINEST will be ignored. Alternatively, you could allow all messages to be logged by using this:
logger.setLevel(level.ALL);
The Java doc has other useful information regarding logging.

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.

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

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)

How to use JMS Appender?

Inmy research about JMS Appenders I've found turorial1 and tutorial2 . I've tried to follow them, but I couldn't run example program.
Fistly I created file log4j.properties
log4j.rootLogger=INFO, stdout, jms
#
log4j.logger.org.apache.activemq=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %-5p %c - %m%n
#
log4j.appender.jms=org.apache.log4j.net.JMSAppender
log4j.appender.jms.InitialContextFactoryName=org.apache.activemq.jndi.ActiveMQInitialContextFactory
log4j.appender.jms.ProviderURL=tcp://localhost:61616
log4j.appender.jms.TopicBindingName=logTopic
log4j.appender.jms.TopicConnectionFactoryBindingName=ConnectionFactory
and jndi.properties
topic.logTopic=logTopic
Then I added Receiver.java to my project
public class Receiver implements MessageListener {
public Receiver() throws Exception {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616");
Connection conn = factory.createConnection();
Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
MessageConsumer consumer = sess.createConsumer(sess.createTopic("logTopic"));
consumer.setMessageListener(this);
Logger log = Logger.getLogger(Receiver.class);
log.info("Test log");
Thread.sleep(1000);
consumer.close();
sess.close();
conn.close();
System.exit(1);
}
public static void main(String[] args) throws Exception {
new Receiver();
}
#Override
public void onMessage(Message message) {
try {
// receive log event in your consumer
LoggingEvent event = (LoggingEvent)((ActiveMQObjectMessage)message).getObject();
System.out.println("Received log [" + event.getLevel() + "]: "+ event.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
}
}
I need make Receiver to gather all logs from project, but I cannot even run this simple example. Probably I don't know how to configure it correctly, because I get this output:
log4j:WARN No appenders could be found for logger (org.apache.activemq.transport.WireFormatNegotiator).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Did I miss adding some lines in code or some files to classpath? I'm new to log4j.
EDIT:
I set Logger in AspectJ class. But I think that also in Receiver Logger is created and log is sent, so probably it should be done in Receiver, not in other class in my project.
static final Logger logger = Logger.getLogger(ReportingAspect.class);
#Before("setLoggingFile()")
public void setProperties() {
PropertyConfigurator.configure("log4j.properties");
}
ProjectJMS
|
\_ src
| \_ packages...
\_jndi.propeties
\_log4j.properties
To configure log4j use :
-Dlog4j.configuration= path to config file
Path to conf file CAN be:
À file in a path outside of classpath , if so préfix it with file:/// , example:
-Dlog4j.configuration=file:/c:/foobar.lcf
Else in classpath in That case:
-Dlog4j.configuration=foobar.lcf where foobar.lcf is at root of your source folder
See:
http://logging.apache.org/log4j/1.2/manual.html
For jms:
-Add jms.jar at least to classpath
ensure you have a JMS broker running ( activemq for example)
Regards
Philippe
You need to move the log4j.properties under 'src' folder so it'll be included in the classpath, since it's not there it is not being loaded.
Have you validated, that your Method setProperties() is called before you used your logger?
Usually that kind of error only pops up, when either the configuration file (log4j.properties) was not found while initializing log4j by PropertyConfigurator, or you tried to log something before you initialized log4j with your PropertyConfigurator.
First your should make sure, that setProperties() is called the way you expect it to be called and if this should work you could try to validate if the configuration can be loaded. From what I see, I guess your configuration file should be found. To validate this, you could load the configuration in several steps to make sure, it was found:
Properties props = new Properties();
props.load( new FileInputStream( "log4j.properties" ) );
PropertyConfigurator.configure( props );
If your configuration will not be found, you'll receive a FileNotFoundException.

Categories

Resources