1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-05-13 21:56:48 +02:00

Use strings.Cut() instead of string.SplitN() (#4049)

strings.Cut() generates less garbage as it does not allocate the slice to hold parts.
This commit is contained in:
Mikhail Mazurskiy 2023-05-18 02:28:44 +10:00 committed by GitHub
parent 8445f21305
commit f95bee22b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 64 additions and 68 deletions

View File

@ -13,6 +13,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- The `go.opentelemetry.io/otel/semconv/v1.20.0` package. - The `go.opentelemetry.io/otel/semconv/v1.20.0` package.
The package contains semantic conventions from the `v1.20.0` version of the OpenTelemetry specification. (#4078) The package contains semantic conventions from the `v1.20.0` version of the OpenTelemetry specification. (#4078)
### Changed
- Use `strings.Cut()` instead of `string.SplitN()` for better readability and memory use. (#4049)
### Removed ### Removed
- The deprecated `go.opentelemetry.io/otel/metric/instrument` package is removed. - The deprecated `go.opentelemetry.io/otel/metric/instrument` package is removed.

View File

@ -289,31 +289,29 @@ func parseMember(member string) (Member, error) {
props properties props properties
) )
parts := strings.SplitN(member, propertyDelimiter, 2) keyValue, properties, found := strings.Cut(member, propertyDelimiter)
switch len(parts) { if found {
case 2:
// Parse the member properties. // Parse the member properties.
for _, pStr := range strings.Split(parts[1], propertyDelimiter) { for _, pStr := range strings.Split(properties, propertyDelimiter) {
p, err := parseProperty(pStr) p, err := parseProperty(pStr)
if err != nil { if err != nil {
return newInvalidMember(), err return newInvalidMember(), err
} }
props = append(props, p) props = append(props, p)
} }
fallthrough }
case 1:
// Parse the member key/value pair. // Parse the member key/value pair.
// Take into account a value can contain equal signs (=). // Take into account a value can contain equal signs (=).
kv := strings.SplitN(parts[0], keyValueDelimiter, 2) k, v, found := strings.Cut(keyValue, keyValueDelimiter)
if len(kv) != 2 { if !found {
return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidMember, member) return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidMember, member)
} }
// "Leading and trailing whitespaces are allowed but MUST be trimmed // "Leading and trailing whitespaces are allowed but MUST be trimmed
// when converting the header into a data structure." // when converting the header into a data structure."
key = strings.TrimSpace(kv[0]) key = strings.TrimSpace(k)
var err error var err error
value, err = url.QueryUnescape(strings.TrimSpace(kv[1])) value, err = url.QueryUnescape(strings.TrimSpace(v))
if err != nil { if err != nil {
return newInvalidMember(), fmt.Errorf("%w: %q", err, value) return newInvalidMember(), fmt.Errorf("%w: %q", err, value)
} }
@ -323,12 +321,6 @@ func parseMember(member string) (Member, error) {
if !valueRe.MatchString(value) { if !valueRe.MatchString(value) {
return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, value) return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, value)
} }
default:
// This should never happen unless a developer has changed the string
// splitting somehow. Panic instead of failing silently and allowing
// the bug to slip past the CI checks.
panic("failed to parse baggage member")
}
return Member{key: key, value: value, properties: props, hasData: true}, nil return Member{key: key, value: value, properties: props, hasData: true}, nil
} }

View File

