001package io.prometheus.client.log4j2;
002
003import io.prometheus.client.Counter;
004import org.apache.logging.log4j.Level;
005import org.apache.logging.log4j.core.LogEvent;
006import org.apache.logging.log4j.core.appender.AbstractAppender;
007import org.apache.logging.log4j.core.config.plugins.Plugin;
008import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
009import org.apache.logging.log4j.core.config.plugins.PluginFactory;
010
011import static org.apache.logging.log4j.Level.*;
012
013/**
014 * Log4j2 log statements at various log levels
015 * <p>
016 * Example log4j2 configuration:
017 * <pre>
018 *   &lt;?xml version="1.0" encoding="UTF-8"?&gt;
019 *   &lt;Configuration packages="io.prometheus.client.log4j2"&gt;
020 *     &lt;Appenders&gt;
021 *       &lt;Prometheus name="PROMETHEUS"/&gt;
022 *     &lt;/Appenders&gt;
023 *     &lt;Loggers&gt;
024 *       &lt;Root level="trace"&gt;
025 *         &lt;AppenderRef ref="PROMETHEUS"/&gt;
026 *       &lt;/Root&gt;
027 *     &lt;/Loggers&gt;
028 *   &lt;/Configuration&gt;
029 * </pre>
030 * Example metrics being exported:
031 * <pre>
032 *   log4j_appender_total{level="trace",} 1.0
033 *   log4j_appender_total{level="debug",} 2.0
034 *   log4j_appender_total{level="info",} 3.0
035 *   log4j_appender_total{level="warn",} 4.0
036 *   log4j_appender_total{level="error",} 5.0
037 *   log4j_appender_total{level="fatal",} 6.0
038 * </pre>
039 */
040@Plugin(name = "Prometheus", category = "Core", elementType = "appender")
041public final class InstrumentedAppender extends AbstractAppender {
042
043    public static final String COUNTER_NAME = "log4j2_appender_total";
044
045    private static final Counter COUNTER;
046    private static final Counter.Child TRACE_LABEL;
047    private static final Counter.Child DEBUG_LABEL;
048    private static final Counter.Child INFO_LABEL;
049    private static final Counter.Child WARN_LABEL;
050    private static final Counter.Child ERROR_LABEL;
051    private static final Counter.Child FATAL_LABEL;
052
053    static {
054        COUNTER = Counter.build().name(COUNTER_NAME)
055                .help("Log4j2 log statements at various log levels")
056                .labelNames("level")
057                .register();
058
059        TRACE_LABEL = COUNTER.labels("trace");
060        DEBUG_LABEL = COUNTER.labels("debug");
061        INFO_LABEL = COUNTER.labels("info");
062        WARN_LABEL = COUNTER.labels("warn");
063        ERROR_LABEL = COUNTER.labels("error");
064        FATAL_LABEL = COUNTER.labels("fatal");
065    }
066
067    /**
068     * Create a new instrumented appender using the default registry.
069     */
070    protected InstrumentedAppender(String name) {
071        super(name, null, null);
072    }
073
074    @Override
075    public void append(LogEvent event) {
076        Level level = event.getLevel();
077        if (TRACE.equals(level)) TRACE_LABEL.inc();
078        else if (DEBUG.equals(level)) DEBUG_LABEL.inc();
079        else if (INFO.equals(level)) INFO_LABEL.inc();
080        else if (WARN.equals(level)) WARN_LABEL.inc();
081        else if (ERROR.equals(level)) ERROR_LABEL.inc();
082        else if (FATAL.equals(level)) FATAL_LABEL.inc();
083    }
084
085    @PluginFactory
086    public static InstrumentedAppender createAppender(
087            @PluginAttribute("name") String name) {
088        if (name == null) {
089            LOGGER.error("No name provided for InstrumentedAppender");
090            return null;
091        }
092        return new InstrumentedAppender(name);
093    }
094
095}