-
Notifications
You must be signed in to change notification settings - Fork 0
/
debug.go
146 lines (125 loc) · 3.07 KB
/
debug.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"regexp"
"runtime"
"strings"
"sync"
)
var logFileMutex sync.Mutex
var logFileTruncated bool
func writeToLogFile(logEntry string) {
if Config.Debug.LogFile == "" {
return
}
// lock log file
logFileMutex.Lock()
defer logFileMutex.Unlock()
// truncate log file if necessary
if !logFileTruncated {
os.Truncate(Config.Debug.LogFile, 0)
logFileTruncated = true
}
// open file for appending
f, err := os.OpenFile(Config.Debug.LogFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
panic(err)
}
defer f.Close()
// write log line
_, err = f.WriteString(logEntry)
if err != nil {
panic(err)
}
}
func DebugCall(args ...any) func(...any) {
if Config.Debug.LogFile == "" {
return func(...any) {}
}
// get name of calling function
pc, _, _, _ := runtime.Caller(1)
caller := runtime.FuncForPC(pc).Name()
// format arguments
var jsonArgs []string
for _, arg := range args {
jsonArg, err := json.Marshal(arg)
if err != nil {
jsonArg = []byte(fmt.Sprintf("%#v", arg))
}
jsonArgs = append(jsonArgs, string(jsonArg))
}
// format log line
argsStr := strings.Join(jsonArgs, ", ")
logLine := fmt.Sprintf("%s(%s)\n", caller, argsStr)
// write log line
writeToLogFile(logLine)
// return a function that can be called to log the return value
return func(ret ...any) {
// get line number of calling function
_, _, line, _ := runtime.Caller(1)
var jsonRet []string
for _, r := range ret {
jsonR, err := json.Marshal(r)
if err != nil {
jsonR = []byte(fmt.Sprintf("%#v", r))
}
jsonRet = append(jsonRet, string(jsonR))
}
retStr := strings.Join(jsonRet, ", ")
origLine := strings.TrimRight(logLine, "\n")
logLine = fmt.Sprintf("%s:%d = %s\n", origLine, line, retStr)
writeToLogFile(logLine)
}
}
func DebugHTTP(c *http.Client, r *http.Request) (*http.Response, error) {
if Config.Debug.LogFile == "" {
return c.Do(r)
}
var logEntry strings.Builder
logEntry.WriteString(fmt.Sprintf(
"=== %s %s ===\n",
r.Method,
r.URL.RequestURI(),
))
// get request body
var reqBody []byte
if r.Body != nil {
reqBody, _ = io.ReadAll(r.Body)
r.Body.Close()
r.Body = io.NopCloser(bytes.NewReader(reqBody))
}
if Config.Debug.RedactPasswords {
r := regexp.MustCompile("smb://[^@]+@")
reqBody = r.ReplaceAll(reqBody, []byte("smb://<redacted>@"))
}
if len(reqBody) > 0 {
logEntry.WriteString(fmt.Sprintf(
"Request body:\n%s\n",
reqBody,
))
}
// do request
resp, reqErr := c.Do(r)
// get response body
var respBody []byte
if resp != nil && resp.Body != nil {
respBody, _ = io.ReadAll(resp.Body)
resp.Body.Close()
resp.Body = io.NopCloser(bytes.NewReader(respBody))
}
if len(respBody) > 0 {
logEntry.WriteString(fmt.Sprintf(
"Response body:\n%s\n",
respBody,
))
}
// write log line
logEntry.WriteString("=== END ===\n")
writeToLogFile(logEntry.String())
return resp, reqErr
}