Codebase list jboss-logmanager / a32bc41
New upstream version 2.1.4 Markus Koschany 5 years ago
13 changed file(s) with 864 addition(s) and 82 deletion(s). Raw diff Collapse all Expand all
2727 <groupId>org.jboss.logmanager</groupId>
2828 <artifactId>jboss-logmanager</artifactId>
2929 <packaging>jar</packaging>
30 <version>2.1.2.Final</version>
30 <version>2.1.4.Final</version>
3131
3232 <parent>
3333 <groupId>org.jboss</groupId>
4646 <properties>
4747 <!-- Dependency versions -->
4848 <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>
5050 <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>
5252 <version.org.wildfly.common.wildfly-common>1.2.0.Final</version.org.wildfly.common.wildfly-common>
5353 <version.junit.junit>4.12</version.junit.junit>
5454
2020
2121 import java.lang.ref.WeakReference;
2222 import java.security.Permission;
23 import java.util.Collection;
2324 import java.util.Enumeration;
2425 import java.util.HashMap;
2526 import java.util.Iterator;
27 import java.util.LinkedHashSet;
2628 import java.util.Map;
2729 import java.util.Map.Entry;
2830 import java.util.NoSuchElementException;
31 import java.util.Set;
2932 import java.util.concurrent.ConcurrentMap;
3033 import java.util.concurrent.ConcurrentSkipListMap;
3134 import java.util.concurrent.atomic.AtomicInteger;
3235 import java.util.concurrent.atomic.AtomicReference;
3336 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
34
3537 import java.util.logging.Level;
3638 import java.util.logging.LoggingMXBean;
3739 import java.util.logging.LoggingPermission;
3941 /**
4042 * A logging context, for producing isolated logging environments.
4143 */
42 public final class LogContext implements Protectable {
44 @SuppressWarnings("unused")
45 public final class LogContext implements Protectable, AutoCloseable {
4346 private static final LogContext SYSTEM_CONTEXT = new LogContext(false);
4447
4548 static final Permission CREATE_CONTEXT_PERMISSION = new RuntimePermission("createLogContext", null);
97100 }
98101
99102 private final AtomicReference<Map<String, LevelRef>> levelMapReference;
103 // Guarded by treeLock
104 private final Set<AutoCloseable> closeHandlers;
100105
101106 /**
102107 * This lock is taken any time a change is made which affects multiple nodes in the hierarchy.
108113 levelMapReference = new AtomicReference<Map<String, LevelRef>>(LazyHolder.INITIAL_LEVEL_MAP);
109114 rootLogger = new LoggerNode(this);
110115 loggerNames = new ConcurrentSkipListMap<String, AtomicInteger>();
116 closeHandlers = new LinkedHashSet<>();
111117 }
112118
113119 /**
337343 @Override
338344 public void disableAccess() {
339345 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 }
340360 }
341361
342362 /**
382402 };
383403 }
384404
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
385448 protected void incrementRef(final String name) {
386449 AtomicInteger counter = loggerNames.get(name);
387450 if (counter == null) {
425488 return strong ? new CopyOnWriteMap<String, LoggerNode>() : new CopyOnWriteWeakMap<String, LoggerNode>();
426489 }
427490
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
428500 private interface LevelRef {
429501 Level get();
430502 }
2323 import java.util.Collection;
2424 import java.util.Collections;
2525 import java.util.HashMap;
26 import java.util.Iterator;
2726 import java.util.Map;
2827 import java.util.concurrent.ConcurrentMap;
2928 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
3433 /**
3534 * A node in the tree of logger names. Maintains weak references to children and a strong reference to its parent.
3635 */
37 final class LoggerNode {
36 final class LoggerNode implements AutoCloseable {
3837
3938 /**
4039 * The log context.
141140 this.context = context;
142141 effectiveLevel = parent.effectiveLevel;
143142 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 }
144163 }
145164
146165 /**
379398 V old;
380399 do {
381400 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);
389403 } while (! attachmentsUpdater.compareAndSet(this, oldAttachments, newAttachments));
390404 return old;
391405 }
402416 Map<Logger.AttachmentKey, Object> newAttachments;
403417 do {
404418 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);
414424 } while (! attachmentsUpdater.compareAndSet(this, oldAttachments, newAttachments));
415425 return null;
416426 }
433443 if (size == 1) {
434444 // special case - the new map is empty
435445 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());
446446 } else {
447447 newAttachments = new HashMap<Logger.AttachmentKey, Object>(oldAttachments);
448448 }
8484
8585 LogContextConfigurationImpl(final LogContext logContext) {
8686 this.logContext = logContext;
87 logContext.addCloseHandler(new LogContextConfigurationCloseHandler());
8788 }
8889
8990 public LogContext getLogContext() {
737738 ObjectProducer resolveFilter(String expression) {
738739 return resolveFilter(expression, false);
739740 }
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 }
740780 }
3333 import java.util.Locale;
3434 import java.util.Map;
3535 import java.util.TimeZone;
36 import java.util.TreeMap;
3637 import java.util.logging.Formatter;
3738 import java.util.logging.Level;
3839 import java.util.logging.LogRecord;
10721073 public static FormatStep mdcFormatStep(final String key, final boolean leftJustify, final int minimumWidth, final boolean truncateBeginning, final int maximumWidth) {
10731074 return new JustifyingFormatStep(leftJustify, minimumWidth, truncateBeginning, maximumWidth) {
10741075 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 }
10781083 }
10791084 }
10801085 };
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 }
6767 private final Object outputLock = new Object();
6868
6969 // All the following fields are guarded by outputLock
70 private ClientSocketFactory clientSocketFactory;
7071 private SocketFactory socketFactory;
7172 private InetAddress address;
7273 private int port;
142143 * @param port the port to connect to
143144 *
144145 * @throws UnknownHostException if an error occurs resolving the hostname
146 * @see #SocketHandler(ClientSocketFactory, Protocol)
145147 */
146148 public SocketHandler(final SocketFactory socketFactory, final Protocol protocol, final String hostname, final int port) throws UnknownHostException {
147149 this(socketFactory, protocol, InetAddress.getByName(hostname), port);
156158 * @param protocol the protocol to connect with
157159 * @param address the address to connect to
158160 * @param port the port to connect to
161 *
162 * @see #SocketHandler(ClientSocketFactory, Protocol)
159163 */
160164 public SocketHandler(final SocketFactory socketFactory, final Protocol protocol, final InetAddress address, final int port) {
165 this.socketFactory = socketFactory;
166 this.clientSocketFactory = null;
161167 this.address = address;
162168 this.port = port;
163 this.protocol = protocol;
169 this.protocol = (protocol == null ? Protocol.TCP : protocol);
164170 initialize = true;
165171 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;
167190 blockOnReconnect = false;
168191 }
169192
228251
229252 /**
230253 * Sets the address to connect to.
254 * <p>
255 * Note that is resets the {@linkplain #setClientSocketFactory(ClientSocketFactory) client socket factory}.
256 * </p>
231257 *
232258 * @param address the address
233259 */
234260 public void setAddress(final InetAddress address) {
235261 checkAccess(this);
236262 synchronized (outputLock) {
263 if (!this.address.equals(address)) {
264 initialize = true;
265 clientSocketFactory = null;
266 }
237267 this.address = address;
238 initialize = true;
239268 }
240269 }
241270
242271 /**
243272 * 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>
244276 *
245277 * @param hostname the host name used to resolve the address
246278 *
276308 checkAccess(this);
277309 synchronized (outputLock) {
278310 this.blockOnReconnect = blockOnReconnect;
311 initialize = true;
279312 }
280313 }
281314
292325 * Sets the protocol to use. If the value is {@code null} the protocol will be set to
293326 * {@linkplain Protocol#TCP TCP}.
294327 * <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.
296329 * </p>
297330 *
298331 * @param protocol the protocol to use
303336 if (protocol == null) {
304337 this.protocol = Protocol.TCP;
305338 }
306 // Reset the socket factory
307 socketFactory = null;
339 if (this.protocol != protocol) {
340 socketFactory = null;
341 initialize = true;
342 }
308343 this.protocol = protocol;
309 initialize = true;
310344 }
311345 }
312346
321355
322356 /**
323357 * Sets the port to connect to.
358 * <p>
359 * Note that is resets the {@linkplain #setClientSocketFactory(ClientSocketFactory) client socket factory}.
360 * </p>
324361 *
325362 * @param port the port
326363 */
327364 public void setPort(final int port) {
328365 checkAccess(this);
329366 synchronized (outputLock) {
367 if (this.port != port) {
368 initialize = true;
369 clientSocketFactory = null;
370 }
330371 this.port = port;
331 initialize = true;
332372 }
333373 }
334374
337377 * connections.
338378 * <p>
339379 * 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}.
341382 * </p>
342383 *
343384 * @param socketFactory the socket factory
385 *
386 * @see #setClientSocketFactory(ClientSocketFactory)
344387 */
345388 public void setSocketFactory(final SocketFactory socketFactory) {
346389 checkAccess(this);
347390 synchronized (outputLock) {
348391 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;
349407 initialize = true;
350408 }
351409 }
387445 private OutputStream createOutputStream() {
388446 if (address != null || port >= 0) {
389447 try {
448 final ClientSocketFactory socketFactory = getClientSocketFactory();
390449 if (protocol == Protocol.UDP) {
391 return new UdpOutputStream(address, port);
450 return new UdpOutputStream(socketFactory);
392451 }
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);
403453 } catch (IOException e) {
404454 reportError("Failed to create socket output stream", e, ErrorManager.OPEN_FAILURE);
405455 }
406456 }
407457 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 }
408480 }
409481
410482 private void writeHead(final Writer writer) {
3434 import java.util.logging.Formatter;
3535 import java.util.logging.Level;
3636 import java.util.regex.Pattern;
37 import javax.net.SocketFactory;
38 import javax.net.ssl.SSLSocketFactory;
3739
3840 import org.jboss.logmanager.ExtHandler;
3941 import org.jboss.logmanager.ExtLogRecord;
323325 private boolean truncate;
324326 private int maxLen;
325327 private boolean blockOnReconnect;
328 private ClientSocketFactory clientSocketFactory;
326329
327330 /**
328331 * The default class constructor.
667670 }
668671
669672 /**
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 /**
670686 * Checks whether or not characters below decimal 32, traditional US-ASCII control values expect {@code DEL}, are
671687 * being escaped or not.
672688 *
10831099 final OutputStream out;
10841100 // Check the sockets
10851101 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);
10921105 } else {
1093 throw new IllegalStateException("Invalid protocol: " + protocol);
1106 out = new TcpOutputStream(clientSocketFactory, blockOnReconnect);
10941107 }
10951108 setOutputStream(out, false);
10961109 } catch (IOException e) {
12951308 return buffer.toArray();
12961309 }
12971310
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
12981321 private static String checkPrintableAscii(final String name, final String value) {
12991322 if (value != null && PRINTABLE_ASCII_PATTERN.matcher(value).find()) {
13001323 final String upper = Character.toUpperCase(name.charAt(0)) + name.substring(1);
5353
5454 protected final Object outputLock = new Object();
5555
56 private final SocketFactory socketFactory;
57 private final InetAddress address;
58 private final int port;
56 private final ClientSocketFactory socketFactory;
5957 private final Deque<Exception> errors = new ArrayDeque<Exception>(maxErrors);
6058
6159 // Guarded by outputLock
107105 *
108106 * @param socket the socket used to write the output to
109107 *
110 * @deprecated Use {@link #TcpOutputStream(javax.net.SocketFactory, java.net.InetAddress, int)}
108 * @deprecated Use {@link #TcpOutputStream(ClientSocketFactory, boolean)}
111109 */
112110 @Deprecated
113111 protected TcpOutputStream(final Socket socket) {
114112 this.socketFactory = null;
115 this.address = null;
116 this.port = -1;
117113 this.socket = socket;
118114 reconnectThread = null;
119115 connected = true;
151147 * a reconnect will be attempted on the next write.
152148 */
153149 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) {
154161 this.socketFactory = socketFactory;
155 this.address = address;
156 this.port = port;
157162 this.blockOnReconnect = blockOnReconnect;
158163 try {
159 socket = socketFactory.createSocket(address, port);
164 socket = this.socketFactory.createSocket();
160165 connected = true;
161166 } catch (IOException e) {
162167 connected = false;
165170
166171 @Override
167172 public void write(final int b) throws IOException {
168 write(new byte[]{(byte) b}, 0, 1);
173 write(new byte[] {(byte) b}, 0, 1);
169174 }
170175
171176 @Override
207212 public void flush() throws IOException {
208213 synchronized (outputLock) {
209214 try {
210 socket.getOutputStream().flush();
215 if (socket != null) {
216 socket.getOutputStream().flush();
217 }
211218 } catch (SocketException e) {
212219 // This should likely never be hit, but should attempt to reconnect if it does happen
213220 if (isReconnectAllowed()) {
229236 if (reconnectThread != null) {
230237 reconnectThread.interrupt();
231238 }
232 socket.close();
239 if (socket != null) {
240 socket.close();
241 }
233242 }
234243 }
235244
344353 while (socketFactory != null && !connected) {
345354 Socket socket = null;
346355 try {
347 socket = socketFactory.createSocket(address, port);
356 socket = socketFactory.createSocket();
348357 synchronized (outputLock) {
349358 // Unlikely but if we've been interrupted due to a close, we should shutdown
350359 if (Thread.currentThread().isInterrupted()) {
2323 import java.net.DatagramPacket;
2424 import java.net.DatagramSocket;
2525 import java.net.InetAddress;
26 import java.net.SocketAddress;
27 import java.net.SocketException;
2628
2729 /**
2830 * An output stream that writes data to a {@link java.net.DatagramSocket DatagramSocket}.
2931 *
3032 * @author <a href="mailto:jperkins@redhat.com">James R. Perkins</a>
3133 */
34 @SuppressWarnings("WeakerAccess")
3235 public class UdpOutputStream extends OutputStream implements FlushableCloseable {
3336 private final DatagramSocket socket;
37 private final SocketAddress socketAddress;
3438
3539 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();
3846 }
3947
4048 @Override
4149 public void write(final int b) throws IOException {
4250 final byte[] msg = new byte[] {(byte) b};
43 final DatagramPacket packet = new DatagramPacket(msg, 1);
51 final DatagramPacket packet = new DatagramPacket(msg, 1, socketAddress);
4452 socket.send(packet);
4553 }
4654
4755 @Override
4856 public void write(final byte[] b) throws IOException {
4957 if (b != null) {
50 final DatagramPacket packet = new DatagramPacket(b, b.length);
58 final DatagramPacket packet = new DatagramPacket(b, b.length, socketAddress);
5159 socket.send(packet);
5260 }
5361 }
5563 @Override
5664 public void write(final byte[] b, final int off, final int len) throws IOException {
5765 if (b != null) {
58 final DatagramPacket packet = new DatagramPacket(b, off, len);
66 final DatagramPacket packet = new DatagramPacket(b, off, len, socketAddress);
5967 socket.send(packet);
6068 }
6169 }
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 }
1919 package org.jboss.logmanager.formatters;
2020
2121 import org.jboss.logmanager.ExtLogRecord;
22 import org.jboss.logmanager.MDC;
2223 import org.jboss.logmanager.NDC;
2324 import org.junit.Assert;
2425 import org.junit.Test;
110111
111112 formatter = new PatternFormatter("%x{2}");
112113 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 }
113136 }
114137
115138 @Test
9999 targetClass = "java.nio.file.Files",
100100 targetMethod = "move",
101101 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+\")",
103103 action = "throw new IOException(\"Fail on purpose\")")
104104 public void testFailedRotate() throws Exception {
105105 final Calendar cal = Calendar.getInstance();