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

com.netflix.spectator.log4j.SpectatorAppender Maven / Gradle / Ivy

There is a newer version: 1.8.2
Show newest version
/*
 * Copyright 2014-2019 Netflix, Inc.
 *
 * 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 com.netflix.spectator.log4j;

import com.netflix.spectator.api.Id;
import com.netflix.spectator.api.Registry;
import com.netflix.spectator.api.Spectator;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.config.Property;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;

import java.io.Serializable;

/**
 * Appender that tracks the number of messages that pass through. If the {@code ignoreExceptions}
 * option is set to false, a more detailed counter for the number of stack traces with the
 * exception types and file will also get tracked.
 */
@Plugin(name = "Spectator", category = "Core", elementType = "appender", printObject = true)
public final class SpectatorAppender extends AbstractAppender {

  private static void addToRootLogger(final Appender appender) {
    LoggerContext context = (LoggerContext) LogManager.getContext(false);
    Configuration config = context.getConfiguration();
    LoggerConfig loggerConfig = config.getLoggerConfig(LogManager.ROOT_LOGGER_NAME);
    loggerConfig.addAppender(appender, Level.ALL, null);
    context.updateLoggers(config);
  }

  /**
   * Add the spectator appender to the root logger. This method is intended to be called once
   * as part of the applications initialization process.
   *
   * @param registry
   *     Spectator registry to use for the appender.
   * @param name
   *     Name for the appender.
   * @param ignoreExceptions
   *     If set to true then the stack trace metrics are disabled.
   */
  public static void addToRootLogger(
      Registry registry,
      String name,
      boolean ignoreExceptions) {
    final Appender appender = new SpectatorAppender(
        registry, name, null, null, ignoreExceptions, Property.EMPTY_ARRAY);
    appender.start();

    LoggerContext context = (LoggerContext) LogManager.getContext(false);
    Configuration config = context.getConfiguration();

    addToRootLogger(appender);
    config.addListener(reconfigurable -> addToRootLogger(appender));
  }

  private static final long serialVersionUID = 42L;

  private final transient Registry registry;
  private transient Id[] numMessages;
  private transient Id[] numStackTraces;

  /** Create a new instance of the appender. */
  SpectatorAppender(
      Registry registry,
      String name,
      Filter filter,
      Layout layout,
      boolean ignoreExceptions,
      Property[] properties) {
    super(name, filter, layout, ignoreExceptions, properties);
    this.registry = registry;
  }

  /** Create a new instance of the appender using the global spectator registry. */
  @PluginFactory
  public static SpectatorAppender createAppender(
      @PluginAttribute("name") String name,
      @PluginAttribute("ignoreExceptions") boolean ignoreExceptions,
      @PluginElement("Layout") Layout layout,
      @PluginElement("Filters") Filter filter) {

    if (name == null) {
      LOGGER.error("no name provided for SpectatorAppender");
      return null;
    }

    return new SpectatorAppender(
        Spectator.globalRegistry(),
        name, filter, layout, ignoreExceptions,
        Property.EMPTY_ARRAY);
  }

  @Override public void start() {
    final LevelTag[] levels = LevelTag.values();
    numMessages = new Id[levels.length];
    numStackTraces = new Id[levels.length];
    for (int i = 0; i < levels.length; ++i) {
      numMessages[i] = registry.createId("log4j.numMessages")
          .withTag("appender", getName())
          .withTag(levels[i]);
      numStackTraces[i] = registry.createId("log4j.numStackTraces")
          .withTag("appender", getName())
          .withTag(levels[i]);
    }
    super.start();
  }

  @Override public void append(LogEvent event) {
    final LevelTag level = LevelTag.get(event.getLevel());
    registry.counter(numMessages[level.ordinal()]).increment();
    if (!ignoreExceptions() && event.getThrown() != null) {
      final String file = (event.getSource() == null) ? "unknown" : event.getSource().getFileName();
      Id stackTraceId = numStackTraces[level.ordinal()]
          .withTag("exception", event.getThrown().getClass().getSimpleName())
          .withTag("file", file);
      registry.counter(stackTraceId).increment();
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy