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

io.airlift.log.SocketMessageOutput Maven / Gradle / Ivy

The newest version!
package io.airlift.log;

import com.google.common.net.HostAndPort;
import com.google.errorprone.annotations.concurrent.GuardedBy;
import org.weakref.jmx.Managed;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.concurrent.atomic.AtomicLong;

import static java.util.Objects.requireNonNull;

public class SocketMessageOutput
        implements MessageOutput
{
    private static final int CONNECTION_TIMEOUT_MILLIS = 100;
    private static final int MAX_WRITE_ATTEMPTS_PER_MESSAGE = 5;

    private final InetSocketAddress socketAddress;
    private final AtomicLong failedConnections = new AtomicLong(0);

    @GuardedBy("this")
    private Socket socket;
    @GuardedBy("this")
    private OutputStream currentOutputStream;

    SocketMessageOutput(HostAndPort hostAndPort)
    {
        requireNonNull(hostAndPort, "hostAndPort is null");
        this.socketAddress = new InetSocketAddress(hostAndPort.getHost(), hostAndPort.getPort());
    }

    @Override
    public synchronized void writeMessage(byte[] message)
            throws IOException
    {
        IOException lastException = null;
        boolean success = false;
        int connectionFailures = 0;
        for (int i = 0; i < MAX_WRITE_ATTEMPTS_PER_MESSAGE; i++) {
            if (socket == null || socket.isClosed() || currentOutputStream == null) {
                try {
                    socket = new Socket();
                    socket.connect(socketAddress, CONNECTION_TIMEOUT_MILLIS);
                    currentOutputStream = socket.getOutputStream();
                }
                catch (IOException e) {
                    socket.close();
                    socket = null;
                    currentOutputStream = null;
                    lastException = e;
                    connectionFailures++;
                    continue;
                }
            }

            try {
                currentOutputStream.write(message);
                success = true;
                break;
            }
            catch (IOException e) {
                socket.close();
                socket = null;
                currentOutputStream = null;
                connectionFailures++;
                lastException = e;
            }
        }

        if (connectionFailures > 0) {
            failedConnections.addAndGet(connectionFailures);
            if (!success) {
                throw new IOException(
                        "Exception caught connecting via socket to %s:%s. There were %s failures attempting to write the log message.".formatted(
                                socketAddress.getHostName(),
                                socketAddress.getPort(),
                                connectionFailures),
                        lastException);
            }
        }
    }

    @Override
    public synchronized void flush()
            throws IOException
    {
        if (currentOutputStream != null) {
            currentOutputStream.flush();
        }
    }

    @Override
    public synchronized void close()
            throws IOException
    {
        IOException exception = new IOException("Exception thrown attempting to close the output stream and socket.");

        if (currentOutputStream != null) {
            try {
                currentOutputStream.flush();
            }
            catch (IOException e) {
                exception.addSuppressed(e);
            }
            try {
                currentOutputStream.close();
            }
            catch (IOException e) {
                exception.addSuppressed(e);
            }
        }

        currentOutputStream = null;

        if (socket != null) {
            try {
                socket.close();
            }
            catch (IOException e) {
                exception.addSuppressed(e);
            }
        }

        socket = null;

        if (exception.getSuppressed().length > 0) {
            throw exception;
        }
    }

    @Managed
    public long getFailedConnections()
    {
        return failedConnections.get();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy