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

com.wavefront.agent.logsharvesting.LogsIngestionConfigManager Maven / Gradle / Ivy

There is a newer version: 4.36
Show newest version
package com.wavefront.agent.logsharvesting;

import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.annotations.VisibleForTesting;
import com.wavefront.agent.config.ConfigurationException;
import com.wavefront.agent.config.LogsIngestionConfig;
import com.wavefront.agent.config.MetricMatcher;
import com.yammer.metrics.Metrics;
import com.yammer.metrics.core.Counter;
import com.yammer.metrics.core.MetricName;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Wrapper for a {@link LogsIngestionConfig} that supports hot-loading and removal notifications.
 *
 * @author Mori Bellamy ([email protected])
 */
public class LogsIngestionConfigManager {
  protected static final Logger logger =
      Logger.getLogger(LogsIngestionConfigManager.class.getCanonicalName());
  private static final Counter configReloads =
      Metrics.newCounter(new MetricName("logsharvesting", "", "config-reloads.successful"));
  private static final Counter failedConfigReloads =
      Metrics.newCounter(new MetricName("logsharvesting", "", "config-reloads.failed"));
  private LogsIngestionConfig lastParsedConfig;
  // The only key in this cache is "true". Basically we want the cache expiry and reloading logic.
  private final LoadingCache logsIngestionConfigLoadingCache;
  private final Consumer removalListener;

  public LogsIngestionConfigManager(
      Supplier logsIngestionConfigSupplier,
      Consumer removalListener)
      throws ConfigurationException {
    this.removalListener = removalListener;
    lastParsedConfig = logsIngestionConfigSupplier.get();
    if (lastParsedConfig == null)
      throw new ConfigurationException("Could not load initial config.");
    lastParsedConfig.verifyAndInit();
    this.logsIngestionConfigLoadingCache =
        Caffeine.newBuilder()
            .expireAfterWrite(lastParsedConfig.configReloadIntervalSeconds, TimeUnit.SECONDS)
            .build(
                (ignored) -> {
                  LogsIngestionConfig nextConfig = logsIngestionConfigSupplier.get();
                  if (nextConfig == null) {
                    logger.warning("Unable to reload logs ingestion config file!");
                    failedConfigReloads.inc();
                  } else if (!lastParsedConfig.equals(nextConfig)) {
                    nextConfig.verifyAndInit(); // If it throws, we keep the last
                    // (good) config.
                    processConfigChange(nextConfig);
                    logger.info("Loaded new config: " + lastParsedConfig.toString());
                    configReloads.inc();
                  }
                  return lastParsedConfig;
                });

    // Force reload every N seconds.
    new Timer("Timer-logsingestion-configmanager")
        .schedule(
            new TimerTask() {
              @Override
              public void run() {
                try {
                  logsIngestionConfigLoadingCache.get(true);
                } catch (Exception e) {
                  logger.log(Level.SEVERE, "Cannot load a new logs ingestion config.", e);
                }
              }
            },
            lastParsedConfig.aggregationIntervalSeconds,
            lastParsedConfig.aggregationIntervalSeconds);
  }

  public LogsIngestionConfig getConfig() {
    return logsIngestionConfigLoadingCache.get(true);
  }

  /** Forces the next call to {@link #getConfig()} to call the config supplier. */
  @VisibleForTesting
  public void forceConfigReload() {
    logsIngestionConfigLoadingCache.invalidate(true);
  }

  private void processConfigChange(LogsIngestionConfig nextConfig) {
    if (nextConfig.useWavefrontHistograms != lastParsedConfig.useWavefrontHistograms) {
      logger.warning(
          "useWavefrontHistograms property cannot be changed at runtime, "
              + "proxy restart required!");
    }
    if (nextConfig.useDeltaCounters != lastParsedConfig.useDeltaCounters) {
      logger.warning(
          "useDeltaCounters property cannot be changed at runtime, " + "proxy restart required!");
    }
    if (nextConfig.reportEmptyHistogramStats != lastParsedConfig.reportEmptyHistogramStats) {
      logger.warning(
          "reportEmptyHistogramStats property cannot be changed at runtime, "
              + "proxy restart required!");
    }
    if (!nextConfig.aggregationIntervalSeconds.equals(
        lastParsedConfig.aggregationIntervalSeconds)) {
      logger.warning(
          "aggregationIntervalSeconds property cannot be changed at runtime, "
              + "proxy restart required!");
    }
    if (nextConfig.configReloadIntervalSeconds != lastParsedConfig.configReloadIntervalSeconds) {
      logger.warning(
          "configReloadIntervalSeconds property cannot be changed at runtime, "
              + "proxy restart required!");
    }
    if (nextConfig.expiryMillis != lastParsedConfig.expiryMillis) {
      logger.warning(
          "expiryMillis property cannot be changed at runtime, " + "proxy restart required!");
    }
    for (MetricMatcher oldMatcher : lastParsedConfig.counters) {
      if (!nextConfig.counters.contains(oldMatcher)) removalListener.accept(oldMatcher);
    }
    for (MetricMatcher oldMatcher : lastParsedConfig.gauges) {
      if (!nextConfig.gauges.contains(oldMatcher)) removalListener.accept(oldMatcher);
    }
    for (MetricMatcher oldMatcher : lastParsedConfig.histograms) {
      if (!nextConfig.histograms.contains(oldMatcher)) removalListener.accept(oldMatcher);
    }
    lastParsedConfig = nextConfig;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy