001/*
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2026, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v2.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.core.net;
015
016import ch.qos.logback.core.util.CloseUtil;
017
018import java.io.ByteArrayOutputStream;
019import java.io.IOException;
020import java.io.OutputStream;
021import java.net.DatagramPacket;
022import java.net.DatagramSocket;
023import java.net.InetAddress;
024import java.net.SocketException;
025import java.net.UnknownHostException;
026
027/**
028 * SyslogOutputStream is a wrapper around the {@link DatagramSocket} class so
029 * that it behaves like an {@link OutputStream}.
030 */
031public class SyslogOutputStream extends OutputStream {
032
033    /**
034     * The maximum length after which we discard the existing string buffer and
035     * start anew.
036     */
037    private static final int MAX_LEN = 1024;
038
039    private InetAddress address;
040    private DatagramSocket ds;
041    private ByteArrayOutputStream baos = new ByteArrayOutputStream();
042    final private int port;
043
044    public SyslogOutputStream(String syslogHost, int port) throws UnknownHostException, SocketException {
045        this.address = InetAddress.getByName(syslogHost);
046        this.port = port;
047        this.ds = new DatagramSocket();
048    }
049
050    boolean isInvalidState() {
051        if(ds == null || baos == null || address == null) {
052            return true;
053        }
054        return false;
055    }
056
057    public void write(byte[] byteArray, int offset, int len) throws IOException {
058        if(isInvalidState()) return;
059        baos.write(byteArray, offset, len);
060    }
061
062    public void flush() throws IOException {
063        if(isInvalidState()) return;
064        byte[] bytes = baos.toByteArray();
065        DatagramPacket packet = new DatagramPacket(bytes, bytes.length, address, port);
066
067        // clean up for next round
068        if (baos.size() > MAX_LEN) {
069            baos = new ByteArrayOutputStream();
070        } else {
071            baos.reset();
072        }
073
074        // after a failure, it can happen that bytes.length is zero
075        // in that case, there is no point in sending out an empty message/
076        if (bytes.length == 0) {
077            return;
078        }
079        if (this.ds != null) {
080            ds.send(packet);
081        }
082
083    }
084
085    @Override
086    public void close() {
087        CloseUtil.closeQuietly(ds);
088        CloseUtil.closeQuietly(baos);
089        address = null;
090        ds = null;
091        baos = null;
092    }
093
094    public int getPort() {
095        return port;
096    }
097
098    @Override
099    public void write(int b) throws IOException {
100        baos.write(b);
101    }
102
103    int getSendBufferSize() throws SocketException {
104        return ds.getSendBufferSize();
105    }
106}