forked from NYANDEV/forgejo
792b4dba2c
* update github.com/blevesearch/bleve v2.0.2 -> v2.0.3 * github.com/denisenkom/go-mssqldb v0.9.0 -> v0.10.0 * github.com/editorconfig/editorconfig-core-go v2.4.1 -> v2.4.2 * github.com/go-chi/cors v1.1.1 -> v1.2.0 * github.com/go-git/go-billy v5.0.0 -> v5.1.0 * github.com/go-git/go-git v5.2.0 -> v5.3.0 * github.com/go-ldap/ldap v3.2.4 -> v3.3.0 * github.com/go-redis/redis v8.6.0 -> v8.8.2 * github.com/go-sql-driver/mysql v1.5.0 -> v1.6.0 * github.com/go-swagger/go-swagger v0.26.1 -> v0.27.0 * github.com/lib/pq v1.9.0 -> v1.10.1 * github.com/mattn/go-sqlite3 v1.14.6 -> v1.14.7 * github.com/go-testfixtures/testfixtures v3.5.0 -> v3.6.0 * github.com/issue9/identicon v1.0.1 -> v1.2.0 * github.com/klauspost/compress v1.11.8 -> v1.12.1 * github.com/mgechev/revive v1.0.3 -> v1.0.6 * github.com/microcosm-cc/bluemonday v1.0.7 -> v1.0.8 * github.com/niklasfasching/go-org v1.4.0 -> v1.5.0 * github.com/olivere/elastic v7.0.22 -> v7.0.24 * github.com/pelletier/go-toml v1.8.1 -> v1.9.0 * github.com/prometheus/client_golang v1.9.0 -> v1.10.0 * github.com/xanzy/go-gitlab v0.44.0 -> v0.48.0 * github.com/yuin/goldmark v1.3.3 -> v1.3.5 * github.com/6543/go-version v1.2.4 -> v1.3.1 * do github.com/lib/pq v1.10.0 -> v1.10.1 again ...
150 lines
4.4 KiB
Go
Vendored
150 lines
4.4 KiB
Go
Vendored
// 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 (
|
|
"bytes"
|
|
"sync"
|
|
"sync/atomic"
|
|
)
|
|
|
|
type (
|
|
// Encoder is a mechanism for serializing a label set into a
|
|
// specific string representation that supports caching, to
|
|
// avoid repeated serialization. An example could be an
|
|
// exporter encoding the label set into a wire representation.
|
|
Encoder interface {
|
|
// Encode returns the serialized encoding of the label
|
|
// 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
|
|
// label encoder. Label encoders allocate these using
|
|
// `NewEncoderID`.
|
|
ID() EncoderID
|
|
}
|
|
|
|
// EncoderID is used to identify distinct Encoder
|
|
// implementations, for caching encoded results.
|
|
EncoderID struct {
|
|
value uint64
|
|
}
|
|
|
|
// defaultLabelEncoder uses a sync.Pool of buffers to reduce
|
|
// the number of allocations used in encoding labels. This
|
|
// implementation encodes a comma-separated list of key=value,
|
|
// with '/'-escaping of '=', ',', and '\'.
|
|
defaultLabelEncoder struct {
|
|
// pool is a pool of labelset builders. The buffers in this
|
|
// pool grow to a size that most label encodings will not
|
|
// allocate new memory.
|
|
pool sync.Pool // *bytes.Buffer
|
|
}
|
|
)
|
|
|
|
// escapeChar is used to ensure uniqueness of the label 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 = &defaultLabelEncoder{}
|
|
|
|
// encoderIDCounter is for generating IDs for other label
|
|
// encoders.
|
|
encoderIDCounter uint64
|
|
|
|
defaultEncoderOnce sync.Once
|
|
defaultEncoderID = NewEncoderID()
|
|
defaultEncoderInstance *defaultLabelEncoder
|
|
)
|
|
|
|
// NewEncoderID returns a unique label encoder ID. It should be
|
|
// called once per each type of label encoder. Preferably in init() or
|
|
// in var definition.
|
|
func NewEncoderID() EncoderID {
|
|
return EncoderID{value: atomic.AddUint64(&encoderIDCounter, 1)}
|
|
}
|
|
|
|
// DefaultEncoder returns a label encoder that encodes labels
|
|
// in such a way that each escaped label's key is followed by an equal
|
|
// sign and then by an escaped label'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 DefaultEncoder() Encoder {
|
|
defaultEncoderOnce.Do(func() {
|
|
defaultEncoderInstance = &defaultLabelEncoder{
|
|
pool: sync.Pool{
|
|
New: func() interface{} {
|
|
return &bytes.Buffer{}
|
|
},
|
|
},
|
|
}
|
|
})
|
|
return defaultEncoderInstance
|
|
}
|
|
|
|
// Encode is a part of an implementation of the LabelEncoder
|
|
// interface.
|
|
func (d *defaultLabelEncoder) Encode(iter Iterator) string {
|
|
buf := d.pool.Get().(*bytes.Buffer)
|
|
defer d.pool.Put(buf)
|
|
buf.Reset()
|
|
|
|
for iter.Next() {
|
|
i, keyValue := iter.IndexedLabel()
|
|
if i > 0 {
|
|
_, _ = buf.WriteRune(',')
|
|
}
|
|
copyAndEscape(buf, string(keyValue.Key))
|
|
|
|
_, _ = buf.WriteRune('=')
|
|
|
|
if keyValue.Value.Type() == STRING {
|
|
copyAndEscape(buf, keyValue.Value.AsString())
|
|
} else {
|
|
_, _ = buf.WriteString(keyValue.Value.Emit())
|
|
}
|
|
}
|
|
return buf.String()
|
|
}
|
|
|
|
// ID is a part of an implementation of the LabelEncoder interface.
|
|
func (*defaultLabelEncoder) ID() EncoderID {
|
|
return defaultEncoderID
|
|
}
|
|
|
|
// copyAndEscape escapes `=`, `,` and its own escape character (`\`),
|
|
// making the default encoding unique.
|
|
func copyAndEscape(buf *bytes.Buffer, val string) {
|
|
for _, ch := range val {
|
|
switch ch {
|
|
case '=', ',', escapeChar:
|
|
buf.WriteRune(escapeChar)
|
|
}
|
|
buf.WriteRune(ch)
|
|
}
|
|
}
|
|
|
|
// Valid returns true if this encoder ID was allocated by
|
|
// `NewEncoderID`. Invalid encoder IDs will not be cached.
|
|
func (id EncoderID) Valid() bool {
|
|
return id.value != 0
|
|
}
|