Skip to content
This repository has been archived by the owner on Jul 25, 2022. It is now read-only.

Commit

Permalink
Change the way the gardenctl displays logs from loki
Browse files Browse the repository at this point in the history
  • Loading branch information
Zhelyazkov committed Mar 24, 2021
1 parent 1e3e5fa commit 9c80b36
Showing 1 changed file with 75 additions and 9 deletions.
84 changes: 75 additions & 9 deletions pkg/cmd/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ import (
"fmt"
"log"
"os"
"os/exec"
"path"
"path/filepath"
"sort"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -61,7 +63,7 @@ func NewLogsCmd(targetReader TargetReader) *cobra.Command {
ValidArgs: []string{"gardener-apiserver", "gardener-controller-manager", "gardener-dashboard", "api", "scheduler", "controller-manager", "etcd-operator", "etcd-main", "etcd-events", "addon-manager", "vpn-seed", "vpn-shoot", "auto-node-repair", "kubernetes-dashboard", "prometheus", "grafana", "gardenlet", "tf"},
Aliases: []string{"log"},
}
cmd.Flags().Int64Var(&flags.tail, "tail", 200, "Lines of recent log file to display. Defaults to 200 with no selector, if a selector is provided takes the number of specified lines (max 100 000 for loki).")
cmd.Flags().Int64Var(&flags.tail, "tail", 1000, "Lines of recent log file to display. Defaults to 200 with no selector, if a selector is provided takes the number of specified lines (max 100 000 for loki).")
cmd.Flags().DurationVar(&flags.sinceSeconds, "since", flags.sinceSeconds, "Only return logs newer than a relative duration like 5s, 2m, or 3h. Defaults to all logs. Only one of since-time / since may be used.")
cmd.Flags().StringVar(&flags.sinceTime, "since-time", flags.sinceTime, "Only return logs after a specific date (RFC3339). Defaults to all logs. Only one of since-time / since may be used.")
cmd.Flags().BoolVar(&flags.loki, "loki", flags.loki, "If the flag is set the logs are retrieved and shown from Loki, otherwise from the kubelet.")
Expand Down Expand Up @@ -389,6 +391,8 @@ func showLogsFromLoki(namespace, toMatch, container string) {
checkError(err)

fmt.Println(response)
fmt.Println("COMMAND: ", "kubectl", BuildLokiCommandArgs(KUBECONFIG, namespace, toMatch, container, flags.tail, flags.sinceSeconds))
fmt.Println("KRIS LENGTH: ", len(response.Data.Result))
}

//BuildLogCommandArgs build kubectl command to get logs
Expand Down Expand Up @@ -943,6 +947,10 @@ func newLogsFlags() *logFlags {
type logResponseLoki struct {
Data struct {
Result []struct {
Stream struct {
ContainerName string `json:"container_name"`
DockerID string `json:"docker_id"`
} `json:"stream"`
Values [][]string `json:"values"`
} `json:"result"`
} `json:"data"`
Expand All @@ -955,6 +963,16 @@ type logMessage struct {
Source string `json:"source"`
}

type containers map[string][]dockerIds
type dockerIds struct {
name string
logs []logField
}
type logField struct {
log string
time time.Time
}

func (msg logMessage) String() string {
message := "\t"
if msg.Severity != emptyString {
Expand All @@ -974,31 +992,53 @@ func (msg logMessage) String() string {
func (response logResponseLoki) String() string {
results := response.Data.Result
var allLogs strings.Builder
valuesDelimeter := "------------------------------------------------------------------------------------------\n"
containers := make(map[string][]dockerIds)
valuesDelimeter := strings.Repeat("=", getTerminalWidth()) + "\n"

for resultIndex := len(results) - 1; resultIndex >= 0; resultIndex-- {
currContainer := results[resultIndex].Stream.ContainerName
currDockerId := results[resultIndex].Stream.DockerID

values := results[resultIndex].Values
isThereLogs := false
for valueIndex := len(values) - 1; valueIndex >= 0; valueIndex-- {
time := parseTimeInRFC(values[valueIndex][0])
log := parseLogMessage(values[valueIndex][1])
allLogs.WriteString(time + log.String())
isThereLogs = true
dockerIdIndex := findDockerIdIndex(containers[currContainer], currDockerId)
if dockerIdIndex == -1 {
containers[currContainer] = append(containers[currContainer], dockerIds{name: currDockerId, logs: make([]logField, 0)})
dockerIdIndex = len(containers[currContainer]) - 1
}

containers[currContainer][dockerIdIndex].logs = append(
containers[currContainer][dockerIdIndex].logs, logField{time: time, log: log.String()})
}
}

if isThereLogs {
allLogs.WriteString(valuesDelimeter)
for containerKey, container := range containers {
//Sort dockerIds by comparing the times of the first logs of each dockerId
sort.Slice(container, func(i, j int) bool {
return container[i].logs[0].time.Before(container[j].logs[0].time)
})
for _, dockerId := range container {
allLogs.WriteString(fmt.Sprintf("%sContainer Name: %s, DockerID: %s\n%s", valuesDelimeter, containerKey, dockerId.name, valuesDelimeter))
//Sort logs in the stream
sort.Slice(dockerId.logs, func(i, j int) bool {
return dockerId.logs[i].time.Before(dockerId.logs[j].time)
})
for _, log := range dockerId.logs {
allLogs.WriteString(log.time.String() + log.log)
}
}
}

return allLogs.String()
}

func parseTimeInRFC(unixTime string) string {
func parseTimeInRFC(unixTime string) time.Time {
intTime, err := strconv.ParseInt(unixTime, 10, 64)
checkError(err)

return time.Unix(0, intTime).String()
return time.Unix(0, intTime)
}

func parseLogMessage(logMsg string) logMessage {
Expand All @@ -1009,3 +1049,29 @@ func parseLogMessage(logMsg string) logMessage {

return log
}

func getTerminalWidth() int {
cmd := exec.Command("stty", "size")
cmd.Stdin = os.Stdin
out, err := cmd.Output()
if err != nil {
return 20
}

size, err := strconv.Atoi(strings.Fields(string(out))[1])
if err != nil {
return 20
}

return size
}

func findDockerIdIndex(dockerIds []dockerIds, id string) int {
for idx, dockerId := range dockerIds {
if dockerId.name == id {
return idx
}
}

return -1
}

0 comments on commit 9c80b36

Please sign in to comment.