📄 filehandler.java
字号:
* handler switches to the next file in the rotating set. A * value of zero means that files can grow without limit. * * @param count specifies the number of log files through which this * handler cycles. * * @param append specifies whether the handler will append log * records to existing files (<code>true</code>), or whether the * handler will clear log files upon switching to them * (<code>false</code>). * * @throws java.io.IOException FIXME: The Sun Javadoc says: "if * there are IO problems opening the files." This conflicts * with the general principle that configuration errors do * not prohibit construction. Needs review. * * @throws SecurityException if a security manager exists and * the caller is not granted the permission to control * the logging infrastructure. * <p>FIXME: This seems in contrast to all other handler * constructors -- verify this by running tests against * the Sun reference implementation. */ public FileHandler(String pattern, int limit, int count, boolean append) throws IOException, SecurityException { super(/* output stream, created below */ null, "java.util.logging.FileHandler", /* default level */ Level.ALL, /* formatter */ null, /* default formatter */ XMLFormatter.class); if ((limit <0) || (count < 1)) throw new IllegalArgumentException(); this.pattern = pattern; this.limit = limit; this.count = count; this.append = append; this.written = 0; this.logFiles = new LinkedList (); setOutputStream (createFileStream (pattern, limit, count, append, /* generation */ 0)); } /* FIXME: Javadoc missing. */ private OutputStream createFileStream(String pattern, int limit, int count, boolean append, int generation) { String path; int unique = 0; /* Throws a SecurityException if the caller does not have * LoggingPermission("control"). */ LogManager.getLogManager().checkAccess(); /* Default value from the java.util.logging.FileHandler.pattern * LogManager configuration property. */ if (pattern == null) pattern = LogManager.getLogManager().getProperty( "java.util.logging.FileHandler.pattern"); if (pattern == null) pattern = "%h/java%u.log"; if (count > 1 && !has (pattern, 'g')) pattern = pattern + ".%g"; do { path = replaceFileNameEscapes(pattern, generation, unique, count); try { File file = new File(path); if (!file.exists () || append) { FileOutputStream fout = new FileOutputStream (file, append); // FIXME we need file locks for this to work properly, but they // are not implemented yet in Classpath! Madness!// FileChannel channel = fout.getChannel ();// FileLock lock = channel.tryLock ();// if (lock != null) // We've locked the file.// { if (logFiles.isEmpty ()) logFiles.addFirst (path); return new ostr (fout);// } } } catch (Exception ex) { reportError (null, ex, ErrorManager.OPEN_FAILURE); } unique = unique + 1; if (!has (pattern, 'u')) pattern = pattern + ".%u"; } while (true); } /** * Replaces the substrings <code>"/"</code> by the value of the * system property <code>"file.separator"</code>, <code>"%t"</code> * by the value of the system property * <code>"java.io.tmpdir"</code>, <code>"%h"</code> by the value of * the system property <code>"user.home"</code>, <code>"%g"</code> * by the value of <code>generation</code>, <code>"%u"</code> by the * value of <code>uniqueNumber</code>, and <code>"%%"</code> by a * single percent character. If <code>pattern</code> does * <em>not</em> contain the sequence <code>"%g"</code>, * the value of <code>generation</code> will be appended to * the result. * * @throws NullPointerException if one of the system properties * <code>"file.separator"</code>, * <code>"java.io.tmpdir"</code>, or * <code>"user.home"</code> has no value and the * corresponding escape sequence appears in * <code>pattern</code>. */ private static String replaceFileNameEscapes(String pattern, int generation, int uniqueNumber, int count) { StringBuffer buf = new StringBuffer(pattern); String replaceWith; boolean foundGeneration = false; int pos = 0; do { // Uncomment the next line for finding bugs. // System.out.println(buf.substring(0,pos) + '|' + buf.substring(pos)); if (buf.charAt(pos) == '/') { /* The same value is also provided by java.io.File.separator. */ replaceWith = System.getProperty("file.separator"); buf.replace(pos, pos + 1, replaceWith); pos = pos + replaceWith.length() - 1; continue; } if (buf.charAt(pos) == '%') { switch (buf.charAt(pos + 1)) { case 't': replaceWith = System.getProperty("java.io.tmpdir"); break; case 'h': replaceWith = System.getProperty("user.home"); break; case 'g': replaceWith = Integer.toString(generation); foundGeneration = true; break; case 'u': replaceWith = Integer.toString(uniqueNumber); break; case '%': replaceWith = "%"; break; default: replaceWith = "??"; break; // FIXME: Throw exception? } buf.replace(pos, pos + 2, replaceWith); pos = pos + replaceWith.length() - 1; continue; } } while (++pos < buf.length() - 1); if (!foundGeneration && (count > 1)) { buf.append('.'); buf.append(generation); } return buf.toString(); } /* FIXME: Javadoc missing. */ public void publish(LogRecord record) { if (limit > 0 && written >= limit) rotate (); super.publish(record); flush (); } /** * Rotates the current log files, possibly removing one if we * exceed the file count. */ private synchronized void rotate () { if (logFiles.size () > 0) { File f1 = null; ListIterator lit = null; // If we reach the file count, ditch the oldest file. if (logFiles.size () == count) { f1 = new File ((String) logFiles.getLast ()); f1.delete (); lit = logFiles.listIterator (logFiles.size () - 1); } // Otherwise, move the oldest to a new location. else { String path = replaceFileNameEscapes (pattern, logFiles.size (), /* unique */ 0, count); f1 = new File (path); logFiles.addLast (path); lit = logFiles.listIterator (logFiles.size () - 1); } // Now rotate the files. while (lit.hasPrevious ()) { String s = (String) lit.previous (); File f2 = new File (s); f2.renameTo (f1); f1 = f2; } } setOutputStream (createFileStream (pattern, limit, count, append, /* generation */ 0)); // Reset written count. written = 0; } /** * Tell if <code>pattern</code> contains the pattern sequence * with character <code>escape</code>. That is, if <code>escape</code> * is 'g', this method returns true if the given pattern contains * "%g", and not just the substring "%g" (for example, in the case of * "%%g"). * * @param pattern The pattern to test. * @param escape The escape character to search for. * @return True iff the pattern contains the escape sequence with the * given character. */ private static boolean has (final String pattern, final char escape) { final int len = pattern.length (); boolean sawPercent = false; for (int i = 0; i < len; i++) { char c = pattern.charAt (i); if (sawPercent) { if (c == escape) return true; if (c == '%') // Double percent { sawPercent = false; continue; } } sawPercent = (c == '%'); } return false; } /** * An output stream that tracks the number of bytes written to it. */ private final class ostr extends FilterOutputStream { private ostr (OutputStream out) { super (out); } public void write (final int b) throws IOException { out.write (b); FileHandler.this.written++; // FIXME: synchronize? } public void write (final byte[] b) throws IOException { write (b, 0, b.length); } public void write (final byte[] b, final int offset, final int length) throws IOException { out.write (b, offset, length); FileHandler.this.written += length; // FIXME: synchronize? } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -