mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-08-08 08:32:16 +01:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8252142e65 | ||
|
|
6e2270632e | ||
|
|
7d14546d3b | ||
|
|
b31024c362 |
2
Makefile
2
Makefile
@@ -63,6 +63,7 @@ LIBREOFFICE_DISABLE_ROUTES=false
|
||||
LOG_LEVEL=info
|
||||
LOG_FORMAT=auto
|
||||
LOG_FIELDS_PREFIX=
|
||||
LOG_ENABLE_GCP_SEVERITY=false
|
||||
PDFENGINES_ENGINES=
|
||||
PDFENGINES_MERGE_ENGINES=qpdf,pdfcpu,pdftk
|
||||
PDFENGINES_SPLIT_ENGINES=pdfcpu,qpdf,pdftk
|
||||
@@ -134,6 +135,7 @@ run: ## Start a Gotenberg container
|
||||
--log-level=$(LOG_LEVEL) \
|
||||
--log-format=$(LOG_FORMAT) \
|
||||
--log-fields-prefix=$(LOG_FIELDS_PREFIX) \
|
||||
--log-enable-gcp-severity=$(LOG_ENABLE_GCP_SEVERITY) \
|
||||
--pdfengines-engines=$(PDFENGINES_ENGINES) \
|
||||
--pdfengines-merge-engines=$(PDFENGINES_MERGE_ENGINES) \
|
||||
--pdfengines-split-engines=$(PDFENGINES_SPLIT_ENGINES) \
|
||||
|
||||
@@ -171,7 +171,7 @@ RUN \
|
||||
apt-get update -qq &&\
|
||||
apt-get upgrade -yqq &&\
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends -t bookworm-backports libreoffice &&\
|
||||
curl -Ls https://raw.githubusercontent.com/gotenberg/unoconverter/v0.0.1/unoconv -o /usr/bin/unoconverter &&\
|
||||
curl -Ls https://raw.githubusercontent.com/gotenberg/unoconverter/v0.1.1/unoconv -o /usr/bin/unoconverter &&\
|
||||
chmod +x /usr/bin/unoconverter &&\
|
||||
# unoconverter will look for the Python binary, which has to be at version 3.
|
||||
ln -s /usr/bin/python3 /usr/bin/python &&\
|
||||
|
||||
6
go.mod
6
go.mod
@@ -6,7 +6,7 @@ require (
|
||||
github.com/alexliesenfeld/health v0.8.0
|
||||
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||
github.com/barasher/go-exiftool v1.10.0
|
||||
github.com/chromedp/cdproto v0.0.0-20250304222902-64be311ed8b0
|
||||
github.com/chromedp/cdproto v0.0.0-20250311215558-29dfcc2791de
|
||||
github.com/chromedp/chromedp v0.13.1
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
@@ -61,10 +61,10 @@ require (
|
||||
github.com/lufia/plan9stats v0.0.0-20250303091104-876f3ea5145d // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/nwaples/rardecode/v2 v2.1.0 // indirect
|
||||
github.com/nwaples/rardecode/v2 v2.1.1 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.62.0 // indirect
|
||||
github.com/prometheus/common v0.63.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/sorairolake/lzip-go v0.3.5 // indirect
|
||||
github.com/therootcompany/xz v1.0.1 // indirect
|
||||
|
||||
12
go.sum
12
go.sum
@@ -38,8 +38,8 @@ github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chromedp/cdproto v0.0.0-20250304222902-64be311ed8b0 h1:eyqx6IwUz4gxJUU5CKiZsuGdNPVRCTWQQN5LpS1T5eo=
|
||||
github.com/chromedp/cdproto v0.0.0-20250304222902-64be311ed8b0/go.mod h1:NItd7aLkcfOA/dcMXvl8p1u+lQqioRMq/SqDp71Pb/k=
|
||||
github.com/chromedp/cdproto v0.0.0-20250311215558-29dfcc2791de h1:tOKSCbB420VENW1Wz10EnSXr4jLnWoq25vnBW4ScmF0=
|
||||
github.com/chromedp/cdproto v0.0.0-20250311215558-29dfcc2791de/go.mod h1:NItd7aLkcfOA/dcMXvl8p1u+lQqioRMq/SqDp71Pb/k=
|
||||
github.com/chromedp/chromedp v0.13.1 h1:FDh9CfaAt0w70gl69Hb69M/xgZrWuppH9AW22aGa+iU=
|
||||
github.com/chromedp/chromedp v0.13.1/go.mod h1:O3nO4Lno7iLoVX+7GdqQkehhKG7DtLf/zFRyJo0AhXY=
|
||||
github.com/chromedp/sysutil v1.1.0 h1:PUFNv5EcprjqXZD9nJb9b/c9ibAbxiYo4exNWZyipwM=
|
||||
@@ -155,8 +155,8 @@ github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwX
|
||||
github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/nwaples/rardecode/v2 v2.1.0 h1:JQl9ZoBPDy+nIZGb1mx8+anfHp/LV3NE2MjMiv0ct/U=
|
||||
github.com/nwaples/rardecode/v2 v2.1.0/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw=
|
||||
github.com/nwaples/rardecode/v2 v2.1.1 h1:OJaYalXdliBUXPmC8CZGQ7oZDxzX1/5mQmgn0/GASew=
|
||||
github.com/nwaples/rardecode/v2 v2.1.1/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw=
|
||||
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw=
|
||||
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
|
||||
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
|
||||
@@ -170,8 +170,8 @@ github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuF
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
|
||||
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||
github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k=
|
||||
github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
|
||||
@@ -62,6 +62,10 @@ type Options struct {
|
||||
// PageRanges allows to select the pages to convert.
|
||||
PageRanges string
|
||||
|
||||
// UpdateIndexes specifies whether to update the indexes before conversion
|
||||
// or not, with the risk of disabling links in documents.
|
||||
UpdateIndexes bool
|
||||
|
||||
// ExportFormFields specifies whether form fields are exported as widgets
|
||||
// or only their fixed print representation is exported.
|
||||
ExportFormFields bool
|
||||
@@ -152,6 +156,7 @@ func DefaultOptions() Options {
|
||||
Password: "",
|
||||
Landscape: false,
|
||||
PageRanges: "",
|
||||
UpdateIndexes: true,
|
||||
ExportFormFields: true,
|
||||
AllowDuplicateFieldNames: false,
|
||||
ExportBookmarks: true,
|
||||
|
||||
@@ -279,6 +279,10 @@ func (p *libreOfficeProcess) pdf(ctx context.Context, logger *zap.Logger, inputP
|
||||
args = append(args, "--export", fmt.Sprintf("PageRange=%s", options.PageRanges))
|
||||
}
|
||||
|
||||
if !options.UpdateIndexes {
|
||||
args = append(args, "--disable-update-indexes")
|
||||
}
|
||||
|
||||
args = append(args, "--export", fmt.Sprintf("ExportFormFields=%t", options.ExportFormFields))
|
||||
args = append(args, "--export", fmt.Sprintf("AllowDuplicateFieldNames=%t", options.AllowDuplicateFieldNames))
|
||||
args = append(args, "--export", fmt.Sprintf("ExportBookmarks=%t", options.ExportBookmarks))
|
||||
|
||||
@@ -39,6 +39,7 @@ func convertRoute(libreOffice libreofficeapi.Uno, engine gotenberg.PdfEngine) ap
|
||||
password string
|
||||
landscape bool
|
||||
nativePageRanges string
|
||||
updateIndexes bool
|
||||
exportFormFields bool
|
||||
allowDuplicateFieldNames bool
|
||||
exportBookmarks bool
|
||||
@@ -68,6 +69,7 @@ func convertRoute(libreOffice libreofficeapi.Uno, engine gotenberg.PdfEngine) ap
|
||||
String("password", &password, defaultOptions.Password).
|
||||
Bool("landscape", &landscape, defaultOptions.Landscape).
|
||||
String("nativePageRanges", &nativePageRanges, defaultOptions.PageRanges).
|
||||
Bool("updateIndexes", &updateIndexes, defaultOptions.UpdateIndexes).
|
||||
Bool("exportFormFields", &exportFormFields, defaultOptions.ExportFormFields).
|
||||
Bool("allowDuplicateFieldNames", &allowDuplicateFieldNames, defaultOptions.AllowDuplicateFieldNames).
|
||||
Bool("exportBookmarks", &exportBookmarks, defaultOptions.ExportBookmarks).
|
||||
@@ -149,6 +151,7 @@ func convertRoute(libreOffice libreofficeapi.Uno, engine gotenberg.PdfEngine) ap
|
||||
Password: password,
|
||||
Landscape: landscape,
|
||||
PageRanges: nativePageRanges,
|
||||
UpdateIndexes: updateIndexes,
|
||||
ExportFormFields: exportFormFields,
|
||||
AllowDuplicateFieldNames: allowDuplicateFieldNames,
|
||||
ExportBookmarks: exportBookmarks,
|
||||
|
||||
49
pkg/modules/logging/color.go
Normal file
49
pkg/modules/logging/color.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
// Foreground colors.
|
||||
// Copy pasted from go.uber.org/zap/internal/color/color.go
|
||||
const (
|
||||
black color = iota + 30
|
||||
red
|
||||
green
|
||||
yellow
|
||||
blue
|
||||
magenta
|
||||
cyan
|
||||
white
|
||||
)
|
||||
|
||||
type color uint8
|
||||
|
||||
func (c color) Add(s string) string {
|
||||
return fmt.Sprintf("\x1b[%dm%s\x1b[0m", uint8(c), s)
|
||||
}
|
||||
|
||||
func levelToColor(l zapcore.Level) color {
|
||||
switch l {
|
||||
case zapcore.DebugLevel:
|
||||
return cyan
|
||||
case zapcore.InfoLevel:
|
||||
return blue
|
||||
case zapcore.WarnLevel:
|
||||
return yellow
|
||||
case zapcore.ErrorLevel:
|
||||
return red
|
||||
case zapcore.DPanicLevel:
|
||||
return red
|
||||
case zapcore.PanicLevel:
|
||||
return red
|
||||
case zapcore.FatalLevel:
|
||||
return red
|
||||
case zapcore.InvalidLevel:
|
||||
return red
|
||||
default:
|
||||
return red
|
||||
}
|
||||
}
|
||||
36
pkg/modules/logging/gcp.go
Normal file
36
pkg/modules/logging/gcp.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package logging
|
||||
|
||||
import "go.uber.org/zap/zapcore"
|
||||
|
||||
func gcpSeverity(l zapcore.Level) string {
|
||||
switch l {
|
||||
case zapcore.DebugLevel:
|
||||
return "DEBUG"
|
||||
case zapcore.InfoLevel:
|
||||
return "INFO"
|
||||
case zapcore.WarnLevel:
|
||||
return "WARNING"
|
||||
case zapcore.ErrorLevel:
|
||||
return "ERROR"
|
||||
case zapcore.DPanicLevel:
|
||||
return "CRITICAL"
|
||||
case zapcore.PanicLevel:
|
||||
return "ALERT"
|
||||
case zapcore.FatalLevel:
|
||||
return "EMERGENCY"
|
||||
case zapcore.InvalidLevel:
|
||||
return "DEFAULT"
|
||||
default:
|
||||
return "DEFAULT"
|
||||
}
|
||||
}
|
||||
|
||||
func gcpSeverityEncoder(l zapcore.Level, enc zapcore.PrimitiveArrayEncoder) {
|
||||
enc.AppendString(gcpSeverity(l))
|
||||
}
|
||||
|
||||
func gcpSeverityColorEncoder(l zapcore.Level, enc zapcore.PrimitiveArrayEncoder) {
|
||||
severity := gcpSeverity(l)
|
||||
c := levelToColor(l)
|
||||
enc.AppendString(c.Add(severity))
|
||||
}
|
||||
@@ -34,9 +34,10 @@ const (
|
||||
// Logging is a module which implements the [gotenberg.LoggerProvider]
|
||||
// interface.
|
||||
type Logging struct {
|
||||
level string
|
||||
format string
|
||||
fieldsPrefix string
|
||||
level string
|
||||
format string
|
||||
fieldsPrefix string
|
||||
enableGcpSeverity bool
|
||||
}
|
||||
|
||||
// Descriptor returns a [Logging]'s module descriptor.
|
||||
@@ -48,6 +49,7 @@ func (log *Logging) Descriptor() gotenberg.ModuleDescriptor {
|
||||
fs.String("log-level", infoLoggingLevel, fmt.Sprintf("Choose the level of logging detail. Options include %s, %s, %s, or %s", errorLoggingLevel, warnLoggingLevel, infoLoggingLevel, debugLoggingLevel))
|
||||
fs.String("log-format", autoLoggingFormat, fmt.Sprintf("Specify the format of logging. Options include %s, %s, or %s", autoLoggingFormat, jsonLoggingFormat, textLoggingFormat))
|
||||
fs.String("log-fields-prefix", "", "Prepend a specified prefix to each field in the logs")
|
||||
fs.Bool("log-enable-gcp-severity", false, "Enable Google Cloud Platform severity mapping")
|
||||
|
||||
return fs
|
||||
}(),
|
||||
@@ -62,6 +64,7 @@ func (log *Logging) Provision(ctx *gotenberg.Context) error {
|
||||
log.level = flags.MustString("log-level")
|
||||
log.format = flags.MustString("log-format")
|
||||
log.fieldsPrefix = flags.MustString("log-fields-prefix")
|
||||
log.enableGcpSeverity = flags.MustBool("log-enable-gcp-severity")
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -101,7 +104,7 @@ func (log *Logging) Logger(mod gotenberg.Module) (*zap.Logger, error) {
|
||||
return nil, fmt.Errorf("get log level: %w", err)
|
||||
}
|
||||
|
||||
encoder, err := newLogEncoder(log.format)
|
||||
encoder, err := newLogEncoder(log.format, log.enableGcpSeverity)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get log encoder: %w", err)
|
||||
}
|
||||
@@ -166,7 +169,7 @@ func newLogLevel(level string) (zapcore.Level, error) {
|
||||
return lvl, nil
|
||||
}
|
||||
|
||||
func newLogEncoder(format string) (zapcore.Encoder, error) {
|
||||
func newLogEncoder(format string, gcpSeverity bool) (zapcore.Encoder, error) {
|
||||
isTerminal := term.IsTerminal(int(os.Stdout.Fd()))
|
||||
encCfg := zap.NewProductionEncoderConfig()
|
||||
|
||||
@@ -177,15 +180,25 @@ func newLogEncoder(format string) (zapcore.Encoder, error) {
|
||||
encoder.AppendString(ts.Local().Format("2006/01/02 15:04:05.000"))
|
||||
}
|
||||
|
||||
if format == textLoggingFormat || format == autoLoggingFormat {
|
||||
encCfg.EncodeLevel = zapcore.CapitalColorLevelEncoder
|
||||
if format == autoLoggingFormat {
|
||||
format = textLoggingFormat
|
||||
}
|
||||
}
|
||||
|
||||
if format == autoLoggingFormat && isTerminal {
|
||||
format = textLoggingFormat
|
||||
} else if format == autoLoggingFormat {
|
||||
format = jsonLoggingFormat
|
||||
if format == textLoggingFormat && gcpSeverity {
|
||||
encCfg.EncodeLevel = gcpSeverityColorEncoder
|
||||
} else if format == textLoggingFormat {
|
||||
encCfg.EncodeLevel = zapcore.CapitalColorLevelEncoder
|
||||
} else if gcpSeverity {
|
||||
encCfg.EncodeLevel = gcpSeverityEncoder
|
||||
}
|
||||
} else {
|
||||
if format == autoLoggingFormat {
|
||||
format = jsonLoggingFormat
|
||||
}
|
||||
|
||||
if gcpSeverity {
|
||||
encCfg.EncodeLevel = gcpSeverityEncoder
|
||||
}
|
||||
}
|
||||
|
||||
switch format {
|
||||
|
||||
@@ -1,347 +0,0 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"go.uber.org/zap/zaptest/observer"
|
||||
|
||||
"github.com/gotenberg/gotenberg/v8/pkg/gotenberg"
|
||||
)
|
||||
|
||||
func TestLogging_Descriptor(t *testing.T) {
|
||||
descriptor := new(Logging).Descriptor()
|
||||
|
||||
actual := reflect.TypeOf(descriptor.New())
|
||||
expect := reflect.TypeOf(new(Logging))
|
||||
|
||||
if actual != expect {
|
||||
t.Errorf("expected '%s' but got '%s'", expect, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogging_Provision(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
scenario string
|
||||
level string
|
||||
format string
|
||||
fieldsPrefix string
|
||||
expectLevel string
|
||||
expectFormat string
|
||||
expectFieldsPrefix string
|
||||
}{
|
||||
{
|
||||
scenario: "default values",
|
||||
expectLevel: infoLoggingLevel,
|
||||
expectFormat: autoLoggingFormat,
|
||||
expectFieldsPrefix: "",
|
||||
},
|
||||
{
|
||||
scenario: "explicit values",
|
||||
level: "debug",
|
||||
format: "json",
|
||||
fieldsPrefix: "gotenberg",
|
||||
expectLevel: debugLoggingLevel,
|
||||
expectFormat: jsonLoggingFormat,
|
||||
expectFieldsPrefix: "gotenberg",
|
||||
},
|
||||
{
|
||||
scenario: "wrong values", // no validation at this point.
|
||||
level: "foo",
|
||||
format: "foo",
|
||||
expectLevel: "foo",
|
||||
expectFormat: "foo",
|
||||
expectFieldsPrefix: "",
|
||||
},
|
||||
} {
|
||||
t.Run(tc.scenario, func(t *testing.T) {
|
||||
var flags []string
|
||||
|
||||
if tc.level != "" {
|
||||
flags = append(flags, "--log-level", tc.level)
|
||||
}
|
||||
|
||||
if tc.format != "" {
|
||||
flags = append(flags, "--log-format", tc.format)
|
||||
}
|
||||
|
||||
if tc.fieldsPrefix != "" {
|
||||
flags = append(flags, "--log-fields-prefix", tc.fieldsPrefix)
|
||||
}
|
||||
|
||||
logging := new(Logging)
|
||||
fs := logging.Descriptor().FlagSet
|
||||
|
||||
err := fs.Parse(flags)
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error while parsing flags but got: %v", err)
|
||||
}
|
||||
|
||||
ctx := gotenberg.NewContext(gotenberg.ParsedFlags{FlagSet: fs}, nil)
|
||||
|
||||
err = logging.Provision(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error while provisioning but got: %v", err)
|
||||
}
|
||||
|
||||
if logging.level != tc.expectLevel {
|
||||
t.Errorf("expected logging level '%s' but got '%s'", tc.expectLevel, logging.level)
|
||||
}
|
||||
|
||||
if logging.format != tc.expectFormat {
|
||||
t.Errorf("expected logging format '%s' but got '%s'", tc.expectFormat, logging.format)
|
||||
}
|
||||
|
||||
if logging.fieldsPrefix != tc.expectFieldsPrefix {
|
||||
t.Errorf("expected logging fields prefix '%s' but got '%s'", tc.expectFieldsPrefix, logging.fieldsPrefix)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogging_Validate(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
scenario string
|
||||
level string
|
||||
format string
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
scenario: "invalid level",
|
||||
level: "foo",
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
scenario: "invalid format",
|
||||
level: debugLoggingLevel,
|
||||
format: "foo",
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
scenario: "valid level and format",
|
||||
level: debugLoggingLevel,
|
||||
format: autoLoggingFormat,
|
||||
},
|
||||
} {
|
||||
logging := new(Logging)
|
||||
logging.level = tc.level
|
||||
logging.format = tc.format
|
||||
|
||||
err := logging.Validate()
|
||||
|
||||
if tc.expectError && err == nil {
|
||||
t.Errorf("%s: expected error but got: %v", tc.scenario, err)
|
||||
}
|
||||
|
||||
if !tc.expectError && err != nil {
|
||||
t.Errorf("%s: expected no error but got: %v", tc.scenario, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogging_Logger(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
scenario string
|
||||
level string
|
||||
format string
|
||||
fieldsPrefix string
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
scenario: "invalid level",
|
||||
level: "foo",
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
scenario: "invalid format",
|
||||
level: debugLoggingLevel,
|
||||
format: "foo",
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
scenario: "valid level and format",
|
||||
level: debugLoggingLevel,
|
||||
format: autoLoggingFormat,
|
||||
},
|
||||
} {
|
||||
t.Run(tc.scenario, func(t *testing.T) {
|
||||
logging := new(Logging)
|
||||
logging.level = tc.level
|
||||
logging.format = tc.format
|
||||
logging.fieldsPrefix = tc.fieldsPrefix
|
||||
|
||||
_, err := logging.Logger(&gotenberg.ModuleMock{
|
||||
DescriptorMock: func() gotenberg.ModuleDescriptor {
|
||||
return gotenberg.ModuleDescriptor{ID: "mock", New: nil}
|
||||
},
|
||||
})
|
||||
|
||||
if tc.expectError && err == nil {
|
||||
t.Fatal("expected error but got none")
|
||||
}
|
||||
|
||||
if !tc.expectError && err != nil {
|
||||
t.Fatalf("expected no error but got: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomCore(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
scenario string
|
||||
level zapcore.Level
|
||||
fieldsPrefix string
|
||||
expectEntry bool
|
||||
}{
|
||||
{
|
||||
scenario: "level enabled",
|
||||
level: zapcore.DebugLevel,
|
||||
fieldsPrefix: "gotenberg",
|
||||
expectEntry: true,
|
||||
},
|
||||
{
|
||||
scenario: "no fields prefix",
|
||||
level: zapcore.DebugLevel,
|
||||
expectEntry: true,
|
||||
},
|
||||
{
|
||||
scenario: "level disabled",
|
||||
level: zapcore.ErrorLevel,
|
||||
},
|
||||
} {
|
||||
t.Run(tc.scenario, func(t *testing.T) {
|
||||
core, obsvr := observer.New(tc.level)
|
||||
lgr := zap.New(customCore{
|
||||
Core: core,
|
||||
fieldsPrefix: tc.fieldsPrefix,
|
||||
}).With(zap.String("a_field", "a value"))
|
||||
|
||||
lgr.Debug("a debug message", zap.String("another_field", "another value"))
|
||||
|
||||
entries := obsvr.TakeAll()
|
||||
|
||||
if tc.expectEntry && len(entries) == 0 {
|
||||
t.Fatal("expected an entry")
|
||||
}
|
||||
|
||||
if !tc.expectEntry && len(entries) != 0 {
|
||||
t.Fatal("expected no entry")
|
||||
}
|
||||
|
||||
var prefix string
|
||||
if tc.fieldsPrefix != "" {
|
||||
prefix = tc.fieldsPrefix + "_"
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
fields := entry.Context
|
||||
|
||||
if len(fields) != 2 {
|
||||
t.Fatalf("expected 2 fields but got %d", len(fields))
|
||||
}
|
||||
|
||||
if fields[0].Key != fmt.Sprintf("%sa_field", prefix) {
|
||||
t.Errorf("expected 'gotenberg_a_field' but got '%s'", fields[0].Key)
|
||||
}
|
||||
|
||||
if fields[1].Key != fmt.Sprintf("%sanother_field", prefix) {
|
||||
t.Errorf("expected 'gotenberg_another_field' but got '%s'", fields[1].Key)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_newLogLevel(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
scenario string
|
||||
level string
|
||||
expectZapLevel zapcore.Level
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
scenario: "error level",
|
||||
level: errorLoggingLevel,
|
||||
expectZapLevel: zapcore.ErrorLevel,
|
||||
},
|
||||
{
|
||||
scenario: "warning level",
|
||||
level: warnLoggingLevel,
|
||||
expectZapLevel: zapcore.WarnLevel,
|
||||
},
|
||||
{
|
||||
scenario: "info level",
|
||||
level: infoLoggingLevel,
|
||||
expectZapLevel: zapcore.InfoLevel,
|
||||
},
|
||||
{
|
||||
scenario: "debug level",
|
||||
level: debugLoggingLevel,
|
||||
expectZapLevel: zapcore.DebugLevel,
|
||||
},
|
||||
{
|
||||
scenario: "invalid level",
|
||||
level: "foo",
|
||||
expectZapLevel: zapcore.InvalidLevel,
|
||||
expectError: true,
|
||||
},
|
||||
} {
|
||||
t.Run(tc.scenario, func(t *testing.T) {
|
||||
actual, err := newLogLevel(tc.level)
|
||||
|
||||
if tc.expectError && err == nil {
|
||||
t.Fatal("expected error but got none")
|
||||
}
|
||||
|
||||
if !tc.expectError && err != nil {
|
||||
t.Fatalf("expected no error but got: %v", err)
|
||||
}
|
||||
|
||||
if tc.expectZapLevel != actual {
|
||||
t.Errorf("expected %d level but got %d", tc.expectZapLevel, actual)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_newLogEncoder(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
scenario string
|
||||
format string
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
scenario: "auto format",
|
||||
format: autoLoggingFormat,
|
||||
},
|
||||
{
|
||||
scenario: "text format",
|
||||
format: textLoggingFormat,
|
||||
},
|
||||
{
|
||||
scenario: "json format",
|
||||
format: jsonLoggingFormat,
|
||||
},
|
||||
{
|
||||
scenario: "invalid format",
|
||||
format: "foo",
|
||||
expectError: true,
|
||||
},
|
||||
} {
|
||||
t.Run(tc.scenario, func(t *testing.T) {
|
||||
_, err := newLogEncoder(tc.format)
|
||||
|
||||
if tc.expectError && err == nil {
|
||||
t.Fatal("expected error but got none")
|
||||
}
|
||||
|
||||
if !tc.expectError && err != nil {
|
||||
t.Errorf("expected no error but got: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user