1// Copyright 2019, OpenTelemetry Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package metric
16
17import (
18	"bytes"
19	"sync"
20
21	"go.opentelemetry.io/otel/api/core"
22	export "go.opentelemetry.io/otel/sdk/export/metric"
23)
24
25type defaultLabelEncoder struct {
26	// pool is a pool of labelset builders.  The buffers in this
27	// pool grow to a size that most label encodings will not
28	// allocate new memory.  This pool reduces the number of
29	// allocations per new LabelSet to 3, typically, as seen in
30	// the benchmarks.  (It should be 2--one for the LabelSet
31	// object and one for the buffer.String() here--see the extra
32	// allocation in the call to sort.Stable).
33	pool sync.Pool // *bytes.Buffer
34}
35
36var _ export.LabelEncoder = &defaultLabelEncoder{}
37
38func NewDefaultLabelEncoder() export.LabelEncoder {
39	return &defaultLabelEncoder{
40		pool: sync.Pool{
41			New: func() interface{} {
42				return &bytes.Buffer{}
43			},
44		},
45	}
46}
47
48func (d *defaultLabelEncoder) Encode(labels []core.KeyValue) string {
49	buf := d.pool.Get().(*bytes.Buffer)
50	defer d.pool.Put(buf)
51	buf.Reset()
52
53	for i, kv := range labels {
54		if i > 0 {
55			_, _ = buf.WriteRune(',')
56		}
57		_, _ = buf.WriteString(string(kv.Key))
58		_, _ = buf.WriteRune('=')
59		_, _ = buf.WriteString(kv.Value.Emit())
60	}
61	return buf.String()
62}
63