Use official logr rather than thockin

This commit is contained in:
Tim Hockin 2019-03-22 09:11:22 -07:00
parent 076076dd9f
commit 831eae8f9f
13 changed files with 352 additions and 198 deletions

View File

@ -37,10 +37,9 @@ import (
"strings" "strings"
"time" "time"
"github.com/go-logr/glogr"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/thockin/glogr"
"github.com/thockin/logr"
) )
var flRepo = flag.String("repo", envString("GIT_SYNC_REPO", ""), var flRepo = flag.String("repo", envString("GIT_SYNC_REPO", ""),
@ -105,7 +104,7 @@ var flHTTPMetrics = flag.Bool("http-metrics", envBool("GIT_SYNC_HTTP_METRICS", t
var flHTTPprof = flag.Bool("http-pprof", envBool("GIT_SYNC_HTTP_PPROF", false), var flHTTPprof = flag.Bool("http-pprof", envBool("GIT_SYNC_HTTP_PPROF", false),
"enable the pprof debug endpoints on git-sync's HTTP endpoint") "enable the pprof debug endpoints on git-sync's HTTP endpoint")
var log = newLoggerOrDie() var log = glogr.New()
// Total pull/error, summary on pull duration // Total pull/error, summary on pull duration
var ( var (
@ -126,15 +125,6 @@ func init() {
prometheus.MustRegister(syncCount) prometheus.MustRegister(syncCount)
} }
func newLoggerOrDie() logr.Logger {
g, err := glogr.New()
if err != nil {
fmt.Fprintf(os.Stderr, "failind to initialize logging: %v\n", err)
os.Exit(1)
}
return g
}
func envString(key, def string) string { func envString(key, def string) string {
if env := os.Getenv(key); env != "" { if env := os.Getenv(key); env != "" {
return env return env
@ -158,7 +148,7 @@ func envInt(key string, def int) int {
if env := os.Getenv(key); env != "" { if env := os.Getenv(key); env != "" {
val, err := strconv.Atoi(env) val, err := strconv.Atoi(env)
if err != nil { if err != nil {
log.Errorf("invalid value for %q: using default: %v", key, def) log.Error(err, "invalid env value, using default", "key", key, "val", os.Getenv(key), "default", def)
return def return def
} }
return val return val
@ -170,7 +160,7 @@ func envFloat(key string, def float64) float64 {
if env := os.Getenv(key); env != "" { if env := os.Getenv(key); env != "" {
val, err := strconv.ParseFloat(env, 64) val, err := strconv.ParseFloat(env, 64)
if err != nil { if err != nil {
log.Errorf("invalid value for %q: using default: %v", key, def) log.Error(err, "invalid env value, using default", "key", key, "val", os.Getenv(key), "default", def)
return def return def
} }
return val return val
@ -182,7 +172,7 @@ func envDuration(key string, def time.Duration) time.Duration {
if env := os.Getenv(key); env != "" { if env := os.Getenv(key); env != "" {
val, err := time.ParseDuration(env) val, err := time.ParseDuration(env)
if err != nil { if err != nil {
log.Errorf("invalid value for %q: using default: %v", key, def) log.Error(err, "invalid env value, using default", "key", key, "val", os.Getenv(key), "default", def)
return def return def
} }
return val return val
@ -267,7 +257,7 @@ func main() {
} }
// From here on, output goes through logging. // From here on, output goes through logging.
log.V(0).Infof("starting up: %q", os.Args) log.V(0).Info("starting up", "args", os.Args)
// Startup webhooks goroutine // Startup webhooks goroutine
webhookTriggerChan := make(chan struct{}, 1) webhookTriggerChan := make(chan struct{}, 1)
@ -291,13 +281,13 @@ func main() {
syncDuration.WithLabelValues("error").Observe(time.Now().Sub(start).Seconds()) syncDuration.WithLabelValues("error").Observe(time.Now().Sub(start).Seconds())
syncCount.WithLabelValues("error").Inc() syncCount.WithLabelValues("error").Inc()
if initialSync || (*flMaxSyncFailures != -1 && failCount >= *flMaxSyncFailures) { if initialSync || (*flMaxSyncFailures != -1 && failCount >= *flMaxSyncFailures) {
log.Errorf("error syncing repo: %v", err) log.Error(err, "failed to sync repo, aborting")
os.Exit(1) os.Exit(1)
} }
failCount++ failCount++
log.Errorf("unexpected error syncing repo: %v", err) log.Error(err, "unexpected error syncing repo, will retry")
log.V(0).Infof("waiting %v before retrying", waitTime(*flWait)) log.V(0).Info("waiting before retrying", "waitTime", waitTime(*flWait))
cancel() cancel()
time.Sleep(waitTime(*flWait)) time.Sleep(waitTime(*flWait))
continue continue
@ -319,17 +309,17 @@ func main() {
os.Exit(0) os.Exit(0)
} }
if isHash, err := revIsHash(ctx, *flRev, *flRoot); err != nil { if isHash, err := revIsHash(ctx, *flRev, *flRoot); err != nil {
log.Errorf("can't tell if rev %s is a git hash, exiting", *flRev) log.Error(err, "can't tell if rev is a git hash, exiting", "rev", *flRev)
os.Exit(1) os.Exit(1)
} else if isHash { } else if isHash {
log.V(0).Infof("rev %s appears to be a git hash, no further sync needed", *flRev) log.V(0).Info("rev appears to be a git hash, no further sync needed", "rev", *flRev)
sleepForever() sleepForever()
} }
initialSync = false initialSync = false
} }
failCount = 0 failCount = 0
log.V(1).Infof("next sync in %v", waitTime(*flWait)) log.V(1).Info("next sync", "wait_time", waitTime(*flWait))
cancel() cancel()
time.Sleep(waitTime(*flWait)) time.Sleep(waitTime(*flWait))
} }
@ -361,7 +351,8 @@ func sleepForever() {
// updateSymlink atomically swaps the symlink to point at the specified directory and cleans up the previous worktree. // updateSymlink atomically swaps the symlink to point at the specified directory and cleans up the previous worktree.
func updateSymlink(ctx context.Context, gitRoot, link, newDir string) error { func updateSymlink(ctx context.Context, gitRoot, link, newDir string) error {
// Get currently-linked repo directory (to be removed), unless it doesn't exist // Get currently-linked repo directory (to be removed), unless it doesn't exist
currentDir, err := filepath.EvalSymlinks(path.Join(gitRoot, link)) fullpath := path.Join(gitRoot, link)
currentDir, err := filepath.EvalSymlinks(fullpath)
if err != nil && !os.IsNotExist(err) { if err != nil && !os.IsNotExist(err) {
return fmt.Errorf("error accessing symlink: %v", err) return fmt.Errorf("error accessing symlink: %v", err)
} }
@ -373,15 +364,16 @@ func updateSymlink(ctx context.Context, gitRoot, link, newDir string) error {
return fmt.Errorf("error converting to relative path: %v", err) return fmt.Errorf("error converting to relative path: %v", err)
} }
if _, err := runCommand(ctx, gitRoot, "ln", "-snf", newDirRelative, "tmp-link"); err != nil { const tmplink = "tmp-link"
if _, err := runCommand(ctx, gitRoot, "ln", "-snf", newDirRelative, tmplink); err != nil {
return fmt.Errorf("error creating symlink: %v", err) return fmt.Errorf("error creating symlink: %v", err)
} }
log.V(1).Infof("created symlink %s -> %s", "tmp-link", newDirRelative) log.V(1).Info("created tmp symlink", "root", gitRoot, "dst", newDirRelative, "src", tmplink)
if _, err := runCommand(ctx, gitRoot, "mv", "-T", "tmp-link", link); err != nil { if _, err := runCommand(ctx, gitRoot, "mv", "-T", tmplink, link); err != nil {
return fmt.Errorf("error replacing symlink: %v", err) return fmt.Errorf("error replacing symlink: %v", err)
} }
log.V(1).Infof("renamed symlink %s to %s", "tmp-link", link) log.V(1).Info("renamed symlink", "root", gitRoot, "old_name", tmplink, "new_name", link)
// Clean up previous worktree // Clean up previous worktree
if len(currentDir) > 0 { if len(currentDir) > 0 {
@ -389,14 +381,14 @@ func updateSymlink(ctx context.Context, gitRoot, link, newDir string) error {
return fmt.Errorf("error removing directory: %v", err) return fmt.Errorf("error removing directory: %v", err)
} }
log.V(1).Infof("removed %s", currentDir) log.V(1).Info("removed previous worktree", "path", currentDir)
_, err := runCommand(ctx, gitRoot, *flGitCmd, "worktree", "prune") _, err := runCommand(ctx, gitRoot, *flGitCmd, "worktree", "prune")
if err != nil { if err != nil {
return err return err
} }
log.V(1).Infof("pruned old worktrees") log.V(1).Info("pruned old worktrees")
} }
return nil return nil
@ -404,7 +396,7 @@ func updateSymlink(ctx context.Context, gitRoot, link, newDir string) error {
// addWorktreeAndSwap creates a new worktree and calls updateSymlink to swap the symlink to point to the new worktree // addWorktreeAndSwap creates a new worktree and calls updateSymlink to swap the symlink to point to the new worktree
func addWorktreeAndSwap(ctx context.Context, gitRoot, dest, branch, rev string, depth int, hash string) error { func addWorktreeAndSwap(ctx context.Context, gitRoot, dest, branch, rev string, depth int, hash string) error {
log.V(0).Infof("syncing to %s (%s)", rev, hash) log.V(0).Info("syncing git", "rev", rev, "hash", hash)
args := []string{"fetch", "--tags"} args := []string{"fetch", "--tags"}
if depth != 0 { if depth != 0 {
@ -428,7 +420,7 @@ func addWorktreeAndSwap(ctx context.Context, gitRoot, dest, branch, rev string,
if err != nil { if err != nil {
return err return err
} }
log.V(0).Infof("added worktree %s for origin/%s", worktreePath, branch) log.V(0).Info("added worktree", "path", worktreePath, "branch", fmt.Sprintf("origin/%s", branch))
// The .git file in the worktree directory holds a reference to // The .git file in the worktree directory holds a reference to
// /git/.git/worktrees/<worktree-dir-name>. Replace it with a reference // /git/.git/worktrees/<worktree-dir-name>. Replace it with a reference
@ -448,7 +440,7 @@ func addWorktreeAndSwap(ctx context.Context, gitRoot, dest, branch, rev string,
if err != nil { if err != nil {
return err return err
} }
log.V(0).Infof("reset worktree %s to %s", worktreePath, hash) log.V(0).Info("reset worktree to hash", "path", worktreePath, "hash", hash)
if *flChmod != 0 { if *flChmod != 0 {
// set file permissions // set file permissions
@ -471,7 +463,7 @@ func cloneRepo(ctx context.Context, repo, branch, rev string, depth int, gitRoot
if err != nil { if err != nil {
if strings.Contains(err.Error(), "already exists and is not an empty directory") { if strings.Contains(err.Error(), "already exists and is not an empty directory") {
// Maybe a previous run crashed? Git won't use this dir. // Maybe a previous run crashed? Git won't use this dir.
log.V(0).Infof("%s exists and is not empty (previous crash?), cleaning up", gitRoot) log.V(0).Info("git root exists and is not empty (previous crash?), cleaning up", "path", gitRoot)
err := os.RemoveAll(gitRoot) err := os.RemoveAll(gitRoot)
if err != nil { if err != nil {
return err return err
@ -484,7 +476,7 @@ func cloneRepo(ctx context.Context, repo, branch, rev string, depth int, gitRoot
return err return err
} }
} }
log.V(0).Infof("cloned %s", repo) log.V(0).Info("cloned repo", "origin", repo)
return nil return nil
} }
@ -533,15 +525,13 @@ func syncRepo(ctx context.Context, repo, branch, rev string, depth int, gitRoot,
if err != nil { if err != nil {
return false, err return false, err
} }
log.V(2).Infof("local hash: %s", local) log.V(2).Info("git state", "local", local, "remote", remote)
log.V(2).Infof("remote hash: %s", remote) if local == remote {
if local != remote { log.V(1).Info("no update required")
log.V(0).Infof("update required")
hash = remote
} else {
log.V(1).Infof("no update required")
return false, nil return false, nil
} }
log.V(0).Info("update required")
hash = remote
} }
return true, addWorktreeAndSwap(ctx, gitRoot, dest, branch, rev, depth, hash) return true, addWorktreeAndSwap(ctx, gitRoot, dest, branch, rev, depth, hash)
@ -594,7 +584,7 @@ func cmdForLog(command string, args ...string) string {
} }
func runCommand(ctx context.Context, cwd, command string, args ...string) (string, error) { func runCommand(ctx context.Context, cwd, command string, args ...string) (string, error) {
log.V(5).Infof("run(%q): %s", cwd, cmdForLog(command, args...)) log.V(5).Info("running command", "cwd", cwd, "cmd", cmdForLog(command, args...))
cmd := exec.CommandContext(ctx, command, args...) cmd := exec.CommandContext(ctx, command, args...)
if cwd != "" { if cwd != "" {
@ -603,6 +593,7 @@ func runCommand(ctx context.Context, cwd, command string, args ...string) (strin
output, err := cmd.CombinedOutput() output, err := cmd.CombinedOutput()
if ctx.Err() == context.DeadlineExceeded { if ctx.Err() == context.DeadlineExceeded {
return "", fmt.Errorf("command timed out: %v: %q", err, string(output)) return "", fmt.Errorf("command timed out: %v: %q", err, string(output))
} }
if err != nil { if err != nil {
return "", fmt.Errorf("error running command: %v: %q", err, string(output)) return "", fmt.Errorf("error running command: %v: %q", err, string(output))
@ -612,7 +603,7 @@ func runCommand(ctx context.Context, cwd, command string, args ...string) (strin
} }
func setupGitAuth(username, password, gitURL string) error { func setupGitAuth(username, password, gitURL string) error {
log.V(1).Infof("setting up the git credential cache") log.V(1).Info("setting up git credential cache")
cmd := exec.Command(*flGitCmd, "config", "--global", "credential.helper", "cache") cmd := exec.Command(*flGitCmd, "config", "--global", "credential.helper", "cache")
output, err := cmd.CombinedOutput() output, err := cmd.CombinedOutput()
if err != nil { if err != nil {
@ -636,20 +627,20 @@ func setupGitAuth(username, password, gitURL string) error {
} }
func setupGitSSH(setupKnownHosts bool) error { func setupGitSSH(setupKnownHosts bool) error {
log.V(1).Infof("setting up git SSH credentials") log.V(1).Info("setting up git SSH credentials")
var pathToSSHSecret = *flSSHKeyFile var pathToSSHSecret = *flSSHKeyFile
var pathToSSHKnownHosts = *flSSHKnownHostsFile var pathToSSHKnownHosts = *flSSHKnownHostsFile
_, err := os.Stat(pathToSSHSecret) _, err := os.Stat(pathToSSHSecret)
if err != nil { if err != nil {
return fmt.Errorf("error: could not find SSH key Secret: %v", err) return fmt.Errorf("error: could not access SSH key Secret: %v", err)
} }
if setupKnownHosts { if setupKnownHosts {
_, err := os.Stat(pathToSSHKnownHosts) _, err := os.Stat(pathToSSHKnownHosts)
if err != nil { if err != nil {
return fmt.Errorf("error: could not find SSH known_hosts file: %v", err) return fmt.Errorf("error: could not access SSH known_hosts file: %v", err)
} }
err = os.Setenv("GIT_SSH_COMMAND", fmt.Sprintf("ssh -q -o UserKnownHostsFile=%s -i %s", pathToSSHKnownHosts, pathToSSHSecret)) err = os.Setenv("GIT_SSH_COMMAND", fmt.Sprintf("ssh -q -o UserKnownHostsFile=%s -i %s", pathToSSHKnownHosts, pathToSSHSecret))
@ -666,13 +657,13 @@ func setupGitSSH(setupKnownHosts bool) error {
} }
func setupGitCookieFile() error { func setupGitCookieFile() error {
log.V(1).Infof("configuring git cookie file") log.V(1).Info("configuring git cookie file")
var pathToCookieFile = "/etc/git-secret/cookie_file" var pathToCookieFile = "/etc/git-secret/cookie_file"
_, err := os.Stat(pathToCookieFile) _, err := os.Stat(pathToCookieFile)
if err != nil { if err != nil {
return fmt.Errorf("error: could not find git cookie file: %v", err) return fmt.Errorf("error: could not access git cookie file: %v", err)
} }
cmd := exec.Command(*flGitCmd, "config", "--global", "http.cookiefile", pathToCookieFile) cmd := exec.Command(*flGitCmd, "config", "--global", "http.cookiefile", pathToCookieFile)

View File

@ -54,10 +54,10 @@ func (w *Webhook) run(ch chan struct{}) {
for { for {
if err := w.Do(); err != nil { if err := w.Do(); err != nil {
log.Errorf("error calling webhook %v: %v", w.URL, err) log.Error(err, "error calling webhook", "url", w.URL)
time.Sleep(w.Backoff) time.Sleep(w.Backoff)
} else { } else {
log.V(0).Infof("calling webhook %v was: OK\n", w.URL) log.V(0).Info("success calling webhook", "url", w.URL)
break break
} }
} }

3
go.mod
View File

@ -1,9 +1,8 @@
module k8s.io/git-sync module k8s.io/git-sync
require ( require (
github.com/go-logr/glogr v0.1.0
github.com/go-logr/logr v0.1.0 // indirect github.com/go-logr/logr v0.1.0 // indirect
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
github.com/prometheus/client_golang v0.9.2 github.com/prometheus/client_golang v0.9.2
github.com/thockin/glogr v0.0.0-20160825042232-7a7f3ced4f9f
github.com/thockin/logr v0.0.0-20160822044224-103d90809f34
) )

11
go.sum
View File

@ -1,9 +1,7 @@
-github.com/thockin/glogr v0.0.0-20160825042232-7a7f3ced4f9f h1:UQ/VqTtxN8EoIShWVbNR9b0/vyxKLwhV6ZGcIjZ5KB4=
-github.com/thockin/glogr v0.0.0-20160825042232-7a7f3ced4f9f/go.mod h1:HRvPbLXOCiSU8hpsTlLSX4Fw6l+yF2uziElIkThrlsI=
-github.com/thockin/logr v0.0.0-20160822044224-103d90809f34 h1:iVWjMSZyeDCd1D2XQkUjsAWPfvA3M4aPGGsEmxaXY1s=
-github.com/thockin/logr v0.0.0-20160822044224-103d90809f34/go.mod h1:GEqn6NzwaoUO+OS+z1oR6Ka9NXmRDe3NUF5KZUAoT+I=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/go-logr/glogr v0.1.0 h1:5W02LkUIi+DaBwtWKYGxoX9gqVMo6i9ehwkhorjcP74=
github.com/go-logr/glogr v0.1.0/go.mod h1:GDQ2+z9PAAX7+qBhL3FzAL2Nf8dxyliu0ppgJIX7YhU=
github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg= github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
@ -20,9 +18,6 @@ github.com/prometheus/common v0.0.0-20181126121408-4724e9255275 h1:PnBWHBf+6L0jO
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/thockin/glogr v0.0.0-20160825042232-7a7f3ced4f9f h1:UQ/VqTtxN8EoIShWVbNR9b0/vyxKLwhV6ZGcIjZ5KB4=
github.com/thockin/glogr v0.0.0-20160825042232-7a7f3ced4f9f/go.mod h1:HRvPbLXOCiSU8hpsTlLSX4Fw6l+yF2uziElIkThrlsI=
github.com/thockin/logr v0.0.0-20160822044224-103d90809f34 h1:iVWjMSZyeDCd1D2XQkUjsAWPfvA3M4aPGGsEmxaXY1s=
github.com/thockin/logr v0.0.0-20160822044224-103d90809f34/go.mod h1:GEqn6NzwaoUO+OS+z1oR6Ka9NXmRDe3NUF5KZUAoT+I=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=

152
vendor/github.com/go-logr/glogr/glogr.go generated vendored Normal file
View File

@ -0,0 +1,152 @@
// Package glogr implements github.com/thockin/logr.Logger in terms of
// github.com/golang/glog.
package glogr
import (
"bytes"
"encoding/json"
"fmt"
"runtime"
"sort"
"github.com/go-logr/logr"
"github.com/golang/glog"
)
// New returns a logr.Logger which is implemented by glog.
func New() logr.Logger {
return glogger{
level: 0,
prefix: "",
values: nil,
}
}
type glogger struct {
level int
prefix string
values []interface{}
}
func (l glogger) clone() glogger {
return glogger{
level: l.level,
prefix: l.prefix,
values: copySlice(l.values),
}
}
func copySlice(in []interface{}) []interface{} {
out := make([]interface{}, len(in))
copy(out, in)
return out
}
// Magic string for intermediate frames that we should ignore.
const autogeneratedFrameName = "<autogenerated>"
// Discover how many frames we need to climb to find the caller. This approach
// was suggested by Ian Lance Taylor of the Go team, so it *should* be safe
// enough (famous last words).
func framesToCaller() int {
// 1 is the immediate caller. 3 should be too many.
for i := 1; i < 3; i++ {
_, file, _, _ := runtime.Caller(i + 1) // +1 for this function's frame
if file != autogeneratedFrameName {
return i
}
}
return 1 // something went wrong, this is safe
}
type kvPair struct {
key string
val interface{}
}
func flatten(kvList ...interface{}) string {
keys := make([]string, 0, len(kvList))
vals := make(map[string]interface{}, len(kvList))
for i := 0; i < len(kvList); i += 2 {
k, ok := kvList[i].(string)
if !ok {
panic(fmt.Sprintf("key is not a string: %s", pretty(kvList[i])))
}
var v interface{}
if i+1 < len(kvList) {
v = kvList[i+1]
}
keys = append(keys, k)
vals[k] = v
}
sort.Strings(keys)
buf := bytes.Buffer{}
for i, k := range keys {
v := vals[k]
if i > 0 {
buf.WriteRune(' ')
}
buf.WriteString(pretty(k))
buf.WriteString("=")
buf.WriteString(pretty(v))
}
return buf.String()
}
func pretty(value interface{}) string {
jb, _ := json.Marshal(value)
return string(jb)
}
func (l glogger) Info(msg string, kvList ...interface{}) {
if l.Enabled() {
lvlStr := flatten("level", l.level)
msgStr := flatten("msg", msg)
fixedStr := flatten(l.values...)
userStr := flatten(kvList...)
glog.InfoDepth(framesToCaller(), l.prefix, " ", lvlStr, " ", msgStr, " ", fixedStr, " ", userStr)
}
}
func (l glogger) Enabled() bool {
return bool(glog.V(glog.Level(l.level)))
}
func (l glogger) Error(err error, msg string, kvList ...interface{}) {
msgStr := flatten("msg", msg)
var loggableErr interface{}
if err != nil {
loggableErr = err.Error()
}
errStr := flatten("error", loggableErr)
fixedStr := flatten(l.values...)
userStr := flatten(kvList...)
glog.ErrorDepth(framesToCaller(), l.prefix, " ", msgStr, " ", errStr, " ", fixedStr, " ", userStr)
}
func (l glogger) V(level int) logr.InfoLogger {
new := l.clone()
new.level = level
return new
}
// WithName returns a new logr.Logger with the specified name appended. glogr
// uses '/' characters to separate name elements. Callers should not pass '/'
// in the provided name string, but this library does not actually enforce that.
func (l glogger) WithName(name string) logr.Logger {
new := l.clone()
if len(l.prefix) > 0 {
new.prefix = l.prefix + "/"
}
new.prefix += name
return new
}
func (l glogger) WithValues(kvList ...interface{}) logr.Logger {
new := l.clone()
new.values = append(new.values, kvList...)
return new
}
var _ logr.Logger = glogger{}
var _ logr.InfoLogger = glogger{}

151
vendor/github.com/go-logr/logr/logr.go generated vendored Normal file
View File

@ -0,0 +1,151 @@
// Package logr defines abstract interfaces for logging. Packages can depend on
// these interfaces and callers can implement logging in whatever way is
// appropriate.
//
// This design derives from Dave Cheney's blog:
// http://dave.cheney.net/2015/11/05/lets-talk-about-logging
//
// This is a BETA grade API. Until there is a significant 2nd implementation,
// I don't really know how it will change.
//
// The logging specifically makes it non-trivial to use format strings, to encourage
// attaching structured information instead of unstructured format strings.
//
// Usage
//
// Logging is done using a Logger. Loggers can have name prefixes and named values
// attached, so that all log messages logged with that Logger have some base context
// associated.
//
// The term "key" is used to refer to the name associated with a particular value, to
// disambiguate it from the general Logger name.
//
// For instance, suppose we're trying to reconcile the state of an object, and we want
// to log that we've made some decision.
//
// With the traditional log package, we might write
// log.Printf(
// "decided to set field foo to value %q for object %s/%s",
// targetValue, object.Namespace, object.Name)
//
// With logr's structured logging, we'd write
// // elsewhere in the file, set up the logger to log with the prefix of "reconcilers",
// // and the named value target-type=Foo, for extra context.
// log := mainLogger.WithName("reconcilers").WithValues("target-type", "Foo")
//
// // later on...
// log.Info("setting field foo on object", "value", targetValue, "object", object)
//
// Depending on our logging implementation, we could then make logging decisions based on field values
// (like only logging such events for objects in a certain namespace), or copy the structured
// information into a structured log store.
//
// For logging errors, Logger has a method called Error. Suppose we wanted to log an
// error while reconciling. With the traditional log package, we might write
// log.Errorf("unable to reconcile object %s/%s: %v", object.Namespace, object.Name, err)
//
// With logr, we'd instead write
// // assuming the above setup for log
// log.Error(err, "unable to reconcile object", "object", object)
//
// This functions similarly to:
// log.Info("unable to reconcile object", "error", err, "object", object)
//
// However, it ensures that a standard key for the error value ("error") is used across all
// error logging. Furthermore, certain implementations may choose to attach additional
// information (such as stack traces) on calls to Error, so it's preferred to use Error
// to log errors.
//
// Parts of a log line
//
// Each log message from a Logger has four types of context:
// logger name, log verbosity, log message, and the named values.
//
// The Logger name constists of a series of name "segments" added by successive calls to WithName.
// These name segments will be joined in some way by the underlying implementation. It is strongly
// reccomended that name segements contain simple identifiers (letters, digits, and hyphen), and do
// not contain characters that could muddle the log output or confuse the joining operation (e.g.
// whitespace, commas, periods, slashes, brackets, quotes, etc).
//
// Log verbosity represents how little a log matters. Level zero, the default, matters most.
// Increasing levels matter less and less. Try to avoid lots of different verbosity levels,
// and instead provide useful keys, logger names, and log messages for users to filter on.
// It's illegal to pass a log level below zero.
//
// The log message consists of a constant message attached to the the log line. This
// should generally be a simple description of what's occuring, and should never be a format string.
//
// Variable information can then be attached using named values (key/value pairs). Keys are arbitrary
// strings, while values may be any Go value.
//
// Key Naming Conventions
//
// While users are generally free to use key names of their choice, it's generally best to avoid
// using the following keys, as they're frequently used by implementations:
//
// - `"error"`: the underlying error value in the `Error` method.
// - `"stacktrace"`: the stack trace associated with a particular log line or error
// (often from the `Error` message).
// - `"caller"`: the calling information (file/line) of a particular log line.
// - `"msg"`: the log message.
// - `"level"`: the log level.
// - `"ts"`: the timestamp for a log line.
//
// Implementations are encouraged to make use of these keys to represent the above
// concepts, when neccessary (for example, in a pure-JSON output form, it would be
// necessary to represent at least message and timestamp as ordinary named values).
package logr
// TODO: consider adding back in format strings if they're really needed
// TODO: consider other bits of zap/zapcore functionality like ObjectMarshaller (for arbitrary objects)
// TODO: consider other bits of glog functionality like Flush, InfoDepth, OutputStats
// InfoLogger represents the ability to log non-error messages, at a particular verbosity.
type InfoLogger interface {
// Info logs a non-error message with the given key/value pairs as context.
//
// The msg argument should be used to add some constant description to
// the log line. The key/value pairs can then be used to add additional
// variable information. The key/value pairs should alternate string
// keys and arbitrary values.
Info(msg string, keysAndValues ...interface{})
// Enabled tests whether this InfoLogger is enabled. For example,
// commandline flags might be used to set the logging verbosity and disable
// some info logs.
Enabled() bool
}
// Logger represents the ability to log messages, both errors and not.
type Logger interface {
// All Loggers implement InfoLogger. Calling InfoLogger methods directly on
// a Logger value is equivalent to calling them on a V(0) InfoLogger. For
// example, logger.Info() produces the same result as logger.V(0).Info.
InfoLogger
// Error logs an error, with the given message and key/value pairs as context.
// It functions similarly to calling Info with the "error" named value, but may
// have unique behavior, and should be preferred for logging errors (see the
// package documentations for more information).
//
// The msg field should be used to add context to any underlying error,
// while the err field should be used to attach the actual error that
// triggered this log line, if present.
Error(err error, msg string, keysAndValues ...interface{})
// V returns an InfoLogger value for a specific verbosity level. A higher
// verbosity level means a log message is less important. It's illegal to
// pass a log level less than zero.
V(level int) InfoLogger
// WithValues adds some key-value pairs of context to a logger.
// See Info for documentation on how key/value pairs work.
WithValues(keysAndValues ...interface{}) Logger
// WithName adds a new element to the logger's name.
// Successive calls with WithName continue to append
// suffixes to the logger's name. It's strongly reccomended
// that name segments contain only letters, digits, and hyphens
// (see the package documentation for more information).
WithName(name string) Logger
}

View File

@ -1,86 +0,0 @@
// Package glogr implements github.com/thockin/logr.Logger in terms of
// github.com/golang/glog.
package glogr
import (
"fmt"
"runtime"
"github.com/golang/glog"
"github.com/thockin/logr"
)
// New returns a logr.Logger which is implemented by glog.
func New() (logr.Logger, error) {
return glogger{
level: 0,
prefix: "",
}, nil
}
type glogger struct {
level int
prefix string
}
func prepend(prefix interface{}, args []interface{}) []interface{} {
return append([]interface{}{prefix}, args...)
}
// Magic string for intermediate frames that we should ignore.
const autogeneratedFrameName = "<autogenerated>"
// Discover how many frames we need to climb to find the caller. This approach
// was suggested by Ian Lance Taylor of the Go team, so it *should* be safe
// enough (famous last words).
func framesToCaller() int {
// 1 is the immediate caller. 3 should be too many.
for i := 1; i < 3; i++ {
_, file, _, _ := runtime.Caller(i + 1) // +1 for this function's frame
if file != autogeneratedFrameName {
return i
}
}
return 1 // something went wrong, this is safe
}
func (l glogger) Info(args ...interface{}) {
if l.Enabled() {
glog.InfoDepth(framesToCaller(), prepend(l.prefix, args)...)
}
}
func (l glogger) Infof(format string, args ...interface{}) {
if l.Enabled() {
glog.InfoDepth(framesToCaller(), fmt.Sprintf("%s"+format, prepend(l.prefix, args)...))
}
}
func (l glogger) Enabled() bool {
return bool(glog.V(glog.Level(l.level)))
}
func (l glogger) Error(args ...interface{}) {
glog.ErrorDepth(framesToCaller(), prepend(l.prefix, args)...)
}
func (l glogger) Errorf(format string, args ...interface{}) {
glog.ErrorDepth(framesToCaller(), fmt.Sprintf("%s"+format, prepend(l.prefix, args)...))
}
func (l glogger) V(level int) logr.InfoLogger {
return glogger{
level: level,
prefix: l.prefix,
}
}
func (l glogger) NewWithPrefix(prefix string) logr.Logger {
return glogger{
level: l.level,
prefix: prefix,
}
}
var _ logr.Logger = glogger{}
var _ logr.InfoLogger = glogger{}

View File

@ -1,48 +0,0 @@
// Package logr defines abstract interfaces for logging. Packages can depend on
// these interfaces and callers can implement logging in whatever way is
// appropriate.
//
// This design derives from Dave Cheney's blog:
// http://dave.cheney.net/2015/11/05/lets-talk-about-logging
//
// This is a BETA grade API. Until there is a significant 2nd implementation,
// I don't really know how it will change.
package logr
// TODO: consider structured logging, a la uber-go/zap
// TODO: consider other bits of glog functionality like Flush, InfoDepth, OutputStats
// InfoLogger represents the ability to log non-error messages.
type InfoLogger interface {
// Info logs a non-error message. This is behaviorally akin to fmt.Print.
Info(args ...interface{})
// Infof logs a formatted non-error message.
Infof(format string, args ...interface{})
// Enabled test whether this InfoLogger is enabled. For example,
// commandline flags might be used to set the logging verbosity and disable
// some info logs.
Enabled() bool
}
// Logger represents the ability to log messages, both errors and not.
type Logger interface {
// All Loggers implement InfoLogger. Calling InfoLogger methods directly on
// a Logger value is equivalent to calling them on a V(0) InfoLogger. For
// example, logger.Info() produces the same result as logger.V(0).Info.
InfoLogger
// Error logs a error message. This is behaviorally akin to fmt.Print.
Error(args ...interface{})
// Errorf logs a formatted error message.
Errorf(format string, args ...interface{})
// V returns an InfoLogger value for a specific verbosity level. A higher
// verbosity level means a log message is less important.
V(level int) InfoLogger
// NewWithPrefix returns a Logger which prefixes all messages.
NewWithPrefix(prefix string) Logger
}

8
vendor/modules.txt vendored
View File

@ -1,5 +1,9 @@
# github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 # github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973
github.com/beorn7/perks/quantile github.com/beorn7/perks/quantile
# github.com/go-logr/glogr v0.1.0
github.com/go-logr/glogr
# github.com/go-logr/logr v0.1.0
github.com/go-logr/logr
# github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b # github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/golang/glog github.com/golang/glog
# github.com/golang/protobuf v1.2.0 # github.com/golang/protobuf v1.2.0
@ -21,7 +25,3 @@ github.com/prometheus/procfs
github.com/prometheus/procfs/nfs github.com/prometheus/procfs/nfs
github.com/prometheus/procfs/xfs github.com/prometheus/procfs/xfs
github.com/prometheus/procfs/internal/util github.com/prometheus/procfs/internal/util
# github.com/thockin/glogr v0.0.0-20160825042232-7a7f3ced4f9f
github.com/thockin/glogr
# github.com/thockin/logr v0.0.0-20160822044224-103d90809f34
github.com/thockin/logr