Improve package API log handling (#35100)

Simplify code and fix log processing logic
This commit is contained in:
wxiaoguang
2025-07-17 00:25:49 +08:00
committed by GitHub
parent 37958e486a
commit f0da1de7e3
23 changed files with 101 additions and 132 deletions

View File

@@ -25,9 +25,8 @@ import (
) )
func apiError(ctx *context.Context, status int, obj any) { func apiError(ctx *context.Context, status int, obj any) {
helper.LogAndProcessError(ctx, status, obj, func(message string) { message := helper.ProcessErrorForUser(ctx, status, obj)
ctx.PlainText(status, message) ctx.PlainText(status, message)
})
} }
func GetRepositoryKey(ctx *context.Context) { func GetRepositoryKey(ctx *context.Context) {

View File

@@ -24,9 +24,8 @@ import (
) )
func apiError(ctx *context.Context, status int, obj any) { func apiError(ctx *context.Context, status int, obj any) {
helper.LogAndProcessError(ctx, status, obj, func(message string) { message := helper.ProcessErrorForUser(ctx, status, obj)
ctx.PlainText(status, message) ctx.PlainText(status, message)
})
} }
func GetRepositoryKey(ctx *context.Context) { func GetRepositoryKey(ctx *context.Context) {

View File

@@ -37,15 +37,14 @@ type StatusMessage struct {
} }
func apiError(ctx *context.Context, status int, obj any) { func apiError(ctx *context.Context, status int, obj any) {
helper.LogAndProcessError(ctx, status, obj, func(message string) { message := helper.ProcessErrorForUser(ctx, status, obj)
ctx.JSON(status, StatusResponse{ ctx.JSON(status, StatusResponse{
OK: false, OK: false,
Errors: []StatusMessage{ Errors: []StatusMessage{
{ {
Message: message, Message: message,
},
}, },
}) },
}) })
} }

View File

@@ -30,10 +30,9 @@ func apiError(ctx *context.Context, status int, obj any) {
ErrorMessages []string `json:"error_messages"` ErrorMessages []string `json:"error_messages"`
} }
helper.LogAndProcessError(ctx, status, obj, func(message string) { message := helper.ProcessErrorForUser(ctx, status, obj)
ctx.JSON(status, Error{ ctx.JSON(status, Error{
ErrorMessages: []string{message}, ErrorMessages: []string{message},
})
}) })
} }

View File

@@ -28,18 +28,17 @@ import (
) )
func apiError(ctx *context.Context, status int, obj any) { func apiError(ctx *context.Context, status int, obj any) {
helper.LogAndProcessError(ctx, status, obj, func(message string) { message := helper.ProcessErrorForUser(ctx, status, obj)
type Error struct { type Error struct {
Status int `json:"status"` Status int `json:"status"`
Message string `json:"message"` Message string `json:"message"`
} }
ctx.JSON(status, struct { ctx.JSON(status, struct {
Errors []Error `json:"errors"` Errors []Error `json:"errors"`
}{ }{
Errors: []Error{ Errors: []Error{
{Status: status, Message: message}, {Status: status, Message: message},
}, },
})
}) })
} }

View File

@@ -61,10 +61,9 @@ func jsonResponse(ctx *context.Context, status int, obj any) {
} }
func apiError(ctx *context.Context, status int, obj any) { func apiError(ctx *context.Context, status int, obj any) {
helper.LogAndProcessError(ctx, status, obj, func(message string) { message := helper.ProcessErrorForUser(ctx, status, obj)
jsonResponse(ctx, status, map[string]string{ jsonResponse(ctx, status, map[string]string{
"message": message, "message": message,
})
}) })
} }

View File

@@ -25,14 +25,13 @@ import (
) )
func apiError(ctx *context.Context, status int, obj any) { func apiError(ctx *context.Context, status int, obj any) {
helper.LogAndProcessError(ctx, status, obj, func(message string) { message := helper.ProcessErrorForUser(ctx, status, obj)
ctx.JSON(status, struct { ctx.JSON(status, struct {
Reason string `json:"reason"` Reason string `json:"reason"`
Message string `json:"message"` Message string `json:"message"`
}{ }{
Reason: http.StatusText(status), Reason: http.StatusText(status),
Message: message, Message: message,
})
}) })
} }

View File

@@ -93,10 +93,9 @@ func jsonResponse(ctx *context.Context, status int, obj any) {
} }
func apiError(ctx *context.Context, status int, err error) { func apiError(ctx *context.Context, status int, err error) {
helper.LogAndProcessError(ctx, status, err, func(message string) { _ = helper.ProcessErrorForUser(ctx, status, err)
setResponseHeaders(ctx.Resp, &containerHeaders{ setResponseHeaders(ctx.Resp, &containerHeaders{
Status: status, Status: status,
})
}) })
} }

View File