@ -160,15 +160,13 @@ func (t *TMultiplexedProcessor) ProcessorMap() map[string]TProcessorFunction {
// the given ProcessorName or if all that is given is the FunctionName and there // the given ProcessorName or if all that is given is the FunctionName and there
// is no DefaultProcessor set. // is no DefaultProcessor set.
func (t *TMultiplexedProcessor) AddToProcessorMap(name string, processorFunc TProcessorFunction) { func (t *TMultiplexedProcessor) AddToProcessorMap(name string, processorFunc TProcessorFunction) {
components := strings.SplitN(name, MULTIPLEXED_SEPARATOR, 2) processorName, funcName, found := strings.Cut(name, MULTIPLEXED_SEPARATOR)
if len(components) != 2 { if !found {
if t.DefaultProcessor != nil && len(components) == 1 { if t.DefaultProcessor != nil {
t.DefaultProcessor.AddToProcessorMap(components[0], processorFunc) t.DefaultProcessor.AddToProcessorMap(processorName, processorFunc)
} }
return return
} }
processorName := components[0]
funcName := components[1]
if processor, ok := t.serviceProcessorMap[processorName]; ok { if processor, ok := t.serviceProcessorMap[processorName]; ok {
processor.AddToProcessorMap(funcName, processorFunc) processor.AddToProcessorMap(funcName, processorFunc)
} }
@ -197,9 +195,9 @@ func (t *TMultiplexedProcessor) Process(ctx context.Context, in, out TProtocol)
if typeId != CALL && typeId != ONEWAY { if typeId != CALL && typeId != ONEWAY {
return false, NewTProtocolException(fmt.Errorf("Unexpected message type %v", typeId)) return false, NewTProtocolException(fmt.Errorf("Unexpected message type %v", typeId))
} }
//extract the service name // extract the service name
v := strings.SplitN(name, MULTIPLEXED_SEPARATOR, 2) processorName, funcName, found := strings.Cut(name, MULTIPLEXED_SEPARATOR)
if len(v) != 2 { if !found {
if t.DefaultProcessor != nil { if t.DefaultProcessor != nil {
smb := NewStoredMessageProtocol(in, name, typeId, seqid) smb := NewStoredMessageProtocol(in, name, typeId, seqid)
return t.DefaultProcessor.Process(ctx, smb, out) return t.DefaultProcessor.Process(ctx, smb, out)
@ -209,18 +207,18 @@ func (t *TMultiplexedProcessor) Process(ctx context.Context, in, out TProtocol)
name, name,
)) ))
} }
actualProcessor, ok := t.serviceProcessorMap[v[0]] actualProcessor, ok := t.serviceProcessorMap[processorName]
if !ok { if !ok {
return false, NewTProtocolException(fmt.Errorf( return false, NewTProtocolException(fmt.Errorf(
"Service name not found: %s. Did you forget to call registerProcessor()?", "Service name not found: %s. Did you forget to call registerProcessor()?",
v[0], processorName,
)) ))
} }
smb := NewStoredMessageProtocol(in, v[1], typeId, seqid) smb := NewStoredMessageProtocol(in, funcName, typeId, seqid)
return actualProcessor.Process(ctx, smb, out) return actualProcessor.Process(ctx, smb, out)
} }
//Protocol that use stored message for ReadMessageBegin // Protocol that use stored message for ReadMessageBegin
type storedMessageProtocol struct { type storedMessageProtocol struct {
TProtocol TProtocol
name string name string

View File

@ -166,20 +166,20 @@ func stringToHeader(value string) map[string]string {
headers := make(map[string]string) headers := make(map[string]string)
for _, header := range headersPairs { for _, header := range headersPairs {
nameValue := strings.SplitN(header, "=", 2) n, v, found := strings.Cut(header, "=")
if len(nameValue) < 2 { if !found {
global.Error(errors.New("missing '="), "parse headers", "input", nameValue) global.Error(errors.New("missing '="), "parse headers", "input", header)
continue continue
} }
name, err := url.QueryUnescape(nameValue[0]) name, err := url.QueryUnescape(n)
if err != nil { if err != nil {
global.Error(err, "escape header key", "key", nameValue[0]) global.Error(err, "escape header key", "key", n)
continue continue
} }
trimmedName := strings.TrimSpace(name) trimmedName := strings.TrimSpace(name)
value, err := url.QueryUnescape(nameValue[1]) value, err := url.QueryUnescape(v)
if err != nil { if err != nil {
global.Error(err, "escape header value", "value", nameValue[1]) global.Error(err, "escape header value", "value", v)
continue continue
} }
trimmedValue := strings.TrimSpace(value) trimmedValue := strings.TrimSpace(value)

View File

@ -35,9 +35,9 @@ func newState(encoded string) state {
if encoded == "" { if encoded == "" {
return state{} return state{}
} }
split := strings.SplitN(encoded, ",", 2) s0, s1, _ := strings.Cut(encoded, ",")
injects, _ := strconv.ParseUint(split[0], 10, 64) injects, _ := strconv.ParseUint(s0, 10, 64)
extracts, _ := strconv.ParseUint(split[1], 10, 64) extracts, _ := strconv.ParseUint(s1, 10, 64)
return state{ return state{
Injections: injects, Injections: injects,
Extractions: extracts, Extractions: extracts,

View File

@ -82,23 +82,23 @@ func constructOTResources(s string) (*Resource, error) {
return Empty(), nil return Empty(), nil
} }
pairs := strings.Split(s, ",") pairs := strings.Split(s, ",")
attrs := []attribute.KeyValue{} var attrs []attribute.KeyValue
var invalid []string var invalid []string
for _, p := range pairs { for _, p := range pairs {
field := strings.SplitN(p, "=", 2) k, v, found := strings.Cut(p, "=")
if len(field) != 2 { if !found {
invalid = append(invalid, p) invalid = append(invalid, p)
continue continue
} }
k := strings.TrimSpace(field[0]) key := strings.TrimSpace(k)
v, err := url.QueryUnescape(strings.TrimSpace(field[1])) val, err := url.QueryUnescape(strings.TrimSpace(v))
if err != nil { if err != nil {
// Retain original value if decoding fails, otherwise it will be // Retain original value if decoding fails, otherwise it will be
// an empty string. // an empty string.
v = field[1] val = v
otel.Handle(err) otel.Handle(err)
} }
attrs = append(attrs, attribute.String(k, v)) attrs = append(attrs, attribute.String(key, val))
} }
var err error var err error
if len(invalid) > 0 { if len(invalid) > 0 {

View File

@ -85,14 +85,14 @@ func skip(line string) bool {
// parse attempts to split the provided line on the first '=' character, and then // parse attempts to split the provided line on the first '=' character, and then
// sanitize each side of the split before returning them as a key-value pair. // sanitize each side of the split before returning them as a key-value pair.
func parse(line string) (string, string, bool) { func parse(line string) (string, string, bool) {
parts := strings.SplitN(line, "=", 2) k, v, found := strings.Cut(line, "=")
if len(parts) != 2 || len(parts[0]) == 0 { if !found || len(k) == 0 {
return "", "", false return "", "", false
} }
key := strings.TrimSpace(parts[0]) key := strings.TrimSpace(k)
value := unescape(unquote(strings.TrimSpace(parts[1]))) value := unescape(unquote(strings.TrimSpace(v)))
return key, value, true return key, value, true
} }

View File

@ -232,10 +232,12 @@ func (sc *SemanticConventions) HTTPServerAttributesFromHTTPRequest(serverName, r
if route != "" { if route != "" {
attrs = append(attrs, sc.HTTPRouteKey.String(route)) attrs = append(attrs, sc.HTTPRouteKey.String(route))
} }
if values, ok := request.Header["X-Forwarded-For"]; ok && len(values) > 0 { if values := request.Header["X-Forwarded-For"]; len(values) > 0 {
if addresses := strings.SplitN(values[0], ",", 2); len(addresses) > 0 { addr := values[0]
attrs = append(attrs, sc.HTTPClientIPKey.String(addresses[0])) if i := strings.Index(addr, ","); i > 0 {
addr = addr[:i]
} }
attrs = append(attrs, sc.HTTPClientIPKey.String(addr))
} }
return append(attrs, sc.httpCommonAttributesFromHTTPRequest(request)...) return append(attrs, sc.httpCommonAttributesFromHTTPRequest(request)...)