diff --git a/pkg/modules/libreoffice/api/api.go b/pkg/modules/libreoffice/api/api.go index fa2d1944..e3d72154 100644 --- a/pkg/modules/libreoffice/api/api.go +++ b/pkg/modules/libreoffice/api/api.go @@ -626,6 +626,7 @@ func (a *Api) Pdf(ctx context.Context, logger *slog.Logger, inputPath, outputPat attribute.Int64("gotenberg.queue.depth_at_arrival", a.supervisor.ReqQueueSize()), attribute.Int64("gotenberg.conversions_since_last_restart", a.supervisor.ConversionsSinceRestart()), ) + span.SetAttributes(conversionRequestAttributes(inputPath, options)...) start := time.Now() var conversionStart time.Time @@ -668,6 +669,7 @@ func (a *Api) Pdf(ctx context.Context, logger *slog.Logger, inputPath, outputPat stat, statErr := os.Stat(outputPath) if statErr == nil { a.pdfOutputSizeCounter.Record(ctx, stat.Size(), attrs) + span.SetAttributes(attribute.Int64("gotenberg.conversion.output.bytes", stat.Size())) } span.SetStatus(codes.Ok, "") @@ -685,6 +687,24 @@ func (a *Api) Pdf(ctx context.Context, logger *slog.Logger, inputPath, outputPat return fmt.Errorf("supervisor run task: %w", err) } +// conversionRequestAttributes derives low-cardinality attributes describing the +// requested conversion: the input document size and the requested PDF format +// options. +func conversionRequestAttributes(inputPath string, options Options) []attribute.KeyValue { + attrs := []attribute.KeyValue{ + attribute.String("gotenberg.libreoffice.pdf_a", options.PdfFormats.PdfA), + attribute.Bool("gotenberg.libreoffice.pdf_ua", options.PdfFormats.PdfUa), + attribute.Bool("gotenberg.conversion.landscape", options.Landscape), + attribute.Bool("gotenberg.conversion.has_page_ranges", options.PageRanges != ""), + } + + if info, err := os.Stat(inputPath); err == nil { + attrs = append(attrs, attribute.Int64("gotenberg.conversion.input.bytes", info.Size())) + } + + return attrs +} + // libreofficeErrorType maps a conversion error to LibreOffice's bounded reason // value, reused as the span error.type. Generic failures fall back to // [gotenberg.ClassifyError]. diff --git a/pkg/modules/libreoffice/api/api_request_attrs_test.go b/pkg/modules/libreoffice/api/api_request_attrs_test.go new file mode 100644 index 00000000..9c8e3031 --- /dev/null +++ b/pkg/modules/libreoffice/api/api_request_attrs_test.go @@ -0,0 +1,44 @@ +package api + +import ( + "os" + "path/filepath" + "testing" + + "github.com/gotenberg/gotenberg/v8/pkg/gotenberg" +) + +func TestConversionRequestAttributes(t *testing.T) { + tmp := filepath.Join(t.TempDir(), "in.docx") + content := []byte("hello world") + if err := os.WriteFile(tmp, content, 0o600); err != nil { + t.Fatalf("write temp file: %v", err) + } + + options := Options{ + Landscape: true, + PageRanges: "1-3", + PdfFormats: gotenberg.PdfFormats{PdfA: "PDF/A-2b", PdfUa: true}, + } + + got := map[string]any{} + for _, kv := range conversionRequestAttributes(tmp, options) { + got[string(kv.Key)] = kv.Value.AsInterface() + } + + if got["gotenberg.libreoffice.pdf_a"] != "PDF/A-2b" { + t.Errorf("pdf_a = %v, want PDF/A-2b", got["gotenberg.libreoffice.pdf_a"]) + } + if got["gotenberg.libreoffice.pdf_ua"] != true { + t.Errorf("pdf_ua = %v, want true", got["gotenberg.libreoffice.pdf_ua"]) + } + if got["gotenberg.conversion.landscape"] != true { + t.Errorf("landscape = %v, want true", got["gotenberg.conversion.landscape"]) + } + if got["gotenberg.conversion.has_page_ranges"] != true { + t.Errorf("has_page_ranges = %v, want true", got["gotenberg.conversion.has_page_ranges"]) + } + if got["gotenberg.conversion.input.bytes"] != int64(len(content)) { + t.Errorf("input.bytes = %v, want %d", got["gotenberg.conversion.input.bytes"], len(content)) + } +}