feat(debug): trace system calls to log file

This commit is contained in:
Jan De Dobbeleer 2021-08-01 15:25:15 +02:00 committed by Jan De Dobbeleer
parent c4db62c644
commit 073f18f53a
5 changed files with 106 additions and 8 deletions

View file

@ -3,7 +3,9 @@ package main
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"io/ioutil" "io/ioutil"
"log"
"net/http" "net/http"
"os" "os"
"os/exec" "os/exec"
@ -97,10 +99,45 @@ func (c *commandCache) get(command string) (string, bool) {
return "", false return "", false
} }
type tracer struct {
file *os.File
debug bool
}
func (t *tracer) init(home string) {
if !t.debug {
return
}
var err error
fileName := home + "/oh-my-posh.log"
t.file, err = os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("error opening file: %v", err)
}
log.SetOutput(t.file)
}
func (t *tracer) close() {
if !t.debug {
return
}
_ = t.file.Close()
}
func (t *tracer) trace(start time.Time, function string, args ...string) {
if !t.debug {
return
}
elapsed := time.Since(start)
trace := fmt.Sprintf("func: %s duration: %s, args: %s", function, elapsed, strings.Trim(fmt.Sprint(args), "[]"))
log.Println(trace)
}
type environment struct { type environment struct {
args *args args *args
cwd string cwd string
cmdCache *commandCache cmdCache *commandCache
tracer *tracer
} }
func (env *environment) init(args *args) { func (env *environment) init(args *args) {
@ -110,13 +147,20 @@ func (env *environment) init(args *args) {
lock: sync.RWMutex{}, lock: sync.RWMutex{},
} }
env.cmdCache = cmdCache env.cmdCache = cmdCache
tracer := &tracer{
debug: *args.Debug,
}
tracer.init(env.homeDir())
env.tracer = tracer
} }
func (env *environment) getenv(key string) string { func (env *environment) getenv(key string) string {
defer env.tracer.trace(time.Now(), "getenv", key)
return os.Getenv(key) return os.Getenv(key)
} }
func (env *environment) getcwd() string { func (env *environment) getcwd() string {
defer env.tracer.trace(time.Now(), "getcwd")
if env.cwd != "" { if env.cwd != "" {
return env.cwd return env.cwd
} }
@ -137,6 +181,7 @@ func (env *environment) getcwd() string {
} }
func (env *environment) hasFiles(pattern string) bool { func (env *environment) hasFiles(pattern string) bool {
defer env.tracer.trace(time.Now(), "hasFiles", pattern)
cwd := env.getcwd() cwd := env.getcwd()
pattern = cwd + env.getPathSeperator() + pattern pattern = cwd + env.getPathSeperator() + pattern
matches, err := filepath.Glob(pattern) matches, err := filepath.Glob(pattern)
@ -147,6 +192,7 @@ func (env *environment) hasFiles(pattern string) bool {
} }
func (env *environment) hasFilesInDir(dir, pattern string) bool { func (env *environment) hasFilesInDir(dir, pattern string) bool {
defer env.tracer.trace(time.Now(), "hasFilesInDir", pattern)
pattern = dir + env.getPathSeperator() + pattern pattern = dir + env.getPathSeperator() + pattern
matches, err := filepath.Glob(pattern) matches, err := filepath.Glob(pattern)
if err != nil { if err != nil {
@ -156,11 +202,13 @@ func (env *environment) hasFilesInDir(dir, pattern string) bool {
} }
func (env *environment) hasFolder(folder string) bool { func (env *environment) hasFolder(folder string) bool {
defer env.tracer.trace(time.Now(), "hasFolder", folder)
_, err := os.Stat(folder) _, err := os.Stat(folder)
return !os.IsNotExist(err) return !os.IsNotExist(err)
} }
func (env *environment) getFileContent(file string) string { func (env *environment) getFileContent(file string) string {
defer env.tracer.trace(time.Now(), "getFileContent", file)
content, err := ioutil.ReadFile(file) content, err := ioutil.ReadFile(file)
if err != nil { if err != nil {
return "" return ""
@ -169,10 +217,12 @@ func (env *environment) getFileContent(file string) string {
} }
func (env *environment) getPathSeperator() string { func (env *environment) getPathSeperator() string {
defer env.tracer.trace(time.Now(), "getPathSeperator")
return string(os.PathSeparator) return string(os.PathSeparator)
} }
func (env *environment) getCurrentUser() string { func (env *environment) getCurrentUser() string {
defer env.tracer.trace(time.Now(), "getCurrentUser")
user := os.Getenv("USER") user := os.Getenv("USER")
if user == "" { if user == "" {
user = os.Getenv("USERNAME") user = os.Getenv("USERNAME")
@ -181,6 +231,7 @@ func (env *environment) getCurrentUser() string {
} }
func (env *environment) getHostName() (string, error) { func (env *environment) getHostName() (string, error) {
defer env.tracer.trace(time.Now(), "getHostName")
hostName, err := os.Hostname() hostName, err := os.Hostname()
if err != nil { if err != nil {
return "", err return "", err
@ -189,10 +240,12 @@ func (env *environment) getHostName() (string, error) {
} }
func (env *environment) getRuntimeGOOS() string { func (env *environment) getRuntimeGOOS() string {
defer env.tracer.trace(time.Now(), "getRuntimeGOOS")
return runtime.GOOS return runtime.GOOS
} }
func (env *environment) getPlatform() string { func (env *environment) getPlatform() string {
defer env.tracer.trace(time.Now(), "getPlatform")
if runtime.GOOS == windowsPlatform { if runtime.GOOS == windowsPlatform {
return windowsPlatform return windowsPlatform
} }
@ -202,6 +255,7 @@ func (env *environment) getPlatform() string {
} }
func (env *environment) runCommand(command string, args ...string) (string, error) { func (env *environment) runCommand(command string, args ...string) (string, error) {
defer env.tracer.trace(time.Now(), "runCommand", append([]string{command}, args...)...)
if cmd, ok := env.cmdCache.get(command); ok { if cmd, ok := env.cmdCache.get(command); ok {
command = cmd command = cmd
} }
@ -218,11 +272,13 @@ func (env *environment) runCommand(command string, args ...string) (string, erro
} }
func (env *environment) runShellCommand(shell, command string) string { func (env *environment) runShellCommand(shell, command string) string {
defer env.tracer.trace(time.Now(), "runShellCommand", shell, command)
out, _ := env.runCommand(shell, "-c", command) out, _ := env.runCommand(shell, "-c", command)
return out return out
} }
func (env *environment) hasCommand(command string) bool { func (env *environment) hasCommand(command string) bool {
defer env.tracer.trace(time.Now(), "hasCommand", command)
if _, ok := env.cmdCache.get(command); ok { if _, ok := env.cmdCache.get(command); ok {
return true return true
} }
@ -235,10 +291,12 @@ func (env *environment) hasCommand(command string) bool {
} }
func (env *environment) lastErrorCode() int { func (env *environment) lastErrorCode() int {
defer env.tracer.trace(time.Now(), "lastErrorCode")
return *env.args.ErrorCode return *env.args.ErrorCode
} }
func (env *environment) executionTime() float64 { func (env *environment) executionTime() float64 {
defer env.tracer.trace(time.Now(), "executionTime")
if *env.args.ExecutionTime < 0 { if *env.args.ExecutionTime < 0 {
return 0 return 0
} }
@ -246,14 +304,17 @@ func (env *environment) executionTime() float64 {
} }
func (env *environment) getArgs() *args { func (env *environment) getArgs() *args {
defer env.tracer.trace(time.Now(), "getArgs")
return env.args return env.args
} }
func (env *environment) getBatteryInfo() ([]*battery.Battery, error) { func (env *environment) getBatteryInfo() ([]*battery.Battery, error) {
defer env.tracer.trace(time.Now(), "getBatteryInfo")
return battery.GetAll() return battery.GetAll()
} }
func (env *environment) getShellName() string { func (env *environment) getShellName() string {
defer env.tracer.trace(time.Now(), "getShellName")
if *env.args.Shell != "" { if *env.args.Shell != "" {
return *env.args.Shell return *env.args.Shell
} }
@ -276,6 +337,7 @@ func (env *environment) getShellName() string {
} }
func (env *environment) doGet(url string) ([]byte, error) { func (env *environment) doGet(url string) ([]byte, error) {
defer env.tracer.trace(time.Now(), "doGet", url)
ctx, cncl := context.WithTimeout(context.Background(), time.Millisecond*20) ctx, cncl := context.WithTimeout(context.Background(), time.Millisecond*20)
defer cncl() defer cncl()
request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
@ -295,6 +357,7 @@ func (env *environment) doGet(url string) ([]byte, error) {
} }
func (env *environment) hasParentFilePath(path string) (*fileInfo, error) { func (env *environment) hasParentFilePath(path string) (*fileInfo, error) {
defer env.tracer.trace(time.Now(), "hasParentFilePath", path)
currentFolder := env.getcwd() currentFolder := env.getcwd()
for { for {
searchPath := filepath.Join(currentFolder, path) searchPath := filepath.Join(currentFolder, path)
@ -318,6 +381,7 @@ func (env *environment) hasParentFilePath(path string) (*fileInfo, error) {
} }
func (env *environment) stackCount() int { func (env *environment) stackCount() int {
defer env.tracer.trace(time.Now(), "stackCount")
if *env.args.StackCount < 0 { if *env.args.StackCount < 0 {
return 0 return 0
} }

View file

@ -5,11 +5,13 @@ package main
import ( import (
"errors" "errors"
"os" "os"
"time"
terminal "github.com/wayneashleyberry/terminal-dimensions" terminal "github.com/wayneashleyberry/terminal-dimensions"
) )
func (env *environment) isRunningAsRoot() bool { func (env *environment) isRunningAsRoot() bool {
defer env.tracer.trace(time.Now(), "isRunningAsRoot")
return os.Geteuid() == 0 return os.Geteuid() == 0
} }
@ -22,6 +24,7 @@ func (env *environment) getWindowTitle(imageName, windowTitleRegex string) (stri
} }
func (env *environment) isWsl() bool { func (env *environment) isWsl() bool {
defer env.tracer.trace(time.Now(), "isWsl")
// one way to check // one way to check
// version := env.getFileContent("/proc/version") // version := env.getFileContent("/proc/version")
// return strings.Contains(version, "microsoft") // return strings.Contains(version, "microsoft")
@ -30,6 +33,7 @@ func (env *environment) isWsl() bool {
} }
func (env *environment) getTerminalWidth() (int, error) { func (env *environment) getTerminalWidth() (int, error) {
defer env.tracer.trace(time.Now(), "getTerminalWidth")
width, err := terminal.Width() width, err := terminal.Width()
return int(width), err return int(width), err
} }

View file

@ -5,11 +5,13 @@ package main
import ( import (
"errors" "errors"
"os" "os"
"time"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
func (env *environment) isRunningAsRoot() bool { func (env *environment) isRunningAsRoot() bool {
defer env.tracer.trace(time.Now(), "isRunningAsRoot")
var sid *windows.SID var sid *windows.SID
// Although this looks scary, it is directly copied from the // Although this looks scary, it is directly copied from the
@ -57,13 +59,16 @@ func (env *environment) homeDir() string {
} }
func (env *environment) getWindowTitle(imageName, windowTitleRegex string) (string, error) { func (env *environment) getWindowTitle(imageName, windowTitleRegex string) (string, error) {
defer env.tracer.trace(time.Now(), "getWindowTitle", imageName, windowTitleRegex)
return getWindowTitle(imageName, windowTitleRegex) return getWindowTitle(imageName, windowTitleRegex)
} }
func (env *environment) isWsl() bool { func (env *environment) isWsl() bool {
defer env.tracer.trace(time.Now(), "isWsl")
return false return false
} }
func (env *environment) getTerminalWidth() (int, error) { func (env *environment) getTerminalWidth() (int, error) {
defer env.tracer.trace(time.Now(), "getTerminalWidth")
return 0, errors.New("Unsupported on Windows") return 0, errors.New("Unsupported on Windows")
} }

View file

@ -155,6 +155,7 @@ func main() {
flag.Parse() flag.Parse()
env := &environment{} env := &environment{}
env.init(args) env.init(args)
defer env.tracer.close()
if *args.Millis { if *args.Millis {
fmt.Print(time.Now().UnixNano() / 1000000) fmt.Print(time.Now().UnixNano() / 1000000)
return return

View file

@ -10,7 +10,10 @@ import (
func TestExecuteCommand(t *testing.T) { func TestExecuteCommand(t *testing.T) {
env := &environment{} env := &environment{}
env.init(nil) debug := false
env.init(&args{
Debug: &debug,
})
props := &properties{ props := &properties{
values: map[Property]interface{}{ values: map[Property]interface{}{
Command: "echo hello", Command: "echo hello",
@ -27,7 +30,10 @@ func TestExecuteCommand(t *testing.T) {
func TestExecuteMultipleCommandsOrFirst(t *testing.T) { func TestExecuteMultipleCommandsOrFirst(t *testing.T) {
env := &environment{} env := &environment{}
env.init(nil) debug := false
env.init(&args{
Debug: &debug,
})
props := &properties{ props := &properties{
values: map[Property]interface{}{ values: map[Property]interface{}{
Command: "exit 1 || echo hello", Command: "exit 1 || echo hello",
@ -44,7 +50,10 @@ func TestExecuteMultipleCommandsOrFirst(t *testing.T) {
func TestExecuteMultipleCommandsOrSecond(t *testing.T) { func TestExecuteMultipleCommandsOrSecond(t *testing.T) {
env := &environment{} env := &environment{}
env.init(nil) debug := false
env.init(&args{
Debug: &debug,
})
props := &properties{ props := &properties{
values: map[Property]interface{}{ values: map[Property]interface{}{
Command: "echo hello || echo world", Command: "echo hello || echo world",
@ -61,7 +70,10 @@ func TestExecuteMultipleCommandsOrSecond(t *testing.T) {
func TestExecuteMultipleCommandsAnd(t *testing.T) { func TestExecuteMultipleCommandsAnd(t *testing.T) {
env := &environment{} env := &environment{}
env.init(nil) debug := false
env.init(&args{
Debug: &debug,
})
props := &properties{ props := &properties{
values: map[Property]interface{}{ values: map[Property]interface{}{
Command: "echo hello && echo world", Command: "echo hello && echo world",
@ -78,7 +90,10 @@ func TestExecuteMultipleCommandsAnd(t *testing.T) {
func TestExecuteSingleCommandEmpty(t *testing.T) { func TestExecuteSingleCommandEmpty(t *testing.T) {
env := &environment{} env := &environment{}
env.init(nil) debug := false
env.init(&args{
Debug: &debug,
})
props := &properties{ props := &properties{
values: map[Property]interface{}{ values: map[Property]interface{}{
Command: "", Command: "",
@ -94,7 +109,10 @@ func TestExecuteSingleCommandEmpty(t *testing.T) {
func TestExecuteSingleCommandNoCommandProperty(t *testing.T) { func TestExecuteSingleCommandNoCommandProperty(t *testing.T) {
env := &environment{} env := &environment{}
env.init(nil) debug := false
env.init(&args{
Debug: &debug,
})
props := &properties{} props := &properties{}
c := &command{ c := &command{
props: props, props: props,
@ -107,7 +125,10 @@ func TestExecuteSingleCommandNoCommandProperty(t *testing.T) {
func TestExecuteMultipleCommandsAndDisabled(t *testing.T) { func TestExecuteMultipleCommandsAndDisabled(t *testing.T) {
env := &environment{} env := &environment{}
env.init(nil) debug := false
env.init(&args{
Debug: &debug,
})
props := &properties{ props := &properties{
values: map[Property]interface{}{ values: map[Property]interface{}{
Command: "echo && echo", Command: "echo && echo",
@ -123,7 +144,10 @@ func TestExecuteMultipleCommandsAndDisabled(t *testing.T) {
func TestExecuteMultipleCommandsOrDisabled(t *testing.T) { func TestExecuteMultipleCommandsOrDisabled(t *testing.T) {
env := &environment{} env := &environment{}
env.init(nil) debug := false
env.init(&args{
Debug: &debug,
})
props := &properties{ props := &properties{
values: map[Property]interface{}{ values: map[Property]interface{}{
Command: "echo|| echo", Command: "echo|| echo",