File: rlog.go

package info (click to toggle)
golang-golang-x-tools 1%3A0.1.0%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 12,588 kB
  • sloc: javascript: 2,011; asm: 1,458; sh: 174; yacc: 155; makefile: 21; ansic: 17
file content (126 lines) | stat: -rw-r--r-- 2,973 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// 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()
}