Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
steps:
- uses: actions/setup-go@v5
with:
go-version: '>=1.20'
go-version: '>=1.24'

- uses: actions/checkout@v4

Expand Down
2 changes: 1 addition & 1 deletion buckets.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,5 @@ func splitMeasureField(s string) (measure, field string) {
} else {
field = s
}
return
return measure, field
}
4 changes: 2 additions & 2 deletions cmd/dogstatsd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ func split(args []string, sep string) (head, tail []string) {
} else {
head, tail = args[:i], args[i+1:]
}
return
return head, tail
}

func indexOf(args []string, s string) int {
Expand Down Expand Up @@ -187,5 +187,5 @@ func (tags *tags) Set(s string) (err error) {
}
*tags = append(*tags, tag)
}
return
return err
}
2 changes: 1 addition & 1 deletion datadog/append_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func BenchmarkAppendMetric(b *testing.B) {

for _, test := range testMetrics {
b.Run(test.m.Name, func(b *testing.B) {
for i := 0; i != b.N; i++ {
for b.Loop() {
appendMetric(buffer[:0], test.m)
}
})
Expand Down
4 changes: 2 additions & 2 deletions datadog/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ func bufSizeFromFD(f *os.File, sizehint int) (bufsize int, err error) {
// to accept larger datagrams, or fallback to the default socket buffer size
// if it failed.
if bufsize, err = unix.GetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_SNDBUF); err != nil {
return
return bufsize, err
}

// The kernel applies a 2x factor on the socket buffer size, only half of it
Expand Down Expand Up @@ -197,7 +197,7 @@ func bufSizeFromFD(f *os.File, sizehint int) (bufsize int, err error) {

// Creating the file put the socket in blocking mode, reverting.
_ = unix.SetNonblock(fd, true)
return
return bufsize, err
}

type ddWriter interface {
Expand Down
38 changes: 19 additions & 19 deletions datadog/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func parseEvent(s string) (e Event, err error) {
header, next = nextToken(next, ':')
if len(header) < 7 {
err = fmt.Errorf("datadog: %#v has a malformed event header", s)
return
return e, err
}

header = header[3 : len(header)-1] // Strip off '_e{' and '}'
Expand All @@ -30,13 +30,13 @@ func parseEvent(s string) (e Event, err error) {
titleLen, err = strconv.ParseInt(rawTitleLen, 10, 64)
if err != nil {
err = fmt.Errorf("datadog: %#v has a malformed title length", s)
return
return e, err
}

textLen, err = strconv.ParseInt(rawTextLen, 10, 64)
if err != nil {
err = fmt.Errorf("datadog: %#v has a malformed text length", s)
return
return e, err
}

rawTitle := next[:titleLen]
Expand All @@ -45,12 +45,12 @@ func parseEvent(s string) (e Event, err error) {

if len(rawTitle) == 0 {
err = fmt.Errorf("datadog: %#v has a malformed title", s)
return
return e, err
}

if len(rawText) == 0 {
err = fmt.Errorf("datadog: %#v has malformed text", s)
return
return e, err
}

e = Event{
Expand All @@ -72,7 +72,7 @@ func parseEvent(s string) (e Event, err error) {
ts, err = strconv.ParseInt(rawMetadataFields[i][2:], 10, 64)
if err != nil {
err = fmt.Errorf("datadog: %#v has a malformed timestamp", s)
return
return e, err
}
e.Ts = ts
case 'p':
Expand All @@ -89,7 +89,7 @@ func parseEvent(s string) (e Event, err error) {
tags = rawMetadataFields[i][1:]
default:
err = fmt.Errorf("datadog: %#v has unexpected metadata field", s)
return
return e, err
}
}
}
Expand All @@ -107,7 +107,7 @@ func parseEvent(s string) (e Event, err error) {
}
}

return
return e, err
}

func parseMetric(s string) (m Metric, err error) {
Expand All @@ -125,17 +125,17 @@ func parseMetric(s string) (m Metric, err error) {

if len(name) == 0 {
err = fmt.Errorf("datadog: %#v is missing a metric name", s)
return
return m, err
}

if len(val) == 0 {
err = fmt.Errorf("datadog: %#v is missing a metric value", s)
return
return m, err
}

if len(typ) == 0 {
err = fmt.Errorf("datadog: %#v is missing a metric type", s)
return
return m, err
}

if len(rate) != 0 {
Expand All @@ -146,7 +146,7 @@ func parseMetric(s string) (m Metric, err error) {
rate = rate[1:]
default:
err = fmt.Errorf("datadog: %#v has a malformed sample rate", s)
return
return m, err
}
}

Expand All @@ -156,7 +156,7 @@ func parseMetric(s string) (m Metric, err error) {
tags = tags[1:]
default:
err = fmt.Errorf("datadog: %#v has malformed tags", s)
return
return m, err
}
}

Expand All @@ -165,13 +165,13 @@ func parseMetric(s string) (m Metric, err error) {

if value, err = strconv.ParseFloat(val, 64); err != nil {
err = fmt.Errorf("datadog: %#v has a malformed value", s)
return
return m, err
}

if len(rate) != 0 {
if sampleRate, err = strconv.ParseFloat(rate, 64); err != nil {
err = fmt.Errorf("datadog: %#v has a malformed sample rate", s)
return
return m, err
}
}

Expand Down Expand Up @@ -199,7 +199,7 @@ func parseMetric(s string) (m Metric, err error) {
}
}

return
return m, err
}

func nextToken(s string, b byte) (token, next string) {
Expand All @@ -208,7 +208,7 @@ func nextToken(s string, b byte) (token, next string) {
} else {
token = s
}
return
return token, next
}

func split(s string, b byte) (head, tail string) {
Expand All @@ -217,7 +217,7 @@ func split(s string, b byte) (head, tail string) {
} else {
head = s
}
return
return head, tail
}

func count(s string, b byte) (n int) {
Expand All @@ -231,5 +231,5 @@ func count(s string, b byte) (n int) {
s = s[off+1:]
}

return
return n
}
4 changes: 2 additions & 2 deletions datadog/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func TestParseMetricFailure(t *testing.T) {
func BenchmarkParseMetric(b *testing.B) {
for _, test := range testMetrics {
b.Run(test.m.Name, func(b *testing.B) {
for i := 0; i != b.N; i++ {
for b.Loop() {
parseMetric(test.s)
}
})
Expand All @@ -64,7 +64,7 @@ func TestParseEventSuccess(t *testing.T) {
func BenchmarkParseEvent(b *testing.B) {
for _, test := range testEvents {
b.Run(test.e.Title, func(b *testing.B) {
for i := 0; i != b.N; i++ {
for b.Loop() {
parseEvent(test.s)
}
})
Expand Down
88 changes: 24 additions & 64 deletions datadog/serializer.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,87 +223,47 @@ func isTrim(b byte) bool { return b == '.' || b == '_' || b == '-' }
// appendSanitizedMetricName converts *any* string into something that StatsD / Graphite
// accepts without complaints.
func appendSanitizedMetricName(dst []byte, raw string) []byte {
nameLen := 0
orig := len(dst)
origLen := len(dst)
if raw == "" {
if len(dst) == 0 {
return append(dst, "_unnamed_"...)
}
return dst
}
// ── 1. accent folding (creates one temporary ↴)
// tmp := stripUnicodeAccents([]byte(raw))

// ── 2. run the same ASCII sanitizer, but write into dst
// Simple transformation: iterate through runes and convert/replace as needed
lastWasRepl := false
for i := 0; i < len(raw); i++ {
c := byte(raw[i])
for i, r := range raw {
if i >= maxLen {
break
}

if c < 128 && valid[c] {
// ASCII valid chars
dst = append(dst, c)
nameLen++
if r < utf8.RuneSelf && valid[byte(r)] {
// Valid ASCII character
dst = append(dst, byte(r))
lastWasRepl = false
} else if c >= 0xC2 && c <= 0xC3 && i+1 < len(raw) {
// Check for 2-byte UTF-8 sequences that are common accented letters
c2 := byte(raw[i+1])
if c2 >= 0x80 && c2 <= 0xBF { // Valid second byte
// Decode the 2-byte sequence
codepoint := uint16(c&0x1F)<<6 | uint16(c2&0x3F)

// Map common accented characters (U+00C0-U+00FF range)
if codepoint >= 0xC0 && codepoint <= 0xFF {
mapped := latin1SupplementMap[codepoint]
if valid[mapped] {
dst = append(dst, mapped)
nameLen++
lastWasRepl = false
i++ // Skip the second byte
continue
}
}
}
// If we get here, treat as invalid
if !lastWasRepl {
dst = append(dst, replacement)
nameLen++
lastWasRepl = true
}
} else {
// Everything else (3-byte, 4-byte sequences, invalid chars)
// Skip continuation bytes (0x80-0xBF) to avoid creating invalid UTF-8
for i+1 < len(raw) && (raw[i+1]&0xC0) == 0x80 {
i++
}
if !lastWasRepl {
} else if r >= 0xC0 && r <= 0xFF {
// Latin-1 Supplement block (common accented characters like À, É, ñ)
mapped := latin1SupplementMap[r]
if valid[mapped] {
dst = append(dst, mapped)
lastWasRepl = false
} else if !lastWasRepl {
dst = append(dst, replacement)
nameLen++
lastWasRepl = true
}
}

if nameLen >= maxLen {
break
} else if !lastWasRepl {
// Invalid or unsupported character - only append if we didn't just add a replacement
dst = append(dst, replacement)
lastWasRepl = true
}
}

// 3. trim leading / trailing '.', '_' or '-'
start, end := orig, len(dst)
for start < end && isTrim(dst[start]) {
start++
}
for end > start && isTrim(dst[end-1]) {
end--
}

// 4. compact if we trimmed something
if start > orig || end < len(dst) {
copy(dst[orig:], dst[start:end])
dst = dst[:orig+(end-start)]
}
// Trim leading/trailing '.', '_' or '-'
trimmed := bytes.Trim(dst[origLen:], "._-")
dst = append(dst[:origLen], trimmed...)

// 5. fallback if everything vanished
if len(dst) == orig {
if len(dst) == origLen {
return append(dst, "_truncated_"...)
}
return dst
Expand Down
Loading
Loading