1
0
out-of-tree/log.go

300 lines
6.2 KiB
Go
Raw Normal View History

2023-01-31 07:13:33 +00:00
// Copyright 2023 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.
package main
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"
"code.dumpstack.io/tools/out-of-tree/config"
)
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
2023-01-31 07:13:33 +00:00
ka, kaErr := config.ReadArtifactConfig(g.WorkDir + "/.out-of-tree.toml")
if kaErr == nil {
2023-03-18 21:30:07 +00:00
log.Print(".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)
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)
if l.Type == config.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()
if l.Type == config.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 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
artifactInfo := fmt.Sprintf("{[%s] %s}", l.Type, l.Name)
colored := ""
if l.Type == config.KernelExploit {
colored = aurora.Sprintf("[%4d %4s] [%s] %40s %40s: %s %s",
l.ID, l.Tag, l.Timestamp, artifactInfo, distroInfo,
genOkFail("BUILD", l.Build.Ok),
genOkFail("LPE", l.Test.Ok))
} else {
colored = aurora.Sprintf("[%4d %4s] [%s] %40s %40s: %s %s %s",
l.ID, l.Tag, l.Timestamp, artifactInfo, distroInfo,
genOkFail("BUILD", l.Build.Ok),
genOkFail("INSMOD", l.Run.Ok),
genOkFail("TEST", l.Test.Ok))
}
additional := ""
if l.KernelPanic {
additional = "(panic)"
} else if l.KilledByTimeout {
additional = "(timeout)"
}
if additional != "" {
fmt.Println(colored, additional)
} else {
fmt.Println(colored)
}
}
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
ka, kaErr := config.ReadArtifactConfig(path + "/.out-of-tree.toml")
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
}