Compare commits

..

4 Commits

Author SHA1 Message Date
Julien Neuhart
8252142e65 chore(deps): update Go dependencies 2025-03-17 14:01:07 +01:00
Julien Neuhart
6e2270632e chore(logging): remove unit tests - integration tests are inc anyway 2025-03-17 13:56:48 +01:00
Julien Neuhart
7d14546d3b feat(logging): add GCP severity mapping 2025-03-17 13:56:48 +01:00
Julien Neuhart
b31024c362 feat(libreoffice): add updateIndexes form field 2025-03-17 13:32:26 +01:00
11 changed files with 134 additions and 369 deletions

View File

@@ -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) \

View File

@@ -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
View File

@@ -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
View File

@@ -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=

View File

@@ -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,

View File

@@ -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))

View File

@@ -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,

View 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
}
}

View 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))
}

View File

@@ -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 {

View File

@@ -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)
}
})
}
}