kata-containers/src/tools/log-parser/agent.go
Snir Sheriber c7dacb1211 log-parser: move the kata-log-parser from the tests repo
to the kata-containers repo under the src/tools/log-parser folder
and vendor the modules

Fixes: #4100
Signed-off-by: Snir Sheriber <ssheribe@redhat.com>
2022-05-10 13:23:25 +03:00

166 lines
4.1 KiB
Go

//
// Copyright (c) 2017-2018 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package main
import (
"fmt"
"strconv"
"strings"
"encoding/json"
)
const (
// "source=agent" logs are actually encoded within proxy logs so need
// to be unpacked.
agentSourceField = "agent"
)
// agentLogEntry returns true if the specified log entry actually contains
// an encoded agent log entry.
func agentLogEntry(le LogEntry) bool {
if le.Source != agentSourceField && le.Source != "virtcontainers" {
return false
}
// agent v1 format
msg := le.Msg
if msg == "" {
return false
}
if msg == "reading guest console" {
// v2 format - check if there is actually something on the console
if le.Data["vmconsole"] != "" {
return true
}
} else if strings.HasPrefix(msg, "time=") {
return true
}
return false
}
// unpackAgentLogEntry unpacks the proxy log entry that encodes an agent
// message and returns the agent log entry, discarding the proxy log entry
// that held it.
func unpackAgentLogEntry(le LogEntry) (agent LogEntry, err error) {
if le.Source == agentSourceField {
return unpackAgentLogEntry_v1(le)
}
if le.Msg == "reading guest console" {
return unpackAgentLogEntry_v2(le)
}
return LogEntry{}, fmt.Errorf("agent log entry not found (source: %v - msg: %v): %+v",
le.Source, le.Msg, le)
}
func unpackAgentLogEntry_v1(le LogEntry) (agent LogEntry, err error) {
msg := le.Msg
if msg == "" {
return LogEntry{}, fmt.Errorf("no agent message data (entry %+v", le)
}
file := le.Filename
if file == "" {
return LogEntry{}, fmt.Errorf("filename blank (entry %+v)", le)
}
line := le.Line
if line == 0 {
return LogEntry{}, fmt.Errorf("invalid line number (entry %+v)", le)
}
reader := strings.NewReader(le.Msg)
entries, err := parseLogFmtData(reader, file, false)
if err != nil {
return LogEntry{}, fmt.Errorf("failed to parse agent log entry %+v: %v", le, err)
}
expectedRecords := 1
count := entries.Len()
if count != expectedRecords {
return LogEntry{}, fmt.Errorf("expected %d record, got %d", expectedRecords, count)
}
agent = entries.Entries[0]
// Supplement the agent entry with a few extra details
agent.Count = le.Count
agent.Source = agentSourceField
agent.Filename = file
agent.Line = line
return agent, nil
}
func unpackAgentLogEntry_v2(le LogEntry) (agent LogEntry, err error) {
agent = le
// we expect the agent's message to be in JSON, under le.Data["vmconsole"]
var result map[string]string
err = json.Unmarshal([]byte(le.Data["vmconsole"]), &result)
if err != nil {
// entry is not in JSON format. Use the vmconsole field as the msg, and keep the rest of the log entry unmodified
agent.Msg = le.Data["vmconsole"]
agent.Source = "vmconsole"
return agent, nil
}
// we were able to unpack agent msg, let's drop previous Data (runtime entries)
agent.Data = make(map[string]string)
for k, v := range result {
switch k {
case "container-id", "cid": // better to ensure consistency in the agent
agent.Container = v
case "level":
switch v {
// match agent's slog short version log leveling to the common log levels
case "CRIT":
agent.Level = "critical"
case "DEBG":
agent.Level = "debug"
case "ERRO":
agent.Level = "error"
case "INFO":
agent.Level = "info"
case "TRCE":
agent.Level = "trace"
case "WARN":
agent.Level = "warning"
default:
agent.Level = v
}
agent.Data[k] = v // in any case let's leave original level under Data
case "msg":
agent.Msg = v
case "name":
agent.Name = v
case "pid":
pid, err := strconv.Atoi(v)
if err != nil {
return LogEntry{}, fmt.Errorf("failed to convert pid")
}
agent.Pid = pid
case "source":
agent.Source = v
default:
// NOTE: we do not take the agent's timestamp into account, because there is a ~1sec delay
// for the agent's log to get through. Using the agent's timestamp would then make its logs
// appear out of order compared to other logs from the guest.
// The agent's logs timestamp is still visible for reference in the Data section of the logs.
agent.Data[k] = v
}
}
return agent, nil
}