Files
zot/pkg/api/recovery.go
T
Luca Muscariello 2402296e9a fix: migrate to Go module v2 for proper semantic versioning (#3462)
* fix: migrate to Go module v2 for proper semantic versioning

This change updates the module path from 'zotregistry.dev/zot' to
'zotregistry.dev/zot/v2' to comply with Go's semantic versioning rules.

According to Go's module versioning requirements, major version v2+
must include the major version in the module path. The current
module path 'zotregistry.dev/zot' only supports v0.x.x and v1.x.x
versions, making existing v2.x.x tags (like v2.1.8) unusable.

Changes:
- Updated go.mod module path to zotregistry.dev/zot/v2
- Updated all internal import paths across 280+ Go source files
- Updated configuration files (golangcilint.yaml, gqlgen.yml)
- Updated README.md Go reference badge

This fix enables proper use of existing v2.x.x Git tags and allows
external packages to import zot v2+ versions without compatibility
errors.

Resolves: Go module import compatibility for v2+ versions
Fixes: #3071
Signed-off-by: Luca Muscariello <muscariello@ieee.org>

* fix: regenerate GraphQL files with updated v2 import paths

The gqlgen tool needs to regenerate the GraphQL schema files after
the module path change to use the new v2 imports.

Signed-off-by: Luca Muscariello <muscariello@ieee.org>

---------

Signed-off-by: Luca Muscariello <muscariello@ieee.org>
2025-10-16 22:43:47 -07:00

86 lines
1.7 KiB
Go

package api
import (
"encoding/json"
"net/http"
"runtime"
"github.com/gorilla/mux"
"zotregistry.dev/zot/v2/pkg/log"
)
type Stack struct {
Frames []Frame `json:"stack"`
}
type Frame struct {
Name string `json:"function"`
File string `json:"file"`
Line int `json:"line"`
}
// RecoveryHandler is a HTTP middleware that recovers from a panic.
// It logs the panic and its traceback in json format, writes http.StatusInternalServerError
// and continues to the next handler.
func RecoveryHandler(log log.Logger) mux.MiddlewareFunc {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
defer func() {
if err := recover(); err != nil {
response.WriteHeader(http.StatusInternalServerError)
stack := Stack{
Frames: getStacktrace(),
}
recoveredErr, ok := err.(error)
if ok {
buf, err := json.Marshal(stack)
if err == nil {
log.Error().Err(recoveredErr).RawJSON("traceback", buf).Msg("panic recovered") //nolint: check-logs
}
}
}
}()
// Process request
next.ServeHTTP(response, request)
})
}
}
func getStacktrace() []Frame {
stack := []Frame{}
//nolint: varnamelen
pc := make([]uintptr, 64)
n := runtime.Callers(0, pc)
if n == 0 {
return []Frame{}
}
// first three frames are from this file, don't need them.
pc = pc[3:]
frames := runtime.CallersFrames(pc)
// loop to get frames.
for {
frame, more := frames.Next()
// store this frame
stack = append(stack, Frame{
Name: frame.Function,
File: frame.File,
Line: frame.Line,
})
// check whether there are more frames to process after this one.
if !more {
break
}
}
return stack
}