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:
parent
8445f21305
commit
f95bee22b9
@ -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.
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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,
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)...)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user