Skip to content

Commit c89a67c

Browse files
author
Pavlo Sumkin
committed
GROUNDWORK-1502 Provide logger based on zerolog
1 parent 20d8ab0 commit c89a67c

File tree

9 files changed

+658
-157
lines changed

9 files changed

+658
-157
lines changed

config/config.go

Lines changed: 78 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ import (
1414
"sync"
1515
"time"
1616

17-
"github.com/gwos/tcg/log"
17+
"github.com/gwos/tcg/logger"
1818
"github.com/kelseyhightower/envconfig"
19+
"github.com/rs/zerolog"
20+
"github.com/rs/zerolog/log"
1921
"go.opentelemetry.io/otel/attribute"
2022
"go.opentelemetry.io/otel/exporters/trace/jaeger"
2123
"go.opentelemetry.io/otel/sdk/resource"
@@ -67,7 +69,7 @@ const (
6769
InstallationModeS = "STANDALONE"
6870
)
6971

70-
// LogLevel defines levels for logrus
72+
// LogLevel defines levels in logrus-style
7173
type LogLevel int
7274

7375
// Enum levels
@@ -117,6 +119,8 @@ type Connector struct {
117119
// If count is 0, old versions are removed rather than rotated.
118120
LogFileRotate int `yaml:"logFileRotate"`
119121
LogLevel LogLevel `yaml:"logLevel"`
122+
LogNoColor bool `yaml:"logNoColor"`
123+
LogTimeFormat string `yaml:"logTimeFormat"`
120124

121125
// NatsAckWait is the time the NATS server will wait before resending a message
122126
// Should be greater then the GWClient request duration
@@ -335,15 +339,17 @@ func defaults() Config {
335339
return Config{
336340
Connector: &Connector{
337341
ControllerAddr: ":8099",
338-
ControllerReadTimeout: time.Duration(time.Second * 10),
339-
ControllerWriteTimeout: time.Duration(time.Second * 20),
340-
ControllerStartTimeout: time.Duration(time.Second * 4),
341-
ControllerStopTimeout: time.Duration(time.Second * 4),
342+
ControllerReadTimeout: time.Second * 10,
343+
ControllerWriteTimeout: time.Second * 20,
344+
ControllerStartTimeout: time.Second * 4,
345+
ControllerStopTimeout: time.Second * 4,
342346
LogCondense: 0,
343347
LogFileMaxSize: 1024 * 1024 * 10, // 10MB
344348
LogFileRotate: 5,
345349
LogLevel: 1,
346-
NatsAckWait: time.Duration(time.Second * 30),
350+
LogNoColor: false,
351+
LogTimeFormat: time.RFC3339,
352+
NatsAckWait: time.Second * 30,
347353
NatsMaxInflight: 1024,
348354
NatsMaxPubAcksInflight: 1024,
349355
NatsMaxPayload: 1024 * 1024 * 80, // 80MB
@@ -352,10 +358,10 @@ func defaults() Config {
352358
NatsMonitorPort: 0,
353359
NatsStoreDir: "natsstore",
354360
NatsStoreType: "FILE",
355-
NatsStoreMaxAge: time.Duration(time.Hour * 24 * 10), // 10days
356-
NatsStoreMaxBytes: 1024 * 1024 * 1024 * 50, // 50GB
357-
NatsStoreBufferSize: 1024 * 1024 * 2, // 2MB
358-
NatsStoreReadBufferSize: 1024 * 1024 * 2, // 2MB
361+
NatsStoreMaxAge: time.Hour * 24 * 10, // 10days
362+
NatsStoreMaxBytes: 1024 * 1024 * 1024 * 50, // 50GB
363+
NatsStoreBufferSize: 1024 * 1024 * 2, // 2MB
364+
NatsStoreReadBufferSize: 1024 * 1024 * 2, // 2MB
359365
},
360366
DSConnection: &DSConnection{},
361367
Jaegertracing: &Jaegertracing{},
@@ -365,54 +371,54 @@ func defaults() Config {
365371
// GetConfig implements Singleton pattern
366372
func GetConfig() *Config {
367373
once.Do(func() {
368-
logBuf := make(map[string]interface{}, 3)
374+
/* buffer the logging while configuring */
375+
logBuf := &logger.LogBuffer{
376+
Level: zerolog.TraceLevel,
377+
Size: 16,
378+
}
379+
log.Logger = zerolog.New(logBuf).
380+
With().Timestamp().Caller().Logger()
381+
log.Info().Msgf("Build info: %s / %s", buildTag, buildTime)
382+
369383
c := defaults()
370384
cfg = &c
371-
372385
if data, err := ioutil.ReadFile(cfg.configPath()); err != nil {
373-
logBuf["ioutil.ReadFile"] = err
386+
log.Warn().Err(err).
387+
Str("configPath", cfg.configPath()).
388+
Msg("could not read config")
374389
} else {
375390
if err := yaml.Unmarshal(data, cfg); err != nil {
376-
logBuf["yaml.Unmarshal"] = err
391+
log.Err(err).
392+
Str("configPath", cfg.configPath()).
393+
Msg("could not parse config")
377394
}
378395
}
379-
380396
if err := envconfig.Process(EnvConfigPrefix, cfg); err != nil {
381-
logBuf["envconfig.Process"] = err
382-
}
383-
384-
log.Config(
385-
cfg.Connector.LogFile,
386-
cfg.Connector.LogFileMaxSize,
387-
cfg.Connector.LogFileRotate,
388-
int(cfg.Connector.LogLevel),
389-
cfg.Connector.LogCondense,
390-
)
391-
log.Info(fmt.Sprintf("Build info: %s / %s", buildTag, buildTime))
392-
if len(logBuf) > 0 {
393-
log.With(logBuf).Warn()
397+
log.Err(err).
398+
Str("EnvConfigPrefix", EnvConfigPrefix).
399+
Msg("could not process config environment")
394400
}
401+
cfg.initLogger()
402+
logger.WriteLogBuffer(logBuf)
395403
})
396404
return cfg
397405
}
398406

399407
func (cfg Config) configPath() string {
400408
configPath := os.Getenv(string(ConfigEnv))
401409
if configPath == "" {
402-
wd, err := os.Getwd()
403-
if err != nil {
404-
log.Warn(err)
405-
wd = ""
410+
configPath = ConfigName
411+
if wd, err := os.Getwd(); err == nil {
412+
configPath = path.Join(wd, ConfigName)
406413
}
407-
configPath = path.Join(wd, ConfigName)
408414
}
409415
return configPath
410416
}
411417

412418
func (cfg *Config) loadConnector(data []byte) (*ConnectorDTO, error) {
413419
var dto ConnectorDTO
414420
if err := json.Unmarshal(data, &dto); err != nil {
415-
log.Error("|config.go| : [loadConnector] : ", err.Error())
421+
log.Err(err).Msg("could not parse connector")
416422
return nil, err
417423
}
418424
cfg.Connector.AgentID = dto.AgentID
@@ -437,7 +443,7 @@ func (cfg *Config) loadAdvancedPrefixes(data []byte) error {
437443
} `json:"advanced,omitempty"`
438444
}
439445
if err := json.Unmarshal(data, &s); err != nil {
440-
log.Error("|config.go| : [loadAdvancedPrefixes] : ", err.Error())
446+
log.Err(err).Msg("could not parse advanced")
441447
return err
442448
}
443449
for _, c := range cfg.GWConnections {
@@ -484,10 +490,14 @@ func (cfg *Config) LoadConnectorDTO(data []byte) (*ConnectorDTO, error) {
484490
newCfg := &c
485491
/* load config file */
486492
if data, err := ioutil.ReadFile(newCfg.configPath()); err != nil {
487-
log.Warn(err)
493+
log.Warn().Err(err).
494+
Str("configPath", cfg.configPath()).
495+
Msg("could not read config")
488496
} else {
489497
if err := yaml.Unmarshal(data, newCfg); err != nil {
490-
log.Warn(err)
498+
log.Warn().Err(err).
499+
Str("configPath", newCfg.configPath()).
500+
Msg("could not parse config")
491501
}
492502
}
493503
/* load as ConnectorDTO */
@@ -505,15 +515,20 @@ func (cfg *Config) LoadConnectorDTO(data []byte) (*ConnectorDTO, error) {
505515
}
506516
/* override config file */
507517
if output, err := yaml.Marshal(newCfg); err != nil {
508-
log.Warn(err)
518+
log.Err(err).
519+
Msg("could not prepare config for writing")
509520
} else {
510521
if err := ioutil.WriteFile(newCfg.configPath(), output, 0644); err != nil {
511-
log.Warn(err)
522+
log.Err(err).
523+
Str("configPath", newCfg.configPath()).
524+
Msg("could not write config")
512525
}
513526
}
514527
/* load environment */
515528
if err := envconfig.Process(EnvConfigPrefix, newCfg); err != nil {
516-
log.Warn(err)
529+
log.Err(err).
530+
Str("EnvConfigPrefix", EnvConfigPrefix).
531+
Msg("could not process config environment")
517532
}
518533
/* process PMC */
519534
if cfg.IsConfiguringPMC() {
@@ -526,13 +541,7 @@ func (cfg *Config) LoadConnectorDTO(data []byte) (*ConnectorDTO, error) {
526541
cfg.GWConnections = newCfg.GWConnections
527542

528543
/* update logger */
529-
log.Config(
530-
cfg.Connector.LogFile,
531-
cfg.Connector.LogFileMaxSize,
532-
cfg.Connector.LogFileRotate,
533-
int(cfg.Connector.LogLevel),
534-
cfg.Connector.LogCondense,
535-
)
544+
cfg.initLogger()
536545

537546
return dto, nil
538547
}
@@ -593,13 +602,13 @@ func (cfg Config) initJaegertracing() (*sdktrace.TracerProvider, error) {
593602
jaeger.WithAgentPort(port),
594603
)
595604
} else {
596-
log.Warn(err)
605+
log.Err(err).Msg("could not parse the JaegerAgent")
597606
return nil, err
598607
}
599608
case len(tcgJaegerCollector) != 0:
600609
endpointOption = jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(tcgJaegerCollector))
601610
default:
602-
log.Debug(errNotConfigured)
611+
log.Debug().Msg(errNotConfigured.Error())
603612
return nil, errNotConfigured
604613
}
605614

@@ -614,7 +623,7 @@ func (cfg Config) initJaegertracing() (*sdktrace.TracerProvider, error) {
614623

615624
exporter, err := jaeger.NewRawExporter(endpointOption)
616625
if err != nil {
617-
log.Warn(err)
626+
log.Err(err).Msg("could not create exporter")
618627
return nil, err
619628
}
620629
tp := sdktrace.NewTracerProvider(
@@ -626,6 +635,24 @@ func (cfg Config) initJaegertracing() (*sdktrace.TracerProvider, error) {
626635
return tp, nil
627636
}
628637

638+
func (cfg Config) initLogger() {
639+
opts := []logger.Option{
640+
logger.WithCondense(cfg.Connector.LogCondense),
641+
logger.WithLastErrors(10),
642+
logger.WithLevel([...]zerolog.Level{3, 2, 1, 0}[cfg.Connector.LogLevel]),
643+
logger.WithNoColor(cfg.Connector.LogNoColor),
644+
logger.WithTimeFormat(cfg.Connector.LogTimeFormat),
645+
}
646+
if cfg.Connector.LogFile != "" {
647+
opts = append(opts, logger.WithLogFile(&logger.LogFile{
648+
FilePath: cfg.Connector.LogFile,
649+
MaxSize: cfg.Connector.LogFileMaxSize,
650+
Rotate: cfg.Connector.LogFileRotate,
651+
}))
652+
}
653+
logger.SetLogger(opts...)
654+
}
655+
629656
// Decrypt decrypts small messages
630657
// golang.org/x/crypto/nacl/secretbox
631658
func Decrypt(message, secret []byte) ([]byte, error) {

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ require (
3535
github.com/prometheus/common v0.29.0
3636
github.com/prometheus/prometheus v2.5.0+incompatible
3737
github.com/robfig/cron/v3 v3.0.1
38+
github.com/rs/zerolog v1.23.0
3839
github.com/shirou/gopsutil v3.21.5+incompatible
3940
github.com/sirupsen/logrus v1.8.1
4041
github.com/stretchr/testify v1.7.0

go.sum

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D
8383
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
8484
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
8585
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
86+
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
8687
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
8788
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
8889
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -167,6 +168,7 @@ github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn
167168
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
168169
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
169170
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
171+
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
170172
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
171173
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
172174
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
@@ -401,6 +403,9 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
401403
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
402404
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
403405
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
406+
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
407+
github.com/rs/zerolog v1.23.0 h1:UskrK+saS9P9Y789yNNulYKdARjPZuS35B8gJF2x60g=
408+
github.com/rs/zerolog v1.23.0/go.mod h1:6c7hFfxPOy7TacJc4Fcdi24/J0NKYGzjG8FWRI916Qo=
404409
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
405410
github.com/shirou/gopsutil v3.21.5+incompatible h1:OloQyEerMi7JUrXiNzy8wQ5XN+baemxSl12QgIzt0jc=
406411
github.com/shirou/gopsutil v3.21.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=

logger/logfile.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package logger
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"sync"
7+
)
8+
9+
// LogFile provides file rotation
10+
type LogFile struct {
11+
mu sync.Mutex
12+
file *os.File
13+
fileSize int64
14+
15+
FilePath string
16+
MaxSize int64
17+
Rotate int
18+
}
19+
20+
// Close implements io.Closer interface
21+
func (f *LogFile) Close() error {
22+
return f.file.Close()
23+
}
24+
25+
// Write implements io.Writer interface
26+
func (f *LogFile) Write(p []byte) (int, error) {
27+
f.mu.Lock()
28+
defer f.mu.Unlock()
29+
30+
if f.file == nil {
31+
f.open()
32+
}
33+
if f.file != nil &&
34+
(f.MaxSize > 0 && f.MaxSize < f.fileSize+int64(len(p))) {
35+
f.rotate()
36+
}
37+
38+
n, err := f.file.Write(p)
39+
if err != nil {
40+
f.open()
41+
n, err = f.file.Write(p)
42+
}
43+
if err == nil {
44+
f.fileSize += int64(n)
45+
}
46+
return n, err
47+
}
48+
49+
func (f *LogFile) open() {
50+
if f.file != nil {
51+
_ = f.file.Close()
52+
}
53+
if file, err := os.OpenFile(f.FilePath,
54+
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err == nil {
55+
f.file = file
56+
if fileInfo, err := file.Stat(); err == nil {
57+
f.fileSize = fileInfo.Size()
58+
}
59+
}
60+
}
61+
62+
func (f *LogFile) rotate() {
63+
filename := f.file.Name()
64+
_ = f.file.Close()
65+
if f.Rotate == 0 {
66+
_ = os.Remove(filename)
67+
} else {
68+
for i := f.Rotate; i > 0; i-- {
69+
_ = os.Rename(fmt.Sprintf("%s.%d", filename, i-1), fmt.Sprintf("%s.%d", filename, i))
70+
}
71+
_ = os.Rename(filename, fmt.Sprintf("%s.%d", filename, 1))
72+
}
73+
f.open()
74+
}

0 commit comments

Comments
 (0)