-
Notifications
You must be signed in to change notification settings - Fork 2
/
middlewares.go
113 lines (104 loc) · 2.76 KB
/
middlewares.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
package rock
import (
"errors"
"fmt"
"net/http"
"strings"
"time"
"github.com/byte-power/rockgo/util"
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/context"
)
const apiPrefix = "api."
const timecostSuffix = ".timecost"
const statusCodeSuffixOK = ".ok"
type panicHandlerProvider interface {
PanicHandler() PanicHandler
}
func newRockMiddleware(provider panicHandlerProvider) context.Handler {
return func(ctx iris.Context) {
startHandleTime := time.Now()
defer func() {
recovered := recover()
if recovered != nil {
var err error
switch v := recovered.(type) {
case error:
err = v
case string:
err = errors.New(v)
default:
err = errors.New(util.AnyToString(v))
}
var fn PanicHandler
if provider != nil {
fn = provider.PanicHandler()
}
if fn != nil {
fn(ctx, err)
} else {
ctx.StatusCode(http.StatusInternalServerError)
ctx.JSON(util.AnyMap{"error": err.Error()})
}
}
recordMetric(ctx, startHandleTime)
}()
ctx.Next()
}
}
func recordMetric(ctx iris.Context, startHandleTime time.Time) {
route := ctx.GetCurrentRoute()
if route == nil || Metric() == nil {
return
}
name := strings.ReplaceAll(strings.Trim(route.Path(), "/"), "/", ".")
if name == "" {
name = "/"
}
code := ctx.GetStatusCode()
dur := time.Now().Sub(startHandleTime)
method := strings.ToLower(ctx.Method())
var codeExpl string
if code > 100 && code < 400 {
codeExpl = statusCodeSuffixOK
} else if code >= 400 && code < 500 {
codeExpl = ".4xx"
} else if code >= 500 {
codeExpl = fmt.Sprintf(".%v", code)
}
var buf strings.Builder
// count: api.all
MetricIncrease(writeStrings(&buf, apiPrefix, "all"))
// timecost: api.all.timecost
buf.WriteString(timecostSuffix)
MetricTimeDuration(buf.String(), dur)
for _, suffix := range []string{method, "all"} {
// count: api.{path}.[{method}|all]
MetricIncrease(writeStrings(&buf, apiPrefix, name, ".", suffix))
if codeExpl != "" {
// count: api.{path}.[{method}|all].[ok|4xx|5xx]
buf.WriteString(codeExpl)
MetricIncrease(buf.String())
}
}
// timecost: api.{path}.all.timecost
MetricTimeDuration(writeStrings(&buf, apiPrefix, name, ".all", timecostSuffix), dur)
if codeExpl != "" {
// count: api.all.[ok|4xx|5xx]
MetricIncrease(writeStrings(&buf, apiPrefix, "all", codeExpl))
// count: api.all.[ok|4xx|5xx].timecost
buf.WriteString(timecostSuffix)
MetricTimeDuration(buf.String(), dur)
if codeExpl == statusCodeSuffixOK {
// timecost: api.{path}.all.ok.timecost
MetricTimeDuration(writeStrings(&buf, apiPrefix, name, ".all", codeExpl, timecostSuffix), dur)
}
}
}
func writeStrings(buf *strings.Builder, strs ...string) string {
buf.Reset()
for _, str := range strs {
buf.WriteString(str)
}
return buf.String()
}