mirror of https://github.com/k3s-io/k3s
Merge pull request #66643 from smarterclayton/improve_events
Automatic merge from submit-queue (batch tested with PRs 66445, 66643, 60551). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. Improve the output of `kubectl get events` Events have long shown the most data of the core objects in their output, but that data is of varying use to a user. Following the principle that events are intended for the system to communicate information back to the user, and that Message is the primary human readable field, this commit alters the default columns to ensure event is shown with the most width given to the message, and all other fields organized by their relevance to the message. 1. Events are no longer sorted in the printer (this was a bug and was broken with paging and server side rendering) 2. Only the last seen, type, reason, kind, and message fields are shown by default, which makes the message prominent 3. Source, subobject, count, and first seen are only shown under `-o wide` 4. The duration fields were changed to be the more precise output introduced for job duration (2-3 sig figs) 5. Prioritized the column order for scanning - when, how important, what kind of error, what kind of object, and the message. 6. Trim trailing newlines on the message. ```release-note Improved the output of `kubectl get events` to prioritize showing the message, and move some fields to `-o wide`. ``` ``` $ kubectl get events --sort-by lastTimestamp LAST SEEN TYPE REASON KIND MESSAGE 16m Normal SawCompletedJob CronJob Saw completed job: image-mirror-origin-v3.11-quay-1532581200 16m Normal SuccessfulDelete CronJob Deleted job image-mirror-origin-v3.11-quay-1532577600 14m Normal Scheduled Pod Successfully assigned 50c42204-9091-11e8-b2a1-0a58ac101869 to origin-ci-ig-n-fqfh 14m Normal Pulling Pod pulling image "docker-registry.default.svc:5000/ci/commenter:latest" 14m Normal Created Pod Created container 14m Normal Pulled Pod Successfully pulled image "docker-registry.default.svc:5000/ci/commenter:latest" 14m Normal Started Pod Started container 14m Normal SandboxChanged Pod Pod sandbox changed, it will be killed and re-created. 4m14s Normal ScaleDown Pod deleting pod for node scale down 4m14s Normal ScaleDown Pod deleting pod for node scale down 4m14s Normal ScaleDown Pod deleting pod for node scale down 4m14s Normal ScaleDown Pod deleting pod for node scale down 4m14s Normal ScaleDown Pod deleting pod for node scale down 4m14s Normal ScaleDown Pod deleting pod for node scale down 4m14s Normal ScaleDown Pod deleting pod for node scale down 4m13s Normal SuccessfulCreate ReplicationController Created pod: tide-30-hmncf 4m13s Normal Scheduled Pod Successfully assigned tide-30-hmncf to origin-ci-ig-n-x64l 4m12s Normal SuccessfulCreate ReplicationController Created pod: console-jenkins-operator-16-dd5k8 4m12s Normal SuccessfulCreate ReplicationController Created pod: sinker-23-scfmt ```pull/8/head
commit
f49708bd49
|
@ -21,7 +21,6 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -44,7 +43,6 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/duration"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/kubernetes/pkg/api/events"
|
||||
"k8s.io/kubernetes/pkg/apis/apps"
|
||||
"k8s.io/kubernetes/pkg/apis/autoscaling"
|
||||
"k8s.io/kubernetes/pkg/apis/batch"
|
||||
|
@ -236,15 +234,15 @@ func AddHandlers(h printers.PrintHandler) {
|
|||
|
||||
eventColumnDefinitions := []metav1beta1.TableColumnDefinition{
|
||||
{Name: "Last Seen", Type: "string", Description: apiv1.Event{}.SwaggerDoc()["lastTimestamp"]},
|
||||
{Name: "First Seen", Type: "string", Description: apiv1.Event{}.SwaggerDoc()["firstTimestamp"]},
|
||||
{Name: "Count", Type: "string", Description: apiv1.Event{}.SwaggerDoc()["count"]},
|
||||
{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
|
||||
{Name: "Kind", Type: "string", Description: apiv1.Event{}.InvolvedObject.SwaggerDoc()["kind"]},
|
||||
{Name: "Subobject", Type: "string", Description: apiv1.Event{}.InvolvedObject.SwaggerDoc()["fieldPath"]},
|
||||
{Name: "Type", Type: "string", Description: apiv1.Event{}.SwaggerDoc()["type"]},
|
||||
{Name: "Reason", Type: "string", Description: apiv1.Event{}.SwaggerDoc()["reason"]},
|
||||
{Name: "Source", Type: "string", Description: apiv1.Event{}.SwaggerDoc()["source"]},
|
||||
{Name: "Kind", Type: "string", Description: apiv1.Event{}.InvolvedObject.SwaggerDoc()["kind"]},
|
||||
{Name: "Source", Type: "string", Priority: 1, Description: apiv1.Event{}.SwaggerDoc()["source"]},
|
||||
{Name: "Message", Type: "string", Description: apiv1.Event{}.SwaggerDoc()["message"]},
|
||||
{Name: "Subobject", Type: "string", Priority: 1, Description: apiv1.Event{}.InvolvedObject.SwaggerDoc()["fieldPath"]},
|
||||
{Name: "First Seen", Type: "string", Priority: 1, Description: apiv1.Event{}.SwaggerDoc()["firstTimestamp"]},
|
||||
{Name: "Count", Type: "string", Priority: 1, Description: apiv1.Event{}.SwaggerDoc()["count"]},
|
||||
{Name: "Name", Type: "string", Priority: 1, Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
|
||||
}
|
||||
h.TableHandler(eventColumnDefinitions, printEvent)
|
||||
h.TableHandler(eventColumnDefinitions, printEventList)
|
||||
|
@ -515,7 +513,7 @@ func translateTimestampSince(timestamp metav1.Time) string {
|
|||
return "<unknown>"
|
||||
}
|
||||
|
||||
return duration.ShortHumanDuration(time.Since(timestamp.Time))
|
||||
return duration.HumanDuration(time.Since(timestamp.Time))
|
||||
}
|
||||
|
||||
// translateTimestampUntil returns the elapsed time until timestamp in
|
||||
|
@ -525,7 +523,7 @@ func translateTimestampUntil(timestamp metav1.Time) string {
|
|||
return "<unknown>"
|
||||
}
|
||||
|
||||
return duration.ShortHumanDuration(time.Until(timestamp.Time))
|
||||
return duration.HumanDuration(time.Until(timestamp.Time))
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -1328,25 +1326,42 @@ func printEvent(obj *api.Event, options printers.PrintOptions) ([]metav1beta1.Ta
|
|||
Object: runtime.RawExtension{Object: obj},
|
||||
}
|
||||
// While watching event, we should print absolute time.
|
||||
var FirstTimestamp, LastTimestamp string
|
||||
var firstTimestamp, lastTimestamp string
|
||||
if options.AbsoluteTimestamps {
|
||||
FirstTimestamp = obj.FirstTimestamp.String()
|
||||
LastTimestamp = obj.LastTimestamp.String()
|
||||
firstTimestamp = obj.FirstTimestamp.String()
|
||||
lastTimestamp = obj.LastTimestamp.String()
|
||||
} else {
|
||||
FirstTimestamp = translateTimestampSince(obj.FirstTimestamp)
|
||||
LastTimestamp = translateTimestampSince(obj.LastTimestamp)
|
||||
firstTimestamp = translateTimestampSince(obj.FirstTimestamp)
|
||||
lastTimestamp = translateTimestampSince(obj.LastTimestamp)
|
||||
}
|
||||
if options.Wide {
|
||||
row.Cells = append(row.Cells,
|
||||
lastTimestamp,
|
||||
obj.Type,
|
||||
obj.Reason,
|
||||
obj.InvolvedObject.Kind,
|
||||
formatEventSource(obj.Source),
|
||||
strings.TrimSpace(obj.Message),
|
||||
obj.InvolvedObject.FieldPath,
|
||||
firstTimestamp,
|
||||
int64(obj.Count),
|
||||
obj.Name,
|
||||
)
|
||||
} else {
|
||||
row.Cells = append(row.Cells,
|
||||
lastTimestamp,
|
||||
obj.Type,
|
||||
obj.Reason,
|
||||
obj.InvolvedObject.Kind,
|
||||
strings.TrimSpace(obj.Message),
|
||||
)
|
||||
}
|
||||
row.Cells = append(row.Cells, LastTimestamp, FirstTimestamp,
|
||||
int64(obj.Count), obj.Name, obj.InvolvedObject.Kind,
|
||||
obj.InvolvedObject.FieldPath, obj.Type, obj.Reason,
|
||||
formatEventSource(obj.Source), obj.Message)
|
||||
|
||||
return []metav1beta1.TableRow{row}, nil
|
||||
}
|
||||
|
||||
// Sorts and prints the EventList in a human-friendly format.
|
||||
func printEventList(list *api.EventList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) {
|
||||
sort.Sort(events.SortableEvents(list.Items))
|
||||
rows := make([]metav1beta1.TableRow, 0, len(list.Items))
|
||||
for i := range list.Items {
|
||||
r, err := printEvent(&list.Items[i], options)
|
||||
|
|
|
@ -1927,7 +1927,7 @@ func TestTranslateTimestampSince(t *testing.T) {
|
|||
{"unknown", translateTimestampSince(metav1.Time{}), "<unknown>"},
|
||||
{"30 seconds ago", translateTimestampSince(metav1.Time{Time: time.Now().Add(-3e10)}), "30s"},
|
||||
{"5 minutes ago", translateTimestampSince(metav1.Time{Time: time.Now().Add(-3e11)}), "5m"},
|
||||
{"an hour ago", translateTimestampSince(metav1.Time{Time: time.Now().Add(-6e12)}), "1h"},
|
||||
{"an hour ago", translateTimestampSince(metav1.Time{Time: time.Now().Add(-6e12)}), "100m"},
|
||||
{"2 days ago", translateTimestampSince(metav1.Time{Time: time.Now().UTC().AddDate(0, 0, -2)}), "2d"},
|
||||
{"months ago", translateTimestampSince(metav1.Time{Time: time.Now().UTC().AddDate(0, 0, -90)}), "90d"},
|
||||
{"10 years ago", translateTimestampSince(metav1.Time{Time: time.Now().UTC().AddDate(-10, 0, 0)}), "10y"},
|
||||
|
@ -1952,7 +1952,7 @@ func TestTranslateTimestampUntil(t *testing.T) {
|
|||
{"unknown", translateTimestampUntil(metav1.Time{}), "<unknown>"},
|
||||
{"in 30 seconds", translateTimestampUntil(metav1.Time{Time: time.Now().Add(3e10 + buf)}), "30s"},
|
||||
{"in 5 minutes", translateTimestampUntil(metav1.Time{Time: time.Now().Add(3e11 + buf)}), "5m"},
|
||||
{"in an hour", translateTimestampUntil(metav1.Time{Time: time.Now().Add(6e12 + buf)}), "1h"},
|
||||
{"in an hour", translateTimestampUntil(metav1.Time{Time: time.Now().Add(6e12 + buf)}), "100m"},
|
||||
{"in 2 days", translateTimestampUntil(metav1.Time{Time: time.Now().UTC().AddDate(0, 0, 2).Add(buf)}), "2d"},
|
||||
{"in months", translateTimestampUntil(metav1.Time{Time: time.Now().UTC().AddDate(0, 0, 90).Add(buf)}), "90d"},
|
||||
{"in 10 years", translateTimestampUntil(metav1.Time{Time: time.Now().UTC().AddDate(10, 0, 0).Add(buf)}), "10y"},
|
||||
|
|
|
@ -463,7 +463,7 @@ func TestConvertToTableList(t *testing.T) {
|
|||
out: &metav1beta1.Table{
|
||||
ColumnDefinitions: columns,
|
||||
Rows: []metav1beta1.TableRow{
|
||||
{Cells: []interface{}{"foo", "1/2", "Pending", int64(10), "1y", "10.1.2.3", "test-node", "nominated-node"}, Object: runtime.RawExtension{Object: pod1}},
|
||||
{Cells: []interface{}{"foo", "1/2", "Pending", int64(10), "370d", "10.1.2.3", "test-node", "nominated-node"}, Object: runtime.RawExtension{Object: pod1}},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -57,17 +57,29 @@ func HumanDuration(d time.Duration) string {
|
|||
}
|
||||
minutes := int(d / time.Minute)
|
||||
if minutes < 10 {
|
||||
return fmt.Sprintf("%dm%ds", minutes, int(d/time.Second)%60)
|
||||
s := int(d/time.Second) % 60
|
||||
if s == 0 {
|
||||
return fmt.Sprintf("%dm", minutes)
|
||||
}
|
||||
return fmt.Sprintf("%dm%ds", minutes, s)
|
||||
} else if minutes < 60*3 {
|
||||
return fmt.Sprintf("%dm", minutes)
|
||||
}
|
||||
hours := int(d / time.Hour)
|
||||
if hours < 8 {
|
||||
return fmt.Sprintf("%dh%dm", hours, int(d/time.Minute)%60)
|
||||
m := int(d/time.Minute) % 60
|
||||
if m == 0 {
|
||||
return fmt.Sprintf("%dh", hours)
|
||||
}
|
||||
return fmt.Sprintf("%dh%dm", hours, m)
|
||||
} else if hours < 48 {
|
||||
return fmt.Sprintf("%dh", hours)
|
||||
} else if hours < 24*8 {
|
||||
return fmt.Sprintf("%dd%dh", hours/24, hours%24)
|
||||
h := hours % 24
|
||||
if h == 0 {
|
||||
return fmt.Sprintf("%dd", hours/24)
|
||||
}
|
||||
return fmt.Sprintf("%dd%dh", hours/24, h)
|
||||
} else if hours < 24*365*2 {
|
||||
return fmt.Sprintf("%dd", hours/24)
|
||||
} else if hours < 24*365*8 {
|
||||
|
|
Loading…
Reference in New Issue