优化开放接口日志分类

This commit is contained in:
yml2213
2026-07-30 21:07:10 +08:00
parent 9c3414607a
commit a16e518b6c
6 changed files with 210 additions and 9 deletions
+116 -9
View File
@@ -11,11 +11,32 @@ import (
)
const (
CtxReqID = "open_req_id"
CtxDebug = "open_debug"
CtxBody = "open_body"
CtxStart = "open_start"
CtxAPIKey = "open_api_key"
CtxReqID = "open_req_id"
CtxDebug = "open_debug"
CtxBody = "open_body"
CtxStart = "open_start"
CtxAPIKey = "open_api_key"
CtxSide = "open_side"
CtxAPIType = "open_api_type"
CtxAction = "open_action"
)
const (
SideClient = "client"
SideSource = "source"
APITypeClientV1 = "client_v1"
APITypeSourceOpenV1 = "source_open_v1"
APITypeUnknown = "unknown"
ActionAuth = "auth"
ActionList = "list"
ActionCreate = "create"
ActionQuery = "query"
ActionCancel = "cancel"
ActionWallet = "wallet"
ActionPush = "push"
ActionUnknown = "unknown"
)
// Enabled 是否开启开放接口详细日志
@@ -50,6 +71,38 @@ func EnsureReqID(c *gin.Context) string {
return id
}
func SetScope(c *gin.Context, side, action string) {
c.Set(CtxSide, side)
c.Set(CtxAPIType, APITypeFromSide(side))
c.Set(CtxAction, action)
}
func SetAction(c *gin.Context, action string) {
c.Set(CtxAction, action)
}
func ScopeFromPath(side, method, path string) (string, string) {
action := ActionUnknown
switch side {
case SideClient:
action = clientAction(method, path)
case SideSource:
action = sourceAction(method, path)
}
return side, action
}
func APITypeFromSide(side string) string {
switch side {
case SideClient:
return APITypeClientV1
case SideSource:
return APITypeSourceOpenV1
default:
return APITypeUnknown
}
}
func IsDebug(c *gin.Context) bool {
if !Enabled {
return false
@@ -92,12 +145,37 @@ func Truncate(s string, max int) string {
return s[:max] + fmt.Sprintf("...(%d bytes)", len(s))
}
func Prefix(c *gin.Context) string {
side, _ := c.Get(CtxSide)
apiType, _ := c.Get(CtxAPIType)
action, _ := c.Get(CtxAction)
sideText, _ := side.(string)
apiTypeText, _ := apiType.(string)
actionText, _ := action.(string)
tag := "open"
if apiTypeText != "" && apiTypeText != APITypeUnknown {
tag += "." + apiTypeText
} else if sideText != "" {
tag += "." + sideText
}
if actionText != "" {
tag += "." + actionText
}
fields := ""
if apiTypeText != "" {
fields += fmt.Sprintf(" api_type=%s", apiTypeText)
}
if actionText != "" {
fields += fmt.Sprintf(" action=%s", actionText)
}
return fmt.Sprintf("[%s] req_id=%s%s ", tag, GetReqID(c), fields)
}
func Info(c *gin.Context, format string, args ...interface{}) {
if !IsDebug(c) {
return
}
prefix := fmt.Sprintf("[open] req_id=%s ", GetReqID(c))
log.Printf(prefix+format, args...)
log.Printf(Prefix(c)+format, args...)
}
func Warn(c *gin.Context, format string, args ...interface{}) {
@@ -105,8 +183,7 @@ func Warn(c *gin.Context, format string, args ...interface{}) {
if !Enabled {
return
}
prefix := fmt.Sprintf("[open] req_id=%s ", GetReqID(c))
log.Printf(prefix+format, args...)
log.Printf(Prefix(c)+format, args...)
}
func Elapsed(c *gin.Context) time.Duration {
@@ -117,3 +194,33 @@ func Elapsed(c *gin.Context) time.Duration {
}
return 0
}
func clientAction(method, path string) string {
method = strings.ToUpper(method)
switch {
case method == "GET" && path == "/api/client/v1/products":
return ActionList
case method == "POST" && path == "/api/client/v1/orders":
return ActionCreate
case method == "GET" && strings.HasPrefix(path, "/api/client/v1/orders/"):
return ActionQuery
case method == "POST" && strings.HasPrefix(path, "/api/client/v1/orders/") && strings.HasSuffix(path, "/cancel"):
return ActionCancel
case method == "GET" && path == "/api/client/v1/wallet":
return ActionWallet
default:
return ActionUnknown
}
}
func sourceAction(method, path string) string {
method = strings.ToUpper(method)
switch {
case method == "GET" && strings.HasPrefix(path, "/api/open/v1/orders/"):
return ActionQuery
case method == "POST" && path == "/api/open/v1/orders/ship-notify":
return ActionPush
default:
return ActionUnknown
}
}
@@ -0,0 +1,83 @@
package openlog
import (
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
)
func TestPrefixIncludesSideAndAction(t *testing.T) {
gin.SetMode(gin.TestMode)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Set(CtxReqID, "req123")
SetScope(c, SideSource, ActionPush)
got := Prefix(c)
want := "[open.source_open_v1.push] req_id=req123 api_type=source_open_v1 action=push "
if got != want {
t.Fatalf("prefix mismatch: got %q want %q", got, want)
}
}
func TestScopeFromPath(t *testing.T) {
cases := []struct {
name string
side string
method string
path string
wantSide string
wantAction string
wantType string
}{
{
name: "客户侧查询订单",
side: SideClient,
method: "GET",
path: "/api/client/v1/orders/FO123",
wantSide: SideClient,
wantAction: ActionQuery,
wantType: APITypeClientV1,
},
{
name: "客户侧创建订单",
side: SideClient,
method: "POST",
path: "/api/client/v1/orders",
wantSide: SideClient,
wantAction: ActionCreate,
wantType: APITypeClientV1,
},
{
name: "源头侧发货推送",
side: SideSource,
method: "POST",
path: "/api/open/v1/orders/ship-notify",
wantSide: SideSource,
wantAction: ActionPush,
wantType: APITypeSourceOpenV1,
},
{
name: "源头侧查询订单",
side: SideSource,
method: "GET",
path: "/api/open/v1/orders/FO123",
wantSide: SideSource,
wantAction: ActionQuery,
wantType: APITypeSourceOpenV1,
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
gotSide, gotAction := ScopeFromPath(tc.side, tc.method, tc.path)
if gotSide != tc.wantSide || gotAction != tc.wantAction {
t.Fatalf("scope mismatch: got %s/%s want %s/%s", gotSide, gotAction, tc.wantSide, tc.wantAction)
}
if gotType := APITypeFromSide(gotSide); gotType != tc.wantType {
t.Fatalf("api type mismatch: got %s want %s", gotType, tc.wantType)
}
})
}
}