Source File
encoder.go
Belonging Package
go.opentelemetry.io/otel/attribute
// 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 attribute // import "go.opentelemetry.io/otel/attribute"
import (
)
type (
// Encoder is a mechanism for serializing an attribute set into a specific
// string representation that supports caching, to avoid repeated
// serialization. An example could be an exporter encoding the attribute
// set into a wire representation.
Encoder interface {
// Encode returns the serialized encoding of the attribute set using
// its Iterator. This result may be cached by a attribute.Set.
Encode(iterator Iterator) string
// ID returns a value that is unique for each class of attribute
// encoder. Attribute encoders allocate these using `NewEncoderID`.
ID() EncoderID
}
// EncoderID is used to identify distinct Encoder
// implementations, for caching encoded results.
EncoderID struct {
value uint64
}
// defaultAttrEncoder uses a sync.Pool of buffers to reduce the number of
// allocations used in encoding attributes. This implementation encodes a
// comma-separated list of key=value, with '/'-escaping of '=', ',', and
// '\'.
defaultAttrEncoder struct {
// pool is a pool of attribute set builders. The buffers in this pool
// grow to a size that most attribute encodings will not allocate new
// memory.
pool sync.Pool // *bytes.Buffer
}
)
// escapeChar is used to ensure uniqueness of the attribute encoding where
// keys or values contain either '=' or ','. Since there is no parser needed
// for this encoding and its only requirement is to be unique, this choice is
// arbitrary. Users will see these in some exporters (e.g., stdout), so the
// backslash ('\') is used as a conventional choice.
const escapeChar = '\\'
var (
_ Encoder = &defaultAttrEncoder{}
// encoderIDCounter is for generating IDs for other attribute encoders.
encoderIDCounter uint64
defaultEncoderOnce sync.Once
defaultEncoderID = NewEncoderID()
defaultEncoderInstance *defaultAttrEncoder
)
// NewEncoderID returns a unique attribute encoder ID. It should be called
// once per each type of attribute encoder. Preferably in init() or in var
// definition.
func () EncoderID {
return EncoderID{value: atomic.AddUint64(&encoderIDCounter, 1)}
}
// DefaultEncoder returns an attribute encoder that encodes attributes in such
// a way that each escaped attribute's key is followed by an equal sign and
// then by an escaped attribute's value. All key-value pairs are separated by
// a comma.
//
// Escaping is done by prepending a backslash before either a backslash, equal
// sign or a comma.
func () Encoder {
defaultEncoderOnce.Do(func() {
defaultEncoderInstance = &defaultAttrEncoder{
pool: sync.Pool{
New: func() interface{} {
return &bytes.Buffer{}
},
},
}
})
return defaultEncoderInstance
}
// Encode is a part of an implementation of the AttributeEncoder interface.
func ( *defaultAttrEncoder) ( Iterator) string {
:= .pool.Get().(*bytes.Buffer)
defer .pool.Put()
.Reset()
for .Next() {
, := .IndexedAttribute()
if > 0 {
_, _ = .WriteRune(',')
}
copyAndEscape(, string(.Key))
_, _ = .WriteRune('=')
if .Value.Type() == STRING {
copyAndEscape(, .Value.AsString())
} else {
_, _ = .WriteString(.Value.Emit())
}
}
return .String()
}
// ID is a part of an implementation of the AttributeEncoder interface.
func (*defaultAttrEncoder) () EncoderID {
return defaultEncoderID
}
// copyAndEscape escapes `=`, `,` and its own escape character (`\`),
// making the default encoding unique.
func ( *bytes.Buffer, string) {
for , := range {
switch {
case '=', ',', escapeChar:
_, _ = .WriteRune(escapeChar)
}
_, _ = .WriteRune()
}
}
// Valid returns true if this encoder ID was allocated by
// `NewEncoderID`. Invalid encoder IDs will not be cached.
func ( EncoderID) () bool {
return .value != 0
}
The pages are generated with Golds v0.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. |