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

org.apache.juli.logging.net.logstash.logback.appender.listener.FailureSummaryAppenderListener Maven / Gradle / Ivy

/*
 * Copyright 2013-2023 the original author or authors.
 *
 * 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 org.apache.juli.logging.net.logstash.logback.appender.listener;

import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;

import org.apache.juli.logging.ch.qos.logback.core.Appender;
import org.apache.juli.logging.ch.qos.logback.core.spi.DeferredProcessingAware;

/**
 * A {@link TcpAppenderListener} that invokes different callbacks for
 * the first successful append/send/connect after a series of failures.
 * The callback includes a summary of the failures that occurred.
 *
 * 

Subclasses implement {@link #handleFailureSummary(FailureSummary, CallbackType)} * to define behavior when the first successful append/send/connect * occurs after a series of consecutive failures.

*/ public abstract class FailureSummaryAppenderListener implements TcpAppenderListener { /** * The current state of appending events to the appender. */ private final AtomicReference appendState = new AtomicReference<>(SUCCEEDING_STATE); /** * The current state of sending events to the TCP destination. */ private final AtomicReference sendState = new AtomicReference<>(SUCCEEDING_STATE); /** * The current state of opening TCP connections. */ private final AtomicReference connectState = new AtomicReference<>(SUCCEEDING_STATE); /** * The type of listener callback. */ public enum CallbackType { /** * Callback for appending events to the appender. */ APPEND, /** * Callback for sending events from a TCP appender. */ SEND, /** * Callback for creating TCP connections for a TCP appender. */ CONNECT } /** * Summary details of consecutive failures */ public interface FailureSummary { /** * Millisecond value of the first failue. * @return Millisecond value of the first failue. */ long getFirstFailureTime(); /** * The first failure that occurred. * @return The first failure that occurred. */ Throwable getFirstFailure(); /** * The most recent failure that occurred. * @return The most recent failure that occurred. */ Throwable getMostRecentFailure(); /** * The number of consecutive failures before a success. * @return number of consecutive failures before a success. */ long getConsecutiveFailures(); } private interface State { boolean isSucceeding(); } /** * Constant representing a state where events are succeeding. */ private static final State SUCCEEDING_STATE = () -> true; /** * A state where events are failing. */ private static class FailingState implements State, FailureSummary { private final Throwable firstThrowable; private final long firstFailureTime; private final AtomicLong consecutiveFailures = new AtomicLong(); private volatile Throwable mostRecentThrowable; private FailingState(Throwable firstThrowable) { this.firstThrowable = firstThrowable; this.firstFailureTime = System.currentTimeMillis(); recordThrowable(firstThrowable); } @Override public boolean isSucceeding() { return false; } @Override public Throwable getFirstFailure() { return firstThrowable; } @Override public long getFirstFailureTime() { return firstFailureTime; } @Override public Throwable getMostRecentFailure() { return mostRecentThrowable; } @Override public long getConsecutiveFailures() { return consecutiveFailures.get(); } private void recordThrowable(Throwable throwable) { consecutiveFailures.incrementAndGet(); mostRecentThrowable = throwable; } } @Override public void eventAppended(Appender appender, Event event, long durationInNanos) { recordSuccess(this.appendState, CallbackType.APPEND); } @Override public void eventAppendFailed(Appender appender, Event event, Throwable reason) { recordFailure(this.appendState, reason); } @Override public void eventSent(Appender appender, Socket socket, Event event, long durationInNanos) { recordSuccess(this.sendState, CallbackType.SEND); } @Override public void eventSendFailure(Appender appender, Event event, Throwable reason) { recordFailure(this.sendState, reason); } @Override public void connectionOpened(Appender appender, Socket socket) { recordSuccess(this.connectState, CallbackType.CONNECT); } @Override public void connectionFailed(Appender appender, InetSocketAddress address, Throwable reason) { recordFailure(this.connectState, reason); } private void recordSuccess(AtomicReference stateRef, CallbackType callbackType) { State currentState = stateRef.get(); if (!currentState.isSucceeding() && stateRef.compareAndSet(currentState, SUCCEEDING_STATE)) { FailingState oldFailingState = (FailingState) currentState; handleFailureSummary(oldFailingState, callbackType); } } private void recordFailure(AtomicReference stateRef, Throwable reason) { State currentState = stateRef.get(); if (currentState.isSucceeding()) { if (!stateRef.compareAndSet(currentState, new FailingState(reason))) { recordFailure(stateRef, reason); } } else { ((FailingState) currentState).recordThrowable(reason); } } /** * Called after the first success after the a series of consecutive failures. * * @param failureSummary contains summary details of all the consecutive failures * @param callbackType the type of callback (append/send/connect) */ protected abstract void handleFailureSummary(FailureSummary failureSummary, CallbackType callbackType); }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy