From 79ab4460bcfdac8ac8f5990dda859f1b8aee00ca Mon Sep 17 00:00:00 2001 From: shanshanzhong Date: Mon, 25 May 2026 12:18:27 -0700 Subject: [PATCH] feat: add GET /v1/admin/log/message/detail endpoint Adds a temporary admin endpoint to query log_message by ID, returning the full record including context (JSON) and digest fields that the existing /error_message/detail endpoint omits. Co-authored-by: multica-agent --- apis/admin/log.api | 28 ++++++++ .../admin/log/getLogMessageRawHandler.go | 23 +++++++ internal/handler/routes.go | 3 + .../logic/admin/log/getLogMessageRawLogic.go | 66 +++++++++++++++++++ internal/types/types.go | 28 ++++++++ 5 files changed, 148 insertions(+) create mode 100644 internal/handler/admin/log/getLogMessageRawHandler.go create mode 100644 internal/logic/admin/log/getLogMessageRawLogic.go diff --git a/apis/admin/log.api b/apis/admin/log.api index 8575ca3..3d24dc4 100644 --- a/apis/admin/log.api +++ b/apis/admin/log.api @@ -239,6 +239,30 @@ type ( OccurredAt int64 `json:"occurred_at"` CreatedAt int64 `json:"created_at"` } + GetLogMessageRawRequest { + Id int64 `form:"id" validate:"required"` + } + GetLogMessageRawResponse { + Id int64 `json:"id"` + Platform string `json:"platform"` + AppVersion string `json:"app_version"` + OsName string `json:"os_name"` + OsVersion string `json:"os_version"` + DeviceId string `json:"device_id"` + UserId *int64 `json:"user_id"` + SessionId string `json:"session_id"` + Level uint8 `json:"level"` + ErrorCode string `json:"error_code"` + Message string `json:"message"` + Stack string `json:"stack"` + Context interface{} `json:"context"` + ClientIP string `json:"client_ip"` + UserAgent string `json:"user_agent"` + Locale string `json:"locale"` + Digest string `json:"digest"` + OccurredAt int64 `json:"occurred_at"` + CreatedAt int64 `json:"created_at"` + } ) @server ( @@ -314,5 +338,9 @@ service ppanel { @doc "Get error log message detail" @handler GetErrorLogMessageDetail get /error_message/detail returns (GetErrorLogMessageDetailResponse) + + @doc "Get log message raw detail (temporary)" + @handler GetLogMessageRaw + get /message/detail (GetLogMessageRawRequest) returns (GetLogMessageRawResponse) } diff --git a/internal/handler/admin/log/getLogMessageRawHandler.go b/internal/handler/admin/log/getLogMessageRawHandler.go new file mode 100644 index 0000000..2060c33 --- /dev/null +++ b/internal/handler/admin/log/getLogMessageRawHandler.go @@ -0,0 +1,23 @@ +package log + +import ( + "github.com/gin-gonic/gin" + "github.com/perfect-panel/server/internal/logic/admin/log" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/result" +) + +func GetLogMessageRawHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { + return func(c *gin.Context) { + var req types.GetLogMessageRawRequest + _ = c.ShouldBind(&req) + if err := svcCtx.Validate(&req); err != nil { + result.ParamErrorResult(c, err) + return + } + l := log.NewGetLogMessageRawLogic(c.Request.Context(), svcCtx) + resp, err := l.GetLogMessageRaw(&req) + result.HttpResult(c, resp, err) + } +} diff --git a/internal/handler/routes.go b/internal/handler/routes.go index 5e387ea..534f4a6 100644 --- a/internal/handler/routes.go +++ b/internal/handler/routes.go @@ -256,6 +256,9 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) { // Get error log message detail adminLogGroupRouter.GET("/error_message/detail", adminLog.GetErrorLogMessageDetailHandler(serverCtx)) + // Get log message raw detail (temporary) + adminLogGroupRouter.GET("/message/detail", adminLog.GetLogMessageRawHandler(serverCtx)) + // Get error log message list adminLogGroupRouter.GET("/error_message/list", adminLog.GetErrorLogMessageListHandler(serverCtx)) diff --git a/internal/logic/admin/log/getLogMessageRawLogic.go b/internal/logic/admin/log/getLogMessageRawLogic.go new file mode 100644 index 0000000..1997ba5 --- /dev/null +++ b/internal/logic/admin/log/getLogMessageRawLogic.go @@ -0,0 +1,66 @@ +package log + +import ( + "context" + "encoding/json" + + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type GetLogMessageRawLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewGetLogMessageRawLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetLogMessageRawLogic { + return &GetLogMessageRawLogic{Logger: logger.WithContext(ctx), ctx: ctx, svcCtx: svcCtx} +} + +func (l *GetLogMessageRawLogic) GetLogMessageRaw(req *types.GetLogMessageRawRequest) (resp *types.GetLogMessageRawResponse, err error) { + row, err := l.svcCtx.LogMessageModel.FindOne(l.ctx, req.Id) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "FindOne log_message id=%d: %v", req.Id, err) + } + + var contextJSON json.RawMessage + if row.Context != "" { + if json.Valid([]byte(row.Context)) { + contextJSON = json.RawMessage(row.Context) + } else { + b, _ := json.Marshal(row.Context) + contextJSON = b + } + } + + var occurredAt int64 + if row.OccurredAt != nil { + occurredAt = row.OccurredAt.UnixMilli() + } + + return &types.GetLogMessageRawResponse{ + Id: row.Id, + Platform: row.Platform, + AppVersion: row.AppVersion, + OsName: row.OsName, + OsVersion: row.OsVersion, + DeviceId: row.DeviceId, + UserId: row.UserId, + SessionId: row.SessionId, + Level: row.Level, + ErrorCode: row.ErrorCode, + Message: row.Message, + Stack: row.Stack, + Context: contextJSON, + ClientIP: row.ClientIP, + UserAgent: row.UserAgent, + Locale: row.Locale, + Digest: row.Digest, + OccurredAt: occurredAt, + CreatedAt: row.CreatedAt.UnixMilli(), + }, nil +} diff --git a/internal/types/types.go b/internal/types/types.go index 385aec1..b226201 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -3,6 +3,8 @@ package types +import "encoding/json" + type ActivateOrderRequest struct { OrderNo string `json:"order_no" validate:"required"` } @@ -3641,3 +3643,29 @@ type GetAdminUserInviteListResponse struct { Total int64 `json:"total"` List []AdminInvitedUser `json:"list"` } + +type GetLogMessageRawRequest struct { + Id int64 `form:"id" validate:"required"` +} + +type GetLogMessageRawResponse struct { + Id int64 `json:"id"` + Platform string `json:"platform"` + AppVersion string `json:"app_version"` + OsName string `json:"os_name"` + OsVersion string `json:"os_version"` + DeviceId string `json:"device_id"` + UserId *int64 `json:"user_id"` + SessionId string `json:"session_id"` + Level uint8 `json:"level"` + ErrorCode string `json:"error_code"` + Message string `json:"message"` + Stack string `json:"stack"` + Context json.RawMessage `json:"context"` + ClientIP string `json:"client_ip"` + UserAgent string `json:"user_agent"` + Locale string `json:"locale"` + Digest string `json:"digest"` + OccurredAt int64 `json:"occurred_at"` + CreatedAt int64 `json:"created_at"` +}