1
0
out-of-tree/cmd/log.go

331 lines
6.8 KiB
Go
Raw Normal View History

2024-10-09 09:53:22 +00:00
// Copyright 2024 Mikhail Klementev. All rights reserved.
// Use of this source code is governed by a AGPLv3 license
// (or later) that can be found in the LICENSE file.
2024-02-17 22:38:43 +00:00
package cmd
import (
"database/sql"
2019-08-16 19:31:58 +00:00
"encoding/json"
"fmt"
"math"
"os"
"github.com/olekukonko/tablewriter"
2023-03-18 21:30:07 +00:00
"github.com/rs/zerolog/log"
"gopkg.in/logrusorgru/aurora.v2"
2024-02-20 13:25:31 +00:00
"code.dumpstack.io/tools/out-of-tree/artifact"
)
2023-01-31 07:13:33 +00:00
type LogCmd struct {
Query LogQueryCmd `cmd:"" help:"query logs"`
Dump LogDumpCmd `cmd:"" help:"show all info for log entry with ID"`
Json LogJsonCmd `cmd:"" help:"generate json statistics"`
2023-02-15 16:57:31 +00:00
Markdown LogMarkdownCmd `cmd:"" help:"generate markdown statistics"`
2023-01-31 07:13:33 +00:00
}
2023-01-31 07:13:33 +00:00
type LogQueryCmd struct {
Num int `help:"how much lines" default:"50"`
Rate bool `help:"show artifact success rate"`
Tag string `help:"filter tag"`
}
2023-01-31 07:13:33 +00:00
func (cmd *LogQueryCmd) Run(g *Globals) (err error) {
db, err := openDatabase(g.Config.Database)
if err != nil {
2023-03-18 21:30:07 +00:00
panic(err)
}
2023-01-31 07:13:33 +00:00
defer db.Close()
var les []logEntry
2024-02-20 13:25:31 +00:00
ka, kaErr := artifact.Artifact{}.Read(g.WorkDir + "/.out-of-tree.toml")
if kaErr == nil {
2024-05-23 10:19:46 +00:00
log.Debug().Msg(".out-of-tree.toml found, filter by artifact name")
2023-01-31 07:13:33 +00:00
les, err = getAllArtifactLogs(db, cmd.Tag, cmd.Num, ka)
} else {
2023-01-31 07:13:33 +00:00
les, err = getAllLogs(db, cmd.Tag, cmd.Num)
}
if err != nil {
return
}
s := "\nS"
2023-01-31 07:13:33 +00:00
if cmd.Rate {
if kaErr != nil {
err = kaErr
return
}
s = fmt.Sprintf("{[%s] %s} Overall s", ka.Type, ka.Name)
2023-01-31 07:13:33 +00:00
les, err = getAllArtifactLogs(db, cmd.Tag, math.MaxInt64, ka)
if err != nil {
return
}
} else {
for _, l := range les {
logLogEntry(l)
}
}
success := 0
for _, l := range les {
if l.Test.Ok {
2019-08-17 08:51:42 +00:00
success++
}
}
overall := float64(success) / float64(len(les))
fmt.Printf("%success rate: %.04f (~%.0f%%)\n",
s, overall, overall*100)
return
}
2023-01-31 07:13:33 +00:00
type LogDumpCmd struct {
ID int `help:"id" default:"-1"`
}
func (cmd *LogDumpCmd) Run(g *Globals) (err error) {
db, err := openDatabase(g.Config.Database)
if err != nil {
2023-03-18 21:30:07 +00:00
panic(err)
2023-01-31 07:13:33 +00:00
}
defer db.Close()
2020-06-14 20:46:56 +00:00
var l logEntry
2023-01-31 07:13:33 +00:00
if cmd.ID > 0 {
l, err = getLogByID(db, cmd.ID)
2020-06-14 20:46:56 +00:00
} else {
l, err = getLastLog(db)
}
if err != nil {
return
}
fmt.Println("ID:", l.ID)
fmt.Println("Date:", l.Timestamp.Format("2006-01-02 15:04"))
2019-08-16 18:30:46 +00:00
fmt.Println("Tag:", l.Tag)
fmt.Println()
fmt.Println("Type:", l.Type.String())
fmt.Println("Name:", l.Name)
fmt.Println()
fmt.Println("Distro:", l.Distro.ID.String(), l.Distro.Release)
fmt.Println("Kernel:", l.KernelRelease)
fmt.Println()
fmt.Println("Build ok:", l.Build.Ok)
2024-02-20 13:25:31 +00:00
if l.Type == artifact.KernelModule {
fmt.Println("Insmod ok:", l.Run.Ok)
}
fmt.Println("Test ok:", l.Test.Ok)
fmt.Println()
fmt.Printf("Build output:\n%s\n", l.Build.Output)
fmt.Println()
2024-02-20 13:25:31 +00:00
if l.Type == artifact.KernelModule {
fmt.Printf("Insmod output:\n%s\n", l.Run.Output)
fmt.Println()
}
fmt.Printf("Test output:\n%s\n", l.Test.Output)
fmt.Println()
fmt.Printf("Qemu stdout:\n%s\n", l.Stdout)
fmt.Println()
fmt.Printf("Qemu stderr:\n%s\n", l.Stderr)
fmt.Println()
return
}
2019-08-16 19:31:58 +00:00
2023-01-31 07:13:33 +00:00
type LogJsonCmd struct {
Tag string `required:"" help:"filter tag"`
}
func (cmd *LogJsonCmd) Run(g *Globals) (err error) {
db, err := openDatabase(g.Config.Database)
if err != nil {
2023-03-18 21:30:07 +00:00
panic(err)
2023-01-31 07:13:33 +00:00
}
defer db.Close()
distros, err := getStats(db, g.WorkDir, cmd.Tag)
if err != nil {
return
}
bytes, err := json.Marshal(&distros)
if err != nil {
return
}
fmt.Println(string(bytes))
return
}
type LogMarkdownCmd struct {
Tag string `required:"" help:"filter tag"`
}
func (cmd *LogMarkdownCmd) Run(g *Globals) (err error) {
db, err := openDatabase(g.Config.Database)
if err != nil {
2023-03-18 21:30:07 +00:00
panic(err)
2023-01-31 07:13:33 +00:00
}
defer db.Close()
distros, err := getStats(db, g.WorkDir, cmd.Tag)
if err != nil {
return
}
table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"Distro", "Release", "Kernel", "Reliability"})
table.SetBorders(tablewriter.Border{
Left: true, Top: false, Right: true, Bottom: false})
table.SetCenterSeparator("|")
for distro, releases := range distros {
for release, kernels := range releases {
for kernel, stats := range kernels {
all := float64(stats.All)
ok := float64(stats.TestOK)
r := fmt.Sprintf("%6.02f%%", (ok/all)*100)
table.Append([]string{distro, release, kernel, r})
}
}
}
table.Render()
return
}
func center(s string, w int) string {
return fmt.Sprintf("%[1]*s", -w, fmt.Sprintf("%[1]*s", (w+len(s))/2, s))
}
func genOkFailCentered(name string, ok bool) (aurv aurora.Value) {
2024-10-09 09:53:22 +00:00
if ok {
name += " OK"
} else {
name += " FAIL"
}
name = center(name, 14)
if ok {
aurv = aurora.BgGreen(aurora.Black(name))
} else {
aurv = aurora.BgRed(aurora.White(aurora.Bold(name)))
}
return
}
2023-01-31 07:13:33 +00:00
func logLogEntry(l logEntry) {
distroInfo := fmt.Sprintf("%s-%s {%s}", l.Distro.ID,
l.Distro.Release, l.KernelRelease)
2023-01-31 07:13:33 +00:00
2024-10-09 09:53:22 +00:00
artifactInfo := fmt.Sprintf("%s", l.Name)
2023-01-31 07:13:33 +00:00
timestamp := l.Timestamp.Format("2006-01-02 15:04")
var status aurora.Value
if l.InternalErrorString != "" {
status = genOkFailCentered("INTERNAL", false)
2024-02-20 13:25:31 +00:00
} else if l.Type == artifact.KernelExploit {
if l.Build.Ok {
status = genOkFailCentered("LPE", l.Test.Ok)
} else {
status = genOkFailCentered("BUILD", l.Build.Ok)
}
2023-01-31 07:13:33 +00:00
} else {
if l.Build.Ok {
if l.Run.Ok {
status = genOkFailCentered("TEST", l.Test.Ok)
} else {
status = genOkFailCentered("INSMOD", l.Run.Ok)
}
} else {
status = genOkFailCentered("BUILD", l.Build.Ok)
}
2023-01-31 07:13:33 +00:00
}
additional := ""
if l.KernelPanic {
additional = "(panic)"
} else if l.KilledByTimeout {
additional = "(timeout)"
}
2024-10-09 09:53:22 +00:00
if len(distroInfo) > 40 {
distroInfo = distroInfo[:40]
}
colored := aurora.Sprintf("[%4d %4s] [%s] %s %-40s: %s %s",
l.ID, l.Tag, timestamp, artifactInfo, distroInfo, status,
additional)
fmt.Println(colored)
2023-01-31 07:13:33 +00:00
}
2019-08-16 19:31:58 +00:00
type runstat struct {
All, BuildOK, RunOK, TestOK, Timeout, Panic int
}
func getStats(db *sql.DB, path, tag string) (
distros map[string]map[string]map[string]runstat, err error) {
2019-08-16 19:31:58 +00:00
var les []logEntry
2024-02-20 13:25:31 +00:00
ka, kaErr := artifact.Artifact{}.Read(path + "/.out-of-tree.toml")
2019-08-16 19:31:58 +00:00
if kaErr == nil {
les, err = getAllArtifactLogs(db, tag, -1, ka)
} else {
les, err = getAllLogs(db, tag, -1)
}
if err != nil {
return
}
distros = make(map[string]map[string]map[string]runstat)
2019-08-16 19:31:58 +00:00
for _, l := range les {
_, ok := distros[l.Distro.ID.String()]
2019-08-16 19:31:58 +00:00
if !ok {
distros[l.Distro.ID.String()] = make(map[string]map[string]runstat)
2019-08-16 19:31:58 +00:00
}
_, ok = distros[l.Distro.ID.String()][l.Distro.Release]
2019-08-16 19:31:58 +00:00
if !ok {
distros[l.Distro.ID.String()][l.Distro.Release] = make(map[string]runstat)
2019-08-16 19:31:58 +00:00
}
rs := distros[l.Distro.ID.String()][l.Distro.Release][l.KernelRelease]
2019-08-16 19:31:58 +00:00
2019-08-17 08:51:42 +00:00
rs.All++
2019-08-16 19:31:58 +00:00
if l.Build.Ok {
2019-08-17 08:51:42 +00:00
rs.BuildOK++
2019-08-16 19:31:58 +00:00
}
if l.Run.Ok {
2019-08-17 08:51:42 +00:00
rs.RunOK++
2019-08-16 19:31:58 +00:00
}
if l.Test.Ok {
2019-08-17 08:51:42 +00:00
rs.TestOK++
2019-08-16 19:31:58 +00:00
}
if l.KernelPanic {
2019-08-17 08:51:42 +00:00
rs.Panic++
2019-08-16 19:31:58 +00:00
}
if l.KilledByTimeout {
2019-08-17 08:51:42 +00:00
rs.Timeout++
2019-08-16 19:31:58 +00:00
}
distros[l.Distro.ID.String()][l.Distro.Release][l.KernelRelease] = rs
2019-08-16 19:31:58 +00:00
}
return
}