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 / LttngLogAppender.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 * Copyright (C) 2014 Christian Babeux <christian.babeux@efficios.com>
7 */
8
9 package org.lttng.ust.agent.log4j2;
10
11 import java.io.IOException;
12 import java.util.Collection;
13 import java.util.Map;
14 import java.util.Map.Entry;
15 import java.util.concurrent.TimeUnit;
16 import java.util.concurrent.atomic.AtomicLong;
17
18 import org.apache.logging.log4j.core.Appender;
19 import org.apache.logging.log4j.core.Core;
20 import org.apache.logging.log4j.core.Filter;
21 import org.apache.logging.log4j.core.LogEvent;
22 import org.apache.logging.log4j.core.appender.AbstractAppender;
23 import org.apache.logging.log4j.core.config.Property;
24 import org.apache.logging.log4j.core.config.plugins.Plugin;
25 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
26 import org.apache.logging.log4j.core.config.plugins.PluginElement;
27 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
28 import org.lttng.ust.agent.ILttngHandler;
29 import org.lttng.ust.agent.context.ContextInfoSerializer;
30
31 /**
32 * LTTng-UST Log4j 2.x log handler.
33 *
34 * Applications can attach this appender to their
35 * {@link org.apache.log4j.Logger} to have it generate UST events from logging
36 * events received through the logger.
37 *
38 * It sends its events to UST via the JNI library "liblttng-ust-log4j-jni.so".
39 * Make sure this library is available before using this appender.
40 *
41 */
42 @Plugin(name = LttngLogAppender.PLUGIN_NAME, category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = false)
43 public final class LttngLogAppender extends AbstractAppender implements ILttngHandler {
44
45 /**
46 * The name of the appender in the configuration.
47 */
48 public static final String PLUGIN_NAME = "Lttng";
49
50 private static final String SHARED_OBJECT_NAME = "lttng-ust-log4j-jni";
51
52 /**
53 * Number of events logged (really sent through JNI) by this handler
54 */
55 private final AtomicLong eventCount = new AtomicLong(0);
56
57 private final LttngLog4j2Agent agent;
58
59 /**
60 * Constructor
61 *
62 * @param name The name of the Appender.
63 * @param filter The Filter or null.
64 * @param ignoreExceptions If {@code "true"} (default) exceptions encountered
65 * when appending events are logged; otherwise they are
66 * propagated to the caller.
67 *
68 * @throws IOException This handler requires the lttng-ust-log4j-jni.so
69 * native library, through which it will send the
70 * trace events. This exception is thrown if this
71 * library cannot be found.
72 * @throws SecurityException We will forward any SecurityExcepion that may be
73 * thrown when trying to load the JNI library.
74 */
75 protected LttngLogAppender(String name, Filter filter, boolean ignoreExceptions)
76 throws IOException, SecurityException {
77
78 super(name, filter, null, ignoreExceptions, Property.EMPTY_ARRAY);
79
80 /* Initialize LTTng UST tracer. */
81 try {
82 System.loadLibrary(SHARED_OBJECT_NAME); // $NON-NLS-1$
83 } catch (UnsatisfiedLinkError e) {
84 throw new IOException(e);
85 }
86
87 /* Register to the relevant agent. */
88 agent = LttngLog4j2Agent.getInstance();
89 agent.registerHandler(this);
90 }
91
92 /**
93 * Create an LttngLogAppender.
94 *
95 * @param name The name of the Appender, null returns null.
96 * @param ignoreExceptions If {@code "true"} (default) exceptions encountered
97 * when appending events are logged; otherwise they are
98 * propagated to the caller.
99 * @param filter The Filter or null.
100 *
101 * @return A new LttngLogAppender, null if the name was null.
102 *
103 * @throws IOException This handler requires the lttng-ust-log4j-jni.so
104 * native library, through which it will send the
105 * trace events. This exception is thrown if this
106 * library cannot be found.
107 * @throws SecurityException We will forward any SecurityExcepion that may be
108 * thrown when trying to load the JNI library.
109 */
110 @PluginFactory
111 public static LttngLogAppender createAppender(@PluginAttribute("name") String name,
112 @PluginAttribute("ignoreExceptions") Boolean ignoreExceptions, @PluginElement("Filters") Filter filter)
113 throws IOException, SecurityException {
114
115 if (name == null) {
116 LOGGER.error("No name provided for LttngLogAppender");
117 return null;
118 }
119
120 if (ignoreExceptions == null) {
121 ignoreExceptions = true;
122 }
123
124 return new LttngLogAppender(name, filter, ignoreExceptions);
125 }
126
127 @Override
128 public synchronized void close() {
129 agent.unregisterHandler(this);
130 }
131
132 @Override
133 public void stop() {
134 close();
135 super.stop();
136
137 getStatusLogger().debug("Appender Lttng stopped");
138 }
139
140 @Override
141 public boolean stop(final long timeout, final TimeUnit timeUnit) {
142 close();
143 boolean status = super.stop(timeout, timeUnit);
144
145 getStatusLogger().debug("Appender Lttng stopped with status " + status);
146
147 return status;
148 }
149
150 /**
151 * Get the number of events logged by this handler so far. This means the number
152 * of events actually sent through JNI to UST.
153 *
154 * @return The number of events logged so far
155 */
156 @Override
157 public long getEventCount() {
158 return eventCount.get();
159 }
160
161 @Override
162 public void append(LogEvent event) {
163 /*
164 * Check if the current message should be logged, according to the UST session
165 * settings.
166 */
167 if (!agent.isEventEnabled(event.getLoggerName())) {
168 return;
169 }
170
171 /*
172 * Default values if the StackTraceElement is null.
173 */
174 String classname = "";
175 String methodname = "";
176 String filename = "";
177 int line = -1;
178
179 StackTraceElement ste = event.getSource();
180 if (ste != null) {
181 classname = ste.getClassName();
182 methodname = ste.getMethodName();
183 filename = ste.getFileName();
184 line = ste.getLineNumber();
185 }
186
187 /* Retrieve all the requested context information we can find. */
188 Collection<Entry<String, Map<String, Integer>>> enabledContexts = agent.getEnabledAppContexts();
189 ContextInfoSerializer.SerializedContexts contextInfo = ContextInfoSerializer
190 .queryAndSerializeRequestedContexts(enabledContexts);
191
192 eventCount.incrementAndGet();
193
194 LttngLog4j2Api.tracepointWithContext(event.getMessage().getFormattedMessage(), event.getLoggerName(), classname,
195 methodname, filename, line, event.getTimeMillis(), event.getLevel().intLevel(), event.getThreadName(),
196 contextInfo.getEntriesArray(), contextInfo.getStringsArray());
197 }
198 }
This page took 0.038096 seconds and 4 git commands to generate.