Skip to content

Commit

Permalink
[logger] Revamp logger to use log/slog. (#462)
Browse files Browse the repository at this point in the history
* Use the newly added `log/slog` (added in Go 1.21) package for logging instead of Google's logger. This makes logs more machine-readable and logs to stderr without any flag.
* By default logs are in log-format, sequence of key=value pairs.
* Logs can now be emitted in JSON format, using flag `--logfmt=json`.
* Add a lot of tests.
  • Loading branch information
manugarg authored Aug 16, 2023
1 parent 829ae26 commit b3891ed
Show file tree
Hide file tree
Showing 15 changed files with 521 additions and 200 deletions.
19 changes: 6 additions & 13 deletions cloudprober.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"context"
"crypto/tls"
"fmt"
"log/slog"
"net"
"net/http"
"net/http/pprof"
Expand All @@ -43,10 +44,10 @@ import (
"github.com/cloudprober/cloudprober/servers"
"github.com/cloudprober/cloudprober/surfacers"
"github.com/cloudprober/cloudprober/sysvars"
"github.com/golang/protobuf/proto"
"google.golang.org/grpc"
"google.golang.org/grpc/channelz/service"
"google.golang.org/grpc/credentials"
"google.golang.org/protobuf/encoding/prototext"
)

const (
Expand Down Expand Up @@ -149,12 +150,7 @@ func InitFromConfig(configFile string) error {
}

// Initialize sysvars module
l, err := logger.NewCloudproberLog(sysvarsModuleName)
if err != nil {
return err
}

if err := sysvars.Init(l, nil); err != nil {
if err := sysvars.Init(logger.NewWithAttrs(slog.String("component", sysvarsModuleName)), nil); err != nil {
return err
}

Expand All @@ -164,18 +160,15 @@ func InitFromConfig(configFile string) error {
}

cfg := &configpb.ProberConfig{}
if err := proto.UnmarshalText(configStr, cfg); err != nil {
if err := prototext.Unmarshal([]byte(configStr), cfg); err != nil {
return err
}

globalLogger, err := logger.NewCloudproberLog("global")
if err != nil {
return fmt.Errorf("error in initializing global logger: %v", err)
}
globalLogger := logger.NewWithAttrs(slog.String("component", "global"))

// Start default HTTP server. It's used for profile handlers and
// prometheus exporter.
ln, err := initDefaultServer(cfg, l)
ln, err := initDefaultServer(cfg, globalLogger)
if err != nil {
return err
}
Expand Down
43 changes: 25 additions & 18 deletions cmd/cloudprober.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ package main
import (
"context"
"fmt"
"log/slog"
"os"
"os/signal"
"runtime/pprof"
Expand All @@ -38,9 +39,9 @@ import (
"github.com/cloudprober/cloudprober/config"
configpb "github.com/cloudprober/cloudprober/config/proto"
"github.com/cloudprober/cloudprober/config/runconfig"
"github.com/cloudprober/cloudprober/logger"
"github.com/cloudprober/cloudprober/sysvars"
"github.com/cloudprober/cloudprober/web"
"github.com/golang/glog"
"google.golang.org/protobuf/encoding/prototext"
)

Expand All @@ -64,6 +65,7 @@ var (
var version string
var buildTimestamp string
var dirty string
var l *logger.Logger

func setupConfigTestVars() {
configTestVars = map[string]string{
Expand Down Expand Up @@ -91,30 +93,30 @@ func setupProfiling() {
var err error
f, err = os.Create(*cpuprofile)
if err != nil {
glog.Exit(err)
l.Critical(err.Error())
}
if err = pprof.StartCPUProfile(f); err != nil {
glog.Errorf("Could not start CPU profiling: %v", err)
l.Criticalf("Could not start CPU profiling: %v", err)
}
}
go func(file *os.File) {
<-sigChan
pprof.StopCPUProfile()
if *cpuprofile != "" {
if err := file.Close(); err != nil {
glog.Exit(err)
l.Critical(err.Error())
}
}
if *memprofile != "" {
f, err := os.Create(*memprofile)
if err != nil {
glog.Exit(err)
l.Critical(err.Error())
}
if err = pprof.WriteHeapProfile(f); err != nil {
glog.Exit(err)
l.Critical(err.Error())
}
if err := f.Close(); err != nil {
glog.Exit(err)
l.Critical(err.Error())
}
}
os.Exit(1)
Expand All @@ -124,7 +126,7 @@ func setupProfiling() {
func configFileToString(fileName string) string {
b, err := file.ReadFile(fileName)
if err != nil {
glog.Exitf("Failed to read the config file: %v", err)
l.Criticalf("Failed to read the config file: %v", err)
}
return string(b)
}
Expand All @@ -133,28 +135,33 @@ func getConfig() string {
if *configFile != "" {
return configFileToString(*configFile)
}

// On GCE first check if there is a config in custom metadata
// attributes.
if metadata.OnGCE() {
if config, err := config.ReadFromGCEMetadata(configMetadataKeyName); err != nil {
glog.Infof("Error reading config from metadata. Err: %v", err)
l.Infof("Error reading config from metadata. Err: %v", err)
} else {
return config
}
}

// If config not found in metadata, check default config on disk
if _, err := os.Stat(defaultConfigFile); !os.IsNotExist(err) {
return configFileToString(defaultConfigFile)
}
glog.Warningf("Config file %s not found. Using default config.", defaultConfigFile)
l.Warningf("Config file %s not found. Using default config.", defaultConfigFile)
return config.DefaultConfig()
}

func main() {
flag.Parse()

// Initialize logger after parsing flags.
l = logger.NewWithAttrs(slog.String("component", "global"))

if len(flag.Args()) > 0 {
glog.Exitf("Unexpected non-flag arguments: %v", flag.Args())
l.Criticalf("Unexpected non-flag arguments: %v", flag.Args())
}

if dirty == "1" {
Expand All @@ -165,7 +172,7 @@ func main() {
if buildTimestamp != "" {
ts, err := strconv.ParseInt(buildTimestamp, 10, 64)
if err != nil {
glog.Exitf("Error parsing build timestamp (%s). Err: %v", buildTimestamp, err)
l.Criticalf("Error parsing build timestamp (%s). Err: %v", buildTimestamp, err)
}
runconfig.SetBuildTimestamp(time.Unix(ts, 0))
}
Expand All @@ -187,7 +194,7 @@ func main() {
sysvars.Init(nil, configTestVars)
text, err := config.ParseTemplate(getConfig(), sysvars.Vars(), nil)
if err != nil {
glog.Exitf("Error parsing config file. Err: %v", err)
l.Criticalf("Error parsing config file. Err: %v", err)
}
fmt.Println(text)
return
Expand All @@ -199,24 +206,24 @@ func main() {
return v + "-test-value", nil
})
if err != nil {
glog.Exitf("Error parsing config file. Err: %v", err)
l.Criticalf("Error parsing config file. Err: %v", err)
}
cfg := &configpb.ProberConfig{}
if err := prototext.Unmarshal([]byte(configStr), cfg); err != nil {
glog.Exitf("Error unmarshalling config. Err: %v", err)
l.Criticalf("Error unmarshalling config. Err: %v", err)
}
return
}

setupProfiling()

if err := cloudprober.InitFromConfig(getConfig()); err != nil {
glog.Exitf("Error initializing cloudprober. Err: %v", err)
l.Criticalf("Error initializing cloudprober. Err: %v", err)
}

// web.Init sets up web UI for cloudprober.
if err := web.Init(); err != nil {
glog.Exitf("Error initializing web interface. Err: %v", err)
l.Criticalf("Error initializing web interface. Err: %v", err)
}

startCtx := context.Background()
Expand All @@ -234,7 +241,7 @@ func main() {

go func() {
sig := <-sigs
glog.Warningf("Received signal \"%v\", canceling the start context and waiting for %v before closing", sig, *stopTime)
l.Warningf("Received signal \"%v\", canceling the start context and waiting for %v before closing", sig, *stopTime)
cancelF()
time.Sleep(*stopTime)
os.Exit(0)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/cloudprober/cloudprober

go 1.20
go 1.21

require (
cloud.google.com/go v0.81.0
Expand Down
Loading

0 comments on commit b3891ed

Please sign in to comment.