@@ -22,9 +22,8 @@ import (
) )
func apiError(ctx *context.Context, status int, obj any) { func apiError(ctx *context.Context, status int, obj any) {
helper.LogAndProcessError(ctx, status, obj, func(message string) { message := helper.ProcessErrorForUser(ctx, status, obj)
ctx.PlainText(status, message) ctx.PlainText(status, message)
})
} }
func EnumerateSourcePackages(ctx *context.Context) { func EnumerateSourcePackages(ctx *context.Context) {

View File

@@ -24,9 +24,8 @@ import (
) )
func apiError(ctx *context.Context, status int, obj any) { func apiError(ctx *context.Context, status int, obj any) {
helper.LogAndProcessError(ctx, status, obj, func(message string) { message := helper.ProcessErrorForUser(ctx, status, obj)
ctx.PlainText(status, message) ctx.PlainText(status, message)
})
} }
func GetRepositoryKey(ctx *context.Context) { func GetRepositoryKey(ctx *context.Context) {

View File

@@ -24,9 +24,8 @@ var (
) )
func apiError(ctx *context.Context, status int, obj any) { func apiError(ctx *context.Context, status int, obj any) {
helper.LogAndProcessError(ctx, status, obj, func(message string) { message := helper.ProcessErrorForUser(ctx, status, obj)
ctx.PlainText(status, message) ctx.PlainText(status, message)
})
} }
// DownloadPackageFile serves the specific generic package. // DownloadPackageFile serves the specific generic package.

View File

@@ -22,9 +22,8 @@ import (
) )
func apiError(ctx *context.Context, status int, obj any) { func apiError(ctx *context.Context, status int, obj any) {
helper.LogAndProcessError(ctx, status, obj, func(message string) { message := helper.ProcessErrorForUser(ctx, status, obj)
ctx.PlainText(status, message) ctx.PlainText(status, message)
})
} }
func EnumeratePackageVersions(ctx *context.Context) { func EnumeratePackageVersions(ctx *context.Context) {

View File

@@ -28,13 +28,12 @@ import (
) )
func apiError(ctx *context.Context, status int, obj any) { func apiError(ctx *context.Context, status int, obj any) {
helper.LogAndProcessError(ctx, status, obj, func(message string) { message := helper.ProcessErrorForUser(ctx, status, obj)
type Error struct { type Error struct {
Error string `json:"error"` Error string `json:"error"`
} }
ctx.JSON(status, Error{ ctx.JSON(status, Error{
Error: message, Error: message,
})
}) })
} }

View File

@@ -15,31 +15,29 @@ import (
"code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/context"
) )
// LogAndProcessError logs an error and calls a custom callback with the processed error message. // ProcessErrorForUser logs the error and returns a user-error message for the end user.
// If the error is an InternalServerError the message is stripped if the user is not an admin. // If the status is http.StatusInternalServerError, the message is stripped for non-admin users in production.
func LogAndProcessError(ctx *context.Context, status int, obj any, cb func(string)) { func ProcessErrorForUser(ctx *context.Context, status int, errObj any) string {
var message string var message string
if err, ok := obj.(error); ok { if err, ok := errObj.(error); ok {
message = err.Error() message = err.Error()
} else if obj != nil { } else if errObj != nil {
message = fmt.Sprintf("%s", obj) message = fmt.Sprint(errObj)
} }
if status == http.StatusInternalServerError { if status == http.StatusInternalServerError {
log.ErrorWithSkip(1, message) log.Log(2, log.ERROR, "Package registry API internal error: %d %s", status, message)
if setting.IsProd && (ctx.Doer == nil || !ctx.Doer.IsAdmin) { if setting.IsProd && (ctx.Doer == nil || !ctx.Doer.IsAdmin) {
message = "" message = "internal server error"
} }
} else { return message
log.Debug(message)
} }
if cb != nil { log.Log(2, log.DEBUG, "Package registry API user error: %d %s", status, message)
cb(message) return message
}
} }
// Serves the content of the package file // ServePackageFile the content of the package file
// If the url is set it will redirect the request, otherwise the content is copied to the response. // If the url is set it will redirect the request, otherwise the content is copied to the response.
func ServePackageFile(ctx *context.Context, s io.ReadSeekCloser, u *url.URL, pf *packages_model.PackageFile, forceOpts ...*context.ServeHeaderOptions) { func ServePackageFile(ctx *context.Context, s io.ReadSeekCloser, u *url.URL, pf *packages_model.PackageFile, forceOpts ...*context.ServeHeaderOptions) {
if u != nil { if u != nil {

View File

@@ -22,7 +22,6 @@ import (
packages_model "code.gitea.io/gitea/models/packages" packages_model "code.gitea.io/gitea/models/packages"
"code.gitea.io/gitea/modules/globallock" "code.gitea.io/gitea/modules/globallock"
"code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
packages_module "code.gitea.io/gitea/modules/packages" packages_module "code.gitea.io/gitea/modules/packages"
maven_module "code.gitea.io/gitea/modules/packages/maven" maven_module "code.gitea.io/gitea/modules/packages/maven"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
@@ -49,14 +48,9 @@ var (
) )
func apiError(ctx *context.Context, status int, obj any) { func apiError(ctx *context.Context, status int, obj any) {
helper.LogAndProcessError(ctx, status, obj, func(message string) { message := helper.ProcessErrorForUser(ctx, status, obj)
// The maven client does not present the error message to the user. Log it for users with access to server logs. // Maven client doesn't present the error message to end users; site admin can check the server logs that outputted by ProcessErrorForUser
if status == http.StatusBadRequest || status == http.StatusInternalServerError { ctx.PlainText(status, message)
log.Error(message)
}
ctx.PlainText(status, message)
})
} }
// DownloadPackageFile serves the content of a package // DownloadPackageFile serves the content of a package

View File

@@ -33,10 +33,9 @@ import (
var errInvalidTagName = errors.New("The tag name is invalid") var errInvalidTagName = errors.New("The tag name is invalid")
func apiError(ctx *context.Context, status int, obj any) { func apiError(ctx *context.Context, status int, obj any) {
helper.LogAndProcessError(ctx, status, obj, func(message string) { message := helper.ProcessErrorForUser(ctx, status, obj)
ctx.JSON(status, map[string]string{ ctx.JSON(status, map[string]string{
"error": message, "error": message,
})
}) })
} }

View File

@@ -29,10 +29,9 @@ import (
) )
func apiError(ctx *context.Context, status int, obj any) { func apiError(ctx *context.Context, status int, obj any) {
helper.LogAndProcessError(ctx, status, obj, func(message string) { message := helper.ProcessErrorForUser(ctx, status, obj)
ctx.JSON(status, map[string]string{ ctx.JSON(status, map[string]string{
"Message": message, "Message": message,
})
}) })
} }

View File

@@ -43,13 +43,12 @@ func apiError(ctx *context.Context, status int, obj any) {
Error Error `json:"error"` Error Error `json:"error"`
} }
helper.LogAndProcessError(ctx, status, obj, func(message string) { message := helper.ProcessErrorForUser(ctx, status, obj)
jsonResponse(ctx, status, ErrorWrapper{ jsonResponse(ctx, status, ErrorWrapper{
Error: Error{ Error: Error{
Code: http.StatusText(status), Code: http.StatusText(status),
Message: message, Message: message,
}, },
})
}) })
} }

View File

@@ -40,9 +40,8 @@ var versionMatcher = regexp.MustCompile(`\Av?` +
`\z`) `\z`)
func apiError(ctx *context.Context, status int, obj any) { func apiError(ctx *context.Context, status int, obj any) {
helper.LogAndProcessError(ctx, status, obj, func(message string) { message := helper.ProcessErrorForUser(ctx, status, obj)
ctx.PlainText(status, message) ctx.PlainText(status, message)
})
} }
// PackageMetadata returns the metadata for a single package // PackageMetadata returns the metadata for a single package

View File

@@ -26,9 +26,8 @@ import (
) )
func apiError(ctx *context.Context, status int, obj any) { func apiError(ctx *context.Context, status int, obj any) {
helper.LogAndProcessError(ctx, status, obj, func(message string) { message := helper.ProcessErrorForUser(ctx, status, obj)
ctx.PlainText(status, message) ctx.PlainText(status, message)
})
} }
// https://dnf.readthedocs.io/en/latest/conf_ref.html // https://dnf.readthedocs.io/en/latest/conf_ref.html

