New upstream version 2.1.4
Markus Koschany
5 years ago
27 | 27 | <groupId>org.jboss.logmanager</groupId> |
28 | 28 | <artifactId>jboss-logmanager</artifactId> |
29 | 29 | <packaging>jar</packaging> |
30 | <version>2.1.2.Final</version> | |
30 | <version>2.1.4.Final</version> | |
31 | 31 | |
32 | 32 | <parent> |
33 | 33 | <groupId>org.jboss</groupId> |
46 | 46 | <properties> |
47 | 47 | <!-- Dependency versions --> |
48 | 48 | <version.javax.json>1.0</version.javax.json> |
49 | <version.org.byteman>3.0.10</version.org.byteman> | |
49 | <version.org.byteman>4.0.3</version.org.byteman> | |
50 | 50 | <version.org.glassfish.javax.json>1.0.4</version.org.glassfish.javax.json> |
51 | <version.org.jboss.modules.jboss-modules>1.7.0.Beta3</version.org.jboss.modules.jboss-modules> | |
51 | <version.org.jboss.modules.jboss-modules>1.7.0.Final</version.org.jboss.modules.jboss-modules> | |
52 | 52 | <version.org.wildfly.common.wildfly-common>1.2.0.Final</version.org.wildfly.common.wildfly-common> |
53 | 53 | <version.junit.junit>4.12</version.junit.junit> |
54 | 54 |
20 | 20 | |
21 | 21 | import java.lang.ref.WeakReference; |
22 | 22 | import java.security.Permission; |
23 | import java.util.Collection; | |
23 | 24 | import java.util.Enumeration; |
24 | 25 | import java.util.HashMap; |
25 | 26 | import java.util.Iterator; |
27 | import java.util.LinkedHashSet; | |
26 | 28 | import java.util.Map; |
27 | 29 | import java.util.Map.Entry; |
28 | 30 | import java.util.NoSuchElementException; |
31 | import java.util.Set; | |
29 | 32 | import java.util.concurrent.ConcurrentMap; |
30 | 33 | import java.util.concurrent.ConcurrentSkipListMap; |
31 | 34 | import java.util.concurrent.atomic.AtomicInteger; |
32 | 35 | import java.util.concurrent.atomic.AtomicReference; |
33 | 36 | import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; |
34 | ||
35 | 37 | import java.util.logging.Level; |
36 | 38 | import java.util.logging.LoggingMXBean; |
37 | 39 | import java.util.logging.LoggingPermission; |
39 | 41 | /** |
40 | 42 | * A logging context, for producing isolated logging environments. |
41 | 43 | */ |
42 | public final class LogContext implements Protectable { | |
44 | @SuppressWarnings("unused") | |
45 | public final class LogContext implements Protectable, AutoCloseable { | |
43 | 46 | private static final LogContext SYSTEM_CONTEXT = new LogContext(false); |
44 | 47 | |
45 | 48 | static final Permission CREATE_CONTEXT_PERMISSION = new RuntimePermission("createLogContext", null); |
97 | 100 | } |
98 | 101 | |
99 | 102 | private final AtomicReference<Map<String, LevelRef>> levelMapReference; |
103 | // Guarded by treeLock | |
104 | private final Set<AutoCloseable> closeHandlers; | |
100 | 105 | |
101 | 106 | /** |
102 | 107 | * This lock is taken any time a change is made which affects multiple nodes in the hierarchy. |
108 | 113 | levelMapReference = new AtomicReference<Map<String, LevelRef>>(LazyHolder.INITIAL_LEVEL_MAP); |
109 | 114 | rootLogger = new LoggerNode(this); |
110 | 115 | loggerNames = new ConcurrentSkipListMap<String, AtomicInteger>(); |
116 | closeHandlers = new LinkedHashSet<>(); | |
111 | 117 | } |
112 | 118 | |
113 | 119 | /** |
337 | 343 | @Override |
338 | 344 | public void disableAccess() { |
339 | 345 | granted.remove(); |
346 | } | |
347 | ||
348 | @Override | |
349 | public void close() throws Exception { | |
350 | synchronized (treeLock) { | |
351 | // First we want to close all loggers | |
352 | recursivelyClose(rootLogger); | |
353 | // Next process the close handlers associated with this log context | |
354 | for (AutoCloseable handler : closeHandlers) { | |
355 | handler.close(); | |
356 | } | |
357 | // Finally clear any logger names | |
358 | loggerNames.clear(); | |
359 | } | |
340 | 360 | } |
341 | 361 | |
342 | 362 | /** |
382 | 402 | }; |
383 | 403 | } |
384 | 404 | |
405 | /** | |
406 | * Adds a handler invoked during the {@linkplain #close() close} of this log context. The close handlers will be | |
407 | * invoked in the order they are added. | |
408 | * <p> | |
409 | * The loggers associated with this context will always be closed. | |
410 | * </p> | |
411 | * | |
412 | * @param closeHandler the close handler to use | |
413 | */ | |
414 | public void addCloseHandler(final AutoCloseable closeHandler) { | |
415 | synchronized (treeLock) { | |
416 | closeHandlers.add(closeHandler); | |
417 | } | |
418 | } | |
419 | ||
420 | /** | |
421 | * Gets the current close handlers associated with this log context. | |
422 | * | |
423 | * @return the current close handlers | |
424 | */ | |
425 | public Set<AutoCloseable> getCloseHandlers() { | |
426 | synchronized (treeLock) { | |
427 | return new LinkedHashSet<>(closeHandlers); | |
428 | } | |
429 | } | |
430 | ||
431 | /** | |
432 | * Clears any current close handlers associated with log context, then adds the handlers to be invoked during | |
433 | * the {@linkplain #close() close} of this log context. The close handlers will be invoked in the order they are | |
434 | * added. | |
435 | * <p> | |
436 | * The loggers associated with this context will always be closed. | |
437 | * </p> | |
438 | * | |
439 | * @param closeHandlers the close handlers to use | |
440 | */ | |
441 | public void setCloseHandlers(final Collection<AutoCloseable> closeHandlers) { | |
442 | synchronized (treeLock) { | |
443 | this.closeHandlers.clear(); | |
444 | this.closeHandlers.addAll(closeHandlers); | |
445 | } | |
446 | } | |
447 | ||
385 | 448 | protected void incrementRef(final String name) { |
386 | 449 | AtomicInteger counter = loggerNames.get(name); |
387 | 450 | if (counter == null) { |
425 | 488 | return strong ? new CopyOnWriteMap<String, LoggerNode>() : new CopyOnWriteWeakMap<String, LoggerNode>(); |
426 | 489 | } |
427 | 490 | |
491 | private void recursivelyClose(final LoggerNode loggerNode) { | |
492 | synchronized (treeLock) { | |
493 | for (LoggerNode child : loggerNode.getChildren()) { | |
494 | recursivelyClose(child); | |
495 | } | |
496 | loggerNode.close(); | |
497 | } | |
498 | } | |
499 | ||
428 | 500 | private interface LevelRef { |
429 | 501 | Level get(); |
430 | 502 | } |
23 | 23 | import java.util.Collection; |
24 | 24 | import java.util.Collections; |
25 | 25 | import java.util.HashMap; |
26 | import java.util.Iterator; | |
27 | 26 | import java.util.Map; |
28 | 27 | import java.util.concurrent.ConcurrentMap; |
29 | 28 | import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; |
34 | 33 | /** |
35 | 34 | * A node in the tree of logger names. Maintains weak references to children and a strong reference to its parent. |
36 | 35 | */ |
37 | final class LoggerNode { | |
36 | final class LoggerNode implements AutoCloseable { | |
38 | 37 | |
39 | 38 | /** |
40 | 39 | * The log context. |
141 | 140 | this.context = context; |
142 | 141 | effectiveLevel = parent.effectiveLevel; |
143 | 142 | children = context.createChildMap(); |
143 | } | |
144 | ||
145 | @Override | |
146 | public void close() { | |
147 | synchronized (context.treeLock) { | |
148 | // Reset everything to defaults | |
149 | filter = null; | |
150 | if ("".equals(fullName)) { | |
151 | level = Level.INFO; | |
152 | effectiveLevel = Level.INFO.intValue(); | |
153 | } else { | |
154 | level = null; | |
155 | effectiveLevel = Level.INFO.intValue(); | |
156 | } | |
157 | handlersUpdater.clear(this); | |
158 | useParentFilter = false; | |
159 | useParentHandlers = true; | |
160 | attachmentsUpdater.get(this).clear(); | |
161 | children.clear(); | |
162 | } | |
144 | 163 | } |
145 | 164 | |
146 | 165 | /** |
379 | 398 | V old; |
380 | 399 | do { |
381 | 400 | oldAttachments = attachments; |
382 | if (oldAttachments.isEmpty() || oldAttachments.size() == 1 && oldAttachments.containsKey(key)) { | |
383 | old = (V) oldAttachments.get(key); | |
384 | newAttachments = Collections.<Logger.AttachmentKey, Object>singletonMap(key, value); | |
385 | } else { | |
386 | newAttachments = new HashMap<Logger.AttachmentKey, Object>(oldAttachments); | |
387 | old = (V) newAttachments.put(key, value); | |
388 | } | |
401 | newAttachments = new HashMap<>(oldAttachments); | |
402 | old = (V) newAttachments.put(key, value); | |
389 | 403 | } while (! attachmentsUpdater.compareAndSet(this, oldAttachments, newAttachments)); |
390 | 404 | return old; |
391 | 405 | } |
402 | 416 | Map<Logger.AttachmentKey, Object> newAttachments; |
403 | 417 | do { |
404 | 418 | oldAttachments = attachments; |
405 | if (oldAttachments.isEmpty()) { | |
406 | newAttachments = Collections.<Logger.AttachmentKey, Object>singletonMap(key, value); | |
407 | } else { | |
408 | if (oldAttachments.containsKey(key)) { | |
409 | return (V) oldAttachments.get(key); | |
410 | } | |
411 | newAttachments = new HashMap<Logger.AttachmentKey, Object>(oldAttachments); | |
412 | newAttachments.put(key, value); | |
413 | } | |
419 | if (oldAttachments.containsKey(key)) { | |
420 | return (V) oldAttachments.get(key); | |
421 | } | |
422 | newAttachments = new HashMap<>(oldAttachments); | |
423 | newAttachments.put(key, value); | |
414 | 424 | } while (! attachmentsUpdater.compareAndSet(this, oldAttachments, newAttachments)); |
415 | 425 | return null; |
416 | 426 | } |
433 | 443 | if (size == 1) { |
434 | 444 | // special case - the new map is empty |
435 | 445 | newAttachments = Collections.emptyMap(); |
436 | } else if (size == 2) { | |
437 | // special case - the new map is a singleton | |
438 | final Iterator<Map.Entry<Logger.AttachmentKey,Object>> it = oldAttachments.entrySet().iterator(); | |
439 | // find the entry that we are not removing | |
440 | Map.Entry<Logger.AttachmentKey, Object> entry = it.next(); | |
441 | if (entry.getKey() == key) { | |
442 | // must be the next one | |
443 | entry = it.next(); | |
444 | } | |
445 | newAttachments = Collections.singletonMap(entry.getKey(), entry.getValue()); | |
446 | 446 | } else { |
447 | 447 | newAttachments = new HashMap<Logger.AttachmentKey, Object>(oldAttachments); |
448 | 448 | } |
84 | 84 | |
85 | 85 | LogContextConfigurationImpl(final LogContext logContext) { |
86 | 86 | this.logContext = logContext; |
87 | logContext.addCloseHandler(new LogContextConfigurationCloseHandler()); | |
87 | 88 | } |
88 | 89 | |
89 | 90 | public LogContext getLogContext() { |
737 | 738 | ObjectProducer resolveFilter(String expression) { |
738 | 739 | return resolveFilter(expression, false); |
739 | 740 | } |
741 | ||
742 | private class LogContextConfigurationCloseHandler implements AutoCloseable { | |
743 | ||
744 | @Override | |
745 | public void close() { | |
746 | final LogContextConfigurationImpl configuration = LogContextConfigurationImpl.this; | |
747 | // Remove all the loggers first | |
748 | for (String name : configuration.getLoggerNames()) { | |
749 | configuration.removeLoggerConfiguration(name); | |
750 | } | |
751 | ||
752 | // Remove all handlers next | |
753 | for (String name : configuration.getHandlerNames()) { | |
754 | configuration.removeHandlerConfiguration(name); | |
755 | } | |
756 | ||
757 | // Remove all filters | |
758 | for (String name : configuration.getFilterNames()) { | |
759 | configuration.removeFilterConfiguration(name); | |
760 | } | |
761 | ||
762 | // Remove all formatters | |
763 | for (String name : configuration.getFormatterNames()) { | |
764 | configuration.removeFormatterConfiguration(name); | |
765 | } | |
766 | ||
767 | // Remove all error managers | |
768 | for (String name : configuration.getErrorManagerNames()) { | |
769 | configuration.removeErrorManagerConfiguration(name); | |
770 | } | |
771 | ||
772 | // Finally remove all POJO's | |
773 | for (String name : configuration.getPojoNames()) { | |
774 | configuration.removePojoConfiguration(name); | |
775 | } | |
776 | ||
777 | configuration.commit(); | |
778 | } | |
779 | } | |
740 | 780 | } |
33 | 33 | import java.util.Locale; |
34 | 34 | import java.util.Map; |
35 | 35 | import java.util.TimeZone; |
36 | import java.util.TreeMap; | |
36 | 37 | import java.util.logging.Formatter; |
37 | 38 | import java.util.logging.Level; |
38 | 39 | import java.util.logging.LogRecord; |
1072 | 1073 | public static FormatStep mdcFormatStep(final String key, final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth) { |
1073 | 1074 | return new JustifyingFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth) { |
1074 | 1075 | public void renderRaw(final StringBuilder builder, final ExtLogRecord record) { |
1075 | final String value = record.getMdc(key); | |
1076 | if (value != null) { | |
1077 | builder.append(value); | |
1076 | if (key == null) { | |
1077 | builder.append(new TreeMap<>(record.getMdcCopy())); | |
1078 | } else { | |
1079 | final String value = record.getMdc(key); | |
1080 | if (value != null) { | |
1081 | builder.append(value); | |
1082 | } | |
1078 | 1083 | } |
1079 | 1084 | } |
1080 | 1085 | }; |
0 | /* | |
1 | * JBoss, Home of Professional Open Source. | |
2 | * | |
3 | * Copyright 2018 Red Hat, Inc., and individual contributors | |
4 | * as indicated by the @author tags. | |
5 | * | |
6 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
7 | * you may not use this file except in compliance with the License. | |
8 | * You may obtain a copy of the License at | |
9 | * | |
10 | * http://www.apache.org/licenses/LICENSE-2.0 | |
11 | * | |
12 | * Unless required by applicable law or agreed to in writing, software | |
13 | * distributed under the License is distributed on an "AS IS" BASIS, | |
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 | * See the License for the specific language governing permissions and | |
16 | * limitations under the License. | |
17 | */ | |
18 | ||
19 | package org.jboss.logmanager.handlers; | |
20 | ||
21 | import java.io.IOException; | |
22 | import java.net.DatagramSocket; | |
23 | import java.net.InetAddress; | |
24 | import java.net.InetSocketAddress; | |
25 | import java.net.Socket; | |
26 | import java.net.SocketAddress; | |
27 | import java.net.SocketException; | |
28 | import javax.net.SocketFactory; | |
29 | ||
30 | /** | |
31 | * A factory used to create writable sockets. | |
32 | * | |
33 | * @author <a href="mailto:jperkins@redhat.com">James R. Perkins</a> | |
34 | */ | |
35 | public interface ClientSocketFactory { | |
36 | ||
37 | /** | |
38 | * Creates a datagram socket for UDP communication. | |
39 | * | |
40 | * @return the newly created socket | |
41 | * | |
42 | * @throws SocketException if binding the socket fails | |
43 | */ | |
44 | DatagramSocket createDatagramSocket() throws SocketException; | |
45 | ||
46 | /** | |
47 | * Creates a TCP socket. | |
48 | * | |
49 | * @return the newly created socket | |
50 | * | |
51 | * @throws IOException if an error occurs creating the socket | |
52 | */ | |
53 | Socket createSocket() throws IOException; | |
54 | ||
55 | /** | |
56 | * Returns the address being used to create sockets. | |
57 | * | |
58 | * @return the address being used | |
59 | */ | |
60 | InetAddress getAddress(); | |
61 | ||
62 | /** | |
63 | * Returns the port being used to create sockets. | |
64 | * | |
65 | * @return the port being used | |
66 | */ | |
67 | int getPort(); | |
68 | ||
69 | /** | |
70 | * A convenience method to return the socket address. | |
71 | * <p> | |
72 | * The default implementation simply returns {@code new InetSocketAddress(getAddress(), getPort())}. | |
73 | * </p> | |
74 | * | |
75 | * @return a socket address | |
76 | */ | |
77 | default SocketAddress getSocketAddress() { | |
78 | return new InetSocketAddress(getAddress(), getPort()); | |
79 | } | |
80 | ||
81 | /** | |
82 | * Creates a new default implementation of the factory which uses {@link SocketFactory#getDefault()} for TCP | |
83 | * sockets and {@code new DatagramSocket()} for UDP sockets. | |
84 | * | |
85 | * @param address the address to bind to | |
86 | * @param port the port to bind to | |
87 | * | |
88 | * @return the client socket factory | |
89 | */ | |
90 | static ClientSocketFactory of(final InetAddress address, final int port) { | |
91 | return of(SocketFactory.getDefault(), address, port); | |
92 | } | |
93 | ||
94 | /** | |
95 | * Creates a new default implementation of the factory which uses the provided | |
96 | * {@linkplain SocketFactory#createSocket(InetAddress, int) socket factory} to create TCP connections and | |
97 | * {@code new DatagramSocket()} for UDP sockets. | |
98 | * | |
99 | * @param socketFactory the socket factory used for TCP connections, if {@code null} the | |
100 | * {@linkplain SocketFactory#getDefault() default} socket factory will be used | |
101 | * @param address the address to bind to | |
102 | * @param port the port to bind to | |
103 | * | |
104 | * @return the client socket factory | |
105 | */ | |
106 | static ClientSocketFactory of(final SocketFactory socketFactory, final InetAddress address, final int port) { | |
107 | if (address == null || port < 0) { | |
108 | throw new IllegalArgumentException(String.format("The address cannot be null (%s) and the port must be a positive integer (%d)", address, port)); | |
109 | } | |
110 | final SocketFactory factory = (socketFactory == null ? SocketFactory.getDefault() : socketFactory); | |
111 | return new ClientSocketFactory() { | |
112 | @Override | |
113 | public DatagramSocket createDatagramSocket() throws SocketException { | |
114 | return new DatagramSocket(); | |
115 | } | |
116 | ||
117 | @Override | |
118 | public Socket createSocket() throws IOException { | |
119 | return factory.createSocket(address, port); | |
120 | } | |
121 | ||
122 | @Override | |
123 | public InetAddress getAddress() { | |
124 | return address; | |
125 | } | |
126 | ||
127 | @Override | |
128 | public int getPort() { | |
129 | return port; | |
130 | } | |
131 | }; | |
132 | } | |
133 | } |
67 | 67 | private final Object outputLock = new Object(); |
68 | 68 | |
69 | 69 | // All the following fields are guarded by outputLock |
70 | private ClientSocketFactory clientSocketFactory; | |
70 | 71 | private SocketFactory socketFactory; |
71 | 72 | private InetAddress address; |
72 | 73 | private int port; |
142 | 143 | * @param port the port to connect to |
143 | 144 | * |
144 | 145 | * @throws UnknownHostException if an error occurs resolving the hostname |
146 | * @see #SocketHandler(ClientSocketFactory, Protocol) | |
145 | 147 | */ |
146 | 148 | public SocketHandler(final SocketFactory socketFactory, final Protocol protocol, final String hostname, final int port) throws UnknownHostException { |
147 | 149 | this(socketFactory, protocol, InetAddress.getByName(hostname), port); |
156 | 158 | * @param protocol the protocol to connect with |
157 | 159 | * @param address the address to connect to |
158 | 160 | * @param port the port to connect to |
161 | * | |
162 | * @see #SocketHandler(ClientSocketFactory, Protocol) | |
159 | 163 | */ |
160 | 164 | public SocketHandler(final SocketFactory socketFactory, final Protocol protocol, final InetAddress address, final int port) { |
165 | this.socketFactory = socketFactory; | |
166 | this.clientSocketFactory = null; | |
161 | 167 | this.address = address; |
162 | 168 | this.port = port; |
163 | this.protocol = protocol; | |
169 | this.protocol = (protocol == null ? Protocol.TCP : protocol); | |
164 | 170 | initialize = true; |
165 | 171 | writer = null; |
166 | this.socketFactory = socketFactory; | |
172 | blockOnReconnect = false; | |
173 | } | |
174 | ||
175 | /** | |
176 | * Creates a socket handler. | |
177 | * | |
178 | * @param clientSocketFactory the client socket factory used to create sockets | |
179 | * @param protocol the protocol to connect with | |
180 | */ | |
181 | public SocketHandler(final ClientSocketFactory clientSocketFactory, final Protocol protocol) { | |
182 | this.clientSocketFactory = clientSocketFactory; | |
183 | if (clientSocketFactory != null) { | |
184 | address = clientSocketFactory.getAddress(); | |
185 | port = clientSocketFactory.getPort(); | |
186 | } | |
187 | this.protocol = (protocol == null ? Protocol.TCP : protocol); | |
188 | initialize = true; | |
189 | writer = null; | |
167 | 190 | blockOnReconnect = false; |
168 | 191 | } |
169 | 192 | |
228 | 251 | |
229 | 252 | /** |
230 | 253 | * Sets the address to connect to. |
254 | * <p> | |
255 | * Note that is resets the {@linkplain #setClientSocketFactory(ClientSocketFactory) client socket factory}. | |
256 | * </p> | |
231 | 257 | * |
232 | 258 | * @param address the address |
233 | 259 | */ |
234 | 260 | public void setAddress(final InetAddress address) { |
235 | 261 | checkAccess(this); |
236 | 262 | synchronized (outputLock) { |
263 | if (!this.address.equals(address)) { | |
264 | initialize = true; | |
265 | clientSocketFactory = null; | |
266 | } | |
237 | 267 | this.address = address; |
238 | initialize = true; | |
239 | 268 | } |
240 | 269 | } |
241 | 270 | |
242 | 271 | /** |
243 | 272 | * Sets the address to connect to by doing a lookup on the hostname. |
273 | * <p> | |
274 | * Note that is resets the {@linkplain #setClientSocketFactory(ClientSocketFactory) client socket factory}. | |
275 | * </p> | |
244 | 276 | * |
245 | 277 | * @param hostname the host name used to resolve the address |
246 | 278 | * |
276 | 308 | checkAccess(this); |
277 | 309 | synchronized (outputLock) { |
278 | 310 | this.blockOnReconnect = blockOnReconnect; |
311 | initialize = true; | |
279 | 312 | } |
280 | 313 | } |
281 | 314 | |
292 | 325 | * Sets the protocol to use. If the value is {@code null} the protocol will be set to |
293 | 326 | * {@linkplain Protocol#TCP TCP}. |
294 | 327 | * <p> |
295 | * Note that is resets the {@linkplain #setSocketFactory(SocketFactory) socket factory}. | |
328 | * Note that is resets the {@linkplain #setSocketFactory(SocketFactory) socket factory} if it was previously set. | |
296 | 329 | * </p> |
297 | 330 | * |
298 | 331 | * @param protocol the protocol to use |
303 | 336 | if (protocol == null) { |
304 | 337 | this.protocol = Protocol.TCP; |
305 | 338 | } |
306 | // Reset the socket factory | |
307 | socketFactory = null; | |
339 | if (this.protocol != protocol) { | |
340 | socketFactory = null; | |
341 | initialize = true; | |
342 | } | |
308 | 343 | this.protocol = protocol; |
309 | initialize = true; | |
310 | 344 | } |
311 | 345 | } |
312 | 346 | |
321 | 355 | |
322 | 356 | /** |
323 | 357 | * Sets the port to connect to. |
358 | * <p> | |
359 | * Note that is resets the {@linkplain #setClientSocketFactory(ClientSocketFactory) client socket factory}. | |
360 | * </p> | |
324 | 361 | * |
325 | 362 | * @param port the port |
326 | 363 | */ |
327 | 364 | public void setPort(final int port) { |
328 | 365 | checkAccess(this); |
329 | 366 | synchronized (outputLock) { |
367 | if (this.port != port) { | |
368 | initialize = true; | |
369 | clientSocketFactory = null; | |
370 | } | |
330 | 371 | this.port = port; |
331 | initialize = true; | |
332 | 372 | } |
333 | 373 | } |
334 | 374 | |
337 | 377 | * connections. |
338 | 378 | * <p> |
339 | 379 | * Note that if the {@linkplain #setProtocol(Protocol) protocol} is set the socket factory will be set to |
340 | * {@code null} and reset. | |
380 | * {@code null} and reset. Setting a value here also resets the | |
381 | * {@linkplain #setClientSocketFactory(ClientSocketFactory) client socket factory}. | |
341 | 382 | * </p> |
342 | 383 | * |
343 | 384 | * @param socketFactory the socket factory |
385 | * | |
386 | * @see #setClientSocketFactory(ClientSocketFactory) | |
344 | 387 | */ |
345 | 388 | public void setSocketFactory(final SocketFactory socketFactory) { |
346 | 389 | checkAccess(this); |
347 | 390 | synchronized (outputLock) { |
348 | 391 | this.socketFactory = socketFactory; |
392 | this.clientSocketFactory = null; | |
393 | initialize = true; | |
394 | } | |
395 | } | |
396 | ||
397 | /** | |
398 | * Sets the client socket factory used to create sockets. If {@code null} the | |
399 | * {@linkplain #setAddress(InetAddress) address} and {@linkplain #setPort(int) port} are required to be set. | |
400 | * | |
401 | * @param clientSocketFactory the client socket factory to use | |
402 | */ | |
403 | public void setClientSocketFactory(final ClientSocketFactory clientSocketFactory) { | |
404 | checkAccess(this); | |
405 | synchronized (outputLock) { | |
406 | this.clientSocketFactory = clientSocketFactory; | |
349 | 407 | initialize = true; |
350 | 408 | } |
351 | 409 | } |
387 | 445 | private OutputStream createOutputStream() { |
388 | 446 | if (address != null || port >= 0) { |
389 | 447 | try { |
448 | final ClientSocketFactory socketFactory = getClientSocketFactory(); | |
390 | 449 | if (protocol == Protocol.UDP) { |
391 | return new UdpOutputStream(address, port); | |
450 | return new UdpOutputStream(socketFactory); | |
392 | 451 | } |
393 | SocketFactory socketFactory = this.socketFactory; | |
394 | if (socketFactory == null) { | |
395 | if (protocol == Protocol.SSL_TCP) { | |
396 | this.socketFactory = socketFactory = SSLSocketFactory.getDefault(); | |
397 | } else { | |
398 | // Assume we want a TCP connection | |
399 | this.socketFactory = socketFactory = SocketFactory.getDefault(); | |
400 | } | |
401 | } | |
402 | return new TcpOutputStream(socketFactory, address, port, blockOnReconnect); | |
452 | return new TcpOutputStream(socketFactory, blockOnReconnect); | |
403 | 453 | } catch (IOException e) { |
404 | 454 | reportError("Failed to create socket output stream", e, ErrorManager.OPEN_FAILURE); |
405 | 455 | } |
406 | 456 | } |
407 | 457 | return null; |
458 | } | |
459 | ||
460 | private ClientSocketFactory getClientSocketFactory() { | |
461 | synchronized (outputLock) { | |
462 | if (clientSocketFactory != null) { | |
463 | return clientSocketFactory; | |
464 | } | |
465 | if (address == null || port <= 0) { | |
466 | throw new IllegalStateException("An address and port greater than 0 is required."); | |
467 | } | |
468 | final ClientSocketFactory clientSocketFactory; | |
469 | if (socketFactory == null) { | |
470 | if (protocol == Protocol.SSL_TCP) { | |
471 | clientSocketFactory = ClientSocketFactory.of(SSLSocketFactory.getDefault(), address, port); | |
472 | } else { | |
473 | clientSocketFactory = ClientSocketFactory.of(address, port); | |
474 | } | |
475 | } else { | |
476 | clientSocketFactory = ClientSocketFactory.of(socketFactory, address, port); | |
477 | } | |
478 | return clientSocketFactory; | |
479 | } | |
408 | 480 | } |
409 | 481 | |
410 | 482 | private void writeHead(final Writer writer) { |
34 | 34 | import java.util.logging.Formatter; |
35 | 35 | import java.util.logging.Level; |
36 | 36 | import java.util.regex.Pattern; |
37 | import javax.net.SocketFactory; | |
38 | import javax.net.ssl.SSLSocketFactory; | |
37 | 39 | |
38 | 40 | import org.jboss.logmanager.ExtHandler; |
39 | 41 | import org.jboss.logmanager.ExtLogRecord; |
323 | 325 | private boolean truncate; |
324 | 326 | private int maxLen; |
325 | 327 | private boolean blockOnReconnect; |
328 | private ClientSocketFactory clientSocketFactory; | |
326 | 329 | |
327 | 330 | /** |
328 | 331 | * The default class constructor. |
667 | 670 | } |
668 | 671 | |
669 | 672 | /** |
673 | * Sets the client socket factory used to create sockets. | |
674 | * | |
675 | * @param clientSocketFactory the client socket factory to use | |
676 | */ | |
677 | public void setClientSocketFactory(final ClientSocketFactory clientSocketFactory) { | |
678 | checkAccess(this); | |
679 | synchronized (outputLock) { | |
680 | this.clientSocketFactory = clientSocketFactory; | |
681 | initializeConnection = true; | |
682 | } | |
683 | } | |
684 | ||
685 | /** | |
670 | 686 | * Checks whether or not characters below decimal 32, traditional US-ASCII control values expect {@code DEL}, are |
671 | 687 | * being escaped or not. |
672 | 688 | * |
1083 | 1099 | final OutputStream out; |
1084 | 1100 | // Check the sockets |
1085 | 1101 | try { |
1086 | if (protocol == Protocol.TCP) { | |
1087 | out = new TcpOutputStream(serverAddress, port, blockOnReconnect); | |
1088 | } else if (protocol == Protocol.UDP) { | |
1089 | out = new UdpOutputStream(serverAddress, port); | |
1090 | } else if (protocol == Protocol.SSL_TCP) { | |
1091 | out = new SslTcpOutputStream(serverAddress, port, blockOnReconnect); | |
1102 | final ClientSocketFactory clientSocketFactory = getClientSocketFactory(); | |
1103 | if (protocol == Protocol.UDP) { | |
1104 | out = new UdpOutputStream(clientSocketFactory); | |
1092 | 1105 | } else { |
1093 | throw new IllegalStateException("Invalid protocol: " + protocol); | |
1106 | out = new TcpOutputStream(clientSocketFactory, blockOnReconnect); | |
1094 | 1107 | } |
1095 | 1108 | setOutputStream(out, false); |
1096 | 1109 | } catch (IOException e) { |
1295 | 1308 | return buffer.toArray(); |
1296 | 1309 | } |
1297 | 1310 | |
1311 | private ClientSocketFactory getClientSocketFactory() { | |
1312 | synchronized (outputLock) { | |
1313 | if (clientSocketFactory != null) { | |
1314 | return clientSocketFactory; | |
1315 | } | |
1316 | final SocketFactory socketFactory = (protocol == Protocol.SSL_TCP ? SSLSocketFactory.getDefault() : SocketFactory.getDefault()); | |
1317 | return ClientSocketFactory.of(socketFactory, serverAddress, port); | |
1318 | } | |
1319 | } | |
1320 | ||
1298 | 1321 | private static String checkPrintableAscii(final String name, final String value) { |
1299 | 1322 | if (value != null && PRINTABLE_ASCII_PATTERN.matcher(value).find()) { |
1300 | 1323 | final String upper = Character.toUpperCase(name.charAt(0)) + name.substring(1); |
53 | 53 | |
54 | 54 | protected final Object outputLock = new Object(); |
55 | 55 | |
56 | private final SocketFactory socketFactory; | |
57 | private final InetAddress address; | |
58 | private final int port; | |
56 | private final ClientSocketFactory socketFactory; | |
59 | 57 | private final Deque<Exception> errors = new ArrayDeque<Exception>(maxErrors); |
60 | 58 | |
61 | 59 | // Guarded by outputLock |
107 | 105 | * |
108 | 106 | * @param socket the socket used to write the output to |
109 | 107 | * |
110 | * @deprecated Use {@link #TcpOutputStream(javax.net.SocketFactory, java.net.InetAddress, int)} | |
108 | * @deprecated Use {@link #TcpOutputStream(ClientSocketFactory, boolean)} | |
111 | 109 | */ |
112 | 110 | @Deprecated |
113 | 111 | protected TcpOutputStream(final Socket socket) { |
114 | 112 | this.socketFactory = null; |
115 | this.address = null; | |
116 | this.port = -1; | |
117 | 113 | this.socket = socket; |
118 | 114 | reconnectThread = null; |
119 | 115 | connected = true; |
151 | 147 | * a reconnect will be attempted on the next write. |
152 | 148 | */ |
153 | 149 | protected TcpOutputStream(final SocketFactory socketFactory, final InetAddress address, final int port, final boolean blockOnReconnect) throws IOException { |
150 | this(ClientSocketFactory.of(socketFactory, address, port), blockOnReconnect); | |
151 | } | |
152 | ||
153 | /** | |
154 | * Creates a new TCP stream which uses the {@link ClientSocketFactory#createSocket()} to create the socket. | |
155 | * | |
156 | * @param socketFactory the socket factory used to create TCP sockets | |
157 | * @param blockOnReconnect {@code true} to block when attempting to reconnect the socket or {@code false} to | |
158 | * reconnect asynchronously | |
159 | */ | |
160 | public TcpOutputStream(final ClientSocketFactory socketFactory, final boolean blockOnReconnect) { | |
154 | 161 | this.socketFactory = socketFactory; |
155 | this.address = address; | |
156 | this.port = port; | |
157 | 162 | this.blockOnReconnect = blockOnReconnect; |
158 | 163 | try { |
159 | socket = socketFactory.createSocket(address, port); | |
164 | socket = this.socketFactory.createSocket(); | |
160 | 165 | connected = true; |
161 | 166 | } catch (IOException e) { |
162 | 167 | connected = false; |
165 | 170 | |
166 | 171 | @Override |
167 | 172 | public void write(final int b) throws IOException { |
168 | write(new byte[]{(byte) b}, 0, 1); | |
173 | write(new byte[] {(byte) b}, 0, 1); | |
169 | 174 | } |
170 | 175 | |
171 | 176 | @Override |
207 | 212 | public void flush() throws IOException { |
208 | 213 | synchronized (outputLock) { |
209 | 214 | try { |
210 | socket.getOutputStream().flush(); | |
215 | if (socket != null) { | |
216 | socket.getOutputStream().flush(); | |
217 | } | |
211 | 218 | } catch (SocketException e) { |
212 | 219 | // This should likely never be hit, but should attempt to reconnect if it does happen |
213 | 220 | if (isReconnectAllowed()) { |
229 | 236 | if (reconnectThread != null) { |
230 | 237 | reconnectThread.interrupt(); |
231 | 238 | } |
232 | socket.close(); | |
239 | if (socket != null) { | |
240 | socket.close(); | |
241 | } | |
233 | 242 | } |
234 | 243 | } |
235 | 244 | |
344 | 353 | while (socketFactory != null && !connected) { |
345 | 354 | Socket socket = null; |
346 | 355 | try { |
347 | socket = socketFactory.createSocket(address, port); | |
356 | socket = socketFactory.createSocket(); | |
348 | 357 | synchronized (outputLock) { |
349 | 358 | // Unlikely but if we've been interrupted due to a close, we should shutdown |
350 | 359 | if (Thread.currentThread().isInterrupted()) { |
23 | 23 | import java.net.DatagramPacket; |
24 | 24 | import java.net.DatagramSocket; |
25 | 25 | import java.net.InetAddress; |
26 | import java.net.SocketAddress; | |
27 | import java.net.SocketException; | |
26 | 28 | |
27 | 29 | /** |
28 | 30 | * An output stream that writes data to a {@link java.net.DatagramSocket DatagramSocket}. |
29 | 31 | * |
30 | 32 | * @author <a href="mailto:jperkins@redhat.com">James R. Perkins</a> |
31 | 33 | */ |
34 | @SuppressWarnings("WeakerAccess") | |
32 | 35 | public class UdpOutputStream extends OutputStream implements FlushableCloseable { |
33 | 36 | private final DatagramSocket socket; |
37 | private final SocketAddress socketAddress; | |
34 | 38 | |
35 | 39 | public UdpOutputStream(final InetAddress address, final int port) throws IOException { |
36 | socket = new DatagramSocket(); | |
37 | socket.connect(address, port); | |
40 | this(ClientSocketFactory.of(address, port)); | |
41 | } | |
42 | ||
43 | public UdpOutputStream(final ClientSocketFactory socketManager) throws SocketException { | |
44 | socket = socketManager.createDatagramSocket(); | |
45 | socketAddress = socketManager.getSocketAddress(); | |
38 | 46 | } |
39 | 47 | |
40 | 48 | @Override |
41 | 49 | public void write(final int b) throws IOException { |
42 | 50 | final byte[] msg = new byte[] {(byte) b}; |
43 | final DatagramPacket packet = new DatagramPacket(msg, 1); | |
51 | final DatagramPacket packet = new DatagramPacket(msg, 1, socketAddress); | |
44 | 52 | socket.send(packet); |
45 | 53 | } |
46 | 54 | |
47 | 55 | @Override |
48 | 56 | public void write(final byte[] b) throws IOException { |
49 | 57 | if (b != null) { |
50 | final DatagramPacket packet = new DatagramPacket(b, b.length); | |
58 | final DatagramPacket packet = new DatagramPacket(b, b.length, socketAddress); | |
51 | 59 | socket.send(packet); |
52 | 60 | } |
53 | 61 | } |
55 | 63 | @Override |
56 | 64 | public void write(final byte[] b, final int off, final int len) throws IOException { |
57 | 65 | if (b != null) { |
58 | final DatagramPacket packet = new DatagramPacket(b, off, len); | |
66 | final DatagramPacket packet = new DatagramPacket(b, off, len, socketAddress); | |
59 | 67 | socket.send(packet); |
60 | 68 | } |
61 | 69 | } |
0 | /* | |
1 | * JBoss, Home of Professional Open Source. | |
2 | * | |
3 | * Copyright 2017 Red Hat, Inc., and individual contributors | |
4 | * as indicated by the @author tags. | |
5 | * | |
6 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
7 | * you may not use this file except in compliance with the License. | |
8 | * You may obtain a copy of the License at | |
9 | * | |
10 | * http://www.apache.org/licenses/LICENSE-2.0 | |
11 | * | |
12 | * Unless required by applicable law or agreed to in writing, software | |
13 | * distributed under the License is distributed on an "AS IS" BASIS, | |
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 | * See the License for the specific language governing permissions and | |
16 | * limitations under the License. | |
17 | */ | |
18 | ||
19 | package org.jboss.logmanager; | |
20 | ||
21 | import java.util.Arrays; | |
22 | import java.util.Collection; | |
23 | import java.util.Iterator; | |
24 | import java.util.UUID; | |
25 | import java.util.logging.ErrorManager; | |
26 | import java.util.logging.Filter; | |
27 | import java.util.logging.Formatter; | |
28 | import java.util.logging.Handler; | |
29 | import java.util.logging.Level; | |
30 | import java.util.logging.LogRecord; | |
31 | ||
32 | import org.jboss.logmanager.config.ErrorManagerConfiguration; | |
33 | import org.jboss.logmanager.config.FilterConfiguration; | |
34 | import org.jboss.logmanager.config.FormatterConfiguration; | |
35 | import org.jboss.logmanager.config.HandlerConfiguration; | |
36 | import org.jboss.logmanager.config.LogContextConfiguration; | |
37 | import org.jboss.logmanager.config.LoggerConfiguration; | |
38 | import org.jboss.logmanager.config.PojoConfiguration; | |
39 | import org.junit.Assert; | |
40 | import org.junit.Before; | |
41 | import org.junit.Test; | |
42 | ||
43 | /** | |
44 | * @author <a href="mailto:jperkins@redhat.com">James R. Perkins</a> | |
45 | */ | |
46 | public class LogContextCloseTests { | |
47 | ||
48 | @Before | |
49 | public void resetTestObjects() { | |
50 | TestErrorManager.POJO_OBJECT = null; | |
51 | TestFilter.POJO_OBJECT = null; | |
52 | TestFormatter.POJO_OBJECT = null; | |
53 | TestHandler.ERROR_MANAGER = null; | |
54 | TestHandler.FILTER = null; | |
55 | TestHandler.FORMATTER = null; | |
56 | TestHandler.HANDLERS = null; | |
57 | TestHandler.IS_CLOSED = false; | |
58 | TestHandler.POJO_OBJECT = null; | |
59 | } | |
60 | ||
61 | ||
62 | @Test | |
63 | public void testCloseLogContext() throws Exception { | |
64 | LogContext logContext = LogContext.create(); | |
65 | ||
66 | // Create a test handler to use | |
67 | final TestHandler handler = new TestHandler(); | |
68 | handler.setErrorManager(new TestErrorManager()); | |
69 | handler.setFilter(new TestFilter()); | |
70 | handler.setFormatter(new TestFormatter()); | |
71 | handler.setLevel(org.jboss.logmanager.Level.TRACE); | |
72 | ||
73 | final Logger rootLogger = logContext.getLogger(""); | |
74 | rootLogger.setLevel(org.jboss.logmanager.Level.WARN); | |
75 | final Logger testLogger = logContext.getLogger(LogContextCloseTests.class.getName()); | |
76 | testLogger.setLevel(Level.FINE); | |
77 | final Logger randomLogger = logContext.getLogger(UUID.randomUUID().toString()); | |
78 | randomLogger.setUseParentFilters(true); | |
79 | ||
80 | rootLogger.addHandler(handler); | |
81 | ||
82 | logContext.close(); | |
83 | ||
84 | // Loggers should have no handlers and have been reset | |
85 | Assert.assertEquals(Level.INFO, rootLogger.getLevel()); | |
86 | final Handler[] handlers = randomLogger.getHandlers(); | |
87 | Assert.assertTrue(handlers == null || handlers.length == 0); | |
88 | ||
89 | assertEmptyContext(logContext, rootLogger, testLogger, randomLogger); | |
90 | } | |
91 | ||
92 | @Test | |
93 | public void testCloseLogContextConfiguration() throws Exception { | |
94 | final LogContext logContext = LogContext.create(); | |
95 | final LogContextConfiguration logContextConfiguration = LogContextConfiguration.Factory.create(logContext); | |
96 | ||
97 | // Add a POJO to ensure it gets removed | |
98 | final PojoConfiguration pojoConfiguration = logContextConfiguration.addPojoConfiguration(null, | |
99 | PojoObject.class.getName(), "pojo"); | |
100 | ||
101 | // Create an error manager | |
102 | final ErrorManagerConfiguration errorManagerConfiguration = logContextConfiguration.addErrorManagerConfiguration(null, | |
103 | TestErrorManager.class.getName(), "error-manager"); | |
104 | errorManagerConfiguration.setPropertyValueString("pojoObject", pojoConfiguration.getName()); | |
105 | ||
106 | // Create a filter | |
107 | final FilterConfiguration filterConfiguration = logContextConfiguration.addFilterConfiguration(null, | |
108 | TestFilter.class.getName(), "filter"); | |
109 | filterConfiguration.setPropertyValueString("pojoObject", pojoConfiguration.getName()); | |
110 | ||
111 | // Create a formatter | |
112 | final FormatterConfiguration formatterConfiguration = logContextConfiguration.addFormatterConfiguration(null, | |
113 | TestFormatter.class.getName(), "formatter"); | |
114 | formatterConfiguration.setPropertyValueString("pojoObject", pojoConfiguration.getName()); | |
115 | ||
116 | // Create a handler | |
117 | final HandlerConfiguration handlerConfiguration = logContextConfiguration.addHandlerConfiguration(null, | |
118 | TestHandler.class.getName(), "handler"); | |
119 | handlerConfiguration.setPropertyValueString("pojoObject", pojoConfiguration.getName()); | |
120 | handlerConfiguration.setFilter(filterConfiguration.getName()); | |
121 | handlerConfiguration.setErrorManagerName(errorManagerConfiguration.getName()); | |
122 | handlerConfiguration.setFormatterName(formatterConfiguration.getName()); | |
123 | ||
124 | // Create the root-logger configuration | |
125 | final LoggerConfiguration rootLoggerConfig = logContextConfiguration.addLoggerConfiguration(""); | |
126 | rootLoggerConfig.setFilter(filterConfiguration.getName()); | |
127 | rootLoggerConfig.addHandlerName(handlerConfiguration.getName()); | |
128 | rootLoggerConfig.setLevel("WARN"); | |
129 | ||
130 | final LoggerConfiguration testLoggerConfig = logContextConfiguration.addLoggerConfiguration(LogContextCloseTests.class.getName()); | |
131 | testLoggerConfig.setLevel("DEBUG"); | |
132 | testLoggerConfig.addHandlerName(handlerConfiguration.getName()); | |
133 | ||
134 | final LoggerConfiguration randomLoggerConfig = logContextConfiguration.addLoggerConfiguration(UUID.randomUUID().toString()); | |
135 | randomLoggerConfig.setLevel("ERROR"); | |
136 | randomLoggerConfig.setUseParentHandlers(false); | |
137 | ||
138 | ||
139 | logContextConfiguration.commit(); | |
140 | ||
141 | // Create the loggers on the log context to test they've been reset, note this is required to be done before | |
142 | // the context is closed, but after a commit | |
143 | final Logger rootLogger = logContext.getLogger(rootLoggerConfig.getName()); | |
144 | final Logger testLogger = logContext.getLogger(testLoggerConfig.getName()); | |
145 | final Logger randomLogger = logContext.getLogger(randomLoggerConfig.getName()); | |
146 | ||
147 | logContext.close(); | |
148 | ||
149 | assertEmptyNames("error manager", logContextConfiguration.getErrorManagerNames()); | |
150 | assertEmptyNames("filter", logContextConfiguration.getFilterNames()); | |
151 | assertEmptyNames("formatter", logContextConfiguration.getFormatterNames()); | |
152 | assertEmptyNames("handler", logContextConfiguration.getHandlerNames()); | |
153 | assertEmptyNames("logger", logContextConfiguration.getLoggerNames()); | |
154 | assertEmptyNames("POJO", logContextConfiguration.getPojoNames()); | |
155 | ||
156 | assertEmptyContext(logContext, rootLogger, testLogger, randomLogger); | |
157 | // The handler is really the only object available for context since it has a close on it | |
158 | Assert.assertNull("Expected the handler to be reset.", TestHandler.FORMATTER); | |
159 | ||
160 | // Assert the handler itself has been closed | |
161 | Assert.assertTrue("The handler was expected to be closed", TestHandler.IS_CLOSED); | |
162 | } | |
163 | ||
164 | @Test | |
165 | public void testCloseWithAttachment() throws Exception { | |
166 | LogContext logContext = LogContext.create(); | |
167 | final Logger.AttachmentKey<String> key = new Logger.AttachmentKey<>(); | |
168 | final String value = "test value"; | |
169 | Logger rootLogger = logContext.getLogger(""); | |
170 | Assert.assertNull(rootLogger.attach(key, value)); | |
171 | ||
172 | // Close and ensure the context is clean | |
173 | logContext.close(); | |
174 | Assert.assertNull(rootLogger.getAttachment(key)); | |
175 | assertEmptyContext(logContext, rootLogger); | |
176 | ||
177 | // Test attachIfAbsent() | |
178 | logContext = LogContext.create(); | |
179 | rootLogger = logContext.getLogger(""); | |
180 | Assert.assertNull(rootLogger.attachIfAbsent(key, value)); | |
181 | ||
182 | // Close and ensure the context is clean | |
183 | logContext.close(); | |
184 | Assert.assertNull(rootLogger.getAttachment(key)); | |
185 | assertEmptyContext(logContext, rootLogger); | |
186 | ||
187 | // Test detach() | |
188 | logContext = LogContext.create(); | |
189 | rootLogger = logContext.getLogger(""); | |
190 | Assert.assertNull(rootLogger.attach(key, value)); | |
191 | Assert.assertEquals(value, rootLogger.detach(key)); | |
192 | logContext.close(); | |
193 | Assert.assertNull(rootLogger.getAttachment(key)); | |
194 | assertEmptyContext(logContext, rootLogger); | |
195 | } | |
196 | ||
197 | private void assertEmptyContext(final LogContext logContext, final Logger... loggers) { | |
198 | // Inspect the log context and ensure it's "empty" | |
199 | final LoggerNode rootLogger = logContext.getRootLoggerNode(); | |
200 | final Handler[] handlers = rootLogger.getHandlers(); | |
201 | Assert.assertTrue("Expected the handlers to be removed.", handlers == null || handlers.length == 0); | |
202 | Assert.assertNull("Expected the filter to be null", rootLogger.getFilter()); | |
203 | Assert.assertEquals("Expected the level to be INFO for logger the root logger", Level.INFO, rootLogger.getLevel()); | |
204 | Assert.assertFalse("Expected the useParentFilters to be false for the root logger", rootLogger.getUseParentFilters()); | |
205 | Assert.assertTrue("Expected the useParentHandlers to be true for the root logger", rootLogger.getUseParentHandlers()); | |
206 | final Collection<LoggerNode> children = rootLogger.getChildren(); | |
207 | if (!children.isEmpty()) { | |
208 | final StringBuilder msg = new StringBuilder("Expected no children to be remaining on the root logger. Remaining loggers: "); | |
209 | final Iterator<LoggerNode> iter = children.iterator(); | |
210 | while (iter.hasNext()) { | |
211 | msg.append('\'').append(iter.next().getFullName()).append('\''); | |
212 | if (iter.hasNext()) { | |
213 | msg.append(", "); | |
214 | } | |
215 | } | |
216 | Assert.fail(msg.toString()); | |
217 | } | |
218 | ||
219 | for (Logger logger : loggers) { | |
220 | assertLoggerReset(logger); | |
221 | } | |
222 | } | |
223 | ||
224 | private void assertLoggerReset(final Logger logger) { | |
225 | String loggerName = logger.getName(); | |
226 | final Level expectedLevel; | |
227 | if ("".equals(loggerName)) { | |
228 | loggerName = "root"; | |
229 | expectedLevel = Level.INFO; | |
230 | } else { | |
231 | expectedLevel = null; | |
232 | } | |
233 | final Handler[] handlers = logger.getHandlers(); | |
234 | Assert.assertNull("Expected the filter to be null for logger " + loggerName, logger.getFilter()); | |
235 | Assert.assertTrue("Empty handlers expected for logger " + loggerName, handlers == null || handlers.length == 0); | |
236 | Assert.assertEquals("Expected the level to be " + expectedLevel + " for logger " + loggerName, expectedLevel, logger.getLevel()); | |
237 | Assert.assertFalse("Expected the useParentFilters to be false for logger " + loggerName, logger.getUseParentFilters()); | |
238 | Assert.assertTrue("Expected the useParentHandlers to be true for logger " + loggerName, logger.getUseParentHandlers()); | |
239 | } | |
240 | ||
241 | private void assertEmptyNames(final String description, final Collection<String> names) { | |
242 | Assert.assertTrue(String.format("The configuration should not have any %s names, but found: %s", description, names), | |
243 | names.isEmpty()); | |
244 | } | |
245 | ||
246 | ||
247 | @SuppressWarnings("unused") | |
248 | public static class TestFilter implements Filter { | |
249 | private static PojoObject POJO_OBJECT; | |
250 | ||
251 | @Override | |
252 | public boolean isLoggable(final LogRecord record) { | |
253 | return true; | |
254 | } | |
255 | ||
256 | public void setPojoObject(final PojoObject pojoObject) { | |
257 | POJO_OBJECT = pojoObject; | |
258 | } | |
259 | } | |
260 | ||
261 | @SuppressWarnings("unused") | |
262 | public static class TestFormatter extends Formatter { | |
263 | private static PojoObject POJO_OBJECT; | |
264 | ||
265 | public void setPojoObject(final PojoObject pojoObject) { | |
266 | POJO_OBJECT = pojoObject; | |
267 | } | |
268 | ||
269 | @Override | |
270 | public String format(final LogRecord record) { | |
271 | return ExtLogRecord.wrap(record).getFormattedMessage(); | |
272 | } | |
273 | } | |
274 | ||
275 | @SuppressWarnings("unused") | |
276 | public static class TestErrorManager extends ErrorManager { | |
277 | private static PojoObject POJO_OBJECT; | |
278 | ||
279 | public void setPojoObject(final PojoObject pojoObject) { | |
280 | POJO_OBJECT = pojoObject; | |
281 | } | |
282 | } | |
283 | ||
284 | @SuppressWarnings({"unused", "WeakerAccess"}) | |
285 | public static class TestHandler extends ExtHandler { | |
286 | private static PojoObject POJO_OBJECT; | |
287 | private static Handler[] HANDLERS; | |
288 | private static Formatter FORMATTER; | |
289 | private static Filter FILTER; | |
290 | private static ErrorManager ERROR_MANAGER; | |
291 | private static boolean IS_CLOSED; | |
292 | ||
293 | public TestHandler() { | |
294 | IS_CLOSED = false; | |
295 | } | |
296 | ||
297 | @Override | |
298 | public void close() throws SecurityException { | |
299 | // Null out static values | |
300 | POJO_OBJECT = null; | |
301 | FORMATTER = null; | |
302 | HANDLERS = null; | |
303 | FORMATTER = null; | |
304 | FILTER = null; | |
305 | ERROR_MANAGER = null; | |
306 | IS_CLOSED = true; | |
307 | super.close(); | |
308 | } | |
309 | ||
310 | @Override | |
311 | public Handler[] setHandlers(final Handler[] newHandlers) throws SecurityException { | |
312 | HANDLERS = Arrays.copyOf(newHandlers, newHandlers.length); | |
313 | return super.setHandlers(newHandlers); | |
314 | } | |
315 | ||
316 | @Override | |
317 | public void addHandler(final Handler handler) throws SecurityException { | |
318 | if (handler == null) { | |
319 | throw new RuntimeException("Cannot add a null handler"); | |
320 | } | |
321 | if (HANDLERS == null) { | |
322 | HANDLERS = new Handler[] {handler}; | |
323 | } else { | |
324 | final int len = HANDLERS.length + 1; | |
325 | HANDLERS = Arrays.copyOf(HANDLERS, len); | |
326 | HANDLERS[len - 1] = handler; | |
327 | } | |
328 | super.addHandler(handler); | |
329 | } | |
330 | ||
331 | @Override | |
332 | public void removeHandler(final Handler handler) throws SecurityException { | |
333 | if (handler == null) { | |
334 | throw new RuntimeException("Cannot remove a null handler"); | |
335 | } | |
336 | if (HANDLERS == null) { | |
337 | throw new RuntimeException("Attempting to remove a handler that does not exist: " + handler); | |
338 | } else { | |
339 | if (HANDLERS.length == 1) { | |
340 | HANDLERS = null; | |
341 | } else { | |
342 | boolean success = false; | |
343 | final Handler[] newHandlers = new Handler[HANDLERS.length - 1]; | |
344 | int newIndex = 0; | |
345 | for (int i = 0; i < HANDLERS.length; i++) { | |
346 | final Handler current = HANDLERS[i]; | |
347 | if (!success && i > newHandlers.length) { | |
348 | break; | |
349 | } | |
350 | if (handler != current) { | |
351 | newHandlers[newIndex++] = current; | |
352 | } else { | |
353 | success = true; | |
354 | } | |
355 | } | |
356 | if (!success) { | |
357 | throw new RuntimeException("Failed to remove handler " + handler + " as it did no appear to exist."); | |
358 | } | |
359 | } | |
360 | } | |
361 | super.removeHandler(handler); | |
362 | } | |
363 | ||
364 | @Override | |
365 | public void setFormatter(final Formatter newFormatter) throws SecurityException { | |
366 | FORMATTER = newFormatter; | |
367 | super.setFormatter(newFormatter); | |
368 | } | |
369 | ||
370 | @Override | |
371 | public void setFilter(final Filter newFilter) throws SecurityException { | |
372 | FILTER = newFilter; | |
373 | super.setFilter(newFilter); | |
374 | } | |
375 | ||
376 | @Override | |
377 | public void setErrorManager(final ErrorManager em) { | |
378 | ERROR_MANAGER = em; | |
379 | super.setErrorManager(em); | |
380 | } | |
381 | ||
382 | @Override | |
383 | public void setLevel(final Level newLevel) throws SecurityException { | |
384 | super.setLevel(newLevel); | |
385 | } | |
386 | ||
387 | public void setPojoObject(final PojoObject pojoObject) { | |
388 | POJO_OBJECT = pojoObject; | |
389 | } | |
390 | } | |
391 | ||
392 | @SuppressWarnings("WeakerAccess") | |
393 | public static class PojoObject { | |
394 | } | |
395 | } |
19 | 19 | package org.jboss.logmanager.formatters; |
20 | 20 | |
21 | 21 | import org.jboss.logmanager.ExtLogRecord; |
22 | import org.jboss.logmanager.MDC; | |
22 | 23 | import org.jboss.logmanager.NDC; |
23 | 24 | import org.junit.Assert; |
24 | 25 | import org.junit.Test; |
110 | 111 | |
111 | 112 | formatter = new PatternFormatter("%x{2}"); |
112 | 113 | Assert.assertEquals("value2.value3", formatter.format(record)); |
114 | } | |
115 | ||
116 | @Test | |
117 | public void mdc() throws Exception { | |
118 | try { | |
119 | MDC.put("primaryKey", "primaryValue"); | |
120 | MDC.put("key1", "value1"); | |
121 | MDC.put("key2", "value2"); | |
122 | final ExtLogRecord record = createLogRecord("test"); | |
123 | ||
124 | PatternFormatter formatter = new PatternFormatter("%X{key1}"); | |
125 | Assert.assertEquals("value1", formatter.format(record)); | |
126 | ||
127 | formatter = new PatternFormatter("%X{not.found}"); | |
128 | Assert.assertEquals("", formatter.format(record)); | |
129 | ||
130 | formatter = new PatternFormatter("%X"); | |
131 | String formatted = formatter.format(record); | |
132 | Assert.assertEquals("{key1=value1, key2=value2, primaryKey=primaryValue}", formatted); | |
133 | } finally { | |
134 | MDC.clear(); | |
135 | } | |
113 | 136 | } |
114 | 137 | |
115 | 138 | @Test |
99 | 99 | targetClass = "java.nio.file.Files", |
100 | 100 | targetMethod = "move", |
101 | 101 | targetLocation = "AT ENTRY", |
102 | condition = "$2.getFileName().toString().matches(\"periodic-rotating-file-handler\\.log\\.\\d+\")", | |
102 | condition = "$2.getFileName().toString().matches(\"periodic-rotating-file-handler\\\\.log\\\\.\\\\d+\")", | |
103 | 103 | action = "throw new IOException(\"Fail on purpose\")") |
104 | 104 | public void testFailedRotate() throws Exception { |
105 | 105 | final Calendar cal = Calendar.getInstance(); |