diff --git a/README.md b/README.md index 9130462a..200afccd 100644 --- a/README.md +++ b/README.md @@ -141,10 +141,11 @@ K9s uses aliases to navigate most K8s resources. ## Known Issues -This initial drop is brittle. K9s will most likely blow up if... +This initial drop is brittle. K9s will most likely blow up... +1. You're running older versions of Kubernetes. K9s works best Kubernetes 1.10+ 1. You don't have enough RBAC fu to manage your cluster -2. Your cluster does not run a metric server. +1. Your cluster does not run a metric server. --- diff --git a/change_logs/release_0.2.2.md b/change_logs/release_0.2.2.md new file mode 100644 index 00000000..dea4edb7 --- /dev/null +++ b/change_logs/release_0.2.2.md @@ -0,0 +1,26 @@ +# Release v0.2.2 + +## Notes + +Thank you to all that contributed with flushing out issues with K9s! I'll try +to mark some of these issues as fixed. But if you don't mind grab the latest +rev and see if we're happier with some of the fixes! + +If you've filed an issue please help me verify and close. + +Thank you so much for your support!! + +--- + +## Change Logs + ++ [Feature #98](https://github.com/derailed/k9s/issues/98) Pod view with node name. ++ [Feature #29](https://github.com/derailed/k9s/issues/29) Support ANSI colors in logs. ++ [Feature #105](https://github.com/derailed/k9s/issues/29) [Experimental] Add support for manual refresh. + +--- + +## Resolved Bugs + ++ [Issue #102](https://github.com/derailed/k9s/issues/102) ++ [Issue #104](https://github.com/derailed/k9s/issues/104) \ No newline at end of file diff --git a/go.mod b/go.mod index 5bbb795c..84a15244 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,8 @@ require ( github.com/onsi/gomega v1.4.3 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/petergtz/pegomock v0.0.0-20181206220228-b113d17a7e81 - github.com/sirupsen/logrus v1.3.0 + github.com/rs/zerolog v1.12.0 + github.com/sirupsen/logrus v1.3.0 // indirect github.com/spf13/cobra v0.0.3 github.com/spf13/pflag v1.0.3 // indirect github.com/stretchr/testify v1.2.2 diff --git a/go.sum b/go.sum index c70b00bb..0ac9bd2b 100644 --- a/go.sum +++ b/go.sum @@ -98,6 +98,8 @@ github.com/prometheus/common v0.0.0-20181218105931-67670fe90761/go.mod h1:daVV7q github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/rivo/tview v0.0.0-20190213202703-b373355e9db4/go.mod h1:J4W+hErFfITUbyFAEXizpmkuxX7ZN56dopxHB4XQhMw= +github.com/rs/zerolog v1.12.0 h1:aqZ1XRadoS8IBknR5IDFvGzbHly1X9ApIqOroooQF/c= +github.com/rs/zerolog v1.12.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME= github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= diff --git a/internal/cmd/root.go b/internal/cmd/root.go index 06799731..85b9e426 100644 --- a/internal/cmd/root.go +++ b/internal/cmd/root.go @@ -7,7 +7,8 @@ import ( "github.com/derailed/k9s/internal/config" "github.com/derailed/k9s/internal/k8s" "github.com/derailed/k9s/internal/views" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" ) @@ -55,7 +56,7 @@ func init() { } func initK9s() { - log.Info("🐶 K9s starting up...") + log.Info().Msg("🐶 K9s starting up...") // Load K9s config file... cfg := k8s.NewConfig(k8sFlags) @@ -64,14 +65,14 @@ func initK9s() { // Init K8s connection... k8s.InitConnectionOrDie(cfg) - log.Info("✅ Kubernetes connectivity") + log.Info().Msg("✅ Kubernetes connectivity") config.Root.Save() } func initK9sConfig() { if err := config.Root.Load(config.K9sConfigFile); err != nil { - log.Warnf("Unable to locate K9s config. Generating new configuration...") + log.Warn().Msg("Unable to locate K9s config. Generating new configuration...") } config.Root.K9s.RefreshRate = refreshRate @@ -93,7 +94,7 @@ func initK9sConfig() { config.Root.SetActiveNamespace(cfg.Contexts[ctx].Namespace) } } - log.Debugf("Active Context `%v`", ctx) + log.Debug().Msgf("Active Context `%v`", ctx) if isSet(k8sFlags.Namespace) { config.Root.SetActiveNamespace(*k8sFlags.Namespace) @@ -120,16 +121,27 @@ func isSet(s *string) bool { // Execute root command func Execute() { if err := rootCmd.Execute(); err != nil { - log.Panic(err) + log.Panic().Err(err) + } +} + +func parseLevel(level string) zerolog.Level { + switch level { + case "debug": + return zerolog.DebugLevel + case "warn": + return zerolog.WarnLevel + case "error": + return zerolog.ErrorLevel + case "fatal": + return zerolog.FatalLevel + default: + return zerolog.InfoLevel } } func run(cmd *cobra.Command, args []string) { - level, err := log.ParseLevel(logLevel) - if err != nil { - level = log.DebugLevel - } - log.SetLevel(level) + zerolog.SetGlobalLevel(parseLevel(logLevel)) initK9s() @@ -140,7 +152,7 @@ func run(cmd *cobra.Command, args []string) { clearScreen() if err := recover(); err != nil { app.Stop() - fmt.Println(err) + log.Error().Msgf("Boom! %#v", err) debug.PrintStack() } }() diff --git a/internal/config/config.go b/internal/config/config.go index 22603a07..f946f988 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -10,7 +10,7 @@ import ( "path/filepath" "github.com/derailed/k9s/internal/resource" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" "gopkg.in/yaml.v2" ) @@ -76,11 +76,11 @@ func (c *Config) FavNamespaces() []string { // SetActiveNamespace set the active namespace in the current cluster. func (c *Config) SetActiveNamespace(ns string) error { - log.Debugf("Setting active namespace `%s", ns) + log.Debug().Msgf("Setting active namespace `%s", ns) if c.K9s.ActiveCluster() != nil { return c.K9s.ActiveCluster().Namespace.SetActive(ns, c.settings) } - log.Error("Doh! no active cluster. unable to set active namespace") + log.Error().Msg("Doh! no active cluster. unable to set active namespace") return fmt.Errorf("no active cluster. unable to set active namespace") } @@ -117,7 +117,7 @@ func (c *Config) Load(path string) error { // Save configuration to disk. func (c *Config) Save() error { - log.Debugf("[Config] Saving configuration...") + log.Debug().Msg("[Config] Saving configuration...") c.Validate() return c.SaveFile(K9sConfigFile) } @@ -127,7 +127,7 @@ func (c *Config) SaveFile(path string) error { EnsurePath(path, DefaultDirMod) cfg, err := yaml.Marshal(c) if err != nil { - log.Errorf("[Config] Unable to save K9s config file: %v", err) + log.Error().Msgf("[Config] Unable to save K9s config file: %v", err) return err } return ioutil.WriteFile(path, cfg, 0644) @@ -140,9 +140,9 @@ func (c *Config) Validate() { // Dump debug... func (c *Config) Dump(msg string) { - log.Debug(msg) - log.Debugf("Current Context: %s\n", c.K9s.CurrentCluster) + log.Debug().Msg(msg) + log.Debug().Msgf("Current Context: %s\n", c.K9s.CurrentCluster) for k, cl := range c.K9s.Clusters { - log.Debugf("K9s cluster: %s -- %s\n", k, cl.Namespace) + log.Debug().Msgf("K9s cluster: %s -- %s\n", k, cl.Namespace) } } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 8c020b2c..7a1cc18d 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -8,9 +8,14 @@ import ( "github.com/derailed/k9s/internal/config" m "github.com/petergtz/pegomock" + "github.com/rs/zerolog" "github.com/stretchr/testify/assert" ) +func init() { + zerolog.SetGlobalLevel(zerolog.FatalLevel) +} + func TestConfigValidate(t *testing.T) { setup(t) diff --git a/internal/config/helpers.go b/internal/config/helpers.go index c123116c..21d88792 100644 --- a/internal/config/helpers.go +++ b/internal/config/helpers.go @@ -5,7 +5,7 @@ import ( "os/user" "path/filepath" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" v1 "k8s.io/api/core/v1" ) @@ -56,7 +56,7 @@ func EnsurePath(path string, mod os.FileMode) { dir := filepath.Dir(path) if _, err := os.Stat(dir); os.IsNotExist(err) { if err = os.Mkdir(dir, mod); err != nil { - log.Errorf("Unable to create K9s home config dir: %v", err) + log.Error().Msgf("Unable to create K9s home config dir: %v", err) panic(err) } } diff --git a/internal/config/ns.go b/internal/config/ns.go index d283ed26..a7db1061 100644 --- a/internal/config/ns.go +++ b/internal/config/ns.go @@ -1,7 +1,7 @@ package config import ( - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" ) const ( @@ -27,20 +27,20 @@ func NewNamespace() *Namespace { // Validate a namespace is setup correctly func (n *Namespace) Validate(ks KubeSettings) { - log.Debug("Validating favorites...", n.Active) + log.Debug().Msgf("Validating favorites... %s", n.Active) nn, err := ks.NamespaceNames() if err != nil { return } if !n.isAllNamespace() && !InList(nn, n.Active) { - log.Debugf("[Config] Validation error active namespace resetting to `default") + log.Debug().Msg("[Config] Validation error active namespace resetting to `default") n.Active = defaultNS } for _, ns := range n.Favorites { if ns != allNS && !InList(nn, ns) { - log.Debugf("[Config] Invalid favorite found '%s' - %t", ns, n.isAllNamespace()) + log.Debug().Msgf("[Config] Invalid favorite found '%s' - %t", ns, n.isAllNamespace()) n.rmFavNS(ns) } } @@ -48,7 +48,7 @@ func (n *Namespace) Validate(ks KubeSettings) { // SetActive set the active namespace. func (n *Namespace) SetActive(ns string, ks KubeSettings) error { - log.Debug("Setting active ns ", ns) + log.Debug().Msgf("Setting active ns %s", ns) n.Active = ns n.addFavNS(ns) return nil diff --git a/internal/k8s/config.go b/internal/k8s/config.go index 7fa638af..ed78cfd2 100644 --- a/internal/k8s/config.go +++ b/internal/k8s/config.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" v1 "k8s.io/api/core/v1" "k8s.io/cli-runtime/pkg/genericclioptions" restclient "k8s.io/client-go/rest" @@ -239,7 +239,7 @@ func (c *Config) ConfigAccess() (clientcmd.ConfigAccess, error) { // RawConfig fetch the current kubeconfig with no overrides. func (c *Config) RawConfig() (clientcmdapi.Config, error) { if c.rawConfig != nil && c.rawConfig.CurrentContext != c.currentContext { - log.Debugf("Context swith detected...") + log.Debug().Msg("Context swith detected...") c.currentContext = c.rawConfig.CurrentContext c.reset() } @@ -248,7 +248,7 @@ func (c *Config) RawConfig() (clientcmdapi.Config, error) { if err := c.configFromFlags(); err != nil { return clientcmdapi.Config{}, err } - log.Debugf("Reloading RawConfig...") + log.Debug().Msg("Reloading RawConfig...") cfg, err := c.clientConfig.RawConfig() if err != nil { return cfg, err @@ -269,7 +269,7 @@ func (c *Config) RESTConfig() (*restclient.Config, error) { if err != nil { return c.restConfig, err } - log.Debugf("Connecting to API Server %s", c.restConfig.Host) + log.Debug().Msgf("Connecting to API Server %s", c.restConfig.Host) } return c.restConfig, nil } diff --git a/internal/k8s/config_test.go b/internal/k8s/config_test.go index 776145ea..d1911238 100644 --- a/internal/k8s/config_test.go +++ b/internal/k8s/config_test.go @@ -6,10 +6,15 @@ import ( "testing" "github.com/derailed/k9s/internal/k8s" + "github.com/rs/zerolog" "github.com/stretchr/testify/assert" "k8s.io/cli-runtime/pkg/genericclioptions" ) +func init() { + zerolog.SetGlobalLevel(zerolog.FatalLevel) +} + func TestConfigCurrentContext(t *testing.T) { name, kubeConfig := "blee", "./assets/config" uu := []struct { @@ -78,7 +83,6 @@ func TestConfigCurrentNamespace(t *testing.T) { for _, u := range uu { cfg := k8s.NewConfig(u.flags) ns, err := cfg.CurrentNamespaceName() - fmt.Println("CRap", ns, err) assert.Equal(t, u.err, err) assert.Equal(t, u.namespace, ns) } diff --git a/internal/k8s/hpa.go b/internal/k8s/hpa.go index 6662dd4b..98374923 100644 --- a/internal/k8s/hpa.go +++ b/internal/k8s/hpa.go @@ -38,5 +38,5 @@ func (*HPA) List(ns string) (Collection, error) { // Delete a service func (*HPA) Delete(ns, n string) error { opts := metav1.DeleteOptions{} - return conn.dialOrDie().Autoscaling().HorizontalPodAutoscalers(ns).Delete(n, &opts) + return conn.dialOrDie().AutoscalingV2beta2().HorizontalPodAutoscalers(ns).Delete(n, &opts) } diff --git a/internal/k8s/job.go b/internal/k8s/job.go index a82ff6bb..f3a56c0b 100644 --- a/internal/k8s/job.go +++ b/internal/k8s/job.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" restclient "k8s.io/client-go/rest" @@ -53,7 +53,7 @@ func (j *Job) Containers(ns, n string, includeInit bool) ([]string, error) { if err != nil { return nil, err } - log.Debug("Containers found assoc pod", pod) + log.Debug().Msgf("Containers found assoc pod %v", pod) return NewPod().(Loggable).Containers(ns, pod, includeInit) } @@ -63,7 +63,6 @@ func (j *Job) Logs(ns, n, co string, lines int64, prev bool) *restclient.Request if err != nil { return nil } - log.Println("Logs found assoc pod", pod) return NewPod().(Loggable).Logs(ns, pod, co, lines, prev) } diff --git a/internal/k8s/resource.go b/internal/k8s/resource.go index 6dc5d5b5..b809a1ce 100644 --- a/internal/k8s/resource.go +++ b/internal/k8s/resource.go @@ -3,7 +3,7 @@ package k8s import ( "fmt" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1" "k8s.io/apimachinery/pkg/runtime" @@ -73,7 +73,7 @@ func (r *Resource) getClient() *rest.RESTClient { crConfig.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: codecs} crRestClient, err := rest.RESTClientFor(&crConfig) if err != nil { - log.Fatal(err) + log.Fatal().Err(err) } return crRestClient } diff --git a/internal/resource/base.go b/internal/resource/base.go index c7c186f4..4a8a4e12 100644 --- a/internal/resource/base.go +++ b/internal/resource/base.go @@ -5,7 +5,7 @@ import ( "path" "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/cli-runtime/pkg/genericclioptions/printers" @@ -103,7 +103,7 @@ func (*Base) marshalObject(o runtime.Object) (string, error) { ) err := p.PrintObj(o, &buff) if err != nil { - log.Errorf("Marshal Error %v", err) + log.Error().Msgf("Marshal Error %v", err) return "", err } return buff.String(), nil diff --git a/internal/resource/context.go b/internal/resource/context.go index b9998639..12d8cfcc 100644 --- a/internal/resource/context.go +++ b/internal/resource/context.go @@ -2,7 +2,7 @@ package resource import ( "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" ) // SwitchableRes represents a resource that can be switched. @@ -52,7 +52,7 @@ func (r *Context) NewInstance(i interface{}) Columnar { ii := i.(k8s.NamedContext) c.instance = &ii default: - log.Fatalf("unknown context type %#v", i) + log.Fatal().Msgf("unknown context type %#v", i) } c.path = c.instance.Name return c diff --git a/internal/resource/cr.go b/internal/resource/cr.go index 6d4ca633..aad70e50 100644 --- a/internal/resource/cr.go +++ b/internal/resource/cr.go @@ -2,7 +2,7 @@ package resource import ( "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" v1 "k8s.io/api/rbac/v1" ) @@ -48,7 +48,7 @@ func (r *ClusterRole) NewInstance(i interface{}) Columnar { ii := i.(v1.ClusterRole) c.instance = &ii default: - log.Fatalf("unknown context type %#v", i) + log.Fatal().Msgf("unknown context type %#v", i) } c.path = c.instance.Name return c diff --git a/internal/resource/cr_binding.go b/internal/resource/cr_binding.go index 53c69a45..95943992 100644 --- a/internal/resource/cr_binding.go +++ b/internal/resource/cr_binding.go @@ -2,7 +2,7 @@ package resource import ( "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" v1 "k8s.io/api/rbac/v1" ) @@ -48,7 +48,7 @@ func (r *ClusterRoleBinding) NewInstance(i interface{}) Columnar { ii := i.(v1.ClusterRoleBinding) c.instance = &ii default: - log.Fatalf("unknown context type %#v", i) + log.Fatal().Msgf("unknown context type %#v", i) } c.path = c.instance.Name return c diff --git a/internal/resource/crd.go b/internal/resource/crd.go index 4f6fdd84..8c12d523 100644 --- a/internal/resource/crd.go +++ b/internal/resource/crd.go @@ -4,7 +4,7 @@ import ( "time" "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" yaml "gopkg.in/yaml.v2" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -52,7 +52,7 @@ func (r *CRD) NewInstance(i interface{}) Columnar { ii := i.(unstructured.Unstructured) c.instance = &ii default: - log.Fatalf("unknown context type %#v", i) + log.Fatal().Msgf("unknown context type %#v", i) } meta := c.instance.Object["metadata"].(map[string]interface{}) c.path = meta["name"].(string) @@ -90,7 +90,7 @@ func (r *CRD) Fields(ns string) Row { meta := i.Object["metadata"].(map[string]interface{}) t, err := time.Parse(time.RFC3339, meta["creationTimestamp"].(string)) if err != nil { - log.Error("Fields timestamp", err) + log.Error().Msgf("Fields timestamp %v", err) } return append(ff, meta["name"].(string), toAge(metav1.Time{t})) } diff --git a/internal/resource/cronjob.go b/internal/resource/cronjob.go index 9ad73630..e23173eb 100644 --- a/internal/resource/cronjob.go +++ b/internal/resource/cronjob.go @@ -5,7 +5,7 @@ import ( "strconv" "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" batchv1beta1 "k8s.io/api/batch/v1beta1" ) @@ -63,7 +63,7 @@ func (*CronJob) NewInstance(i interface{}) Columnar { ii := i.(batchv1beta1.CronJob) job.instance = &ii default: - log.Fatalf("Unknown %#v", i) + log.Fatal().Msgf("Unknown %#v", i) } job.path = job.namespacedName(job.instance.ObjectMeta) return job diff --git a/internal/resource/custom.go b/internal/resource/custom.go index 6c85eee0..ab6ac3eb 100644 --- a/internal/resource/custom.go +++ b/internal/resource/custom.go @@ -8,7 +8,7 @@ import ( "strings" "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" yaml "gopkg.in/yaml.v2" metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1" ) @@ -60,12 +60,12 @@ func (*Custom) NewInstance(i interface{}) Columnar { t := i.(metav1beta1.TableRow) cr.instance = &t default: - log.Fatalf("Unknown %#v", i) + log.Fatal().Msgf("Unknown %#v", i) } var obj map[string]interface{} err := json.Unmarshal(cr.instance.Object.Raw, &obj) if err != nil { - log.Error(err) + log.Error().Err(err) } meta := obj["metadata"].(map[string]interface{}) ns := "" @@ -137,7 +137,7 @@ func (r *Custom) Fields(ns string) Row { var obj map[string]interface{} err := json.Unmarshal(r.instance.Object.Raw, &obj) if err != nil { - log.Error(err) + log.Error().Err(err) return Row{} } diff --git a/internal/resource/dp.go b/internal/resource/dp.go index 08cb5e44..4af65d9f 100644 --- a/internal/resource/dp.go +++ b/internal/resource/dp.go @@ -4,7 +4,7 @@ import ( "strconv" "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" v1 "k8s.io/api/apps/v1" ) @@ -50,7 +50,7 @@ func (*Deployment) NewInstance(i interface{}) Columnar { ii := i.(v1.Deployment) cm.instance = &ii default: - log.Fatalf("Unknown %#v", i) + log.Fatal().Msgf("Unknown %#v", i) } cm.path = cm.namespacedName(cm.instance.ObjectMeta) return cm diff --git a/internal/resource/ds.go b/internal/resource/ds.go index 52f7df30..373db328 100644 --- a/internal/resource/ds.go +++ b/internal/resource/ds.go @@ -4,7 +4,7 @@ import ( "strconv" "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" extv1beta1 "k8s.io/api/extensions/v1beta1" ) @@ -50,7 +50,7 @@ func (*DaemonSet) NewInstance(i interface{}) Columnar { ii := i.(extv1beta1.DaemonSet) cm.instance = &ii default: - log.Fatalf("Unknown %#v", i) + log.Fatal().Msgf("Unknown %#v", i) } cm.path = cm.namespacedName(cm.instance.ObjectMeta) return cm diff --git a/internal/resource/ep.go b/internal/resource/ep.go index 8d7ec704..208e569f 100644 --- a/internal/resource/ep.go +++ b/internal/resource/ep.go @@ -6,7 +6,7 @@ import ( "strings" "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" v1 "k8s.io/api/core/v1" ) @@ -52,7 +52,7 @@ func (*Endpoints) NewInstance(i interface{}) Columnar { ii := i.(v1.Endpoints) cm.instance = &ii default: - log.Fatalf("Unknown %#v", i) + log.Fatal().Msgf("Unknown %#v", i) } cm.path = cm.namespacedName(cm.instance.ObjectMeta) return cm diff --git a/internal/resource/evt.go b/internal/resource/evt.go index be87018b..798ccef9 100644 --- a/internal/resource/evt.go +++ b/internal/resource/evt.go @@ -5,7 +5,7 @@ import ( "strconv" "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" v1 "k8s.io/api/core/v1" ) @@ -51,7 +51,7 @@ func (*Event) NewInstance(i interface{}) Columnar { ii := i.(v1.Event) cm.instance = &ii default: - log.Fatalf("Unknown %#v", i) + log.Fatal().Msgf("Unknown %#v", i) } cm.path = cm.namespacedName(cm.instance.ObjectMeta) return cm diff --git a/internal/resource/hpa.go b/internal/resource/hpa.go index ac780d75..be8cbc05 100644 --- a/internal/resource/hpa.go +++ b/internal/resource/hpa.go @@ -6,8 +6,7 @@ import ( "strings" "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" - v1 "k8s.io/api/autoscaling/v1" + "github.com/rs/zerolog/log" autoscalingv2beta2 "k8s.io/api/autoscaling/v2beta2" ) @@ -53,7 +52,7 @@ func (*HPA) NewInstance(i interface{}) Columnar { ii := i.(autoscalingv2beta2.HorizontalPodAutoscaler) cm.instance = &ii default: - log.Fatalf("Unknown %#v", i) + log.Fatal().Msgf("Unknown %#v", i) } cm.path = cm.namespacedName(cm.instance.ObjectMeta) return cm @@ -67,8 +66,8 @@ func (r *HPA) Marshal(path string) (string, error) { return "", err } - hpa := i.(*v1.HorizontalPodAutoscaler) - hpa.TypeMeta.APIVersion = "autoscaling/v1" + hpa := i.(*autoscalingv2beta2.HorizontalPodAutoscaler) + hpa.TypeMeta.APIVersion = "autoscaling/v2beta2" hpa.TypeMeta.Kind = "HorizontalPodAutoscaler" return r.marshalObject(hpa) } diff --git a/internal/resource/hpa_test.go b/internal/resource/hpa_test.go index fe4adaf2..c4817c70 100644 --- a/internal/resource/hpa_test.go +++ b/internal/resource/hpa_test.go @@ -5,9 +5,12 @@ import ( "github.com/derailed/k9s/internal/k8s" "github.com/derailed/k9s/internal/resource" + res "k8s.io/apimachinery/pkg/api/resource" + m "github.com/petergtz/pegomock" "github.com/stretchr/testify/assert" - v1 "k8s.io/api/autoscaling/v1" + autoscalingv2beta2 "k8s.io/api/autoscaling/v2beta2" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -86,26 +89,46 @@ func TestHPAListDescribe(t *testing.T) { // Helpers... -func k8sHPA() *v1.HorizontalPodAutoscaler { +func k8sHPA() *autoscalingv2beta2.HorizontalPodAutoscaler { var i int32 = 1 - return &v1.HorizontalPodAutoscaler{ + return &autoscalingv2beta2.HorizontalPodAutoscaler{ ObjectMeta: metav1.ObjectMeta{ Namespace: "blee", Name: "fred", CreationTimestamp: metav1.Time{Time: testTime()}, }, - Spec: v1.HorizontalPodAutoscalerSpec{ - ScaleTargetRef: v1.CrossVersionObjectReference{ + Spec: autoscalingv2beta2.HorizontalPodAutoscalerSpec{ + ScaleTargetRef: autoscalingv2beta2.CrossVersionObjectReference{ Kind: "fred", Name: "blee", }, - MinReplicas: &i, - MaxReplicas: 1, - TargetCPUUtilizationPercentage: &i, + MinReplicas: &i, + MaxReplicas: 1, + Metrics: []autoscalingv2beta2.MetricSpec{ + { + Type: autoscalingv2beta2.ResourceMetricSourceType, + Resource: &autoscalingv2beta2.ResourceMetricSource{ + Name: v1.ResourceCPU, + Target: autoscalingv2beta2.MetricTarget{ + Type: autoscalingv2beta2.UtilizationMetricType, + }, + }, + }, + }, }, - Status: v1.HorizontalPodAutoscalerStatus{ - CurrentReplicas: 1, - CurrentCPUUtilizationPercentage: &i, + Status: autoscalingv2beta2.HorizontalPodAutoscalerStatus{ + CurrentReplicas: 1, + CurrentMetrics: []autoscalingv2beta2.MetricStatus{ + { + Type: autoscalingv2beta2.ResourceMetricSourceType, + Resource: &autoscalingv2beta2.ResourceMetricStatus{ + Name: v1.ResourceCPU, + Current: autoscalingv2beta2.MetricValueStatus{ + Value: &res.Quantity{}, + }, + }, + }, + }, }, } } @@ -115,7 +138,7 @@ func newHPA() resource.Columnar { } func hpaYaml() string { - return `apiVersion: autoscaling/v1 + return `apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler metadata: creationTimestamp: "2018-12-14T17:36:43Z" @@ -123,13 +146,24 @@ metadata: namespace: blee spec: maxReplicas: 1 + metrics: + - resource: + name: cpu + target: + type: Utilization + type: Resource minReplicas: 1 scaleTargetRef: kind: fred name: blee - targetCPUUtilizationPercentage: 1 status: - currentCPUUtilizationPercentage: 1 + conditions: null + currentMetrics: + - resource: + current: + value: "0" + name: cpu + type: Resource currentReplicas: 1 desiredReplicas: 0 ` diff --git a/internal/resource/ing.go b/internal/resource/ing.go index 967f1ce2..0dbfa860 100644 --- a/internal/resource/ing.go +++ b/internal/resource/ing.go @@ -4,7 +4,7 @@ import ( "strings" "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" v1 "k8s.io/api/core/v1" "k8s.io/api/extensions/v1beta1" ) @@ -51,7 +51,7 @@ func (*Ingress) NewInstance(i interface{}) Columnar { ii := i.(v1beta1.Ingress) cm.instance = &ii default: - log.Fatalf("Unknown %#v", i) + log.Fatal().Msgf("Unknown %#v", i) } cm.path = cm.namespacedName(cm.instance.ObjectMeta) return cm diff --git a/internal/resource/job.go b/internal/resource/job.go index 35914733..b9f199f1 100644 --- a/internal/resource/job.go +++ b/internal/resource/job.go @@ -7,7 +7,7 @@ import ( "time" "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" v1 "k8s.io/api/batch/v1" "k8s.io/apimachinery/pkg/util/duration" ) @@ -54,7 +54,7 @@ func (*Job) NewInstance(i interface{}) Columnar { ii := i.(v1.Job) job.instance = &ii default: - log.Fatalf("Unknown %#v", i) + log.Fatal().Msgf("Unknown %#v", i) } job.path = job.namespacedName(job.instance.ObjectMeta) return job diff --git a/internal/resource/no.go b/internal/resource/no.go index 0a7dc44e..d4a288ad 100644 --- a/internal/resource/no.go +++ b/internal/resource/no.go @@ -6,7 +6,7 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" v1 "k8s.io/api/core/v1" ) @@ -60,7 +60,7 @@ func (*Node) NewInstance(i interface{}) Columnar { ii := i.(v1.Node) cm.instance = &ii default: - log.Fatalf("Unknown %#v", i) + log.Fatal().Msgf("Unknown %#v", i) } cm.path = cm.namespacedName(cm.instance.ObjectMeta) return cm @@ -81,7 +81,7 @@ func (r *Node) List(ns string) (Columnars, error) { cc := make(Columnars, 0, len(nn)) mx, err := r.metricSvc.PerNodeMetrics(nn) if err != nil { - log.Warnf("No metrics: %#v", err) + log.Warn().Msgf("No metrics: %#v", err) } for i := 0; i < len(nn); i++ { @@ -99,7 +99,7 @@ func (r *Node) Marshal(path string) (string, error) { ns, n := namespaced(path) i, err := r.caller.Get(ns, n) if err != nil { - log.Error(err) + log.Error().Err(err) return "", err } diff --git a/internal/resource/ns.go b/internal/resource/ns.go index a02c3b03..820367cd 100644 --- a/internal/resource/ns.go +++ b/internal/resource/ns.go @@ -2,7 +2,7 @@ package resource import ( "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" v1 "k8s.io/api/core/v1" ) @@ -48,7 +48,7 @@ func (*Namespace) NewInstance(i interface{}) Columnar { ii := i.(v1.Namespace) cm.instance = &ii default: - log.Fatalf("Unknown %#v", i) + log.Fatal().Msgf("Unknown %#v", i) } cm.path = cm.namespacedName(cm.instance.ObjectMeta) return cm @@ -59,7 +59,7 @@ func (r *Namespace) Marshal(path string) (string, error) { ns, n := namespaced(path) i, err := r.caller.Get(ns, n) if err != nil { - log.Error(err) + log.Error().Err(err) return "", err } diff --git a/internal/resource/pod.go b/internal/resource/pod.go index ac32773c..9218426d 100644 --- a/internal/resource/pod.go +++ b/internal/resource/pod.go @@ -8,7 +8,7 @@ import ( "time" "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" v1 "k8s.io/api/core/v1" ) @@ -86,7 +86,7 @@ func (r *Pod) NewInstance(i interface{}) Columnar { po := ptr.(v1.Pod) pod.instance = &po default: - log.Fatalf("Unknown %#v", i) + log.Fatal().Msgf("Unknown %#v", i) } pod.path = r.namespacedName(pod.instance.ObjectMeta) return pod @@ -169,7 +169,7 @@ func (r *Pod) List(ns string) (Columnars, error) { metrics, err := r.metricSvc.PodMetrics() if err != nil { - log.Warn(err) + log.Error().Err(err) } cc := make(Columnars, 0, len(ii)) @@ -221,7 +221,7 @@ func (r *Pod) Fields(ns string) Row { r.metrics.CPU, r.metrics.Mem, i.Status.PodIP, - i.Status.HostIP, + i.Spec.NodeName, string(i.Status.QOSClass), toAge(i.ObjectMeta.CreationTimestamp), ) @@ -231,15 +231,6 @@ func (r *Pod) Fields(ns string) Row { func (r *Pod) ExtFields() Properties { i := r.instance - // po := k8s.Pod{} - // e, err := po.Events(i.Namespace, i.Name) - // if err != nil { - // log.Error("Boom!", err) - // } - // if len(e.Items) > 0 { - // log.Println("Events", ee.Items) - // } - return Properties{ "Priority": strconv.Itoa(int(*i.Spec.Priority)), "Priority Class": missing(i.Spec.PriorityClassName), @@ -249,22 +240,9 @@ func (r *Pod) ExtFields() Properties { "Init Containers": r.toContainers(i.Spec.InitContainers), "Node Selectors": mapToStr(i.Spec.NodeSelector), "Volumes": r.toVolumes(i.Spec.Volumes), - // "Events": r.toEvents(e), } } -// func (r *Pod) toEvents(e *v1.EventList) []string { -// ss := make([]string, 0, len(e.Items)+1) -// for _, h := range([]string{"Type", "Reason", "From", "Message", "Age"}) { -// ss[0] = fmt.Printf("%10s %10s %20s %30s", ) -// } -// for i, e := range e.Items { -// ss[i] = e. - -// } -// return ss -// } - func (r *Pod) toVolumes(vv []v1.Volume) map[string]interface{} { m := make(map[string]interface{}, len(vv)) for _, v := range vv { diff --git a/internal/resource/pv.go b/internal/resource/pv.go index 375911c1..2d32f3c3 100644 --- a/internal/resource/pv.go +++ b/internal/resource/pv.go @@ -5,7 +5,7 @@ import ( "strings" "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" v1 "k8s.io/api/core/v1" ) @@ -51,7 +51,7 @@ func (*PV) NewInstance(i interface{}) Columnar { ii := i.(v1.PersistentVolume) cm.instance = &ii default: - log.Fatalf("Unknown %#v", i) + log.Fatal().Msgf("Unknown %#v", i) } cm.path = cm.namespacedName(cm.instance.ObjectMeta) return cm diff --git a/internal/resource/pvc.go b/internal/resource/pvc.go index 681ea3e4..947a09c1 100644 --- a/internal/resource/pvc.go +++ b/internal/resource/pvc.go @@ -2,7 +2,7 @@ package resource import ( "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" v1 "k8s.io/api/core/v1" ) @@ -48,7 +48,7 @@ func (*PVC) NewInstance(i interface{}) Columnar { ii := i.(v1.PersistentVolumeClaim) cm.instance = &ii default: - log.Fatalf("Unknown %#v", i) + log.Fatal().Msgf("Unknown %#v", i) } cm.path = cm.namespacedName(cm.instance.ObjectMeta) return cm diff --git a/internal/resource/rc.go b/internal/resource/rc.go index 091934b0..0076ac8e 100644 --- a/internal/resource/rc.go +++ b/internal/resource/rc.go @@ -4,7 +4,7 @@ import ( "strconv" "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" v1 "k8s.io/api/core/v1" ) @@ -50,7 +50,7 @@ func (*ReplicationController) NewInstance(i interface{}) Columnar { ii := i.(v1.ReplicationController) cm.instance = &ii default: - log.Fatalf("Unknown %#v", i) + log.Fatal().Msgf("Unknown %#v", i) } cm.path = cm.namespacedName(cm.instance.ObjectMeta) return cm diff --git a/internal/resource/ro.go b/internal/resource/ro.go index 46f6120f..3a67a20e 100644 --- a/internal/resource/ro.go +++ b/internal/resource/ro.go @@ -4,7 +4,7 @@ import ( "strings" "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" v1 "k8s.io/api/rbac/v1" ) @@ -52,7 +52,7 @@ func (*Role) NewInstance(i interface{}) Columnar { ii := i.(v1.Role) cm.instance = &ii default: - log.Fatalf("Unknown %#v", i) + log.Fatal().Msgf("Unknown %#v", i) } cm.path = cm.namespacedName(cm.instance.ObjectMeta) return cm diff --git a/internal/resource/ro_binding.go b/internal/resource/ro_binding.go index 53d0eae2..3ce528a5 100644 --- a/internal/resource/ro_binding.go +++ b/internal/resource/ro_binding.go @@ -4,7 +4,7 @@ import ( "strings" "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" v1 "k8s.io/api/rbac/v1" ) @@ -50,7 +50,7 @@ func (*RoleBinding) NewInstance(i interface{}) Columnar { ii := i.(v1.RoleBinding) cm.instance = &ii default: - log.Fatalf("Unknown %#v", i) + log.Fatal().Msgf("Unknown %#v", i) } cm.path = cm.namespacedName(cm.instance.ObjectMeta) return cm diff --git a/internal/resource/rs.go b/internal/resource/rs.go index 19d6b8db..a531d958 100644 --- a/internal/resource/rs.go +++ b/internal/resource/rs.go @@ -4,7 +4,7 @@ import ( "strconv" "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" v1 "k8s.io/api/apps/v1" ) @@ -50,7 +50,7 @@ func (*ReplicaSet) NewInstance(i interface{}) Columnar { ii := i.(v1.ReplicaSet) cm.instance = &ii default: - log.Fatalf("Unknown %#v", i) + log.Fatal().Msgf("Unknown %#v", i) } cm.path = cm.namespacedName(cm.instance.ObjectMeta) return cm diff --git a/internal/resource/sa.go b/internal/resource/sa.go index 440b8bdc..ea2ed4dc 100644 --- a/internal/resource/sa.go +++ b/internal/resource/sa.go @@ -4,7 +4,7 @@ import ( "strconv" "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" v1 "k8s.io/api/core/v1" ) @@ -50,7 +50,7 @@ func (*ServiceAccount) NewInstance(i interface{}) Columnar { ii := i.(v1.ServiceAccount) cm.instance = &ii default: - log.Fatalf("Unknown %#v", i) + log.Fatal().Msgf("Unknown %#v", i) } cm.path = cm.namespacedName(cm.instance.ObjectMeta) return cm diff --git a/internal/resource/sts.go b/internal/resource/sts.go index 3235cebd..c5e16c66 100644 --- a/internal/resource/sts.go +++ b/internal/resource/sts.go @@ -4,7 +4,7 @@ import ( "strconv" "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" v1 "k8s.io/api/apps/v1" ) @@ -50,7 +50,7 @@ func (*StatefulSet) NewInstance(i interface{}) Columnar { ii := i.(v1.StatefulSet) cm.instance = &ii default: - log.Fatalf("Unknown %#v", i) + log.Fatal().Msgf("Unknown %#v", i) } cm.path = cm.namespacedName(cm.instance.ObjectMeta) return cm diff --git a/internal/resource/svc.go b/internal/resource/svc.go index 89084842..fd68b9a7 100644 --- a/internal/resource/svc.go +++ b/internal/resource/svc.go @@ -6,7 +6,7 @@ import ( "strings" "github.com/derailed/k9s/internal/k8s" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" v1 "k8s.io/api/core/v1" ) @@ -54,7 +54,7 @@ func (*Service) NewInstance(i interface{}) Columnar { ii := i.(v1.Service) cm.instance = &ii default: - log.Fatalf("Unknown %#v", i) + log.Fatal().Msgf("Unknown %#v", i) } cm.path = cm.namespacedName(cm.instance.ObjectMeta) return cm diff --git a/internal/views/alias.go b/internal/views/alias.go index 3855e7e4..e942fd05 100644 --- a/internal/views/alias.go +++ b/internal/views/alias.go @@ -9,7 +9,7 @@ import ( "github.com/derailed/k9s/internal/resource" "github.com/gdamore/tcell" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" ) const ( @@ -42,7 +42,7 @@ func newAliasView(app *appView) *aliasView { for { select { case <-ctx.Done(): - log.Debug("Alias GR bailing out!") + log.Debug().Msg("Alias GR bailing out!") return case <-time.After(1 * time.Second): v.update(v.hydrate()) diff --git a/internal/views/app.go b/internal/views/app.go index 4f9513df..60cb6170 100644 --- a/internal/views/app.go +++ b/internal/views/app.go @@ -8,7 +8,7 @@ import ( "github.com/derailed/k9s/internal/config" "github.com/derailed/tview" "github.com/gdamore/tcell" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" "k8s.io/cli-runtime/pkg/genericclioptions" ) @@ -136,7 +136,7 @@ func (a *appView) keyboard(evt *tcell.EventKey) *tcell.EventKey { key = tcell.Key(evt.Rune()) } if a, ok := a.actions[key]; ok { - log.Debug(">> AppView handled key: ", tcell.KeyNames[key]) + log.Debug().Msgf(">> AppView handled key: %s", tcell.KeyNames[key]) return a.action(evt) } return evt @@ -178,8 +178,11 @@ func (a *appView) gotoCmd(evt *tcell.EventKey) *tcell.EventKey { } func (a *appView) activateCmd(evt *tcell.EventKey) *tcell.EventKey { + if a.cmdView.inCmdMode() { + return evt + } a.flash(flashInfo, "Entering command mode...") - log.Debug("Entering app command mode...") + log.Debug().Msg("Entering app command mode...") a.cmdBuff.setActive(true) a.cmdBuff.clear() return nil diff --git a/internal/views/cmd.go b/internal/views/cmd.go index 17549614..f6a683fb 100644 --- a/internal/views/cmd.go +++ b/internal/views/cmd.go @@ -5,7 +5,7 @@ import ( "github.com/derailed/tview" "github.com/gdamore/tcell" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" ) const defaultPrompt = "%c> %s" @@ -62,7 +62,7 @@ func (v *cmdView) changed(s string) { func (v *cmdView) active(f bool) { v.activated = f if f { - log.Debug("CmdView was activated...") + log.Debug().Msg("CmdView was activated...") v.SetBackgroundColor(tcell.ColorDodgerBlue) v.activate() } else { diff --git a/internal/views/details.go b/internal/views/details.go index 2eff8e95..84ef630a 100644 --- a/internal/views/details.go +++ b/internal/views/details.go @@ -8,7 +8,7 @@ import ( "github.com/derailed/tview" "github.com/gdamore/tcell" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" ) const detailsTitleFmt = " [aqua::b]%s([fuchsia::b]%s[aqua::-])[aqua::-] " @@ -26,6 +26,11 @@ type detailsView struct { numSelections int } +var ( + regionRX = regexp.MustCompile(`\["([a-zA-Z0-9_,;: \-\.]*)"\]`) + escapeRX = regexp.MustCompile(`\[([a-zA-Z0-9_,;: \-\."#]+)\[(\[*)\]`) +) + func newDetailsView(app *appView, backFn actionHandler) *detailsView { v := detailsView{TextView: tview.NewTextView(), app: app, actions: make(keyActions)} { @@ -74,7 +79,7 @@ func (v *detailsView) keyboard(evt *tcell.EventKey) *tcell.EventKey { } if a, ok := v.actions[key]; ok { - log.Debug(">> DetailsView handled ", tcell.KeyNames[key]) + log.Debug().Msgf(">> DetailsView handled %s", tcell.KeyNames[key]) return a.action(evt) } return evt @@ -128,8 +133,9 @@ func (v *detailsView) searchCmd(evt *tcell.EventKey) *tcell.EventKey { func (v *detailsView) search(evt *tcell.EventKey) { v.numSelections = 0 v.Highlight() - log.Debug("Searching...", v.cmdBuff, v.numSelections) - v.SetText(v.decorateLines(v.GetText(true), v.cmdBuff.String())) + log.Debug().Msgf("Searching... %s - %d", v.cmdBuff, v.numSelections) + v.Highlight("") + v.SetText(v.decorateLines(v.GetText(false), v.cmdBuff.String())) if v.cmdBuff.empty() { v.app.flash(flashWarn, "Clearing out search query...") @@ -203,9 +209,13 @@ func (v *detailsView) decorateLines(buff, q string) string { rx := regexp.MustCompile(`(?i)` + q) lines := strings.Split(buff, "\n") for i, l := range lines { + l = regionRX.ReplaceAllString(l, "") + l = escapeRX.ReplaceAllString(l, "") if m := rx.FindString(l); len(m) > 0 { lines[i] = rx.ReplaceAllString(l, fmt.Sprintf(`["%d"]%s[""]`, v.numSelections, m)) v.numSelections++ + } else { + lines[i] = l } } return strings.Join(lines, "\n") diff --git a/internal/views/exec.go b/internal/views/exec.go index 9a37ff4e..ed5f684a 100644 --- a/internal/views/exec.go +++ b/internal/views/exec.go @@ -10,13 +10,13 @@ import ( "strings" "syscall" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" ) func runK(app *appView, args ...string) bool { bin, err := exec.LookPath("kubectl") if err != nil { - log.Error("Unable to find kubeclt command in path") + log.Error().Msgf("Unable to find kubeclt command in path %v", err) return false } @@ -31,7 +31,7 @@ func runK(app *appView, args ...string) bool { } } if err := execute(bin, args...); err != nil { - log.Errorf("Command exited: %T %v %v", err, err, args) + log.Error().Msgf("Command exited: %T %v %v", err, err, args) app.flash(flashErr, "Command exited:", err.Error()) } }) @@ -40,7 +40,7 @@ func runK(app *appView, args ...string) bool { func run1(app *appView, bin string, args ...string) bool { return app.Suspend(func() { if err := execute(bin, args...); err != nil { - log.Errorf("Command exited: %T %v %v", err, err, args) + log.Error().Msgf("Command exited: %T %v %v", err, err, args) app.flash(flashErr, "Command exited: ", err.Error()) } }) @@ -48,7 +48,7 @@ func run1(app *appView, bin string, args ...string) bool { func execute(bin string, args ...string) error { clearScreen() - log.Debugf("Running command > %s %s", bin, strings.Join(args, " ")) + log.Debug().Msgf("Running command > %s %s", bin, strings.Join(args, " ")) ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -56,14 +56,14 @@ func execute(bin string, args ...string) error { signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM) go func() { <-sigChan - log.Debug("Command canceled with signal!") + log.Debug().Msg("Command canceled with signal!") cancel() }() cmd := exec.Command(bin, args...) cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr err := cmd.Run() - log.Debug("Command return status ", err) + log.Debug().Msgf("Command return status %v", err) select { case <-ctx.Done(): return errors.New("canceled by operator") diff --git a/internal/views/flash.go b/internal/views/flash.go index 5299f2e2..f924b9a7 100644 --- a/internal/views/flash.go +++ b/internal/views/flash.go @@ -14,7 +14,7 @@ const ( flashWarn flashErr flashFatal - flashDelay = 5 + flashDelay = 3 emoDoh = "😗" emoRed = "😡" diff --git a/internal/views/info.go b/internal/views/info.go index 2144820c..2100ab41 100644 --- a/internal/views/info.go +++ b/internal/views/info.go @@ -4,7 +4,7 @@ import ( "github.com/derailed/k9s/internal/resource" "github.com/derailed/tview" "github.com/gdamore/tcell" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" ) type infoView struct { @@ -77,7 +77,7 @@ func (v *infoView) refresh() { mx, err := cluster.Metrics() if err != nil { - log.Error(err) + log.Error().Err(err) return } c := v.GetCell(row, 1) diff --git a/internal/views/job.go b/internal/views/job.go index a43c1f81..6b055c92 100644 --- a/internal/views/job.go +++ b/internal/views/job.go @@ -3,7 +3,7 @@ package views import ( "github.com/derailed/k9s/internal/resource" "github.com/gdamore/tcell" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" ) type jobView struct { @@ -48,7 +48,7 @@ func (v *jobView) logs(evt *tcell.EventKey) *tcell.EventKey { cc, err := fetchContainers(v.list, v.selectedItem, true) if err != nil { v.app.flash(flashErr, err.Error()) - log.Error(err) + log.Error().Err(err) return evt } diff --git a/internal/views/log.go b/internal/views/log.go index e4d50b44..3b8d6e00 100644 --- a/internal/views/log.go +++ b/internal/views/log.go @@ -2,10 +2,14 @@ package views import ( "fmt" + "io" + + "github.com/derailed/tview" ) type logView struct { *detailsView + ansiWriter io.Writer } func newLogView(title string, parent loggable) *logView { @@ -13,14 +17,19 @@ func newLogView(title string, parent loggable) *logView { { v.SetBorderPadding(0, 0, 1, 1) v.setCategory("Logs") - v.SetDynamicColors(false) + v.SetDynamicColors(true) v.SetWrap(true) v.setTitle(parent.getSelection()) } + v.ansiWriter = tview.ANSIWriter(v) return &v } +func (l *logView) logLine(line string) { + fmt.Fprintln(l.ansiWriter, line) +} + func (l *logView) log(lines fmt.Stringer) { l.Clear() - fmt.Fprintln(l, lines.String()) + fmt.Fprintln(l.ansiWriter, lines.String()) } diff --git a/internal/views/logs.go b/internal/views/logs.go index 5c2fba4d..23438e3c 100644 --- a/internal/views/logs.go +++ b/internal/views/logs.go @@ -10,7 +10,7 @@ import ( "github.com/derailed/k9s/internal/resource" "github.com/derailed/tview" "github.com/gdamore/tcell" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" ) const ( @@ -26,16 +26,13 @@ type logsView struct { containers []string actions keyActions cancelFunc context.CancelFunc - buffer *logBuffer } func newLogsView(parent loggable) *logsView { - maxBuff := config.Root.K9s.LogBufferSize v := logsView{ Pages: tview.NewPages(), parent: parent, containers: []string{}, - buffer: newLogBuffer(int(maxBuff), true), } v.setActions(keyActions{ tcell.KeyEscape: {description: "Back", action: v.back}, @@ -57,27 +54,31 @@ func (v *logsView) init() { } func (v *logsView) keyboard(evt *tcell.EventKey) *tcell.EventKey { + key := evt.Key() + if key == tcell.KeyRune { + key = tcell.Key(evt.Rune()) + } + if kv, ok := v.CurrentPage().Item.(keyHandler); ok { if kv.keyboard(evt) == nil { return nil } } - key := evt.Key() - if key == tcell.KeyRune { + if evt.Key() == tcell.KeyRune { if i, err := strconv.Atoi(string(evt.Rune())); err == nil { if _, ok := numKeys[i]; ok { v.load(i - 1) return nil } } - key = tcell.Key(evt.Rune()) } if m, ok := v.actions[key]; ok { - log.Debug(">> LogsView handled ", tcell.KeyNames[key]) + log.Debug().Msgf(">> LogsView handled %s", tcell.KeyNames[key]) return m.action(evt) } + return evt } @@ -101,6 +102,7 @@ func (v *logsView) addContainer(n string) { l := newLogView(n, v.parent) { l.SetInputCapture(v.keyboard) + l.backFn = v.back } v.AddPage(n, l, true, false) } @@ -114,7 +116,12 @@ func (v *logsView) deleteAllPages() { } func (v *logsView) stop() { - v.killLogIfAny() + if v.cancelFunc == nil { + return + } + log.Debug().Msg("Canceling logs...") + v.cancelFunc() + v.cancelFunc = nil } func (v *logsView) load(i int) { @@ -122,60 +129,31 @@ func (v *logsView) load(i int) { return } v.SwitchToPage(v.containers[i]) - v.buffer.clear() if err := v.doLoad(v.parent.getSelection(), v.containers[i]); err != nil { v.parent.appView().flash(flashErr, err.Error()) - v.buffer.add("😂 Doh! No logs are available at this time. Check again later on...") l := v.CurrentPage().Item.(*logView) - l.log(v.buffer) + l.logLine("😂 Doh! No logs are available at this time. Check again later on...") return } v.parent.appView().SetFocus(v) } -func (v *logsView) killLogIfAny() { - if v.cancelFunc == nil { - return - } - v.cancelFunc() - v.cancelFunc = nil -} - func (v *logsView) doLoad(path, co string) error { - v.killLogIfAny() + v.stop() c := make(chan string) go func() { - l, count, first := v.CurrentPage().Item.(*logView), 0, true + l := v.CurrentPage().Item.(*logView) l.setTitle(path + ":" + co) for { select { case line, ok := <-c: if !ok { - if v.buffer.length() > 0 { - v.buffer.add("--- No more logs ---") - l.log(v.buffer) - l.ScrollToEnd() - } + l.logLine("--- No more logs ---") + l.ScrollToEnd() return } - v.buffer.add(line) - case <-time.After(refreshRate): - if count == maxCleanse { - log.Debug("Cleansing logs") - v.buffer.cleanse() - count = 0 - } - count++ - if v.buffer.length() == 0 { - l.Clear() - continue - } - l.log(v.buffer) - if first { - l.ScrollToEnd() - first = false - } + l.logLine(line) } } }() @@ -185,8 +163,8 @@ func (v *logsView) doLoad(path, co string) error { if !ok { return fmt.Errorf("Resource %T is not tailable", v.parent.getList().Resource) } - maxBuff := config.Root.K9s.LogBufferSize - cancelFn, err := res.Logs(c, ns, po, co, int64(maxBuff), false) + maxBuff := int64(config.Root.K9s.LogBufferSize) + cancelFn, err := res.Logs(c, ns, po, co, maxBuff, false) if err != nil { cancelFn() return err @@ -237,7 +215,6 @@ func (v *logsView) pageDown(*tcell.EventKey) *tcell.EventKey { func (v *logsView) clearLogs(*tcell.EventKey) *tcell.EventKey { if p := v.CurrentPage(); p != nil { v.parent.appView().flash(flashInfo, "Clearing logs...") - v.buffer.clear() p.Item.(*logView).Clear() } return nil diff --git a/internal/views/menu.go b/internal/views/menu.go index 80fbf898..d9504c37 100644 --- a/internal/views/menu.go +++ b/internal/views/menu.go @@ -10,7 +10,7 @@ import ( "github.com/derailed/k9s/internal/resource" "github.com/derailed/tview" "github.com/gdamore/tcell" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" ) const ( @@ -143,7 +143,7 @@ func (a keyActions) toHints() hints { mnemonic: name, display: a[tcell.Key(k)].description}) } else { - log.Errorf("Unable to local KeyName for %#v", k) + log.Error().Msgf("Unable to local KeyName for %#v", k) } } return hh diff --git a/internal/views/pod.go b/internal/views/pod.go index 0afecaa3..1fd22f66 100644 --- a/internal/views/pod.go +++ b/internal/views/pod.go @@ -5,7 +5,7 @@ import ( "github.com/derailed/k9s/internal/resource" "github.com/gdamore/tcell" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" ) type podView struct { @@ -60,14 +60,13 @@ func (v *podView) getSelection() string { // Handlers... func (v *podView) logsCmd(evt *tcell.EventKey) *tcell.EventKey { - log.Println("Selected", v.rowSelected()) if !v.rowSelected() { return evt } cc, err := fetchContainers(v.list, v.selectedItem, true) if err != nil { v.app.flash(flashErr, err.Error()) - log.Error(err) + log.Error().Err(err) return evt } l := v.GetPrimitive("logs").(*logsView) @@ -117,7 +116,7 @@ func (v *podView) shellCmd(evt *tcell.EventKey) *tcell.EventKey { cc, err := fetchContainers(v.list, v.selectedItem, false) if err != nil { v.app.flash(flashErr, err.Error()) - log.Error("Error fetching containers", err) + log.Error().Msgf("Error fetching containers %v", err) return evt } if len(cc) == 1 { @@ -146,7 +145,7 @@ func (v *podView) shellIn(path, co string) { args = append(args, "-c", co) } args = append(args, "--", "sh") - log.Debug("Shell args", args) + log.Debug().Msgf("Shell args %v", args) runK(v.app, args...) } diff --git a/internal/views/resource.go b/internal/views/resource.go index b735645a..ff98721e 100644 --- a/internal/views/resource.go +++ b/internal/views/resource.go @@ -14,7 +14,7 @@ import ( "github.com/derailed/k9s/internal/resource" "github.com/derailed/tview" "github.com/gdamore/tcell" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" ) const noSelection = "" @@ -74,7 +74,7 @@ func (v *resourceView) init(ctx context.Context, ns string) { for { select { case <-ctx.Done(): - log.Debugf("%s watcher canceled!", v.title) + log.Debug().Msgf("%s watcher canceled!", v.title) return case <-time.After(time.Duration(initTick) * time.Second): v.refresh() @@ -118,6 +118,12 @@ func (v *resourceView) hints() hints { // ---------------------------------------------------------------------------- // Actions... +func (v *resourceView) refreshCmd(*tcell.EventKey) *tcell.EventKey { + log.Debug().Msg("Refreshing resource...") + v.refresh() + return nil +} + func (v *resourceView) backCmd(*tcell.EventKey) *tcell.EventKey { v.switchPage(v.list.GetName()) return nil @@ -145,7 +151,7 @@ func (v *resourceView) describeCmd(evt *tcell.EventKey) *tcell.EventKey { raw, err := v.list.Resource().Describe(v.title, sel) if err != nil { v.app.flash(flashErr, "Unable to describeCmd this resource", err.Error()) - log.Error(err) + log.Error().Err(err) return evt } details := v.GetPrimitive("details").(*detailsView) @@ -168,7 +174,7 @@ func (v *resourceView) viewCmd(evt *tcell.EventKey) *tcell.EventKey { raw, err := v.list.Resource().Marshal(sel) if err != nil { v.app.flash(flashErr, "Unable to marshal resource", err.Error()) - log.Error(err) + log.Error().Err(err) return evt } details := v.GetPrimitive("details").(*detailsView) @@ -324,6 +330,8 @@ func (v *resourceView) refreshActions() { } } + aa[tcell.KeyCtrlR] = newKeyAction("Refresh", v.refreshCmd) + if v.list.Access(resource.EditAccess) { aa[KeyE] = newKeyAction("Edit", v.editCmd) } diff --git a/internal/views/table.go b/internal/views/table.go index 66f2ce74..6c23fb70 100644 --- a/internal/views/table.go +++ b/internal/views/table.go @@ -9,7 +9,7 @@ import ( "github.com/derailed/k9s/internal/resource" "github.com/derailed/tview" "github.com/gdamore/tcell" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" ) const ( @@ -83,7 +83,7 @@ func (v *tableView) keyboard(evt *tcell.EventKey) *tcell.EventKey { } if a, ok := v.actions[key]; ok { - log.Debug(">> TableView handled ", tcell.KeyNames[key]) + log.Debug().Msgf(">> TableView handled %s", tcell.KeyNames[key]) return a.action(evt) } return evt @@ -125,7 +125,7 @@ func (v *tableView) activateCmd(evt *tcell.EventKey) *tcell.EventKey { } v.app.flash(flashInfo, "Filtering...") - log.Info("Entering filtering mode...") + log.Info().Msg("Entering filtering mode...") v.cmdBuff.reset() v.cmdBuff.setActive(true) return nil diff --git a/main.go b/main.go index b75950f6..8c84bbce 100644 --- a/main.go +++ b/main.go @@ -5,7 +5,8 @@ import ( "github.com/derailed/k9s/internal/cmd" "github.com/derailed/k9s/internal/config" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" _ "k8s.io/client-go/plugin/pkg/client/auth" ) @@ -14,8 +15,7 @@ func init() { mod := os.O_CREATE | os.O_APPEND | os.O_WRONLY if file, err := os.OpenFile(config.K9sLogs, mod, config.DefaultFileMod); err == nil { - log.SetOutput(file) - log.SetFormatter(&log.TextFormatter{FullTimestamp: true, ForceColors: true}) + log.Logger = log.Output(zerolog.ConsoleWriter{Out: file}) } else { panic(err) }