View File

@@ -25,9 +25,8 @@ import (
) )
func apiError(ctx *context.Context, status int, obj any) { func apiError(ctx *context.Context, status int, obj any) {
helper.LogAndProcessError(ctx, status, obj, func(message string) { message := helper.ProcessErrorForUser(ctx, status, obj)
ctx.PlainText(status, message) ctx.PlainText(status, message)
})
} }
// EnumeratePackages serves the package list // EnumeratePackages serves the package list

View File

@@ -77,17 +77,14 @@ func apiError(ctx *context.Context, status int, obj any) {
Detail string `json:"detail"` Detail string `json:"detail"`
} }
helper.LogAndProcessError(ctx, status, obj, func(message string) { message := helper.ProcessErrorForUser(ctx, status, obj)
setResponseHeaders(ctx.Resp, &headers{ setResponseHeaders(ctx.Resp, &headers{
Status: status, Status: status,
ContentType: "application/problem+json", ContentType: "application/problem+json",
}) })
if err := json.NewEncoder(ctx.Resp).Encode(Problem{ _ = json.NewEncoder(ctx.Resp).Encode(Problem{
Status: status, Status: status,
Detail: message, Detail: message,
}); err != nil {
log.Error("JSON encode: %v", err)
}
}) })
} }

View File

@@ -24,14 +24,13 @@ import (
) )
func apiError(ctx *context.Context, status int, obj any) { func apiError(ctx *context.Context, status int, obj any) {
helper.LogAndProcessError(ctx, status, obj, func(message string) { message := helper.ProcessErrorForUser(ctx, status, obj)
ctx.JSON(status, struct { ctx.JSON(status, struct {
Errors []string `json:"errors"` Errors []string `json:"errors"`
}{ }{
Errors: []string{ Errors: []string{
message, message,
}, },
})
}) })
} }