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

io.fluxcapacitor.javaclient.common.logging.FluxCapacitorLogbackAppender Maven / Gradle / Ivy

There is a newer version: 0.1072.0
Show newest version
/*
 * Copyright (c) Flux Capacitor IP B.V. or its affiliates. All Rights Reserved.
 *
 * 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 io.fluxcapacitor.javaclient.common.logging;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.filter.LevelFilter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.ThrowableProxy;
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.AppenderBase;
import ch.qos.logback.core.Context;
import io.fluxcapacitor.common.api.Metadata;
import io.fluxcapacitor.javaclient.FluxCapacitor;
import io.fluxcapacitor.javaclient.common.ClientUtils;
import io.fluxcapacitor.javaclient.common.serialization.DeserializingMessage;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;

import static java.lang.String.format;
import static java.util.Optional.ofNullable;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace;

@Slf4j
public class FluxCapacitorLogbackAppender extends AppenderBase {

    public static void attach() {
        Context loggerContext = (Context) LoggerFactory.getILoggerFactory();
        FluxCapacitorLogbackAppender appender = new FluxCapacitorLogbackAppender();
        LevelFilter filter = new LevelFilter();
        filter.setLevel(Level.WARN);
        appender.addFilter(filter);
        appender.setContext(loggerContext);
        appender.start();
        Logger rootLogger = getRootLogger();
        rootLogger.addAppender(appender);
    }

    public static void detach() {
        Logger rootLogger = getRootLogger();
        Iterator> iterator = rootLogger.iteratorForAppenders();
        List> appenders = new ArrayList<>();
        while (iterator.hasNext()) {
            Appender appender = iterator.next();
            if (appender instanceof FluxCapacitorLogbackAppender) {
                appenders.add(appender);
            }
        }
        appenders.forEach(rootLogger::detachAppender);
    }

    @Override
    protected void append(ILoggingEvent event) {
        try {
            if (!event.getLevel().isGreaterOrEqual(Level.WARN)) {
                return;
            }
            Optional throwable =
                    ofNullable((ThrowableProxy) event.getThrowableProxy()).map(ThrowableProxy::getThrowable);
            if (ignoreEvent(event)) {
                String errorMessage = "Ignoring error: %s".formatted(event.getFormattedMessage());
                throwable.ifPresentOrElse(e -> log.info(errorMessage, e), () -> log.info(errorMessage));
                return;
            }
            Metadata metadata = ofNullable(DeserializingMessage.getCurrent())
                    .map(DeserializingMessage::getMetadata).orElse(Metadata.empty());
            metadata = metadata.with(
                    "stackTrace", format("[%s] %s %s - %s%s", event.getThreadName(), event.getLevel(),
                                         event.getLoggerName(), event.getFormattedMessage(),
                                         throwable.map(e -> "\n" + getStackTrace(e)).orElse("")),
                    "level", event.getLevel().toString(),
                    "loggerName", event.getLoggerName(),
                    "messageTemplate", event.getMessage());
            if (throwable.isPresent()) {
                Throwable e = throwable.get();
                metadata = metadata.with(
                        "error", e.getClass().getSimpleName(),
                        "message", event.getFormattedMessage(),
                        "errorMessage", isBlank(e.getMessage()) ? event.getFormattedMessage() : e.getMessage());
                StackTraceElement[] stackTraceElements =
                        ofNullable(e.getStackTrace()).filter(s -> s.length > 0).orElse(null);
                if (stackTraceElements != null) {
                    metadata = metadata.with(
                            "traceElement", stackTraceElements[0].toString());
                }
            } else {
                metadata = metadata.with(
                        "message", event.getFormattedMessage(), "errorMessage", event.getFormattedMessage());
            }
            FluxCapacitor.get().errorGateway().report(
                    event.getLevel() == Level.WARN ? new ConsoleWarning() : new ConsoleError(), metadata);
        } catch (Throwable e) {
            log.info("Failed to publish console error", e);
        }
    }

    protected boolean ignoreEvent(ILoggingEvent event) {
        return Optional.ofNullable(event.getMarkerList()).map(markers -> markers.stream().anyMatch(
                m -> m.contains(ClientUtils.ignoreMarker))).orElse(false);
    }

    private static Logger getRootLogger() {
        return (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy