8000 Use strings.Cut() instead of string.SplitN() (#4049) · open-telemetry/opentelemetry-go@f95bee2 · GitHub 8000
[go: up one dir, main page]

Skip to content

Commit f95bee2

Browse files
authored
Use strings.Cut() instead of string.SplitN() (#4049)
strings.Cut() generates less garbage as it does not allocate the slice to hold parts.
1 parent 8445f21 commit f95bee2

File tree

8 files changed

+65
-69
lines changed

8 files changed

+65
-69
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
1313
- The `go.opentelemetry.io/otel/semconv/v1.20.0` package.
1414
The package contains semantic conventions from the `v1.20.0` version of the OpenTelemetry specification. (#4078)
1515

16+
### Changed
17+
18+
- Use `strings.Cut()` instead of `string.SplitN()` for better readability and memory use. (#4049)
19+
1620
### Removed
1721

1822
- The deprecated `go.opentelemetry.io/otel/metric/instrument` package is removed.

baggage/baggage.go

Lines changed: 24 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -289,45 +289,37 @@ func parseMember(member string) (Member, error) {
289289
props properties
290290
)
291291

292-
parts := strings.SplitN(member, propertyDelimiter, 2)
293-
switch len(parts) {
294-
case 2:
292+
keyValue, properties, found := strings.Cut(member, propertyDelimiter)
293+
if found {
295294
// Parse the member properties.
296-
for _, pStr := range strings.Split(parts[1], propertyDelimiter) {
295+
for _, pStr := range strings.Split(properties, propertyDelimiter) {
297296
p, err := parseProperty(pStr)
298297
if err != nil {
299298
return newInvalidMember(), err
300299
}
301300
props = append(props, p)
302301
}
303-
fallthrough
304-
case 1:
305-
// Parse the member key/value pair.
306-
307-
// Take into account a value can contain equal signs (=).
308-
kv := strings.SplitN(parts[0], keyValueDelimiter, 2)
309-
if len(kv) != 2 {
310-
return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidMember, member)
311-
}
312-
// "Leading and trailing whitespaces are allowed but MUST be trimmed
313-
// when converting the header into a data structure."
314-
key = strings.TrimSpace(kv[0])
315-
var err error
316-
value, err = url.QueryUnescape(strings.TrimSpace(kv[1]))
317-
if err != nil {
318-
return newInvalidMember(), fmt.Errorf("%w: %q", err, value)
319-
}
320-
if !keyRe.MatchString(key) {
321-
return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidKey, key)
322-
}
323-
if !valueRe.MatchString(value) {
324-
return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, value)
325-
}
326-
default:
327-
// This should never happen unless a developer has changed the string
328-
// splitting somehow. Panic instead of failing silently and allowing
329-
// the bug to slip past the CI checks.
330-
panic("failed to parse baggage member")
302+
}
303+
// Parse the member key/value pair.
304+
305+
// Take into account a value can contain equal signs (=).
306+
k, v, found := strings.Cut(keyValue, keyValueDelimiter)
307+
if !found {
308+
return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidMember, member)
309+
}
310+
// "Leading and trailing whitespaces are allowed but MUST be trimmed
311+
// when converting the header into a data structure."
312+
key = strings.TrimSpace(k)
313+
var err error
314+
value, err = url.QueryUnescape(strings.TrimSpace(v))
315+
if err != nil {
316+
return newInvalidMember(), fmt.Errorf("%w: %q", err, value)
317+
}
318+
if !keyRe.MatchString(key) {
319+
return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidKey, key)
320+
}
321+
if !valueRe.MatchString(value) {
322+
return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, value)
331323
}
332324

333325
return Member{key: key, value: value, properties: props, hasData: true}, nil

exporters/jaeger/internal/third_party/thrift/lib/go/thrift/multiplexed_protocol.go

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -160,15 +160,13 @@ func (t *TMultiplexedProcessor) ProcessorMap() map[string]TProcessorFunction {
160160
// the given ProcessorName or if all that is given is the FunctionName and there
161161
// is no DefaultProcessor set.
162162
func (t *TMultiplexedProcessor) AddToProcessorMap(name string, processorFunc TProcessorFunction) {
163-
components := strings.SplitN(name, MULTIPLEXED_SEPARATOR, 2)
164-
if len(components) != 2 {
165-
if t.DefaultProcessor != nil && len(components) == 1 {
166-
t.DefaultProcessor.AddToProcessorMap(components[0], processorFunc)
163+
processorName, funcName, found := strings.Cut(name, MULTIPLEXED_SEPARATOR)
164+
if !found {
165+
if t.DefaultProcessor != nil {
166+
t.DefaultProcessor.AddToProcessorMap(processorName, processorFunc)
167167
}
168168
return
169169
}
170-
processorName := components[0]
171-
funcName := components[1]
172170
if processor, ok := t.serviceProcessorMap[processorName]; ok {
173171
processor.AddToProcessorMap(funcName, processorFunc)
174172
}
@@ -197,9 +195,9 @@ func (t *TMultiplexedProcessor) Process(ctx context.Context, in, out TProtocol)
197195
if typeId != CALL && typeId != ONEWAY {
198196
return false, NewTProtocolException(fmt.Errorf("Unexpected message type %v", typeId))
199197
}
200-
//extract the service name
201-
v := strings.SplitN(name, MULTIPLEXED_SEPARATOR, 2)
202-
if len(v) != 2 {
198+
// extract the service name
199+
processorName, funcName, found := strings.Cut(name, MULTIPLEXED_SEPARATOR)
200+
if !found {
203201
if t.DefaultProcessor != nil {
204202
smb := NewStoredMessageProtocol(in, name, typeId, seqid)
205203
return t.DefaultProcessor.Process(ctx, smb, out)
@@ -209,18 +207,18 @@ func (t *TMultiplexedProcessor) Process(ctx context.Context, in, out TProtocol)
209207
name,
210208
))
211209
}
212-
actualProcessor, ok := t.serviceProcessorMap[v[0]]
210+
actualProcessor, ok := t.serviceProcessorMap[processorName]
213211
if !ok {
214212
return false, NewTProtocolException(fmt.Errorf(
215213
"Service name not found: %s. Did you forget to call registerProcessor()?",
216-
v[0],
214+
processorName,
217215
))
218216
}
219-
smb := NewStoredMessageProtocol(in, v[1], typeId, seqid)
217+
smb := NewStoredMessageProtocol(in, funcName, typeId, seqid)
220218
return actualProcessor.Process(ctx, smb, out)
221219
}
222220

223-
//Protocol that use stored message for ReadMessageBegin
221+
// Protocol that use stored message for ReadMessageBegin
224222
type storedMessageProtocol struct {
225223
TProtocol
226224
name string

exporters/otlp/internal/envconfig/envconfig.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -166,20 +166,20 @@ func stringToHeader(value string) map[string]string {
166166
headers := make(map[string]string)
167167

168168
for _, header := range headersPairs {
169-
nameValue := strings.SplitN(header, "=", 2)
170-
if len(nameValue) < 2 {
171-
global.Error(errors.New("missing '="), "parse headers", "input", nameValue)
169+
n, v, found := strings.Cut(header, "=")
170+
if !found {
171+
global.Error(errors.New("missing '="), "parse headers", "input", header)
172172
continue
173173
}
174-
name, err := url.QueryUnescape(nameValue[0])
174+
name, err := url.QueryUnescape(n)
175175
if err != nil {
176-
global.Error(err, "escape header key", "key", nameValue[0])
176+
global.Error(err, "escape header key", "key", n)
177177
continue
178178
}
179179
trimmedName := strings.TrimSpace(name)
180-
value, err := url.QueryUnescape(nameValue[1])
180+
value, err := url.QueryUnescape(v)
181181
if err != nil {
182-
global.Error(err, "escape header value", "value", nameValue[1])
182+
global.Error(err, "escape header value", "value", v)
183183
continue
184184
}
185185
trimmedValue := strings.TrimSpace(value)

internal/internaltest/text_map_propagator.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ func newState(encoded string) state {
3535
if encoded == "" {
3636
return state{}
3737
}
38-
split := strings.SplitN(encoded, ",", 2)
39-
injects, _ := strconv.ParseUint(split[0], 10, 64)
40-
extracts, _ := strconv.ParseUint(split[1], 10, 64)
38+
s0, s1, _ := strings.Cut(encoded, ",")
39+
injects, _ := strconv.ParseUint(s0, 10, 64)
40+
extracts, _ := strconv.ParseUint(s1, 10, 64)
4141
return state{
4242
Injections: injects,
4343
Extractions: extracts,

sdk/resource/env.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,23 +82,23 @@ func constructOTResources(s string) (*Resource, error) {
8282
return Empty(), nil
8383
}
8484
pairs := strings.Split(s, ",")
85-
attrs := []attribute.KeyValue{}
85+
var attrs []attribute.KeyValue
8686
var invalid []string
8787
for _, p := range pairs {
88-
field := strings.SplitN(p, "=", 2)
89-
if len(field) != 2 {
88+
k, v, found := strings.Cut(p, "=")
89+
if !found {
9090
invalid = append(invalid, p)
9191
continue
9292
}
93-
k := strings.TrimSpace(field[0])
94-
v, err := url.QueryUnescape(strings.TrimSpace(field[1]))
93+
key := strings.TrimSpace(k)
94+
val, err := url.QueryUnescape(strings.TrimSpace(v))
9595
if err != nil {
9696
// Retain original value if decoding fails, otherwise it will be
9797
// an empty string.
98-
v = field[1]
98+
val = v
9999
otel.Handle(err)
100100
}
101-
attrs = append(attrs, attribute.String(k, v))
101+
attrs = append(attrs, attribute.String(key, val))
102102
}
103103
var err error
104104
if len(invalid) > 0 {

sdk/resource/os_release_unix.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,14 +85,14 @@ func skip(line string) bool {
8585
// parse attempts to split the provided line on the first '=' character, and then
8686
// sanitize each side of the split before returning them as a key-value pair.
8787
func parse(line string) (string, string, bool) {
88-
parts := strings.SplitN(line, "=", 2)
88+
k, v, found := strings.Cut(line, "=")
8989

90-
if len(parts) != 2 || len(parts[0]) == 0 {
90+
if !found || len(k) == 0 {
9191
return "", "", false
9292
}
9393

94-
key := strings.TrimSpace(parts[0])
95-
value := unescape(unquote(strings.TrimSpace(parts[1])))
94+
key := strings.TrimSpace(k)
95+
value := unescape(unquote(strings.TrimSpace(v)))
9696

9797
return key, value, true
9898
}

semconv/internal/http.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,10 +232,12 @@ func (sc *SemanticConventions) HTTPServerAttributesFromHTTPRequest(serverName, r
232232
if route != "" {
233233
attrs = append(attrs, sc.HTTPRouteKey.String(route))
234234
}
235-
if values, ok := request.Header["X-Forwarded-For"]; ok && len(values) > 0 {
236-
if addresses := strings.SplitN(values[0], ",", 2); len(addresses) > 0 {
237-
attrs = append(attrs, sc.HTTPClientIPKey.String(addresses[0]))
235+
if values := request.Header["X-Forwarded-For"]; len(values) > 0 {
236+
addr := values[0]
237+
if i := strings.Index(addr, ","); i > 0 {
238+
addr = addr[:i]
238239
}
240+
attrs = append(attrs, sc.HTTPClientIPKey.String(addr))
239241
}
240242

241243
return append(attrs, sc.httpCommonAttributesFromHTTPRequest(request)...)

0 commit comments

Comments
 (0)
0