mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-10-30 18:22:49 -04:00 
			
		
		
		
	The vendor/ folder was created with the help of @FiloSottile's gvt and vendorcheck. Any dependencies of Caddy plugins outside this repo are not vendored. We do not remove any unused, vendored packages because vendorcheck -u only checks using the current build configuration; i.e. packages that may be imported by files toggled by build tags of other systems. CI tests have been updated to ignore the vendor/ folder. When Go 1.9 is released, a few of the go commands should be revised to again use ./... as it will ignore the vendor folder by default.
		
			
				
	
	
		
			215 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			215 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // This file is taken from the log/syslog in the standard lib.
 | |
| // However, there is a bug with overwhelming syslog that causes writes
 | |
| // to block indefinitely. This is fixed by adding a write deadline.
 | |
| //
 | |
| // +build !windows,!nacl,!plan9
 | |
| 
 | |
| package gsyslog
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"log/syslog"
 | |
| 	"net"
 | |
| 	"os"
 | |
| 	"strings"
 | |
| 	"sync"
 | |
| 	"time"
 | |
| )
 | |
| 
 | |
| const severityMask = 0x07
 | |
| const facilityMask = 0xf8
 | |
| const localDeadline = 20 * time.Millisecond
 | |
| const remoteDeadline = 50 * time.Millisecond
 | |
| 
 | |
| // A builtinWriter is a connection to a syslog server.
 | |
| type builtinWriter struct {
 | |
| 	priority syslog.Priority
 | |
| 	tag      string
 | |
| 	hostname string
 | |
| 	network  string
 | |
| 	raddr    string
 | |
| 
 | |
| 	mu   sync.Mutex // guards conn
 | |
| 	conn serverConn
 | |
| }
 | |
| 
 | |
| // This interface and the separate syslog_unix.go file exist for
 | |
| // Solaris support as implemented by gccgo.  On Solaris you can not
 | |
| // simply open a TCP connection to the syslog daemon.  The gccgo
 | |
| // sources have a syslog_solaris.go file that implements unixSyslog to
 | |
| // return a type that satisfies this interface and simply calls the C
 | |
| // library syslog function.
 | |
| type serverConn interface {
 | |
| 	writeString(p syslog.Priority, hostname, tag, s, nl string) error
 | |
| 	close() error
 | |
| }
 | |
| 
 | |
| type netConn struct {
 | |
| 	local bool
 | |
| 	conn  net.Conn
 | |
| }
 | |
| 
 | |
| // New establishes a new connection to the system log daemon.  Each
 | |
| // write to the returned writer sends a log message with the given
 | |
| // priority and prefix.
 | |
| func newBuiltin(priority syslog.Priority, tag string) (w *builtinWriter, err error) {
 | |
| 	return dialBuiltin("", "", priority, tag)
 | |
| }
 | |
| 
 | |
| // Dial establishes a connection to a log daemon by connecting to
 | |
| // address raddr on the specified network.  Each write to the returned
 | |
| // writer sends a log message with the given facility, severity and
 | |
| // tag.
 | |
| // If network is empty, Dial will connect to the local syslog server.
 | |
| func dialBuiltin(network, raddr string, priority syslog.Priority, tag string) (*builtinWriter, error) {
 | |
| 	if priority < 0 || priority > syslog.LOG_LOCAL7|syslog.LOG_DEBUG {
 | |
| 		return nil, errors.New("log/syslog: invalid priority")
 | |
| 	}
 | |
| 
 | |
| 	if tag == "" {
 | |
| 		tag = os.Args[0]
 | |
| 	}
 | |
| 	hostname, _ := os.Hostname()
 | |
| 
 | |
| 	w := &builtinWriter{
 | |
| 		priority: priority,
 | |
| 		tag:      tag,
 | |
| 		hostname: hostname,
 | |
| 		network:  network,
 | |
| 		raddr:    raddr,
 | |
| 	}
 | |
| 
 | |
| 	w.mu.Lock()
 | |
| 	defer w.mu.Unlock()
 | |
| 
 | |
| 	err := w.connect()
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return w, err
 | |
| }
 | |
| 
 | |
| // connect makes a connection to the syslog server.
 | |
| // It must be called with w.mu held.
 | |
