2 * SPDX-License-Identifier: LGPL-2.1-only
4 * Copyright (C) 2015-2022 EfficiOS Inc.
5 * Copyright (C) 2015 Alexandre Montplaisir <alexmonthy@efficios.com>
8 package org.lttng.ust.agent.log4j2;
10 import java.util.Collection;
13 import java.util.TreeSet;
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;
26 * Agent implementation for Log4j 2.x.
28 class LttngLog4j2Agent extends AbstractLttngAgent<LttngLogAppender> {
30 private static LttngLog4j2Agent instance = null;
32 private LttngLog4j2Agent() {
36 public static synchronized LttngLog4j2Agent getInstance() {
37 if (instance == null) {
38 instance = new LttngLog4j2Agent();
44 public Collection<String> listAvailableEvents() {
45 Set<String> eventNames = new TreeSet<>();
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");
54 ContextSelector selector = ((Log4jContextFactory) contextFactory).getSelector();
56 for (LoggerContext logContext : selector.getLoggerContexts()) {
57 Collection<? extends Logger> loggers = logContext.getLoggers();
58 for (Logger logger : loggers) {
60 * Check if that logger has at least one LTTng log4j appender attached.
62 if (hasLttngAppenderAttached(logger)) {
63 eventNames.add(logger.getName());
71 * Check if a logger has an LttngLogAppender attached.
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
76 private static boolean hasLttngAppenderAttached(Logger logger) {
83 * Check all the appenders associated with the logger and return true if one of
84 * them is an LttngLogAppender.
86 Map<String, Appender> appenders = logger.getAppenders();
87 for (Map.Entry<String, Appender> appender : appenders.entrySet()) {
88 if (appender.getValue() instanceof LttngLogAppender) {
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.
98 * Despite the doc, getParent can return null based on the implementation as of
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.
105 return hasLttngAppenderAttached(logger.getParent());