// Copyright The OpenTelemetry Authors//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at//// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.package trace // import "go.opentelemetry.io/otel/trace"import ()const (maxListMembers = 32listDelimiter = ","// based on the W3C Trace Context specification, see // https://www.w3.org/TR/trace-context-1/#tracestate-headernoTenantKeyFormat = `[a-z][_0-9a-z\-\*\/]*`withTenantKeyFormat = `[a-z0-9][_0-9a-z\-\*\/]*@[a-z][_0-9a-z\-\*\/]*`valueFormat = `[\x20-\x2b\x2d-\x3c\x3e-\x7e]*[\x21-\x2b\x2d-\x3c\x3e-\x7e]`errInvalidKeyerrorConst = "invalid tracestate key"errInvalidValueerrorConst = "invalid tracestate value"errInvalidMembererrorConst = "invalid tracestate list-member"errMemberNumbererrorConst = "too many list-members in tracestate"errDuplicateerrorConst = "duplicate list-member in tracestate")var (noTenantKeyRe = regexp.MustCompile(`^` + noTenantKeyFormat + `$`)withTenantKeyRe = regexp.MustCompile(`^` + withTenantKeyFormat + `$`)valueRe = regexp.MustCompile(`^` + valueFormat + `$`)memberRe = regexp.MustCompile(`^\s*((?:` + noTenantKeyFormat + `)|(?:` + withTenantKeyFormat + `))=(` + valueFormat + `)\s*$`))typememberstruct {KeystringValuestring}func (, string) (member, error) {iflen() > 256 {returnmember{}, fmt.Errorf("%w: %s", errInvalidKey, ) }if !noTenantKeyRe.MatchString() {if !withTenantKeyRe.MatchString() {returnmember{}, fmt.Errorf("%w: %s", errInvalidKey, ) } := strings.LastIndex(, "@")if > 241 || len()-1- > 14 {returnmember{}, fmt.Errorf("%w: %s", errInvalidKey, ) } }iflen() > 256 || !valueRe.MatchString() {returnmember{}, fmt.Errorf("%w: %s", errInvalidValue, ) }returnmember{Key: , Value: }, nil}func ( string) (member, error) { := memberRe.FindStringSubmatch()iflen() != 3 {returnmember{}, fmt.Errorf("%w: %s", errInvalidMember, ) } , := newMember([1], [2])if != nil {returnmember{}, fmt.Errorf("%w: %s", errInvalidMember, ) }return , nil}// String encodes member into a string compliant with the W3C Trace Context// specification.func ( member) () string {returnfmt.Sprintf("%s=%s", .Key, .Value)}// TraceState provides additional vendor-specific trace identification// information across different distributed tracing systems. It represents an// immutable list consisting of key/value pairs, each pair is referred to as a// list-member.//// TraceState conforms to the W3C Trace Context specification// (https://www.w3.org/TR/trace-context-1). All operations that create or copy// a TraceState do so by validating all input and will only produce TraceState// that conform to the specification. Specifically, this means that all// list-member's key/value pairs are valid, no duplicate list-members exist,// and the maximum number of list-members (32) is not exceeded.typeTraceStatestruct { //nolint:revive // revive complains about stutter of `trace.TraceState`// list is the members in order.list []member}var _ json.Marshaler = TraceState{}// ParseTraceState attempts to decode a TraceState from the passed// string. It returns an error if the input is invalid according to the W3C// Trace Context specification.func ( string) (TraceState, error) {if == "" {returnTraceState{}, nil } := func( error) error {returnfmt.Errorf("failed to parse tracestate: %w", ) }var []member := make(map[string]struct{})for , := rangestrings.Split(, listDelimiter) {iflen() == 0 {continue } , := parseMember()if != nil {returnTraceState{}, () }if , := [.Key]; {returnTraceState{}, (errDuplicate) } [.Key] = struct{}{} = append(, )if := len(); > maxListMembers {returnTraceState{}, (errMemberNumber) } }returnTraceState{list: }, nil}// MarshalJSON marshals the TraceState into JSON.func ( TraceState) () ([]byte, error) {returnjson.Marshal(.String())}// String encodes the TraceState into a string compliant with the W3C// Trace Context specification. The returned string will be invalid if the// TraceState contains any invalid members.func ( TraceState) () string { := make([]string, len(.list))for , := range .list { [] = .String() }returnstrings.Join(, listDelimiter)}// Get returns the value paired with key from the corresponding TraceState// list-member if it exists, otherwise an empty string is returned.func ( TraceState) ( string) string {for , := range .list {if .Key == {return .Value } }return""}// Insert adds a new list-member defined by the key/value pair to the// TraceState. If a list-member already exists for the given key, that// list-member's value is updated. The new or updated list-member is always// moved to the beginning of the TraceState as specified by the W3C Trace// Context specification.//// If key or value are invalid according to the W3C Trace Context// specification an error is returned with the original TraceState.//// If adding a new list-member means the TraceState would have more members// then is allowed, the new list-member will be inserted and the right-most// list-member will be dropped in the returned TraceState.func ( TraceState) (, string) (TraceState, error) { , := newMember(, )if != nil {return , } := .Delete()if .Len()+1 <= maxListMembers { .list = append(.list, member{}) }// When the number of members exceeds capacity, drop the "right-most".copy(.list[1:], .list) .list[0] = return , nil}// Delete returns a copy of the TraceState with the list-member identified by// key removed.func ( TraceState) ( string) TraceState { := make([]member, .Len())copy(, .list)for , := range .list {if .Key == { = append([:], [+1:]...)// TraceState should contain no duplicate members.break } }returnTraceState{list: }}// Len returns the number of list-members in the TraceState.func ( TraceState) () int {returnlen(.list)}
The pages are generated with Goldsv0.6.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.