All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openapitools.codegen.utils.OnceLogger Maven / Gradle / Ivy

The newest version!
package org.openapitools.codegen.utils;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.Ticker;
import org.openapitools.codegen.config.GlobalSettings;
import org.slf4j.Logger;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
import org.slf4j.ext.LoggerWrapper;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Provides calling code a way to log important messages only once, regardless of how many times the invocation has occurred.
 * This can be used, for instance, to log a warning like "One or more schemas aren't declared" without logging that message
 * for every time the schema is mentioned in a document.
 * 

* This implementation currently only supports single-argument string literal log methods (e.g. {@link Logger#debug(String)}). */ @SuppressWarnings("FieldCanBeLocal") public class OnceLogger extends LoggerWrapper { /** * Allow advanced users to modify cache size of the OnceLogger (more for performance tuning in hosted environments) */ static final String CACHE_SIZE_PROPERTY = "org.openapitools.codegen.utils.oncelogger.cachesize"; /** * Allow advanced users to disable the OnceLogger (more for performance tuning in hosted environments). * This is really only useful or necessary if this implementation causes issues. */ static final String ENABLE_ONCE_LOGGER_PROPERTY = "org.openapitools.codegen.utils.oncelogger.enabled"; /** * Allow advanced users to modify cache expiration of the OnceLogger (more for performance tuning in hosted environments) */ static final String EXPIRY_PROPERTY = "org.openapitools.codegen.utils.oncelogger.expiry"; /** * Internal message cache for logger decorated with the onceler. */ static Cache messageCountCache; /** * The fully qualified class name of the logger instance, * typically the logger class, logger bridge or a logger wrapper. */ private static final String FQCN = OnceLogger.class.getName(); /** * Gets the marker instance. This can be used by supported log implementations to filter/manage logs coming from * this implementation differently than others (i.e. make them stand out since they're to be logged once). */ private static final Marker MARKER = MarkerFactory.getMarker("ONCE"); /** * The allowed size of the cache. */ private static int maxCacheSize = Integer.parseInt(GlobalSettings.getProperty(CACHE_SIZE_PROPERTY, "200")); /** * The millis to expire a cached log message. */ private static int expireMillis = Integer.parseInt(GlobalSettings.getProperty(EXPIRY_PROPERTY, "2000")); /** * The number of allowed repetitions. */ private static int maxRepetitions = 1; OnceLogger(Logger logger) { this(logger, FQCN); } OnceLogger(Logger logger, String fqcn) { super(logger, fqcn); } static { caffeineCache(Ticker.systemTicker(), expireMillis); } static void caffeineCache(Ticker ticker, int expireMillis) { // Initializes a cache which holds an atomic counter of log message instances. // The intent is to debounce log messages such that they occur at most [maxRepetitions] per [expireMillis]. messageCountCache = Caffeine.newBuilder() .maximumSize(maxCacheSize) .expireAfterWrite(expireMillis, TimeUnit.MILLISECONDS) .ticker(ticker) .build(); } public static Logger once(Logger logger) { try { if (Boolean.parseBoolean(GlobalSettings.getProperty(ENABLE_ONCE_LOGGER_PROPERTY, "true"))) { return new OnceLogger(logger); } } catch (Exception ex) { logger.warn("Unable to wrap logger instance in OnceLogger. Falling back to non-decorated implementation, which may be noisy."); } return logger; } /** * Delegate to the appropriate method of the underlying logger. * * @param msg The log message. */ @Override public void trace(String msg) { if (!isTraceEnabled() || !isTraceEnabled(MARKER)) return; if (shouldLog(msg)) super.trace(MARKER, msg); } @SuppressWarnings("ConstantConditions") private boolean shouldLog(final String msg) { AtomicInteger counter = messageCountCache.get(msg, i -> new AtomicInteger(0)); return counter.incrementAndGet() <= maxRepetitions; } /** * Delegate to the appropriate method of the underlying logger. * * @param msg The log message. */ @Override public void debug(String msg) { if (!isDebugEnabled() || !isDebugEnabled(MARKER)) return; if (shouldLog(msg)) super.debug(MARKER, msg); } /** * Delegate to the appropriate method of the underlying logger. * * @param msg The log message. */ @Override public void info(String msg) { if (!isInfoEnabled() || !isInfoEnabled(MARKER)) return; if (shouldLog(msg)) super.info(MARKER, msg); } /** * Delegate to the appropriate method of the underlying logger. * * @param msg The log message. */ @Override public void warn(String msg) { if (!isWarnEnabled() || !isWarnEnabled(MARKER)) return; if (shouldLog(msg)) super.warn(MARKER, msg); } /** * Delegate to the appropriate method of the underlying logger. *

* Use this method sparingly. If you're limiting error messages, ask yourself * whether your log fits better as a warning. * * @param msg The log message. */ @Override public void error(String msg) { if (!isErrorEnabled() || !isErrorEnabled(MARKER)) return; if (shouldLog(msg)) super.error(MARKER, msg); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy