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

nebula.plugin.metrics.collector.LogbackCollector Maven / Gradle / Ivy

/*
 * Copyright 2015 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 nebula.plugin.metrics.collector;

import nebula.plugin.metrics.MetricsPluginExtension;
import nebula.plugin.metrics.dispatcher.MetricsDispatcher;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.classic.spi.TurboFilterList;
import ch.qos.logback.classic.turbo.TurboFilter;
import ch.qos.logback.core.spi.FilterReply;
import com.google.common.base.Supplier;
import com.google.common.util.concurrent.Service;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * Collector that intercepts Logback events by binding an appender to a provided {@link Logger}.
 *
 * @author Danny THomas
 */
public class LogbackCollector {
    /**
     * Thread local to prevent stack overflows when logging statements within the event dispatcher chain log while
     * processing another event.
     */
    private static final ThreadLocal IN_FILTER = new ThreadLocal() {
        @Override
        protected Boolean initialValue() {
            return false;
        }
    };

    /**
     * Logging marker to indicate messages that should be collected, regardless of logging level.
     */
    private static final Marker MARKER = MarkerFactory.getMarker("metrics");

    /**
     * Configure a logback filter to capture all root logging events.
     * 

* Avoids having to depend on a particular Gradle logging level being set. Gradle's logging is such that * encoders/layouts/etc aren't an option and LogbackLoggingConfigurer.doConfigure() adds a TurboFilter which * prevents us getting at those events, so we re-wire the filters so ours comes first. */ public static void configureLogbackCollection(final Supplier dispatcherSupplier, final MetricsPluginExtension extension) { checkNotNull(dispatcherSupplier); checkNotNull(extension); final BlockingQueue logbackEvents = new LinkedBlockingQueue<>(); TurboFilter metricsFilter = new TurboFilter() { @Override public FilterReply decide(Marker marker, Logger logger, Level level, String s, Object[] objects, Throwable throwable) { if (IN_FILTER.get()) { return FilterReply.NEUTRAL; } try { IN_FILTER.set(true); if (level.isGreaterOrEqual(extension.getLogLevel()) || MARKER.equals(marker)) { LoggingEvent event = new LoggingEvent(Logger.class.getCanonicalName(), logger, level, s, throwable, objects); MetricsDispatcher dispatcher = dispatcherSupplier.get(); if (dispatcher.state() == Service.State.NEW || dispatcher.state() == Service.State.STARTING) { logbackEvents.add(event); } else { if (!logbackEvents.isEmpty()) { for (LoggingEvent loggingEvent : logbackEvents) { dispatcher.logbackEvent(loggingEvent); } } dispatcher.logbackEvent(event); } } return FilterReply.NEUTRAL; } finally { IN_FILTER.set(false); } } }; LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); TurboFilterList filterList = context.getTurboFilterList(); if (!filterList.isEmpty()) { TurboFilter gradleFilter = filterList.get(0); context.resetTurboFilterList(); context.addTurboFilter(metricsFilter); context.addTurboFilter(gradleFilter); } else { context.resetTurboFilterList(); context.addTurboFilter(metricsFilter); } } public static void resetLogbackCollection() { LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); TurboFilterList filterList = context.getTurboFilterList(); if (filterList.size() == 2) { TurboFilter gradleFilter = filterList.get(1); context.resetTurboFilterList(); context.addTurboFilter(gradleFilter); } else { assert filterList.size() == 1 : "Expected 1 filter to be registered, found " + filterList.size(); context.resetTurboFilterList(); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy