fix(watchdog): fix watchdog unable to send webhook and simplify the parsing of json config
- Change webhook config headers and body from map to string format - Move command parsing logic to separate function in command.go - Add debug logging for webhook operations - Improve exception handling with proper JSON parsing - Simplify config loading logic with default values
This commit is contained in:
@@ -57,17 +57,29 @@ func LoadConfig(configPath string, getInitSystem func() string) error {
|
|||||||
return fmt.Errorf("failed to parse config file: %w", err)
|
return fmt.Errorf("failed to parse config file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if fileConfig.ListenAddr != "" {
|
global.CurrentConfig.ListenAddr = fileConfig.ListenAddr
|
||||||
global.CurrentConfig.ListenAddr = fileConfig.ListenAddr
|
global.CurrentConfig.ListenPort = fileConfig.ListenPort
|
||||||
|
global.CurrentConfig.FrpcPath = fileConfig.FrpcPath
|
||||||
|
global.CurrentConfig.InstancePath = fileConfig.InstancePath
|
||||||
|
global.CurrentConfig.Debug = fileConfig.Debug
|
||||||
|
global.CurrentConfig.Watchdog.Enabled = fileConfig.Watchdog.Enabled
|
||||||
|
global.CurrentConfig.Watchdog.Port = fileConfig.Watchdog.Port
|
||||||
|
global.CurrentConfig.Notification.Enabled = fileConfig.Notification.Enabled
|
||||||
|
global.CurrentConfig.Notification.Method = fileConfig.Notification.Method
|
||||||
|
global.CurrentConfig.Webhook.Method = fileConfig.Webhook.Method
|
||||||
|
global.CurrentConfig.Webhook.URL = fileConfig.Webhook.URL
|
||||||
|
global.CurrentConfig.Webhook.Headers = fileConfig.Webhook.Headers
|
||||||
|
global.CurrentConfig.Webhook.Body = fileConfig.Webhook.Body
|
||||||
|
|
||||||
|
if fileConfig.ListenAddr == "" {
|
||||||
|
global.CurrentConfig.ListenAddr = "0.0.0.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
if fileConfig.ListenPort != "" {
|
if fileConfig.ListenPort == "" {
|
||||||
global.CurrentConfig.ListenPort = fileConfig.ListenPort
|
global.CurrentConfig.ListenPort = "7000"
|
||||||
}
|
}
|
||||||
|
|
||||||
if fileConfig.FrpcPath != "" {
|
if fileConfig.FrpcPath == "" {
|
||||||
global.CurrentConfig.FrpcPath = fileConfig.FrpcPath
|
|
||||||
} else {
|
|
||||||
if getInitSystem() == "windows" {
|
if getInitSystem() == "windows" {
|
||||||
global.CurrentConfig.FrpcPath = "frp_client/frpc.exe"
|
global.CurrentConfig.FrpcPath = "frp_client/frpc.exe"
|
||||||
} else {
|
} else {
|
||||||
@@ -75,22 +87,14 @@ func LoadConfig(configPath string, getInitSystem func() string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if fileConfig.InstancePath != "" {
|
if fileConfig.InstancePath == "" {
|
||||||
global.CurrentConfig.InstancePath = fileConfig.InstancePath
|
|
||||||
} else {
|
|
||||||
global.CurrentConfig.InstancePath = "./configs"
|
global.CurrentConfig.InstancePath = "./configs"
|
||||||
}
|
}
|
||||||
|
|
||||||
global.CurrentConfig.Debug = fileConfig.Debug
|
if fileConfig.Watchdog.Port == 0 {
|
||||||
|
|
||||||
if fileConfig.Watchdog.Port != 0 {
|
|
||||||
global.CurrentConfig.Watchdog.Port = fileConfig.Watchdog.Port
|
|
||||||
} else {
|
|
||||||
global.CurrentConfig.Watchdog.Port = 12380
|
global.CurrentConfig.Watchdog.Port = 12380
|
||||||
}
|
}
|
||||||
|
|
||||||
global.CurrentConfig.Watchdog.Enabled = fileConfig.Watchdog.Enabled
|
|
||||||
|
|
||||||
if err := os.MkdirAll(global.CurrentConfig.InstancePath, 0755); err != nil {
|
if err := os.MkdirAll(global.CurrentConfig.InstancePath, 0755); err != nil {
|
||||||
return fmt.Errorf("failed to create config directory: %w", err)
|
return fmt.Errorf("failed to create config directory: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,53 +51,49 @@ type Config struct {
|
|||||||
Debug bool `json:"debug"`
|
Debug bool `json:"debug"`
|
||||||
Watchdog struct {
|
Watchdog struct {
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
Port int `json:"port"`
|
Port int `json:"port"`
|
||||||
} `json:"watchdog"`
|
} `json:"watchdog"`
|
||||||
Notification struct {
|
Notification struct {
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
} `json:"notification"`
|
} `json:"notification"`
|
||||||
Webhook struct {
|
Webhook struct {
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
Headers map[string]string `json:"headers"`
|
Headers string `json:"headers"`
|
||||||
Body map[string]string `json:"body"`
|
Body string `json:"body"`
|
||||||
} `json:"webhook"`
|
} `json:"webhook"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var CurrentConfig = Config{
|
var CurrentConfig = Config{
|
||||||
ListenAddr: "0.0.0.0",
|
ListenAddr: "0.0.0.0",
|
||||||
ListenPort: "7000",
|
ListenPort: "7000",
|
||||||
FrpcPath: "",
|
FrpcPath: "",
|
||||||
InstancePath: "",
|
InstancePath: "",
|
||||||
Debug: false,
|
Debug: false,
|
||||||
Watchdog: struct {
|
Watchdog: struct {
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
Port int `json:"port"`
|
Port int `json:"port"`
|
||||||
}{
|
}{
|
||||||
Enabled: false,
|
Enabled: false,
|
||||||
Port: 0,
|
Port: 0,
|
||||||
},
|
},
|
||||||
Notification: struct {
|
Notification: struct {
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
}{
|
}{
|
||||||
Enabled: false,
|
Enabled: false,
|
||||||
Method: "webhook",
|
Method: "webhook",
|
||||||
},
|
},
|
||||||
Webhook: struct {
|
Webhook: struct {
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
Headers map[string]string `json:"headers"`
|
Headers string `json:"headers"`
|
||||||
Body map[string]string `json:"body"`
|
Body string `json:"body"`
|
||||||
}{
|
}{
|
||||||
Method: "",
|
Method: "",
|
||||||
URL: "",
|
URL: "",
|
||||||
Headers: map[string]string{
|
Headers: "Content-Type: application/json",
|
||||||
"Content-Type": "",
|
Body: "",
|
||||||
},
|
|
||||||
Body: map[string]string{
|
|
||||||
"text": "",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package watchdog
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"super-frpc/postLog"
|
"super-frpc/postLog"
|
||||||
|
"super-frpc/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func AddInstance(serviceName string) bool {
|
func AddInstance(serviceName string) bool {
|
||||||
@@ -70,4 +71,17 @@ func Close() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseCommand(cmd string) (result string, err error) {
|
||||||
|
cmdType := utils.GetCmdType(cmd)
|
||||||
|
if cmdType == "Exception" {
|
||||||
|
// Watchdog msg: [Exception] <exceptionType>...</exceptionType> <serviceName>...</serviceName> <errorMsg>...</errorMsg>
|
||||||
|
exceptionType := utils.GetCmdParams(cmd, "exceptionType")
|
||||||
|
serviceName := utils.GetCmdParams(cmd, "serviceName")
|
||||||
|
errorMsg := utils.GetCmdParams(cmd, "errorMsg")
|
||||||
|
postLog.Error(fmt.Sprintf("[Watchdog] Exception[%s]: %s, %s", serviceName, exceptionType, errorMsg))
|
||||||
|
exceptionHandle(exceptionType, serviceName, errorMsg)
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
}
|
}
|
||||||
@@ -1,18 +1,26 @@
|
|||||||
package watchdog
|
package watchdog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"super-frpc/global"
|
"super-frpc/global"
|
||||||
|
"super-frpc/postLog"
|
||||||
"super-frpc/webhook"
|
"super-frpc/webhook"
|
||||||
)
|
)
|
||||||
|
|
||||||
func exceptionHandle(exceptionType string, serviceName string, errorMsg string) {
|
func exceptionHandle(exceptionType string, serviceName string, errorMsg string) {
|
||||||
if global.CurrentConfig.Notification.Enabled {
|
if global.CurrentConfig.Notification.Enabled {
|
||||||
body := make(map[string]string)
|
if global.CurrentConfig.Notification.Method == "webhook" {
|
||||||
if global.CurrentConfig.Notification.Method == "Webhook" {
|
var bodyMap map[string]string
|
||||||
for k, v := range global.CurrentConfig.Webhook.Body {
|
err := json.Unmarshal([]byte(global.CurrentConfig.Webhook.Body), &bodyMap)
|
||||||
|
if err != nil {
|
||||||
|
postLog.Error(fmt.Sprintf("[exceptionHandler] Failed to parse webhook body: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range bodyMap {
|
||||||
replaced := v
|
replaced := v
|
||||||
for strings.Contains(replaced, "{{ exceptionType }}") ||
|
for strings.Contains(replaced, "{{ exceptionType }}") ||
|
||||||
strings.Contains(replaced, "{{ serviceName }}") ||
|
strings.Contains(replaced, "{{ serviceName }}") ||
|
||||||
@@ -21,17 +29,33 @@ func exceptionHandle(exceptionType string, serviceName string, errorMsg string)
|
|||||||
replaced = strings.ReplaceAll(replaced, "{{ serviceName }}", serviceName)
|
replaced = strings.ReplaceAll(replaced, "{{ serviceName }}", serviceName)
|
||||||
replaced = strings.ReplaceAll(replaced, "{{ exceptionMsg }}", errorMsg)
|
replaced = strings.ReplaceAll(replaced, "{{ exceptionMsg }}", errorMsg)
|
||||||
}
|
}
|
||||||
body[k] = replaced
|
bodyMap[k] = replaced
|
||||||
}
|
}
|
||||||
|
|
||||||
bodyJSON := ""
|
bodyJSON, err := json.Marshal(bodyMap)
|
||||||
for k, v := range body {
|
if err != nil {
|
||||||
bodyJSON = fmt.Sprintf(`{"%s": "%s"}`, k, v)
|
postLog.Error(fmt.Sprintf("[exceptionHandler] Failed to marshal webhook body: %v", err))
|
||||||
break
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
webhook.SendHook(global.CurrentConfig.Webhook.URL, global.CurrentConfig.Webhook.Method, global.CurrentConfig.Webhook.Headers, bodyJSON)
|
// Parse headers as map[string]string format
|
||||||
|
headersMap := make(map[string]string)
|
||||||
|
headerPairs := strings.Split(global.CurrentConfig.Webhook.Headers, ";")
|
||||||
|
for _, pair := range headerPairs {
|
||||||
|
pair = strings.TrimSpace(pair)
|
||||||
|
if pair == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
parts := strings.SplitN(pair, ":", 2)
|
||||||
|
if len(parts) == 2 {
|
||||||
|
headersMap[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
webhook.SendHook(global.CurrentConfig.Webhook.URL, global.CurrentConfig.Webhook.Method, headersMap, string(bodyJSON))
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
postLog.Warning("[exceptionHandler] exception occoured, but notification is not enabled!")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"super-frpc/postLog"
|
|
||||||
"super-frpc/utils"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -117,15 +115,8 @@ func recvMsg() {
|
|||||||
}
|
}
|
||||||
// Here add logic to handle the message
|
// Here add logic to handle the message
|
||||||
if !isResponseMessage(line) {
|
if !isResponseMessage(line) {
|
||||||
postLog.Debug(fmt.Sprintf("[Watchdog] TCP Socket received message: %s", line))
|
// postLog.Debug(fmt.Sprintf("[Watchdog] TCP Socket received message: %s", line))
|
||||||
cmdType := utils.GetCmdType(line)
|
parseCommand(line)
|
||||||
if cmdType == "Exception" {
|
|
||||||
exceptionType := utils.GetCmdParams(line, "exceptionType")
|
|
||||||
serviceName := utils.GetCmdParams(line, "serviceName")
|
|
||||||
errorMsg := utils.GetCmdParams(line, "errorMsg")
|
|
||||||
postLog.Error(fmt.Sprintf("[Watchdog] Exception[%s]: %s, %s", serviceName, exceptionType, errorMsg))
|
|
||||||
exceptionHandle(exceptionType, serviceName, errorMsg)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
// If the status code is not 200, it logs the error and returns the status code and response message.
|
// If the status code is not 200, it logs the error and returns the status code and response message.
|
||||||
// If the status code is 200, it returns an empty error message, status code, and response message.
|
// If the status code is 200, it returns an empty error message, status code, and response message.
|
||||||
func SendHook(url string, method string, headers map[string]string, body string) (err string, code int, msg string) {
|
func SendHook(url string, method string, headers map[string]string, body string) (err string, code int, msg string) {
|
||||||
|
postLog.Debug(fmt.Sprintf("[SendHook] SendHook { %s, %s, %s, %s }", url, method, headers, body))
|
||||||
req, reqErr := http.NewRequest(method, url, strings.NewReader(body))
|
req, reqErr := http.NewRequest(method, url, strings.NewReader(body))
|
||||||
if reqErr != nil {
|
if reqErr != nil {
|
||||||
return reqErr.Error(), 500, ""
|
return reqErr.Error(), 500, ""
|
||||||
@@ -34,6 +35,8 @@ func SendHook(url string, method string, headers map[string]string, body string)
|
|||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
postLog.Debug(fmt.Sprintf("[SendHook] SendHook { %s, %s, %s, %s } failed, status code: %d, response: [%s]: %s", url, method, headers, body, resp.StatusCode, resp.Status, respMsg))
|
postLog.Debug(fmt.Sprintf("[SendHook] SendHook { %s, %s, %s, %s } failed, status code: %d, response: [%s]: %s", url, method, headers, body, resp.StatusCode, resp.Status, respMsg))
|
||||||
return fmt.Sprintf("unexpected status code: %d, response: [%s]: %s", resp.StatusCode, resp.Status, respMsg), resp.StatusCode, respMsg
|
return fmt.Sprintf("unexpected status code: %d, response: [%s]: %s", resp.StatusCode, resp.Status, respMsg), resp.StatusCode, respMsg
|
||||||
|
} else {
|
||||||
|
postLog.Debug(fmt.Sprintf("[SendHook] SendHook { %s, %s, %s, %s } success, status code: %d, response: [%s]: %s", url, method, headers, body, resp.StatusCode, resp.Status, respMsg))
|
||||||
}
|
}
|
||||||
return "", 200, ""
|
return "", 200, ""
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user