mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-08-14 11:22:15 +01:00
feat(api): add debug route
This commit is contained in:
@@ -1,4 +1,65 @@
|
||||
package gotenberg
|
||||
|
||||
// Version is the... version of the Gotenberg application.
|
||||
var Version = "snapshot"
|
||||
import (
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
flag "github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
// DebugInfo gathers data for debugging.
|
||||
type DebugInfo struct {
|
||||
Version string `json:"version"`
|
||||
Architecture string `json:"architecture"`
|
||||
Modules []string `json:"modules"`
|
||||
ModulesAdditionalData map[string]map[string]interface{} `json:"modules_additional_data"`
|
||||
Flags map[string]interface{} `json:"flags"`
|
||||
}
|
||||
|
||||
// BuildDebug builds the debug data from modules.
|
||||
func BuildDebug(ctx *Context) {
|
||||
debugMu.Lock()
|
||||
defer debugMu.Unlock()
|
||||
|
||||
debug = &DebugInfo{
|
||||
Version: Version,
|
||||
Architecture: runtime.GOARCH,
|
||||
Modules: make([]string, len(ctx.moduleInstances)),
|
||||
ModulesAdditionalData: make(map[string]map[string]interface{}),
|
||||
Flags: make(map[string]interface{}),
|
||||
}
|
||||
|
||||
i := 0
|
||||
for ID, mod := range ctx.moduleInstances {
|
||||
debug.Modules[i] = ID
|
||||
i++
|
||||
|
||||
debuggable, ok := mod.(Debuggable)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
debug.ModulesAdditionalData[ID] = debuggable.Debug()
|
||||
}
|
||||
|
||||
ctx.ParsedFlags().VisitAll(func(f *flag.Flag) {
|
||||
debug.Flags[f.Name] = f.Value.String()
|
||||
})
|
||||
}
|
||||
|
||||
// Debug returns the debug data.
|
||||
func Debug() DebugInfo {
|
||||
debugMu.Lock()
|
||||
defer debugMu.Unlock()
|
||||
|
||||
if debug == nil {
|
||||
return DebugInfo{}
|
||||
}
|
||||
|
||||
return *debug
|
||||
}
|
||||
|
||||
var (
|
||||
debug *DebugInfo
|
||||
debugMu sync.Mutex
|
||||
)
|
||||
|
||||
72
pkg/gotenberg/debug_test.go
Normal file
72
pkg/gotenberg/debug_test.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package gotenberg
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
flag "github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
func TestBuildDebug(t *testing.T) {
|
||||
if !reflect.DeepEqual(Debug(), DebugInfo{}) {
|
||||
t.Errorf("Debug() should return empty debug data")
|
||||
}
|
||||
|
||||
fs := flag.NewFlagSet("gotenberg", flag.ExitOnError)
|
||||
fs.String("foo", "bar", "Set foo")
|
||||
ctx := NewContext(ParsedFlags{
|
||||
FlagSet: fs,
|
||||
}, func() []ModuleDescriptor {
|
||||
mod1 := &struct {
|
||||
ModuleMock
|
||||
}{}
|
||||
mod1.DescriptorMock = func() ModuleDescriptor {
|
||||
return ModuleDescriptor{ID: "foo", New: func() Module { return mod1 }}
|
||||
}
|
||||
mod2 := &struct {
|
||||
ModuleMock
|
||||
DebuggableMock
|
||||
}{}
|
||||
mod2.DescriptorMock = func() ModuleDescriptor {
|
||||
return ModuleDescriptor{ID: "bar", New: func() Module { return mod2 }}
|
||||
}
|
||||
mod2.DebugMock = func() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"foo": "bar",
|
||||
}
|
||||
}
|
||||
|
||||
return []ModuleDescriptor{mod1.Descriptor(), mod2.Descriptor()}
|
||||
}())
|
||||
|
||||
// Load modules.
|
||||
_, err := ctx.Modules(new(Module))
|
||||
if err != nil {
|
||||
t.Errorf("expected no error but got: %v", err)
|
||||
}
|
||||
|
||||
// Build debug data.
|
||||
BuildDebug(ctx)
|
||||
|
||||
expect := DebugInfo{
|
||||
Version: Version,
|
||||
Architecture: runtime.GOARCH,
|
||||
Modules: []string{
|
||||
"foo",
|
||||
"bar",
|
||||
},
|
||||
ModulesAdditionalData: map[string]map[string]interface{}{
|
||||
"bar": {
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
Flags: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(expect, Debug()) {
|
||||
t.Errorf("expected '%+v', bug got '%+v'", expect, Debug())
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,14 @@ func (mod *ValidatorMock) Validate() error {
|
||||
return mod.ValidateMock()
|
||||
}
|
||||
|
||||
type DebuggableMock struct {
|
||||
DebugMock func() map[string]interface{}
|
||||
}
|
||||
|
||||
func (mod *DebuggableMock) Debug() map[string]interface{} {
|
||||
return mod.DebugMock()
|
||||
}
|
||||
|
||||
// PdfEngineMock is a mock for the [PdfEngine] interface.
|
||||
//
|
||||
//nolint:dupl
|
||||
|
||||
@@ -48,6 +48,21 @@ func TestValidatorMock(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebuggableMock(t *testing.T) {
|
||||
mock := &DebuggableMock{
|
||||
DebugMock: func() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"foo": "bar",
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
d := mock.Debug()
|
||||
if d == nil {
|
||||
t.Errorf("expected debug data, but got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPDFEngineMock(t *testing.T) {
|
||||
mock := &PdfEngineMock{
|
||||
MergeMock: func(ctx context.Context, logger *zap.Logger, inputPaths []string, outputPath string) error {
|
||||
|
||||
@@ -75,6 +75,12 @@ type SystemLogger interface {
|
||||
SystemMessages() []string
|
||||
}
|
||||
|
||||
// Debuggable is a module interface for modules which want to provide
|
||||
// additional debug data.
|
||||
type Debuggable interface {
|
||||
Debug() map[string]interface{}
|
||||
}
|
||||
|
||||
// MustRegisterModule registers a module.
|
||||
//
|
||||
// To register a module, create an init() method in the module main go file:
|
||||
|
||||
4
pkg/gotenberg/version.go
Normal file
4
pkg/gotenberg/version.go
Normal file
@@ -0,0 +1,4 @@
|
||||
package gotenberg
|
||||
|
||||
// Version is the... version of the Gotenberg application.
|
||||
var Version = "snapshot"
|
||||
Reference in New Issue
Block a user