From 45b384fa48c412c15e9f15cff6c3077b8d85211e Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 23 Mar 2020 19:41:38 -0700 Subject: [PATCH] fix: normalize paths on windows Fixes #73 by normalizing paths to UNC on windows. This is _slightly_ less hacky than registering a new schema. The underlying issue was twofold: 1. When specifying a windows file URL as `file://c:/foo/bar`, go barfs because `:` can't be in a domain name. 2. When specifying a windows file URL as `file:///c:/foo/bar`, we'd end up trying to open `/c:/foo/bar` which is actually `CURRENT_DRIVE:/c:/foo/bar`. --- path_other.go | 11 +++++++++++ path_windows.go | 35 +++++++++++++++++++++++++++++++++++ setup.go | 8 ++++++-- 3 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 path_other.go create mode 100644 path_windows.go diff --git a/path_other.go b/path_other.go new file mode 100644 index 0000000..94d3398 --- /dev/null +++ b/path_other.go @@ -0,0 +1,11 @@ +//+build !windows + +package log + +import ( + "path/filepath" +) + +func normalizePath(p string) (string, error) { + return filepath.Abs(p) +} diff --git a/path_windows.go b/path_windows.go new file mode 100644 index 0000000..b441857 --- /dev/null +++ b/path_windows.go @@ -0,0 +1,35 @@ +//+build windows + +package log + +import ( + "fmt" + "path/filepath" + "strings" +) + +func normalizePath(p string) (string, error) { + if p == "" { + return "", fmt.Errorf("path empty") + } + p, err := filepath.Abs(p) + if err != nil { + return "", err + } + // Is this _really_ an absolute path? + if !strings.HasPrefix(p, "\\\\") { + // It's a drive: path! + // Return a UNC path. + p = "\\\\?\\" + p + } + + // This will return file:////?/c:/foobar + // + // Why? Because: + // 1. Go will choke on file://c:/ because the "domain" includes a :. + // 2. Windows will choke on file:///c:/ because the path will be + // /c:/... which is _relative_ to the current drive. + // + // This path (a) has no "domain" and (b) starts with a slash. Yay! + return "file://" + filepath.ToSlash(p), nil +} diff --git a/setup.go b/setup.go index 7195613..a8a67cf 100644 --- a/setup.go +++ b/setup.go @@ -68,7 +68,11 @@ func SetupLogging() { zapCfg.OutputPaths = []string{"stderr"} // check if we log to a file if logfp := os.Getenv(envLoggingFile); len(logfp) > 0 { - zapCfg.OutputPaths = append(zapCfg.OutputPaths, logfp) + if path, err := normalizePath(logfp); err != nil { + fmt.Fprintf(os.Stderr, "failed to resolve log path '%q', logging to stderr only: %s\n", logfp, err) + } else { + zapCfg.OutputPaths = append(zapCfg.OutputPaths, path) + } } // set the backend(s) @@ -83,7 +87,7 @@ func SetupLogging() { var err error lvl, err = LevelFromString(logenv) if err != nil { - fmt.Println("error setting log levels", err) + fmt.Fprintf(os.Stderr, "error setting log levels: %s\n", err) } } zapCfg.Level.SetLevel(zapcore.Level(lvl))