mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-08-08 00:22:14 +01:00
refactor(chromium): classify Pdf and Screenshot errors and set span error.type
This commit is contained in:
@@ -799,6 +799,8 @@ func (mod *Chromium) Routes() ([]api.Route, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Pdf converts a URL to PDF.
|
// Pdf converts a URL to PDF.
|
||||||
|
//
|
||||||
|
//nolint:dupl
|
||||||
func (mod *Chromium) Pdf(ctx context.Context, logger *slog.Logger, url, outputPath string, options PdfOptions) error {
|
func (mod *Chromium) Pdf(ctx context.Context, logger *slog.Logger, url, outputPath string, options PdfOptions) error {
|
||||||
ctx, span := gotenberg.Tracer().Start(ctx, "chromium.Pdf",
|
ctx, span := gotenberg.Tracer().Start(ctx, "chromium.Pdf",
|
||||||
trace.WithSpanKind(trace.SpanKindClient),
|
trace.WithSpanKind(trace.SpanKindClient),
|
||||||
@@ -824,21 +826,12 @@ func (mod *Chromium) Pdf(ctx context.Context, logger *slog.Logger, url, outputPa
|
|||||||
status = "error"
|
status = "error"
|
||||||
}
|
}
|
||||||
|
|
||||||
reason := "unknown"
|
reason := chromiumErrorType(err, "chromium_unavailable")
|
||||||
switch {
|
|
||||||
case errors.Is(err, context.DeadlineExceeded):
|
|
||||||
reason = "timeout"
|
|
||||||
case errors.Is(err, context.Canceled):
|
|
||||||
reason = "context_cancelled"
|
|
||||||
case errors.Is(err, ErrInvalidHttpStatusCode) || errors.Is(err, ErrInvalidResourceHttpStatusCode) || errors.Is(err, ErrLoadingFailed) || errors.Is(err, ErrResourceLoadingFailed) || errors.Is(err, ErrInvalidEvaluationExpression) || errors.Is(err, ErrInvalidSelectorQuery):
|
|
||||||
reason = "invalid_input"
|
|
||||||
case errors.Is(err, gotenberg.ErrMaximumQueueSizeExceeded) || errors.Is(err, gotenberg.ErrProcessAlreadyRestarting):
|
|
||||||
reason = "chromium_unavailable"
|
|
||||||
}
|
|
||||||
|
|
||||||
mod.errsCounter.Add(ctx, 1, metric.WithAttributes(
|
mod.errsCounter.Add(ctx, 1, metric.WithAttributes(
|
||||||
attribute.String("reason", reason),
|
attribute.String("reason", reason),
|
||||||
))
|
))
|
||||||
|
gotenberg.SpanErrorType(span, reason)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !conversionStart.IsZero() {
|
if !conversionStart.IsZero() {
|
||||||
@@ -876,6 +869,9 @@ func (mod *Chromium) Pdf(ctx context.Context, logger *slog.Logger, url, outputPa
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Screenshot captures a screenshot from a URL.
|
||||||
|
//
|
||||||
|
//nolint:dupl
|
||||||
func (mod *Chromium) Screenshot(ctx context.Context, logger *slog.Logger, url, outputPath string, options ScreenshotOptions) error {
|
func (mod *Chromium) Screenshot(ctx context.Context, logger *slog.Logger, url, outputPath string, options ScreenshotOptions) error {
|
||||||
ctx, span := gotenberg.Tracer().Start(ctx, "chromium.Screenshot",
|
ctx, span := gotenberg.Tracer().Start(ctx, "chromium.Screenshot",
|
||||||
trace.WithSpanKind(trace.SpanKindClient),
|
trace.WithSpanKind(trace.SpanKindClient),
|
||||||
@@ -901,23 +897,12 @@ func (mod *Chromium) Screenshot(ctx context.Context, logger *slog.Logger, url, o
|
|||||||
status = "error"
|
status = "error"
|
||||||
}
|
}
|
||||||
|
|
||||||
reason := "unknown"
|
reason := chromiumErrorType(err, "chromium_maximum_queue_size_exceeded")
|
||||||
switch {
|
|
||||||
case errors.Is(err, context.DeadlineExceeded):
|
|
||||||
reason = "timeout"
|
|
||||||
case errors.Is(err, context.Canceled):
|
|
||||||
reason = "context_cancelled"
|
|
||||||
case errors.Is(err, ErrInvalidHttpStatusCode) || errors.Is(err, ErrInvalidResourceHttpStatusCode) || errors.Is(err, ErrLoadingFailed) || errors.Is(err, ErrResourceLoadingFailed) || errors.Is(err, ErrInvalidEvaluationExpression) || errors.Is(err, ErrInvalidSelectorQuery):
|
|
||||||
reason = "invalid_input"
|
|
||||||
case errors.Is(err, gotenberg.ErrMaximumQueueSizeExceeded):
|
|
||||||
reason = "chromium_maximum_queue_size_exceeded"
|
|
||||||
case errors.Is(err, gotenberg.ErrProcessAlreadyRestarting):
|
|
||||||
reason = "chromium_unavailable"
|
|
||||||
}
|
|
||||||
|
|
||||||
mod.errsCounter.Add(ctx, 1, metric.WithAttributes(
|
mod.errsCounter.Add(ctx, 1, metric.WithAttributes(
|
||||||
attribute.String("reason", reason),
|
attribute.String("reason", reason),
|
||||||
))
|
))
|
||||||
|
gotenberg.SpanErrorType(span, reason)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !conversionStart.IsZero() {
|
if !conversionStart.IsZero() {
|
||||||
@@ -955,6 +940,30 @@ func (mod *Chromium) Screenshot(ctx context.Context, logger *slog.Logger, url, o
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// chromiumErrorType maps a conversion error to chromium's bounded reason value,
|
||||||
|
// reused as the span error.type. queueReason preserves the historical,
|
||||||
|
// route-specific label for a saturated queue: Pdf collapses it into
|
||||||
|
// "chromium_unavailable", whereas Screenshot keeps
|
||||||
|
// "chromium_maximum_queue_size_exceeded". Generic failures fall back to
|
||||||
|
// [gotenberg.ClassifyError].
|
||||||
|
func chromiumErrorType(err error, queueReason string) string {
|
||||||
|
switch {
|
||||||
|
case errors.Is(err, ErrInvalidHttpStatusCode),
|
||||||
|
errors.Is(err, ErrInvalidResourceHttpStatusCode),
|
||||||
|
errors.Is(err, ErrLoadingFailed),
|
||||||
|
errors.Is(err, ErrResourceLoadingFailed),
|
||||||
|
errors.Is(err, ErrInvalidEvaluationExpression),
|
||||||
|
errors.Is(err, ErrInvalidSelectorQuery):
|
||||||
|
return gotenberg.ErrorTypeInvalidInput
|
||||||
|
case errors.Is(err, gotenberg.ErrMaximumQueueSizeExceeded):
|
||||||
|
return queueReason
|
||||||
|
case errors.Is(err, gotenberg.ErrProcessAlreadyRestarting):
|
||||||
|
return "chromium_unavailable"
|
||||||
|
default:
|
||||||
|
return gotenberg.ClassifyError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Interface guards.
|
// Interface guards.
|
||||||
var (
|
var (
|
||||||
_ gotenberg.Module = (*Chromium)(nil)
|
_ gotenberg.Module = (*Chromium)(nil)
|
||||||
|
|||||||
37
pkg/modules/chromium/errortype_test.go
Normal file
37
pkg/modules/chromium/errortype_test.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package chromium
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gotenberg/gotenberg/v8/pkg/gotenberg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestChromiumErrorType(t *testing.T) {
|
||||||
|
for _, tc := range []struct {
|
||||||
|
name string
|
||||||
|
err error
|
||||||
|
queueReason string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{"deadline", context.DeadlineExceeded, "chromium_unavailable", "timeout"},
|
||||||
|
{"canceled", context.Canceled, "chromium_unavailable", "context_cancelled"},
|
||||||
|
{"invalid http status", ErrInvalidHttpStatusCode, "chromium_unavailable", "invalid_input"},
|
||||||
|
{"invalid resource http status", ErrInvalidResourceHttpStatusCode, "chromium_unavailable", "invalid_input"},
|
||||||
|
{"loading failed", ErrLoadingFailed, "chromium_unavailable", "invalid_input"},
|
||||||
|
{"resource loading failed", ErrResourceLoadingFailed, "chromium_unavailable", "invalid_input"},
|
||||||
|
{"invalid evaluation expression", ErrInvalidEvaluationExpression, "chromium_unavailable", "invalid_input"},
|
||||||
|
{"invalid selector query", ErrInvalidSelectorQuery, "chromium_unavailable", "invalid_input"},
|
||||||
|
{"pdf queue", gotenberg.ErrMaximumQueueSizeExceeded, "chromium_unavailable", "chromium_unavailable"},
|
||||||
|
{"screenshot queue", gotenberg.ErrMaximumQueueSizeExceeded, "chromium_maximum_queue_size_exceeded", "chromium_maximum_queue_size_exceeded"},
|
||||||
|
{"restarting", gotenberg.ErrProcessAlreadyRestarting, "chromium_maximum_queue_size_exceeded", "chromium_unavailable"},
|
||||||
|
{"unknown", errors.New("boom"), "chromium_unavailable", "unknown"},
|
||||||
|
} {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
if got := chromiumErrorType(tc.err, tc.queueReason); got != tc.want {
|
||||||
|
t.Errorf("chromiumErrorType(%v, %q) = %q, want %q", tc.err, tc.queueReason, got, tc.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user