From 15b4d26d92a90cac2743bff0cfceb6e661ba9969 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 18 Feb 2020 19:21:02 -0800 Subject: [PATCH] logpolicy: automatically figure out paths and filenames. The autoselection should pick sensible paths for all of: - Windows (LocalAppData) - Mac (Library/Caches) - Unix user (XDG_CACHE_DIR) - Linux systemd service (CACHE_DIRECTORY) As a last resort, if cache dir lookup fails, plops sufficiently uniquely named files into the current working directory. Signed-off-by: David Anderson --- cmd/relaynode/relaynode.go | 2 +- cmd/taillogin/taillogin.go | 2 +- cmd/tailscale/tailscale.go | 2 +- cmd/tailscaled/tailscaled.go | 2 +- logpolicy/logpolicy.go | 46 +++++++++++++++++++++++------------- 5 files changed, 34 insertions(+), 20 deletions(-) diff --git a/cmd/relaynode/relaynode.go b/cmd/relaynode/relaynode.go index da28abc74..1dcf209df 100644 --- a/cmd/relaynode/relaynode.go +++ b/cmd/relaynode/relaynode.go @@ -66,7 +66,7 @@ func main() { log.Printf("Warning: no --tun device specified; routing disabled.\n") } - pol := logpolicy.New("tailnode.log.tailscale.io", *config) + pol := logpolicy.New("tailnode.log.tailscale.io") logf := wgengine.RusagePrefixLog(log.Printf) diff --git a/cmd/taillogin/taillogin.go b/cmd/taillogin/taillogin.go index 187289c25..483e82c7a 100644 --- a/cmd/taillogin/taillogin.go +++ b/cmd/taillogin/taillogin.go @@ -31,7 +31,7 @@ func main() { if *config == "" { log.Fatal("no --config file specified") } - pol := logpolicy.New("tailnode.log.tailscale.io", *config) + pol := logpolicy.New("tailnode.log.tailscale.io") defer pol.Close() cfg, err := loadConfig(*config) diff --git a/cmd/tailscale/tailscale.go b/cmd/tailscale/tailscale.go index f8ee24269..837dd857f 100644 --- a/cmd/tailscale/tailscale.go +++ b/cmd/tailscale/tailscale.go @@ -59,7 +59,7 @@ func main() { nopf := getopt.BoolLong("no-packet-filter", 'F', "disable packet filter") advroutes := getopt.ListLong("routes", 'r', "routes to advertise to other nodes (comma-separated, e.g. 10.0.0.0/8,192.168.1.0/24)") getopt.Parse() - pol := logpolicy.New("tailnode.log.tailscale.io", "tailscale") + pol := logpolicy.New("tailnode.log.tailscale.io") if len(getopt.Args()) > 0 { log.Fatalf("too many non-flag arguments: %#v", getopt.Args()[0]) } diff --git a/cmd/tailscaled/tailscaled.go b/cmd/tailscaled/tailscaled.go index 87d3be6e1..821941a00 100644 --- a/cmd/tailscaled/tailscaled.go +++ b/cmd/tailscaled/tailscaled.go @@ -46,7 +46,7 @@ func main() { if err != nil { logf("fixConsoleOutput: %v\n", err) } - pol := logpolicy.New("tailnode.log.tailscale.io", "tailscaled") + pol := logpolicy.New("tailnode.log.tailscale.io") getopt.Parse() if len(getopt.Args()) > 0 { diff --git a/logpolicy/logpolicy.go b/logpolicy/logpolicy.go index 4beef34fc..d85830148 100644 --- a/logpolicy/logpolicy.go +++ b/logpolicy/logpolicy.go @@ -10,6 +10,7 @@ import ( "context" "encoding/json" + "fmt" "io/ioutil" "log" "os" @@ -49,9 +50,9 @@ func (c *Config) ToBytes() []byte { } // Save writes the JSON representation of c to stateFile. -func (c *Config) Save(stateFile string) error { +func (c *Config) save(stateFile string) error { c.PublicID = c.PrivateID.Public() - if err := os.MkdirAll(filepath.Dir(stateFile), 0777); err != nil { + if err := os.MkdirAll(filepath.Dir(stateFile), 0750); err != nil { return err } data := c.ToBytes() @@ -88,14 +89,28 @@ func (l logWriter) Write(buf []byte) (int, error) { return len(buf), nil } +// logsDir returns the directory to use for log configuration and +// buffer storage. +func logsDir() string { + systemdCacheDir := os.Getenv("CACHE_DIRECTORY") + if systemdCacheDir != "" { + return systemdCacheDir + } + + cacheDir, err := os.UserCacheDir() + if err == nil { + return filepath.Join(cacheDir, "Tailscale") + } + + // No idea where to put stuff. This only happens when $HOME is + // unset, which os.UserCacheDir doesn't like. Use the current + // working directory and hope for the best. + return "" +} + // New returns a new log policy (a logger and its instance ID) for a -// given collection name. The provided filePrefix is used as a -// filename prefix for both for the logger's state file, as well as -// temporary log entries themselves. -// -// TODO: the state and the logs locations should perhaps be separated. -func New(collection, filePrefix string) *Policy { - stateFile := filePrefix + ".log.conf" +// given collection name. +func New(collection string) *Policy { var lflags int if terminal.IsTerminal(2) || runtime.GOOS == "windows" { lflags = 0 @@ -104,10 +119,12 @@ func New(collection, filePrefix string) *Policy { } console := log.New(stderrWriter{}, "", lflags) + dir := logsDir() + cfgPath := filepath.Join(dir, fmt.Sprintf("%s.log.conf", version.CmdName())) var oldc *Config - data, err := ioutil.ReadFile(stateFile) + data, err := ioutil.ReadFile(cfgPath) if err != nil { - log.Printf("logpolicy.Read %v: %v\n", stateFile, err) + log.Printf("logpolicy.Read %v: %v\n", cfgPath, err) oldc = &Config{} oldc.Collection = collection } else { @@ -134,7 +151,7 @@ func New(collection, filePrefix string) *Policy { } newc.PublicID = newc.PrivateID.Public() if newc != *oldc { - if err := newc.Save(stateFile); err != nil { + if err := newc.save(cfgPath); err != nil { log.Printf("logpolicy.Config.Save: %v\n", err) } } @@ -152,10 +169,7 @@ func New(collection, filePrefix string) *Policy { }, } - // TODO(crawshaw): filePrefix is a place meant to store configuration. - // OS policies usually have other preferred places to - // store logs. Use one of them? - filchBuf, filchErr := filch.New(filePrefix, filch.Options{}) + filchBuf, filchErr := filch.New(filepath.Join(dir, version.CmdName()), filch.Options{}) if filchBuf != nil { c.Buffer = filchBuf }