package mightypork.utils.logging; import java.io.File; import java.io.FileFilter; import java.io.PrintWriter; import java.io.StringWriter; import java.text.SimpleDateFormat; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.logging.FileHandler; import java.util.logging.Formatter; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; import mightypork.utils.files.FileUtils; /** * Static logger class. * * @author MightyPork * @copy (c) 2014 */ public class LogInstance { /** log file */ private File file; /** Log name */ private String name; /** Number of old logs to keep */ private int logs_to_keep; /** Logs dir */ private File dir; /** Logger instance. */ private Logger logger; /** Logging enabled */ private boolean enabled = true; private boolean sysout = true; private int monitorId = 0; private HashMap monitors = new HashMap(); private LogToSysoutMonitor sysoutMonitor; public LogInstance(String name, File dir, int oldLogCount) { this.name = name; this.file = new File(dir, name + getSuffix()); this.dir = dir; this.logs_to_keep = oldLogCount; init(); } /** * Prepare logs for logging */ private void init() { logger = Logger.getLogger(name); cleanup(); FileHandler handler = null; try { handler = new FileHandler(file.getPath()); } catch (Exception e) { throw new RuntimeException("Failed to init log", e); } handler.setFormatter(new LogFormatter()); logger.addHandler(handler); enabled = true; sysoutMonitor = new LogToSysoutMonitor(); addMonitor(sysoutMonitor); logger.setUseParentHandlers(false); logger.setLevel(Level.ALL); logger.info("Main logger initialized."); logger.info((new SimpleDateFormat("yyyy/MM/dd HH:mm:ss")).format(new Date())); } private void cleanup() { if (logs_to_keep == 0) return; // overwrite for (File f : FileUtils.listDirectory(file.getParentFile())) { if (!f.isFile()) continue; if (f.equals(file)) { Date d = new Date(f.lastModified()); String fbase = name + '_' + (new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss")).format(d); String suff = getSuffix(); String cntStr = ""; File f2; for (int cnt = 0; (f2 = new File(dir, fbase + cntStr + suff)).exists(); cntStr = "_" + (++cnt)); f.renameTo(f2); } } if (logs_to_keep == -1) return; // keep all List oldLogs = FileUtils.listDirectory(dir, new FileFilter() { @Override public boolean accept(File f) { if (f.isDirectory()) return false; if (!f.getName().endsWith(getSuffix())) return false; if (!f.getName().startsWith(name)) return false; return true; } }); Collections.sort(oldLogs, new Comparator() { @Override public int compare(File o1, File o2) { return o1.getName().compareTo(o2.getName()); } }); for (int i = 0; i < oldLogs.size() - logs_to_keep; i++) { oldLogs.get(i).delete(); } } /** * Add log monitor * * @param mon monitor * @return assigned ID */ public synchronized int addMonitor(LogMonitor mon) { int id = monitorId; monitorId++; monitors.put(id, mon); return id; } /** * Remove a monitor by ID * * @param id monitor ID */ public synchronized void removeMonitor(int id) { monitors.remove(id); } /** * Enable logging. * * @param flag do enable logging */ public void enable(boolean flag) { enabled = flag; } /** * Enable printing logs to sysout * * @param flag do enable logging */ public void enableSysout(boolean flag) { sysout = flag; sysoutMonitor.enable(sysout); } /** * Log FINE message * * @param msg message */ public void f1(String msg) { if (enabled) logger.log(Level.FINE, msg); } /** * Log FINER message * * @param msg message */ public void f2(String msg) { if (enabled) logger.log(Level.FINER, msg); } /** * Log FINEST message * * @param msg message */ public void f3(String msg) { if (enabled) logger.log(Level.FINEST, msg); } /** * Log INFO message * * @param msg message */ public void i(String msg) { if (enabled) logger.log(Level.INFO, msg); } /** * Log WARNING message (less severe than ERROR) * * @param msg message */ public void w(String msg) { if (enabled) logger.log(Level.WARNING, msg); } /** * Log ERROR message * * @param msg message */ public void e(String msg) { if (enabled) logger.log(Level.SEVERE, msg); } /** * Log THROWING message * * @param msg message * @param thrown thrown exception */ public void e(String msg, Throwable thrown) { if (enabled) logger.log(Level.SEVERE, msg + "\n" + getStackTrace(thrown)); } /** * Log exception thrown * * @param thrown thrown exception */ public void e(Throwable thrown) { if (enabled) logger.log(Level.SEVERE, getStackTrace(thrown)); } /** * Get stack trace from throwable * * @param t * @return trace */ private String getStackTrace(Throwable t) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw, true); t.printStackTrace(pw); pw.flush(); sw.flush(); return sw.toString(); } /** * PowerCraft Log file formatter. * * @author MightyPork * @copy (c) 2012 */ private class LogFormatter extends Formatter { /** Newline string constant */ private final String nl = System.getProperty("line.separator"); @Override public String format(LogRecord record) { StringBuffer buf = new StringBuffer(180); if (record.getMessage().equals("\n")) { return nl; } if (record.getMessage().charAt(0) == '\n') { buf.append(nl); record.setMessage(record.getMessage().substring(1)); } Level level = record.getLevel(); String trail = "[ ? ]"; if (level == Level.FINE) { trail = "[ # ] "; } if (level == Level.FINER) { trail = "[ - ] "; } if (level == Level.FINEST) { trail = "[ ] "; } if (level == Level.INFO) { trail = "[ i ] "; } if (level == Level.SEVERE) { trail = "[!E!] "; } if (level == Level.WARNING) { trail = "[!W!] "; } record.setMessage(record.getMessage().replaceAll("\n", nl + trail)); buf.append(trail); buf.append(formatMessage(record)); buf.append(nl); Throwable throwable = record.getThrown(); if (throwable != null) { buf.append("at "); buf.append(record.getSourceClassName()); buf.append('.'); buf.append(record.getSourceMethodName()); buf.append(nl); StringWriter sink = new StringWriter(); throwable.printStackTrace(new PrintWriter(sink, true)); buf.append(sink.toString()); buf.append(nl); } String str = buf.toString(); for (LogMonitor mon : monitors.values()) { mon.log(level, str); } return str; } } /** * @return log filename suffix (incl. dot) */ protected String getSuffix() { return ".log"; } }