TUN-3607: Set up single-file logger with zerolog
This commit is contained in:
parent
9bc1c0c70b
commit
2ea491b1d0
|
@ -271,7 +271,7 @@ func (d *deleteMockTunnelStore) CleanupConnections(tunnelID uuid.UUID) error {
|
||||||
func Test_subcommandContext_Delete(t *testing.T) {
|
func Test_subcommandContext_Delete(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
c *cli.Context
|
c *cli.Context
|
||||||
logger logger.Service
|
log *zerolog.Logger
|
||||||
isUIEnabled bool
|
isUIEnabled bool
|
||||||
fs fileSystem
|
fs fileSystem
|
||||||
tunnelstoreClient *deleteMockTunnelStore
|
tunnelstoreClient *deleteMockTunnelStore
|
||||||
|
@ -283,8 +283,7 @@ func Test_subcommandContext_Delete(t *testing.T) {
|
||||||
newCertPath := "new_cert.json"
|
newCertPath := "new_cert.json"
|
||||||
tunnelID1 := uuid.MustParse("df5ed608-b8b4-4109-89f3-9f2cf199df64")
|
tunnelID1 := uuid.MustParse("df5ed608-b8b4-4109-89f3-9f2cf199df64")
|
||||||
tunnelID2 := uuid.MustParse("af5ed608-b8b4-4109-89f3-9f2cf199df64")
|
tunnelID2 := uuid.MustParse("af5ed608-b8b4-4109-89f3-9f2cf199df64")
|
||||||
logger, err := logger.New()
|
log := zerolog.Nop()
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -296,7 +295,7 @@ func Test_subcommandContext_Delete(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "clean up continues if credentials are not found",
|
name: "clean up continues if credentials are not found",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
logger: logger,
|
log: &log,
|
||||||
fs: mockFileSystem{
|
fs: mockFileSystem{
|
||||||
rf: func(filePath string) ([]byte, error) {
|
rf: func(filePath string) ([]byte, error) {
|
||||||
return nil, errors.New("file not found")
|
return nil, errors.New("file not found")
|
||||||
|
@ -307,7 +306,7 @@ func Test_subcommandContext_Delete(t *testing.T) {
|
||||||
flagSet := flag.NewFlagSet("test0", flag.PanicOnError)
|
flagSet := flag.NewFlagSet("test0", flag.PanicOnError)
|
||||||
flagSet.String(CredFileFlag, newCertPath, "")
|
flagSet.String(CredFileFlag, newCertPath, "")
|
||||||
c := cli.NewContext(cli.NewApp(), flagSet, nil)
|
c := cli.NewContext(cli.NewApp(), flagSet, nil)
|
||||||
err = c.Set(CredFileFlag, newCertPath)
|
_ = c.Set(CredFileFlag, newCertPath)
|
||||||
return c
|
return c
|
||||||
}(),
|
}(),
|
||||||
tunnelstoreClient: newDeleteMockTunnelStore(
|
tunnelstoreClient: newDeleteMockTunnelStore(
|
||||||
|
@ -331,7 +330,7 @@ func Test_subcommandContext_Delete(t *testing.T) {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
sc := &subcommandContext{
|
sc := &subcommandContext{
|
||||||
c: tt.fields.c,
|
c: tt.fields.c,
|
||||||
logger: tt.fields.logger,
|
log: tt.fields.log,
|
||||||
isUIEnabled: tt.fields.isUIEnabled,
|
isUIEnabled: tt.fields.isUIEnabled,
|
||||||
fs: tt.fields.fs,
|
fs: tt.fields.fs,
|
||||||
tunnelstoreClient: tt.fields.tunnelstoreClient,
|
tunnelstoreClient: tt.fields.tunnelstoreClient,
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package logger
|
package logger
|
||||||
|
|
||||||
|
import "path/filepath"
|
||||||
|
|
||||||
var defaultConfig = createDefaultConfig()
|
var defaultConfig = createDefaultConfig()
|
||||||
|
|
||||||
// Logging configuration
|
// Logging configuration
|
||||||
|
@ -16,12 +18,17 @@ type ConsoleConfig struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type FileConfig struct {
|
type FileConfig struct {
|
||||||
Filepath string
|
Dirname string
|
||||||
|
Filename string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fc *FileConfig) Fullpath() string {
|
||||||
|
return filepath.Join(fc.Dirname, fc.Filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
type RollingConfig struct {
|
type RollingConfig struct {
|
||||||
Directory string
|
Dirname string
|
||||||
Filename string
|
Filename string
|
||||||
|
|
||||||
maxSize int // megabytes
|
maxSize int // megabytes
|
||||||
maxBackups int // files
|
maxBackups int // files
|
||||||
|
@ -34,18 +41,19 @@ func createDefaultConfig() Config {
|
||||||
const RollingMaxSize = 1 // Mb
|
const RollingMaxSize = 1 // Mb
|
||||||
const RollingMaxBackups = 5 // files
|
const RollingMaxBackups = 5 // files
|
||||||
const RollingMaxAge = 0 // Keep forever
|
const RollingMaxAge = 0 // Keep forever
|
||||||
const rollingLogFilename = "cloudflared.log"
|
const defaultLogFilename = "cloudflared.log"
|
||||||
|
|
||||||
return Config{
|
return Config{
|
||||||
ConsoleConfig: &ConsoleConfig{
|
ConsoleConfig: &ConsoleConfig{
|
||||||
noColor: false,
|
noColor: false,
|
||||||
},
|
},
|
||||||
FileConfig: &FileConfig{
|
FileConfig: &FileConfig{
|
||||||
Filepath: "",
|
Dirname: "",
|
||||||
|
Filename: defaultLogFilename,
|
||||||
},
|
},
|
||||||
RollingConfig: &RollingConfig{
|
RollingConfig: &RollingConfig{
|
||||||
Directory: "",
|
Dirname: "",
|
||||||
Filename: rollingLogFilename,
|
Filename: defaultLogFilename,
|
||||||
maxSize: RollingMaxSize,
|
maxSize: RollingMaxSize,
|
||||||
maxBackups: RollingMaxBackups,
|
maxBackups: RollingMaxBackups,
|
||||||
maxAge: RollingMaxAge,
|
maxAge: RollingMaxAge,
|
||||||
|
@ -57,7 +65,7 @@ func createDefaultConfig() Config {
|
||||||
func CreateConfig(
|
func CreateConfig(
|
||||||
minLevel string,
|
minLevel string,
|
||||||
disableTerminal bool,
|
disableTerminal bool,
|
||||||
rollingLogPath, rollingLogFilename, nonRollingLogFilePath string,
|
rollingLogPath, nonRollingLogFilePath string,
|
||||||
) *Config {
|
) *Config {
|
||||||
var console *ConsoleConfig
|
var console *ConsoleConfig
|
||||||
if !disableTerminal {
|
if !disableTerminal {
|
||||||
|
@ -65,13 +73,11 @@ func CreateConfig(
|
||||||
}
|
}
|
||||||
|
|
||||||
var file *FileConfig
|
var file *FileConfig
|
||||||
if nonRollingLogFilePath != "" {
|
|
||||||
file = createFileConfig(nonRollingLogFilePath)
|
|
||||||
}
|
|
||||||
|
|
||||||
var rolling *RollingConfig
|
var rolling *RollingConfig
|
||||||
if rollingLogPath != "" {
|
if rollingLogPath != "" {
|
||||||
rolling = createRollingConfig(rollingLogPath, rollingLogFilename)
|
rolling = createRollingConfig(rollingLogPath)
|
||||||
|
} else if nonRollingLogFilePath != "" {
|
||||||
|
file = createFileConfig(nonRollingLogFilePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
if minLevel == "" {
|
if minLevel == "" {
|
||||||
|
@ -93,24 +99,27 @@ func createConsoleConfig() *ConsoleConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createFileConfig(filepath string) *FileConfig {
|
func createFileConfig(fullpath string) *FileConfig {
|
||||||
if filepath == "" {
|
if fullpath == "" {
|
||||||
filepath = defaultConfig.FileConfig.Filepath
|
return defaultConfig.FileConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dirname, filename := filepath.Split(fullpath)
|
||||||
|
|
||||||
return &FileConfig{
|
return &FileConfig{
|
||||||
Filepath: filepath,
|
Dirname: dirname,
|
||||||
|
Filename: filename,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createRollingConfig(directory, filename string) *RollingConfig {
|
func createRollingConfig(directory string) *RollingConfig {
|
||||||
if directory == "" {
|
if directory == "" {
|
||||||
directory = defaultConfig.RollingConfig.Directory
|
directory = defaultConfig.RollingConfig.Dirname
|
||||||
}
|
}
|
||||||
|
|
||||||
return &RollingConfig{
|
return &RollingConfig{
|
||||||
Directory: directory,
|
Dirname: directory,
|
||||||
Filename: filename,
|
Filename: defaultConfig.RollingConfig.Filename,
|
||||||
maxSize: defaultConfig.RollingConfig.maxSize,
|
maxSize: defaultConfig.RollingConfig.maxSize,
|
||||||
maxBackups: defaultConfig.RollingConfig.maxBackups,
|
maxBackups: defaultConfig.RollingConfig.maxBackups,
|
||||||
maxAge: defaultConfig.RollingConfig.maxAge,
|
maxAge: defaultConfig.RollingConfig.maxAge,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package logger
|
package logger
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
@ -22,6 +23,9 @@ const (
|
||||||
|
|
||||||
LogSSHDirectoryFlag = "log-directory"
|
LogSSHDirectoryFlag = "log-directory"
|
||||||
LogSSHLevelFlag = "log-level"
|
LogSSHLevelFlag = "log-level"
|
||||||
|
|
||||||
|
dirPermMode = 0744 // rwxr--r--
|
||||||
|
filePermMode = 0644 // rw-r--r--
|
||||||
)
|
)
|
||||||
|
|
||||||
func fallbackLogger(err error) *zerolog.Logger {
|
func fallbackLogger(err error) *zerolog.Logger {
|
||||||
|
@ -38,6 +42,15 @@ func newZerolog(loggerConfig *Config) *zerolog.Logger {
|
||||||
writers = append(writers, createConsoleLogger(*loggerConfig.ConsoleConfig))
|
writers = append(writers, createConsoleLogger(*loggerConfig.ConsoleConfig))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if loggerConfig.FileConfig != nil {
|
||||||
|
fileLogger, err := createFileLogger(*loggerConfig.FileConfig)
|
||||||
|
if err != nil {
|
||||||
|
return fallbackLogger(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
writers = append(writers, fileLogger)
|
||||||
|
}
|
||||||
|
|
||||||
if loggerConfig.RollingConfig != nil {
|
if loggerConfig.RollingConfig != nil {
|
||||||
rollingLogger, err := createRollingLogger(*loggerConfig.RollingConfig)
|
rollingLogger, err := createRollingLogger(*loggerConfig.RollingConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -84,11 +97,14 @@ func createFromContext(
|
||||||
logLevel,
|
logLevel,
|
||||||
disableTerminal,
|
disableTerminal,
|
||||||
logDirectory,
|
logDirectory,
|
||||||
defaultConfig.RollingConfig.Filename,
|
|
||||||
logFile,
|
logFile,
|
||||||
)
|
)
|
||||||
|
|
||||||
return newZerolog(loggerConfig)
|
log := newZerolog(loggerConfig)
|
||||||
|
if incompatibleFlagsSet := logFile != "" && logDirectory != ""; incompatibleFlagsSet {
|
||||||
|
log.Error().Msgf("Your config includes values for both %s and %s, but they are incompatible. %s takes precedence.", LogFileFlag, logDirectoryFlagName, LogFileFlag)
|
||||||
|
}
|
||||||
|
return log
|
||||||
}
|
}
|
||||||
|
|
||||||
func Create(loggerConfig *Config) *zerolog.Logger {
|
func Create(loggerConfig *Config) *zerolog.Logger {
|
||||||
|
@ -106,13 +122,53 @@ func createConsoleLogger(config ConsoleConfig) io.Writer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createFileLogger(config FileConfig) (io.Writer, error) {
|
||||||
|
var logFile io.Writer
|
||||||
|
fullpath := config.Fullpath()
|
||||||
|
|
||||||
|
// Try to open the existing file
|
||||||
|
logFile, err := os.OpenFile(fullpath, os.O_APPEND|os.O_WRONLY, filePermMode)
|
||||||
|
if err != nil {
|
||||||
|
// If the existing file wasn't found, or couldn't be opened, just ignore
|
||||||
|
// it and recreate a new one.
|
||||||
|
logFile, err = createLogFile(config)
|
||||||
|
// If creating a new logfile fails, then we have no choice but to error out.
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fileLogger := zerolog.New(logFile).With().Logger()
|
||||||
|
|
||||||
|
return fileLogger, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createLogFile(config FileConfig) (io.Writer, error) {
|
||||||
|
if config.Dirname != "" {
|
||||||
|
err := os.MkdirAll(config.Dirname, dirPermMode)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to create directories for new logfile: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mode := os.FileMode(filePermMode)
|
||||||
|
|
||||||
|
logFile, err := os.OpenFile(config.Filename, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, mode)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to create a new logfile: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return logFile, nil
|
||||||
|
}
|
||||||
|
|
||||||
func createRollingLogger(config RollingConfig) (io.Writer, error) {
|
func createRollingLogger(config RollingConfig) (io.Writer, error) {
|
||||||
if err := os.MkdirAll(config.Directory, 0744); err != nil {
|
if err := os.MkdirAll(config.Dirname, dirPermMode); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &lumberjack.Logger{
|
return &lumberjack.Logger{
|
||||||
Filename: path.Join(config.Directory, config.Filename),
|
Filename: path.Join(config.Dirname, config.Filename),
|
||||||
MaxBackups: config.maxBackups,
|
MaxBackups: config.maxBackups,
|
||||||
MaxSize: config.maxSize,
|
MaxSize: config.maxSize,
|
||||||
MaxAge: config.maxAge,
|
MaxAge: config.maxAge,
|
||||||
|
|
Loading…
Reference in New Issue