mirror of
https://github.com/miniflux/v2.git
synced 2025-09-15 18:57:04 +00:00
Implement structured logging using log/slog package
This commit is contained in:
parent
54cb8fa028
commit
c0e954f19d
77 changed files with 1868 additions and 892 deletions
|
@ -8,6 +8,181 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
func TestLogFileDefaultValue(t *testing.T) {
|
||||
os.Clearenv()
|
||||
|
||||
parser := NewParser()
|
||||
opts, err := parser.ParseEnvironmentVariables()
|
||||
if err != nil {
|
||||
t.Fatalf(`Parsing failure: %v`, err)
|
||||
}
|
||||
|
||||
if opts.LogFile() != defaultLogFile {
|
||||
t.Fatalf(`Unexpected log file value, got %q`, opts.LogFile())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogFileWithCustomFilename(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("LOG_FILE", "foobar.log")
|
||||
|
||||
parser := NewParser()
|
||||
opts, err := parser.ParseEnvironmentVariables()
|
||||
if err != nil {
|
||||
t.Fatalf(`Parsing failure: %v`, err)
|
||||
}
|
||||
if opts.LogFile() != "foobar.log" {
|
||||
t.Fatalf(`Unexpected log file value, got %q`, opts.LogFile())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogFileWithEmptyValue(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("LOG_FILE", "")
|
||||
|
||||
parser := NewParser()
|
||||
opts, err := parser.ParseEnvironmentVariables()
|
||||
if err != nil {
|
||||
t.Fatalf(`Parsing failure: %v`, err)
|
||||
}
|
||||
|
||||
if opts.LogFile() != defaultLogFile {
|
||||
t.Fatalf(`Unexpected log file value, got %q`, opts.LogFile())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogLevelDefaultValue(t *testing.T) {
|
||||
os.Clearenv()
|
||||
|
||||
parser := NewParser()
|
||||
opts, err := parser.ParseEnvironmentVariables()
|
||||
if err != nil {
|
||||
t.Fatalf(`Parsing failure: %v`, err)
|
||||
}
|
||||
|
||||
if opts.LogLevel() != defaultLogLevel {
|
||||
t.Fatalf(`Unexpected log level value, got %q`, opts.LogLevel())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogLevelWithCustomValue(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("LOG_LEVEL", "warning")
|
||||
|
||||
parser := NewParser()
|
||||
opts, err := parser.ParseEnvironmentVariables()
|
||||
if err != nil {
|
||||
t.Fatalf(`Parsing failure: %v`, err)
|
||||
}
|
||||
|
||||
if opts.LogLevel() != "warning" {
|
||||
t.Fatalf(`Unexpected log level value, got %q`, opts.LogLevel())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogLevelWithInvalidValue(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("LOG_LEVEL", "invalid")
|
||||
|
||||
parser := NewParser()
|
||||
opts, err := parser.ParseEnvironmentVariables()
|
||||
if err != nil {
|
||||
t.Fatalf(`Parsing failure: %v`, err)
|
||||
}
|
||||
|
||||
if opts.LogLevel() != defaultLogLevel {
|
||||
t.Fatalf(`Unexpected log level value, got %q`, opts.LogLevel())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogDateTimeDefaultValue(t *testing.T) {
|
||||
os.Clearenv()
|
||||
|
||||
parser := NewParser()
|
||||
opts, err := parser.ParseEnvironmentVariables()
|
||||
if err != nil {
|
||||
t.Fatalf(`Parsing failure: %v`, err)
|
||||
}
|
||||
|
||||
if opts.LogDateTime() != defaultLogDateTime {
|
||||
t.Fatalf(`Unexpected log date time value, got %v`, opts.LogDateTime())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogDateTimeWithCustomValue(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("LOG_DATETIME", "false")
|
||||
|
||||
parser := NewParser()
|
||||
opts, err := parser.ParseEnvironmentVariables()
|
||||
if err != nil {
|
||||
t.Fatalf(`Parsing failure: %v`, err)
|
||||
}
|
||||
|
||||
if opts.LogDateTime() != false {
|
||||
t.Fatalf(`Unexpected log date time value, got %v`, opts.LogDateTime())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogDateTimeWithInvalidValue(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("LOG_DATETIME", "invalid")
|
||||
|
||||
parser := NewParser()
|
||||
opts, err := parser.ParseEnvironmentVariables()
|
||||
if err != nil {
|
||||
t.Fatalf(`Parsing failure: %v`, err)
|
||||
}
|
||||
|
||||
if opts.LogDateTime() != defaultLogDateTime {
|
||||
t.Fatalf(`Unexpected log date time value, got %v`, opts.LogDateTime())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogFormatDefaultValue(t *testing.T) {
|
||||
os.Clearenv()
|
||||
|
||||
parser := NewParser()
|
||||
opts, err := parser.ParseEnvironmentVariables()
|
||||
if err != nil {
|
||||
t.Fatalf(`Parsing failure: %v`, err)
|
||||
}
|
||||
|
||||
if opts.LogFormat() != defaultLogFormat {
|
||||
t.Fatalf(`Unexpected log format value, got %q`, opts.LogFormat())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogFormatWithCustomValue(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("LOG_FORMAT", "json")
|
||||
|
||||
parser := NewParser()
|
||||
opts, err := parser.ParseEnvironmentVariables()
|
||||
if err != nil {
|
||||
t.Fatalf(`Parsing failure: %v`, err)
|
||||
}
|
||||
|
||||
if opts.LogFormat() != "json" {
|
||||
t.Fatalf(`Unexpected log format value, got %q`, opts.LogFormat())
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogFormatWithInvalidValue(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("LOG_FORMAT", "invalid")
|
||||
|
||||
parser := NewParser()
|
||||
opts, err := parser.ParseEnvironmentVariables()
|
||||
if err != nil {
|
||||
t.Fatalf(`Parsing failure: %v`, err)
|
||||
}
|
||||
|
||||
if opts.LogFormat() != defaultLogFormat {
|
||||
t.Fatalf(`Unexpected log format value, got %q`, opts.LogFormat())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebugModeOn(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("DEBUG", "1")
|
||||
|
@ -18,8 +193,8 @@ func TestDebugModeOn(t *testing.T) {
|
|||
t.Fatalf(`Parsing failure: %v`, err)
|
||||
}
|
||||
|
||||
if !opts.HasDebugMode() {
|
||||
t.Fatalf(`Unexpected debug mode value, got "%v"`, opts.HasDebugMode())
|
||||
if opts.LogLevel() != "debug" {
|
||||
t.Fatalf(`Unexpected debug mode value, got %q`, opts.LogLevel())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,8 +207,8 @@ func TestDebugModeOff(t *testing.T) {
|
|||
t.Fatalf(`Parsing failure: %v`, err)
|
||||
}
|
||||
|
||||
if opts.HasDebugMode() {
|
||||
t.Fatalf(`Unexpected debug mode value, got "%v"`, opts.HasDebugMode())
|
||||
if opts.LogLevel() != "info" {
|
||||
t.Fatalf(`Unexpected debug mode value, got %q`, opts.LogLevel())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1544,8 +1719,8 @@ Invalid text
|
|||
t.Errorf(`Parsing failure: %v`, err)
|
||||
}
|
||||
|
||||
if opts.HasDebugMode() != true {
|
||||
t.Errorf(`Unexpected debug mode value, got "%v"`, opts.HasDebugMode())
|
||||
if opts.LogLevel() != "debug" {
|
||||
t.Errorf(`Unexpected debug mode value, got %q`, opts.LogLevel())
|
||||
}
|
||||
|
||||
expected := ">#1234"
|
||||
|
|
|
@ -15,7 +15,10 @@ import (
|
|||
|
||||
const (
|
||||
defaultHTTPS = false
|
||||
defaultLogFile = "stderr"
|
||||
defaultLogDateTime = false
|
||||
defaultLogFormat = "text"
|
||||
defaultLogLevel = "info"
|
||||
defaultHSTS = true
|
||||
defaultHTTPService = true
|
||||
defaultSchedulerService = true
|
||||
|
@ -91,11 +94,13 @@ type Option struct {
|
|||
// Options contains configuration options.
|
||||
type Options struct {
|
||||
HTTPS bool
|
||||
logFile string
|
||||
logDateTime bool
|
||||
logFormat string
|
||||
logLevel string
|
||||
hsts bool
|
||||
httpService bool
|
||||
schedulerService bool
|
||||
debug bool
|
||||
serverTimingHeader bool
|
||||
baseURL string
|
||||
rootURL string
|
||||
|
@ -165,11 +170,13 @@ func NewOptions() *Options {
|
|||
|
||||
return &Options{
|
||||
HTTPS: defaultHTTPS,
|
||||
logFile: defaultLogFile,
|
||||
logDateTime: defaultLogDateTime,
|
||||
logFormat: defaultLogFormat,
|
||||
logLevel: defaultLogLevel,
|
||||
hsts: defaultHSTS,
|
||||
httpService: defaultHTTPService,
|
||||
schedulerService: defaultSchedulerService,
|
||||
debug: defaultDebug,
|
||||
serverTimingHeader: defaultTiming,
|
||||
baseURL: defaultBaseURL,
|
||||
rootURL: defaultRootURL,
|
||||
|
@ -231,11 +238,30 @@ func NewOptions() *Options {
|
|||
}
|
||||
}
|
||||
|
||||
func (o *Options) LogFile() string {
|
||||
return o.logFile
|
||||
}
|
||||
|
||||
// LogDateTime returns true if the date/time should be displayed in log messages.
|
||||
func (o *Options) LogDateTime() bool {
|
||||
return o.logDateTime
|
||||
}
|
||||
|
||||
// LogFormat returns the log format.
|
||||
func (o *Options) LogFormat() string {
|
||||
return o.logFormat
|
||||
}
|
||||
|
||||
// LogLevel returns the log level.
|
||||
func (o *Options) LogLevel() string {
|
||||
return o.logLevel
|
||||
}
|
||||
|
||||
// SetLogLevel sets the log level.
|
||||
func (o *Options) SetLogLevel(level string) {
|
||||
o.logLevel = level
|
||||
}
|
||||
|
||||
// HasMaintenanceMode returns true if maintenance mode is enabled.
|
||||
func (o *Options) HasMaintenanceMode() bool {
|
||||
return o.maintenanceMode
|
||||
|
@ -246,11 +272,6 @@ func (o *Options) MaintenanceMessage() string {
|
|||
return o.maintenanceMessage
|
||||
}
|
||||
|
||||
// HasDebugMode returns true if debug mode is enabled.
|
||||
func (o *Options) HasDebugMode() bool {
|
||||
return o.debug
|
||||
}
|
||||
|
||||
// HasServerTimingHeader returns true if server-timing headers enabled.
|
||||
func (o *Options) HasServerTimingHeader() bool {
|
||||
return o.serverTimingHeader
|
||||
|
@ -593,7 +614,6 @@ func (o *Options) SortedOptions(redactSecret bool) []*Option {
|
|||
"DATABASE_MAX_CONNS": o.databaseMaxConns,
|
||||
"DATABASE_MIN_CONNS": o.databaseMinConns,
|
||||
"DATABASE_URL": redactSecretValue(o.databaseURL, redactSecret),
|
||||
"DEBUG": o.debug,
|
||||
"DISABLE_HSTS": !o.hsts,
|
||||
"DISABLE_HTTP_SERVICE": !o.httpService,
|
||||
"DISABLE_SCHEDULER_SERVICE": !o.schedulerService,
|
||||
|
@ -609,7 +629,10 @@ func (o *Options) SortedOptions(redactSecret bool) []*Option {
|
|||
"INVIDIOUS_INSTANCE": o.invidiousInstance,
|
||||
"KEY_FILE": o.certKeyFile,
|
||||
"LISTEN_ADDR": o.listenAddr,
|
||||
"LOG_FILE": o.logFile,
|
||||
"LOG_DATE_TIME": o.logDateTime,
|
||||
"LOG_FORMAT": o.logFormat,
|
||||
"LOG_LEVEL": o.logLevel,
|
||||
"MAINTENANCE_MESSAGE": o.maintenanceMessage,
|
||||
"MAINTENANCE_MODE": o.maintenanceMode,
|
||||
"METRICS_ALLOWED_NETWORKS": strings.Join(o.metricsAllowedNetworks, ","),
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
url_parser "net/url"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -72,10 +72,25 @@ func (p *Parser) parseLines(lines []string) (err error) {
|
|||
value := strings.TrimSpace(fields[1])
|
||||
|
||||
switch key {
|
||||
case "LOG_FILE":
|
||||
p.opts.logFile = parseString(value, defaultLogFile)
|
||||
case "LOG_DATE_TIME":
|
||||
p.opts.logDateTime = parseBool(value, defaultLogDateTime)
|
||||
case "LOG_LEVEL":
|
||||
parsedValue := parseString(value, defaultLogLevel)
|
||||
if parsedValue == "debug" || parsedValue == "info" || parsedValue == "warning" || parsedValue == "error" {
|
||||
p.opts.logLevel = parsedValue
|
||||
}
|
||||
case "LOG_FORMAT":
|
||||
parsedValue := parseString(value, defaultLogFormat)
|
||||
if parsedValue == "json" || parsedValue == "text" {
|
||||
p.opts.logFormat = parsedValue
|
||||
}
|
||||
case "DEBUG":
|
||||
p.opts.debug = parseBool(value, defaultDebug)
|
||||
parsedValue := parseBool(value, defaultDebug)
|
||||
if parsedValue {
|
||||
p.opts.logLevel = "debug"
|
||||
}
|
||||
case "SERVER_TIMING_HEADER":
|
||||
p.opts.serverTimingHeader = parseBool(value, defaultTiming)
|
||||
case "BASE_URL":
|
||||
|
@ -247,19 +262,19 @@ func parseBaseURL(value string) (string, string, string, error) {
|
|||
value = value[:len(value)-1]
|
||||
}
|
||||
|
||||
url, err := url_parser.Parse(value)
|
||||
parsedURL, err := url.Parse(value)
|
||||
if err != nil {
|
||||
return "", "", "", fmt.Errorf("config: invalid BASE_URL: %w", err)
|
||||
}
|
||||
|
||||
scheme := strings.ToLower(url.Scheme)
|
||||
scheme := strings.ToLower(parsedURL.Scheme)
|
||||
if scheme != "https" && scheme != "http" {
|
||||
return "", "", "", errors.New("config: invalid BASE_URL: scheme must be http or https")
|
||||
}
|
||||
|
||||
basePath := url.Path
|
||||
url.Path = ""
|
||||
return value, url.String(), basePath, nil
|
||||
basePath := parsedURL.Path
|
||||
parsedURL.Path = ""
|
||||
return value, parsedURL.String(), basePath, nil
|
||||
}
|
||||
|
||||
func parseBool(value string, fallback bool) bool {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue