|
26 | 26 | import org.apache.logging.log4j.spi.ExtendedLogger;
|
27 | 27 | import org.apache.logging.log4j.spi.ExtendedLoggerWrapper;
|
28 | 28 |
|
29 |
| -import java.lang.ref.WeakReference; |
30 | 29 | import java.util.WeakHashMap;
|
31 | 30 |
|
| 31 | +/** |
| 32 | + * A logger that prefixes all messages with a fixed prefix specified during construction. The prefix mechanism uses the marker construct, so |
| 33 | + * for the prefixes to appear, the logging layout pattern must include the marker in its pattern. |
| 34 | + */ |
32 | 35 | class PrefixLogger extends ExtendedLoggerWrapper {
|
33 | 36 |
|
34 |
| - // we can not use the built-in Marker tracking (MarkerManager) because the MarkerManager holds |
35 |
| - // a permanent reference to the marker; however, we have transient markers from index-level and |
36 |
| - // shard-level components so this would effectively be a memory leak |
37 |
| - private static final WeakHashMap<String, WeakReference<Marker>> markers = new WeakHashMap<>(); |
| 37 | + /* |
| 38 | + * We can not use the built-in Marker tracking (MarkerManager) because the MarkerManager holds a permanent reference to the marker; |
| 39 | + * however, we have transient markers from index-level and shard-level components so this would effectively be a memory leak. Since we |
| 40 | + * can not tie into the lifecycle of these components, we have to use a mechanism that enables garbage collection of such markers when |
| 41 | + * they are no longer in use. |
| 42 | + */ |
| 43 | + private static final WeakHashMap<String, Marker> markers = new WeakHashMap<>(); |
| 44 | + |
| 45 | + /** |
| 46 | + * Return the size of the cached markers. This size can vary as markers are cached but collected during GC activity when a given prefix |
| 47 | + * is no longer in use. |
| 48 | + * |
| 49 | + * @return the size of the cached markers |
| 50 | + */ |
| 51 | + static int markersSize() { |
| 52 | + return markers.size(); |
| 53 | + } |
38 | 54 |
|
| 55 | + /** |
| 56 | + * The marker for this prefix logger. |
| 57 | + */ |
39 | 58 | private final Marker marker;
|
40 | 59 |
|
| 60 | + /** |
| 61 | + * Obtain the prefix for this prefix logger. This can be used to create a logger with the same prefix as this one. |
| 62 | + * |
| 63 | + * @return the prefix |
| 64 | + */ |
41 | 65 | public String prefix() {
|
42 | 66 | return marker.getName();
|
43 | 67 | }
|
44 | 68 |
|
| 69 | + /** |
| 70 | + * Construct a prefix logger with the specified name and prefix. |
| 71 | + * |
| 72 | + * @param logger the extended logger to wrap |
| 73 | + * @param name the name of this prefix logger |
| 74 | + * @param prefix the prefix for this prefix logger |
| 75 | + */ |
45 | 76 | PrefixLogger(final ExtendedLogger logger, final String name, final String prefix) {
|
46 | 77 | super(logger, name, null);
|
47 | 78 |
|
48 | 79 | final String actualPrefix = (prefix == null ? "" : prefix).intern();
|
49 | 80 | final Marker actualMarker;
|
50 | 81 | // markers is not thread-safe, so we synchronize access
|
51 | 82 | synchronized (markers) {
|
52 |
| - final WeakReference<Marker> marker = markers.get(actualPrefix); |
53 |
| - final Marker maybeMarker = marker == null ? null : marker.get(); |
| 83 | + final Marker maybeMarker = markers.get(actualPrefix); |
54 | 84 | if (maybeMarker == null) {
|
55 | 85 | actualMarker = new MarkerManager.Log4jMarker(actualPrefix);
|
56 |
| - markers.put(actualPrefix, new WeakReference<>(actualMarker)); |
| 86 | + /* |
| 87 | + * We must create a new instance here as otherwise the marker will hold a reference to the key in the weak hash map; as |
| 88 | + * those references are held strongly, this would give a strong reference back to the key preventing them from ever being |
| 89 | + * collected. This also guarantees that no other strong reference can be held to the prefix anywhere. |
| 90 | + */ |
| 91 | + markers.put(new String(actualPrefix), actualMarker); |
57 | 92 | } else {
|
58 | 93 | actualMarker = maybeMarker;
|
59 | 94 | }
|
|
0 commit comments