package ru.yandex.webmaster3.core.util.qloud;

import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.classic.spi.ThrowableProxy;
import net.logstash.logback.appender.LogstashTcpSocketAppender;

public class QloudRemoteAppender extends LogstashTcpSocketAppender {
    private static final String ENV_BUFSIZE = "QLOUD_LOGGER_BUFFER_SIZE";
    private static final String ENV_MSGSIZE = "QLOUD_LOGGER_MESSAGE_SIZE";
    private static final String ENV_HOST = "QLOUD_LOGGER_HOST";
    private static final String ENV_PORT = "QLOUD_LOGGER_PORT";

    private static final int DEFAULT_STATUSREPORT_FREQ = 100;

    private static final int DEFAULT_RING_BUFFER_SIZE = 8192;
    private static final int DEFAULT_MESSAGE_SIZE = 8192;

    private int messageSize = DEFAULT_MESSAGE_SIZE;

    private final AtomicLong consecutiveTruncCount = new AtomicLong();

    @Override
    public synchronized void start() {
        if (isStarted()) {
            return;
        }
        Map<String, String> env = System.getenv();
        if (env.containsKey(ENV_MSGSIZE)) {
            messageSize = Integer.valueOf(env.get(ENV_MSGSIZE));
        }
        int ringBufferSize = DEFAULT_RING_BUFFER_SIZE;
        if (env.containsKey(ENV_BUFSIZE)) {
            ringBufferSize = Integer.valueOf(env.get(ENV_BUFSIZE));
        }
        setRingBufferSize(ringBufferSize);
        setDroppedWarnFrequency(DEFAULT_STATUSREPORT_FREQ);
        setEncoder(new QloudRemoteEncoder(env));
        setRemoteHost(env.get(ENV_HOST));
        setPort(Integer.valueOf(env.get(ENV_PORT)));
        super.start();
    }

    @Override
    protected void append(ILoggingEvent origEvent) {
        origEvent.prepareForDeferredProcessing();

        final LoggingEvent event = new LoggingEvent();
        event.setLoggerName(origEvent.getLoggerName());
        event.setLoggerContextRemoteView(origEvent.getLoggerContextVO());
        event.setLevel(origEvent.getLevel());
        event.setThrowableProxy((ThrowableProxy) origEvent.getThrowableProxy());
        event.setTimeStamp(origEvent.getTimeStamp());
        event.setCallerData(origEvent.getCallerData());
        event.setMarker(origEvent.getMarker());
        event.setMDCPropertyMap(origEvent.getMDCPropertyMap());

        final String formattedMessage = origEvent.getFormattedMessage();
        if (formattedMessage != null && formattedMessage.length() > messageSize) {
            long consecutiveTruncated = consecutiveTruncCount.incrementAndGet();
            if ((consecutiveTruncated) % DEFAULT_STATUSREPORT_FREQ == 1) {
                addWarn("Truncated " + consecutiveTruncated + " events (and counting...) due to max message size [" + messageSize + "]");
            }
            event.setMessage(formattedMessage.substring(0, messageSize) + "...");
        } else {
            event.setMessage(formattedMessage);
        }

        super.append(event);
    }

}
