From e7db109a23d20315466a5a04a784c20afe3c38c1 Mon Sep 17 00:00:00 2001 From: Russ Egan Date: Fri, 17 Jan 2025 14:42:22 -0600 Subject: [PATCH] Better trimming of the source file path Only make the source file path relative to the current working directly *if* the source file is a child path of the current working directory. Typically, the source file path will only be a child of the CWD when the code is being run from its own project folder. But if the executable moved somewhere else first, or packaged in a container, or compiled with the -trimpath option, then this relative path logic doesn't work. If the file path isn't related to the CWT, then trim to just one path element above the file name, which is typically the go package name, e.g. "io/reader.go" Address #16 --- encoding.go | 45 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/encoding.go b/encoding.go index 6088e65..2bdee91 100644 --- a/encoding.go +++ b/encoding.go @@ -5,6 +5,7 @@ import ( "log/slog" "path/filepath" "runtime" + "strings" "time" ) @@ -77,13 +78,8 @@ func (e encoder) writeTimestamp(buf *buffer, tt time.Time) { func (e encoder) writeSource(buf *buffer, pc uintptr, cwd string) { frame, _ := runtime.CallersFrames([]uintptr{pc}).Next() - if cwd != "" { - if ff, err := filepath.Rel(cwd, frame.File); err == nil { - frame.File = ff - } - } e.withColor(buf, e.opts.Theme.Source(), func() { - buf.AppendString(frame.File) + buf.AppendString(trimmedPath(frame.File, cwd)) buf.AppendByte(':') buf.AppendInt(int64(frame.Line)) }) @@ -190,3 +186,40 @@ func (e encoder) writeLevel(buf *buffer, l slog.Level) { e.writeColoredString(buf, str, style) buf.AppendByte(' ') } + +func trimmedPath(path string, cwd string) string { + // if the file path appears to be under the current + // working directory, then we're probably running + // in a dev environment, and we can show the + // path of the source file relative to the + // working directory + if cwd != "" && strings.HasPrefix(path, cwd) { + if ff, err := filepath.Rel(cwd, path); err == nil { + return ff + } + } + + // Otherwise, show the filename and one + // path above it, which is typically going to + // be the package name + // Note that the go compiler always uses forward + // slashes, even if the compiler was run on Windows. + // + // See https://github.com/golang/go/issues/3335 + // and https://github.com/golang/go/issues/18151 + + // This is equivalent to filepath.Base(path) + idx := strings.LastIndexByte(path, '/') + if idx == -1 { + return path + } + + // And this walks back one more separater, which is + // equivalent to filepath.Join(filepath.Base(filepath.Dir(path)), filepath.Base(path)) + idx = strings.LastIndexByte(path[:idx], '/') + if idx == -1 { + return path + } + + return path[idx+1:] +}