1package log
2
3import (
4	"fmt"
5	"io"
6	"os"
7
8	"github.com/sirupsen/logrus"
9)
10
11type loggerConfig struct {
12	logger     *logrus.Logger
13	level      logrus.Level
14	formatter  logrus.Formatter
15	outputPath string
16	writer     io.Writer
17
18	// A list of warnings that will be emitted once the logger is configured
19	warnings []string
20}
21
22// LoggerOption will configure a new logrus Logger.
23type LoggerOption func(*loggerConfig)
24
25func applyLoggerOptions(opts []LoggerOption) *loggerConfig {
26	conf := loggerConfig{
27		logger:    logger,
28		level:     logrus.InfoLevel,
29		formatter: &logrus.TextFormatter{},
30		writer:    os.Stdout,
31	}
32
33	for _, v := range opts {
34		v(&conf)
35	}
36
37	return &conf
38}
39
40// WithFormatter allows setting the format to `text`, `json`, `color` or `combined`. In case
41// the input is not recognized it defaults to text with a warning.
42// More details of these formats:
43// * `text` - human readable.
44// * `json` - computer readable, new-line delimited JSON.
45// * `color` - human readable, in color. Useful for development.
46// * `combined` - httpd access logs. Good for legacy access log parsers.
47func WithFormatter(format string) LoggerOption {
48	return func(conf *loggerConfig) {
49		switch format {
50		case "text":
51			conf.formatter = &logrus.TextFormatter{}
52		case "color":
53			conf.formatter = &logrus.TextFormatter{ForceColors: true, EnvironmentOverrideColors: true}
54		case "json":
55			conf.formatter = &logrus.JSONFormatter{}
56		case "combined":
57			conf.formatter = newCombinedcombinedAccessLogFormatter()
58		default:
59			conf.warnings = append(conf.warnings, fmt.Sprintf("unknown logging format %s, ignoring option", format))
60		}
61	}
62}
63
64// WithLogLevel is used to set the log level when defaulting to `info` is not
65// wanted. Other options are: `debug`, `warn`, `error`, `fatal`, and `panic`.
66func WithLogLevel(level string) LoggerOption {
67	return func(conf *loggerConfig) {
68		logrusLevel, err := logrus.ParseLevel(level)
69		if err != nil {
70			conf.warnings = append(conf.warnings, fmt.Sprintf("unknown log level, ignoring option: %v", err))
71		} else {
72			conf.level = logrusLevel
73		}
74	}
75}
76
77// WithOutputName allows customization of the sink of the logger. Output is either:
78// `stdout`, `stderr`, or a path to a file.
79func WithOutputName(outputName string) LoggerOption {
80	return func(conf *loggerConfig) {
81		switch outputName {
82		case "stdout":
83			conf.writer = os.Stdout
84		case "stderr":
85			conf.writer = os.Stderr
86		default:
87			conf.writer = nil
88			conf.outputPath = outputName
89		}
90	}
91}
92
93// WithWriter allows the writer to be customized. The application is responsible for closing the writer manually.
94func WithWriter(writer io.Writer) LoggerOption {
95	return func(conf *loggerConfig) {
96		conf.writer = writer
97	}
98}
99
100// WithLogger allows you to configure a proprietary logger using the `Initialize` method.
101func WithLogger(logger *logrus.Logger) LoggerOption {
102	return func(conf *loggerConfig) {
103		conf.logger = logger
104	}
105}
106