package javaforce; import java.io.*; import java.util.*; /** * JFLog is a file logger with support for multiple files and optional outputs * to System.out as well. */ public class JFLog { private static class LogInstance { private Object lock = new Object(); private FileOutputStream fos; private PrintStream stdout; private long filesize; private String filename; private boolean enabled = true; } private static Hashtable<Integer, LogInstance> list = new Hashtable<Integer, LogInstance>(); private static boolean useTimestamp = false; private static long timestampBase; private static class TraceException extends Exception { public TraceException(String msg) { super(msg); } } public static boolean init(int id, String filename, boolean append, PrintStream stdout) { LogInstance log = new LogInstance(); log.stdout = stdout; log.filename = filename; if (filename != null) { if (append) { File file = new File(filename); log.filesize = file.length(); } else { log.filesize = 0; } try { log.fos = new FileOutputStream(filename, append); } catch (Exception e) { System.out.println("Log:create file failed:" + filename); return false; } } synchronized(list) { list.put(id, log); } return true; } public static boolean init(String filename, boolean stdout) { return init(0, filename, false, stdout ? System.out : null); } public static boolean init(int id, String filename, boolean stdout) { return init(id, filename, false, stdout ? System.out : null); } public static boolean append(String filename, boolean stdout) { return init(0, filename, true, stdout ? System.out : null); } public static boolean append(int id, String filename, boolean stdout) { return init(id, filename, true, stdout ? System.out : null); } public static boolean close(int id) { LogInstance log = list.get(id); if (log == null) { return false; } synchronized(list) { list.remove(id); } try { if (log.fos != null) { log.fos.close(); } } catch (Exception e) { } return true; } public static boolean close() { return close(0); } /** Uses a timestamp instead of date/time for each message logged. */ public static void enableTimestamp(boolean state) { timestampBase = System.nanoTime() / 1000000; useTimestamp = state; } public static boolean log(String msg) { return log(0, msg); } public static boolean log(int id, String msg) { LogInstance log = list.get(id); if (log == null) { System.out.println(msg); return false; } if (!log.enabled) { return true; } if (!useTimestamp) { Calendar cal = Calendar.getInstance(); msg = String.format("[%1$04d/%2$02d/%3$02d %4$02d:%5$02d:%6$02d] %7$s\r\n", cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND), msg); } else { msg = String.format("[%1$d] %2$s\r\n", (System.nanoTime() / 1000000) - timestampBase, msg); } synchronized (log.lock) { if (log.stdout != null) { log.stdout.print(msg); } if (log.fos == null) return true; try { log.fos.write(msg.getBytes()); log.fos.flush(); } catch (Exception e) { System.out.println("Log:write file failed:" + id); return false; } log.filesize += msg.length(); if (log.filesize > 1024 * 1024) { log.filesize = 0; //start new log file Calendar cal = Calendar.getInstance(); String tmp = String.format(".%1$04d-%2$02d-%3$02d-%4$02d-%5$02d-%6$02d", cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND)); int idx = log.filename.lastIndexOf('.'); if (idx == -1) { tmp = log.filename + tmp; } else { tmp = log.filename.substring(0, idx) + tmp + log.filename.substring(idx); } try { log.fos.close(); } catch (Exception e1) { } File file = new File(log.filename); file.renameTo(new File(tmp)); try { log.fos = new FileOutputStream(log.filename); } catch (Exception e2) { } } } return true; } public static boolean log(Throwable t) { return log(0, t); } public static boolean log(int id, Throwable t) { StringBuffer buf = new StringBuffer(); buf.append(t.toString()); buf.append("\r\n"); StackTraceElement ste[] = t.getStackTrace(); int start = 0; if (t instanceof TraceException) { start = 1; //skip JFLog.logTrace() step } if (ste != null) { for (int a = start; a < ste.length; a++) { buf.append("\tat "); buf.append(ste[a].toString()); buf.append("\r\n"); } } return log(id, buf.toString()); } public static boolean log(String msg, Throwable t) { return log(0, msg, t); } public static boolean log(int id, String msg, Throwable t) { if (!log(id, msg)) { return false; } return log(id, t); } public static void setEnabled(int id, boolean state) { LogInstance log = list.get(id); if (log == null) { return; } log.enabled = state; } public static void setEnabled(boolean state) { setEnabled(0, state); } /** * NOTE: write() doesn't cycle log files. */ public static boolean write(int id, byte data[], int off, int len) { LogInstance log = list.get(id); synchronized (log.lock) { try { log.fos.write(data, off, len); log.fos.flush(); log.filesize += len; } catch (Exception e) { return false; } } return true; } /** * NOTE: write() doesn't cycle log files. */ public static boolean write(byte data[], int off, int len) { return write(0, data, off, len); } public static OutputStream getOutputStream(int id) { LogInstance log = list.get(id); if (log == null) { return null; } return log.fos; } public static OutputStream getOutputStream() { return getOutputStream(0); } public static void logTrace(int id, String msg) { try { throw new TraceException(msg); } catch (Exception e) { log(id, e); } } public static void logTrace(String msg) { try { throw new TraceException(msg); } catch (Exception e) { log(0, e); } } }