perf(recovery): optimize the log output of CustomRecoveryWithWriter#4258
Merged
appleboy merged 1 commit intogin-gonic:masterfrom Aug 2, 2025
Merged
perf(recovery): optimize the log output of CustomRecoveryWithWriter#4258appleboy merged 1 commit intogin-gonic:masterfrom
appleboy merged 1 commit intogin-gonic:masterfrom
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #4258 +/- ##
==========================================
- Coverage 99.21% 98.92% -0.30%
==========================================
Files 42 44 +2
Lines 3182 3435 +253
==========================================
+ Hits 3157 3398 +241
- Misses 17 26 +9
- Partials 8 11 +3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Contributor
Author
secureRequestDump test codepackage recovery
import (
"net/http"
"net/http/httputil"
"strings"
"testgolang/gin/bytesconv"
"testing"
)
func maskHeaders(r *http.Request) string {
httpRequest, _ := httputil.DumpRequest(r, false)
headers := strings.Split(string(httpRequest), "\r\n")
maskAuthorization(headers)
return strings.Join(headers, "\r\n")
}
func maskAuthorization(headers []string) {
for idx, header := range headers {
key, _, _ := strings.Cut(header, ":")
if strings.EqualFold(key, "Authorization") {
headers[idx] = key + ": *"
}
}
}
func secureRequestDump(r *http.Request) string {
httpRequest, _ := httputil.DumpRequest(r, false)
lines := strings.Split(bytesconv.BytesToString(httpRequest), "\r\n")
for i, line := range lines {
if strings.HasPrefix(line, "Authorization:") {
lines[i] = "Authorization: *"
}
}
return strings.Join(lines, "\r\n")
}
func makeTestRequest() *http.Request {
req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
req.Header.Set("Authorization", "Bearer secret-token")
req.Header.Set("User-Agent", "GoTest")
return req
}
var (
stringRes string
)
func BenchmarkMaskHeaders(b *testing.B) {
b.Run("original", func(b *testing.B) {
req := makeTestRequest()
var bStringRes string
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
bStringRes = maskHeaders(req)
}
stringRes = bStringRes
})
b.Run("optimized", func(b *testing.B) {
req := makeTestRequest()
var bStringRes string
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
bStringRes = secureRequestDump(req)
}
stringRes = bStringRes
})
}benchmark secureRequestDump outputhey load testrecovery test codepackage main
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
gin.SetMode(gin.ReleaseMode)
r := gin.New()
r.Use(gin.CustomRecoveryWithWriter(gin.DefaultErrorWriter, func(c *gin.Context, err any) {
c.JSON(http.StatusInternalServerError, gin.H{
"message": "internal error",
})
}))
r.GET("/panic", func(c *gin.Context) {
panic("trigger panic")
})
err := r.Run(":8080")
if err != nil {
log.Fatal(err)
}
}hey commandhey -n 100000 -c 100 http://localhost:8080/panicbenchmark results before optimization using hey hey -n 100000 -c 100 http://localhost:8080/panic
Summary:
Total: 25.3032 secs
Slowest: 0.3537 secs
Fastest: 0.0005 secs
Average: 0.0245 secs
Requests/sec: 3952.0755
Total data: 2800000 bytes
Size/request: 28 bytes
Response time histogram:
0.001 [1] |
0.036 [73128] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.071 [18003] |■■■■■■■■■■
0.106 [6049] |■■■
0.142 [1955] |■
0.177 [618] |
0.212 [169] |
0.248 [51] |
0.283 [18] |
0.318 [5] |
0.354 [3] |
Latency distribution:
10% in 0.0013 secs
25% in 0.0024 secs
50% in 0.0061 secs
75% in 0.0374 secs
90% in 0.0679 secs
95% in 0.0896 secs
99% in 0.1376 secs
Details (average, fastest, slowest):
DNS+dialup: 0.0000 secs, 0.0005 secs, 0.3537 secs
DNS-lookup: 0.0000 secs, 0.0000 secs, 0.0075 secs
req write: 0.0000 secs, 0.0000 secs, 0.0037 secs
resp wait: 0.0245 secs, 0.0005 secs, 0.3537 secs
resp read: 0.0000 secs, 0.0000 secs, 0.0030 secs
Status code distribution:
[500] 100000 responsesbenchmark results after optimization using heyhey -n 100000 -c 100 http://localhost:8080/panic
Summary:
Total: 24.2673 secs
Slowest: 0.3359 secs
Fastest: 0.0005 secs
Average: 0.0237 secs
Requests/sec: 4120.7731
Total data: 2800000 bytes
Size/request: 28 bytes
Response time histogram:
0.001 [1] |
0.034 [72225] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.068 [18400] |■■■■■■■■■■
0.101 [6245] |■■■
0.135 [2095] |■
0.168 [708] |
0.202 [222] |
0.235 [66] |
0.269 [28] |
0.302 [8] |
0.336 [2] |
Latency distribution:
10% in 0.0013 secs
25% in 0.0024 secs
50% in 0.0057 secs
75% in 0.0362 secs
90% in 0.0660 secs
95% in 0.0872 secs
99% in 0.1356 secs
Details (average, fastest, slowest):
DNS+dialup: 0.0000 secs, 0.0005 secs, 0.3359 secs
DNS-lookup: 0.0000 secs, 0.0000 secs, 0.0071 secs
req write: 0.0000 secs, 0.0000 secs, 0.0036 secs
resp wait: 0.0236 secs, 0.0005 secs, 0.3359 secs
resp read: 0.0000 secs, 0.0000 secs, 0.0030 secs
Status code distribution:
[500] 100000 responses |
Contributor
Author
|
I've just updated this pull request. Compared to the previous version of the pull request, the code is now more simplified and offers higher performance. Please help review this pull request. |
appleboy
approved these changes
Jul 25, 2025
ubutatu
approved these changes
Apr 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
stackandsecureRequestDumpinto conditional blocks so they only execute when needed.Authorizationheader .secureRequestDump, accounting for the fact thathttputil.DumpRequestnormalizes all header keys (e.g., "authorization" or "AUTHORIZATION", and so on) to "Authorization".