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

me.moocar.logback.net.SocketEncoderAppender Maven / Gradle / Ivy

Go to download

A Logback Appender that encodes logs using an Encoder, and sends the result to a remote host over TCP

The newest version!
package me.moocar.logback.net;

import ch.qos.logback.core.OutputStreamAppender;
import ch.qos.logback.core.net.DefaultSocketConnector;
import ch.qos.logback.core.net.SocketConnector;
import ch.qos.logback.core.util.CloseUtil;
import ch.qos.logback.core.util.Duration;

import javax.net.SocketFactory;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.*;

public class SocketEncoderAppender extends OutputStreamAppender implements SocketConnector.ExceptionHandler{

    /**
     * Default timeout when waiting for the remote server to accept our
     * connection.
     */
    private static final int DEFAULT_ACCEPT_CONNECTION_DELAY = 1000;

    /**
     * Default timeout for how long to wait when inserting an event into
     * the BlockingQueue.
     */
    private static final int DEFAULT_EVENT_DELAY_TIMEOUT = 100;

    /**
     * Default size of the deque used to hold logging events that are destined
     * for the remote peer.
     */
    public static final int DEFAULT_QUEUE_SIZE = 128;

    private static final String DEFAULT_REMOTE_HOST = "localhost";

    private int port;
    private String remoteHost = DEFAULT_REMOTE_HOST;
    private InetAddress address;

    private int acceptConnectionTimeout = DEFAULT_ACCEPT_CONNECTION_DELAY;

    private String peerId;
    private SocketConnector connector;
    private Future task;

    private int queueSize = DEFAULT_QUEUE_SIZE;
    private BlockingDeque deque;
    private Duration eventDelayLimit = new Duration(DEFAULT_EVENT_DELAY_TIMEOUT);

    private volatile Socket socket;

    @Override
    public void start() {
        if (isStarted()) return;
        int errorCount = 0;
        if (port <= 0) {
            errorCount++;
            addError("No port was configured for appender" + name);
        }

        if (remoteHost == null) {
            errorCount++;
            addError("No remote host was configured for appender" + name);
        }

        if (errorCount == 0) {
            try {
                address = InetAddress.getByName(remoteHost);
            } catch (UnknownHostException ex) {
                addError("unknown host: " + remoteHost);
                errorCount++;
            }
        }

        final FutureTask connectionFuture = new FutureTask(new Callable() {
            @Override
            public Boolean call() throws Exception {
                return true;
            }
        });

        if (errorCount == 0) {
            deque = new LinkedBlockingDeque(queueSize);
            peerId = "remote peer " + remoteHost + ":" + port + ": ";
            connector = createConnector(address, port, 0, 1000);
            task = getContext().getExecutorService().submit(new Runnable() {
                @Override
                public void run() {
                    connectSocketAndDispatchEvents(connectionFuture);
                }
            });
        }

        try {
            connectionFuture.get();
            super.start();
        } catch (InterruptedException e) {

        } catch (ExecutionException e) {

        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void stop() {
        if (!isStarted()) return;
        CloseUtil.closeQuietly(socket);
        task.cancel(true);
        super.stop();
    }

    private SocketConnector createConnector(InetAddress address, int port, int initialDelay, long retryDelay) {
        SocketConnector connector = newConnector(address, port, initialDelay, retryDelay);
        connector.setExceptionHandler(this);
        connector.setSocketFactory(getSocketFactory());
        return connector;
    }

    protected SocketConnector newConnector(InetAddress address, int port, long initialDelay, long retryDelay) {
        return new DefaultSocketConnector(address, port, initialDelay, retryDelay);
    }

    /**
     * Gets the default {@link SocketFactory} for the platform.
     * 

* Subclasses may override to provide a custom socket factory. */ protected SocketFactory getSocketFactory() { return SocketFactory.getDefault(); } private void connectSocketAndDispatchEvents(FutureTask connectionFuture) { try { while (socketConnectionCouldBeEstablished()) { try { socket.setSoTimeout(acceptConnectionTimeout); setOutputStream(socket.getOutputStream()); connectionFuture.run(); addInfo(peerId + "connection established"); dispatchEvents(); } catch (IOException ex) { addInfo(peerId + "connection failed: " + ex); } catch (Exception e) { addError("Error in connect loop", e); } finally { CloseUtil.closeQuietly(socket); socket = null; super.closeOutputStream(); addInfo(peerId + "connection closed"); } } } catch (InterruptedException ex) { assert true; // ok... we'll exit now } addInfo("shutting down"); } private void dispatchEvents() throws InterruptedException, IOException { while (true) { E event = deque.takeFirst(); super.subAppend(event); this.getOutputStream().write('\0'); } } @Override protected void subAppend(E event) { if (event == null || !isStarted()) return; try { final boolean inserted = deque.offer(event, eventDelayLimit.getMilliseconds(), TimeUnit.MILLISECONDS); if (!inserted) { addInfo("Dropping event due to timeout limit of [" + eventDelayLimit + "] being exceeded"); } } catch (InterruptedException e) { addError("Interrupted while appending event to SocketAppender", e); } } private boolean socketConnectionCouldBeEstablished() throws InterruptedException { return (socket = connector.call()) != null; } @Override public void connectionFailed(SocketConnector socketConnector, Exception ex) { if (ex instanceof InterruptedException) { addInfo("connector interrupted"); } else if (ex instanceof ConnectException) { addInfo(peerId + "connection refused"); } else { addInfo(peerId + ex); } } public int getPort() { return this.port; } public void setPort(int port) { this.port = port; } public String getRemoteHost() { return remoteHost; } public void setRemoteHost(String remoteHost) { this.remoteHost = remoteHost; } public int getQueueSize() { return queueSize; } public void setQueueSize(int queueSize) { this.queueSize = queueSize; } public int getAcceptConnectionTimeout() { return acceptConnectionTimeout; } public void setAcceptConnectionTimeout(int acceptConnectionTimeout) { this.acceptConnectionTimeout = acceptConnectionTimeout; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy