Add a Log4j 2.x Java agent
[lttng-ust.git] / src / lib / lttng-ust-java-agent / java / lttng-ust-agent-log4j2 / org / lttng / ust / agent / log4j2 / LttngLog4j2Agent.java
1 /*
2 * SPDX-License-Identifier: LGPL-2.1-only
3 *
4 * Copyright (C) 2015-2022 EfficiOS Inc.
5 * Copyright (C) 2015 Alexandre Montplaisir <alexmonthy@efficios.com>
6 */
7
8 package org.lttng.ust.agent.log4j2;
9
10 import java.util.Collection;
11 import java.util.Map;
12 import java.util.Set;
13 import java.util.TreeSet;
14
15 import org.apache.logging.log4j.LogManager;
16 import org.apache.logging.log4j.core.Appender;
17 import org.apache.logging.log4j.core.Logger;
18 import org.apache.logging.log4j.core.LoggerContext;
19 import org.apache.logging.log4j.core.impl.Log4jContextFactory;
20 import org.apache.logging.log4j.core.selector.ContextSelector;
21 import org.apache.logging.log4j.spi.LoggerContextFactory;
22 import org.apache.logging.log4j.status.StatusLogger;
23 import org.lttng.ust.agent.AbstractLttngAgent;
24
25 /**
26 * Agent implementation for Log4j 2.x.
27 */
28 class LttngLog4j2Agent extends AbstractLttngAgent<LttngLogAppender> {
29
30 private static LttngLog4j2Agent instance = null;
31
32 private LttngLog4j2Agent() {
33 super(Domain.LOG4J);
34 }
35
36 public static synchronized LttngLog4j2Agent getInstance() {
37 if (instance == null) {
38 instance = new LttngLog4j2Agent();
39 }
40 return instance;
41 }
42
43 @Override
44 public Collection<String> listAvailableEvents() {
45 Set<String> eventNames = new TreeSet<>();
46
47 LoggerContextFactory contextFactory = LogManager.getFactory();
48 if (!(contextFactory instanceof Log4jContextFactory)) {
49 /* Using a custom ContextFactory is not supported. */
50 StatusLogger.getLogger().error("Can't list events with custom ContextFactory");
51 return eventNames;
52 }
53
54 ContextSelector selector = ((Log4jContextFactory) contextFactory).getSelector();
55
56 for (LoggerContext logContext : selector.getLoggerContexts()) {
57 Collection<? extends Logger> loggers = logContext.getLoggers();
58 for (Logger logger : loggers) {
59 /*
60 * Check if that logger has at least one LTTng log4j appender attached.
61 */
62 if (hasLttngAppenderAttached(logger)) {
63 eventNames.add(logger.getName());
64 }
65 }
66 }
67 return eventNames;
68 }
69
70 /*
71 * Check if a logger has an LttngLogAppender attached.
72 *
73 * @param logger the Logger to check, null returns false
74 * @return true if the logger or its parent has at least one LttngLogAppender attached
75 */
76 private static boolean hasLttngAppenderAttached(Logger logger) {
77
78 if (logger == null) {
79 return false;
80 }
81
82 /*
83 * Check all the appenders associated with the logger and return true if one of
84 * them is an LttngLogAppender.
85 */
86 Map<String, Appender> appenders = logger.getAppenders();
87 for (Map.Entry<String, Appender> appender : appenders.entrySet()) {
88 if (appender.getValue() instanceof LttngLogAppender) {
89 return true;
90 }
91 }
92
93 /*
94 * A parent logger, if any, may be connected to an LTTng handler. In this case,
95 * we will want to include this child logger in the output, since it will be
96 * accessible by LTTng.
97 *
98 * Despite the doc, getParent can return null based on the implementation as of
99 * log4j 2.17.1.
100 *
101 * The getParent function is there as a backward compat for 1.x. It is not clear
102 * in which context it should be used. The cost of doing the lookup is minimal
103 * and mimics what was done for the 1.x agent.
104 */
105 return hasLttngAppenderAttached(logger.getParent());
106
107 }
108 }
This page took 0.032077 seconds and 4 git commands to generate.