Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 2024-05-23 - Flag Parsing Performance
**Learning:** `kingpin` flags are global variables but accessing and processing their values (e.g. `strings.Split` on a comma-separated list) inside a hot path (like HTTP request parsing) can cause significant overhead due to repeated allocations.
**Action:** Cache the processed value of configuration flags, especially for high-frequency operations. Use `sync.RWMutex` or `atomic.Value` to ensure thread-safe access if the flag value can change (even if only in tests).
51 changes: 41 additions & 10 deletions ebpftracer/l7/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,50 @@ import (
"net/http"
"net/url"
"strings"
"sync"
"unicode/utf8"

"github.com/coroot/coroot-node-agent/flags"
)

var (
sensitiveHeadersCache map[string]bool
sensitiveHeadersMu sync.RWMutex
lastSensitiveHeader string
)

func getSensitiveHeaders() map[string]bool {
currentHeader := ""
if flags.SensitiveHeader != nil {
currentHeader = *flags.SensitiveHeader
}

sensitiveHeadersMu.RLock()
if sensitiveHeadersCache != nil && lastSensitiveHeader == currentHeader {
m := sensitiveHeadersCache
sensitiveHeadersMu.RUnlock()
return m
}
sensitiveHeadersMu.RUnlock()

sensitiveHeadersMu.Lock()
defer sensitiveHeadersMu.Unlock()

// Double check
if sensitiveHeadersCache != nil && lastSensitiveHeader == currentHeader {
return sensitiveHeadersCache
}

m := make(map[string]bool)
sensitiveKeysList := strings.Split(currentHeader, ",")
for _, key := range sensitiveKeysList {
m[strings.ToLower(strings.TrimSpace(key))] = true
}
sensitiveHeadersCache = m
lastSensitiveHeader = currentHeader
return m
}

// safeString converts bytes to string with UTF-8 validation
// If bytes contain invalid UTF-8, returns base64 encoded version as fallback
func safeString(data []byte) string {
Expand Down Expand Up @@ -100,11 +139,7 @@ func ParseHTTPRequest(data []byte) (*http.Request, error) {
var header = http.Header{}
var host = ""
headerLines := bytes.Split(headers, []byte("\n"))
sensitiveHeaders := make(map[string]bool)
sensitiveKeysList := strings.Split(*flags.SensitiveHeader, ",")
for _, key := range sensitiveKeysList {
sensitiveHeaders[strings.ToLower(strings.TrimSpace(key))] = true
}
sensitiveHeaders := getSensitiveHeaders()
for _, line := range headerLines {
// Skip empty lines
if len(line) == 0 {
Expand Down Expand Up @@ -252,11 +287,7 @@ func ParseHTTPResponse(data []byte) (*http.Response, error) {

// Parse headers
var header = http.Header{}
sensitiveHeaders := make(map[string]bool)
sensitiveKeysList := strings.Split(*flags.SensitiveHeader, ",")
for _, key := range sensitiveKeysList {
sensitiveHeaders[strings.ToLower(strings.TrimSpace(key))] = true
}
sensitiveHeaders := getSensitiveHeaders()

headerLines := bytes.Split(headerData, []byte("\r\n"))
if len(headerLines) == 1 {
Expand Down