Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do leveled logging #4

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ package main
import (
"context"
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"os/signal"
"strings"
Expand All @@ -27,12 +25,17 @@ import (
"time"

"github.com/mumoshu/crossover/pkg/controller"
"github.com/mumoshu/crossover/pkg/log"
)

func main() {
var tokenfile string

manager := &controller.Manager{}
logger := log.StdLogger

manager := &controller.Manager{
Logger: logger,
}

defaultNs := os.Getenv("NS")
if defaultNs == "" {
Expand Down Expand Up @@ -60,7 +63,8 @@ func main() {

tokenBytes, err := ioutil.ReadFile(tokenfile)
if err != nil {
fmt.Fprintf(os.Stderr, "reading token: %v\n", err)
logger.Errorf("Error: reading token from %s: %v\n", tokenfile, err)
os.Exit(1)
}

manager.Token = strings.TrimSpace(string(tokenBytes))
Expand All @@ -72,7 +76,7 @@ func main() {
wg.Add(1)
go func() {
if err := manager.Run(ctx); err != nil {
log.Printf("Error: %v", err)
logger.Errorf("Error: %v", err)
os.Exit(1)
}
wg.Done()
Expand All @@ -84,11 +88,11 @@ func main() {

select {
case <-signalChan:
log.Printf("Shutdown signal received. Exiting...")
logger.Infof("Shutdown signal received. Exiting...")
cancel()
wg.Wait()
case <-ctx.Done():
log.Printf("Done writing Envoy configs. Existing...")
logger.Infof("Done writing Envoy configs. Existing...")
}
os.Exit(0)
}
8 changes: 5 additions & 3 deletions pkg/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,24 @@ package controller
import (
"context"
"fmt"
"log"
"sync"
"time"

"github.com/mumoshu/crossover/pkg/kubeclient"
"github.com/mumoshu/crossover/pkg/log"
"github.com/mumoshu/crossover/pkg/reconciler"
"github.com/mumoshu/crossover/pkg/types"
)

type Controller struct {
namespace string
namespace string
resourceNames StringSlice

client kubeclient.Client
reconciler reconciler.Reconciler
updated chan string

log.Logger
}

type Opts struct {
Expand All @@ -55,7 +57,7 @@ func (s *Controller) Poll(ctx context.Context, syncInterval time.Duration) error
for _, c := range s.resourceNames {
s.updated <- c
}
log.Printf("Enqueued %d resources. Next sync in %v seconds.", len(s.resourceNames), syncInterval.Seconds())
s.Infof("Enqueued %d resources. Next sync in %v seconds.", len(s.resourceNames), syncInterval.Seconds())
select {
case <-time.After(syncInterval):
case <-ctx.Done():
Expand Down
1 change: 0 additions & 1 deletion pkg/controller/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,3 @@ func (s *StringSlice) Set(value string) error {
*s = append(*s, value)
return nil
}

31 changes: 23 additions & 8 deletions pkg/controller/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import (
"context"
"crypto/tls"
"fmt"
"log"
"net"
"net/http"
"os"
"sync"
"time"

"github.com/mumoshu/crossover/pkg/kubeclient"
"github.com/mumoshu/crossover/pkg/log"
"github.com/mumoshu/crossover/pkg/reconciler"
)

Expand All @@ -29,11 +30,15 @@ type Manager struct {
TrafficSplits StringSlice

SMITrafficSplitVersion string

log.Logger
}

func (m *Manager) Run(ctx context.Context) error {
controllers := []*Controller{}

logger := m.Logger

cmclient := &kubeclient.KubeClient{
Resource: "configmaps",
GroupVersion: "api/v1",
Expand Down Expand Up @@ -63,8 +68,10 @@ func (m *Manager) Run(ctx context.Context) error {
Client: cmclient,
Namespace: m.Namespace,
OutputDir: m.OutputDir,
Logger: logger,
},
resourceNames: genConfigs,
Logger: logger,
}

if m.SMIEnabled {
Expand All @@ -81,6 +88,7 @@ func (m *Manager) Run(ctx context.Context) error {
Server: m.Server,
Token: m.Token,
HttpClient: createHttpClient(m.Insecure),
Logger: logger,
}
trafficsplits := &Controller{
updated: make(chan string),
Expand All @@ -89,10 +97,12 @@ func (m *Manager) Run(ctx context.Context) error {
reconciler: &reconciler.TrafficSplitReconciler{
TrafficSplits: tsclient,
ConfigMaps: cmclient,
TsToConfigs: tsToConfigs,
TsToConfigs: tsToConfigs,
Namespace: m.Namespace,
Logger: logger,
},
resourceNames: m.TrafficSplits,
Logger: logger,
}

// trafficsplits controller needs to be before configmaps controller
Expand All @@ -111,7 +121,7 @@ func (m *Manager) Run(ctx context.Context) error {
return nil
}

log.Println("Starting crossover...")
logger.Infof("Starting crossover...")

var wg sync.WaitGroup

Expand All @@ -121,7 +131,7 @@ func (m *Manager) Run(ctx context.Context) error {
go func() {
defer wg.Done()
if err := c.Poll(ctx, m.SyncInterval); err != nil {
log.Fatalf("%v", err)
m.fatalf("%v", err)
}
}()
}
Expand All @@ -133,9 +143,9 @@ func (m *Manager) Run(ctx context.Context) error {
go func() {
defer wg.Done()
if err := c.Watch(ctx); err != nil {
log.Fatalf("Watch stopped due to error: %v", err)
m.fatalf("Watch stopped due to error: %v", err)
}
log.Printf("Watch stopped normally.")
logger.Infof("Watch stopped normally.")
}()
}
}
Expand All @@ -146,9 +156,9 @@ func (m *Manager) Run(ctx context.Context) error {
go func() {
defer wg.Done()
if err := c.Run(ctx); err != nil {
log.Fatalf("Run loop stopped due to error: %v", err)
m.fatalf("Run loop stopped due to error: %v", err)
}
log.Printf("Run loop stopped normally.")
logger.Infof("Run loop stopped normally.")
}()
}

Expand All @@ -157,6 +167,11 @@ func (m *Manager) Run(ctx context.Context) error {
return nil
}

func (m *Manager) fatalf(f string, args ...interface{}) {
m.Errorf(f, args...)
os.Exit(1)
}

func createHttpClient(insecure bool) *http.Client {
transport := &http.Transport{
Proxy: http.ProxyFromEnvironment,
Expand Down
36 changes: 19 additions & 17 deletions pkg/kubeclient/kubeclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"time"

"github.com/mumoshu/crossover/pkg/log"
"github.com/mumoshu/crossover/pkg/types"
)

Expand All @@ -32,6 +32,8 @@ type KubeClient struct {
// api/v1 for configmaps, apis/split.smi-spec.io/v1alpha2 for trafficsplits
GroupVersion string
HttpClient *http.Client

log.Logger
}

var _ ReadOnlyClient = &KubeClient{}
Expand All @@ -58,7 +60,7 @@ func (tp *KubeClient) Get(namespace, name string, obj interface{}) error {
resp.Body.Close()

if resp.StatusCode == 404 {
log.Printf("Get %s/%s: %s", namespace, name, data)
tp.Errorf("Get %s/%s: %s", namespace, name, data)
return types.ErrNotExist
}

Expand Down Expand Up @@ -87,61 +89,61 @@ WATCHES:
go func() {
defer close(names)

log.Printf("Watch starting...")
tp.Infof("Watch starting...")

req, err := http.NewRequest("GET", u, nil)
if err != nil {
log.Printf("Watch failed: %v", fmt.Errorf("http get request creation: %v", err))
tp.Infof("Watch failed: %v", fmt.Errorf("http get request creation: %v", err))
return
}
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tp.Token))

resp, err := client.Do(req)
if err != nil {
log.Printf("Watch failed: %v", fmt.Errorf("http get: %v", err))
tp.Infof("Watch failed: %v", fmt.Errorf("http get: %v", err))
return
}

scanner := bufio.NewScanner(resp.Body)

// Read chunks until error or stop
for names != nil && scanner.Scan() {
log.Printf("Watch reading next chunk...")
for names != nil && scanner.Scan() {
tp.Infof("Watch reading next chunk...")
evt := map[string]interface{}{}
body := scanner.Bytes()
if err := json.Unmarshal(body, &evt); err != nil {
log.Printf("Watch failed: %s: parsing %s: %v", u, body, err)
tp.Infof("Watch failed: %s: parsing %s: %v", u, body, err)
return
}
names <- name
}

log.Printf("Sent all chunks.")
tp.Infof("Sent all chunks.")
}()

CHUNK_READS:
for {
select {
case <-ctx.Done():
names = nil
log.Printf("Watch cancelled.")
tp.Infof("Watch cancelled.")
break WATCHES
case name, ok := <-names:
if !ok {
log.Printf("Watch read all chunks.")
tp.Infof("Watch read all chunks.")
break CHUNK_READS
}
log.Printf("Enqueing %s", name)
tp.Infof("Enqueing %s", name)
updated <- name
}
}

// Prevent busy loop
log.Printf("Watch stopped. Retrying in %s", backoff)
tp.Infof("Watch stopped. Retrying in %s", backoff)
time.Sleep(backoff)
}

log.Printf("Watch canceled")
tp.Infof("Watch canceled")

return nil
}
Expand Down Expand Up @@ -174,7 +176,7 @@ func (tp *KubeClient) Create(namespace string, obj interface{}) error {
resp.Body.Close()

if resp.StatusCode == 404 {
log.Printf("Create %s/%s: %s", namespace, tp.Resource, body)
tp.Errorf("Create %s/%s: %s", namespace, tp.Resource, body)
return types.ErrNotExist
}

Expand Down Expand Up @@ -213,14 +215,14 @@ func (tp *KubeClient) Replace(namespace, name string, obj interface{}) error {
resp.Body.Close()

if resp.StatusCode == 404 {
log.Printf("Replace %s/%s: %s", namespace, tp.Resource, body)
tp.Errorf("Replace %s/%s: %s", namespace, tp.Resource, body)
return types.ErrNotExist
}

// 409 CONFLICT here mean that another crossover sidecar has successfully updated the resource i.e. the configmap
// is already up-to-date, that we don't need to retry it now.
if resp.StatusCode == 409 {
log.Printf("Replace %s/%s: %s", namespace, tp.Resource, body)
tp.Infof("Replace %s/%s: %s", namespace, tp.Resource, body)
return nil
}

Expand Down
11 changes: 11 additions & 0 deletions pkg/log/logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package log

// Logger is the logging interface for Crossover
//
// Inspired from, even though the implementation here doesn't completely match the idea explained in:
// - https://dave.cheney.net/2017/01/23/the-package-level-logger-anti-pattern
// - https://dave.cheney.net/2015/11/05/lets-talk-about-logging
type Logger interface {
Infof(string, ...interface{})
Errorf(string, ...interface{})
}
30 changes: 30 additions & 0 deletions pkg/log/stdlogger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package log

import (
"log"
"os"
)

type stdLogger struct {
info, err *log.Logger
}

var StdLogger = NewStdLogger(
log.New(os.Stdout, "", log.LstdFlags),
log.New(os.Stderr, "", log.LstdFlags),
)

func NewStdLogger(info, err *log.Logger) *stdLogger {
return &stdLogger{
info: info,
err: err,
}
}

func (l *stdLogger) Infof(f string, args ...interface{}) {
l.info.Printf(f, args...)
}

func (l *stdLogger) Errorf(f string, args ...interface{}) {
l.err.Printf(f, args...)
}
Loading