| func (w *builtinWriter) connect() (err error) {
 | |
| 	if w.conn != nil {
 | |
| 		// ignore err from close, it makes sense to continue anyway
 | |
| 		w.conn.close()
 | |
| 		w.conn = nil
 | |
| 	}
 | |
| 
 | |
| 	if w.network == "" {
 | |
| 		w.conn, err = unixSyslog()
 | |
| 		if w.hostname == "" {
 | |
| 			w.hostname = "localhost"
 | |
| 		}
 | |
| 	} else {
 | |
| 		var c net.Conn
 | |
| 		c, err = net.DialTimeout(w.network, w.raddr, remoteDeadline)
 | |
| 		if err == nil {
 | |
| 			w.conn = &netConn{conn: c}
 | |
| 			if w.hostname == "" {
 | |
| 				w.hostname = c.LocalAddr().String()
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // Write sends a log message to the syslog daemon.
 | |
| func (w *builtinWriter) Write(b []byte) (int, error) {
 | |
| 	return w.writeAndRetry(w.priority, string(b))
 | |
| }
 | |
| 
 | |
| // Close closes a connection to the syslog daemon.
 | |
| func (w *builtinWriter) Close() error {
 | |
| 	w.mu.Lock()
 | |
| 	defer w.mu.Unlock()
 | |
| 
 | |
| 	if w.conn != nil {
 | |
| 		err := w.conn.close()
 | |
| 		w.conn = nil
 | |
| 		return err
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (w *builtinWriter) writeAndRetry(p syslog.Priority, s string) (int, error) {
 | |
| 	pr := (w.priority & facilityMask) | (p & severityMask)
 | |
| 
 | |
| 	w.mu.Lock()
 | |
| 	defer w.mu.Unlock()
 | |
| 
 | |
| 	if w.conn != nil {
 | |
| 		if n, err := w.write(pr, s); err == nil {
 | |
| 			return n, err
 | |
| 		}
 | |
| 	}
 | |
| 	if err := w.connect(); err != nil {
 | |
| 		return 0, err
 | |
| 	}
 | |
| 	return w.write(pr, s)
 | |
| }
 | |
| 
 | |
| // write generates and writes a syslog formatted string. The
 | |
| // format is as follows: <PRI>TIMESTAMP HOSTNAME TAG[PID]: MSG
 | |
| func (w *builtinWriter) write(p syslog.Priority, msg string) (int, error) {
 | |
| 	// ensure it ends in a \n
 | |
| 	nl := ""
 | |
| 	if !strings.HasSuffix(msg, "\n") {
 | |
| 		nl = "\n"
 | |
| 	}
 | |
| 
 | |
| 	err := w.conn.writeString(p, w.hostname, w.tag, msg, nl)
 | |
| 	if err != nil {
 | |
| 		return 0, err
 | |
| 	}
 | |
| 	// Note: return the length of the input, not the number of
 | |
| 	// bytes printed by Fprintf, because this must behave like
 | |
| 	// an io.Writer.
 | |
| 	return len(msg), nil
 | |
| }
 | |
| 
 | |
| func (n *netConn) writeString(p syslog.Priority, hostname, tag, msg, nl string) error {
 | |
| 	if n.local {
 | |
| 		// Compared to the network form below, the changes are:
 | |
| 		//	1. Use time.Stamp instead of time.RFC3339.
 | |
| 		//	2. Drop the hostname field from the Fprintf.
 | |
| 		timestamp := time.Now().Format(time.Stamp)
 | |
| 		n.conn.SetWriteDeadline(time.Now().Add(localDeadline))
 | |
| 		_, err := fmt.Fprintf(n.conn, "<%d>%s %s[%d]: %s%s",
 | |
| 			p, timestamp,
 | |
| 			tag, os.Getpid(), msg, nl)
 | |
| 		return err
 | |
| 	}
 | |
| 	timestamp := time.Now().Format(time.RFC3339)
 | |
| 	n.conn.SetWriteDeadline(time.Now().Add(remoteDeadline))
 | |
| 	_, err := fmt.Fprintf(n.conn, "<%d>%s %s %s[%d]: %s%s",
 | |
| 		p, timestamp, hostname,
 | |
| 		tag, os.Getpid(), msg, nl)
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| func (n *netConn) close() error {
 | |
| 	return n.conn.Close()
 | |
| }
 | |
| 
 | |
| // unixSyslog opens a connection to the syslog daemon running on the
 | |
| // local machine using a Unix domain socket.
 | |
| func unixSyslog() (conn serverConn, err error) {
 | |
| 	logTypes := []string{"unixgram", "unix"}
 | |
| 	logPaths := []string{"/dev/log", "/var/run/syslog", "/var/run/log"}
 | |
| 	for _, network := range logTypes {
 | |
| 		for _, path := range logPaths {
 | |
| 			conn, err := net.DialTimeout(network, path, localDeadline)
 | |
| 			if err != nil {
 | |
| 				continue
 | |
| 			} else {
 | |
| 				return &netConn{conn: conn, local: true}, nil
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return nil, errors.New("Unix syslog delivery error")
 | |
| }
 |