java logger calling from another class - java

I'm learning this logger from java and trying to call the class MyLogger from the main class but it seems not to be working
MyLogger.java
public class MyLogger {
public MyLogger() {
Logger logger = Logger.getLogger("MyLog");
FileHandler fh;
try {
fh = new FileHandler("c:\\opt\\MyLogFile.log", true);
logger.addHandler(fh);
logger.setLevel(Level.ALL);
SimpleFormatter formatter = new SimpleFormatter();
fh.setFormatter(formatter);
logger.log(Level.WARNING,"My first log");
} catch (SecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client.java
public class Client {
private final static Logger LOGGER = Logger.getLogger(Client.class.getName());
public static void main(String[] args) {
LOGGER.setLevel(Level.SEVERE);
LOGGER.getName();
LOGGER.getClass();
LOGGER.info("ABC");
}
}
Why is it not calling the MyLogger.java to create the log file?
Is there a beter way to log the eclipse console rather than putting LOGGER on each methods for each class?
Why some uses flush() before closing the log file?

Why is it not calling the MyLogger.java to create the log file?
If it refers to running Client, then that's because there is no relation between that class and your MyLogger class.
Is there a beter way to log the eclipse console rather than putting
LOGGER on each methods for each class?
Better is very subjective. The majority of source code I've seen use the paradigm you're using in your Client class. That is, declaring a static final Logger with the name of enclosing class and using it where you need to log something within that class.
Some applications make use of AOP concepts for logging.
Why some uses flush() before closing the log file?
Some implementations may buffer log messages so as not to make many small IO system calls, but instead make few big ones. Closing the log file may not flush the buffer, so you'll want to flush it explicitly.

Related

Java Logger usage

I made a custom logger for my project by using java.util.logging:
public class SpotifyLogger {
private static final Logger LOGGER = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
public SpotifyLogger(String loggerFilePath) throws IOException {
Logger myLogger = Logger.getLogger("");
// suppress console messaging
Handler[] handlers = myLogger.getHandlers();
if (handlers[0] instanceof ConsoleHandler) { //exception occurs here
myLogger.removeHandler(handlers[0]);
}
// set level
LOGGER.setLevel(Level.SEVERE);
// create a txt handler
FileHandler textFileHandler = new FileHandler(loggerFilePath);
SimpleFormatter simpleFormatter = new SimpleFormatter();
textFileHandler.setFormatter(simpleFormatter);
LOGGER.addHandler(textFileHandler);
}
public void log(String user, Exception e) {
LOGGER.log(Level.SEVERE, user, e);
}
}
For the client and the server parts of my program, I create two separate Logger objects:
// class member initialized as null, because of exception handling
private SpotifyLogger logger = null;
//...
//in constructor:
this.logger = new SpotifyLogger(LOGGER_FILE_NAME); // the LOGGER_FILE_NAME is different for the client and the server
When I test my program manually, the loggers seem to work (the two log files contain exceptions that I have caused). Then, I wrote automatic tests. For each class that I am testing (a total of 5), I create a separate logger object with a different destination path. The tests (for whichever class comes first) work correctly. All other tests fail because I get an ArrayIndexOutOfBoundsException, when I initialize the logger for that particular class. The reason is that I am trying to access handlers[0], when handlers has 0 length. From what I understood after searching the web, this is because the logger is using parent handlers. I tried this:
public SpotifyLogger(String loggerFilePath) throws IOException {
Logger myLogger = Logger.getLogger("");
// suppress console messaging
myLogger.setUseParentHandlers(false);
Handler[] handlers = myLogger.getHandlers();
if (handlers.length > 0) {
if (handlers[0] instanceof ConsoleHandler) {
myLogger.removeHandler(handlers[0]);
}
}
//etc
}
I don't get an exception anymore but the logging doesn't work. What am I doing wrong?
If you want different Loggers, you need to supply different names for each. Hence this line of your code (in SpotifyLogger constructor) always returns the same Logger.
Logger myLogger = Logger.getLogger("");
This actually returns the java.util.logging.LogManager.RootLogger which has a single Handler which is an instance of ConsoleLogger. You subsequently remove that Handler in the first invocation of SpotifyLogger constructor, hence in every subsequent invocation, method getHandlers returns an empty array.
Since you only ever add Handlers to the global Logger, another FileHandler is added to the global logger every time SpotifyLogger constructor is called. I have not verified but I believe that a Logger will use the first, appropriate Handler in the array returned by method getHandlers, hence the behavior you are seeing whereby only the first log file is being written to, i.e. the file that you passed to the first invocation of SpotifyLogger constructor.
Note that you have not provided a reproducible example so I cannot verify any of the above with regard to your context. I only tested the code in your question in order to arrive at the above.
Consider the following rewrite of class SpotifyLogger – including a main method for testing purposes only.
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
public class SpotifyLogger {
private static final String[] NAMES = {"First", "Second"};
private static int count;
private int index;
public SpotifyLogger(String loggerFilePath) throws IOException {
index = count;
Logger myLogger = Logger.getLogger(NAMES[count++]);
myLogger.setUseParentHandlers(false);
// set level
myLogger.setLevel(Level.SEVERE);
// create a txt handler
FileHandler textFileHandler = new FileHandler(loggerFilePath);
SimpleFormatter simpleFormatter = new SimpleFormatter();
textFileHandler.setFormatter(simpleFormatter);
myLogger.addHandler(textFileHandler);
}
public void log(String user, Exception e) {
Logger myLogger = Logger.getLogger(NAMES[index]);
myLogger.log(Level.SEVERE, user, e);
}
public static void main(String[] args) {
try {
SpotifyLogger x = new SpotifyLogger("spotifyx.log");
SpotifyLogger y = new SpotifyLogger("spotifyy.log");
x.log("George", new Exception());
y.log("Martha", new RuntimeException());
}
catch (IOException x) {
x.printStackTrace();
}
}
}
Note that you are correct regarding parent Handlers, hence the following line in the above code:
myLogger.setUseParentHandlers(false);
After running the above code, the contents of file spotifyx.log is:
Feb 12, 2022 2:12:28 PM javalogp.SpotifyLogger log
SEVERE: George
java.lang.Exception
at javalogp/javalogp.SpotifyLogger.main(SpotifyLogger.java:38)
And the contents of file spotifyy.log is:
Feb 12, 2022 2:12:28 PM javalogp.SpotifyLogger log
SEVERE: Martha
java.lang.RuntimeException
at javalogp/javalogp.SpotifyLogger.main(SpotifyLogger.java:39)
And no log messages are written to the console.
This doesn't make much sense to me
Logger myLogger = Logger.getLogger("")
Reference: Oracle java docs

Simplest possible setting Java logging level, and it still fails. But, System.out.println still works

I am having problems getting logging to print out in some of my constructors. With others, logging is working just as I would expect.
I have attempted to eliminate every possible source of confusion by going with defaults, and by explicitly setting the log levels within the class itself. I've tried instantiating the logger as both a static and instance variable.
But, even setting the logging level to "Level.ALL" doesn't seem to be working in some of the classes.
For instance loggers, I have been setting the logging level within an instance-initializer / anonymous block. For the static instance, I am using the static block to set the logging level.
Any ideas why the log messages aren't printing out in the classes below?
Note: Code has been edited to show the fix, based on comment by #jmehrens
public abstract class ReadFileInformation extends SimpleFileVisitor<Path> {
static public ConsoleHandler globalConsoleHandler = new ConsoleHandler(); // fix, based on comment by #jmehrens
static private final Logger logger = Logger.getLogger(ReadFileInformation.class.getName());
static { // fix: See comment by #jmehrens
globalConsoleHandler.setLevel(Level.ALL);
logger.addHandler(globalConsoleHandler);
}
{
logger.setLevel(Level.ALL);
logger.log(Level.FINEST, String.format("This does NOT print.\n"));
System.out.println("In ReadFileInformation Static Block. This prints out!");
}
}
public class ReadMetadateFileInformation extends ReadFileInformation {
static private final Logger logger = Logger.getLogger(ReadMetadateFileInformation.class.getName());
static {
logger.setLevel(Level.ALL);
logger.log(Level.FINEST, String.format("This does NOT print.\n"));
System.out.println("In ReadMetadateFileInformation Static Block. This prints out!");
}
{
logger.log(Level.FINEST, String.format("This does NOT print.\n"));
System.out.println("In ReadMetadateFileInformation Anonymous Block. This prints out!");
}
public ReadMetadateFileInformation() {
super();
logger.log(Level.FINE, String.format("This does NOT print.\n"));
}
}
Per the java.util.logging.ConsoleHandler docs:
.level specifies the default level for the Handler (defaults to Level.INFO).
You are adjusting the logger to set the level to ALL which will produce the log records you want to see. However, the ConsoleHandler will filter them because the default level of the ConsoleHandler is INFO. Therefore, you have to adjust the level of the ConsoleHandler too. You need to do one of the following:
Add a ConsoleHandler and set the level to ALL.
Modify the root ConsoleHandler to set the level to ALL.
Since you are modifying the logger configuration via code it might be easier to do #1.
ConsoleHandler ch = new ConsoleHandler();
ch.setLevel(Level.ALL);
logger.addHandler(ch);
logger.setLevel(Level.ALL);
logger.log(Level.FINEST, String.format("This does NOT print.\n"));
You also have to ensure you don't add the ConsoleHandler multiple times to the logger as each handler add will result in duplicated console output.

How to make logs print only on files without being printed out on a console?

Although I've configured handler to write logs to files structure, but I get the log on the console bar when I run the program, how can I masquerade logs so it will only be written on files without exposing to console.
static {
System.setProperty("java.util.logging.config.file",
"log.properties");
//must initialize loggers after setting above property
}
static Logger logger = Logger.getLogger("com.debugz");
public static void main(String[] args) {
try {
FileHandler h = new FileHandler("%h/file_%g.log",1,4);
h.setFormatter(new SimpleFormatter());
logger.addHandler(h);
logger.log(Level.INFO,"Hello");
}
catch (Exception error){
System.out.println("Error : "+error.getMessage());
}
}
You may try logger.setUseParentHandlers(false);
void java.util.logging.Logger.setUseParentHandlers(boolean useParentHandlers)
Specify whether or not this logger should send its output to its parent Logger. This means that any LogRecords willalso be written to the parent's Handlers, and potentially to its parent, recursively up the namespace.
Parameters: useParentHandlers true if output is to be sent to the logger's parent.
The above won't work for your use case if a ConsoleHandler has been explicitely added to the logger e.g. logger.addHandler(new ConsoleHandler()); in which case, you may remove that handler if needed via logger.removeHandler(<handlerToBeRemoved>)
Hope that helps! Cheers

Java logger problem

I would like to record the logs of my Java application.
I have created this class:
public class Log {
final Logger logger = Logger.getLogger("DigiScope.log");
public static void main(String[] args) {
}
public Log(String message) {
try {
// Create an appending file handler
boolean append = true;
FileHandler handler = new FileHandler("my.log", append);
// Add to the desired logger
Logger logger = Logger.getLogger("com.mycompany");
logger.addHandler(handler);
logger.info(message);
} catch (IOException e) {
}
}
}
And for each button I have a code like that:
private void btnNewPatient ActionPerformed(java.awt.event.ActionEvent evt) {
Log a = new Log("New Patient created");
}
This code creates a log.txt, but records only the click on the first button, the others clicks on the others buttons are not record.
Can you help me?
Thank you.
It doesn't make much sense to create a proprietary logging wrapper in your app - java.util.logging is already such a wrapper, so I recommend using it directly. You should create logger objects in your classes, then log messages within handler methods something like this:
logger.info("New Patient created");
And you should use the same Logger instance throughout your class, instead of creating new instances all the time. The standard way is to create one static final instance per class.
It is also better to configure logging from a config file, not from code.
I recommend reading through the Java Logging Tutorial.
Péter Török and StriplingWarrior are right with their suggestion to use the Logging framework in the right way:
logger.info("New Patient created");
instead of creating a new Logger for each statement.
But even with your construction, you should have a logfile with all logging information.
For each invocation of the Log constructor, a new my.log.X file is created (X is a number). And from this point in time each log statement is logged in this file.
So if you invoke the constructor three times (with message: "first", "second", "third") then you should have the files: my.log, my.log.1. my.log.2
my.log: "first", "second", "third"
my.log.1: "second", "third"
my.log.2: "third"
I'm guessing that it's probably logging each click, but you're reopening the file with each new log message, rather than appending to it.

Problem with java.util.logging and Lock file

I have an application that scans a set of files. And this scanning take place parallely. I mean if I upload 5 files, five process will be created and start executing the job parallely. Now For logging the exceptions for the jobs running, there is only one log file. The problem that is coming is, the logger creates a lot of logs files as -
mylogfile.log(actual log file)
mylogfile.log.1
mylogfile.log.2
mylogfile.log.3
mylogfile.log.4
mylogfile.log.5
...
with their respective lock files.
Below is the code snippet that I used:
public static Logger getLogger(final String className) {
final Logger logger = Logger.getLogger(className);
FileHandler fh;
try {
// This block configure the logger with handler and formatter
fh = new FileHandler("mylogfile.log", true);
logger.addHandler(fh);
logger.setLevel(Level.ALL);
logger.setUseParentHandlers(false);
fh.setFormatter(new SimpleFormatter());
} catch (final SecurityException e) {
// }
} catch (final IOException e) {
//
}
return logger;
}
How do I make sure that only one log file should be used to write the exception of all the jobs running parallely..??
Thanks,
Anish
I face the same problem and what I was missing is an standard programming practice that I should close the filehandler after I finish the logging.
So you can create multiple loggers but make sure you close them at the end.
Following 2 lines in below example:
successLogFileHandler.close();
failureLogFileHandler.close();
class LoggerExample {
private Logger loggerFailure;
private Logger loggerSuccess;
public void myLogger() {
// some code block
FileHandler successLogFileHandler = new FileHandler(successLogFile.getAbsolutePath());
FileHandler failureLogFileHandler = new FileHandler(failureLogFile.getAbsolutePath());
// Create loggers
loggerFailure = createLogger(STR_FAILURE_LOG_FILE, failureLogFileHandler, Level.INFO, customFormatter);
loggerSuccess = createLogger(STR_SUCCESS_LOG_FILE, successLogFileHandler, Level.INFO, customFormatter);
// Write messages into loggers
// and at the end close the file handlers
successLogFileHandler.close();
failureLogFileHandler.close();
}
public static Logger createLogger(String strLoggerName, FileHandler handler, Level level, Formatter formatter) throws Exception
{
Logger logger = Logger.getLogger(strLoggerName);
logger.setLevel(level);
handler.setFormatter(formatter);
logger.addHandler(handler);
return logger;
}
}
You can use a singlton locator class that you can retrieve the logger from, that would force your application to use one logger (which means you'll have one log file)
class LoggerLocator {
private static LoggerLocator locator = new LoggerLocator();
private Logger logger;
/**
*
*/
private LoggerLocator() {
initLogger();
}
/**
* #return
*/
public static LoggerLocator getLocator(){
return locator;
}
/**
* #return
*/
public Logger getLogger() {
return logger;
}
/**
*
*/
private void initLogger() {
logger = Logger.getLogger("My General Logger");
FileHandler fh;
try {
// This block configure the logger with handler and formatter
fh = new FileHandler("mylogfile.log", true);
logger.addHandler(fh);
logger.setLevel(Level.ALL);
logger.setUseParentHandlers(false);
fh.setFormatter(new SimpleFormatter());
} catch (final SecurityException e) {
// }
} catch (final IOException e) {
//
}
}
}
In your jobs you will get the logger by the following call:
Logger logger = LoggerLocator.getLocator().getLogger();
This does not have much to do with parallel calls. As well from single thread with each call to your getLogger (even with same string as argument) you create a new FileHandler and add it to existing logger.Maybe you do not want to do all of the setup each time when you call your getLogger-method.
//now we will create new Filehandler and set it to logger
getLogger("identifier").log(Level.SEVERE, "Log to one file");
//now we have already one filehandler, but lets add one more
getLogger("identifier").log(Level.SEVERE, "Log to two files");
//now we have already two filehandlers, but lets add one more
getLogger("identifier").log(Level.SEVERE, "Log to three files");
Configure logging once and after that you can get reference to logger via java.util.loggingLogger.getLogger. Overview from Sun gives more ideas how to configure logging via properties files.

Categories

Resources