-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlog_file_reader.go
135 lines (115 loc) · 3.79 KB
/
log_file_reader.go
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
127
128
129
130
131
132
133
134
135
package main
import (
"bufio"
"fmt"
"golang.org/x/exp/slices"
"io"
"strings"
)
type LogFileReader struct {
pathTransformingRules []PathTransformingRule
targetPaths []string
}
func NewLogFileReader(paths []PathTransformingRule, targetPaths []string) *LogFileReader {
return &LogFileReader{pathTransformingRules: paths, targetPaths: targetPaths}
}
func (p *LogFileReader) Read(r io.Reader) (map[string]*Metric, error) {
scanner := bufio.NewScanner(r)
metricMap := map[string]*Metric{}
for scanner.Scan() {
text := scanner.Text()
r, err := NewAlbLogRecord(text, p.pathTransformingRules)
if err != nil {
fmt.Printf("failed to read alb log record: %s\n", text)
return nil, err
}
if slices.Contains(p.targetPaths, r.RequestPath) {
metricKey := r.MetricKey()
// When metricMap doesn't have key of `metricsKey`, add new Metrics.
if _, ok := metricMap[metricKey]; !ok {
metricMap[metricKey] = &Metric{
RequestCountMap: map[Timestamp]RequestCount{},
TargetProcessingTimesMap: map[Timestamp]TargetProcessingTimes{},
Method: r.RequestMethod,
Path: r.RequestPath,
ElbStatusCode: r.ElbStatusCode,
TargetStatusCode: r.TargetStatusCode,
Elb: r.Elb,
TargetGroupArn: r.TargetGroupArn,
}
}
metric := metricMap[metricKey]
// When RequestCountMap of metric doesn't have key of timestamp, initialize value to 1.
// When RequestCountMap of metric have key of timestamp, increment value.
if _, exist := metric.RequestCountMap[r.Timestamp()]; exist {
metric.RequestCountMap[r.Timestamp()] = metric.RequestCountMap[r.Timestamp()] + RequestCount(1)
} else {
metric.RequestCountMap[r.Timestamp()] = RequestCount(1)
}
// TargetProcessingTime is -1 when load balancer can't dispatch request to target or target doesn't respond until idle timeout.
// see: https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/load-balancer-access-logs.html
if r.TargetProcessingTime != -1 {
if _, exist := metric.RequestCountMap[r.Timestamp()]; exist {
metric.TargetProcessingTimesMap[r.Timestamp()] = append(metric.TargetProcessingTimesMap[r.Timestamp()], TargetProcessingTime(r.TargetProcessingTime))
} else {
metric.TargetProcessingTimesMap[r.Timestamp()] = TargetProcessingTimes{TargetProcessingTime(r.TargetProcessingTime)}
}
}
metricMap[metricKey] = metric
}
}
return metricMap, nil
}
type Timestamp int64
func (ts *Timestamp) PtrInt64() *int64 {
v := int64(*ts)
return &v
}
func (ts *Timestamp) PtrFloat64() *float64 {
v := float64(*ts)
return &v
}
type RequestCount float64
func (c *RequestCount) PtrFloat64() *float64 {
v := float64(*c)
return &v
}
type TargetProcessingTime float64
func (t *TargetProcessingTime) PtrFloat64() *float64 {
v := float64(*t)
return &v
}
type TargetProcessingTimes []TargetProcessingTime
func (t *TargetProcessingTimes) Float64() *[]float64 {
r := make([]float64, len(*t))
for i, f := range *t {
r[i] = float64(f)
}
return &r
}
type Metric struct {
RequestCountMap map[Timestamp]RequestCount
TargetProcessingTimesMap map[Timestamp]TargetProcessingTimes
Method string
Path string
ElbStatusCode string
TargetStatusCode string
Elb string
TargetGroupArn string
}
func (m *Metric) TargetStatusCodeGroup() string {
code := ""
switch {
case strings.HasPrefix(m.TargetStatusCode, "1"):
code = "1xx"
case strings.HasPrefix(m.TargetStatusCode, "2"):
code = "2xx"
case strings.HasPrefix(m.TargetStatusCode, "3"):
code = "3xx"
case strings.HasPrefix(m.TargetStatusCode, "4"):
code = "4xx"
case strings.HasPrefix(m.TargetStatusCode, "5"):
code = "5xx"
}
return code
}