mirror of
https://github.com/golang/go
synced 2024-11-18 13:34:41 -07:00
81ef4df1d3
These are changes to treat errors more like responses. They are important for the forthcoming log viewer. Change-Id: Ief8de6ecea716673d4aee417de205842ceab4fc8 Reviewed-on: https://go-review.googlesource.com/c/tools/+/213124 Run-TryBot: Rebecca Stambler <rstambler@golang.org> Reviewed-by: Robert Findley <rfindley@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
127 lines
2.9 KiB
Go
127 lines
2.9 KiB
Go
// Copyright 2019 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package parse
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"strings"
|
|
)
|
|
|
|
// Rlog contains the processed logs
|
|
type Rlog struct {
|
|
Logs []*Logmsg // In the order in the log file
|
|
ServerCall map[string]*Logmsg // ID->Request, client->server
|
|
ServerReply map[string]*Logmsg // ID->Response, server->client (includes Errors)
|
|
ClientCall map[string]*Logmsg
|
|
ClientReply map[string]*Logmsg
|
|
ClientNotifs []*Logmsg
|
|
ServerNotifs []*Logmsg
|
|
Histogram *LogHist
|
|
}
|
|
|
|
func newRlog(x []*Logmsg) *Rlog {
|
|
return &Rlog{Logs: x,
|
|
ServerCall: make(map[string]*Logmsg),
|
|
ServerReply: make(map[string]*Logmsg),
|
|
ClientCall: make(map[string]*Logmsg),
|
|
ClientReply: make(map[string]*Logmsg),
|
|
ClientNotifs: []*Logmsg{},
|
|
ServerNotifs: []*Logmsg{},
|
|
Histogram: &LogHist{},
|
|
}
|
|
}
|
|
|
|
// Counts returns a one-line summary of an Rlog
|
|
func (r *Rlog) Counts() string {
|
|
return fmt.Sprintf("logs:%d srvC:%d srvR:%d clC:%d clR:%d clN:%d srvN:%d",
|
|
len(r.Logs),
|
|
len(r.ServerCall), len(r.ServerReply), len(r.ClientCall), len(r.ClientReply),
|
|
len(r.ClientNotifs), len(r.ServerNotifs))
|
|
}
|
|
|
|
// ToRlog reads a log file and returns a *Rlog
|
|
func ToRlog(fname string) (*Rlog, error) {
|
|
x, err := ReadLogs(fname)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ans := newRlog(x)
|
|
for _, l := range x {
|
|
switch l.Type {
|
|
case ClRequest:
|
|
ans.ServerCall[l.ID] = l
|
|
case ClResponse:
|
|
ans.ServerReply[l.ID] = l
|
|
if l.Type != ReportErr {
|
|
n := 0
|
|
fmt.Sscanf(l.Elapsed, "%d", &n)
|
|
ans.Histogram.add(n)
|
|
}
|
|
case SvRequest:
|
|
ans.ClientCall[l.ID] = l
|
|
case SvResponse:
|
|
ans.ClientReply[l.ID] = l
|
|
case ToClient:
|
|
ans.ClientNotifs = append(ans.ClientNotifs, l)
|
|
case ToServer:
|
|
ans.ServerNotifs = append(ans.ServerNotifs, l)
|
|
case ReportErr:
|
|
ans.ServerReply[l.ID] = l
|
|
l.Method = ans.ServerCall[l.ID].Method // Method not in log message
|
|
default:
|
|
log.Fatalf("eh? %s/%s (%s)", l.Type, l.Method, l.ID)
|
|
}
|
|
}
|
|
return ans, nil
|
|
}
|
|
|
|
// LogHist gets ints, and puts them into buckets:
|
|
// <=10, <=30, 100, 300, 1000, ...
|
|
// It produces a historgram of elapsed times in milliseconds
|
|
type LogHist struct {
|
|
cnts []int
|
|
}
|
|
|
|
func (l *LogHist) add(n int) {
|
|
if n < 0 {
|
|
n = 0
|
|
}
|
|
bucket := 0
|
|
for ; n > 0; n /= 10 {
|
|
if n < 10 {
|
|
break
|
|
}
|
|
if n < 30 {
|
|
bucket++
|
|
break
|
|
}
|
|
bucket += 2
|
|
}
|
|
if len(l.cnts) <= bucket {
|
|
for j := len(l.cnts); j < bucket+10; j++ {
|
|
l.cnts = append(l.cnts, 0)
|
|
}
|
|
}
|
|
l.cnts[bucket]++
|
|
}
|
|
|
|
// String returns a string describing a histogram
|
|
func (l *LogHist) String() string {
|
|
top := len(l.cnts) - 1
|
|
for ; top > 0 && l.cnts[top] == 0; top-- {
|
|
}
|
|
labs := []string{"10", "30"}
|
|
out := strings.Builder{}
|
|
out.WriteByte('[')
|
|
for i := 0; i <= top; i++ {
|
|
label := labs[i%2]
|
|
labs[i%2] += "0"
|
|
fmt.Fprintf(&out, "%s:%d ", label, l.cnts[i])
|
|
}
|
|
out.WriteByte(']')
|
|
return out.String()
|
|
}
|