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 |