2 * SPDX-License-Identifier: LGPL-2.1-only
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>
9 package org
.lttng
.ust
.agent
.log4j2
;
11 import java
.io
.IOException
;
12 import java
.util
.Collection
;
14 import java
.util
.Map
.Entry
;
15 import java
.util
.concurrent
.TimeUnit
;
16 import java
.util
.concurrent
.atomic
.AtomicLong
;
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
;
32 * LTTng-UST Log4j 2.x log handler.
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.
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.
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
{
46 * The name of the appender in the configuration.
48 public static final String PLUGIN_NAME
= "Lttng";
50 private static final String SHARED_OBJECT_NAME
= "lttng-ust-log4j-jni";
53 * Number of events logged (really sent through JNI) by this handler
55 private final AtomicLong eventCount
= new AtomicLong(0);
57 private final LttngLog4j2Agent agent
;
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.
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.
75 protected LttngLogAppender(String name
, Filter filter
, boolean ignoreExceptions
)
76 throws IOException
, SecurityException
{
78 super(name
, filter
, null, ignoreExceptions
, Property
.EMPTY_ARRAY
);
80 /* Initialize LTTng UST tracer. */
82 System
.loadLibrary(SHARED_OBJECT_NAME
); // $NON-NLS-1$
83 } catch (UnsatisfiedLinkError e
) {
84 throw new IOException(e
);
87 /* Register to the relevant agent. */
88 agent
= LttngLog4j2Agent
.getInstance();
89 agent
.registerHandler(this);
93 * Create an LttngLogAppender.
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.
101 * @return A new LttngLogAppender, null if the name was null.
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.
111 public static LttngLogAppender
createAppender(@PluginAttribute("name") String name
,
112 @PluginAttribute("ignoreExceptions") Boolean ignoreExceptions
, @PluginElement("Filters") Filter filter
)
113 throws IOException
, SecurityException
{
116 LOGGER
.error("No name provided for LttngLogAppender");
120 if (ignoreExceptions
== null) {
121 ignoreExceptions
= true;
124 return new LttngLogAppender(name
, filter
, ignoreExceptions
);
128 public synchronized void close() {
129 agent
.unregisterHandler(this);
137 getStatusLogger().debug("Appender Lttng stopped");
141 public boolean stop(final long timeout
, final TimeUnit timeUnit
) {
143 boolean status
= super.stop(timeout
, timeUnit
);
145 getStatusLogger().debug("Appender Lttng stopped with status " + status
);
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.
154 * @return The number of events logged so far
157 public long getEventCount() {
158 return eventCount
.get();
162 public void append(LogEvent event
) {
164 * Check if the current message should be logged, according to the UST session
167 if (!agent
.isEventEnabled(event
.getLoggerName())) {
172 * Default values if the StackTraceElement is null.
174 String classname
= "";
175 String methodname
= "";
176 String filename
= "";
179 StackTraceElement ste
= event
.getSource();
181 classname
= ste
.getClassName();
182 methodname
= ste
.getMethodName();
183 filename
= ste
.getFileName();
184 line
= ste
.getLineNumber();
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
);
192 eventCount
.incrementAndGet();
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());