/************************************************************************** OmegaT - Computer Assisted Translation (CAT) tool with fuzzy matching, translation memory, keyword search, glossaries, and translation leveraging into updated projects. Copyright (C) 2008 Alex Buloichik 2013 Didier Briel Home page: http://www.omegat.org/ Support center: http://groups.yahoo.com/group/OmegaT/ This file is part of OmegaT. OmegaT is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OmegaT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. **************************************************************************/ package org.omegat.util.logging; import java.io.File; import java.io.FileFilter; import java.io.FileOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Comparator; import java.util.Date; import java.util.logging.ErrorManager; import java.util.logging.Level; import java.util.logging.LogManager; import java.util.logging.LogRecord; import java.util.logging.StreamHandler; import org.omegat.util.OStrings; import org.omegat.util.StaticUtils; /** * File handler for standard logging for support logrotating(on startup only) * and file naming with datetime part. * * This handler will create 'OmegaT.log' for OmegaT(and OmegaT-1.log, * OmegaT-2.log for next instances which runned in the same time). logrotate * will work only on create handler, i.e. logs from one OmegaT run will be only * in one log file. It means, what log file can be much longer than maxinum file * size. Maximum file size used only on startup for decide: should we rotate * logs or not. * * Rotated logs will be named like 'OmegaT.20080325.1800.log'. * * @author Alex Buloichik (alex73mail@gmail.com) */ public class OmegaTFileHandler extends StreamHandler { private String logFileName; private File lockFile; private FileOutputStream lockStream; private final long maxSize; private final int count; public OmegaTFileHandler() throws IOException { LogManager manager = LogManager.getLogManager(); String cname = getClass().getName(); String level = manager.getProperty(cname + ".level"); if (level != null) { setLevel(Level.parse(level.trim())); } String maxSizeStr = manager.getProperty(cname + ".size"); if (maxSizeStr != null) { maxSize = Long.parseLong(maxSizeStr); } else { maxSize = 1024 * 1024; } String countStr = manager.getProperty(cname + ".count"); if (countStr != null) { count = Integer.parseInt(countStr); } else { count = 10; } openFiles(new File(StaticUtils.getConfigDir(), "logs")); } /** * @return the name of the current log file */ public String getOmegaTLogFileName(){ return logFileName; } /** * Open log file and lock. */ private void openFiles(final File dir) throws IOException { dir.mkdirs(); for (int instanceIndex = 0; instanceIndex < 100; instanceIndex++) { String fileName = OStrings.getApplicationName() // Instance index + (instanceIndex > 0 ? ("-" + instanceIndex) : ""); lockFile = new File(dir, fileName + ".log.lck"); logFileName = fileName; // try to create lock file lockStream = new FileOutputStream(lockFile); if (lockStream.getChannel().tryLock() != null) { rotate(dir, fileName); setEncoding(StandardCharsets.UTF_8.name()); setOutputStream(new FileOutputStream(new File(dir, fileName + ".log"), true)); break; } } setErrorManager(new ErrorManager()); } @Override public synchronized void close() throws SecurityException { try { lockStream.close(); lockFile.delete(); } catch (Exception ex) { // shouldn't happen ex.printStackTrace(); } } /** * Rotate log files if need. */ private void rotate(final File dir, final String fileName) { File logFile = new File(dir, fileName + ".log"); if (!logFile.exists() || logFile.length() < maxSize) { // do not need to rotate return; } String suffix = new SimpleDateFormat("yyyyMMdd.HHmm").format(new Date()); File destFile = new File(dir, fileName + '.' + suffix + ".log"); logFile.renameTo(destFile); File[] oldLogs = dir.listFiles(new FileFilter() { public boolean accept(File pathname) { return pathname.getName().startsWith(fileName + '.') && pathname.getName().endsWith(".log"); } }); if (oldLogs != null) { Arrays.sort(oldLogs, new Comparator<File>() { public int compare(File o1, File o2) { return o2.getName().compareToIgnoreCase(o1.getName()); } }); for (int i = count; i < oldLogs.length; i++) { oldLogs[i].delete(); } } } @Override public synchronized void publish(LogRecord record) { if (isLoggable(record)) { super.publish(record); flush(); } } }