1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2026-06-03 18:35:08 +02:00
Files
opentelemetry-go/attribute/encoder.go
T
renovate[bot] 6d79ac3936 fix(deps): update golang.org/x (#8045)
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) | Type |
Update |
|---|---|---|---|---|---|
| [golang.org/x/crypto](https://pkg.go.dev/golang.org/x/crypto) |
[`v0.48.0` →
`v0.49.0`](https://cs.opensource.google/go/x/crypto/+/refs/tags/v0.48.0...refs/tags/v0.49.0)
|
![age](https://developer.mend.io/api/mc/badges/age/go/golang.org%2fx%2fcrypto/v0.49.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/go/golang.org%2fx%2fcrypto/v0.48.0/v0.49.0?slim=true)
| indirect | minor |
| [golang.org/x/mod](https://pkg.go.dev/golang.org/x/mod) | [`v0.33.0` →
`v0.34.0`](https://cs.opensource.google/go/x/mod/+/refs/tags/v0.33.0...refs/tags/v0.34.0)
|
![age](https://developer.mend.io/api/mc/badges/age/go/golang.org%2fx%2fmod/v0.34.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/go/golang.org%2fx%2fmod/v0.33.0/v0.34.0?slim=true)
| indirect | minor |
| [golang.org/x/net](https://pkg.go.dev/golang.org/x/net) | [`v0.51.0` →
`v0.52.0`](https://cs.opensource.google/go/x/net/+/refs/tags/v0.51.0...refs/tags/v0.52.0)
|
![age](https://developer.mend.io/api/mc/badges/age/go/golang.org%2fx%2fnet/v0.52.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/go/golang.org%2fx%2fnet/v0.51.0/v0.52.0?slim=true)
| indirect | minor |
| [golang.org/x/telemetry](https://pkg.go.dev/golang.org/x/telemetry) |
`e526e8a` → `579e4da` |
![age](https://developer.mend.io/api/mc/badges/age/go/golang.org%2fx%2ftelemetry/v0.0.0-20260311193753-579e4da9a98c?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/go/golang.org%2fx%2ftelemetry/v0.0.0-20260306145045-e526e8a188f5/v0.0.0-20260311193753-579e4da9a98c?slim=true)
| indirect | digest |
| [golang.org/x/text](https://pkg.go.dev/golang.org/x/text) | [`v0.34.0`
→
`v0.35.0`](https://cs.opensource.google/go/x/text/+/refs/tags/v0.34.0...refs/tags/v0.35.0)
|
![age](https://developer.mend.io/api/mc/badges/age/go/golang.org%2fx%2ftext/v0.35.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/go/golang.org%2fx%2ftext/v0.34.0/v0.35.0?slim=true)
| indirect | minor |
| [golang.org/x/tools](https://pkg.go.dev/golang.org/x/tools) |
[`v0.42.0` →
`v0.43.0`](https://cs.opensource.google/go/x/tools/+/refs/tags/v0.42.0...refs/tags/v0.43.0)
|
![age](https://developer.mend.io/api/mc/badges/age/go/golang.org%2fx%2ftools/v0.43.0?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/go/golang.org%2fx%2ftools/v0.42.0/v0.43.0?slim=true)
| require | minor |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/5322) for more information.

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config
help](https://redirect.github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/open-telemetry/opentelemetry-go).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My41OS4wIiwidXBkYXRlZEluVmVyIjoiNDMuNTkuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiU2tpcCBDaGFuZ2Vsb2ciLCJkZXBlbmRlbmNpZXMiXX0=-->

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: dmathieu <damien.mathieu@elastic.co>
2026-03-12 15:40:07 +01:00

136 lines
4.0 KiB
Go

// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package attribute // import "go.opentelemetry.io/otel/attribute"
import (
"bytes"
"sync"
"sync/atomic"
)
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 an 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 atomic.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 NewEncoderID() EncoderID {
return EncoderID{value: encoderIDCounter.Add(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 DefaultEncoder() Encoder {
defaultEncoderOnce.Do(func() {
defaultEncoderInstance = &defaultAttrEncoder{
pool: sync.Pool{
New: func() any {
return &bytes.Buffer{}
},
},
}
})
return defaultEncoderInstance
}
// Encode is a part of an implementation of the AttributeEncoder interface.
func (d *defaultAttrEncoder) Encode(iter Iterator) string {
buf := d.pool.Get().(*bytes.Buffer)
defer d.pool.Put(buf)
buf.Reset()
for iter.Next() {
i, keyValue := iter.IndexedAttribute()
if i > 0 {
_ = buf.WriteByte(',')
}
copyAndEscape(buf, string(keyValue.Key))
_ = buf.WriteByte('=')
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 AttributeEncoder interface.
func (*defaultAttrEncoder) 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.WriteByte(escapeChar)
}
_, _ = buf.WriteRune(ch)
}
}
// Valid reports whether this encoder ID was allocated by
// [NewEncoderID]. Invalid encoder IDs will not be cached.
func (id EncoderID) Valid() bool {
return id.value != 0
}