Nicolas Villacorta
Nicolas Villacorta

Reputation: 341

Best way for closing FileHandler on REST API's

I don't know how to handle my FileHandler on API REST

I have a REST API installed at Weblogic, I'm using Java Logging and when my app starts, inits the logger, and open the FileHandler. Like i never close the FileHandler the .lck file that is created stays at my logs folder. I really don't care the presence of that file, but when i redeploy the app, like the FileHandler is still open, my app starts a new log file (ex: myLog.log.0, myLog.log.1). I have read that JVM itself should be closing FileHandler but that is not happening. I have tried to addShutodownHook for closing FileHandler, but that code is not working, if I redeploy the app, it still stays open.

@ApplicationPath("api")
public class GenericApplication extends Application {
    public GenericApplication() {
        initSwagger();
        initLog();

        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                CtgLogger.fileJson.close();
                // fileJson is my FileHandler, i made it public static to call him here.
            }
        });
    }

My initLog() method just calls the next CtgLogger.setup()...

public static void setup() throws IOException {
    Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
    String level = PropertiesUtil.get("ctg.log.level");
    logger.setLevel(LEVEL_MAP.get(level));

    String filePath = PropertiesUtil.get("ctg.log.path");
    String fileSize = PropertiesUtil.get("ctg.log.max.size");
    String fileCount = PropertiesUtil.get("ctg.log.max.count");
    if (StringUtils.isNotEmpty(fileSize) && StringUtils.isNotEmpty(fileSize) &&
        NumberUtils.isNumber(fileSize) && NumberUtils.isNumber(fileCount)) {
        fileJson = new FileHandler(filePath != null ? filePath : DEFAULT_LOG_NAME,
            Integer.parseInt(fileSize), Integer.parseInt(fileCount), true);
    } else {
        fileJson = new FileHandler(filePath != null ? filePath : DEFAULT_LOG_NAME);
    }
    jsonFormatter = new JsonCustomFormatter();
    fileJson.setFormatter(jsonFormatter);
    for (Handler h: logger.getHandlers())
        h.close();
    logger.addHandler(fileJson);
}

And that's all, then I just call my endpoints and use my logger.

My question is, should I open and close my FileHandler each time a endpoint is called? Or is there a better way for doing this?

Upvotes: 0

Views: 165

Answers (1)

jmehrens
jmehrens

Reputation: 11045

My question is, should I open and close my FileHandler each time a endpoint is called? Or is there a better way for doing this?

No need to open and close every time the endpoint is called.

  1. Remove the shutdown hook code. The LogManager will close any attached file handler for you on shutdown.
  2. Change logger to a static final reference so it is impossible to garbage collect. This ensures your settings are maintained.
  3. Since you are using JavaEE use the javax.annotation.PostConstruct and javax.annotation.PreDestroy annotations to manage your logger settings.
  4. If you close a FileHandler manually, make sure you call Logger::remove(Handler) so that handler can be garbage collected. You current code only closes the handler.
    private final Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
    private volatile FileHandler fileJson;

    public void preDestroy() {
       Handler h = this.fileJson;
       this.fileJson = null;
       if (h != null) {
           h.close();
       }
       logger.removeHandler(h);  
    }

    @PostConstruct 
    public void setup() throws IOException {
        if (fileJson != null) {
            preDestroy();
        }

        String level = PropertiesUtil.get("ctg.log.level");
        logger.setLevel(LEVEL_MAP.get(level));

        String filePath = PropertiesUtil.get("ctg.log.path");
        String fileSize = PropertiesUtil.get("ctg.log.max.size");
        String fileCount = PropertiesUtil.get("ctg.log.max.count");
        if (StringUtils.isNotEmpty(fileSize) && StringUtils.isNotEmpty(fileSize) &&
        NumberUtils.isNumber(fileSize) && NumberUtils.isNumber(fileCount)) {
            fileJson = new FileHandler(filePath != null ? filePath : DEFAULT_LOG_NAME,
                Integer.parseInt(fileSize), Integer.parseInt(fileCount), true);
        } else {
               fileJson = new FileHandler(filePath != null ? filePath : DEFAULT_LOG_NAME);
        }
        jsonFormatter = new JsonCustomFormatter();
        fileJson.setFormatter(jsonFormatter);
        for (Handler h: logger.getHandlers()) {
            h.close();
            logger.removeHander(h);
        }
        logger.addHandler(fileJson);
    }

Upvotes: 1

Related Questions