mirror of
https://github.com/tailscale/tailscale.git
synced 2026-07-20 21:23:07 +08:00
Add a new modular syslog feature providing a tailscaled --syslog flag that sends the daemon's logs to the system syslog daemon instead of stderr, which is useful when running as a daemon without a service manager that captures stderr (e.g. OpenWrt's procd). The feature package registers two new hooks: one to register its flag before flag parsing, and one that tailscaled calls early in main to redirect the standard library's default logger. Because logpolicy later points the default logger at logtail, whose local console copy writes to stderr, logpolicy now also consults the hook and sends its console copy to the same sink (with timestamps disabled, as syslog records its own). The feature is linked by default only on Linux, FreeBSD, and OpenBSD, and can be removed with the ts_omit_syslog build tag. If connecting to the syslog daemon fails at startup, tailscaled logs a warning and continues logging to stderr. Fixes #16270 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> Change-Id: I8f3a92d4c1e6b70a5d29e4f61b3c874250a9de13
48 lines
1.2 KiB
Go
48 lines
1.2 KiB
Go
// Copyright (c) Tailscale Inc & contributors
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
//go:build unix
|
|
|
|
// Package syslog provides the tailscaled --syslog flag, which sends the
|
|
// daemon's logs to the system syslog daemon instead of stderr.
|
|
package syslog
|
|
|
|
import (
|
|
"flag"
|
|
"io"
|
|
"log"
|
|
"log/syslog"
|
|
"sync"
|
|
|
|
"tailscale.com/feature"
|
|
)
|
|
|
|
func init() {
|
|
feature.Register("syslog")
|
|
feature.HookRegisterLogSinkFlags.Set(registerFlags)
|
|
feature.HookLogSink.Set(logSink)
|
|
}
|
|
|
|
var useSyslog bool
|
|
|
|
func registerFlags() {
|
|
flag.BoolVar(&useSyslog, "syslog", false, "log to the system syslog daemon instead of stderr")
|
|
}
|
|
|
|
// logSink returns the writer to which logs should be sent, pointing the
|
|
// standard library's default logger at it on first call. It returns nil if
|
|
// syslog logging was not requested or the syslog daemon is unreachable.
|
|
var logSink = sync.OnceValue(func() io.Writer {
|
|
if !useSyslog {
|
|
return nil
|
|
}
|
|
w, err := syslog.New(syslog.LOG_DAEMON|syslog.LOG_INFO, "tailscaled")
|
|
if err != nil {
|
|
log.Printf("syslog: connecting to syslog daemon failed; continuing to log to stderr: %v", err)
|
|
return nil
|
|
}
|
|
log.SetFlags(0) // syslog records its own timestamps
|
|
log.SetOutput(w)
|
|
return w
|
|
})
|