jdk/src/java.logging/share/classes/java/util/logging/XMLFormatter.java
changeset 29117 7956b5dc0eac
parent 25859 3317bb8137f4
child 35782 cce69c0777dc
equal deleted inserted replaced
29116:9918719cfcc0 29117:7956b5dc0eac
     1 /*
     1 /*
     2  * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    24  */
    24  */
    25 
    25 
    26 
    26 
    27 package java.util.logging;
    27 package java.util.logging;
    28 
    28 
    29 import java.io.*;
       
    30 import java.nio.charset.Charset;
    29 import java.nio.charset.Charset;
       
    30 import java.time.Instant;
       
    31 import java.time.format.DateTimeFormatter;
    31 import java.util.*;
    32 import java.util.*;
    32 
    33 
    33 /**
    34 /**
    34  * Format a LogRecord into a standard XML format.
    35  * Format a LogRecord into a standard XML format.
    35  * <p>
    36  * <p>
    38  * <p>
    39  * <p>
    39  * The XMLFormatter can be used with arbitrary character encodings,
    40  * The XMLFormatter can be used with arbitrary character encodings,
    40  * but it is recommended that it normally be used with UTF-8.  The
    41  * but it is recommended that it normally be used with UTF-8.  The
    41  * character encoding can be set on the output Handler.
    42  * character encoding can be set on the output Handler.
    42  *
    43  *
       
    44  * @implSpec Since JDK 1.9, instances of {@linkplain LogRecord} contain
       
    45  * an {@link LogRecord#getInstant() Instant} which can have nanoseconds below
       
    46  * the millisecond resolution.
       
    47  * The DTD specification has been updated to allow for an optional
       
    48  * {@code <nanos>} element. By default, the XMLFormatter will compute the
       
    49  * nanosecond adjustment below the millisecond resolution (using
       
    50  * {@code LogRecord.getInstant().getNano() % 1000_000}) - and if this is not 0,
       
    51  * this adjustment value will be printed in the new {@code <nanos>} element.
       
    52  * The event instant can then be reconstructed using
       
    53  * {@code Instant.ofEpochSecond(millis/1000L, (millis % 1000L) * 1000_000L + nanos)}
       
    54  * where {@code millis} and {@code nanos} represent the numbers serialized in
       
    55  * the {@code <millis>} and {@code <nanos>} elements, respectively.
       
    56  * <br>
       
    57  * The {@code <date>} element will now contain the whole instant as formatted
       
    58  * by the {@link DateTimeFormatter#ISO_INSTANT DateTimeFormatter.ISO_INSTANT}
       
    59  * formatter.
       
    60  * <p>
       
    61  * For compatibility with old parsers, XMLFormatters can
       
    62  * be configured to revert to the old format by specifying a
       
    63  * {@code <xml-formatter-fully-qualified-class-name>.useInstant = false}
       
    64  * {@linkplain LogManager#getProperty(java.lang.String) property} in the
       
    65  * logging configuration. When {@code useInstant} is {@code false}, the old
       
    66  * formatting will be preserved. When {@code useInstant} is {@code true}
       
    67  * (the default), the {@code <nanos>} element will be printed and the
       
    68  * {@code <date>} element will contain the {@linkplain
       
    69  * DateTimeFormatter#ISO_INSTANT formatted} instant.
       
    70  * <p>
       
    71  * For instance, in order to configure plain instances of XMLFormatter to omit
       
    72  * the new {@code <nano>} element,
       
    73  * {@code java.util.logging.XMLFormatter.useInstant = false} can be specified
       
    74  * in the logging configuration.
       
    75  *
    43  * @since 1.4
    76  * @since 1.4
    44  */
    77  */
    45 
    78 
    46 public class XMLFormatter extends Formatter {
    79 public class XMLFormatter extends Formatter {
    47     private LogManager manager = LogManager.getLogManager();
    80     private final LogManager manager = LogManager.getLogManager();
       
    81     private final boolean useInstant;
       
    82 
       
    83     /**
       
    84      * Creates a new instance of XMLFormatter.
       
    85      *
       
    86      * @implSpec
       
    87      *    Since JDK 1.9, the XMLFormatter will print out the record {@linkplain
       
    88      *    LogRecord#getInstant() event time} as an Instant. This instant
       
    89      *    has the best resolution available on the system. The {@code <date>}
       
    90      *    element will contain the instant as formatted by the {@link
       
    91      *    DateTimeFormatter#ISO_INSTANT}.
       
    92      *    In addition, an optional {@code <nanos>} element containing a
       
    93      *    nanosecond adjustment will be printed if the instant contains some
       
    94      *    nanoseconds below the millisecond resolution.
       
    95      *    <p>
       
    96      *    This new behavior can be turned off, and the old formatting restored,
       
    97      *    by specifying a property in the {@linkplain
       
    98      *    LogManager#getProperty(java.lang.String) logging configuration}.
       
    99      *    If {@code LogManager.getLogManager().getProperty(
       
   100      *    this.getClass().getName()+".useInstant")} is {@code "false"} or
       
   101      *    {@code "0"}, the old formatting will be restored.
       
   102      */
       
   103     public XMLFormatter() {
       
   104         useInstant = (manager == null)
       
   105             || manager.getBooleanProperty(
       
   106                     this.getClass().getName()+".useInstant", true);
       
   107     }
    48 
   108 
    49     // Append a two digit number.
   109     // Append a two digit number.
    50     private void a2(StringBuilder sb, int x) {
   110     private void a2(StringBuilder sb, int x) {
    51         if (x < 10) {
   111         if (x < 10) {
    52             sb.append('0');
   112             sb.append('0');
   100      * convenience method to localize and format the message field.
   160      * convenience method to localize and format the message field.
   101      *
   161      *
   102      * @param record the log record to be formatted.
   162      * @param record the log record to be formatted.
   103      * @return a formatted log record
   163      * @return a formatted log record
   104      */
   164      */
       
   165     @Override
   105     public String format(LogRecord record) {
   166     public String format(LogRecord record) {
   106         StringBuilder sb = new StringBuilder(500);
   167         StringBuilder sb = new StringBuilder(500);
   107         sb.append("<record>\n");
   168         sb.append("<record>\n");
   108 
   169 
       
   170         final Instant instant = record.getInstant();
       
   171 
   109         sb.append("  <date>");
   172         sb.append("  <date>");
   110         appendISO8601(sb, record.getMillis());
   173         if (useInstant) {
       
   174             // If useInstant is true - we will print the instant in the
       
   175             // date field, using the ISO_INSTANT formatter.
       
   176             DateTimeFormatter.ISO_INSTANT.formatTo(instant, sb);
       
   177         } else {
       
   178             // If useInstant is false - we will keep the 'old' formating
       
   179             appendISO8601(sb, instant.toEpochMilli());
       
   180         }
   111         sb.append("</date>\n");
   181         sb.append("</date>\n");
   112 
   182 
   113         sb.append("  <millis>");
   183         sb.append("  <millis>");
   114         sb.append(record.getMillis());
   184         sb.append(instant.toEpochMilli());
   115         sb.append("</millis>\n");
   185         sb.append("</millis>\n");
       
   186 
       
   187         final int nanoAdjustment = instant.getNano() % 1000_000;
       
   188         if (useInstant && nanoAdjustment != 0) {
       
   189             sb.append("  <nanos>");
       
   190             sb.append(nanoAdjustment);
       
   191             sb.append("</nanos>\n");
       
   192         }
   116 
   193 
   117         sb.append("  <sequence>");
   194         sb.append("  <sequence>");
   118         sb.append(record.getSequenceNumber());
   195         sb.append(record.getSequenceNumber());
   119         sb.append("</sequence>\n");
   196         sb.append("</sequence>\n");
   120 
   197 
   221      * Return the header string for a set of XML formatted records.
   298      * Return the header string for a set of XML formatted records.
   222      *
   299      *
   223      * @param   h  The target handler (can be null)
   300      * @param   h  The target handler (can be null)
   224      * @return  a valid XML string
   301      * @return  a valid XML string
   225      */
   302      */
       
   303     @Override
   226     public String getHead(Handler h) {
   304     public String getHead(Handler h) {
   227         StringBuilder sb = new StringBuilder();
   305         StringBuilder sb = new StringBuilder();
   228         String encoding;
   306         String encoding;
   229         sb.append("<?xml version=\"1.0\"");
   307         sb.append("<?xml version=\"1.0\"");
   230 
   308 
   249 
   327 
   250         sb.append(" encoding=\"");
   328         sb.append(" encoding=\"");
   251         sb.append(encoding);
   329         sb.append(encoding);
   252         sb.append("\"");
   330         sb.append("\"");
   253         sb.append(" standalone=\"no\"?>\n");
   331         sb.append(" standalone=\"no\"?>\n");
       
   332 
   254         sb.append("<!DOCTYPE log SYSTEM \"logger.dtd\">\n");
   333         sb.append("<!DOCTYPE log SYSTEM \"logger.dtd\">\n");
   255         sb.append("<log>\n");
   334         sb.append("<log>\n");
   256         return sb.toString();
   335         return sb.toString();
   257     }
   336     }
   258 
   337 
   260      * Return the tail string for a set of XML formatted records.
   339      * Return the tail string for a set of XML formatted records.
   261      *
   340      *
   262      * @param   h  The target handler (can be null)
   341      * @param   h  The target handler (can be null)
   263      * @return  a valid XML string
   342      * @return  a valid XML string
   264      */
   343      */
       
   344     @Override
   265     public String getTail(Handler h) {
   345     public String getTail(Handler h) {
   266         return "</log>\n";
   346         return "</log>\n";
   267     }
   347     }
   268 }
   348 }