Add LOG4J2 domain to the Log4j 2.x 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 log4j2_instance = null;
31 private static LttngLog4j2Agent log4j1_instance = null;
32
33 private LttngLog4j2Agent(Domain domain) {
34 super(domain);
35 }
36
37 public static synchronized LttngLog4j2Agent getLog4j1Instance() {
38 if (log4j1_instance == null) {
39 log4j1_instance = new LttngLog4j2Agent(Domain.LOG4J);
40 }
41 return log4j1_instance;
42 }
43
44 public static synchronized LttngLog4j2Agent getLog4j2Instance() {
45 if (log4j2_instance == null) {
46 log4j2_instance = new LttngLog4j2Agent(Domain.LOG4J2);
47 }
48 return log4j2_instance;
49 }
50
51 @Override
52 public Collection<String> listAvailableEvents() {
53 Set<String> eventNames = new TreeSet<>();
54
55 LoggerContextFactory contextFactory = LogManager.getFactory();
56 if (!(contextFactory instanceof Log4jContextFactory)) {
57 /* Using a custom ContextFactory is not supported. */
58 StatusLogger.getLogger().error("Can't list events with custom ContextFactory");
59 return eventNames;
60 }
61
62 ContextSelector selector = ((Log4jContextFactory) contextFactory).getSelector();
63
64 for (LoggerContext logContext : selector.getLoggerContexts()) {
65 Collection<? extends Logger> loggers = logContext.getLoggers();
66 for (Logger logger : loggers) {
67 /*
68 * Check if that logger has at least one LTTng log4j appender attached.
69 */
70 if (hasLttngAppenderAttached(logger)) {
71 eventNames.add(logger.getName());
72 }
73 }
74 }
75 return eventNames;
76 }
77
78 /*
79 * Check if a logger has an LttngLogAppender attached.
80 *
81 * @param logger the Logger to check, null returns false
82 * @return true if the logger or its parent has at least one LttngLogAppender attached
83 */
84 private static boolean hasLttngAppenderAttached(Logger logger) {
85
86 if (logger == null) {
87 return false;
88 }
89
90 /*
91 * Check all the appenders associated with the logger and return true if one of
92 * them is an LttngLogAppender.
93 */
94 Map<String, Appender> appenders = logger.getAppenders();
95 for (Map.Entry<String, Appender> appender : appenders.entrySet()) {
96 if (appender.getValue() instanceof LttngLogAppender) {
97 return true;
98 }
99 }
100
101 /*
102 * A parent logger, if any, may be connected to an LTTng handler. In this case,
103 * we will want to include this child logger in the output, since it will be
104 * accessible by LTTng.
105 *
106 * Despite the doc, getParent can return null based on the implementation as of
107 * log4j 2.17.1.
108 *
109 * The getParent function is there as a backward compat for 1.x. It is not clear
110 * in which context it should be used. The cost of doing the lookup is minimal
111 * and mimics what was done for the 1.x agent.
112 */
113 return hasLttngAppenderAttached(logger.getParent());
114
115 }
116 }
This page took 0.030984 seconds and 4 git commands to generate.