mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
8187443: Forest Consolidation: Move files to unified layout
Reviewed-by: darcy, ihse
This commit is contained in:
parent
270fe13182
commit
3789983e89
56923 changed files with 3 additions and 15727 deletions
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package java.util.logging;
|
||||
|
||||
/**
|
||||
* This {@code Handler} publishes log records to {@code System.err}.
|
||||
* By default the {@code SimpleFormatter} is used to generate brief summaries.
|
||||
* <p>
|
||||
* <b>Configuration:</b>
|
||||
* By default each {@code ConsoleHandler} is initialized using the following
|
||||
* {@code LogManager} configuration properties where {@code <handler-name>}
|
||||
* refers to the fully-qualified class name of the handler.
|
||||
* If properties are not defined
|
||||
* (or have invalid values) then the specified default values are used.
|
||||
* <ul>
|
||||
* <li> <handler-name>.level
|
||||
* specifies the default level for the {@code Handler}
|
||||
* (defaults to {@code Level.INFO}). </li>
|
||||
* <li> <handler-name>.filter
|
||||
* specifies the name of a {@code Filter} class to use
|
||||
* (defaults to no {@code Filter}). </li>
|
||||
* <li> <handler-name>.formatter
|
||||
* specifies the name of a {@code Formatter} class to use
|
||||
* (defaults to {@code java.util.logging.SimpleFormatter}). </li>
|
||||
* <li> <handler-name>.encoding
|
||||
* the name of the character set encoding to use (defaults to
|
||||
* the default platform encoding). </li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* For example, the properties for {@code ConsoleHandler} would be:
|
||||
* <ul>
|
||||
* <li> java.util.logging.ConsoleHandler.level=INFO </li>
|
||||
* <li> java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter </li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* For a custom handler, e.g. com.foo.MyHandler, the properties would be:
|
||||
* <ul>
|
||||
* <li> com.foo.MyHandler.level=INFO </li>
|
||||
* <li> com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter </li>
|
||||
* </ul>
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
public class ConsoleHandler extends StreamHandler {
|
||||
|
||||
/**
|
||||
* Create a {@code ConsoleHandler} for {@code System.err}.
|
||||
* <p>
|
||||
* The {@code ConsoleHandler} is configured based on
|
||||
* {@code LogManager} properties (or their default values).
|
||||
*
|
||||
*/
|
||||
public ConsoleHandler() {
|
||||
// configure with specific defaults for ConsoleHandler
|
||||
super(Level.INFO, new SimpleFormatter(), null);
|
||||
|
||||
setOutputStreamPrivileged(System.err);
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish a {@code LogRecord}.
|
||||
* <p>
|
||||
* The logging request was made initially to a {@code Logger} object,
|
||||
* which initialized the {@code LogRecord} and forwarded it here.
|
||||
*
|
||||
* @param record description of the log event. A null record is
|
||||
* silently ignored and is not published
|
||||
*/
|
||||
@Override
|
||||
public void publish(LogRecord record) {
|
||||
super.publish(record);
|
||||
flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Override {@code StreamHandler.close} to do a flush but not
|
||||
* to close the output stream. That is, we do <b>not</b>
|
||||
* close {@code System.err}.
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
flush();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package java.util.logging;
|
||||
|
||||
/**
|
||||
* ErrorManager objects can be attached to Handlers to process
|
||||
* any error that occurs on a Handler during Logging.
|
||||
* <p>
|
||||
* When processing logging output, if a Handler encounters problems
|
||||
* then rather than throwing an Exception back to the issuer of
|
||||
* the logging call (who is unlikely to be interested) the Handler
|
||||
* should call its associated ErrorManager.
|
||||
*/
|
||||
|
||||
public class ErrorManager {
|
||||
private boolean reported = false;
|
||||
|
||||
/*
|
||||
* We declare standard error codes for important categories of errors.
|
||||
*/
|
||||
|
||||
/**
|
||||
* GENERIC_FAILURE is used for failure that don't fit
|
||||
* into one of the other categories.
|
||||
*/
|
||||
public final static int GENERIC_FAILURE = 0;
|
||||
/**
|
||||
* WRITE_FAILURE is used when a write to an output stream fails.
|
||||
*/
|
||||
public final static int WRITE_FAILURE = 1;
|
||||
/**
|
||||
* FLUSH_FAILURE is used when a flush to an output stream fails.
|
||||
*/
|
||||
public final static int FLUSH_FAILURE = 2;
|
||||
/**
|
||||
* CLOSE_FAILURE is used when a close of an output stream fails.
|
||||
*/
|
||||
public final static int CLOSE_FAILURE = 3;
|
||||
/**
|
||||
* OPEN_FAILURE is used when an open of an output stream fails.
|
||||
*/
|
||||
public final static int OPEN_FAILURE = 4;
|
||||
/**
|
||||
* FORMAT_FAILURE is used when formatting fails for any reason.
|
||||
*/
|
||||
public final static int FORMAT_FAILURE = 5;
|
||||
|
||||
/**
|
||||
* The error method is called when a Handler failure occurs.
|
||||
* <p>
|
||||
* This method may be overridden in subclasses. The default
|
||||
* behavior in this base class is that the first call is
|
||||
* reported to System.err, and subsequent calls are ignored.
|
||||
*
|
||||
* @param msg a descriptive string (may be null)
|
||||
* @param ex an exception (may be null)
|
||||
* @param code an error code defined in ErrorManager
|
||||
*/
|
||||
public synchronized void error(String msg, Exception ex, int code) {
|
||||
if (reported) {
|
||||
// We only report the first error, to avoid clogging
|
||||
// the screen.
|
||||
return;
|
||||
}
|
||||
reported = true;
|
||||
String text = "java.util.logging.ErrorManager: " + code;
|
||||
if (msg != null) {
|
||||
text = text + ": " + msg;
|
||||
}
|
||||
System.err.println(text);
|
||||
if (ex != null) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,786 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.logging;
|
||||
|
||||
import static java.nio.file.StandardOpenOption.APPEND;
|
||||
import static java.nio.file.StandardOpenOption.CREATE_NEW;
|
||||
import static java.nio.file.StandardOpenOption.WRITE;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.OverlappingFileLockException;
|
||||
import java.nio.file.FileAlreadyExistsException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.LinkOption;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Simple file logging {@code Handler}.
|
||||
* <p>
|
||||
* The {@code FileHandler} can either write to a specified file,
|
||||
* or it can write to a rotating set of files.
|
||||
* <p>
|
||||
* For a rotating set of files, as each file reaches a given size
|
||||
* limit, it is closed, rotated out, and a new file opened.
|
||||
* Successively older files are named by adding "0", "1", "2",
|
||||
* etc. into the base filename.
|
||||
* <p>
|
||||
* By default buffering is enabled in the IO libraries but each log
|
||||
* record is flushed out when it is complete.
|
||||
* <p>
|
||||
* By default the {@code XMLFormatter} class is used for formatting.
|
||||
* <p>
|
||||
* <b>Configuration:</b>
|
||||
* By default each {@code FileHandler} is initialized using the following
|
||||
* {@code LogManager} configuration properties where {@code <handler-name>}
|
||||
* refers to the fully-qualified class name of the handler.
|
||||
* If properties are not defined
|
||||
* (or have invalid values) then the specified default values are used.
|
||||
* <ul>
|
||||
* <li> <handler-name>.level
|
||||
* specifies the default level for the {@code Handler}
|
||||
* (defaults to {@code Level.ALL}). </li>
|
||||
* <li> <handler-name>.filter
|
||||
* specifies the name of a {@code Filter} class to use
|
||||
* (defaults to no {@code Filter}). </li>
|
||||
* <li> <handler-name>.formatter
|
||||
* specifies the name of a {@code Formatter} class to use
|
||||
* (defaults to {@code java.util.logging.XMLFormatter}) </li>
|
||||
* <li> <handler-name>.encoding
|
||||
* the name of the character set encoding to use (defaults to
|
||||
* the default platform encoding). </li>
|
||||
* <li> <handler-name>.limit
|
||||
* specifies an approximate maximum amount to write (in bytes)
|
||||
* to any one file. If this is zero, then there is no limit.
|
||||
* (Defaults to no limit). </li>
|
||||
* <li> <handler-name>.count
|
||||
* specifies how many output files to cycle through (defaults to 1). </li>
|
||||
* <li> <handler-name>.pattern
|
||||
* specifies a pattern for generating the output file name. See
|
||||
* below for details. (Defaults to "%h/java%u.log"). </li>
|
||||
* <li> <handler-name>.append
|
||||
* specifies whether the FileHandler should append onto
|
||||
* any existing files (defaults to false). </li>
|
||||
* <li> <handler-name>.maxLocks
|
||||
* specifies the maximum number of concurrent locks held by
|
||||
* FileHandler (defaults to 100). </li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* For example, the properties for {@code FileHandler} would be:
|
||||
* <ul>
|
||||
* <li> java.util.logging.FileHandler.level=INFO </li>
|
||||
* <li> java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter </li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* For a custom handler, e.g. com.foo.MyHandler, the properties would be:
|
||||
* <ul>
|
||||
* <li> com.foo.MyHandler.level=INFO </li>
|
||||
* <li> com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter </li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* A pattern consists of a string that includes the following special
|
||||
* components that will be replaced at runtime:
|
||||
* <ul>
|
||||
* <li> "/" the local pathname separator </li>
|
||||
* <li> "%t" the system temporary directory </li>
|
||||
* <li> "%h" the value of the "user.home" system property </li>
|
||||
* <li> "%g" the generation number to distinguish rotated logs </li>
|
||||
* <li> "%u" a unique number to resolve conflicts </li>
|
||||
* <li> "%%" translates to a single percent sign "%" </li>
|
||||
* </ul>
|
||||
* If no "%g" field has been specified and the file count is greater
|
||||
* than one, then the generation number will be added to the end of
|
||||
* the generated filename, after a dot.
|
||||
* <p>
|
||||
* Thus for example a pattern of "%t/java%g.log" with a count of 2
|
||||
* would typically cause log files to be written on Solaris to
|
||||
* /var/tmp/java0.log and /var/tmp/java1.log whereas on Windows 95 they
|
||||
* would be typically written to C:\TEMP\java0.log and C:\TEMP\java1.log
|
||||
* <p>
|
||||
* Generation numbers follow the sequence 0, 1, 2, etc.
|
||||
* <p>
|
||||
* Normally the "%u" unique field is set to 0. However, if the {@code FileHandler}
|
||||
* tries to open the filename and finds the file is currently in use by
|
||||
* another process it will increment the unique number field and try
|
||||
* again. This will be repeated until {@code FileHandler} finds a file name that
|
||||
* is not currently in use. If there is a conflict and no "%u" field has
|
||||
* been specified, it will be added at the end of the filename after a dot.
|
||||
* (This will be after any automatically added generation number.)
|
||||
* <p>
|
||||
* Thus if three processes were all trying to log to fred%u.%g.txt then
|
||||
* they might end up using fred0.0.txt, fred1.0.txt, fred2.0.txt as
|
||||
* the first file in their rotating sequences.
|
||||
* <p>
|
||||
* Note that the use of unique ids to avoid conflicts is only guaranteed
|
||||
* to work reliably when using a local disk file system.
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
|
||||
public class FileHandler extends StreamHandler {
|
||||
private MeteredStream meter;
|
||||
private boolean append;
|
||||
private long limit; // zero => no limit.
|
||||
private int count;
|
||||
private String pattern;
|
||||
private String lockFileName;
|
||||
private FileChannel lockFileChannel;
|
||||
private File files[];
|
||||
private static final int MAX_LOCKS = 100;
|
||||
private int maxLocks = MAX_LOCKS;
|
||||
private static final Set<String> locks = new HashSet<>();
|
||||
|
||||
/**
|
||||
* A metered stream is a subclass of OutputStream that
|
||||
* (a) forwards all its output to a target stream
|
||||
* (b) keeps track of how many bytes have been written
|
||||
*/
|
||||
private static final class MeteredStream extends OutputStream {
|
||||
final OutputStream out;
|
||||
long written;
|
||||
|
||||
MeteredStream(OutputStream out, long written) {
|
||||
this.out = out;
|
||||
this.written = written;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
out.write(b);
|
||||
written++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte buff[]) throws IOException {
|
||||
out.write(buff);
|
||||
written += buff.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte buff[], int off, int len) throws IOException {
|
||||
out.write(buff,off,len);
|
||||
written += len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
out.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void open(File fname, boolean append) throws IOException {
|
||||
long len = 0;
|
||||
if (append) {
|
||||
len = fname.length();
|
||||
}
|
||||
FileOutputStream fout = new FileOutputStream(fname.toString(), append);
|
||||
BufferedOutputStream bout = new BufferedOutputStream(fout);
|
||||
meter = new MeteredStream(bout, len);
|
||||
setOutputStream(meter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a FileHandler from LogManager properties and/or default values
|
||||
* as specified in the class javadoc.
|
||||
*/
|
||||
private void configure() {
|
||||
LogManager manager = LogManager.getLogManager();
|
||||
|
||||
String cname = getClass().getName();
|
||||
|
||||
pattern = manager.getStringProperty(cname + ".pattern", "%h/java%u.log");
|
||||
limit = manager.getLongProperty(cname + ".limit", 0);
|
||||
if (limit < 0) {
|
||||
limit = 0;
|
||||
}
|
||||
count = manager.getIntProperty(cname + ".count", 1);
|
||||
if (count <= 0) {
|
||||
count = 1;
|
||||
}
|
||||
append = manager.getBooleanProperty(cname + ".append", false);
|
||||
setLevel(manager.getLevelProperty(cname + ".level", Level.ALL));
|
||||
setFilter(manager.getFilterProperty(cname + ".filter", null));
|
||||
setFormatter(manager.getFormatterProperty(cname + ".formatter", new XMLFormatter()));
|
||||
// Initialize maxLocks from the logging.properties file.
|
||||
// If invalid/no property is provided 100 will be used as a default value.
|
||||
maxLocks = manager.getIntProperty(cname + ".maxLocks", MAX_LOCKS);
|
||||
if(maxLocks <= 0) {
|
||||
maxLocks = MAX_LOCKS;
|
||||
}
|
||||
try {
|
||||
setEncoding(manager.getStringProperty(cname +".encoding", null));
|
||||
} catch (Exception ex) {
|
||||
try {
|
||||
setEncoding(null);
|
||||
} catch (Exception ex2) {
|
||||
// doing a setEncoding with null should always work.
|
||||
// assert false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a default {@code FileHandler}. This will be configured
|
||||
* entirely from {@code LogManager} properties (or their default values).
|
||||
*
|
||||
* @exception IOException if there are IO problems opening the files.
|
||||
* @exception SecurityException if a security manager exists and if
|
||||
* the caller does not have {@code LoggingPermission("control"))}.
|
||||
* @exception NullPointerException if pattern property is an empty String.
|
||||
*/
|
||||
public FileHandler() throws IOException, SecurityException {
|
||||
checkPermission();
|
||||
configure();
|
||||
// pattern will have been set by configure. check that it's not
|
||||
// empty.
|
||||
if (pattern.isEmpty()) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
openFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a {@code FileHandler} to write to the given filename.
|
||||
* <p>
|
||||
* The {@code FileHandler} is configured based on {@code LogManager}
|
||||
* properties (or their default values) except that the given pattern
|
||||
* argument is used as the filename pattern, the file limit is
|
||||
* set to no limit, and the file count is set to one.
|
||||
* <p>
|
||||
* There is no limit on the amount of data that may be written,
|
||||
* so use this with care.
|
||||
*
|
||||
* @param pattern the name of the output file
|
||||
* @exception IOException if there are IO problems opening the files.
|
||||
* @exception SecurityException if a security manager exists and if
|
||||
* the caller does not have {@code LoggingPermission("control")}.
|
||||
* @exception IllegalArgumentException if pattern is an empty string
|
||||
*/
|
||||
public FileHandler(String pattern) throws IOException, SecurityException {
|
||||
if (pattern.length() < 1 ) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
checkPermission();
|
||||
configure();
|
||||
this.pattern = pattern;
|
||||
this.limit = 0;
|
||||
this.count = 1;
|
||||
openFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a {@code FileHandler} to write to the given filename,
|
||||
* with optional append.
|
||||
* <p>
|
||||
* The {@code FileHandler} is configured based on {@code LogManager}
|
||||
* properties (or their default values) except that the given pattern
|
||||
* argument is used as the filename pattern, the file limit is
|
||||
* set to no limit, the file count is set to one, and the append
|
||||
* mode is set to the given {@code append} argument.
|
||||
* <p>
|
||||
* There is no limit on the amount of data that may be written,
|
||||
* so use this with care.
|
||||
*
|
||||
* @param pattern the name of the output file
|
||||
* @param append specifies append mode
|
||||
* @exception IOException if there are IO problems opening the files.
|
||||
* @exception SecurityException if a security manager exists and if
|
||||
* the caller does not have {@code LoggingPermission("control")}.
|
||||
* @exception IllegalArgumentException if pattern is an empty string
|
||||
*/
|
||||
public FileHandler(String pattern, boolean append) throws IOException,
|
||||
SecurityException {
|
||||
if (pattern.length() < 1 ) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
checkPermission();
|
||||
configure();
|
||||
this.pattern = pattern;
|
||||
this.limit = 0;
|
||||
this.count = 1;
|
||||
this.append = append;
|
||||
openFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a {@code FileHandler} to write to a set of files. When
|
||||
* (approximately) the given limit has been written to one file,
|
||||
* another file will be opened. The output will cycle through a set
|
||||
* of count files.
|
||||
* <p>
|
||||
* The {@code FileHandler} is configured based on {@code LogManager}
|
||||
* properties (or their default values) except that the given pattern
|
||||
* argument is used as the filename pattern, the file limit is
|
||||
* set to the limit argument, and the file count is set to the
|
||||
* given count argument.
|
||||
* <p>
|
||||
* The count must be at least 1.
|
||||
*
|
||||
* @param pattern the pattern for naming the output file
|
||||
* @param limit the maximum number of bytes to write to any one file
|
||||
* @param count the number of files to use
|
||||
* @exception IOException if there are IO problems opening the files.
|
||||
* @exception SecurityException if a security manager exists and if
|
||||
* the caller does not have {@code LoggingPermission("control")}.
|
||||
* @exception IllegalArgumentException if {@code limit < 0}, or {@code count < 1}.
|
||||
* @exception IllegalArgumentException if pattern is an empty string
|
||||
*/
|
||||
public FileHandler(String pattern, int limit, int count)
|
||||
throws IOException, SecurityException {
|
||||
if (limit < 0 || count < 1 || pattern.length() < 1) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
checkPermission();
|
||||
configure();
|
||||
this.pattern = pattern;
|
||||
this.limit = limit;
|
||||
this.count = count;
|
||||
openFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a {@code FileHandler} to write to a set of files
|
||||
* with optional append. When (approximately) the given limit has
|
||||
* been written to one file, another file will be opened. The
|
||||
* output will cycle through a set of count files.
|
||||
* <p>
|
||||
* The {@code FileHandler} is configured based on {@code LogManager}
|
||||
* properties (or their default values) except that the given pattern
|
||||
* argument is used as the filename pattern, the file limit is
|
||||
* set to the limit argument, and the file count is set to the
|
||||
* given count argument, and the append mode is set to the given
|
||||
* {@code append} argument.
|
||||
* <p>
|
||||
* The count must be at least 1.
|
||||
*
|
||||
* @param pattern the pattern for naming the output file
|
||||
* @param limit the maximum number of bytes to write to any one file
|
||||
* @param count the number of files to use
|
||||
* @param append specifies append mode
|
||||
* @exception IOException if there are IO problems opening the files.
|
||||
* @exception SecurityException if a security manager exists and if
|
||||
* the caller does not have {@code LoggingPermission("control")}.
|
||||
* @exception IllegalArgumentException if {@code limit < 0}, or {@code count < 1}.
|
||||
* @exception IllegalArgumentException if pattern is an empty string
|
||||
*
|
||||
*/
|
||||
public FileHandler(String pattern, int limit, int count, boolean append)
|
||||
throws IOException, SecurityException {
|
||||
this(pattern, (long)limit, count, append);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a {@code FileHandler} to write to a set of files
|
||||
* with optional append. When (approximately) the given limit has
|
||||
* been written to one file, another file will be opened. The
|
||||
* output will cycle through a set of count files.
|
||||
* <p>
|
||||
* The {@code FileHandler} is configured based on {@code LogManager}
|
||||
* properties (or their default values) except that the given pattern
|
||||
* argument is used as the filename pattern, the file limit is
|
||||
* set to the limit argument, and the file count is set to the
|
||||
* given count argument, and the append mode is set to the given
|
||||
* {@code append} argument.
|
||||
* <p>
|
||||
* The count must be at least 1.
|
||||
*
|
||||
* @param pattern the pattern for naming the output file
|
||||
* @param limit the maximum number of bytes to write to any one file
|
||||
* @param count the number of files to use
|
||||
* @param append specifies append mode
|
||||
* @exception IOException if there are IO problems opening the files.
|
||||
* @exception SecurityException if a security manager exists and if
|
||||
* the caller does not have {@code LoggingPermission("control")}.
|
||||
* @exception IllegalArgumentException if {@code limit < 0}, or {@code count < 1}.
|
||||
* @exception IllegalArgumentException if pattern is an empty string
|
||||
*
|
||||
* @since 9
|
||||
*
|
||||
*/
|
||||
public FileHandler(String pattern, long limit, int count, boolean append)
|
||||
throws IOException {
|
||||
if (limit < 0 || count < 1 || pattern.length() < 1) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
checkPermission();
|
||||
configure();
|
||||
this.pattern = pattern;
|
||||
this.limit = limit;
|
||||
this.count = count;
|
||||
this.append = append;
|
||||
openFiles();
|
||||
}
|
||||
|
||||
private boolean isParentWritable(Path path) {
|
||||
Path parent = path.getParent();
|
||||
if (parent == null) {
|
||||
parent = path.toAbsolutePath().getParent();
|
||||
}
|
||||
return parent != null && Files.isWritable(parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the set of output files, based on the configured
|
||||
* instance variables.
|
||||
*/
|
||||
private void openFiles() throws IOException {
|
||||
LogManager manager = LogManager.getLogManager();
|
||||
manager.checkPermission();
|
||||
if (count < 1) {
|
||||
throw new IllegalArgumentException("file count = " + count);
|
||||
}
|
||||
if (limit < 0) {
|
||||
limit = 0;
|
||||
}
|
||||
|
||||
// All constructors check that pattern is neither null nor empty.
|
||||
assert pattern != null : "pattern should not be null";
|
||||
assert !pattern.isEmpty() : "pattern should not be empty";
|
||||
|
||||
// We register our own ErrorManager during initialization
|
||||
// so we can record exceptions.
|
||||
InitializationErrorManager em = new InitializationErrorManager();
|
||||
setErrorManager(em);
|
||||
|
||||
// Create a lock file. This grants us exclusive access
|
||||
// to our set of output files, as long as we are alive.
|
||||
int unique = -1;
|
||||
for (;;) {
|
||||
unique++;
|
||||
if (unique > maxLocks) {
|
||||
throw new IOException("Couldn't get lock for " + pattern);
|
||||
}
|
||||
// Generate a lock file name from the "unique" int.
|
||||
lockFileName = generate(pattern, 0, unique).toString() + ".lck";
|
||||
// Now try to lock that filename.
|
||||
// Because some systems (e.g., Solaris) can only do file locks
|
||||
// between processes (and not within a process), we first check
|
||||
// if we ourself already have the file locked.
|
||||
synchronized(locks) {
|
||||
if (locks.contains(lockFileName)) {
|
||||
// We already own this lock, for a different FileHandler
|
||||
// object. Try again.
|
||||
continue;
|
||||
}
|
||||
|
||||
final Path lockFilePath = Paths.get(lockFileName);
|
||||
FileChannel channel = null;
|
||||
int retries = -1;
|
||||
boolean fileCreated = false;
|
||||
while (channel == null && retries++ < 1) {
|
||||
try {
|
||||
channel = FileChannel.open(lockFilePath,
|
||||
CREATE_NEW, WRITE);
|
||||
fileCreated = true;
|
||||
} catch (FileAlreadyExistsException ix) {
|
||||
// This may be a zombie file left over by a previous
|
||||
// execution. Reuse it - but only if we can actually
|
||||
// write to its directory.
|
||||
// Note that this is a situation that may happen,
|
||||
// but not too frequently.
|
||||
if (Files.isRegularFile(lockFilePath, LinkOption.NOFOLLOW_LINKS)
|
||||
&& isParentWritable(lockFilePath)) {
|
||||
try {
|
||||
channel = FileChannel.open(lockFilePath,
|
||||
WRITE, APPEND);
|
||||
} catch (NoSuchFileException x) {
|
||||
// Race condition - retry once, and if that
|
||||
// fails again just try the next name in
|
||||
// the sequence.
|
||||
continue;
|
||||
} catch(IOException x) {
|
||||
// the file may not be writable for us.
|
||||
// try the next name in the sequence
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// at this point channel should still be null.
|
||||
// break and try the next name in the sequence.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (channel == null) continue; // try the next name;
|
||||
lockFileChannel = channel;
|
||||
|
||||
boolean available;
|
||||
try {
|
||||
available = lockFileChannel.tryLock() != null;
|
||||
// We got the lock OK.
|
||||
// At this point we could call File.deleteOnExit().
|
||||
// However, this could have undesirable side effects
|
||||
// as indicated by JDK-4872014. So we will instead
|
||||
// rely on the fact that close() will remove the lock
|
||||
// file and that whoever is creating FileHandlers should
|
||||
// be responsible for closing them.
|
||||
} catch (IOException ix) {
|
||||
// We got an IOException while trying to get the lock.
|
||||
// This normally indicates that locking is not supported
|
||||
// on the target directory. We have to proceed without
|
||||
// getting a lock. Drop through, but only if we did
|
||||
// create the file...
|
||||
available = fileCreated;
|
||||
} catch (OverlappingFileLockException x) {
|
||||
// someone already locked this file in this VM, through
|
||||
// some other channel - that is - using something else
|
||||
// than new FileHandler(...);
|
||||
// continue searching for an available lock.
|
||||
available = false;
|
||||
}
|
||||
if (available) {
|
||||
// We got the lock. Remember it.
|
||||
locks.add(lockFileName);
|
||||
break;
|
||||
}
|
||||
|
||||
// We failed to get the lock. Try next file.
|
||||
lockFileChannel.close();
|
||||
}
|
||||
}
|
||||
|
||||
files = new File[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
files[i] = generate(pattern, i, unique);
|
||||
}
|
||||
|
||||
// Create the initial log file.
|
||||
if (append) {
|
||||
open(files[0], true);
|
||||
} else {
|
||||
rotate();
|
||||
}
|
||||
|
||||
// Did we detect any exceptions during initialization?
|
||||
Exception ex = em.lastException;
|
||||
if (ex != null) {
|
||||
if (ex instanceof IOException) {
|
||||
throw (IOException) ex;
|
||||
} else if (ex instanceof SecurityException) {
|
||||
throw (SecurityException) ex;
|
||||
} else {
|
||||
throw new IOException("Exception: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Install the normal default ErrorManager.
|
||||
setErrorManager(new ErrorManager());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a file based on a user-supplied pattern, generation number,
|
||||
* and an integer uniqueness suffix
|
||||
* @param pattern the pattern for naming the output file
|
||||
* @param generation the generation number to distinguish rotated logs
|
||||
* @param unique a unique number to resolve conflicts
|
||||
* @return the generated File
|
||||
* @throws IOException
|
||||
*/
|
||||
private File generate(String pattern, int generation, int unique)
|
||||
throws IOException {
|
||||
File file = null;
|
||||
String word = "";
|
||||
int ix = 0;
|
||||
boolean sawg = false;
|
||||
boolean sawu = false;
|
||||
while (ix < pattern.length()) {
|
||||
char ch = pattern.charAt(ix);
|
||||
ix++;
|
||||
char ch2 = 0;
|
||||
if (ix < pattern.length()) {
|
||||
ch2 = Character.toLowerCase(pattern.charAt(ix));
|
||||
}
|
||||
if (ch == '/') {
|
||||
if (file == null) {
|
||||
file = new File(word);
|
||||
} else {
|
||||
file = new File(file, word);
|
||||
}
|
||||
word = "";
|
||||
continue;
|
||||
} else if (ch == '%') {
|
||||
if (ch2 == 't') {
|
||||
String tmpDir = System.getProperty("java.io.tmpdir");
|
||||
if (tmpDir == null) {
|
||||
tmpDir = System.getProperty("user.home");
|
||||
}
|
||||
file = new File(tmpDir);
|
||||
ix++;
|
||||
word = "";
|
||||
continue;
|
||||
} else if (ch2 == 'h') {
|
||||
file = new File(System.getProperty("user.home"));
|
||||
if (jdk.internal.misc.VM.isSetUID()) {
|
||||
// Ok, we are in a set UID program. For safety's sake
|
||||
// we disallow attempts to open files relative to %h.
|
||||
throw new IOException("can't use %h in set UID program");
|
||||
}
|
||||
ix++;
|
||||
word = "";
|
||||
continue;
|
||||
} else if (ch2 == 'g') {
|
||||
word = word + generation;
|
||||
sawg = true;
|
||||
ix++;
|
||||
continue;
|
||||
} else if (ch2 == 'u') {
|
||||
word = word + unique;
|
||||
sawu = true;
|
||||
ix++;
|
||||
continue;
|
||||
} else if (ch2 == '%') {
|
||||
word = word + "%";
|
||||
ix++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
word = word + ch;
|
||||
}
|
||||
if (count > 1 && !sawg) {
|
||||
word = word + "." + generation;
|
||||
}
|
||||
if (unique > 0 && !sawu) {
|
||||
word = word + "." + unique;
|
||||
}
|
||||
if (word.length() > 0) {
|
||||
if (file == null) {
|
||||
file = new File(word);
|
||||
} else {
|
||||
file = new File(file, word);
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate the set of output files
|
||||
*/
|
||||
private synchronized void rotate() {
|
||||
Level oldLevel = getLevel();
|
||||
setLevel(Level.OFF);
|
||||
|
||||
super.close();
|
||||
for (int i = count-2; i >= 0; i--) {
|
||||
File f1 = files[i];
|
||||
File f2 = files[i+1];
|
||||
if (f1.exists()) {
|
||||
if (f2.exists()) {
|
||||
f2.delete();
|
||||
}
|
||||
f1.renameTo(f2);
|
||||
}
|
||||
}
|
||||
try {
|
||||
open(files[0], false);
|
||||
} catch (IOException ix) {
|
||||
// We don't want to throw an exception here, but we
|
||||
// report the exception to any registered ErrorManager.
|
||||
reportError(null, ix, ErrorManager.OPEN_FAILURE);
|
||||
|
||||
}
|
||||
setLevel(oldLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format and publish a {@code LogRecord}.
|
||||
*
|
||||
* @param record description of the log event. A null record is
|
||||
* silently ignored and is not published
|
||||
*/
|
||||
@Override
|
||||
public synchronized void publish(LogRecord record) {
|
||||
if (!isLoggable(record)) {
|
||||
return;
|
||||
}
|
||||
super.publish(record);
|
||||
flush();
|
||||
if (limit > 0 && (meter.written >= limit || meter.written < 0)) {
|
||||
// We performed access checks in the "init" method to make sure
|
||||
// we are only initialized from trusted code. So we assume
|
||||
// it is OK to write the target files, even if we are
|
||||
// currently being called from untrusted code.
|
||||
// So it is safe to raise privilege here.
|
||||
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||
@Override
|
||||
public Object run() {
|
||||
rotate();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close all the files.
|
||||
*
|
||||
* @exception SecurityException if a security manager exists and if
|
||||
* the caller does not have {@code LoggingPermission("control")}.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void close() throws SecurityException {
|
||||
super.close();
|
||||
// Unlock any lock file.
|
||||
if (lockFileName == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// Close the lock file channel (which also will free any locks)
|
||||
lockFileChannel.close();
|
||||
} catch (Exception ex) {
|
||||
// Problems closing the stream. Punt.
|
||||
}
|
||||
synchronized(locks) {
|
||||
locks.remove(lockFileName);
|
||||
}
|
||||
new File(lockFileName).delete();
|
||||
lockFileName = null;
|
||||
lockFileChannel = null;
|
||||
}
|
||||
|
||||
private static class InitializationErrorManager extends ErrorManager {
|
||||
Exception lastException;
|
||||
@Override
|
||||
public void error(String msg, Exception ex, int code) {
|
||||
lastException = ex;
|
||||
}
|
||||
}
|
||||
}
|
49
src/java.logging/share/classes/java/util/logging/Filter.java
Normal file
49
src/java.logging/share/classes/java/util/logging/Filter.java
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package java.util.logging;
|
||||
|
||||
/**
|
||||
* A Filter can be used to provide fine grain control over
|
||||
* what is logged, beyond the control provided by log levels.
|
||||
* <p>
|
||||
* Each Logger and each Handler can have a filter associated with it.
|
||||
* The Logger or Handler will call the isLoggable method to check
|
||||
* if a given LogRecord should be published. If isLoggable returns
|
||||
* false, the LogRecord will be discarded.
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Filter {
|
||||
|
||||
/**
|
||||
* Check if a given log record should be published.
|
||||
* @param record a LogRecord
|
||||
* @return true if the log record should be published.
|
||||
*/
|
||||
public boolean isLoggable(LogRecord record);
|
||||
}
|
151
src/java.logging/share/classes/java/util/logging/Formatter.java
Normal file
151
src/java.logging/share/classes/java/util/logging/Formatter.java
Normal file
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package java.util.logging;
|
||||
|
||||
/**
|
||||
* A Formatter provides support for formatting LogRecords.
|
||||
* <p>
|
||||
* Typically each logging Handler will have a Formatter associated
|
||||
* with it. The Formatter takes a LogRecord and converts it to
|
||||
* a string.
|
||||
* <p>
|
||||
* Some formatters (such as the XMLFormatter) need to wrap head
|
||||
* and tail strings around a set of formatted records. The getHeader
|
||||
* and getTail methods can be used to obtain these strings.
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
|
||||
public abstract class Formatter {
|
||||
|
||||
/**
|
||||
* Construct a new formatter.
|
||||
*/
|
||||
protected Formatter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the given log record and return the formatted string.
|
||||
* <p>
|
||||
* The resulting formatted String will normally include a
|
||||
* localized and formatted version of the LogRecord's message field.
|
||||
* It is recommended to use the {@link Formatter#formatMessage}
|
||||
* convenience method to localize and format the message field.
|
||||
*
|
||||
* @param record the log record to be formatted.
|
||||
* @return the formatted log record
|
||||
*/
|
||||
public abstract String format(LogRecord record);
|
||||
|
||||
|
||||
/**
|
||||
* Return the header string for a set of formatted records.
|
||||
* <p>
|
||||
* This base class returns an empty string, but this may be
|
||||
* overridden by subclasses.
|
||||
*
|
||||
* @param h The target handler (can be null)
|
||||
* @return header string
|
||||
*/
|
||||
public String getHead(Handler h) {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tail string for a set of formatted records.
|
||||
* <p>
|
||||
* This base class returns an empty string, but this may be
|
||||
* overridden by subclasses.
|
||||
*
|
||||
* @param h The target handler (can be null)
|
||||
* @return tail string
|
||||
*/
|
||||
public String getTail(Handler h) {
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Localize and format the message string from a log record. This
|
||||
* method is provided as a convenience for Formatter subclasses to
|
||||
* use when they are performing formatting.
|
||||
* <p>
|
||||
* The message string is first localized to a format string using
|
||||
* the record's ResourceBundle. (If there is no ResourceBundle,
|
||||
* or if the message key is not found, then the key is used as the
|
||||
* format string.) The format String uses java.text style
|
||||
* formatting.
|
||||
* <ul>
|
||||
* <li>If there are no parameters, no formatter is used.
|
||||
* <li>Otherwise, if the string contains "{{@literal<digit>}"
|
||||
* where {@literal <digit>} is in [0-9],
|
||||
* java.text.MessageFormat is used to format the string.
|
||||
* <li>Otherwise no formatting is performed.
|
||||
* </ul>
|
||||
*
|
||||
* @param record the log record containing the raw message
|
||||
* @return a localized and formatted message
|
||||
*/
|
||||
public String formatMessage(LogRecord record) {
|
||||
String format = record.getMessage();
|
||||
java.util.ResourceBundle catalog = record.getResourceBundle();
|
||||
if (catalog != null) {
|
||||
try {
|
||||
format = catalog.getString(format);
|
||||
} catch (java.util.MissingResourceException ex) {
|
||||
// Drop through. Use record message as format
|
||||
}
|
||||
}
|
||||
// Do the formatting.
|
||||
try {
|
||||
Object parameters[] = record.getParameters();
|
||||
if (parameters == null || parameters.length == 0) {
|
||||
// No parameters. Just return format string.
|
||||
return format;
|
||||
}
|
||||
// Is it a java.text style format?
|
||||
// Ideally we could match with
|
||||
// Pattern.compile("\\{\\d").matcher(format).find())
|
||||
// However the cost is 14% higher, so we cheaply use indexOf
|
||||
// and charAt to look for that pattern.
|
||||
int index = -1;
|
||||
int fence = format.length() - 1;
|
||||
while ((index = format.indexOf('{', index+1)) > -1) {
|
||||
if (index >= fence) break;
|
||||
char digit = format.charAt(index+1);
|
||||
if (digit >= '0' & digit <= '9') {
|
||||
return java.text.MessageFormat.format(format, parameters);
|
||||
}
|
||||
}
|
||||
return format;
|
||||
|
||||
} catch (Exception ex) {
|
||||
// Formatting failed: use localized format string.
|
||||
return format;
|
||||
}
|
||||
}
|
||||
}
|
354
src/java.logging/share/classes/java/util/logging/Handler.java
Normal file
354
src/java.logging/share/classes/java/util/logging/Handler.java
Normal file
|
@ -0,0 +1,354 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package java.util.logging;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* A {@code Handler} object takes log messages from a {@code Logger} and
|
||||
* exports them. It might for example, write them to a console
|
||||
* or write them to a file, or send them to a network logging service,
|
||||
* or forward them to an OS log, or whatever.
|
||||
* <p>
|
||||
* A {@code Handler} can be disabled by doing a {@code setLevel(Level.OFF)}
|
||||
* and can be re-enabled by doing a {@code setLevel} with an appropriate level.
|
||||
* <p>
|
||||
* {@code Handler} classes typically use {@code LogManager} properties to set
|
||||
* default values for the {@code Handler}'s {@code Filter}, {@code Formatter},
|
||||
* and {@code Level}. See the specific documentation for each concrete
|
||||
* {@code Handler} class.
|
||||
*
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
|
||||
public abstract class Handler {
|
||||
private static final int offValue = Level.OFF.intValue();
|
||||
private final LogManager manager = LogManager.getLogManager();
|
||||
|
||||
// We're using volatile here to avoid synchronizing getters, which
|
||||
// would prevent other threads from calling isLoggable()
|
||||
// while publish() is executing.
|
||||
// On the other hand, setters will be synchronized to exclude concurrent
|
||||
// execution with more complex methods, such as StreamHandler.publish().
|
||||
// We wouldn't want 'level' to be changed by another thread in the middle
|
||||
// of the execution of a 'publish' call.
|
||||
private volatile Filter filter;
|
||||
private volatile Formatter formatter;
|
||||
private volatile Level logLevel = Level.ALL;
|
||||
private volatile ErrorManager errorManager = new ErrorManager();
|
||||
private volatile String encoding;
|
||||
|
||||
/**
|
||||
* Default constructor. The resulting {@code Handler} has a log
|
||||
* level of {@code Level.ALL}, no {@code Formatter}, and no
|
||||
* {@code Filter}. A default {@code ErrorManager} instance is installed
|
||||
* as the {@code ErrorManager}.
|
||||
*/
|
||||
protected Handler() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Package-private constructor for chaining from subclass constructors
|
||||
* that wish to configure the handler with specific default and/or
|
||||
* specified values.
|
||||
*
|
||||
* @param defaultLevel a default {@link Level} to configure if one is
|
||||
* not found in LogManager configuration properties
|
||||
* @param defaultFormatter a default {@link Formatter} to configure if one is
|
||||
* not specified by {@code specifiedFormatter} parameter
|
||||
* nor found in LogManager configuration properties
|
||||
* @param specifiedFormatter if not null, this is the formatter to configure
|
||||
*/
|
||||
Handler(Level defaultLevel, Formatter defaultFormatter,
|
||||
Formatter specifiedFormatter) {
|
||||
|
||||
LogManager manager = LogManager.getLogManager();
|
||||
String cname = getClass().getName();
|
||||
|
||||
final Level level = manager.getLevelProperty(cname + ".level", defaultLevel);
|
||||
final Filter filter = manager.getFilterProperty(cname + ".filter", null);
|
||||
final Formatter formatter = specifiedFormatter == null
|
||||
? manager.getFormatterProperty(cname + ".formatter", defaultFormatter)
|
||||
: specifiedFormatter;
|
||||
final String encoding = manager.getStringProperty(cname + ".encoding", null);
|
||||
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
@Override
|
||||
public Void run() {
|
||||
setLevel(level);
|
||||
setFilter(filter);
|
||||
setFormatter(formatter);
|
||||
try {
|
||||
setEncoding(encoding);
|
||||
} catch (Exception ex) {
|
||||
try {
|
||||
setEncoding(null);
|
||||
} catch (Exception ex2) {
|
||||
// doing a setEncoding with null should always work.
|
||||
// assert false;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}, null, LogManager.controlPermission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish a {@code LogRecord}.
|
||||
* <p>
|
||||
* The logging request was made initially to a {@code Logger} object,
|
||||
* which initialized the {@code LogRecord} and forwarded it here.
|
||||
* <p>
|
||||
* The {@code Handler} is responsible for formatting the message, when and
|
||||
* if necessary. The formatting should include localization.
|
||||
*
|
||||
* @param record description of the log event. A null record is
|
||||
* silently ignored and is not published
|
||||
*/
|
||||
public abstract void publish(LogRecord record);
|
||||
|
||||
/**
|
||||
* Flush any buffered output.
|
||||
*/
|
||||
public abstract void flush();
|
||||
|
||||
/**
|
||||
* Close the {@code Handler} and free all associated resources.
|
||||
* <p>
|
||||
* The close method will perform a {@code flush} and then close the
|
||||
* {@code Handler}. After close has been called this {@code Handler}
|
||||
* should no longer be used. Method calls may either be silently
|
||||
* ignored or may throw runtime exceptions.
|
||||
*
|
||||
* @exception SecurityException if a security manager exists and if
|
||||
* the caller does not have {@code LoggingPermission("control")}.
|
||||
*/
|
||||
public abstract void close() throws SecurityException;
|
||||
|
||||
/**
|
||||
* Set a {@code Formatter}. This {@code Formatter} will be used
|
||||
* to format {@code LogRecords} for this {@code Handler}.
|
||||
* <p>
|
||||
* Some {@code Handlers} may not use {@code Formatters}, in
|
||||
* which case the {@code Formatter} will be remembered, but not used.
|
||||
*
|
||||
* @param newFormatter the {@code Formatter} to use (may not be null)
|
||||
* @exception SecurityException if a security manager exists and if
|
||||
* the caller does not have {@code LoggingPermission("control")}.
|
||||
*/
|
||||
public synchronized void setFormatter(Formatter newFormatter) throws SecurityException {
|
||||
checkPermission();
|
||||
formatter = Objects.requireNonNull(newFormatter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@code Formatter} for this {@code Handler}.
|
||||
* @return the {@code Formatter} (may be null).
|
||||
*/
|
||||
public Formatter getFormatter() {
|
||||
return formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the character encoding used by this {@code Handler}.
|
||||
* <p>
|
||||
* The encoding should be set before any {@code LogRecords} are written
|
||||
* to the {@code Handler}.
|
||||
*
|
||||
* @param encoding The name of a supported character encoding.
|
||||
* May be null, to indicate the default platform encoding.
|
||||
* @exception SecurityException if a security manager exists and if
|
||||
* the caller does not have {@code LoggingPermission("control")}.
|
||||
* @exception UnsupportedEncodingException if the named encoding is
|
||||
* not supported.
|
||||
*/
|
||||
public synchronized void setEncoding(String encoding)
|
||||
throws SecurityException, java.io.UnsupportedEncodingException {
|
||||
checkPermission();
|
||||
if (encoding != null) {
|
||||
try {
|
||||
if(!java.nio.charset.Charset.isSupported(encoding)) {
|
||||
throw new UnsupportedEncodingException(encoding);
|
||||
}
|
||||
} catch (java.nio.charset.IllegalCharsetNameException e) {
|
||||
throw new UnsupportedEncodingException(encoding);
|
||||
}
|
||||
}
|
||||
this.encoding = encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the character encoding for this {@code Handler}.
|
||||
*
|
||||
* @return The encoding name. May be null, which indicates the
|
||||
* default encoding should be used.
|
||||
*/
|
||||
public String getEncoding() {
|
||||
return encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a {@code Filter} to control output on this {@code Handler}.
|
||||
* <P>
|
||||
* For each call of {@code publish} the {@code Handler} will call
|
||||
* this {@code Filter} (if it is non-null) to check if the
|
||||
* {@code LogRecord} should be published or discarded.
|
||||
*
|
||||
* @param newFilter a {@code Filter} object (may be null)
|
||||
* @exception SecurityException if a security manager exists and if
|
||||
* the caller does not have {@code LoggingPermission("control")}.
|
||||
*/
|
||||
public synchronized void setFilter(Filter newFilter) throws SecurityException {
|
||||
checkPermission();
|
||||
filter = newFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current {@code Filter} for this {@code Handler}.
|
||||
*
|
||||
* @return a {@code Filter} object (may be null)
|
||||
*/
|
||||
public Filter getFilter() {
|
||||
return filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define an ErrorManager for this Handler.
|
||||
* <p>
|
||||
* The ErrorManager's "error" method will be invoked if any
|
||||
* errors occur while using this Handler.
|
||||
*
|
||||
* @param em the new ErrorManager
|
||||
* @exception SecurityException if a security manager exists and if
|
||||
* the caller does not have {@code LoggingPermission("control")}.
|
||||
*/
|
||||
public synchronized void setErrorManager(ErrorManager em) {
|
||||
checkPermission();
|
||||
if (em == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
errorManager = em;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ErrorManager for this Handler.
|
||||
*
|
||||
* @return the ErrorManager for this Handler
|
||||
* @exception SecurityException if a security manager exists and if
|
||||
* the caller does not have {@code LoggingPermission("control")}.
|
||||
*/
|
||||
public ErrorManager getErrorManager() {
|
||||
checkPermission();
|
||||
return errorManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected convenience method to report an error to this Handler's
|
||||
* ErrorManager. Note that this method retrieves and uses the ErrorManager
|
||||
* without doing a security check. It can therefore be used in
|
||||
* environments where the caller may be non-privileged.
|
||||
*
|
||||
* @param msg a descriptive string (may be null)
|
||||
* @param ex an exception (may be null)
|
||||
* @param code an error code defined in ErrorManager
|
||||
*/
|
||||
protected void reportError(String msg, Exception ex, int code) {
|
||||
try {
|
||||
errorManager.error(msg, ex, code);
|
||||
} catch (Exception ex2) {
|
||||
System.err.println("Handler.reportError caught:");
|
||||
ex2.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the log level specifying which message levels will be
|
||||
* logged by this {@code Handler}. Message levels lower than this
|
||||
* value will be discarded.
|
||||
* <p>
|
||||
* The intention is to allow developers to turn on voluminous
|
||||
* logging, but to limit the messages that are sent to certain
|
||||
* {@code Handlers}.
|
||||
*
|
||||
* @param newLevel the new value for the log level
|
||||
* @exception SecurityException if a security manager exists and if
|
||||
* the caller does not have {@code LoggingPermission("control")}.
|
||||
*/
|
||||
public synchronized void setLevel(Level newLevel) throws SecurityException {
|
||||
if (newLevel == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
checkPermission();
|
||||
logLevel = newLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the log level specifying which messages will be
|
||||
* logged by this {@code Handler}. Message levels lower
|
||||
* than this level will be discarded.
|
||||
* @return the level of messages being logged.
|
||||
*/
|
||||
public Level getLevel() {
|
||||
return logLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this {@code Handler} would actually log a given {@code LogRecord}.
|
||||
* <p>
|
||||
* This method checks if the {@code LogRecord} has an appropriate
|
||||
* {@code Level} and whether it satisfies any {@code Filter}. It also
|
||||
* may make other {@code Handler} specific checks that might prevent a
|
||||
* handler from logging the {@code LogRecord}. It will return false if
|
||||
* the {@code LogRecord} is null.
|
||||
*
|
||||
* @param record a {@code LogRecord}
|
||||
* @return true if the {@code LogRecord} would be logged.
|
||||
*
|
||||
*/
|
||||
public boolean isLoggable(LogRecord record) {
|
||||
final int levelValue = getLevel().intValue();
|
||||
if (record.getLevel().intValue() < levelValue || levelValue == offValue) {
|
||||
return false;
|
||||
}
|
||||
final Filter filter = getFilter();
|
||||
if (filter == null) {
|
||||
return true;
|
||||
}
|
||||
return filter.isLoggable(record);
|
||||
}
|
||||
|
||||
// Package-private support method for security checks.
|
||||
// We check that the caller has appropriate security privileges
|
||||
// to update Handler state and if not throw a SecurityException.
|
||||
void checkPermission() throws SecurityException {
|
||||
manager.checkPermission();
|
||||
}
|
||||
}
|
710
src/java.logging/share/classes/java/util/logging/Level.java
Normal file
710
src/java.logging/share/classes/java/util/logging/Level.java
Normal file
|
@ -0,0 +1,710 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.logging;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.function.Function;
|
||||
import jdk.internal.loader.ClassLoaderValue;
|
||||
import jdk.internal.misc.JavaUtilResourceBundleAccess;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
|
||||
/**
|
||||
* The Level class defines a set of standard logging levels that
|
||||
* can be used to control logging output. The logging Level objects
|
||||
* are ordered and are specified by ordered integers. Enabling logging
|
||||
* at a given level also enables logging at all higher levels.
|
||||
* <p>
|
||||
* Clients should normally use the predefined Level constants such
|
||||
* as Level.SEVERE.
|
||||
* <p>
|
||||
* The levels in descending order are:
|
||||
* <ul>
|
||||
* <li>SEVERE (highest value)
|
||||
* <li>WARNING
|
||||
* <li>INFO
|
||||
* <li>CONFIG
|
||||
* <li>FINE
|
||||
* <li>FINER
|
||||
* <li>FINEST (lowest value)
|
||||
* </ul>
|
||||
* In addition there is a level OFF that can be used to turn
|
||||
* off logging, and a level ALL that can be used to enable
|
||||
* logging of all messages.
|
||||
* <p>
|
||||
* It is possible for third parties to define additional logging
|
||||
* levels by subclassing Level. In such cases subclasses should
|
||||
* take care to chose unique integer level values and to ensure that
|
||||
* they maintain the Object uniqueness property across serialization
|
||||
* by defining a suitable readResolve method.
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
|
||||
public class Level implements java.io.Serializable {
|
||||
private static final String defaultBundle =
|
||||
"sun.util.logging.resources.logging";
|
||||
|
||||
// Calling SharedSecrets.getJavaUtilResourceBundleAccess()
|
||||
// forces the initialization of ResourceBundle.class, which
|
||||
// can be too early if the VM has not finished booting yet.
|
||||
private static final class RbAccess {
|
||||
static final JavaUtilResourceBundleAccess RB_ACCESS =
|
||||
SharedSecrets.getJavaUtilResourceBundleAccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* @serial The non-localized name of the level.
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* @serial The integer value of the level.
|
||||
*/
|
||||
private final int value;
|
||||
|
||||
/**
|
||||
* @serial The resource bundle name to be used in localizing the level name.
|
||||
*/
|
||||
private final String resourceBundleName;
|
||||
|
||||
// localized level name
|
||||
private transient String localizedLevelName;
|
||||
private transient Locale cachedLocale;
|
||||
|
||||
/**
|
||||
* OFF is a special level that can be used to turn off logging.
|
||||
* This level is initialized to <CODE>Integer.MAX_VALUE</CODE>.
|
||||
*/
|
||||
public static final Level OFF = new Level("OFF",Integer.MAX_VALUE, defaultBundle);
|
||||
|
||||
/**
|
||||
* SEVERE is a message level indicating a serious failure.
|
||||
* <p>
|
||||
* In general SEVERE messages should describe events that are
|
||||
* of considerable importance and which will prevent normal
|
||||
* program execution. They should be reasonably intelligible
|
||||
* to end users and to system administrators.
|
||||
* This level is initialized to <CODE>1000</CODE>.
|
||||
*/
|
||||
public static final Level SEVERE = new Level("SEVERE",1000, defaultBundle);
|
||||
|
||||
/**
|
||||
* WARNING is a message level indicating a potential problem.
|
||||
* <p>
|
||||
* In general WARNING messages should describe events that will
|
||||
* be of interest to end users or system managers, or which
|
||||
* indicate potential problems.
|
||||
* This level is initialized to <CODE>900</CODE>.
|
||||
*/
|
||||
public static final Level WARNING = new Level("WARNING", 900, defaultBundle);
|
||||
|
||||
/**
|
||||
* INFO is a message level for informational messages.
|
||||
* <p>
|
||||
* Typically INFO messages will be written to the console
|
||||
* or its equivalent. So the INFO level should only be
|
||||
* used for reasonably significant messages that will
|
||||
* make sense to end users and system administrators.
|
||||
* This level is initialized to <CODE>800</CODE>.
|
||||
*/
|
||||
public static final Level INFO = new Level("INFO", 800, defaultBundle);
|
||||
|
||||
/**
|
||||
* CONFIG is a message level for static configuration messages.
|
||||
* <p>
|
||||
* CONFIG messages are intended to provide a variety of static
|
||||
* configuration information, to assist in debugging problems
|
||||
* that may be associated with particular configurations.
|
||||
* For example, CONFIG message might include the CPU type,
|
||||
* the graphics depth, the GUI look-and-feel, etc.
|
||||
* This level is initialized to <CODE>700</CODE>.
|
||||
*/
|
||||
public static final Level CONFIG = new Level("CONFIG", 700, defaultBundle);
|
||||
|
||||
/**
|
||||
* FINE is a message level providing tracing information.
|
||||
* <p>
|
||||
* All of FINE, FINER, and FINEST are intended for relatively
|
||||
* detailed tracing. The exact meaning of the three levels will
|
||||
* vary between subsystems, but in general, FINEST should be used
|
||||
* for the most voluminous detailed output, FINER for somewhat
|
||||
* less detailed output, and FINE for the lowest volume (and
|
||||
* most important) messages.
|
||||
* <p>
|
||||
* In general the FINE level should be used for information
|
||||
* that will be broadly interesting to developers who do not have
|
||||
* a specialized interest in the specific subsystem.
|
||||
* <p>
|
||||
* FINE messages might include things like minor (recoverable)
|
||||
* failures. Issues indicating potential performance problems
|
||||
* are also worth logging as FINE.
|
||||
* This level is initialized to <CODE>500</CODE>.
|
||||
*/
|
||||
public static final Level FINE = new Level("FINE", 500, defaultBundle);
|
||||
|
||||
/**
|
||||
* FINER indicates a fairly detailed tracing message.
|
||||
* By default logging calls for entering, returning, or throwing
|
||||
* an exception are traced at this level.
|
||||
* This level is initialized to <CODE>400</CODE>.
|
||||
*/
|
||||
public static final Level FINER = new Level("FINER", 400, defaultBundle);
|
||||
|
||||
/**
|
||||
* FINEST indicates a highly detailed tracing message.
|
||||
* This level is initialized to <CODE>300</CODE>.
|
||||
*/
|
||||
public static final Level FINEST = new Level("FINEST", 300, defaultBundle);
|
||||
|
||||
/**
|
||||
* ALL indicates that all messages should be logged.
|
||||
* This level is initialized to <CODE>Integer.MIN_VALUE</CODE>.
|
||||
*/
|
||||
public static final Level ALL = new Level("ALL", Integer.MIN_VALUE, defaultBundle);
|
||||
|
||||
private static final Level[] standardLevels = {
|
||||
OFF, SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST, ALL
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a named Level with a given integer value.
|
||||
* <p>
|
||||
* Note that this constructor is "protected" to allow subclassing.
|
||||
* In general clients of logging should use one of the constant Level
|
||||
* objects such as SEVERE or FINEST. However, if clients need to
|
||||
* add new logging levels, they may subclass Level and define new
|
||||
* constants.
|
||||
* @param name the name of the Level, for example "SEVERE".
|
||||
* @param value an integer value for the level.
|
||||
* @throws NullPointerException if the name is null
|
||||
*/
|
||||
protected Level(String name, int value) {
|
||||
this(name, value, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a named Level with a given integer value and a
|
||||
* given localization resource name.
|
||||
*
|
||||
* @param name the name of the Level, for example "SEVERE".
|
||||
* @param value an integer value for the level.
|
||||
* @param resourceBundleName name of a resource bundle to use in
|
||||
* localizing the given name. If the resourceBundleName is null
|
||||
* or an empty string, it is ignored.
|
||||
* @throws NullPointerException if the name is null
|
||||
*/
|
||||
protected Level(String name, int value, String resourceBundleName) {
|
||||
this(name, value, resourceBundleName, true);
|
||||
}
|
||||
|
||||
// private constructor to specify whether this instance should be added
|
||||
// to the KnownLevel list from which Level.parse method does its look up
|
||||
private Level(String name, int value, String resourceBundleName, boolean visible) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.resourceBundleName = resourceBundleName;
|
||||
this.localizedLevelName = resourceBundleName == null ? name : null;
|
||||
this.cachedLocale = null;
|
||||
if (visible) {
|
||||
KnownLevel.add(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the level's localization resource bundle name, or
|
||||
* null if no localization bundle is defined.
|
||||
*
|
||||
* @return localization resource bundle name
|
||||
*/
|
||||
public String getResourceBundleName() {
|
||||
return resourceBundleName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the non-localized string name of the Level.
|
||||
*
|
||||
* @return non-localized name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the localized string name of the Level, for
|
||||
* the current default locale.
|
||||
* <p>
|
||||
* If no localization information is available, the
|
||||
* non-localized name is returned.
|
||||
*
|
||||
* @return localized name
|
||||
*/
|
||||
public String getLocalizedName() {
|
||||
return getLocalizedLevelName();
|
||||
}
|
||||
|
||||
// package-private getLevelName() is used by the implementation
|
||||
// instead of getName() to avoid calling the subclass's version
|
||||
final String getLevelName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
private String computeLocalizedLevelName(Locale newLocale) {
|
||||
// Resource bundle should be loaded from the defining module
|
||||
// or its defining class loader, if it's unnamed module,
|
||||
// of this Level instance that can be a custom Level subclass;
|
||||
Module module = this.getClass().getModule();
|
||||
ResourceBundle rb = RbAccess.RB_ACCESS.getBundle(resourceBundleName,
|
||||
newLocale, module);
|
||||
|
||||
final String localizedName = rb.getString(name);
|
||||
final boolean isDefaultBundle = defaultBundle.equals(resourceBundleName);
|
||||
if (!isDefaultBundle) return localizedName;
|
||||
|
||||
// This is a trick to determine whether the name has been translated
|
||||
// or not. If it has not been translated, we need to use Locale.ROOT
|
||||
// when calling toUpperCase().
|
||||
final Locale rbLocale = rb.getLocale();
|
||||
final Locale locale =
|
||||
Locale.ROOT.equals(rbLocale)
|
||||
|| name.equals(localizedName.toUpperCase(Locale.ROOT))
|
||||
? Locale.ROOT : rbLocale;
|
||||
|
||||
// ALL CAPS in a resource bundle's message indicates no translation
|
||||
// needed per Oracle translation guideline. To workaround this
|
||||
// in Oracle JDK implementation, convert the localized level name
|
||||
// to uppercase for compatibility reason.
|
||||
return Locale.ROOT.equals(locale) ? name : localizedName.toUpperCase(locale);
|
||||
}
|
||||
|
||||
// Avoid looking up the localizedLevelName twice if we already
|
||||
// have it.
|
||||
final String getCachedLocalizedLevelName() {
|
||||
|
||||
if (localizedLevelName != null) {
|
||||
if (cachedLocale != null) {
|
||||
if (cachedLocale.equals(Locale.getDefault())) {
|
||||
// OK: our cached value was looked up with the same
|
||||
// locale. We can use it.
|
||||
return localizedLevelName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (resourceBundleName == null) {
|
||||
// No resource bundle: just use the name.
|
||||
return name;
|
||||
}
|
||||
|
||||
// We need to compute the localized name.
|
||||
// Either because it's the first time, or because our cached
|
||||
// value is for a different locale. Just return null.
|
||||
return null;
|
||||
}
|
||||
|
||||
final synchronized String getLocalizedLevelName() {
|
||||
|
||||
// See if we have a cached localized name
|
||||
final String cachedLocalizedName = getCachedLocalizedLevelName();
|
||||
if (cachedLocalizedName != null) {
|
||||
return cachedLocalizedName;
|
||||
}
|
||||
|
||||
// No cached localized name or cache invalid.
|
||||
// Need to compute the localized name.
|
||||
final Locale newLocale = Locale.getDefault();
|
||||
try {
|
||||
localizedLevelName = computeLocalizedLevelName(newLocale);
|
||||
} catch (Exception ex) {
|
||||
localizedLevelName = name;
|
||||
}
|
||||
cachedLocale = newLocale;
|
||||
return localizedLevelName;
|
||||
}
|
||||
|
||||
// Returns a mirrored Level object that matches the given name as
|
||||
// specified in the Level.parse method. Returns null if not found.
|
||||
//
|
||||
// It returns the same Level object as the one returned by Level.parse
|
||||
// method if the given name is a non-localized name or integer.
|
||||
//
|
||||
// If the name is a localized name, findLevel and parse method may
|
||||
// return a different level value if there is a custom Level subclass
|
||||
// that overrides Level.getLocalizedName() to return a different string
|
||||
// than what's returned by the default implementation.
|
||||
//
|
||||
static Level findLevel(String name) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
Optional<Level> level;
|
||||
|
||||
// Look for a known Level with the given non-localized name.
|
||||
level = KnownLevel.findByName(name, KnownLevel::mirrored);
|
||||
if (level.isPresent()) {
|
||||
return level.get();
|
||||
}
|
||||
|
||||
// Now, check if the given name is an integer. If so,
|
||||
// first look for a Level with the given value and then
|
||||
// if necessary create one.
|
||||
try {
|
||||
int x = Integer.parseInt(name);
|
||||
level = KnownLevel.findByValue(x, KnownLevel::mirrored);
|
||||
if (!level.isPresent()) {
|
||||
// add new Level
|
||||
Level levelObject = new Level(name, x);
|
||||
// There's no need to use a reachability fence here because
|
||||
// KnownLevel keeps a strong reference on the level when
|
||||
// level.getClass() == Level.class.
|
||||
return KnownLevel.findByValue(x, KnownLevel::mirrored).get();
|
||||
}
|
||||
} catch (NumberFormatException ex) {
|
||||
// Not an integer.
|
||||
// Drop through.
|
||||
}
|
||||
|
||||
level = KnownLevel.findByLocalizedLevelName(name,
|
||||
KnownLevel::mirrored);
|
||||
if (level.isPresent()) {
|
||||
return level.get();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this Level.
|
||||
*
|
||||
* @return the non-localized name of the Level, for example "INFO".
|
||||
*/
|
||||
@Override
|
||||
public final String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the integer value for this level. This integer value
|
||||
* can be used for efficient ordering comparisons between
|
||||
* Level objects.
|
||||
* @return the integer value for this level.
|
||||
*/
|
||||
public final int intValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = -8176160795706313070L;
|
||||
|
||||
// Serialization magic to prevent "doppelgangers".
|
||||
// This is a performance optimization.
|
||||
private Object readResolve() {
|
||||
Optional<Level> level = KnownLevel.matches(this);
|
||||
if (level.isPresent()) {
|
||||
return level.get();
|
||||
}
|
||||
// Woops. Whoever sent us this object knows
|
||||
// about a new log level. Add it to our list.
|
||||
return new Level(this.name, this.value, this.resourceBundleName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a level name string into a Level.
|
||||
* <p>
|
||||
* The argument string may consist of either a level name
|
||||
* or an integer value.
|
||||
* <p>
|
||||
* For example:
|
||||
* <ul>
|
||||
* <li> "SEVERE"
|
||||
* <li> "1000"
|
||||
* </ul>
|
||||
*
|
||||
* @param name string to be parsed
|
||||
* @throws NullPointerException if the name is null
|
||||
* @throws IllegalArgumentException if the value is not valid.
|
||||
* Valid values are integers between <CODE>Integer.MIN_VALUE</CODE>
|
||||
* and <CODE>Integer.MAX_VALUE</CODE>, and all known level names.
|
||||
* Known names are the levels defined by this class (e.g., <CODE>FINE</CODE>,
|
||||
* <CODE>FINER</CODE>, <CODE>FINEST</CODE>), or created by this class with
|
||||
* appropriate package access, or new levels defined or created
|
||||
* by subclasses.
|
||||
*
|
||||
* @return The parsed value. Passing an integer that corresponds to a known name
|
||||
* (e.g., 700) will return the associated name (e.g., <CODE>CONFIG</CODE>).
|
||||
* Passing an integer that does not (e.g., 1) will return a new level name
|
||||
* initialized to that value.
|
||||
*/
|
||||
public static synchronized Level parse(String name) throws IllegalArgumentException {
|
||||
// Check that name is not null.
|
||||
name.length();
|
||||
|
||||
Optional<Level> level;
|
||||
|
||||
// Look for a known Level with the given non-localized name.
|
||||
level = KnownLevel.findByName(name, KnownLevel::referent);
|
||||
if (level.isPresent()) {
|
||||
return level.get();
|
||||
}
|
||||
|
||||
// Now, check if the given name is an integer. If so,
|
||||
// first look for a Level with the given value and then
|
||||
// if necessary create one.
|
||||
try {
|
||||
int x = Integer.parseInt(name);
|
||||
level = KnownLevel.findByValue(x, KnownLevel::referent);
|
||||
if (level.isPresent()) {
|
||||
return level.get();
|
||||
}
|
||||
// add new Level.
|
||||
Level levelObject = new Level(name, x);
|
||||
// There's no need to use a reachability fence here because
|
||||
// KnownLevel keeps a strong reference on the level when
|
||||
// level.getClass() == Level.class.
|
||||
return KnownLevel.findByValue(x, KnownLevel::referent).get();
|
||||
} catch (NumberFormatException ex) {
|
||||
// Not an integer.
|
||||
// Drop through.
|
||||
}
|
||||
|
||||
// Finally, look for a known level with the given localized name,
|
||||
// in the current default locale.
|
||||
// This is relatively expensive, but not excessively so.
|
||||
level = KnownLevel.findByLocalizedLevelName(name, KnownLevel::referent);
|
||||
if (level .isPresent()) {
|
||||
return level.get();
|
||||
}
|
||||
|
||||
// OK, we've tried everything and failed
|
||||
throw new IllegalArgumentException("Bad level \"" + name + "\"");
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two objects for value equality.
|
||||
* @return true if and only if the two objects have the same level value.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object ox) {
|
||||
try {
|
||||
Level lx = (Level)ox;
|
||||
return (lx.value == this.value);
|
||||
} catch (Exception ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a hashcode.
|
||||
* @return a hashcode based on the level value
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
// KnownLevel class maintains the global list of all known levels.
|
||||
// The API allows multiple custom Level instances of the same name/value
|
||||
// be created. This class provides convenient methods to find a level
|
||||
// by a given name, by a given value, or by a given localized name.
|
||||
//
|
||||
// KnownLevel wraps the following Level objects:
|
||||
// 1. levelObject: standard Level object or custom Level object
|
||||
// 2. mirroredLevel: Level object representing the level specified in the
|
||||
// logging configuration.
|
||||
//
|
||||
// Level.getName, Level.getLocalizedName, Level.getResourceBundleName methods
|
||||
// are non-final but the name and resource bundle name are parameters to
|
||||
// the Level constructor. Use the mirroredLevel object instead of the
|
||||
// levelObject to prevent the logging framework to execute foreign code
|
||||
// implemented by untrusted Level subclass.
|
||||
//
|
||||
// Implementation Notes:
|
||||
// If Level.getName, Level.getLocalizedName, Level.getResourceBundleName methods
|
||||
// were final, the following KnownLevel implementation can be removed.
|
||||
// Future API change should take this into consideration.
|
||||
static final class KnownLevel extends WeakReference<Level> {
|
||||
private static Map<String, List<KnownLevel>> nameToLevels = new HashMap<>();
|
||||
private static Map<Integer, List<KnownLevel>> intToLevels = new HashMap<>();
|
||||
private static final ReferenceQueue<Level> QUEUE = new ReferenceQueue<>();
|
||||
|
||||
// CUSTOM_LEVEL_CLV is used to register custom level instances with
|
||||
// their defining class loader, so that they are garbage collected
|
||||
// if and only if their class loader is no longer strongly
|
||||
// referenced.
|
||||
private static final ClassLoaderValue<List<Level>> CUSTOM_LEVEL_CLV =
|
||||
new ClassLoaderValue<>();
|
||||
|
||||
final Level mirroredLevel; // mirror of the custom Level
|
||||
KnownLevel(Level l) {
|
||||
super(l, QUEUE);
|
||||
if (l.getClass() == Level.class) {
|
||||
this.mirroredLevel = l;
|
||||
} else {
|
||||
// this mirrored level object is hidden
|
||||
this.mirroredLevel = new Level(l.name, l.value,
|
||||
l.resourceBundleName, false);
|
||||
}
|
||||
}
|
||||
|
||||
Optional<Level> mirrored() {
|
||||
return Optional.of(mirroredLevel);
|
||||
}
|
||||
|
||||
Optional<Level> referent() {
|
||||
return Optional.ofNullable(get());
|
||||
}
|
||||
|
||||
private void remove() {
|
||||
Optional.ofNullable(nameToLevels.get(mirroredLevel.name))
|
||||
.ifPresent((x) -> x.remove(this));
|
||||
Optional.ofNullable(intToLevels.get(mirroredLevel.value))
|
||||
.ifPresent((x) -> x.remove(this));
|
||||
}
|
||||
|
||||
// Remove all stale KnownLevel instances
|
||||
static synchronized void purge() {
|
||||
Reference<? extends Level> ref;
|
||||
while ((ref = QUEUE.poll()) != null) {
|
||||
if (ref instanceof KnownLevel) {
|
||||
((KnownLevel)ref).remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void registerWithClassLoader(Level customLevel) {
|
||||
PrivilegedAction<ClassLoader> pa =
|
||||
() -> customLevel.getClass().getClassLoader();
|
||||
PrivilegedAction<String> pn = customLevel.getClass()::getName;
|
||||
final String name = AccessController.doPrivileged(pn);
|
||||
final ClassLoader cl = AccessController.doPrivileged(pa);
|
||||
CUSTOM_LEVEL_CLV.computeIfAbsent(cl, (c, v) -> new ArrayList<>())
|
||||
.add(customLevel);
|
||||
}
|
||||
|
||||
static synchronized void add(Level l) {
|
||||
purge();
|
||||
// the mirroredLevel object is always added to the list
|
||||
// before the custom Level instance
|
||||
KnownLevel o = new KnownLevel(l);
|
||||
List<KnownLevel> list = nameToLevels.get(l.name);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
nameToLevels.put(l.name, list);
|
||||
}
|
||||
list.add(o);
|
||||
|
||||
list = intToLevels.get(l.value);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
intToLevels.put(l.value, list);
|
||||
}
|
||||
list.add(o);
|
||||
|
||||
// keep the custom level reachable from its class loader
|
||||
// This will ensure that custom level values are not GC'ed
|
||||
// until there class loader is GC'ed.
|
||||
if (o.mirroredLevel != l) {
|
||||
registerWithClassLoader(l);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Returns a KnownLevel with the given non-localized name.
|
||||
static synchronized Optional<Level> findByName(String name,
|
||||
Function<KnownLevel, Optional<Level>> selector) {
|
||||
purge();
|
||||
return nameToLevels.getOrDefault(name, Collections.emptyList())
|
||||
.stream()
|
||||
.map(selector)
|
||||
.flatMap(Optional::stream)
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
// Returns a KnownLevel with the given value.
|
||||
static synchronized Optional<Level> findByValue(int value,
|
||||
Function<KnownLevel, Optional<Level>> selector) {
|
||||
purge();
|
||||
return intToLevels.getOrDefault(value, Collections.emptyList())
|
||||
.stream()
|
||||
.map(selector)
|
||||
.flatMap(Optional::stream)
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
// Returns a KnownLevel with the given localized name matching
|
||||
// by calling the Level.getLocalizedLevelName() method (i.e. found
|
||||
// from the resourceBundle associated with the Level object).
|
||||
// This method does not call Level.getLocalizedName() that may
|
||||
// be overridden in a subclass implementation
|
||||
static synchronized Optional<Level> findByLocalizedLevelName(String name,
|
||||
Function<KnownLevel, Optional<Level>> selector) {
|
||||
purge();
|
||||
return nameToLevels.values().stream()
|
||||
.flatMap(List::stream)
|
||||
.map(selector)
|
||||
.flatMap(Optional::stream)
|
||||
.filter(l -> name.equals(l.getLocalizedLevelName()))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
static synchronized Optional<Level> matches(Level l) {
|
||||
purge();
|
||||
List<KnownLevel> list = nameToLevels.get(l.name);
|
||||
if (list != null) {
|
||||
for (KnownLevel ref : list) {
|
||||
Level levelObject = ref.get();
|
||||
if (levelObject == null) continue;
|
||||
Level other = ref.mirroredLevel;
|
||||
Class<? extends Level> type = levelObject.getClass();
|
||||
if (l.value == other.value &&
|
||||
(l.resourceBundleName == other.resourceBundleName ||
|
||||
(l.resourceBundleName != null &&
|
||||
l.resourceBundleName.equals(other.resourceBundleName)))) {
|
||||
if (type == l.getClass()) {
|
||||
return Optional.of(levelObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
2708
src/java.logging/share/classes/java/util/logging/LogManager.java
Normal file
2708
src/java.logging/share/classes/java/util/logging/LogManager.java
Normal file
File diff suppressed because it is too large
Load diff
742
src/java.logging/share/classes/java/util/logging/LogRecord.java
Normal file
742
src/java.logging/share/classes/java/util/logging/LogRecord.java
Normal file
|
@ -0,0 +1,742 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.logging;
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.io.*;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.time.Clock;
|
||||
import java.util.function.Predicate;
|
||||
import static jdk.internal.logger.SurrogateLogger.isFilteredFrame;
|
||||
|
||||
/**
|
||||
* LogRecord objects are used to pass logging requests between
|
||||
* the logging framework and individual log Handlers.
|
||||
* <p>
|
||||
* When a LogRecord is passed into the logging framework it
|
||||
* logically belongs to the framework and should no longer be
|
||||
* used or updated by the client application.
|
||||
* <p>
|
||||
* Note that if the client application has not specified an
|
||||
* explicit source method name and source class name, then the
|
||||
* LogRecord class will infer them automatically when they are
|
||||
* first accessed (due to a call on getSourceMethodName or
|
||||
* getSourceClassName) by analyzing the call stack. Therefore,
|
||||
* if a logging Handler wants to pass off a LogRecord to another
|
||||
* thread, or to transmit it over RMI, and if it wishes to subsequently
|
||||
* obtain method name or class name information it should call
|
||||
* one of getSourceClassName or getSourceMethodName to force
|
||||
* the values to be filled in.
|
||||
* <p>
|
||||
* <b> Serialization notes:</b>
|
||||
* <ul>
|
||||
* <li>The LogRecord class is serializable.
|
||||
*
|
||||
* <li> Because objects in the parameters array may not be serializable,
|
||||
* during serialization all objects in the parameters array are
|
||||
* written as the corresponding Strings (using Object.toString).
|
||||
*
|
||||
* <li> The ResourceBundle is not transmitted as part of the serialized
|
||||
* form, but the resource bundle name is, and the recipient object's
|
||||
* readObject method will attempt to locate a suitable resource bundle.
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
|
||||
public class LogRecord implements java.io.Serializable {
|
||||
private static final AtomicLong globalSequenceNumber
|
||||
= new AtomicLong(0);
|
||||
|
||||
/**
|
||||
* The default value of threadID will be the current thread's
|
||||
* thread id, for ease of correlation, unless it is greater than
|
||||
* MIN_SEQUENTIAL_THREAD_ID, in which case we try harder to keep
|
||||
* our promise to keep threadIDs unique by avoiding collisions due
|
||||
* to 32-bit wraparound. Unfortunately, LogRecord.getThreadID()
|
||||
* returns int, while Thread.getId() returns long.
|
||||
*/
|
||||
private static final int MIN_SEQUENTIAL_THREAD_ID = Integer.MAX_VALUE / 2;
|
||||
|
||||
private static final AtomicInteger nextThreadId
|
||||
= new AtomicInteger(MIN_SEQUENTIAL_THREAD_ID);
|
||||
|
||||
private static final ThreadLocal<Integer> threadIds = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* Logging message level
|
||||
*/
|
||||
private Level level;
|
||||
|
||||
/**
|
||||
* Sequence number
|
||||
*/
|
||||
private long sequenceNumber;
|
||||
|
||||
/**
|
||||
* Class that issued logging call
|
||||
*/
|
||||
private String sourceClassName;
|
||||
|
||||
/**
|
||||
* Method that issued logging call
|
||||
*/
|
||||
private String sourceMethodName;
|
||||
|
||||
/**
|
||||
* Non-localized raw message text
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* Thread ID for thread that issued logging call.
|
||||
*/
|
||||
private int threadID;
|
||||
|
||||
/**
|
||||
* The Throwable (if any) associated with log message
|
||||
*/
|
||||
private Throwable thrown;
|
||||
|
||||
/**
|
||||
* Name of the source Logger.
|
||||
*/
|
||||
private String loggerName;
|
||||
|
||||
/**
|
||||
* Resource bundle name to localized log message.
|
||||
*/
|
||||
private String resourceBundleName;
|
||||
|
||||
/**
|
||||
* Event time.
|
||||
* @since 9
|
||||
*/
|
||||
private Instant instant;
|
||||
|
||||
/**
|
||||
* @serialField level Level Logging message level
|
||||
* @serialField sequenceNumber long Sequence number
|
||||
* @serialField sourceClassName String Class that issued logging call
|
||||
* @serialField sourceMethodName String Method that issued logging call
|
||||
* @serialField message String Non-localized raw message text
|
||||
* @serialField threadID int Thread ID for thread that issued logging call
|
||||
* @serialField millis long Truncated event time in milliseconds since 1970
|
||||
* - calculated as getInstant().toEpochMilli().
|
||||
* The event time instant can be reconstructed using
|
||||
* <code>Instant.ofEpochSecond(millis/1000, (millis % 1000) * 1000_000 + nanoAdjustment)</code>
|
||||
* @serialField nanoAdjustment int Nanoseconds adjustment to the millisecond of
|
||||
* event time - calculated as getInstant().getNano() % 1000_000
|
||||
* The event time instant can be reconstructed using
|
||||
* <code>Instant.ofEpochSecond(millis/1000, (millis % 1000) * 1000_000 + nanoAdjustment)</code>
|
||||
* <p>
|
||||
* Since: 9
|
||||
* @serialField thrown Throwable The Throwable (if any) associated with log
|
||||
* message
|
||||
* @serialField loggerName String Name of the source Logger
|
||||
* @serialField resourceBundleName String Resource bundle name to localized
|
||||
* log message
|
||||
*/
|
||||
private static final ObjectStreamField[] serialPersistentFields =
|
||||
new ObjectStreamField[] {
|
||||
new ObjectStreamField("level", Level.class),
|
||||
new ObjectStreamField("sequenceNumber", long.class),
|
||||
new ObjectStreamField("sourceClassName", String.class),
|
||||
new ObjectStreamField("sourceMethodName", String.class),
|
||||
new ObjectStreamField("message", String.class),
|
||||
new ObjectStreamField("threadID", int.class),
|
||||
new ObjectStreamField("millis", long.class),
|
||||
new ObjectStreamField("nanoAdjustment", int.class),
|
||||
new ObjectStreamField("thrown", Throwable.class),
|
||||
new ObjectStreamField("loggerName", String.class),
|
||||
new ObjectStreamField("resourceBundleName", String.class),
|
||||
};
|
||||
|
||||
private transient boolean needToInferCaller;
|
||||
private transient Object parameters[];
|
||||
private transient ResourceBundle resourceBundle;
|
||||
|
||||
/**
|
||||
* Returns the default value for a new LogRecord's threadID.
|
||||
*/
|
||||
private int defaultThreadID() {
|
||||
long tid = Thread.currentThread().getId();
|
||||
if (tid < MIN_SEQUENTIAL_THREAD_ID) {
|
||||
return (int) tid;
|
||||
} else {
|
||||
Integer id = threadIds.get();
|
||||
if (id == null) {
|
||||
id = nextThreadId.getAndIncrement();
|
||||
threadIds.set(id);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a LogRecord with the given level and message values.
|
||||
* <p>
|
||||
* The sequence property will be initialized with a new unique value.
|
||||
* These sequence values are allocated in increasing order within a VM.
|
||||
* <p>
|
||||
* Since JDK 9, the event time is represented by an {@link Instant}.
|
||||
* The instant property will be initialized to the {@linkplain
|
||||
* Instant#now() current instant}, using the best available
|
||||
* {@linkplain Clock#systemUTC() clock} on the system.
|
||||
* <p>
|
||||
* The thread ID property will be initialized with a unique ID for
|
||||
* the current thread.
|
||||
* <p>
|
||||
* All other properties will be initialized to "null".
|
||||
*
|
||||
* @param level a logging level value
|
||||
* @param msg the raw non-localized logging message (may be null)
|
||||
* @see java.time.Clock#systemUTC()
|
||||
*/
|
||||
public LogRecord(Level level, String msg) {
|
||||
this.level = Objects.requireNonNull(level);
|
||||
message = msg;
|
||||
// Assign a thread ID and a unique sequence number.
|
||||
sequenceNumber = globalSequenceNumber.getAndIncrement();
|
||||
threadID = defaultThreadID();
|
||||
instant = Instant.now();
|
||||
needToInferCaller = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source Logger's name.
|
||||
*
|
||||
* @return source logger name (may be null)
|
||||
*/
|
||||
public String getLoggerName() {
|
||||
return loggerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the source Logger's name.
|
||||
*
|
||||
* @param name the source logger name (may be null)
|
||||
*/
|
||||
public void setLoggerName(String name) {
|
||||
loggerName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the localization resource bundle
|
||||
* <p>
|
||||
* This is the ResourceBundle that should be used to localize
|
||||
* the message string before formatting it. The result may
|
||||
* be null if the message is not localizable, or if no suitable
|
||||
* ResourceBundle is available.
|
||||
* @return the localization resource bundle
|
||||
*/
|
||||
public ResourceBundle getResourceBundle() {
|
||||
return resourceBundle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the localization resource bundle.
|
||||
*
|
||||
* @param bundle localization bundle (may be null)
|
||||
*/
|
||||
public void setResourceBundle(ResourceBundle bundle) {
|
||||
resourceBundle = bundle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the localization resource bundle name
|
||||
* <p>
|
||||
* This is the name for the ResourceBundle that should be
|
||||
* used to localize the message string before formatting it.
|
||||
* The result may be null if the message is not localizable.
|
||||
* @return the localization resource bundle name
|
||||
*/
|
||||
public String getResourceBundleName() {
|
||||
return resourceBundleName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the localization resource bundle name.
|
||||
*
|
||||
* @param name localization bundle name (may be null)
|
||||
*/
|
||||
public void setResourceBundleName(String name) {
|
||||
resourceBundleName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the logging message level, for example Level.SEVERE.
|
||||
* @return the logging message level
|
||||
*/
|
||||
public Level getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the logging message level, for example Level.SEVERE.
|
||||
* @param level the logging message level
|
||||
*/
|
||||
public void setLevel(Level level) {
|
||||
if (level == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sequence number.
|
||||
* <p>
|
||||
* Sequence numbers are normally assigned in the LogRecord
|
||||
* constructor, which assigns unique sequence numbers to
|
||||
* each new LogRecord in increasing order.
|
||||
* @return the sequence number
|
||||
*/
|
||||
public long getSequenceNumber() {
|
||||
return sequenceNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sequence number.
|
||||
* <p>
|
||||
* Sequence numbers are normally assigned in the LogRecord constructor,
|
||||
* so it should not normally be necessary to use this method.
|
||||
* @param seq the sequence number
|
||||
*/
|
||||
public void setSequenceNumber(long seq) {
|
||||
sequenceNumber = seq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the class that (allegedly) issued the logging request.
|
||||
* <p>
|
||||
* Note that this sourceClassName is not verified and may be spoofed.
|
||||
* This information may either have been provided as part of the
|
||||
* logging call, or it may have been inferred automatically by the
|
||||
* logging framework. In the latter case, the information may only
|
||||
* be approximate and may in fact describe an earlier call on the
|
||||
* stack frame.
|
||||
* <p>
|
||||
* May be null if no information could be obtained.
|
||||
*
|
||||
* @return the source class name
|
||||
*/
|
||||
public String getSourceClassName() {
|
||||
if (needToInferCaller) {
|
||||
inferCaller();
|
||||
}
|
||||
return sourceClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the class that (allegedly) issued the logging request.
|
||||
*
|
||||
* @param sourceClassName the source class name (may be null)
|
||||
*/
|
||||
public void setSourceClassName(String sourceClassName) {
|
||||
this.sourceClassName = sourceClassName;
|
||||
needToInferCaller = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the method that (allegedly) issued the logging request.
|
||||
* <p>
|
||||
* Note that this sourceMethodName is not verified and may be spoofed.
|
||||
* This information may either have been provided as part of the
|
||||
* logging call, or it may have been inferred automatically by the
|
||||
* logging framework. In the latter case, the information may only
|
||||
* be approximate and may in fact describe an earlier call on the
|
||||
* stack frame.
|
||||
* <p>
|
||||
* May be null if no information could be obtained.
|
||||
*
|
||||
* @return the source method name
|
||||
*/
|
||||
public String getSourceMethodName() {
|
||||
if (needToInferCaller) {
|
||||
inferCaller();
|
||||
}
|
||||
return sourceMethodName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the method that (allegedly) issued the logging request.
|
||||
*
|
||||
* @param sourceMethodName the source method name (may be null)
|
||||
*/
|
||||
public void setSourceMethodName(String sourceMethodName) {
|
||||
this.sourceMethodName = sourceMethodName;
|
||||
needToInferCaller = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the "raw" log message, before localization or formatting.
|
||||
* <p>
|
||||
* May be null, which is equivalent to the empty string "".
|
||||
* <p>
|
||||
* This message may be either the final text or a localization key.
|
||||
* <p>
|
||||
* During formatting, if the source logger has a localization
|
||||
* ResourceBundle and if that ResourceBundle has an entry for
|
||||
* this message string, then the message string is replaced
|
||||
* with the localized value.
|
||||
*
|
||||
* @return the raw message string
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the "raw" log message, before localization or formatting.
|
||||
*
|
||||
* @param message the raw message string (may be null)
|
||||
*/
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parameters to the log message.
|
||||
*
|
||||
* @return the log message parameters. May be null if
|
||||
* there are no parameters.
|
||||
*/
|
||||
public Object[] getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parameters to the log message.
|
||||
*
|
||||
* @param parameters the log message parameters. (may be null)
|
||||
*/
|
||||
public void setParameters(Object parameters[]) {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an identifier for the thread where the message originated.
|
||||
* <p>
|
||||
* This is a thread identifier within the Java VM and may or
|
||||
* may not map to any operating system ID.
|
||||
*
|
||||
* @return thread ID
|
||||
*/
|
||||
public int getThreadID() {
|
||||
return threadID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an identifier for the thread where the message originated.
|
||||
* @param threadID the thread ID
|
||||
*/
|
||||
public void setThreadID(int threadID) {
|
||||
this.threadID = threadID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get truncated event time in milliseconds since 1970.
|
||||
*
|
||||
* @return truncated event time in millis since 1970
|
||||
*
|
||||
* @implSpec This is equivalent to calling
|
||||
* {@link #getInstant() getInstant().toEpochMilli()}.
|
||||
*
|
||||
* @apiNote To get the full nanosecond resolution event time,
|
||||
* use {@link #getInstant()}.
|
||||
*
|
||||
* @see #getInstant()
|
||||
*/
|
||||
public long getMillis() {
|
||||
return instant.toEpochMilli();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set event time.
|
||||
*
|
||||
* @param millis event time in millis since 1970.
|
||||
*
|
||||
* @implSpec This is equivalent to calling
|
||||
* {@link #setInstant(java.time.Instant)
|
||||
* setInstant(Instant.ofEpochMilli(millis))}.
|
||||
*
|
||||
* @deprecated LogRecord maintains timestamps with nanosecond resolution,
|
||||
* using {@link Instant} values. For this reason,
|
||||
* {@link #setInstant(java.time.Instant) setInstant()}
|
||||
* should be used in preference to {@code setMillis()}.
|
||||
*
|
||||
* @see #setInstant(java.time.Instant)
|
||||
*/
|
||||
@Deprecated
|
||||
public void setMillis(long millis) {
|
||||
this.instant = Instant.ofEpochMilli(millis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instant that the event occurred.
|
||||
*
|
||||
* @return the instant that the event occurred.
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
public Instant getInstant() {
|
||||
return instant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the instant that the event occurred.
|
||||
* <p>
|
||||
* If the given {@code instant} represents a point on the time-line too
|
||||
* far in the future or past to fit in a {@code long} milliseconds and
|
||||
* nanoseconds adjustment, then an {@code ArithmeticException} will be
|
||||
* thrown.
|
||||
*
|
||||
* @param instant the instant that the event occurred.
|
||||
*
|
||||
* @throws NullPointerException if {@code instant} is null.
|
||||
* @throws ArithmeticException if numeric overflow would occur while
|
||||
* calling {@link Instant#toEpochMilli() instant.toEpochMilli()}.
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
public void setInstant(Instant instant) {
|
||||
instant.toEpochMilli();
|
||||
this.instant = instant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get any throwable associated with the log record.
|
||||
* <p>
|
||||
* If the event involved an exception, this will be the
|
||||
* exception object. Otherwise null.
|
||||
*
|
||||
* @return a throwable
|
||||
*/
|
||||
public Throwable getThrown() {
|
||||
return thrown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a throwable associated with the log event.
|
||||
*
|
||||
* @param thrown a throwable (may be null)
|
||||
*/
|
||||
public void setThrown(Throwable thrown) {
|
||||
this.thrown = thrown;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 5372048053134512534L;
|
||||
|
||||
/**
|
||||
* @serialData Serialized fields, followed by a two byte version number
|
||||
* (major byte, followed by minor byte), followed by information on
|
||||
* the log record parameter array. If there is no parameter array,
|
||||
* then -1 is written. If there is a parameter array (possible of zero
|
||||
* length) then the array length is written as an integer, followed
|
||||
* by String values for each parameter. If a parameter is null, then
|
||||
* a null String is written. Otherwise the output of Object.toString()
|
||||
* is written.
|
||||
*/
|
||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||
// We have to write serialized fields first.
|
||||
ObjectOutputStream.PutField pf = out.putFields();
|
||||
pf.put("level", level);
|
||||
pf.put("sequenceNumber", sequenceNumber);
|
||||
pf.put("sourceClassName", sourceClassName);
|
||||
pf.put("sourceMethodName", sourceMethodName);
|
||||
pf.put("message", message);
|
||||
pf.put("threadID", threadID);
|
||||
pf.put("millis", instant.toEpochMilli());
|
||||
pf.put("nanoAdjustment", instant.getNano() % 1000_000);
|
||||
pf.put("thrown", thrown);
|
||||
pf.put("loggerName", loggerName);
|
||||
pf.put("resourceBundleName", resourceBundleName);
|
||||
out.writeFields();
|
||||
|
||||
// Write our version number.
|
||||
out.writeByte(1);
|
||||
out.writeByte(0);
|
||||
if (parameters == null) {
|
||||
out.writeInt(-1);
|
||||
return;
|
||||
}
|
||||
out.writeInt(parameters.length);
|
||||
// Write string values for the parameters.
|
||||
for (Object parameter : parameters) {
|
||||
out.writeObject(Objects.toString(parameter, null));
|
||||
}
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in)
|
||||
throws IOException, ClassNotFoundException {
|
||||
// We have to read serialized fields first.
|
||||
ObjectInputStream.GetField gf = in.readFields();
|
||||
level = (Level) gf.get("level", null);
|
||||
sequenceNumber = gf.get("sequenceNumber", 0L);
|
||||
sourceClassName = (String) gf.get("sourceClassName", null);
|
||||
sourceMethodName = (String) gf.get("sourceMethodName", null);
|
||||
message = (String) gf.get("message", null);
|
||||
threadID = gf.get("threadID", 0);
|
||||
long millis = gf.get("millis", 0L);
|
||||
int nanoOfMilli = gf.get("nanoAdjustment", 0);
|
||||
instant = Instant.ofEpochSecond(
|
||||
millis / 1000L, (millis % 1000L) * 1000_000L + nanoOfMilli);
|
||||
thrown = (Throwable) gf.get("thrown", null);
|
||||
loggerName = (String) gf.get("loggerName", null);
|
||||
resourceBundleName = (String) gf.get("resourceBundleName", null);
|
||||
|
||||
// Read version number.
|
||||
byte major = in.readByte();
|
||||
byte minor = in.readByte();
|
||||
if (major != 1) {
|
||||
throw new IOException("LogRecord: bad version: " + major + "." + minor);
|
||||
}
|
||||
int len = in.readInt();
|
||||
if (len < -1) {
|
||||
throw new NegativeArraySizeException();
|
||||
} else if (len == -1) {
|
||||
parameters = null;
|
||||
} else if (len < 255) {
|
||||
parameters = new Object[len];
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
parameters[i] = in.readObject();
|
||||
}
|
||||
} else {
|
||||
List<Object> params = new ArrayList<>(Math.min(len, 1024));
|
||||
for (int i = 0; i < len; i++) {
|
||||
params.add(in.readObject());
|
||||
}
|
||||
parameters = params.toArray(new Object[params.size()]);
|
||||
}
|
||||
// If necessary, try to regenerate the resource bundle.
|
||||
if (resourceBundleName != null) {
|
||||
try {
|
||||
// use system class loader to ensure the ResourceBundle
|
||||
// instance is a different instance than null loader uses
|
||||
final ResourceBundle bundle =
|
||||
ResourceBundle.getBundle(resourceBundleName,
|
||||
Locale.getDefault(),
|
||||
ClassLoader.getSystemClassLoader());
|
||||
resourceBundle = bundle;
|
||||
} catch (MissingResourceException ex) {
|
||||
// This is not a good place to throw an exception,
|
||||
// so we simply leave the resourceBundle null.
|
||||
resourceBundle = null;
|
||||
}
|
||||
}
|
||||
|
||||
needToInferCaller = false;
|
||||
}
|
||||
|
||||
// Private method to infer the caller's class and method names
|
||||
//
|
||||
// Note:
|
||||
// For testing purposes - it is possible to customize the process
|
||||
// by which LogRecord will infer the source class name and source method name
|
||||
// when analyzing the call stack.
|
||||
// <p>
|
||||
// The system property {@code jdk.logger.packages} can define a comma separated
|
||||
// list of strings corresponding to additional package name prefixes that
|
||||
// should be ignored when trying to infer the source caller class name.
|
||||
// Those stack frames whose {@linkplain StackTraceElement#getClassName()
|
||||
// declaring class name} start with one such prefix will be ignored.
|
||||
// <p>
|
||||
// This is primarily useful when providing utility logging classes wrapping
|
||||
// a logger instance, as it makes it possible to instruct LogRecord to skip
|
||||
// those utility frames when inferring the caller source class name.
|
||||
// <p>
|
||||
// The {@code jdk.logger.packages} system property is consulted only once.
|
||||
// <p>
|
||||
// This property is not standard, implementation specific, and yet
|
||||
// undocumented (and thus subject to changes without notice).
|
||||
//
|
||||
private void inferCaller() {
|
||||
needToInferCaller = false;
|
||||
// Skip all frames until we have found the first logger frame.
|
||||
Optional<StackWalker.StackFrame> frame = new CallerFinder().get();
|
||||
frame.ifPresent(f -> {
|
||||
setSourceClassName(f.getClassName());
|
||||
setSourceMethodName(f.getMethodName());
|
||||
});
|
||||
|
||||
// We haven't found a suitable frame, so just punt. This is
|
||||
// OK as we are only committed to making a "best effort" here.
|
||||
}
|
||||
|
||||
/*
|
||||
* CallerFinder is a stateful predicate.
|
||||
*/
|
||||
static final class CallerFinder implements Predicate<StackWalker.StackFrame> {
|
||||
private static final StackWalker WALKER;
|
||||
static {
|
||||
final PrivilegedAction<StackWalker> action =
|
||||
() -> StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
|
||||
WALKER = AccessController.doPrivileged(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns StackFrame of the caller's frame.
|
||||
* @return StackFrame of the caller's frame.
|
||||
*/
|
||||
Optional<StackWalker.StackFrame> get() {
|
||||
return WALKER.walk((s) -> s.filter(this).findFirst());
|
||||
}
|
||||
|
||||
private boolean lookingForLogger = true;
|
||||
/**
|
||||
* Returns true if we have found the caller's frame, false if the frame
|
||||
* must be skipped.
|
||||
*
|
||||
* @param t The frame info.
|
||||
* @return true if we have found the caller's frame, false if the frame
|
||||
* must be skipped.
|
||||
*/
|
||||
@Override
|
||||
public boolean test(StackWalker.StackFrame t) {
|
||||
final String cname = t.getClassName();
|
||||
// We should skip all frames until we have found the logger,
|
||||
// because these frames could be frames introduced by e.g. custom
|
||||
// sub classes of Handler.
|
||||
if (lookingForLogger) {
|
||||
// the log record could be created for a platform logger
|
||||
lookingForLogger = !isLoggerImplFrame(cname);
|
||||
return false;
|
||||
}
|
||||
// Continue walking until we've found the relevant calling frame.
|
||||
// Skips logging/logger infrastructure.
|
||||
return !isFilteredFrame(t);
|
||||
}
|
||||
|
||||
private boolean isLoggerImplFrame(String cname) {
|
||||
return (cname.equals("java.util.logging.Logger") ||
|
||||
cname.startsWith("sun.util.logging.PlatformLogger"));
|
||||
}
|
||||
}
|
||||
}
|
2531
src/java.logging/share/classes/java/util/logging/Logger.java
Normal file
2531
src/java.logging/share/classes/java/util/logging/Logger.java
Normal file
File diff suppressed because it is too large
Load diff
131
src/java.logging/share/classes/java/util/logging/Logging.java
Normal file
131
src/java.logging/share/classes/java/util/logging/Logging.java
Normal file
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.logging;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Logging is the implementation class of LoggingMXBean.
|
||||
*
|
||||
* The {@code LoggingMXBean} interface provides a standard
|
||||
* method for management access to the individual
|
||||
* {@code Logger} objects available at runtime.
|
||||
*
|
||||
* @author Ron Mann
|
||||
* @author Mandy Chung
|
||||
* @since 1.5
|
||||
*
|
||||
* @see javax.management
|
||||
* @see Logger
|
||||
* @see LogManager
|
||||
*/
|
||||
@SuppressWarnings("deprecation") // implements LoggingMXBean
|
||||
final class Logging implements LoggingMXBean {
|
||||
|
||||
private static LogManager logManager = LogManager.getLogManager();
|
||||
|
||||
/** Constructor of Logging which is the implementation class
|
||||
* of LoggingMXBean.
|
||||
*/
|
||||
private Logging() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getLoggerNames() {
|
||||
Enumeration<String> loggers = logManager.getLoggerNames();
|
||||
ArrayList<String> array = new ArrayList<>();
|
||||
|
||||
for (; loggers.hasMoreElements();) {
|
||||
array.add(loggers.nextElement());
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
private static String EMPTY_STRING = "";
|
||||
@Override
|
||||
public String getLoggerLevel(String loggerName) {
|
||||
Logger l = logManager.getLogger(loggerName);
|
||||
if (l == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Level level = l.getLevel();
|
||||
if (level == null) {
|
||||
return EMPTY_STRING;
|
||||
} else {
|
||||
return level.getLevelName();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoggerLevel(String loggerName, String levelName) {
|
||||
if (loggerName == null) {
|
||||
throw new NullPointerException("loggerName is null");
|
||||
}
|
||||
|
||||
Logger logger = logManager.getLogger(loggerName);
|
||||
if (logger == null) {
|
||||
throw new IllegalArgumentException("Logger " + loggerName +
|
||||
" does not exist");
|
||||
}
|
||||
|
||||
Level level = null;
|
||||
if (levelName != null) {
|
||||
// parse will throw IAE if logLevel is invalid
|
||||
level = Level.findLevel(levelName);
|
||||
if (level == null) {
|
||||
throw new IllegalArgumentException("Unknown level \"" + levelName + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
logger.setLevel(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParentLoggerName( String loggerName ) {
|
||||
Logger l = logManager.getLogger( loggerName );
|
||||
if (l == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Logger p = l.getParent();
|
||||
if (p == null) {
|
||||
// root logger
|
||||
return EMPTY_STRING;
|
||||
} else {
|
||||
return p.getName();
|
||||
}
|
||||
}
|
||||
|
||||
static Logging getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private static final Logging INSTANCE = new Logging();
|
||||
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.logging;
|
||||
|
||||
|
||||
/**
|
||||
* The management interface for the logging facility.
|
||||
*
|
||||
* {@link java.lang.management.PlatformLoggingMXBean
|
||||
* java.lang.management.PlatformLoggingMXBean} is the management interface
|
||||
* for logging facility registered in the {@link
|
||||
* java.lang.management.ManagementFactory#getPlatformMBeanServer()
|
||||
* platform MBeanServer}.
|
||||
* It is recommended to use the {@code PlatformLoggingMXBean} obtained via
|
||||
* the {@link java.lang.management.ManagementFactory#getPlatformMXBean(Class)
|
||||
* ManagementFactory.getPlatformMXBean(PlatformLoggingMXBean.class)} method.
|
||||
*
|
||||
* @deprecated {@code LoggingMXBean} is no longer a {@link
|
||||
* java.lang.management.PlatformManagedObject platform MXBean} and is replaced
|
||||
* with {@link java.lang.management.PlatformLoggingMXBean}.
|
||||
* It will not register in the platform {@code MBeanServer}.
|
||||
* Use {@code ManagementFactory.getPlatformMXBean(PlatformLoggingMXBean.class)}
|
||||
* instead.
|
||||
*
|
||||
* @author Ron Mann
|
||||
* @author Mandy Chung
|
||||
* @since 1.5
|
||||
*
|
||||
* @see java.lang.management.PlatformLoggingMXBean
|
||||
*/
|
||||
@Deprecated(since="9")
|
||||
public interface LoggingMXBean {
|
||||
|
||||
/**
|
||||
* Returns the list of currently registered logger names. This method
|
||||
* calls {@link LogManager#getLoggerNames} and returns a list
|
||||
* of the logger names.
|
||||
*
|
||||
* @return A list of {@code String} each of which is a
|
||||
* currently registered {@code Logger} name.
|
||||
*/
|
||||
public java.util.List<String> getLoggerNames();
|
||||
|
||||
/**
|
||||
* Gets the name of the log level associated with the specified logger.
|
||||
* If the specified logger does not exist, {@code null}
|
||||
* is returned.
|
||||
* This method first finds the logger of the given name and
|
||||
* then returns the name of the log level by calling:
|
||||
* <blockquote>
|
||||
* {@link Logger#getLevel Logger.getLevel()}.{@link Level#getName getName()};
|
||||
* </blockquote>
|
||||
*
|
||||
* <p>
|
||||
* If the {@code Level} of the specified logger is {@code null},
|
||||
* which means that this logger's effective level is inherited
|
||||
* from its parent, an empty string will be returned.
|
||||
*
|
||||
* @param loggerName The name of the {@code Logger} to be retrieved.
|
||||
*
|
||||
* @return The name of the log level of the specified logger; or
|
||||
* an empty string if the log level of the specified logger
|
||||
* is {@code null}. If the specified logger does not
|
||||
* exist, {@code null} is returned.
|
||||
*
|
||||
* @see Logger#getLevel
|
||||
*/
|
||||
public String getLoggerLevel(String loggerName);
|
||||
|
||||
/**
|
||||
* Sets the specified logger to the specified new level.
|
||||
* If the {@code levelName} is not {@code null}, the level
|
||||
* of the specified logger is set to the parsed {@code Level}
|
||||
* matching the {@code levelName}.
|
||||
* If the {@code levelName} is {@code null}, the level
|
||||
* of the specified logger is set to {@code null} and
|
||||
* the effective level of the logger is inherited from
|
||||
* its nearest ancestor with a specific (non-null) level value.
|
||||
*
|
||||
* @param loggerName The name of the {@code Logger} to be set.
|
||||
* Must be non-null.
|
||||
* @param levelName The name of the level to set on the specified logger,
|
||||
* or {@code null} if setting the level to inherit
|
||||
* from its nearest ancestor.
|
||||
*
|
||||
* @throws IllegalArgumentException if the specified logger
|
||||
* does not exist, or {@code levelName} is not a valid level name.
|
||||
*
|
||||
* @throws SecurityException if a security manager exists and if
|
||||
* the caller does not have LoggingPermission("control").
|
||||
*
|
||||
* @see Logger#setLevel
|
||||
*/
|
||||
public void setLoggerLevel(String loggerName, String levelName);
|
||||
|
||||
/**
|
||||
* Returns the name of the parent for the specified logger.
|
||||
* If the specified logger does not exist, {@code null} is returned.
|
||||
* If the specified logger is the root {@code Logger} in the namespace,
|
||||
* the result will be an empty string.
|
||||
*
|
||||
* @param loggerName The name of a {@code Logger}.
|
||||
*
|
||||
* @return the name of the nearest existing parent logger;
|
||||
* an empty string if the specified logger is the root logger.
|
||||
* If the specified logger does not exist, {@code null}
|
||||
* is returned.
|
||||
*/
|
||||
public String getParentLoggerName(String loggerName);
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package java.util.logging;
|
||||
|
||||
import java.security.*;
|
||||
|
||||
/**
|
||||
* The permission which the SecurityManager will check when code
|
||||
* that is running with a SecurityManager calls one of the logging
|
||||
* control methods (such as Logger.setLevel).
|
||||
* <p>
|
||||
* Currently there is only one named LoggingPermission. This is "control"
|
||||
* and it grants the ability to control the logging configuration, for
|
||||
* example by adding or removing Handlers, by adding or removing Filters,
|
||||
* or by changing logging levels.
|
||||
* <p>
|
||||
* Programmers do not normally create LoggingPermission objects directly.
|
||||
* Instead they are created by the security policy code based on reading
|
||||
* the security policy file.
|
||||
*
|
||||
*
|
||||
* @since 1.4
|
||||
* @see java.security.BasicPermission
|
||||
* @see java.security.Permission
|
||||
* @see java.security.Permissions
|
||||
* @see java.security.PermissionCollection
|
||||
* @see java.lang.SecurityManager
|
||||
*
|
||||
*/
|
||||
|
||||
public final class LoggingPermission extends java.security.BasicPermission {
|
||||
|
||||
private static final long serialVersionUID = 63564341580231582L;
|
||||
|
||||
/**
|
||||
* Creates a new LoggingPermission object.
|
||||
*
|
||||
* @param name Permission name. Must be "control".
|
||||
* @param actions Must be either null or the empty string.
|
||||
*
|
||||
* @throws NullPointerException if <code>name</code> is <code>null</code>.
|
||||
* @throws IllegalArgumentException if <code>name</code> is empty or if
|
||||
* arguments are invalid.
|
||||
*/
|
||||
public LoggingPermission(String name, String actions) throws IllegalArgumentException {
|
||||
super(name);
|
||||
if (!name.equals("control")) {
|
||||
throw new IllegalArgumentException("name: " + name);
|
||||
}
|
||||
if (actions != null && actions.length() > 0) {
|
||||
throw new IllegalArgumentException("actions: " + actions);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util.logging;
|
||||
|
||||
/**
|
||||
* {@code Handler} that buffers requests in a circular buffer in memory.
|
||||
* <p>
|
||||
* Normally this {@code Handler} simply stores incoming {@code LogRecords}
|
||||
* into its memory buffer and discards earlier records. This buffering
|
||||
* is very cheap and avoids formatting costs. On certain trigger
|
||||
* conditions, the {@code MemoryHandler} will push out its current buffer
|
||||
* contents to a target {@code Handler}, which will typically publish
|
||||
* them to the outside world.
|
||||
* <p>
|
||||
* There are three main models for triggering a push of the buffer:
|
||||
* <ul>
|
||||
* <li>
|
||||
* An incoming {@code LogRecord} has a type that is greater than
|
||||
* a pre-defined level, the {@code pushLevel}. </li>
|
||||
* <li>
|
||||
* An external class calls the {@code push} method explicitly. </li>
|
||||
* <li>
|
||||
* A subclass overrides the {@code log} method and scans each incoming
|
||||
* {@code LogRecord} and calls {@code push} if a record matches some
|
||||
* desired criteria. </li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* <b>Configuration:</b>
|
||||
* By default each {@code MemoryHandler} is initialized using the following
|
||||
* {@code LogManager} configuration properties where {@code <handler-name>}
|
||||
* refers to the fully-qualified class name of the handler.
|
||||
* If properties are not defined
|
||||
* (or have invalid values) then the specified default values are used.
|
||||
* If no default value is defined then a RuntimeException is thrown.
|
||||
* <ul>
|
||||
* <li> <handler-name>.level
|
||||
* specifies the level for the {@code Handler}
|
||||
* (defaults to {@code Level.ALL}). </li>
|
||||
* <li> <handler-name>.filter
|
||||
* specifies the name of a {@code Filter} class to use
|
||||
* (defaults to no {@code Filter}). </li>
|
||||
* <li> <handler-name>.size
|
||||
* defines the buffer size (defaults to 1000). </li>
|
||||
* <li> <handler-name>.push
|
||||
* defines the {@code pushLevel} (defaults to {@code level.SEVERE}). </li>
|
||||
* <li> <handler-name>.target
|
||||
* specifies the name of the target {@code Handler } class.
|
||||
* (no default). </li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* For example, the properties for {@code MemoryHandler} would be:
|
||||
* <ul>
|
||||
* <li> java.util.logging.MemoryHandler.level=INFO </li>
|
||||
* <li> java.util.logging.MemoryHandler.formatter=java.util.logging.SimpleFormatter </li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* For a custom handler, e.g. com.foo.MyHandler, the properties would be:
|
||||
* <ul>
|
||||
* <li> com.foo.MyHandler.level=INFO </li>
|
||||
* <li> com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter </li>
|
||||
* </ul>
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
|
||||
public class MemoryHandler extends Handler {
|
||||
private final static int DEFAULT_SIZE = 1000;
|
||||
private volatile Level pushLevel;
|
||||
private int size;
|
||||
private Handler target;
|
||||
private LogRecord buffer[];
|
||||
int start, count;
|
||||
|
||||
/**
|
||||
* Create a {@code MemoryHandler} and configure it based on
|
||||
* {@code LogManager} configuration properties.
|
||||
*/
|
||||
public MemoryHandler() {
|
||||
// configure with specific defaults for MemoryHandler
|
||||
super(Level.ALL, new SimpleFormatter(), null);
|
||||
|
||||
LogManager manager = LogManager.getLogManager();
|
||||
String cname = getClass().getName();
|
||||
pushLevel = manager.getLevelProperty(cname +".push", Level.SEVERE);
|
||||
size = manager.getIntProperty(cname + ".size", DEFAULT_SIZE);
|
||||
if (size <= 0) {
|
||||
size = DEFAULT_SIZE;
|
||||
}
|
||||
String targetName = manager.getProperty(cname+".target");
|
||||
if (targetName == null) {
|
||||
throw new RuntimeException("The handler " + cname
|
||||
+ " does not specify a target");
|
||||
}
|
||||
Class<?> clz;
|
||||
try {
|
||||
clz = ClassLoader.getSystemClassLoader().loadClass(targetName);
|
||||
@SuppressWarnings("deprecation")
|
||||
Object o = clz.newInstance();
|
||||
target = (Handler) o;
|
||||
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
|
||||
throw new RuntimeException("MemoryHandler can't load handler target \"" + targetName + "\"" , e);
|
||||
}
|
||||
init();
|
||||
}
|
||||
|
||||
// Initialize. Size is a count of LogRecords.
|
||||
private void init() {
|
||||
buffer = new LogRecord[size];
|
||||
start = 0;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@code MemoryHandler}.
|
||||
* <p>
|
||||
* The {@code MemoryHandler} is configured based on {@code LogManager}
|
||||
* properties (or their default values) except that the given {@code pushLevel}
|
||||
* argument and buffer size argument are used.
|
||||
*
|
||||
* @param target the Handler to which to publish output.
|
||||
* @param size the number of log records to buffer (must be greater than zero)
|
||||
* @param pushLevel message level to push on
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code size is <= 0}
|
||||
*/
|
||||
public MemoryHandler(Handler target, int size, Level pushLevel) {
|
||||
// configure with specific defaults for MemoryHandler
|
||||
super(Level.ALL, new SimpleFormatter(), null);
|
||||
|
||||
if (target == null || pushLevel == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (size <= 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.target = target;
|
||||
this.pushLevel = pushLevel;
|
||||
this.size = size;
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a {@code LogRecord} in an internal buffer.
|
||||
* <p>
|
||||
* If there is a {@code Filter}, its {@code isLoggable}
|
||||
* method is called to check if the given log record is loggable.
|
||||
* If not we return. Otherwise the given record is copied into
|
||||
* an internal circular buffer. Then the record's level property is
|
||||
* compared with the {@code pushLevel}. If the given level is
|
||||
* greater than or equal to the {@code pushLevel} then {@code push}
|
||||
* is called to write all buffered records to the target output
|
||||
* {@code Handler}.
|
||||
*
|
||||
* @param record description of the log event. A null record is
|
||||
* silently ignored and is not published
|
||||
*/
|
||||
@Override
|
||||
public synchronized void publish(LogRecord record) {
|
||||
if (!isLoggable(record)) {
|
||||
return;
|
||||
}
|
||||
int ix = (start+count)%buffer.length;
|
||||
buffer[ix] = record;
|
||||
if (count < buffer.length) {
|
||||
count++;
|
||||
} else {
|
||||
start++;
|
||||
start %= buffer.length;
|
||||
}
|
||||
if (record.getLevel().intValue() >= pushLevel.intValue()) {
|
||||
push();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Push any buffered output to the target {@code Handler}.
|
||||
* <p>
|
||||
* The buffer is then cleared.
|
||||
*/
|
||||
public synchronized void push() {
|
||||
for (int i = 0; i < count; i++) {
|
||||
int ix = (start+i)%buffer.length;
|
||||
LogRecord record = buffer[ix];
|
||||
target.publish(record);
|
||||
}
|
||||
// Empty the buffer.
|
||||
start = 0;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Causes a flush on the target {@code Handler}.
|
||||
* <p>
|
||||
* Note that the current contents of the {@code MemoryHandler}
|
||||
* buffer are <b>not</b> written out. That requires a "push".
|
||||
*/
|
||||
@Override
|
||||
public void flush() {
|
||||
target.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the {@code Handler} and free all associated resources.
|
||||
* This will also close the target {@code Handler}.
|
||||
*
|
||||
* @exception SecurityException if a security manager exists and if
|
||||
* the caller does not have {@code LoggingPermission("control")}.
|
||||
*/
|
||||
@Override
|
||||
public void close() throws SecurityException {
|
||||
target.close();
|
||||
setLevel(Level.OFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@code pushLevel}. After a {@code LogRecord} is copied
|
||||
* into our internal buffer, if its level is greater than or equal to
|
||||
* the {@code pushLevel}, then {@code push} will be called.
|
||||
*
|
||||
* @param newLevel the new value of the {@code pushLevel}
|
||||
* @exception SecurityException if a security manager exists and if
|
||||
* the caller does not have {@code LoggingPermission("control")}.
|
||||
*/
|
||||
public synchronized void setPushLevel(Level newLevel) throws SecurityException {
|
||||
if (newLevel == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
checkPermission();
|
||||
pushLevel = newLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@code pushLevel}.
|
||||
*
|
||||
* @return the value of the {@code pushLevel}
|
||||
*/
|
||||
public Level getPushLevel() {
|
||||
return pushLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this {@code Handler} would actually log a given
|
||||
* {@code LogRecord} into its internal buffer.
|
||||
* <p>
|
||||
* This method checks if the {@code LogRecord} has an appropriate level and
|
||||
* whether it satisfies any {@code Filter}. However it does <b>not</b>
|
||||
* check whether the {@code LogRecord} would result in a "push" of the
|
||||
* buffer contents. It will return false if the {@code LogRecord} is null.
|
||||
*
|
||||
* @param record a {@code LogRecord}
|
||||
* @return true if the {@code LogRecord} would be logged.
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public boolean isLoggable(LogRecord record) {
|
||||
return super.isLoggable(record);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package java.util.logging;
|
||||
|
||||
import java.io.*;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import jdk.internal.logger.SurrogateLogger;
|
||||
|
||||
/**
|
||||
* Print a brief summary of the {@code LogRecord} in a human readable
|
||||
* format. The summary will typically be 1 or 2 lines.
|
||||
*
|
||||
* <p>
|
||||
* <a id="formatting">
|
||||
* <b>Configuration:</b></a>
|
||||
* The {@code SimpleFormatter} is initialized with the
|
||||
* <a href="../Formatter.html#syntax">format string</a>
|
||||
* specified in the {@code java.util.logging.SimpleFormatter.format}
|
||||
* property to {@linkplain #format(LogRecord) format} the log messages.
|
||||
* This property can be defined
|
||||
* in the {@linkplain LogManager#getProperty logging properties}
|
||||
* configuration file
|
||||
* or as a system property. If this property is set in both
|
||||
* the logging properties and system properties,
|
||||
* the format string specified in the system property will be used.
|
||||
* If this property is not defined or the given format string
|
||||
* is {@linkplain java.util.IllegalFormatException illegal},
|
||||
* the default format is implementation-specific.
|
||||
*
|
||||
* @since 1.4
|
||||
* @see java.util.Formatter
|
||||
*/
|
||||
|
||||
public class SimpleFormatter extends Formatter {
|
||||
|
||||
// format string for printing the log record
|
||||
static String getLoggingProperty(String name) {
|
||||
return LogManager.getLogManager().getProperty(name);
|
||||
}
|
||||
|
||||
private final String format =
|
||||
SurrogateLogger.getSimpleFormat(SimpleFormatter::getLoggingProperty);
|
||||
|
||||
/**
|
||||
* Format the given LogRecord.
|
||||
* <p>
|
||||
* The formatting can be customized by specifying the
|
||||
* <a href="../Formatter.html#syntax">format string</a>
|
||||
* in the <a href="#formatting">
|
||||
* {@code java.util.logging.SimpleFormatter.format}</a> property.
|
||||
* The given {@code LogRecord} will be formatted as if by calling:
|
||||
* <pre>
|
||||
* {@link String#format String.format}(format, date, source, logger, level, message, thrown);
|
||||
* </pre>
|
||||
* where the arguments are:<br>
|
||||
* <ol>
|
||||
* <li>{@code format} - the {@link java.util.Formatter
|
||||
* java.util.Formatter} format string specified in the
|
||||
* {@code java.util.logging.SimpleFormatter.format} property
|
||||
* or the default format.</li>
|
||||
* <li>{@code date} - a {@link ZonedDateTime} object representing
|
||||
* {@linkplain LogRecord#getInstant() event time} of the log record
|
||||
* in the {@link ZoneId#systemDefault()} system time zone.</li>
|
||||
* <li>{@code source} - a string representing the caller, if available;
|
||||
* otherwise, the logger's name.</li>
|
||||
* <li>{@code logger} - the logger's name.</li>
|
||||
* <li>{@code level} - the {@linkplain Level#getLocalizedName
|
||||
* log level}.</li>
|
||||
* <li>{@code message} - the formatted log message
|
||||
* returned from the {@link Formatter#formatMessage(LogRecord)}
|
||||
* method. It uses {@link java.text.MessageFormat java.text}
|
||||
* formatting and does not use the {@code java.util.Formatter
|
||||
* format} argument.</li>
|
||||
* <li>{@code thrown} - a string representing
|
||||
* the {@linkplain LogRecord#getThrown throwable}
|
||||
* associated with the log record and its backtrace
|
||||
* beginning with a newline character, if any;
|
||||
* otherwise, an empty string.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p>Some example formats:<br>
|
||||
* <ul>
|
||||
* <li> {@code java.util.logging.SimpleFormatter.format="%4$s: %5$s [%1$tc]%n"}
|
||||
* <p>This prints 1 line with the log level ({@code 4$}),
|
||||
* the log message ({@code 5$}) and the timestamp ({@code 1$}) in
|
||||
* a square bracket.
|
||||
* <pre>
|
||||
* WARNING: warning message [Tue Mar 22 13:11:31 PDT 2011]
|
||||
* </pre></li>
|
||||
* <li> {@code java.util.logging.SimpleFormatter.format="%1$tc %2$s%n%4$s: %5$s%6$s%n"}
|
||||
* <p>This prints 2 lines where the first line includes
|
||||
* the timestamp ({@code 1$}) and the source ({@code 2$});
|
||||
* the second line includes the log level ({@code 4$}) and
|
||||
* the log message ({@code 5$}) followed with the throwable
|
||||
* and its backtrace ({@code 6$}), if any:
|
||||
* <pre>
|
||||
* Tue Mar 22 13:11:31 PDT 2011 MyClass fatal
|
||||
* SEVERE: several message with an exception
|
||||
* java.lang.IllegalArgumentException: invalid argument
|
||||
* at MyClass.mash(MyClass.java:9)
|
||||
* at MyClass.crunch(MyClass.java:6)
|
||||
* at MyClass.main(MyClass.java:3)
|
||||
* </pre></li>
|
||||
* <li> {@code java.util.logging.SimpleFormatter.format="%1$tb %1$td, %1$tY %1$tl:%1$tM:%1$tS %1$Tp %2$s%n%4$s: %5$s%n"}
|
||||
* <p>This prints 2 lines similar to the example above
|
||||
* with a different date/time formatting and does not print
|
||||
* the throwable and its backtrace:
|
||||
* <pre>
|
||||
* Mar 22, 2011 1:11:31 PM MyClass fatal
|
||||
* SEVERE: several message with an exception
|
||||
* </pre></li>
|
||||
* <li> {@code java.util.logging.SimpleFormatter.format="%1$tb %1$td, %1$tY %1$tl:%1$tM:%1$tS.%1$tN %1$Tp %2$s%n%4$s: %5$s%6$s%n"}
|
||||
* <p>Since JDK 9, {@code java.util.logging} uses {@link
|
||||
* java.time.Clock#systemUTC() java.time} to create more precise time
|
||||
* stamps.
|
||||
* The format above can be used to add a {@code .%1$tN} to the
|
||||
* date/time formatting so that nanoseconds will also be printed:
|
||||
* <pre>
|
||||
* Feb 06, 2015 5:33:10.279216000 PM example.Main main
|
||||
* INFO: This is a test
|
||||
* </pre></li>
|
||||
* </ul>
|
||||
* <p>This method can also be overridden in a subclass.
|
||||
* It is recommended to use the {@link Formatter#formatMessage}
|
||||
* convenience method to localize and format the message field.
|
||||
*
|
||||
* @param record the log record to be formatted.
|
||||
* @return a formatted log record
|
||||
*/
|
||||
@Override
|
||||
public String format(LogRecord record) {
|
||||
ZonedDateTime zdt = ZonedDateTime.ofInstant(
|
||||
record.getInstant(), ZoneId.systemDefault());
|
||||
String source;
|
||||
if (record.getSourceClassName() != null) {
|
||||
source = record.getSourceClassName();
|
||||
if (record.getSourceMethodName() != null) {
|
||||
source += " " + record.getSourceMethodName();
|
||||
}
|
||||
} else {
|
||||
source = record.getLoggerName();
|
||||
}
|
||||
String message = formatMessage(record);
|
||||
String throwable = "";
|
||||
if (record.getThrown() != null) {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
pw.println();
|
||||
record.getThrown().printStackTrace(pw);
|
||||
pw.close();
|
||||
throwable = sw.toString();
|
||||
}
|
||||
return String.format(format,
|
||||
zdt,
|
||||
source,
|
||||
record.getLoggerName(),
|
||||
record.getLevel().getLocalizedLevelName(),
|
||||
message,
|
||||
throwable);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package java.util.logging;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
|
||||
/**
|
||||
* Simple network logging {@code Handler}.
|
||||
* <p>
|
||||
* {@code LogRecords} are published to a network stream connection. By default
|
||||
* the {@code XMLFormatter} class is used for formatting.
|
||||
* <p>
|
||||
* <b>Configuration:</b>
|
||||
* By default each {@code SocketHandler} is initialized using the following
|
||||
* {@code LogManager} configuration properties where {@code <handler-name>}
|
||||
* refers to the fully-qualified class name of the handler.
|
||||
* If properties are not defined
|
||||
* (or have invalid values) then the specified default values are used.
|
||||
* <ul>
|
||||
* <li> <handler-name>.level
|
||||
* specifies the default level for the {@code Handler}
|
||||
* (defaults to {@code Level.ALL}). </li>
|
||||
* <li> <handler-name>.filter
|
||||
* specifies the name of a {@code Filter} class to use
|
||||
* (defaults to no {@code Filter}). </li>
|
||||
* <li> <handler-name>.formatter
|
||||
* specifies the name of a {@code Formatter} class to use
|
||||
* (defaults to {@code java.util.logging.XMLFormatter}). </li>
|
||||
* <li> <handler-name>.encoding
|
||||
* the name of the character set encoding to use (defaults to
|
||||
* the default platform encoding). </li>
|
||||
* <li> <handler-name>.host
|
||||
* specifies the target host name to connect to (no default). </li>
|
||||
* <li> <handler-name>.port
|
||||
* specifies the target TCP port to use (no default). </li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* For example, the properties for {@code SocketHandler} would be:
|
||||
* <ul>
|
||||
* <li> java.util.logging.SocketHandler.level=INFO </li>
|
||||
* <li> java.util.logging.SocketHandler.formatter=java.util.logging.SimpleFormatter </li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* For a custom handler, e.g. com.foo.MyHandler, the properties would be:
|
||||
* <ul>
|
||||
* <li> com.foo.MyHandler.level=INFO </li>
|
||||
* <li> com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter </li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* The output IO stream is buffered, but is flushed after each
|
||||
* {@code LogRecord} is written.
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
|
||||
public class SocketHandler extends StreamHandler {
|
||||
private Socket sock;
|
||||
private String host;
|
||||
private int port;
|
||||
|
||||
/**
|
||||
* Create a {@code SocketHandler}, using only {@code LogManager} properties
|
||||
* (or their defaults).
|
||||
* @throws IllegalArgumentException if the host or port are invalid or
|
||||
* are not specified as LogManager properties.
|
||||
* @throws IOException if we are unable to connect to the target
|
||||
* host and port.
|
||||
*/
|
||||
public SocketHandler() throws IOException {
|
||||
// configure with specific defaults for SocketHandler
|
||||
super(Level.ALL, new XMLFormatter(), null);
|
||||
|
||||
LogManager manager = LogManager.getLogManager();
|
||||
String cname = getClass().getName();
|
||||
port = manager.getIntProperty(cname + ".port", 0);
|
||||
host = manager.getStringProperty(cname + ".host", null);
|
||||
|
||||
try {
|
||||
connect();
|
||||
} catch (IOException ix) {
|
||||
System.err.println("SocketHandler: connect failed to " + host + ":" + port);
|
||||
throw ix;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a {@code SocketHandler} using a specified host and port.
|
||||
*
|
||||
* The {@code SocketHandler} is configured based on {@code LogManager}
|
||||
* properties (or their default values) except that the given target host
|
||||
* and port arguments are used. If the host argument is empty, but not
|
||||
* null String then the localhost is used.
|
||||
*
|
||||
* @param host target host.
|
||||
* @param port target port.
|
||||
*
|
||||
* @throws IllegalArgumentException if the host or port are invalid.
|
||||
* @throws IOException if we are unable to connect to the target
|
||||
* host and port.
|
||||
*/
|
||||
public SocketHandler(String host, int port) throws IOException {
|
||||
// configure with specific defaults for SocketHandler
|
||||
super(Level.ALL, new XMLFormatter(), null);
|
||||
|
||||
this.port = port;
|
||||
this.host = host;
|
||||
|
||||
connect();
|
||||
}
|
||||
|
||||
private void connect() throws IOException {
|
||||
// Check the arguments are valid.
|
||||
if (port == 0) {
|
||||
throw new IllegalArgumentException("Bad port: " + port);
|
||||
}
|
||||
if (host == null) {
|
||||
throw new IllegalArgumentException("Null host name: " + host);
|
||||
}
|
||||
|
||||
// Try to open a new socket.
|
||||
sock = new Socket(host, port);
|
||||
OutputStream out = sock.getOutputStream();
|
||||
BufferedOutputStream bout = new BufferedOutputStream(out);
|
||||
setOutputStreamPrivileged(bout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close this output stream.
|
||||
*
|
||||
* @exception SecurityException if a security manager exists and if
|
||||
* the caller does not have {@code LoggingPermission("control")}.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void close() throws SecurityException {
|
||||
super.close();
|
||||
if (sock != null) {
|
||||
try {
|
||||
sock.close();
|
||||
} catch (IOException ix) {
|
||||
// drop through.
|
||||
}
|
||||
}
|
||||
sock = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format and publish a {@code LogRecord}.
|
||||
*
|
||||
* @param record description of the log event. A null record is
|
||||
* silently ignored and is not published
|
||||
*/
|
||||
@Override
|
||||
public synchronized void publish(LogRecord record) {
|
||||
if (!isLoggable(record)) {
|
||||
return;
|
||||
}
|
||||
super.publish(record);
|
||||
flush();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,304 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package java.util.logging;
|
||||
|
||||
import java.io.*;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Stream based logging {@code Handler}.
|
||||
* <p>
|
||||
* This is primarily intended as a base class or support class to
|
||||
* be used in implementing other logging {@code Handlers}.
|
||||
* <p>
|
||||
* {@code LogRecords} are published to a given {@code java.io.OutputStream}.
|
||||
* <p>
|
||||
* <b>Configuration:</b>
|
||||
* By default each {@code StreamHandler} is initialized using the following
|
||||
* {@code LogManager} configuration properties where {@code <handler-name>}
|
||||
* refers to the fully-qualified class name of the handler.
|
||||
* If properties are not defined
|
||||
* (or have invalid values) then the specified default values are used.
|
||||
* <ul>
|
||||
* <li> <handler-name>.level
|
||||
* specifies the default level for the {@code Handler}
|
||||
* (defaults to {@code Level.INFO}). </li>
|
||||
* <li> <handler-name>.filter
|
||||
* specifies the name of a {@code Filter} class to use
|
||||
* (defaults to no {@code Filter}). </li>
|
||||
* <li> <handler-name>.formatter
|
||||
* specifies the name of a {@code Formatter} class to use
|
||||
* (defaults to {@code java.util.logging.SimpleFormatter}). </li>
|
||||
* <li> <handler-name>.encoding
|
||||
* the name of the character set encoding to use (defaults to
|
||||
* the default platform encoding). </li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* For example, the properties for {@code StreamHandler} would be:
|
||||
* <ul>
|
||||
* <li> java.util.logging.StreamHandler.level=INFO </li>
|
||||
* <li> java.util.logging.StreamHandler.formatter=java.util.logging.SimpleFormatter </li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* For a custom handler, e.g. com.foo.MyHandler, the properties would be:
|
||||
* <ul>
|
||||
* <li> com.foo.MyHandler.level=INFO </li>
|
||||
* <li> com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter </li>
|
||||
* </ul>
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
|
||||
public class StreamHandler extends Handler {
|
||||
private OutputStream output;
|
||||
private boolean doneHeader;
|
||||
private volatile Writer writer;
|
||||
|
||||
/**
|
||||
* Create a {@code StreamHandler}, with no current output stream.
|
||||
*/
|
||||
public StreamHandler() {
|
||||
// configure with specific defaults for StreamHandler
|
||||
super(Level.INFO, new SimpleFormatter(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@code StreamHandler} with a given {@code Formatter}
|
||||
* and output stream.
|
||||
*
|
||||
* @param out the target output stream
|
||||
* @param formatter Formatter to be used to format output
|
||||
*/
|
||||
public StreamHandler(OutputStream out, Formatter formatter) {
|
||||
// configure with default level but use specified formatter
|
||||
super(Level.INFO, null, Objects.requireNonNull(formatter));
|
||||
|
||||
setOutputStreamPrivileged(out);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Handler#Handler(Level, Formatter, Formatter)
|
||||
*/
|
||||
StreamHandler(Level defaultLevel,
|
||||
Formatter defaultFormatter,
|
||||
Formatter specifiedFormatter) {
|
||||
super(defaultLevel, defaultFormatter, specifiedFormatter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the output stream.
|
||||
* <P>
|
||||
* If there is a current output stream then the {@code Formatter}'s
|
||||
* tail string is written and the stream is flushed and closed.
|
||||
* Then the output stream is replaced with the new output stream.
|
||||
*
|
||||
* @param out New output stream. May not be null.
|
||||
* @exception SecurityException if a security manager exists and if
|
||||
* the caller does not have {@code LoggingPermission("control")}.
|
||||
*/
|
||||
protected synchronized void setOutputStream(OutputStream out) throws SecurityException {
|
||||
if (out == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
flushAndClose();
|
||||
output = out;
|
||||
doneHeader = false;
|
||||
String encoding = getEncoding();
|
||||
if (encoding == null) {
|
||||
writer = new OutputStreamWriter(output);
|
||||
} else {
|
||||
try {
|
||||
writer = new OutputStreamWriter(output, encoding);
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
// This shouldn't happen. The setEncoding method
|
||||
// should have validated that the encoding is OK.
|
||||
throw new Error("Unexpected exception " + ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set (or change) the character encoding used by this {@code Handler}.
|
||||
* <p>
|
||||
* The encoding should be set before any {@code LogRecords} are written
|
||||
* to the {@code Handler}.
|
||||
*
|
||||
* @param encoding The name of a supported character encoding.
|
||||
* May be null, to indicate the default platform encoding.
|
||||
* @exception SecurityException if a security manager exists and if
|
||||
* the caller does not have {@code LoggingPermission("control")}.
|
||||
* @exception UnsupportedEncodingException if the named encoding is
|
||||
* not supported.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void setEncoding(String encoding)
|
||||
throws SecurityException, java.io.UnsupportedEncodingException {
|
||||
super.setEncoding(encoding);
|
||||
if (output == null) {
|
||||
return;
|
||||
}
|
||||
// Replace the current writer with a writer for the new encoding.
|
||||
flush();
|
||||
if (encoding == null) {
|
||||
writer = new OutputStreamWriter(output);
|
||||
} else {
|
||||
writer = new OutputStreamWriter(output, encoding);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format and publish a {@code LogRecord}.
|
||||
* <p>
|
||||
* The {@code StreamHandler} first checks if there is an {@code OutputStream}
|
||||
* and if the given {@code LogRecord} has at least the required log level.
|
||||
* If not it silently returns. If so, it calls any associated
|
||||
* {@code Filter} to check if the record should be published. If so,
|
||||
* it calls its {@code Formatter} to format the record and then writes
|
||||
* the result to the current output stream.
|
||||
* <p>
|
||||
* If this is the first {@code LogRecord} to be written to a given
|
||||
* {@code OutputStream}, the {@code Formatter}'s "head" string is
|
||||
* written to the stream before the {@code LogRecord} is written.
|
||||
*
|
||||
* @param record description of the log event. A null record is
|
||||
* silently ignored and is not published
|
||||
*/
|
||||
@Override
|
||||
public synchronized void publish(LogRecord record) {
|
||||
if (!isLoggable(record)) {
|
||||
return;
|
||||
}
|
||||
String msg;
|
||||
try {
|
||||
msg = getFormatter().format(record);
|
||||
} catch (Exception ex) {
|
||||
// We don't want to throw an exception here, but we
|
||||
// report the exception to any registered ErrorManager.
|
||||
reportError(null, ex, ErrorManager.FORMAT_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!doneHeader) {
|
||||
writer.write(getFormatter().getHead(this));
|
||||
doneHeader = true;
|
||||
}
|
||||
writer.write(msg);
|
||||
} catch (Exception ex) {
|
||||
// We don't want to throw an exception here, but we
|
||||
// report the exception to any registered ErrorManager.
|
||||
reportError(null, ex, ErrorManager.WRITE_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if this {@code Handler} would actually log a given {@code LogRecord}.
|
||||
* <p>
|
||||
* This method checks if the {@code LogRecord} has an appropriate level and
|
||||
* whether it satisfies any {@code Filter}. It will also return false if
|
||||
* no output stream has been assigned yet or the LogRecord is null.
|
||||
*
|
||||
* @param record a {@code LogRecord}
|
||||
* @return true if the {@code LogRecord} would be logged.
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public boolean isLoggable(LogRecord record) {
|
||||
if (writer == null || record == null) {
|
||||
return false;
|
||||
}
|
||||
return super.isLoggable(record);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush any buffered messages.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void flush() {
|
||||
if (writer != null) {
|
||||
try {
|
||||
writer.flush();
|
||||
} catch (Exception ex) {
|
||||
// We don't want to throw an exception here, but we
|
||||
// report the exception to any registered ErrorManager.
|
||||
reportError(null, ex, ErrorManager.FLUSH_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void flushAndClose() throws SecurityException {
|
||||
checkPermission();
|
||||
if (writer != null) {
|
||||
try {
|
||||
if (!doneHeader) {
|
||||
writer.write(getFormatter().getHead(this));
|
||||
doneHeader = true;
|
||||
}
|
||||
writer.write(getFormatter().getTail(this));
|
||||
writer.flush();
|
||||
writer.close();
|
||||
} catch (Exception ex) {
|
||||
// We don't want to throw an exception here, but we
|
||||
// report the exception to any registered ErrorManager.
|
||||
reportError(null, ex, ErrorManager.CLOSE_FAILURE);
|
||||
}
|
||||
writer = null;
|
||||
output = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the current output stream.
|
||||
* <p>
|
||||
* The {@code Formatter}'s "tail" string is written to the stream before it
|
||||
* is closed. In addition, if the {@code Formatter}'s "head" string has not
|
||||
* yet been written to the stream, it will be written before the
|
||||
* "tail" string.
|
||||
*
|
||||
* @exception SecurityException if a security manager exists and if
|
||||
* the caller does not have LoggingPermission("control").
|
||||
*/
|
||||
@Override
|
||||
public synchronized void close() throws SecurityException {
|
||||
flushAndClose();
|
||||
}
|
||||
|
||||
// Package-private support for setting OutputStream
|
||||
// with elevated privilege.
|
||||
final void setOutputStreamPrivileged(final OutputStream out) {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
@Override
|
||||
public Void run() {
|
||||
setOutputStream(out);
|
||||
return null;
|
||||
}
|
||||
}, null, LogManager.controlPermission);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,348 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package java.util.logging;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.time.Instant;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Format a LogRecord into a standard XML format.
|
||||
* <p>
|
||||
* The DTD specification is provided as Appendix A to the
|
||||
* Java Logging APIs specification.
|
||||
* <p>
|
||||
* The XMLFormatter can be used with arbitrary character encodings,
|
||||
* but it is recommended that it normally be used with UTF-8. The
|
||||
* character encoding can be set on the output Handler.
|
||||
*
|
||||
* @implSpec Since JDK 9, instances of {@linkplain LogRecord} contain
|
||||
* an {@link LogRecord#getInstant() Instant} which can have nanoseconds below
|
||||
* the millisecond resolution.
|
||||
* The DTD specification has been updated to allow for an optional
|
||||
* {@code <nanos>} element. By default, the XMLFormatter will compute the
|
||||
* nanosecond adjustment below the millisecond resolution (using
|
||||
* {@code LogRecord.getInstant().getNano() % 1000_000}) - and if this is not 0,
|
||||
* this adjustment value will be printed in the new {@code <nanos>} element.
|
||||
* The event instant can then be reconstructed using
|
||||
* {@code Instant.ofEpochSecond(millis/1000L, (millis % 1000L) * 1000_000L + nanos)}
|
||||
* where {@code millis} and {@code nanos} represent the numbers serialized in
|
||||
* the {@code <millis>} and {@code <nanos>} elements, respectively.
|
||||
* <br>
|
||||
* The {@code <date>} element will now contain the whole instant as formatted
|
||||
* by the {@link DateTimeFormatter#ISO_INSTANT DateTimeFormatter.ISO_INSTANT}
|
||||
* formatter.
|
||||
* <p>
|
||||
* For compatibility with old parsers, XMLFormatters can
|
||||
* be configured to revert to the old format by specifying a
|
||||
* {@code <xml-formatter-fully-qualified-class-name>.useInstant = false}
|
||||
* {@linkplain LogManager#getProperty(java.lang.String) property} in the
|
||||
* logging configuration. When {@code useInstant} is {@code false}, the old
|
||||
* formatting will be preserved. When {@code useInstant} is {@code true}
|
||||
* (the default), the {@code <nanos>} element will be printed and the
|
||||
* {@code <date>} element will contain the {@linkplain
|
||||
* DateTimeFormatter#ISO_INSTANT formatted} instant.
|
||||
* <p>
|
||||
* For instance, in order to configure plain instances of XMLFormatter to omit
|
||||
* the new {@code <nano>} element,
|
||||
* {@code java.util.logging.XMLFormatter.useInstant = false} can be specified
|
||||
* in the logging configuration.
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
|
||||
public class XMLFormatter extends Formatter {
|
||||
private final LogManager manager = LogManager.getLogManager();
|
||||
private final boolean useInstant;
|
||||
|
||||
/**
|
||||
* Creates a new instance of XMLFormatter.
|
||||
*
|
||||
* @implSpec
|
||||
* Since JDK 9, the XMLFormatter will print out the record {@linkplain
|
||||
* LogRecord#getInstant() event time} as an Instant. This instant
|
||||
* has the best resolution available on the system. The {@code <date>}
|
||||
* element will contain the instant as formatted by the {@link
|
||||
* DateTimeFormatter#ISO_INSTANT}.
|
||||
* In addition, an optional {@code <nanos>} element containing a
|
||||
* nanosecond adjustment will be printed if the instant contains some
|
||||
* nanoseconds below the millisecond resolution.
|
||||
* <p>
|
||||
* This new behavior can be turned off, and the old formatting restored,
|
||||
* by specifying a property in the {@linkplain
|
||||
* LogManager#getProperty(java.lang.String) logging configuration}.
|
||||
* If {@code LogManager.getLogManager().getProperty(
|
||||
* this.getClass().getName()+".useInstant")} is {@code "false"} or
|
||||
* {@code "0"}, the old formatting will be restored.
|
||||
*/
|
||||
public XMLFormatter() {
|
||||
useInstant = (manager == null)
|
||||
|| manager.getBooleanProperty(
|
||||
this.getClass().getName()+".useInstant", true);
|
||||
}
|
||||
|
||||
// Append a two digit number.
|
||||
private void a2(StringBuilder sb, int x) {
|
||||
if (x < 10) {
|
||||
sb.append('0');
|
||||
}
|
||||
sb.append(x);
|
||||
}
|
||||
|
||||
// Append the time and date in ISO 8601 format
|
||||
private void appendISO8601(StringBuilder sb, long millis) {
|
||||
GregorianCalendar cal = new GregorianCalendar();
|
||||
cal.setTimeInMillis(millis);
|
||||
sb.append(cal.get(Calendar.YEAR));
|
||||
sb.append('-');
|
||||
a2(sb, cal.get(Calendar.MONTH) + 1);
|
||||
sb.append('-');
|
||||
a2(sb, cal.get(Calendar.DAY_OF_MONTH));
|
||||
sb.append('T');
|
||||
a2(sb, cal.get(Calendar.HOUR_OF_DAY));
|
||||
sb.append(':');
|
||||
a2(sb, cal.get(Calendar.MINUTE));
|
||||
sb.append(':');
|
||||
a2(sb, cal.get(Calendar.SECOND));
|
||||
}
|
||||
|
||||
// Append to the given StringBuilder an escaped version of the
|
||||
// given text string where XML special characters have been escaped.
|
||||
// For a null string we append "<null>"
|
||||
private void escape(StringBuilder sb, String text) {
|
||||
if (text == null) {
|
||||
text = "<null>";
|
||||
}
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
char ch = text.charAt(i);
|
||||
if (ch == '<') {
|
||||
sb.append("<");
|
||||
} else if (ch == '>') {
|
||||
sb.append(">");
|
||||
} else if (ch == '&') {
|
||||
sb.append("&");
|
||||
} else {
|
||||
sb.append(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the given message to XML.
|
||||
* <p>
|
||||
* This method can be overridden in a subclass.
|
||||
* It is recommended to use the {@link Formatter#formatMessage}
|
||||
* convenience method to localize and format the message field.
|
||||
*
|
||||
* @param record the log record to be formatted.
|
||||
* @return a formatted log record
|
||||
*/
|
||||
@Override
|
||||
public String format(LogRecord record) {
|
||||
StringBuilder sb = new StringBuilder(500);
|
||||
sb.append("<record>\n");
|
||||
|
||||
final Instant instant = record.getInstant();
|
||||
|
||||
sb.append(" <date>");
|
||||
if (useInstant) {
|
||||
// If useInstant is true - we will print the instant in the
|
||||
// date field, using the ISO_INSTANT formatter.
|
||||
DateTimeFormatter.ISO_INSTANT.formatTo(instant, sb);
|
||||
} else {
|
||||
// If useInstant is false - we will keep the 'old' formating
|
||||
appendISO8601(sb, instant.toEpochMilli());
|
||||
}
|
||||
sb.append("</date>\n");
|
||||
|
||||
sb.append(" <millis>");
|
||||
sb.append(instant.toEpochMilli());
|
||||
sb.append("</millis>\n");
|
||||
|
||||
final int nanoAdjustment = instant.getNano() % 1000_000;
|
||||
if (useInstant && nanoAdjustment != 0) {
|
||||
sb.append(" <nanos>");
|
||||
sb.append(nanoAdjustment);
|
||||
sb.append("</nanos>\n");
|
||||
}
|
||||
|
||||
sb.append(" <sequence>");
|
||||
sb.append(record.getSequenceNumber());
|
||||
sb.append("</sequence>\n");
|
||||
|
||||
String name = record.getLoggerName();
|
||||
if (name != null) {
|
||||
sb.append(" <logger>");
|
||||
escape(sb, name);
|
||||
sb.append("</logger>\n");
|
||||
}
|
||||
|
||||
sb.append(" <level>");
|
||||
escape(sb, record.getLevel().toString());
|
||||
sb.append("</level>\n");
|
||||
|
||||
if (record.getSourceClassName() != null) {
|
||||
sb.append(" <class>");
|
||||
escape(sb, record.getSourceClassName());
|
||||
sb.append("</class>\n");
|
||||
}
|
||||
|
||||
if (record.getSourceMethodName() != null) {
|
||||
sb.append(" <method>");
|
||||
escape(sb, record.getSourceMethodName());
|
||||
sb.append("</method>\n");
|
||||
}
|
||||
|
||||
sb.append(" <thread>");
|
||||
sb.append(record.getThreadID());
|
||||
sb.append("</thread>\n");
|
||||
|
||||
if (record.getMessage() != null) {
|
||||
// Format the message string and its accompanying parameters.
|
||||
String message = formatMessage(record);
|
||||
sb.append(" <message>");
|
||||
escape(sb, message);
|
||||
sb.append("</message>");
|
||||
sb.append("\n");
|
||||
}
|
||||
|
||||
// If the message is being localized, output the key, resource
|
||||
// bundle name, and params.
|
||||
ResourceBundle bundle = record.getResourceBundle();
|
||||
try {
|
||||
if (bundle != null && bundle.getString(record.getMessage()) != null) {
|
||||
sb.append(" <key>");
|
||||
escape(sb, record.getMessage());
|
||||
sb.append("</key>\n");
|
||||
sb.append(" <catalog>");
|
||||
escape(sb, record.getResourceBundleName());
|
||||
sb.append("</catalog>\n");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// The message is not in the catalog. Drop through.
|
||||
}
|
||||
|
||||
Object parameters[] = record.getParameters();
|
||||
// Check to see if the parameter was not a messagetext format
|
||||
// or was not null or empty
|
||||
if (parameters != null && parameters.length != 0
|
||||
&& record.getMessage().indexOf('{') == -1 ) {
|
||||
for (Object parameter : parameters) {
|
||||
sb.append(" <param>");
|
||||
try {
|
||||
escape(sb, parameter.toString());
|
||||
} catch (Exception ex) {
|
||||
sb.append("???");
|
||||
}
|
||||
sb.append("</param>\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (record.getThrown() != null) {
|
||||
// Report on the state of the throwable.
|
||||
Throwable th = record.getThrown();
|
||||
sb.append(" <exception>\n");
|
||||
sb.append(" <message>");
|
||||
escape(sb, th.toString());
|
||||
sb.append("</message>\n");
|
||||
StackTraceElement trace[] = th.getStackTrace();
|
||||
for (StackTraceElement frame : trace) {
|
||||
sb.append(" <frame>\n");
|
||||
sb.append(" <class>");
|
||||
escape(sb, frame.getClassName());
|
||||
sb.append("</class>\n");
|
||||
sb.append(" <method>");
|
||||
escape(sb, frame.getMethodName());
|
||||
sb.append("</method>\n");
|
||||
// Check for a line number.
|
||||
if (frame.getLineNumber() >= 0) {
|
||||
sb.append(" <line>");
|
||||
sb.append(frame.getLineNumber());
|
||||
sb.append("</line>\n");
|
||||
}
|
||||
sb.append(" </frame>\n");
|
||||
}
|
||||
sb.append(" </exception>\n");
|
||||
}
|
||||
|
||||
sb.append("</record>\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the header string for a set of XML formatted records.
|
||||
*
|
||||
* @param h The target handler (can be null)
|
||||
* @return a valid XML string
|
||||
*/
|
||||
@Override
|
||||
public String getHead(Handler h) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String encoding;
|
||||
sb.append("<?xml version=\"1.0\"");
|
||||
|
||||
if (h != null) {
|
||||
encoding = h.getEncoding();
|
||||
} else {
|
||||
encoding = null;
|
||||
}
|
||||
|
||||
if (encoding == null) {
|
||||
// Figure out the default encoding.
|
||||
encoding = java.nio.charset.Charset.defaultCharset().name();
|
||||
}
|
||||
// Try to map the encoding name to a canonical name.
|
||||
try {
|
||||
Charset cs = Charset.forName(encoding);
|
||||
encoding = cs.name();
|
||||
} catch (Exception ex) {
|
||||
// We hit problems finding a canonical name.
|
||||
// Just use the raw encoding name.
|
||||
}
|
||||
|
||||
sb.append(" encoding=\"");
|
||||
sb.append(encoding);
|
||||
sb.append("\"");
|
||||
sb.append(" standalone=\"no\"?>\n");
|
||||
|
||||
sb.append("<!DOCTYPE log SYSTEM \"logger.dtd\">\n");
|
||||
sb.append("<log>\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tail string for a set of XML formatted records.
|
||||
*
|
||||
* @param h The target handler (can be null)
|
||||
* @return a valid XML string
|
||||
*/
|
||||
@Override
|
||||
public String getTail(Handler h) {
|
||||
return "</log>\n";
|
||||
}
|
||||
}
|
127
src/java.logging/share/classes/java/util/logging/package.html
Normal file
127
src/java.logging/share/classes/java/util/logging/package.html
Normal file
|
@ -0,0 +1,127 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
Copyright (c) 2001, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
|
||||
This code is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License version 2 only, as
|
||||
published by the Free Software Foundation. Oracle designates this
|
||||
particular file as subject to the "Classpath" exception as provided
|
||||
by Oracle in the LICENSE file that accompanied this code.
|
||||
|
||||
This code 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
|
||||
version 2 for more details (a copy is included in the LICENSE file that
|
||||
accompanied this code).
|
||||
|
||||
You should have received a copy of the GNU General Public License version
|
||||
2 along with this work; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
or visit www.oracle.com if you need additional information or have any
|
||||
questions.
|
||||
-->
|
||||
|
||||
</head>
|
||||
<body bgcolor="white">
|
||||
<P>
|
||||
Provides the classes and interfaces of
|
||||
the Java™ 2 platform's core logging facilities.
|
||||
The central goal of the logging APIs is to support maintaining and servicing
|
||||
software at customer sites.
|
||||
|
||||
<P>
|
||||
There are four main target uses of the logs:
|
||||
</P>
|
||||
|
||||
<OL>
|
||||
<LI> <I>Problem diagnosis by end users and system administrators</I>.
|
||||
This consists of simple logging of common problems that can be fixed
|
||||
or tracked locally, such as running out of resources, security failures,
|
||||
and simple configuration errors.
|
||||
|
||||
<LI> <I>Problem diagnosis by field service engineers</I>. The logging information
|
||||
used by field service engineers may be considerably more complex and
|
||||
verbose than that required by system administrators. Typically such information
|
||||
will require extra logging within particular subsystems.
|
||||
|
||||
<LI> <I>Problem diagnosis by the development organization</I>.
|
||||
When a problem occurs in the field, it may be necessary to return the captured logging
|
||||
information to the original development team for diagnosis. This logging
|
||||
information may be extremely detailed and fairly inscrutable. Such information might include
|
||||
detailed tracing on the internal execution of particular subsystems.
|
||||
|
||||
<LI> <I>Problem diagnosis by developers</I>. The Logging APIs may also be
|
||||
used to help debug an application under development. This may
|
||||
include logging information generated by the target application
|
||||
as well as logging information generated by lower-level libraries.
|
||||
Note however that while this use is perfectly reasonable,
|
||||
the logging APIs are not intended to replace the normal debugging
|
||||
and profiling tools that may already exist in the development environment.
|
||||
</OL>
|
||||
|
||||
<p>
|
||||
The key elements of this package include:
|
||||
<UL>
|
||||
<LI> <I>Logger</I>: The main entity on which applications make
|
||||
logging calls. A Logger object is used to log messages
|
||||
for a specific system or application
|
||||
component.
|
||||
<LI> <I>LogRecord</I>: Used to pass logging requests between the logging
|
||||
framework and individual log handlers.
|
||||
<LI> <I>Handler</I>: Exports LogRecord objects to a variety of destinations
|
||||
including memory, output streams, consoles, files, and sockets.
|
||||
A variety of Handler subclasses exist for this purpose. Additional Handlers
|
||||
may be developed by third parties and delivered on top of the core platform.
|
||||
<LI> <I>Level</I>: Defines a set of standard logging levels that can be used
|
||||
to control logging output. Programs can be configured to output logging
|
||||
for some levels while ignoring output for others.
|
||||
<LI> <I>Filter</I>: Provides fine-grained control over what gets logged,
|
||||
beyond the control provided by log levels. The logging APIs support a general-purpose
|
||||
filter mechanism that allows application code to attach arbitrary filters to
|
||||
control logging output.
|
||||
|
||||
<LI> <I>Formatter</I>: Provides support for formatting LogRecord objects. This
|
||||
package includes two formatters, SimpleFormatter and
|
||||
XMLFormatter, for formatting log records in plain text
|
||||
or XML respectively. As with Handlers, additional Formatters
|
||||
may be developed by third parties.
|
||||
</UL>
|
||||
<P>
|
||||
The Logging APIs offer both static and dynamic configuration control.
|
||||
Static control enables field service staff to set up a particular configuration and then re-launch the
|
||||
application with the new logging settings. Dynamic control allows for updates to the
|
||||
logging configuration within a currently running program. The APIs also allow for logging to be
|
||||
enabled or disabled for different functional areas of the system. For example,
|
||||
a field service engineer might be interested in tracing all AWT events, but might have no interest in
|
||||
socket events or memory management.
|
||||
</P>
|
||||
|
||||
<h2>Null Pointers</h2>
|
||||
<p>
|
||||
In general, unless otherwise noted in the javadoc, methods and
|
||||
constructors will throw NullPointerException if passed a null argument.
|
||||
The one broad exception to this rule is that the logging convenience
|
||||
methods in the Logger class (the config, entering, exiting, fine, finer, finest,
|
||||
log, logp, logrb, severe, throwing, and warning methods)
|
||||
will accept null values
|
||||
for all arguments except for the initial Level argument (if any).
|
||||
|
||||
<H2>Related Documentation</H2>
|
||||
<P>
|
||||
For an overview of control flow,
|
||||
please refer to the
|
||||
{@extLink logging_overview Java Logging Overview}
|
||||
</P>
|
||||
|
||||
<!-- Put @see and @since tags down here. -->
|
||||
|
||||
@since 1.4
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
38
src/java.logging/share/classes/module-info.java
Normal file
38
src/java.logging/share/classes/module-info.java
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Defines the Java Logging API.
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
module java.logging {
|
||||
exports java.util.logging;
|
||||
|
||||
provides jdk.internal.logger.DefaultLoggerFinder with
|
||||
sun.util.logging.internal.LoggingProviderImpl;
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.protocol.http.logging;
|
||||
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.regex.*;
|
||||
|
||||
/**
|
||||
* A Formatter to make the HTTP logs a bit more palatable to the developer
|
||||
* looking at them. The idea is to present the HTTP events in such a way that
|
||||
* commands and headers are easily spotted (i.e. on separate lines).
|
||||
* @author jccollet
|
||||
*/
|
||||
public class HttpLogFormatter extends java.util.logging.SimpleFormatter {
|
||||
// Pattern for MessageHeader data. Mostly pairs within curly brackets
|
||||
private static volatile Pattern pattern = null;
|
||||
// Pattern for Cookies
|
||||
private static volatile Pattern cpattern = null;
|
||||
|
||||
public HttpLogFormatter() {
|
||||
if (pattern == null) {
|
||||
pattern = Pattern.compile("\\{[^\\}]*\\}");
|
||||
cpattern = Pattern.compile("[^,\\] ]{2,}");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(LogRecord record) {
|
||||
String sourceClassName = record.getSourceClassName();
|
||||
if (sourceClassName == null ||
|
||||
!(sourceClassName.startsWith("sun.net.www.protocol.http") ||
|
||||
sourceClassName.startsWith("sun.net.www.http"))) {
|
||||
return super.format(record);
|
||||
}
|
||||
String src = record.getMessage();
|
||||
StringBuilder buf = new StringBuilder("HTTP: ");
|
||||
if (src.startsWith("sun.net.www.MessageHeader@")) {
|
||||
// MessageHeader logs are composed of pairs within curly brackets
|
||||
// Let's extract them to make it more readable. That way we get one
|
||||
// header pair (name, value) per line. A lot easier to read.
|
||||
Matcher match = pattern.matcher(src);
|
||||
while (match.find()) {
|
||||
int i = match.start();
|
||||
int j = match.end();
|
||||
String s = src.substring(i + 1, j - 1);
|
||||
if (s.startsWith("null: ")) {
|
||||
s = s.substring(6);
|
||||
}
|
||||
if (s.endsWith(": null")) {
|
||||
s = s.substring(0, s.length() - 6);
|
||||
}
|
||||
buf.append("\t").append(s).append("\n");
|
||||
}
|
||||
} else if (src.startsWith("Cookies retrieved: {")) {
|
||||
// This comes from the Cookie handler, let's clean up the format a bit
|
||||
String s = src.substring(20);
|
||||
buf.append("Cookies from handler:\n");
|
||||
while (s.length() >= 7) {
|
||||
if (s.startsWith("Cookie=[")) {
|
||||
String s2 = s.substring(8);
|
||||
int c = s2.indexOf("Cookie2=[");
|
||||
if (c > 0) {
|
||||
s2 = s2.substring(0, c-1);
|
||||
s = s2.substring(c);
|
||||
} else {
|
||||
s = "";
|
||||
}
|
||||
if (s2.length() < 4) {
|
||||
continue;
|
||||
}
|
||||
Matcher m = cpattern.matcher(s2);
|
||||
while (m.find()) {
|
||||
int i = m.start();
|
||||
int j = m.end();
|
||||
if (i >= 0) {
|
||||
String cookie = s2.substring(i + 1, j > 0 ? j - 1 : s2.length() - 1);
|
||||
buf.append("\t").append(cookie).append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s.startsWith("Cookie2=[")) {
|
||||
String s2 = s.substring(9);
|
||||
int c = s2.indexOf("Cookie=[");
|
||||
if (c > 0) {
|
||||
s2 = s2.substring(0, c-1);
|
||||
s = s2.substring(c);
|
||||
} else {
|
||||
s = "";
|
||||
}
|
||||
Matcher m = cpattern.matcher(s2);
|
||||
while (m.find()) {
|
||||
int i = m.start();
|
||||
int j = m.end();
|
||||
if (i >= 0) {
|
||||
String cookie = s2.substring(i+1, j > 0 ? j-1 : s2.length() - 1);
|
||||
buf.append("\t").append(cookie).append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Anything else we let as is.
|
||||
buf.append(src).append("\n");
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,465 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package sun.util.logging.internal;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.function.Supplier;
|
||||
import java.lang.System.LoggerFinder;
|
||||
import java.lang.System.Logger;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.LogManager;
|
||||
import jdk.internal.logger.DefaultLoggerFinder;
|
||||
import java.util.logging.LoggingPermission;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
import sun.util.logging.PlatformLogger.ConfigurableBridge.LoggerConfiguration;
|
||||
|
||||
/**
|
||||
* This {@code LoggingProviderImpl} is the JDK internal implementation of the
|
||||
* {@link jdk.internal.logger.DefaultLoggerFinder} which is used by
|
||||
* the default implementation of the {@link Logger}
|
||||
* when no {@link LoggerFinder} is found
|
||||
* and {@code java.util.logging} is present.
|
||||
* When {@code java.util.logging} is present, the {@code LoggingProviderImpl}
|
||||
* is {@linkplain java.util.ServiceLoader#loadInstalled(Class) installed} as
|
||||
* an internal service provider, making it possible to use {@code java.util.logging}
|
||||
* as the backend for loggers returned by the default LoggerFinder implementation.
|
||||
* <p>
|
||||
* This implementation of {@link DefaultLoggerFinder} returns instances of
|
||||
* {@link java.lang.System.Logger} which
|
||||
* delegate to a wrapped instance of {@link java.util.logging.Logger
|
||||
* java.util.logging.Logger}.
|
||||
* <br>
|
||||
* Loggers returned by this class can therefore be configured by accessing
|
||||
* their wrapped implementation through the regular {@code java.util.logging}
|
||||
* APIs - such as {@link java.util.logging.LogManager java.util.logging.LogManager}
|
||||
* and {@link java.util.logging.Logger java.util.logging.Logger}.
|
||||
*
|
||||
* @apiNote Programmers are not expected to call this class directly.
|
||||
* Instead they should rely on the static methods defined by
|
||||
* {@link java.lang.System java.lang.System}.
|
||||
* <p>
|
||||
* To replace this default
|
||||
* {@code java.util.logging} backend, an application is expected to install
|
||||
* its own {@link java.lang.System.LoggerFinder}.
|
||||
*
|
||||
* @see java.lang.System.Logger
|
||||
* @see java.lang.System.LoggerFinder
|
||||
* @see sun.util.logging.PlatformLogger.Bridge
|
||||
* @see java.lang.System
|
||||
* @see jdk.internal.logger
|
||||
* @see jdk.internal.logger
|
||||
*
|
||||
*/
|
||||
public final class LoggingProviderImpl extends DefaultLoggerFinder {
|
||||
static final RuntimePermission LOGGERFINDER_PERMISSION =
|
||||
new RuntimePermission("loggerFinder");
|
||||
private static final LoggingPermission LOGGING_CONTROL_PERMISSION =
|
||||
new LoggingPermission("control", null);
|
||||
|
||||
/**
|
||||
* Creates a new instance of LoggingProviderImpl.
|
||||
* @throws SecurityException if the calling code does not have the
|
||||
* {@code RuntimePermission("loggerFinder")}.
|
||||
*/
|
||||
public LoggingProviderImpl() {
|
||||
}
|
||||
|
||||
/**
|
||||
* A logger that delegates to a java.util.logging.Logger delegate.
|
||||
*/
|
||||
static final class JULWrapper extends LoggerConfiguration
|
||||
implements System.Logger, PlatformLogger.Bridge,
|
||||
PlatformLogger.ConfigurableBridge {
|
||||
|
||||
|
||||
private static final java.util.logging.Level[] spi2JulLevelMapping = {
|
||||
java.util.logging.Level.ALL, // mapped from ALL
|
||||
java.util.logging.Level.FINER, // mapped from TRACE
|
||||
java.util.logging.Level.FINE, // mapped from DEBUG
|
||||
java.util.logging.Level.INFO, // mapped from INFO
|
||||
java.util.logging.Level.WARNING, // mapped from WARNING
|
||||
java.util.logging.Level.SEVERE, // mapped from ERROR
|
||||
java.util.logging.Level.OFF // mapped from OFF
|
||||
};
|
||||
|
||||
private static final java.util.logging.Level[] platform2JulLevelMapping = {
|
||||
java.util.logging.Level.ALL, // mapped from ALL
|
||||
java.util.logging.Level.FINEST, // mapped from FINEST
|
||||
java.util.logging.Level.FINER, // mapped from FINER
|
||||
java.util.logging.Level.FINE, // mapped from FINE
|
||||
java.util.logging.Level.CONFIG, // mapped from CONFIG
|
||||
java.util.logging.Level.INFO, // mapped from INFO
|
||||
java.util.logging.Level.WARNING, // mapped from WARNING
|
||||
java.util.logging.Level.SEVERE, // mapped from SEVERE
|
||||
java.util.logging.Level.OFF // mapped from OFF
|
||||
};
|
||||
|
||||
private final java.util.logging.Logger julLogger;
|
||||
|
||||
|
||||
private JULWrapper(java.util.logging.Logger logger) {
|
||||
this.julLogger = logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return julLogger.getName();
|
||||
}
|
||||
@Override
|
||||
public void log(sun.util.logging.PlatformLogger.Level level, String msg, Throwable throwable) {
|
||||
julLogger.log(toJUL(level), msg, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(sun.util.logging.PlatformLogger.Level level, String format, Object... params) {
|
||||
julLogger.log(toJUL(level), format, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(sun.util.logging.PlatformLogger.Level level, String msg) {
|
||||
julLogger.log(toJUL(level), msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(sun.util.logging.PlatformLogger.Level level, Supplier<String> msgSuppier) {
|
||||
julLogger.log(toJUL(level), msgSuppier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(sun.util.logging.PlatformLogger.Level level, Throwable thrown, Supplier<String> msgSuppier) {
|
||||
julLogger.log(toJUL(level), thrown, msgSuppier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logrb(sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle, String key, Throwable throwable) {
|
||||
julLogger.logrb(toJUL(level), bundle, key, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logrb(sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle, String key, Object... params) {
|
||||
julLogger.logrb(toJUL(level), bundle, key, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, String msg) {
|
||||
julLogger.logp(toJUL(level), sourceClass, sourceMethod, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod,
|
||||
Supplier<String> msgSupplier) {
|
||||
julLogger.logp(toJUL(level), sourceClass, sourceMethod, msgSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod,
|
||||
String msg, Object... params) {
|
||||
julLogger.logp(toJUL(level), sourceClass, sourceMethod, msg, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod,
|
||||
String msg, Throwable thrown) {
|
||||
julLogger.logp(toJUL(level), sourceClass, sourceMethod, msg, thrown);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod,
|
||||
Throwable thrown, Supplier<String> msgSupplier) {
|
||||
julLogger.logp(toJUL(level), sourceClass, sourceMethod,
|
||||
thrown, msgSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logrb(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod,
|
||||
ResourceBundle bundle, String key, Object... params) {
|
||||
julLogger.logrb(toJUL(level), sourceClass, sourceMethod,
|
||||
bundle, key, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logrb(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod,
|
||||
ResourceBundle bundle, String key, Throwable thrown) {
|
||||
julLogger.logrb(toJUL(level), sourceClass, sourceMethod,
|
||||
bundle, key, thrown);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoggable(sun.util.logging.PlatformLogger.Level level) {
|
||||
return julLogger.isLoggable(toJUL(level));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Generic methods taking a Level as parameter
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isLoggable(Level level) {
|
||||
return julLogger.isLoggable(toJUL(level));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(Level level, String msg) {
|
||||
julLogger.log(toJUL(level), msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(Level level,
|
||||
Supplier<String> msgSupplier) {
|
||||
// We need to check for null here to satisfy the contract
|
||||
// of System.Logger - because the underlying implementation
|
||||
// of julLogger will check for it only if the level is
|
||||
// loggable
|
||||
Objects.requireNonNull(msgSupplier);
|
||||
julLogger.log(toJUL(level), msgSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(Level level, Object obj) {
|
||||
// We need to check for null here to satisfy the contract
|
||||
// of System.Logger - because the underlying implementation
|
||||
// of julLogger will check for it only if the level is
|
||||
// loggable
|
||||
Objects.requireNonNull(obj);
|
||||
julLogger.log(toJUL(level), () -> obj.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(Level level,
|
||||
String msg, Throwable thrown) {
|
||||
julLogger.log(toJUL(level), msg, thrown);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(Level level, Supplier<String> msgSupplier,
|
||||
Throwable thrown) {
|
||||
// We need to check for null here to satisfy the contract
|
||||
// of System.Logger - because the underlying implementation
|
||||
// of julLogger will check for it only if the level is
|
||||
// loggable
|
||||
Objects.requireNonNull(msgSupplier);
|
||||
julLogger.log(toJUL(level), thrown, msgSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(Level level,
|
||||
String format, Object... params) {
|
||||
julLogger.log(toJUL(level), format, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(Level level, ResourceBundle bundle,
|
||||
String key, Throwable thrown) {
|
||||
julLogger.logrb(toJUL(level), bundle, key, thrown);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(Level level, ResourceBundle bundle,
|
||||
String format, Object... params) {
|
||||
julLogger.logrb(toJUL(level), bundle, format, params);
|
||||
}
|
||||
|
||||
static java.util.logging.Level toJUL(Level level) {
|
||||
if (level == null) return null;
|
||||
assert level.ordinal() < spi2JulLevelMapping.length;
|
||||
return spi2JulLevelMapping[level.ordinal()];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Methods from PlatformLogger.Bridge
|
||||
// ---------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return julLogger.getLevel() != java.util.logging.Level.OFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformLogger.Level getPlatformLevel() {
|
||||
final java.util.logging.Level javaLevel = julLogger.getLevel();
|
||||
if (javaLevel == null) return null;
|
||||
try {
|
||||
return PlatformLogger.Level.valueOf(javaLevel.getName());
|
||||
} catch (IllegalArgumentException e) {
|
||||
return PlatformLogger.Level.valueOf(javaLevel.intValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlatformLevel(PlatformLogger.Level level) {
|
||||
// null is allowed here
|
||||
julLogger.setLevel(toJUL(level));
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoggerConfiguration getLoggerConfiguration() {
|
||||
return this;
|
||||
}
|
||||
|
||||
static java.util.logging.Level toJUL(PlatformLogger.Level level) {
|
||||
// The caller will throw if null is invalid in its context.
|
||||
// There's at least one case where a null level is valid.
|
||||
if (level == null) return null;
|
||||
assert level.ordinal() < platform2JulLevelMapping.length;
|
||||
return platform2JulLevelMapping[level.ordinal()];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return (obj instanceof JULWrapper)
|
||||
&& obj.getClass() == this.getClass()
|
||||
&& ((JULWrapper)obj).julLogger == this.julLogger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return julLogger.hashCode();
|
||||
}
|
||||
|
||||
// A JULWrapper is just a stateless thin shell over a JUL logger - so
|
||||
// for a given JUL logger, we could always return the same wrapper.
|
||||
//
|
||||
// This is an optimization which may - or may not - be worth the
|
||||
// trouble: if many classes use the same logger, and if each class
|
||||
// keeps a reference to that logger, then caching the wrapper will
|
||||
// be worthwhile. Otherwise, if each logger is only referred once,
|
||||
// then the cache will eat up more memory than would be necessary...
|
||||
//
|
||||
// Here is an example of how we could implement JULWrapper.of(...)
|
||||
// if we wanted to create at most one wrapper instance for each logger
|
||||
// instance:
|
||||
//
|
||||
// static final WeakHashMap<JULWrapper, WeakReference<JULWrapper>>
|
||||
// wrappers = new WeakHashMap<>();
|
||||
//
|
||||
// static JULWrapper of(java.util.logging.Logger logger) {
|
||||
//
|
||||
// // First access without synchronizing
|
||||
// final JULWrapper candidate = new JULWrapper(logger);
|
||||
// WeakReference<JULWrapper> ref = wrappers.get(candidate);
|
||||
// JULWrapper found = ref.get();
|
||||
//
|
||||
// // OK - we found it - lets return it.
|
||||
// if (found != null) return found;
|
||||
//
|
||||
// // Not found. Need to synchronize.
|
||||
// synchronized (wrappers) {
|
||||
// ref = wrappers.get(candidate);
|
||||
// found = ref.get();
|
||||
// if (found == null) {
|
||||
// wrappers.put(candidate, new WeakReference<>(candidate));
|
||||
// found = candidate;
|
||||
// }
|
||||
// }
|
||||
// assert found != null;
|
||||
// return found;
|
||||
// }
|
||||
//
|
||||
// But given that it may end up eating more memory in the nominal case
|
||||
// (where each class that does logging has its own logger with the
|
||||
// class name as logger name and stashes that logger away in a static
|
||||
// field, thus making the cache redundant - as only one wrapper will
|
||||
// ever be created anyway) - then we will simply return a new wrapper
|
||||
// for each invocation of JULWrapper.of(...) - which may
|
||||
// still prove more efficient in terms of memory consumption...
|
||||
//
|
||||
static JULWrapper of(java.util.logging.Logger logger) {
|
||||
return new JULWrapper(logger);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a java.util.logging.Logger for the given module.
|
||||
* @param name the logger name.
|
||||
* @param module the module for which the logger should be created.
|
||||
* @return a Logger suitable for use in the given module.
|
||||
*/
|
||||
private static java.util.logging.Logger demandJULLoggerFor(final String name,
|
||||
Module module) {
|
||||
final LogManager manager = LogManager.getLogManager();
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
if (sm == null) {
|
||||
return logManagerAccess.demandLoggerFor(manager, name, module);
|
||||
} else {
|
||||
final PrivilegedAction<java.util.logging.Logger> pa =
|
||||
() -> logManagerAccess.demandLoggerFor(manager, name, module);
|
||||
return AccessController.doPrivileged(pa, null, LOGGING_CONTROL_PERMISSION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @apiNote The logger returned by this method can be configured through
|
||||
* its {@linkplain java.util.logging.LogManager#getLogger(String)
|
||||
* corresponding java.util.logging.Logger backend}.
|
||||
*
|
||||
* @return {@inheritDoc}
|
||||
* @throws SecurityException if the calling code doesn't have the
|
||||
* {@code RuntimePermission("loggerFinder")}.
|
||||
*/
|
||||
@Override
|
||||
protected Logger demandLoggerFor(String name, Module module) {
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(LOGGERFINDER_PERMISSION);
|
||||
}
|
||||
return JULWrapper.of(demandJULLoggerFor(name,module));
|
||||
}
|
||||
|
||||
public static interface LogManagerAccess {
|
||||
java.util.logging.Logger demandLoggerFor(LogManager manager,
|
||||
String name, Module module);
|
||||
}
|
||||
|
||||
// Hook for tests
|
||||
public static LogManagerAccess getLogManagerAccess() {
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(LOGGING_CONTROL_PERMISSION);
|
||||
}
|
||||
// Triggers initialization of accessJulLogger if not set.
|
||||
if (logManagerAccess == null) LogManager.getLogManager();
|
||||
return logManagerAccess;
|
||||
}
|
||||
|
||||
|
||||
private static volatile LogManagerAccess logManagerAccess;
|
||||
public static void setLogManagerAccess(LogManagerAccess accesLoggers) {
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(LOGGING_CONTROL_PERMISSION);
|
||||
}
|
||||
logManagerAccess = accesLoggers;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code 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
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* <b>[JDK INTERNAL]</b>
|
||||
* The {@code sun.util.logging.internal} package defines an internal
|
||||
* implementation of the {@link jdk.internal.logger.DefaultLoggerFinder} which
|
||||
* provides an extension of the {@link java.lang.System.Logger System.Logger}
|
||||
* interface making it easy to bridge from {@link java.util.logging};
|
||||
* the JDK default implementation of the LoggerFinder will return loggers
|
||||
* implementing this extension when {@code java.util.logging} is present.
|
||||
* </p>
|
||||
* <p>
|
||||
* When {@code java.util.logging} is present, Logger instances returned by
|
||||
* the JDK default implementation of the LoggerFinder
|
||||
* wrap an instance of {@link java.util.logging.Logger java.util.logging.Logger}
|
||||
* and implement the {@link
|
||||
* sun.util.logging.PlatformLogger.Bridge PlatformLogger.Bridge}
|
||||
* extension, overriding all the methods defined in
|
||||
* that extension in order to call the corresponding methods on their wrapped
|
||||
* {@linkplain java.util.logging.Logger backend Logger} instance.
|
||||
* <p>
|
||||
* <br>
|
||||
* @see java.lang.System.LoggerFinder
|
||||
* @see java.lang.System.Logger
|
||||
* @see sun.util.logging.PlatformLogger
|
||||
* @see sun.util.logging.PlatformLogger.Bridge
|
||||
* @see jdk.internal.logger
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
package sun.util.logging.internal;
|
|
@ -0,0 +1,46 @@
|
|||
#
|
||||
# Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code 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
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
# Localizations for Level names. For the US locale
|
||||
# these are the same as the non-localized level name.
|
||||
|
||||
# The following ALL CAPS words should be translated.
|
||||
ALL=All
|
||||
# The following ALL CAPS words should be translated.
|
||||
SEVERE=Severe
|
||||
# The following ALL CAPS words should be translated.
|
||||
WARNING=Warning
|
||||
# The following ALL CAPS words should be translated.
|
||||
INFO=Info
|
||||
# The following ALL CAPS words should be translated.
|
||||
CONFIG= Config
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINE=Fine
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINER=Finer
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINEST=Finest
|
||||
# The following ALL CAPS words should be translated.
|
||||
OFF=Off
|
|
@ -0,0 +1,46 @@
|
|||
#
|
||||
# Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code 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
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
# Localizations for Level names. For the US locale
|
||||
# these are the same as the non-localized level name.
|
||||
|
||||
# The following ALL CAPS words should be translated.
|
||||
ALL=Alle
|
||||
# The following ALL CAPS words should be translated.
|
||||
SEVERE=Schwerwiegend
|
||||
# The following ALL CAPS words should be translated.
|
||||
WARNING=Warnung
|
||||
# The following ALL CAPS words should be translated.
|
||||
INFO=Information
|
||||
# The following ALL CAPS words should be translated.
|
||||
CONFIG= Konfiguration
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINE=Fein
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINER=Feiner
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINEST=Am feinsten
|
||||
# The following ALL CAPS words should be translated.
|
||||
OFF=Deaktiviert
|
|
@ -0,0 +1,46 @@
|
|||
#
|
||||
# Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code 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
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
# Localizations for Level names. For the US locale
|
||||
# these are the same as the non-localized level name.
|
||||
|
||||
# The following ALL CAPS words should be translated.
|
||||
ALL=Todo
|
||||
# The following ALL CAPS words should be translated.
|
||||
SEVERE=Grave
|
||||
# The following ALL CAPS words should be translated.
|
||||
WARNING=Advertencia
|
||||
# The following ALL CAPS words should be translated.
|
||||
INFO=Informaci\u00F3n
|
||||
# The following ALL CAPS words should be translated.
|
||||
CONFIG= Configurar
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINE=Detallado
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINER=Muy Detallado
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINEST=M\u00E1s Detallado
|
||||
# The following ALL CAPS words should be translated.
|
||||
OFF=Desactivado
|
|
@ -0,0 +1,46 @@
|
|||
#
|
||||
# Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code 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
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
# Localizations for Level names. For the US locale
|
||||
# these are the same as the non-localized level name.
|
||||
|
||||
# The following ALL CAPS words should be translated.
|
||||
ALL=Tout
|
||||
# The following ALL CAPS words should be translated.
|
||||
SEVERE=Grave
|
||||
# The following ALL CAPS words should be translated.
|
||||
WARNING=Avertissement
|
||||
# The following ALL CAPS words should be translated.
|
||||
INFO=Infos
|
||||
# The following ALL CAPS words should be translated.
|
||||
CONFIG= Config
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINE=Pr\u00E9cis
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINER=Plus pr\u00E9cis
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINEST=Le plus pr\u00E9cis
|
||||
# The following ALL CAPS words should be translated.
|
||||
OFF=D\u00E9sactiv\u00E9
|
|
@ -0,0 +1,46 @@
|
|||
#
|
||||
# Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code 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
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
# Localizations for Level names. For the US locale
|
||||
# these are the same as the non-localized level name.
|
||||
|
||||
# The following ALL CAPS words should be translated.
|
||||
ALL=Tutto
|
||||
# The following ALL CAPS words should be translated.
|
||||
SEVERE=Grave
|
||||
# The following ALL CAPS words should be translated.
|
||||
WARNING=Avvertenza
|
||||
# The following ALL CAPS words should be translated.
|
||||
INFO=Informazioni
|
||||
# The following ALL CAPS words should be translated.
|
||||
CONFIG= Configurazione
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINE=Buono
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINER=Migliore
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINEST=Ottimale
|
||||
# The following ALL CAPS words should be translated.
|
||||
OFF=Non attivo
|
|
@ -0,0 +1,46 @@
|
|||
#
|
||||
# Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code 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
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
# Localizations for Level names. For the US locale
|
||||
# these are the same as the non-localized level name.
|
||||
|
||||
# The following ALL CAPS words should be translated.
|
||||
ALL=\u3059\u3079\u3066
|
||||
# The following ALL CAPS words should be translated.
|
||||
SEVERE=\u91CD\u5927
|
||||
# The following ALL CAPS words should be translated.
|
||||
WARNING=\u8B66\u544A
|
||||
# The following ALL CAPS words should be translated.
|
||||
INFO=\u60C5\u5831
|
||||
# The following ALL CAPS words should be translated.
|
||||
CONFIG= \u69CB\u6210
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINE=\u666E\u901A
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINER=\u8A73\u7D30
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINEST=\u6700\u3082\u8A73\u7D30
|
||||
# The following ALL CAPS words should be translated.
|
||||
OFF=\u30AA\u30D5
|
|
@ -0,0 +1,46 @@
|
|||
#
|
||||
# Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code 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
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
# Localizations for Level names. For the US locale
|
||||
# these are the same as the non-localized level name.
|
||||
|
||||
# The following ALL CAPS words should be translated.
|
||||
ALL=\uBAA8\uB450
|
||||
# The following ALL CAPS words should be translated.
|
||||
SEVERE=\uC2EC\uAC01
|
||||
# The following ALL CAPS words should be translated.
|
||||
WARNING=\uACBD\uACE0
|
||||
# The following ALL CAPS words should be translated.
|
||||
INFO=\uC815\uBCF4
|
||||
# The following ALL CAPS words should be translated.
|
||||
CONFIG= \uAD6C\uC131
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINE=\uBBF8\uC138
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINER=\uBCF4\uB2E4 \uBBF8\uC138
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINEST=\uAC00\uC7A5 \uBBF8\uC138
|
||||
# The following ALL CAPS words should be translated.
|
||||
OFF=\uD574\uC81C
|
|
@ -0,0 +1,46 @@
|
|||
#
|
||||
# Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code 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
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
# Localizations for Level names. For the US locale
|
||||
# these are the same as the non-localized level name.
|
||||
|
||||
# The following ALL CAPS words should be translated.
|
||||
ALL=Tudo
|
||||
# The following ALL CAPS words should be translated.
|
||||
SEVERE=Grave
|
||||
# The following ALL CAPS words should be translated.
|
||||
WARNING=Advert\u00EAncia
|
||||
# The following ALL CAPS words should be translated.
|
||||
INFO=Informa\u00E7\u00F5es
|
||||
# The following ALL CAPS words should be translated.
|
||||
CONFIG= Configura\u00E7\u00E3o
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINE=Detalhado
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINER=Mais Detalhado
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINEST=O Mais Detalhado
|
||||
# The following ALL CAPS words should be translated.
|
||||
OFF=Desativado
|
|
@ -0,0 +1,46 @@
|
|||
#
|
||||
# Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code 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
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
# Localizations for Level names. For the US locale
|
||||
# these are the same as the non-localized level name.
|
||||
|
||||
# The following ALL CAPS words should be translated.
|
||||
ALL=Alla
|
||||
# The following ALL CAPS words should be translated.
|
||||
SEVERE=Allvarlig
|
||||
# The following ALL CAPS words should be translated.
|
||||
WARNING=Varning
|
||||
# The following ALL CAPS words should be translated.
|
||||
INFO=Info
|
||||
# The following ALL CAPS words should be translated.
|
||||
CONFIG= Konfig
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINE=Fin
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINER=Finare
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINEST=Finaste
|
||||
# The following ALL CAPS words should be translated.
|
||||
OFF=Av
|
|
@ -0,0 +1,46 @@
|
|||
#
|
||||
# Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code 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
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
# Localizations for Level names. For the US locale
|
||||
# these are the same as the non-localized level name.
|
||||
|
||||
# The following ALL CAPS words should be translated.
|
||||
ALL=\u5168\u90E8
|
||||
# The following ALL CAPS words should be translated.
|
||||
SEVERE=\u4E25\u91CD
|
||||
# The following ALL CAPS words should be translated.
|
||||
WARNING=\u8B66\u544A
|
||||
# The following ALL CAPS words should be translated.
|
||||
INFO=\u4FE1\u606F
|
||||
# The following ALL CAPS words should be translated.
|
||||
CONFIG= \u914D\u7F6E
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINE=\u8BE6\u7EC6
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINER=\u8F83\u8BE6\u7EC6
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINEST=\u975E\u5E38\u8BE6\u7EC6
|
||||
# The following ALL CAPS words should be translated.
|
||||
OFF=\u7981\u7528
|
|
@ -0,0 +1,46 @@
|
|||
#
|
||||
# Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code 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
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
# Localizations for Level names. For the US locale
|
||||
# these are the same as the non-localized level name.
|
||||
|
||||
# The following ALL CAPS words should be translated.
|
||||
ALL=\u6240\u6709
|
||||
# The following ALL CAPS words should be translated.
|
||||
SEVERE=\u56B4\u91CD
|
||||
# The following ALL CAPS words should be translated.
|
||||
WARNING=\u8B66\u544A
|
||||
# The following ALL CAPS words should be translated.
|
||||
INFO=\u8CC7\u8A0A
|
||||
# The following ALL CAPS words should be translated.
|
||||
CONFIG= \u7D44\u614B
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINE=\u8A73\u7D30
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINER=\u8F03\u8A73\u7D30
|
||||
# The following ALL CAPS words should be translated.
|
||||
FINEST=\u6700\u8A73\u7D30
|
||||
# The following ALL CAPS words should be translated.
|
||||
OFF=\u95DC\u9589
|
63
src/java.logging/share/conf/logging.properties
Normal file
63
src/java.logging/share/conf/logging.properties
Normal file
|
@ -0,0 +1,63 @@
|
|||
############################################################
|
||||
# Default Logging Configuration File
|
||||
#
|
||||
# You can use a different file by specifying a filename
|
||||
# with the java.util.logging.config.file system property.
|
||||
# For example java -Djava.util.logging.config.file=myfile
|
||||
############################################################
|
||||
|
||||
############################################################
|
||||
# Global properties
|
||||
############################################################
|
||||
|
||||
# "handlers" specifies a comma separated list of log Handler
|
||||
# classes. These handlers will be installed during VM startup.
|
||||
# Note that these classes must be on the system classpath.
|
||||
# By default we only configure a ConsoleHandler, which will only
|
||||
# show messages at the INFO and above levels.
|
||||
handlers= java.util.logging.ConsoleHandler
|
||||
|
||||
# To also add the FileHandler, use the following line instead.
|
||||
#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler
|
||||
|
||||
# Default global logging level.
|
||||
# This specifies which kinds of events are logged across
|
||||
# all loggers. For any given facility this global level
|
||||
# can be overriden by a facility specific level
|
||||
# Note that the ConsoleHandler also has a separate level
|
||||
# setting to limit messages printed to the console.
|
||||
.level= INFO
|
||||
|
||||
############################################################
|
||||
# Handler specific properties.
|
||||
# Describes specific configuration info for Handlers.
|
||||
############################################################
|
||||
|
||||
# default file output is in user's home directory.
|
||||
java.util.logging.FileHandler.pattern = %h/java%u.log
|
||||
java.util.logging.FileHandler.limit = 50000
|
||||
java.util.logging.FileHandler.count = 1
|
||||
# Default number of locks FileHandler can obtain synchronously.
|
||||
# This specifies maximum number of attempts to obtain lock file by FileHandler
|
||||
# implemented by incrementing the unique field %u as per FileHandler API documentation.
|
||||
java.util.logging.FileHandler.maxLocks = 100
|
||||
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
|
||||
|
||||
# Limit the message that are printed on the console to INFO and above.
|
||||
java.util.logging.ConsoleHandler.level = INFO
|
||||
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
|
||||
|
||||
# Example to customize the SimpleFormatter output format
|
||||
# to print one-line log message like this:
|
||||
# <level>: <log message> [<date/time>]
|
||||
#
|
||||
# java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n
|
||||
|
||||
############################################################
|
||||
# Facility specific properties.
|
||||
# Provides extra control for each logger.
|
||||
############################################################
|
||||
|
||||
# For example, set the com.xyz.foo logger to only log SEVERE
|
||||
# messages:
|
||||
com.xyz.foo.level = SEVERE
|
Loading…
Add table
Add a link
Reference in a new issue