feat: improve error handling in OLTP APIs

This commit is contained in:
Yang Luo
2026-04-05 02:27:04 +08:00
parent 9030a06792
commit f6a3fb9455
3 changed files with 48 additions and 26 deletions

View File

@@ -34,27 +34,28 @@ func (c *ApiController) AddOtlpTrace() {
if body == nil {
return
}
provider := resolveOpenClawProvider(c.Ctx)
if provider == nil {
provider, status, err := resolveOpenClawProvider(c.Ctx)
if err != nil {
responseOtlpError(c.Ctx, status, body, err.Error())
return
}
var req coltracepb.ExportTraceServiceRequest
if err := proto.Unmarshal(body, &req); err != nil {
responseOtlpError(c.Ctx, 400, "bad protobuf: %v", err)
responseOtlpError(c.Ctx, 400, body, "bad protobuf: %v", err)
return
}
message, err := protojson.MarshalOptions{Multiline: true, Indent: " "}.Marshal(&req)
if err != nil {
responseOtlpError(c.Ctx, 500, "marshal trace failed: %v", err)
responseOtlpError(c.Ctx, 500, body, "marshal trace failed: %v", err)
return
}
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
userAgent := c.Ctx.Request.Header.Get("User-Agent")
if err := provider.AddTrace(message, clientIp, userAgent); err != nil {
responseOtlpError(c.Ctx, 500, "save trace failed: %v", err)
responseOtlpError(c.Ctx, 500, body, "save trace failed: %v", err)
return
}
@@ -74,27 +75,28 @@ func (c *ApiController) AddOtlpMetrics() {
if body == nil {
return
}
provider := resolveOpenClawProvider(c.Ctx)
if provider == nil {
provider, status, err := resolveOpenClawProvider(c.Ctx)
if err != nil {
responseOtlpError(c.Ctx, status, body, err.Error())
return
}
var req colmetricspb.ExportMetricsServiceRequest
if err := proto.Unmarshal(body, &req); err != nil {
responseOtlpError(c.Ctx, 400, "bad protobuf: %v", err)
responseOtlpError(c.Ctx, 400, body, "bad protobuf: %v", err)
return
}
message, err := protojson.MarshalOptions{Multiline: true, Indent: " "}.Marshal(&req)
if err != nil {
responseOtlpError(c.Ctx, 500, "marshal metrics failed: %v", err)
responseOtlpError(c.Ctx, 500, body, "marshal metrics failed: %v", err)
return
}
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
userAgent := c.Ctx.Request.Header.Get("User-Agent")
if err := provider.AddMetrics(message, clientIp, userAgent); err != nil {
responseOtlpError(c.Ctx, 500, "save metrics failed: %v", err)
responseOtlpError(c.Ctx, 500, body, "save metrics failed: %v", err)
return
}
@@ -114,27 +116,28 @@ func (c *ApiController) AddOtlpLogs() {
if body == nil {
return
}
provider := resolveOpenClawProvider(c.Ctx)
if provider == nil {
provider, status, err := resolveOpenClawProvider(c.Ctx)
if err != nil {
responseOtlpError(c.Ctx, status, body, err.Error())
return
}
var req collogspb.ExportLogsServiceRequest
if err := proto.Unmarshal(body, &req); err != nil {
responseOtlpError(c.Ctx, 400, "bad protobuf: %v", err)
responseOtlpError(c.Ctx, 400, body, "bad protobuf: %v", err)
return
}
message, err := protojson.MarshalOptions{Multiline: true, Indent: " "}.Marshal(&req)
if err != nil {
responseOtlpError(c.Ctx, 500, "marshal logs failed: %v", err)
responseOtlpError(c.Ctx, 500, body, "marshal logs failed: %v", err)
return
}
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
userAgent := c.Ctx.Request.Header.Get("User-Agent")
if err := provider.AddLogs(message, clientIp, userAgent); err != nil {
responseOtlpError(c.Ctx, 500, "save logs failed: %v", err)
responseOtlpError(c.Ctx, 500, body, "save logs failed: %v", err)
return
}

View File

@@ -25,33 +25,53 @@ import (
"github.com/casdoor/casdoor/util"
)
func responseOtlpError(ctx *context.Context, status int, format string, args ...interface{}) {
func responseOtlpError(ctx *context.Context, status int, body []byte, format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
req := ctx.Request
bodyInfo := "(no body)"
if len(body) > 0 {
bodyInfo = fmt.Sprintf("%d bytes: %q", len(body), truncate(body, 256))
}
fmt.Printf("responseOtlpError: [%d] %s | %s %s | remoteAddr=%s | Content-Type=%s | User-Agent=%s | body=%s\n",
status, msg,
req.Method, req.URL.Path,
req.RemoteAddr,
req.Header.Get("Content-Type"),
req.Header.Get("User-Agent"),
bodyInfo,
)
ctx.Output.SetStatus(status)
ctx.Output.Body([]byte(fmt.Sprintf(format, args...)))
ctx.Output.Body([]byte(msg))
}
func resolveOpenClawProvider(ctx *context.Context) *log.OpenClawProvider {
func truncate(b []byte, max int) []byte {
if len(b) <= max {
return b
}
return b[:max]
}
func resolveOpenClawProvider(ctx *context.Context) (*log.OpenClawProvider, int, error) {
clientIP := util.GetClientIpFromRequest(ctx.Request)
provider, err := object.GetOpenClawProviderByIP(clientIP)
if err != nil {
responseOtlpError(ctx, 500, "provider lookup failed: %v", err)
return nil
return nil, 500, fmt.Errorf("provider lookup failed: %w", err)
}
if provider == nil {
responseOtlpError(ctx, 403, "forbidden: no OpenClaw provider configured for IP %s", clientIP)
return nil
return nil, 403, fmt.Errorf("forbidden: no OpenClaw provider configured for IP %s", clientIP)
}
return provider
return provider, 0, nil
}
func readProtobufBody(ctx *context.Context) []byte {
if !strings.HasPrefix(ctx.Input.Header("Content-Type"), "application/x-protobuf") {
responseOtlpError(ctx, 415, "unsupported content type")
preview, _ := io.ReadAll(io.LimitReader(ctx.Request.Body, 256))
responseOtlpError(ctx, 415, preview, "unsupported content type")
return nil
}
body, err := io.ReadAll(ctx.Request.Body)
if err != nil {
responseOtlpError(ctx, 400, "read body failed")
responseOtlpError(ctx, 400, nil, "read body failed")
return nil
}
return body

View File

@@ -37,7 +37,6 @@ type Entry struct {
Message string `xorm:"mediumtext" json:"message"`
}
func GetEntries(owner string) ([]*Entry, error) {
entries := []*Entry{}
err := ormer.Engine.Desc("created_time").Find(&entries, &Entry{Owner: owner})