@@ -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+
153201var timestampRe = regexp .MustCompile (`\[(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z)\].*` )
154202
155203const timeFmt = "2006-01-02T15:04:05.000000000Z"
0 commit comments