![JAR search and dependency download from the Maven repository](/logo.png)
no.digipost.monitoring.logging.LogbackLoggerMetrics Maven / Gradle / Ivy
/*
* Copyright (C) Posten Norge AS
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package no.digipost.monitoring.logging;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.UnsynchronizedAppenderBase;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.MeterBinder;
import no.digipost.monitoring.util.Minutes;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Log-events metrics for specified logback appender. Dimensions for level
, logger
*
* USAGE:
*
* LogbackLoggerMetrics.forRootLogger().bindTo(meterRegistry);
*
*/
public class LogbackLoggerMetrics implements MeterBinder {
private final LoggerContext loggerContext;
private final String loggerName;
private Counter traceCounter;
private Counter debugCounter;
private Counter infoCounter;
private Counter warnCounter;
private Counter errorCounter;
private final List threshold5MinMetrics = new ArrayList<>();
private final Set excludedLoggerNameSet = new HashSet<>();
private LogbackLoggerMetrics(String loggerName) {
this.loggerName = loggerName;
loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
}
public static LogbackLoggerMetrics forRootLogger() {
return new LogbackLoggerMetrics(Logger.ROOT_LOGGER_NAME);
}
public static LogbackLoggerMetrics forLogger(String loggerName) {
return new LogbackLoggerMetrics(loggerName);
}
/**
* Creates a new metric with name log_events_5min_threshold and dimensions level="warn" and logger="YourLoggerName"
* @param threshold the value of the threshold metric
* @return this
*/
public LogbackLoggerMetrics warnThreshold5min(double threshold) {
threshold5MinMetrics.add(new LoggerThresholdMetric(loggerName, threshold, "warn", Minutes.of(5)));
return this;
}
/**
* Creates a new metric with name log_events_5min_threshold and dimensions level="error" and logger="YourLoggerName"
* @param threshold the value of the threshold metric
* @return this
*/
public LogbackLoggerMetrics errorThreshold5min(double threshold) {
threshold5MinMetrics.add(new LoggerThresholdMetric(loggerName, threshold, "error", Minutes.of(5)));
return this;
}
/**
* Exclude events logged by loggerName from being counted in logback_logger_events metrics (all log levels).
* @param loggerName The name of the logger to exclude counting events from
* @return this
*/
public LogbackLoggerMetrics excludeLogger(String loggerName) {
excludedLoggerNameSet.add(loggerName);
return this;
}
@Override
public void bindTo(MeterRegistry registry) {
traceCounter = createCounter(registry, "trace");
debugCounter = createCounter(registry, "debug");
infoCounter = createCounter(registry, "info");
warnCounter = createCounter(registry, "warn");
errorCounter = createCounter(registry, "error");
Logger logger = loggerContext.getLogger(loggerName);
MetricsAppender metricsAppender = new MetricsAppender();
metricsAppender.setContext(loggerContext);
metricsAppender.start();
logger.addAppender(metricsAppender);
for (LoggerThresholdMetric loggerThresholdMetric : threshold5MinMetrics) {
loggerThresholdMetric.bindTo(registry);
}
}
private Counter createCounter(MeterRegistry registry, String level) {
return Counter.builder("logback_logger_events")
.tag("logger", loggerName)
.tag("level", level)
.register(registry);
}
/**
* Based on https://github.com/prometheus/client_java/blob/master/simpleclient_logback/src/main/java/io/prometheus/client/logback/InstrumentedAppender.java
*/
private class MetricsAppender extends UnsynchronizedAppenderBase {
@Override
public void start() {
super.start();
}
@Override
protected void append(ILoggingEvent event) {
if (excludedLoggerNameSet.contains(event.getLoggerName())) return;
try {
switch (event.getLevel().toInt()) {
case Level.TRACE_INT:
traceCounter.increment();
break;
case Level.DEBUG_INT:
debugCounter.increment();
break;
case Level.INFO_INT:
infoCounter.increment();
break;
case Level.WARN_INT:
warnCounter.increment();
break;
case Level.ERROR_INT:
errorCounter.increment();
break;
default:
break;
}
} catch (Exception e) {
// Guard against increment-exceptions causing more logging (however unlikely)
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy