Commit | Line | Data |
---|---|---|
464c4756 MJ |
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 | ||
495b8381 MJ |
30 | private static LttngLog4j2Agent log4j2_instance = null; |
31 | private static LttngLog4j2Agent log4j1_instance = null; | |
464c4756 | 32 | |
495b8381 MJ |
33 | private LttngLog4j2Agent(Domain domain) { |
34 | super(domain); | |
464c4756 MJ |
35 | } |
36 | ||
495b8381 MJ |
37 | public static synchronized LttngLog4j2Agent getLog4j1Instance() { |
38 | if (log4j1_instance == null) { | |
39 | log4j1_instance = new LttngLog4j2Agent(Domain.LOG4J); | |
464c4756 | 40 | } |
495b8381 MJ |
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; | |
464c4756 MJ |
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 | } |