Skip to content

Commit 4408841

Browse files
authored
feat(handler): add sseSlowThreshold (#5196)
1 parent 271f105 commit 4408841

File tree

2 files changed

+122
-6
lines changed

2 files changed

+122
-6
lines changed

rest/handler/loghandler.go

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,16 @@ import (
2424
)
2525

2626
const (
27-
limitBodyBytes = 1024
28-
limitDetailedBodyBytes = 4096
29-
defaultSlowThreshold = time.Millisecond * 500
27+
limitBodyBytes = 1024
28+
limitDetailedBodyBytes = 4096
29+
defaultSlowThreshold = time.Millisecond * 500
30+
defaultSSESlowThreshold = time.Minute * 3
3031
)
3132

32-
var slowThreshold = syncx.ForAtomicDuration(defaultSlowThreshold)
33+
var (
34+
slowThreshold = syncx.ForAtomicDuration(defaultSlowThreshold)
35+
sseSlowThreshold = syncx.ForAtomicDuration(defaultSSESlowThreshold)
36+
)
3337

3438
// LogHandler returns a middleware that logs http request and response.
3539
func LogHandler(next http.Handler) http.Handler {
@@ -109,6 +113,11 @@ func SetSlowThreshold(threshold time.Duration) {
109113
slowThreshold.Set(threshold)
110114
}
111115

116+
// SetSSESlowThreshold sets the slow threshold for SSE requests.
117+
func SetSSESlowThreshold(threshold time.Duration) {
118+
sseSlowThreshold.Set(threshold)
119+
}
120+
112121
func dumpRequest(r *http.Request) string {
113122
reqContent, err := httputil.DumpRequest(r, true)
114123
if err != nil {
@@ -129,7 +138,8 @@ func logBrief(r *http.Request, code int, timer *utils.ElapsedTimer, logs *intern
129138
logger := logx.WithContext(r.Context()).WithDuration(duration)
130139
buf.WriteString(fmt.Sprintf("[HTTP] %s - %s %s - %s - %s",
131140
wrapStatusCode(code), wrapMethod(r.Method), r.RequestURI, httpx.GetRemoteAddr(r), r.UserAgent()))
132-
if duration > slowThreshold.Load() {
141+
142+
if duration > getSlowThreshold(r) {
133143
logger.Slowf("[HTTP] %s - %s %s - %s - %s - slowcall(%s)",
134144
wrapStatusCode(code), wrapMethod(r.Method), r.RequestURI, httpx.GetRemoteAddr(r), r.UserAgent(),
135145
timex.ReprOfDuration(duration))
@@ -160,7 +170,8 @@ func logDetails(r *http.Request, response *detailLoggedResponseWriter, timer *ut
160170
logger := logx.WithContext(r.Context())
161171
buf.WriteString(fmt.Sprintf("[HTTP] %s - %d - %s - %s\n=> %s\n",
162172
r.Method, code, r.RemoteAddr, timex.ReprOfDuration(duration), dumpRequest(r)))
163-
if duration > slowThreshold.Load() {
173+
174+
if duration > getSlowThreshold(r) {
164175
logger.Slowf("[HTTP] %s - %d - %s - slowcall(%s)\n=> %s\n", r.Method, code, r.RemoteAddr,
165176
timex.ReprOfDuration(duration), dumpRequest(r))
166177
}
@@ -223,3 +234,12 @@ func wrapStatusCode(code int) string {
223234

224235
return logx.WithColorPadding(strconv.Itoa(code), colour)
225236
}
237+
238+
func getSlowThreshold(r *http.Request) time.Duration {
239+
threshold := slowThreshold.Load()
240+
if r.Header.Get(headerAccept) == valueSSE {
241+
threshold = sseSlowThreshold.Load()
242+
}
243+
244+
return threshold
245+
}

rest/handler/loghandler_test.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,96 @@ func TestLogHandlerSlow(t *testing.T) {
8888
}
8989
}
9090

91+
func TestLogHandlerSSE(t *testing.T) {
92+
handlers := []func(handler http.Handler) http.Handler{
93+
LogHandler,
94+
DetailedLogHandler,
95+
}
96+
97+
for _, logHandler := range handlers {
98+
t.Run("SSE request with normal duration", func(t *testing.T) {
99+
req := httptest.NewRequest(http.MethodGet, "http://localhost", http.NoBody)
100+
req.Header.Set(headerAccept, valueSSE)
101+
102+
handler := logHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
103+
time.Sleep(defaultSlowThreshold + time.Second)
104+
w.WriteHeader(http.StatusOK)
105+
}))
106+
107+
resp := httptest.NewRecorder()
108+
handler.ServeHTTP(resp, req)
109+
assert.Equal(t, http.StatusOK, resp.Code)
110+
})
111+
112+
t.Run("SSE request exceeding SSE threshold", func(t *testing.T) {
113+
originalThreshold := sseSlowThreshold.Load()
114+
SetSSESlowThreshold(time.Millisecond * 100)
115+
defer SetSSESlowThreshold(originalThreshold)
116+
117+
req := httptest.NewRequest(http.MethodGet, "http://localhost", http.NoBody)
118+
req.Header.Set(headerAccept, valueSSE)
119+
120+
handler := logHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
121+
time.Sleep(time.Millisecond * 150)
122+
w.WriteHeader(http.StatusOK)
123+
}))
124+
125+
resp := httptest.NewRecorder()
126+
handler.ServeHTTP(resp, req)
127+
assert.Equal(t, http.StatusOK, resp.Code)
128+
})
129+
}
130+
}
131+
132+
func TestLogHandlerThresholdSelection(t *testing.T) {
133+
tests := []struct {
134+
name string
135+
acceptHeader string
136+
expectedIsSSE bool
137+
}{
138+
{
139+
name: "Regular HTTP request",
140+
acceptHeader: "text/html",
141+
expectedIsSSE: false,
142+
},
143+
{
144+
name: "SSE request",
145+
acceptHeader: valueSSE,
146+
expectedIsSSE: true,
147+
},
148+
{
149+
name: "No Accept header",
150+
acceptHeader: "",
151+
expectedIsSSE: false,
152+
},
153+
}
154+
155+
for _, tt := range tests {
156+
t.Run(tt.name, func(t *testing.T) {
157+
req := httptest.NewRequest(http.MethodGet, "http://localhost", http.NoBody)
158+
if tt.acceptHeader != "" {
159+
req.Header.Set(headerAccept, tt.acceptHeader)
160+
}
161+
162+
SetSlowThreshold(time.Millisecond * 100)
163+
SetSSESlowThreshold(time.Millisecond * 200)
164+
defer func() {
165+
SetSlowThreshold(defaultSlowThreshold)
166+
SetSSESlowThreshold(defaultSSESlowThreshold)
167+
}()
168+
169+
handler := LogHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
170+
time.Sleep(time.Millisecond * 150)
171+
w.WriteHeader(http.StatusOK)
172+
}))
173+
174+
resp := httptest.NewRecorder()
175+
handler.ServeHTTP(resp, req)
176+
assert.Equal(t, http.StatusOK, resp.Code)
177+
})
178+
}
179+
}
180+
91181
func TestDetailedLogHandler_LargeBody(t *testing.T) {
92182
lbuf := logtest.NewCollector(t)
93183

@@ -139,6 +229,12 @@ func TestSetSlowThreshold(t *testing.T) {
139229
assert.Equal(t, time.Second, slowThreshold.Load())
140230
}
141231

232+
func TestSetSSESlowThreshold(t *testing.T) {
233+
assert.Equal(t, defaultSSESlowThreshold, sseSlowThreshold.Load())
234+
SetSSESlowThreshold(time.Minute * 10)
235+
assert.Equal(t, time.Minute*10, sseSlowThreshold.Load())
236+
}
237+
142238
func TestWrapMethodWithColor(t *testing.T) {
143239
// no tty
144240
assert.Equal(t, http.MethodGet, wrapMethod(http.MethodGet))

0 commit comments

Comments
 (0)