package com.atlassian.bitbucket.mesh.logback;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.turbo.TurboFilter;
import ch.qos.logback.core.spi.FilterReply;
import com.google.common.annotations.VisibleForTesting;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;

import java.util.Locale;

/**
 * A {@link TurboFilter} that adjusts logging levels for messages that are considered not worth logging at the level
 * they were originally logged at.
 */
public class KnownMessageLevelAdjustingFilter extends TurboFilter {

    @VisibleForTesting
    static final Marker FILTERED = MarkerFactory.getDetachedMarker("mesh.filtered");

    @Override
    public FilterReply decide(Marker marker, Logger logger, Level level, String format, Object[] params, Throwable t) {
        if (FILTERED.equals(marker)) {
            return FilterReply.NEUTRAL;
        }
        //This filter needs to be fast as it is invoked for every single log message at every level.
        if (Level.WARN.equals(level) && logger != null && format != null) {
            String name = logger.getName();
            if ("io.grpc.netty.NettyServerHandler".equals(name)) {
                String lower = format.toLowerCase(Locale.ROOT);
                //When a streaming call is canceled, gRPC can race between the underlying stream closing and the server
                //trying to dispatch a last message. That race results in gRPC logging a warning. Since there isn't much
                //we can do about this, we reduce the level of that log message to DEBUG.
                if (lower.contains("stream error")) {
                    logger.debug(FILTERED, format, params, t);
                    return FilterReply.DENY;
                }
            }
        }
        return FilterReply.NEUTRAL;
    }
}
