Skip to content

Commit 78a3092

Browse files
authored
Merge pull request #761 from doringeman/cli-wsl2
fix(cli): support docker model logs from WSL2 with Docker Desktop
2 parents d62da68 + 56d4632 commit 78a3092

1 file changed

Lines changed: 53 additions & 5 deletions

File tree

cmd/cli/commands/logs.go

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ import (
77
"fmt"
88
"io"
99
"os"
10+
"os/exec"
1011
"os/signal"
1112
"path/filepath"
1213
"regexp"
1314
"runtime"
15+
"strings"
1416
"time"
1517

1618
"github.com/docker/model-runner/cmd/cli/commands/completion"
@@ -70,9 +72,22 @@ func newLogsCmd() *cobra.Command {
7072
case "darwin":
7173
serviceLogPath = filepath.Join(homeDir, "Library/Containers/com.docker.docker/Data/log/host/inference.log")
7274
runtimeLogPath = filepath.Join(homeDir, "Library/Containers/com.docker.docker/Data/log/host/inference-llama.cpp-server.log")
73-
case "windows":
74-
serviceLogPath = filepath.Join(homeDir, "AppData/Local/Docker/log/host/inference.log")
75-
runtimeLogPath = filepath.Join(homeDir, "AppData/Local/Docker/log/host/inference-llama.cpp-server.log")
75+
case "windows", "linux":
76+
baseDir := homeDir
77+
if runtime.GOOS == "linux" {
78+
if !isWSL() {
79+
return fmt.Errorf("log viewing on native Linux is only supported in standalone mode")
80+
}
81+
// When running inside WSL2 with Docker Desktop, the log files
82+
// are on the Windows host filesystem mounted under /mnt/.
83+
winHomeDir, wslErr := windowsHomeDirFromWSL(cmd.Context())
84+
if wslErr != nil {
85+
return fmt.Errorf("unable to determine Windows home directory from WSL2: %w", wslErr)
86+
}
87+
baseDir = winHomeDir
88+
}
89+
serviceLogPath = filepath.Join(baseDir, "AppData/Local/Docker/log/host/inference.log")
90+
runtimeLogPath = filepath.Join(baseDir, "AppData/Local/Docker/log/host/inference-llama.cpp-server.log")
7691
default:
7792
return fmt.Errorf("unsupported OS: %s", runtime.GOOS)
7893
}
@@ -98,9 +113,13 @@ func newLogsCmd() *cobra.Command {
98113

99114
g, ctx := errgroup.WithContext(ctx)
100115

116+
// Poll mode is needed when tailing files over a mounted filesystem
117+
// (Windows or WSL2 accessing the Windows host via /mnt/).
118+
pollMode := runtime.GOOS == "windows" || (runtime.GOOS == "linux" && isWSL())
119+
101120
g.Go(func() error {
102121
t, err := tail.TailFile(
103-
serviceLogPath, tail.Config{Location: &tail.SeekInfo{Offset: 0, Whence: io.SeekEnd}, Follow: true, ReOpen: true},
122+
serviceLogPath, tail.Config{Location: &tail.SeekInfo{Offset: 0, Whence: io.SeekEnd}, Follow: true, ReOpen: true, Poll: pollMode},
104123
)
105124
if err != nil {
106125
return err
@@ -121,7 +140,7 @@ func newLogsCmd() *cobra.Command {
121140
if !noEngines {
122141
g.Go(func() error {
123142
t, err := tail.TailFile(
124-
runtimeLogPath, tail.Config{Location: &tail.SeekInfo{Offset: 0, Whence: io.SeekEnd}, Follow: true, ReOpen: true},
143+
runtimeLogPath, tail.Config{Location: &tail.SeekInfo{Offset: 0, Whence: io.SeekEnd}, Follow: true, ReOpen: true, Poll: pollMode},
125144
)
126145
if err != nil {
127146
return err
@@ -150,6 +169,35 @@ func newLogsCmd() *cobra.Command {
150169
return c
151170
}
152171

172+
// isWSL reports whether the current process is running inside a WSL2 environment.
173+
func isWSL() bool {
174+
_, ok := os.LookupEnv("WSL_DISTRO_NAME")
175+
return ok
176+
}
177+
178+
// windowsHomeDirFromWSL resolves the Windows user's home directory from
179+
// within a WSL2 environment by running "wslpath" on the USERPROFILE path
180+
// obtained via "wslvar". This returns a Linux path like /mnt/c/Users/Name.
181+
func windowsHomeDirFromWSL(ctx context.Context) (string, error) {
182+
out, err := exec.CommandContext(ctx, "wslvar", "USERPROFILE").Output()
183+
if err != nil {
184+
return "", fmt.Errorf("wslvar USERPROFILE: %w", err)
185+
}
186+
winPath := strings.TrimSpace(string(out))
187+
if winPath == "" {
188+
return "", fmt.Errorf("USERPROFILE is empty")
189+
}
190+
out, err = exec.CommandContext(ctx, "wslpath", "-u", winPath).Output()
191+
if err != nil {
192+
return "", fmt.Errorf("wslpath -u %q: %w", winPath, err)
193+
}
194+
linuxPath := strings.TrimSpace(string(out))
195+
if linuxPath == "" {
196+
return "", fmt.Errorf("wslpath returned empty path")
197+
}
198+
return linuxPath, nil
199+
}
200+
153201
var timestampRe = regexp.MustCompile(`\[(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z)\].*`)
154202

155203
const timeFmt = "2006-01-02T15:04:05.000000000Z"

0 commit comments

Comments
 (0)