func (this *Server) StartDrainer(address string, filter EntryFilter) *Drainer { c := make(chan Entry) listener := &Listener{ Channel: c, Filter: filter, LastEntry: time.Now(), } this.AddListener <- listener drainer := &Drainer{ Address: address, Filter: filter, server: this, listener: listener, terminate: make(chan bool, 1), } go func() { var w *syslog.Writer var err error for entry := range Throttle(c, 100) { for { // If we terminated give up select { case <-drainer.terminate: return default: } // Connect if w == nil { log.Printf("connecting to syslog://%v\n", address) w, err = syslog.Dial("tcp", address, syslog.LOG_INFO, "") if err != nil { w = nil time.Sleep(time.Second * 5) continue } } // Send the message _, err = w.Write(entry.Line()) if err != nil { w.Close() w = nil time.Sleep(time.Second * 5) continue } // Successfully sent the message so break break } } }() return drainer }
// New syslog TCP output. // // If the network is empty, the local syslog daemon will be used. func NewSyslogOutput(network, raddr string, priority syslog.Priority, tag string) (Output, error) { desc := "syslog" if network != "" { desc = fmt.Sprintf("syslog at %s://%s", network, raddr) } failing := false var w *syslog.Writer dial := func() error { var err error w, err = syslog.Dial(network, raddr, priority, tag) if err != nil { if !failing { failing = true fmt.Fprintf(os.Stderr, "Failed to connect to %s: %s\n", desc, err) } w = nil return err } else if failing { fmt.Fprintf(os.Stderr, "Connected to %s\n", desc) failing = false } return nil } return newDrainingOutput(10240, func(lines [][]byte) error { // Connect if a connection does not already exist. if w == nil { if err := dial(); err != nil { return err } } // Send data. first := true for _, l := range lines { if len(l) == 0 { continue } n, err := w.Write(l) // If the first send fails without sending any data, let's attempt // to reconnect. if first { first = false if n == 0 && err != nil { fmt.Fprintf(os.Stderr, "Failed to send data to %s: %s - reconnecting...\n", desc, err) if err = dial(); err != nil { return err } } } // Update the payload and handle any errors. if err != nil { fmt.Fprintf(os.Stderr, "Failed to send data to %s: %s\n", desc, err) failing = true w.Close() w = nil return err } } return nil }, func() { if w != nil { w.Close() } }) }
func main() { flag.Parse() // Set logTarget if *logTarget == "" { logger = log.New(os.Stdout, "LOG ", log.LstdFlags) debugLogger = log.New(os.Stdout, "DEBUG ", log.LstdFlags) } else { u, err := url.Parse(*logTarget) if err != nil { log.Fatalln("fatal: unable to parse logtarget url", err) } query, _ := url.ParseQuery(u.RawQuery) switch { case (u.Scheme == "" || u.Scheme == "file") && u.Path != "": var logFile *os.File fileMode := os.FileMode(*logPermission) _, err = os.Stat(u.Path) if os.IsNotExist(err) { logFile, err = os.Create(u.Path) if err != nil { log.Fatalln("fatal: unable to create log target", err) } err = os.Chmod(u.Path, fileMode) if err != nil { log.Fatalln("fatal: unable to set file permissions", err) } } else { logFile, err = os.OpenFile(u.Path, os.O_WRONLY|os.O_APPEND, fileMode) if err != nil { log.Fatalln("fatal: unable to open log target", err) } } defer logFile.Close() logTargetWriter = io.Writer(logFile) // Check if logTarget is writable _, err = logTargetWriter.Write([]byte("")) if err != nil { log.Fatalln("fatal: unable to write to log target") } case strings.HasPrefix(u.Scheme, "syslog"): var syslogLogger *syslog.Writer var tag string priority := int(syslog.LOG_NOTICE | syslog.LOG_LOCAL0) if query["priority"][0] != "" { priority, err = strconv.Atoi(query["priority"][0]) if err != nil { log.Fatalln("fatal: unable to connect to syslog", *logTarget, "err:", err) } } if query["tag"][0] != "" { tag = query["tag"][0] } if u.Host == "" { syslogLogger, err = syslog.New(syslog.Priority(priority), tag) if err != nil { log.Fatalln("fatal: unable to connect to syslog", *logTarget, "err:", err) } } else { schemeParts := strings.Split(u.Scheme, "+") network := "tcp" if len(schemeParts) > 1 { network = schemeParts[1] } _, _, err := net.SplitHostPort(u.Host) if err != nil { u.Host = u.Host + ":514" } syslogLogger, err = syslog.Dial(network, u.Host, syslog.Priority(priority), tag) if err != nil { log.Fatalln("fatal: unable to connect to syslog", *logTarget, "err:", err) } } defer syslogLogger.Close() logTargetWriter = io.Writer(syslogLogger) default: log.Fatalln("fatal: no valid schema:", *logTarget) } logger = log.New(logTargetWriter, "LOG ", log.LstdFlags) debugLogger = log.New(logTargetWriter, "DEBUG ", log.LstdFlags) } // Set log-function based on log level switch *logLevel { case 0: logf = emptyLogf case 2: debugf = debugLogf default: } // Write example log lines logf("log output %s, %d", "string1", 10) debugf("debug output %s, %d", "string1", 10) }