Skip to content

Commit 015b721

Browse files
committed
feat: add default log_file name
add max log size, add tests, update website docs fix func comments address comments fix docs fail fast add tests to TestErrorSpam, switch to using log
1 parent 2aa2d1f commit 015b721

File tree

3 files changed

+148
-4
lines changed

3 files changed

+148
-4
lines changed

cmd/minikube/main.go

+49
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ package main
1818

1919
import (
2020
"bytes"
21+
"crypto/sha1"
22+
"encoding/hex"
2123
"flag"
2224
"fmt"
2325
"log"
@@ -123,6 +125,39 @@ func (lb machineLogBridge) Write(b []byte) (n int, err error) {
123125
return len(b), nil
124126
}
125127

128+
// checkLogFileMaxSize checks if a file's size is greater than or equal to max size in KB
129+
func checkLogFileMaxSize(file string, maxSizeKB int64) bool {
130+
f, err := os.Stat(file)
131+
if err != nil {
132+
return false
133+
}
134+
kb := (f.Size() / 1024)
135+
return kb >= maxSizeKB
136+
}
137+
138+
// logFileName generates a default logfile name in the form minikube_<argv[1]>_<hash>_<count>.log from args
139+
func logFileName(dir string, logIdx int64) string {
140+
h := sha1.New()
141+
for _, s := range os.Args {
142+
if _, err := h.Write([]byte(s)); err != nil {
143+
klog.Warningf("Unable to add arg %s to log filename hash: %v", s, err)
144+
}
145+
}
146+
hs := hex.EncodeToString(h.Sum(nil))
147+
var logfilePath string
148+
// check if subcommand specified
149+
if len(os.Args) < 2 {
150+
logfilePath = filepath.Join(dir, fmt.Sprintf("minikube_%s_%d.log", hs, logIdx))
151+
} else {
152+
logfilePath = filepath.Join(dir, fmt.Sprintf("minikube_%s_%s_%d.log", os.Args[1], hs, logIdx))
153+
}
154+
// if log has reached max size 1M, generate new logfile name by incrementing count
155+
if checkLogFileMaxSize(logfilePath, 1024) {
156+
return logFileName(dir, logIdx+1)
157+
}
158+
return logfilePath
159+
}
160+
126161
// setFlags sets the flags
127162
func setFlags() {
128163
// parse flags beyond subcommand - get aroung go flag 'limitations':
@@ -146,6 +181,20 @@ func setFlags() {
146181
}
147182
setLastStartFlags()
148183

184+
// set default log_file name but don't override user's preferences
185+
if !pflag.CommandLine.Changed("log_file") {
186+
// default log_file dir to $TMP
187+
dir := os.TempDir()
188+
// set log_dir to user input if specified
189+
if pflag.CommandLine.Changed("log_dir") && pflag.Lookup("log_dir").Value.String() != "" {
190+
dir = pflag.Lookup("log_dir").Value.String()
191+
}
192+
l := logFileName(dir, 0)
193+
if err := pflag.Set("log_file", l); err != nil {
194+
klog.Warningf("Unable to set default flag value for log_file: %v", err)
195+
}
196+
}
197+
149198
// make sure log_dir exists if log_file is not also set - the log_dir is mutually exclusive with the log_file option
150199
// ref: https://github.com/kubernetes/klog/blob/52c62e3b70a9a46101f33ebaf0b100ec55099975/klog.go#L491
151200
if pflag.Lookup("log_file") != nil && pflag.Lookup("log_file").Value.String() == "" &&

site/content/en/docs/handbook/troubleshooting.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@ Example:
1919

2020
## Post-mortem minikube debug logs
2121

22-
minikube stores post-mortem INFO logs in the temporary directory of your system. On macOS or Linux, it's easy to get a list of recent INFO logs:
22+
minikube stores post-mortem logs in the temporary directory of your system. One log file is created per subcommand and any subsequent invocations of the subcommand with the same args will append to the same file. If the log file has exceeded 1MB in size, a new log file is created. On macOS or Linux, it's easy to get a list of recent logs:
2323

2424
```shell
25-
find $TMPDIR -mtime -1 -type f -name "*minikube*INFO*" -ls 2>/dev/null
25+
find $TMPDIR -mtime -1 -type f -name "*minikube*" -ls 2>/dev/null
2626
```
2727

28-
For instance, this shows:
28+
For instance after running `minikube start`, the above comamnd will show:
2929

30-
`-rw-r--r-- 1 user grp 718 Aug 18 12:40 /var/folders/n1/qxvd9kc/T//minikube.mac.user.log.INFO.20200818-124017.63501`
30+
`-rw-r--r-- 1 user grp 718 Aug 18 12:40 /var/folders/n1/qxvd9kc/T//minikube_start_dc950831e1a232e0318a6d6ca82aaf4f4a8a048b_0.log`
3131

3232
These are plain text log files: you may rename them to "<filename>.log" and then drag/drop them into a GitHub issue for further analysis by the minikube team. You can quickly inspect the final lines of any of these logs via:
3333

test/integration/error_spam_test.go

+95
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ package integration
2020

2121
import (
2222
"context"
23+
"fmt"
24+
"os"
2325
"os/exec"
26+
"path/filepath"
2427
"regexp"
2528
"strings"
2629
"testing"
@@ -104,4 +107,96 @@ func TestErrorSpam(t *testing.T) {
104107
t.Errorf("missing kubeadm init sub-step %q", step)
105108
}
106109
}
110+
111+
logTests := []struct {
112+
command string
113+
args []string
114+
runCount int // number of times to run command
115+
expectedLogFiles int // number of logfiles expected after running command runCount times
116+
}{
117+
{
118+
command: "logs",
119+
runCount: 15, // calling this 15 times should create 2 files with 1 greater than 1M
120+
expectedLogFiles: 2,
121+
},
122+
{
123+
command: "status",
124+
runCount: 100,
125+
expectedLogFiles: 1,
126+
}, {
127+
command: "pause",
128+
runCount: 5,
129+
expectedLogFiles: 1,
130+
}, {
131+
command: "unpause",
132+
runCount: 1,
133+
expectedLogFiles: 1,
134+
}, {
135+
command: "stop",
136+
runCount: 1,
137+
expectedLogFiles: 1,
138+
},
139+
}
140+
141+
for _, test := range logTests {
142+
t.Run(test.command, func(t *testing.T) {
143+
args := []string{test.command, "-p", profile}
144+
args = append(args, test.args...)
145+
// run command runCount times
146+
for i := 0; i < test.runCount; i++ {
147+
rr, err := Run(t, exec.CommandContext(ctx, Target(), args...))
148+
if err != nil {
149+
t.Fatalf("%q failed: %v", rr.Command(), err)
150+
}
151+
}
152+
// get log files generated above
153+
logFiles, err := getLogFiles(test.command)
154+
if err != nil {
155+
t.Errorf("failed to find tmp log files: command %s : %v", test.command, err)
156+
}
157+
// cleanup generated logfiles
158+
defer cleanupLogFiles(t, logFiles)
159+
// if not the expected number of files, throw err
160+
if len(logFiles) != test.expectedLogFiles {
161+
t.Errorf("failed to find expected number of log files: cmd %s: expected: %d got %d", test.command, test.expectedLogFiles, len(logFiles))
162+
}
163+
// if more than 1 logfile is expected, only one file should be less than 1M
164+
if test.expectedLogFiles > 1 {
165+
foundSmall := false
166+
maxSize := 1024 * 1024 // 1M
167+
for _, logFile := range logFiles {
168+
isSmall := int(logFile.Size()) < maxSize
169+
if isSmall && !foundSmall {
170+
foundSmall = true
171+
} else if isSmall && foundSmall {
172+
t.Errorf("expected to find only one file less than 1M: cmd %s:", test.command)
173+
}
174+
}
175+
}
176+
})
177+
178+
}
179+
}
180+
181+
// getLogFiles returns logfiles corresponding to cmd
182+
func getLogFiles(cmdName string) ([]os.FileInfo, error) {
183+
var logFiles []os.FileInfo
184+
err := filepath.Walk(os.TempDir(), func(path string, info os.FileInfo, err error) error {
185+
if strings.Contains(info.Name(), fmt.Sprintf("minikube_%s", cmdName)) {
186+
logFiles = append(logFiles, info)
187+
}
188+
return nil
189+
})
190+
return logFiles, err
191+
}
192+
193+
// cleanupLogFiles removes logfiles generated during testing
194+
func cleanupLogFiles(t *testing.T, logFiles []os.FileInfo) {
195+
for _, logFile := range logFiles {
196+
logFilePath := filepath.Join(os.TempDir(), logFile.Name())
197+
t.Logf("Cleaning up logfile %s ...", logFilePath)
198+
if err := os.Remove(logFilePath); err != nil {
199+
t.Errorf("failed to cleanup log file: %s : %v", logFilePath, err)
200+
}
201+
}
107202
}

0 commit comments

Comments
 (0)