Java: Is this proper behavior of singleton class u

2019-08-18 04:57发布

I created the below wrapper for a singleton logger class so that I can log exceptions from any file and/or class. My inspiration comes from here: Logging to one file from multiple java files

I'm new to java and this is my first use of attempting to log exceptions to a file. While the following code does work, I noticed a few quirks I wanted to ask whether or not they were "normal behavior" or whether a workaround exists.

(1) Once the log file is created and has been written to with exceptions, if I edit the log file (e.g. remove some lines of text) then the log file is never written again from that moment forward. The web server needs to restart the domain associated with the web application before the log file is written to again. Is this normal? Ideally, I would like to retain only relevant errors in the log file, and delete the irrelevant ones, without needing to restart the web application's domain in the web server.

(2) If I delete the log file, then later an exception occurs in the java program(s), the log file does not get created again, and the exception is lost. Again, the web server needs to restart the domain associated with the web application before a new log file is created. Is this normal, or is there a workaround somehow by editing the below code? Ideally, I'd like to be able to delete the log file at any time and have the application create a new one.

Again, I'm new here so feel free to point out of the above intentions are bad design, etc.

------code follows------

Here's the file: LoggerWrapper.java

import java.io.OutputStream;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.logging.Logger;
import java.util.logging.Level;   
import java.util.logging.FileHandler;  
import java.util.logging.SimpleFormatter;

public class LoggerWrapper {
public static final Logger myLogger = Logger.getLogger("Test");
private static LoggerWrapper instance = null;  

 public static LoggerWrapper getInstance() {  
    if(instance == null) {  
        prepareLogger();  
        instance = new LoggerWrapper ();  
    }  
    return instance;  
 }  

private static void prepareLogger() {
try {
   FileHandler myFileHandler = new FileHandler("/path/to/myLogFile.log", true);  
   myFileHandler.setFormatter(new SimpleFormatter());  
   myLogger.addHandler(myFileHandler);  
   myLogger.setUseParentHandlers(false);  
   myLogger.setLevel(Level.ALL);
} catch (Exception e) {
   ...
}
}    
} 

To call the above code in a different file or class, issue these lines (for example):

LoggerWrapper loggerWrapper = LoggerWrapper.getInstance();
...
loggerWrapper.myLogger.log(Level.SEVERE, "some text here"+e.fillInStackTrace());

4条回答
2楼-- · 2019-08-18 05:07

You don't need to go to all of this trouble with logging. The log handler (and all of the alternatives, like logback, log4j) or a wrapper framework like Commons Logging or slf4j will do almost all of this work for you.

The most widely accepted method of using logging is to use a wrapper system (slf4j is very popular) and then just include the log class as a private static attribute of each class. Then you can do all of the configuration either with a separate program, or you can have configuration files that will set everything up for you.

If you want to set up your logging system in code (not the way I would do it, but you can...), do it in a static initializer that you know will load relatively early. Once the logging system has it's information, it won't need to be configured again.

查看更多
可以哭但决不认输i
3楼-- · 2019-08-18 05:10

I would suggest you just don't edit the files! And don't delete them!

HAHAHAHA, that would be an ace solution, no?

You should really use the open source logging (i've always liked log4j - most IB use that, or slf4j) that has been suggested by Jonathan - it is the standard way to do logging, nobody really does logging like you're doing it. At least, not that I am aware.

Ok, that said - and I do not know linux at all, in any shape or form - it sounds like, as Rick suggests, whatever you are pointing to disappears when you edit/delete the file. So, in pseudo-code (because, and i am sorry for this - as i indicated, i use windows so cannot test):

public class LoggerWrapper {
    *private* FileHandler myFileHandler;
    *private* static final Logger myLogger = Logger.getLogger("Test");
    private static LoggerWrapper instance = null;  

    /*
      here check if the file you're using has been changed! If so, re-do the file setting
    */
    public void log(Level level, String message){
        //argh you are on your own here. I don't know how to *check* the file being used by the file handler...
        //you know what? you can just do this (but it isn't too clean)
        myLogger.removeFileHandler(myFileHandler);
        myFileHandler = new FileHandler("/path/to/myLogFile.log", true); 
        myLogger.addHandler(myFileHandler);
        myLogger.log(level,message);     
    }  

    private static void prepareLogger() {
        try {
            //don't shadow the myFileHandler by accident!
            myFileHandler = new FileHandler("/path/to/myLogFile.log", true); 

...

of course, that just resets the file handler every time you log. And you won't log with the command:

loggerWrapper.myLogger.log(Level.SEVERE, "some text here"+e.fillInStackTrace());

but with

loggerWrapper.log(Level.SEVERE, "some text here"+e.fillInStackTrace());

Or just use open source logging (log4j!) and be happy! There might be some way to check if the file is lost - oh! maybe check the isLoggable method? I don't know if that will pick up on changed files... i don't think it does though.

Also, you might need to setErrorManager on your fileHandler - from the looks of things, if the logger cannot, well, log, it sends something to the errorManager. I am unfamiliar with this though, and i might be speaking jibberish.

查看更多
Root(大扎)
4楼-- · 2019-08-18 05:22

I'm assuming this is running on linux? When you open the file it's pointing to a reference to that file. When you delete the file the reference is gone, but since you saved the reference in a static variable, your code is now holding a file handle that points to nothing. Instead you should do something like

cat /dev/null > file

Which will just copy nothing over the file without changing the actual inode that the file points to.

查看更多
狗以群分
5楼-- · 2019-08-18 05:24

Have you seen this ?

It may have to do with your editor/os. The poster from the linked question had a similar problem with log4j.

As the other answer states, to clear out the log file w/o disturbing the handler:

cat /dev/null > file.log
查看更多
登录 后发表回答