mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-11-30 15:33:32 -06:00
[chore] update otel libraries (#3740)
* chore: update otel dependencies * refactor: combine tracing & metrics in observability package * chore: update example tracing compose file
This commit is contained in:
parent
baed591a1d
commit
dd094e4012
217 changed files with 6873 additions and 2734 deletions
|
|
@ -13,7 +13,8 @@ func InstrumentationScope(il instrumentation.Scope) *commonpb.InstrumentationSco
|
|||
return nil
|
||||
}
|
||||
return &commonpb.InstrumentationScope{
|
||||
Name: il.Name,
|
||||
Version: il.Version,
|
||||
Name: il.Name,
|
||||
Version: il.Version,
|
||||
Attributes: Iterator(il.Attributes.Iter()),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,8 +97,8 @@ func span(sd tracesdk.ReadOnlySpan) *tracepb.Span {
|
|||
SpanId: sid[:],
|
||||
TraceState: sd.SpanContext().TraceState().String(),
|
||||
Status: status(sd.Status().Code, sd.Status().Description),
|
||||
StartTimeUnixNano: uint64(sd.StartTime().UnixNano()),
|
||||
EndTimeUnixNano: uint64(sd.EndTime().UnixNano()),
|
||||
StartTimeUnixNano: uint64(max(0, sd.StartTime().UnixNano())), // nolint:gosec // Overflow checked.
|
||||
EndTimeUnixNano: uint64(max(0, sd.EndTime().UnixNano())), // nolint:gosec // Overflow checked.
|
||||
Links: links(sd.Links()),
|
||||
Kind: spanKind(sd.SpanKind()),
|
||||
Name: sd.Name(),
|
||||
|
|
@ -178,7 +178,7 @@ func buildSpanFlags(sc trace.SpanContext) uint32 {
|
|||
flags |= tracepb.SpanFlags_SPAN_FLAGS_CONTEXT_IS_REMOTE_MASK
|
||||
}
|
||||
|
||||
return uint32(flags)
|
||||
return uint32(flags) // nolint:gosec // Flags is a bitmask and can't be negative
|
||||
}
|
||||
|
||||
// spanEvents transforms span Events to an OTLP span events.
|
||||
|
|
@ -192,7 +192,7 @@ func spanEvents(es []tracesdk.Event) []*tracepb.Span_Event {
|
|||
for i := 0; i < len(es); i++ {
|
||||
events[i] = &tracepb.Span_Event{
|
||||
Name: es[i].Name,
|
||||
TimeUnixNano: uint64(es[i].Time.UnixNano()),
|
||||
TimeUnixNano: uint64(max(0, es[i].Time.UnixNano())), // nolint:gosec // Overflow checked.
|
||||
Attributes: KeyValues(es[i].Attributes),
|
||||
DroppedAttributesCount: clampUint32(es[i].DroppedAttributeCount),
|
||||
}
|
||||
|
|
|
|||
9
vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/client.go
generated
vendored
9
vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/client.go
generated
vendored
|
|
@ -229,7 +229,12 @@ func (c *client) exportContext(parent context.Context) (context.Context, context
|
|||
}
|
||||
|
||||
if c.metadata.Len() > 0 {
|
||||
ctx = metadata.NewOutgoingContext(ctx, c.metadata)
|
||||
md := c.metadata
|
||||
if outMD, ok := metadata.FromOutgoingContext(ctx); ok {
|
||||
md = metadata.Join(md, outMD)
|
||||
}
|
||||
|
||||
ctx = metadata.NewOutgoingContext(ctx, md)
|
||||
}
|
||||
|
||||
// Unify the client stopCtx with the parent.
|
||||
|
|
@ -289,7 +294,7 @@ func (c *client) MarshalLog() interface{} {
|
|||
Type string
|
||||
Endpoint string
|
||||
}{
|
||||
Type: "otlphttpgrpc",
|
||||
Type: "otlptracegrpc",
|
||||
Endpoint: c.endpoint,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ func cleanPath(urlPath string, defaultPath string) string {
|
|||
return defaultPath
|
||||
}
|
||||
if !path.IsAbs(tmp) {
|
||||
tmp = fmt.Sprintf("/%s", tmp)
|
||||
tmp = "/" + tmp
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
|
|
@ -125,7 +125,7 @@ func NewGRPCConfig(opts ...GRPCOption) Config {
|
|||
if cfg.ServiceConfig != "" {
|
||||
cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultServiceConfig(cfg.ServiceConfig))
|
||||
}
|
||||
// Priroritize GRPCCredentials over Insecure (passing both is an error).
|
||||
// Prioritize GRPCCredentials over Insecure (passing both is an error).
|
||||
if cfg.Traces.GRPCCredentials != nil {
|
||||
cfg.DialOptions = append(cfg.DialOptions, grpc.WithTransportCredentials(cfg.Traces.GRPCCredentials))
|
||||
} else if cfg.Traces.Insecure {
|
||||
|
|
@ -278,9 +278,7 @@ func WithEndpointURL(v string) GenericOption {
|
|||
|
||||
cfg.Traces.Endpoint = u.Host
|
||||
cfg.Traces.URLPath = u.Path
|
||||
if u.Scheme != "https" {
|
||||
cfg.Traces.Insecure = true
|
||||
}
|
||||
cfg.Traces.Insecure = u.Scheme != "https"
|
||||
|
||||
return cfg
|
||||
})
|
||||
|
|
|
|||
56
vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/client.go
generated
vendored
56
vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/client.go
generated
vendored
|
|
@ -166,8 +166,7 @@ func (d *client) UploadTraces(ctx context.Context, protoSpans []*tracepb.Resourc
|
|||
}()
|
||||
}
|
||||
|
||||
switch sc := resp.StatusCode; {
|
||||
case sc >= 200 && sc <= 299:
|
||||
if sc := resp.StatusCode; sc >= 200 && sc <= 299 {
|
||||
// Success, do not retry.
|
||||
// Read the partial success message, if any.
|
||||
var respData bytes.Buffer
|
||||
|
|
@ -194,34 +193,33 @@ func (d *client) UploadTraces(ctx context.Context, protoSpans []*tracepb.Resourc
|
|||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// Error cases.
|
||||
|
||||
case sc == http.StatusTooManyRequests,
|
||||
sc == http.StatusBadGateway,
|
||||
sc == http.StatusServiceUnavailable,
|
||||
sc == http.StatusGatewayTimeout:
|
||||
// Retry-able failures.
|
||||
rErr := newResponseError(resp.Header, nil)
|
||||
// server may return a message with the response
|
||||
// body, so we read it to include in the error
|
||||
// message to be returned. It will help in
|
||||
// debugging the actual issue.
|
||||
var respData bytes.Buffer
|
||||
if _, err := io.Copy(&respData, resp.Body); err != nil {
|
||||
return err
|
||||
}
|
||||
respStr := strings.TrimSpace(respData.String())
|
||||
if len(respStr) == 0 {
|
||||
respStr = "(empty)"
|
||||
}
|
||||
bodyErr := fmt.Errorf("body: %s", respStr)
|
||||
|
||||
// server may return a message with the response
|
||||
// body, so we read it to include in the error
|
||||
// message to be returned. It will help in
|
||||
// debugging the actual issue.
|
||||
var respData bytes.Buffer
|
||||
if _, err := io.Copy(&respData, resp.Body); err != nil {
|
||||
_ = resp.Body.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
// overwrite the error message with the response body
|
||||
// if it is not empty
|
||||
if respStr := strings.TrimSpace(respData.String()); respStr != "" {
|
||||
// Include response for context.
|
||||
e := errors.New(respStr)
|
||||
rErr = newResponseError(resp.Header, e)
|
||||
}
|
||||
return rErr
|
||||
switch resp.StatusCode {
|
||||
case http.StatusTooManyRequests,
|
||||
http.StatusBadGateway,
|
||||
http.StatusServiceUnavailable,
|
||||
http.StatusGatewayTimeout:
|
||||
// Retryable failure.
|
||||
return newResponseError(resp.Header, bodyErr)
|
||||
default:
|
||||
return fmt.Errorf("failed to send to %s: %s", request.URL, resp.Status)
|
||||
// Non-retryable failure.
|
||||
return fmt.Errorf("failed to send to %s: %s (%w)", request.URL, resp.Status, bodyErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -278,7 +276,7 @@ func (d *client) MarshalLog() interface{} {
|
|||
Endpoint string
|
||||
Insecure bool
|
||||
}{
|
||||
Type: "otlphttphttp",
|
||||
Type: "otlptracehttp",
|
||||
Endpoint: d.cfg.Endpoint,
|
||||
Insecure: d.cfg.Insecure,
|
||||
}
|
||||
|
|
@ -328,7 +326,7 @@ func newResponseError(header http.Header, wrapped error) error {
|
|||
|
||||
func (e retryableError) Error() string {
|
||||
if e.err != nil {
|
||||
return fmt.Sprintf("retry-able request failure: %s", e.err.Error())
|
||||
return "retry-able request failure: " + e.err.Error()
|
||||
}
|
||||
|
||||
return "retry-able request failure"
|
||||
|
|
|
|||
2
vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/doc.go
generated
vendored
2
vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp/doc.go
generated
vendored
|
|
@ -22,7 +22,7 @@ target URL to which the exporter sends telemetry.
|
|||
The value must contain a scheme ("http" or "https") and host.
|
||||
The value may additionally contain a port and a path.
|
||||
The value should not contain a query string or fragment.
|
||||
The configuration can be overridden by [WithEndpoint], [WithEndpointURL], [WitnInsecure], and [WithURLPath] options.
|
||||
The configuration can be overridden by [WithEndpoint], [WithEndpointURL], [WithInsecure], and [WithURLPath] options.
|
||||
|
||||
OTEL_EXPORTER_OTLP_HEADERS, OTEL_EXPORTER_OTLP_TRACES_HEADERS (default: none) -
|
||||
key-value pairs used as headers associated with HTTP requests.
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ func cleanPath(urlPath string, defaultPath string) string {
|
|||
return defaultPath
|
||||
}
|
||||
if !path.IsAbs(tmp) {
|
||||
tmp = fmt.Sprintf("/%s", tmp)
|
||||
tmp = "/" + tmp
|
||||
}
|
||||
return tmp
|
||||
}
|
||||
|
|
@ -125,7 +125,7 @@ func NewGRPCConfig(opts ...GRPCOption) Config {
|
|||
if cfg.ServiceConfig != "" {
|
||||
cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultServiceConfig(cfg.ServiceConfig))
|
||||
}
|
||||
// Priroritize GRPCCredentials over Insecure (passing both is an error).
|
||||
// Prioritize GRPCCredentials over Insecure (passing both is an error).
|
||||
if cfg.Traces.GRPCCredentials != nil {
|
||||
cfg.DialOptions = append(cfg.DialOptions, grpc.WithTransportCredentials(cfg.Traces.GRPCCredentials))
|
||||
} else if cfg.Traces.Insecure {
|
||||
|
|
@ -278,9 +278,7 @@ func WithEndpointURL(v string) GenericOption {
|
|||
|
||||
cfg.Traces.Endpoint = u.Host
|
||||
cfg.Traces.URLPath = u.Path
|
||||
if u.Scheme != "https" {
|
||||
cfg.Traces.Insecure = true
|
||||
}
|
||||
cfg.Traces.Insecure = u.Scheme != "https"
|
||||
|
||||
return cfg
|
||||
})
|
||||
|
|
|
|||
2
vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/version.go
generated
vendored
2
vendor/go.opentelemetry.io/otel/exporters/otlp/otlptrace/version.go
generated
vendored
|
|
@ -5,5 +5,5 @@ package otlptrace // import "go.opentelemetry.io/otel/exporters/otlp/otlptrace"
|
|||
|
||||
// Version is the current release version of the OpenTelemetry OTLP trace exporter in use.
|
||||
func Version() string {
|
||||
return "1.29.0"
|
||||
return "1.34.0"
|
||||
}
|
||||
|
|
|
|||
6
vendor/go.opentelemetry.io/otel/exporters/prometheus/config.go
generated
vendored
6
vendor/go.opentelemetry.io/otel/exporters/prometheus/config.go
generated
vendored
|
|
@ -7,6 +7,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/sdk/metric"
|
||||
|
|
@ -131,7 +132,10 @@ func WithoutScopeInfo() Option {
|
|||
// have special behavior based on their name.
|
||||
func WithNamespace(ns string) Option {
|
||||
return optionFunc(func(cfg config) config {
|
||||
ns = sanitizeName(ns)
|
||||
if model.NameValidationScheme != model.UTF8Validation {
|
||||
// Only sanitize if prometheus does not support UTF-8.
|
||||
ns = model.EscapeName(ns, model.NameEscapingScheme)
|
||||
}
|
||||
if !strings.HasSuffix(ns, "_") {
|
||||
// namespace and metric names should be separated with an underscore,
|
||||
// adds a trailing underscore if there is not one already.
|
||||
|
|
|
|||
204
vendor/go.opentelemetry.io/otel/exporters/prometheus/exporter.go
generated
vendored
204
vendor/go.opentelemetry.io/otel/exporters/prometheus/exporter.go
generated
vendored
|
|
@ -11,11 +11,10 @@ import (
|
|||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
"github.com/prometheus/common/model"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
|
|
@ -34,15 +33,14 @@ const (
|
|||
scopeInfoMetricName = "otel_scope_info"
|
||||
scopeInfoDescription = "Instrumentation Scope metadata"
|
||||
|
||||
scopeNameLabel = "otel_scope_name"
|
||||
scopeVersionLabel = "otel_scope_version"
|
||||
|
||||
traceIDExemplarKey = "trace_id"
|
||||
spanIDExemplarKey = "span_id"
|
||||
)
|
||||
|
||||
var (
|
||||
scopeInfoKeys = [2]string{"otel_scope_name", "otel_scope_version"}
|
||||
|
||||
errScopeInvalid = errors.New("invalid scope")
|
||||
)
|
||||
var errScopeInvalid = errors.New("invalid scope")
|
||||
|
||||
// Exporter is a Prometheus Exporter that embeds the OTel metric.Reader
|
||||
// interface for easy instantiation with a MeterProvider.
|
||||
|
|
@ -188,7 +186,11 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) {
|
|||
}
|
||||
|
||||
for _, scopeMetrics := range metrics.ScopeMetrics {
|
||||
var keys, values [2]string
|
||||
n := len(c.resourceKeyVals.keys) + 2 // resource attrs + scope name + scope version
|
||||
kv := keyVals{
|
||||
keys: make([]string, 0, n),
|
||||
vals: make([]string, 0, n),
|
||||
}
|
||||
|
||||
if !c.disableScopeInfo {
|
||||
scopeInfo, err := c.scopeInfo(scopeMetrics.Scope)
|
||||
|
|
@ -203,10 +205,13 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) {
|
|||
|
||||
ch <- scopeInfo
|
||||
|
||||
keys = scopeInfoKeys
|
||||
values = [2]string{scopeMetrics.Scope.Name, scopeMetrics.Scope.Version}
|
||||
kv.keys = append(kv.keys, scopeNameLabel, scopeVersionLabel)
|
||||
kv.vals = append(kv.vals, scopeMetrics.Scope.Name, scopeMetrics.Scope.Version)
|
||||
}
|
||||
|
||||
kv.keys = append(kv.keys, c.resourceKeyVals.keys...)
|
||||
kv.vals = append(kv.vals, c.resourceKeyVals.vals...)
|
||||
|
||||
for _, m := range scopeMetrics.Metrics {
|
||||
typ := c.metricType(m)
|
||||
if typ == nil {
|
||||
|
|
@ -225,25 +230,27 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) {
|
|||
|
||||
switch v := m.Data.(type) {
|
||||
case metricdata.Histogram[int64]:
|
||||
addHistogramMetric(ch, v, m, keys, values, name, c.resourceKeyVals)
|
||||
addHistogramMetric(ch, v, m, name, kv)
|
||||
case metricdata.Histogram[float64]:
|
||||
addHistogramMetric(ch, v, m, keys, values, name, c.resourceKeyVals)
|
||||
addHistogramMetric(ch, v, m, name, kv)
|
||||
case metricdata.Sum[int64]:
|
||||
addSumMetric(ch, v, m, keys, values, name, c.resourceKeyVals)
|
||||
addSumMetric(ch, v, m, name, kv)
|
||||
case metricdata.Sum[float64]:
|
||||
addSumMetric(ch, v, m, keys, values, name, c.resourceKeyVals)
|
||||
addSumMetric(ch, v, m, name, kv)
|
||||
case metricdata.Gauge[int64]:
|
||||
addGaugeMetric(ch, v, m, keys, values, name, c.resourceKeyVals)
|
||||
addGaugeMetric(ch, v, m, name, kv)
|
||||
case metricdata.Gauge[float64]:
|
||||
addGaugeMetric(ch, v, m, keys, values, name, c.resourceKeyVals)
|
||||
addGaugeMetric(ch, v, m, name, kv)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func addHistogramMetric[N int64 | float64](ch chan<- prometheus.Metric, histogram metricdata.Histogram[N], m metricdata.Metrics, ks, vs [2]string, name string, resourceKV keyVals) {
|
||||
func addHistogramMetric[N int64 | float64](ch chan<- prometheus.Metric, histogram metricdata.Histogram[N], m metricdata.Metrics, name string, kv keyVals) {
|
||||
for _, dp := range histogram.DataPoints {
|
||||
keys, values := getAttrs(dp.Attributes, ks, vs, resourceKV)
|
||||
keys, values := getAttrs(dp.Attributes)
|
||||
keys = append(keys, kv.keys...)
|
||||
values = append(values, kv.vals...)
|
||||
|
||||
desc := prometheus.NewDesc(name, m.Description, keys, nil)
|
||||
buckets := make(map[float64]uint64, len(dp.Bounds))
|
||||
|
|
@ -263,14 +270,16 @@ func addHistogramMetric[N int64 | float64](ch chan<- prometheus.Metric, histogra
|
|||
}
|
||||
}
|
||||
|
||||
func addSumMetric[N int64 | float64](ch chan<- prometheus.Metric, sum metricdata.Sum[N], m metricdata.Metrics, ks, vs [2]string, name string, resourceKV keyVals) {
|
||||
func addSumMetric[N int64 | float64](ch chan<- prometheus.Metric, sum metricdata.Sum[N], m metricdata.Metrics, name string, kv keyVals) {
|
||||
valueType := prometheus.CounterValue
|
||||
if !sum.IsMonotonic {
|
||||
valueType = prometheus.GaugeValue
|
||||
}
|
||||
|
||||
for _, dp := range sum.DataPoints {
|
||||
keys, values := getAttrs(dp.Attributes, ks, vs, resourceKV)
|
||||
keys, values := getAttrs(dp.Attributes)
|
||||
keys = append(keys, kv.keys...)
|
||||
values = append(values, kv.vals...)
|
||||
|
||||
desc := prometheus.NewDesc(name, m.Description, keys, nil)
|
||||
m, err := prometheus.NewConstMetric(desc, valueType, float64(dp.Value), values...)
|
||||
|
|
@ -278,14 +287,20 @@ func addSumMetric[N int64 | float64](ch chan<- prometheus.Metric, sum metricdata
|
|||
otel.Handle(err)
|
||||
continue
|
||||
}
|
||||
m = addExemplars(m, dp.Exemplars)
|
||||
// GaugeValues don't support Exemplars at this time
|
||||
// https://github.com/prometheus/client_golang/blob/aef8aedb4b6e1fb8ac1c90790645169125594096/prometheus/metric.go#L199
|
||||
if valueType != prometheus.GaugeValue {
|
||||
m = addExemplars(m, dp.Exemplars)
|
||||
}
|
||||
ch <- m
|
||||
}
|
||||
}
|
||||
|
||||
func addGaugeMetric[N int64 | float64](ch chan<- prometheus.Metric, gauge metricdata.Gauge[N], m metricdata.Metrics, ks, vs [2]string, name string, resourceKV keyVals) {
|
||||
func addGaugeMetric[N int64 | float64](ch chan<- prometheus.Metric, gauge metricdata.Gauge[N], m metricdata.Metrics, name string, kv keyVals) {
|
||||
for _, dp := range gauge.DataPoints {
|
||||
keys, values := getAttrs(dp.Attributes, ks, vs, resourceKV)
|
||||
keys, values := getAttrs(dp.Attributes)
|
||||
keys = append(keys, kv.keys...)
|
||||
values = append(values, kv.vals...)
|
||||
|
||||
desc := prometheus.NewDesc(name, m.Description, keys, nil)
|
||||
m, err := prometheus.NewConstMetric(desc, prometheus.GaugeValue, float64(dp.Value), values...)
|
||||
|
|
@ -297,61 +312,58 @@ func addGaugeMetric[N int64 | float64](ch chan<- prometheus.Metric, gauge metric
|
|||
}
|
||||
}
|
||||
|
||||
// getAttrs parses the attribute.Set to two lists of matching Prometheus-style
|
||||
// keys and values. It sanitizes invalid characters and handles duplicate keys
|
||||
// (due to sanitization) by sorting and concatenating the values following the spec.
|
||||
func getAttrs(attrs attribute.Set, ks, vs [2]string, resourceKV keyVals) ([]string, []string) {
|
||||
keysMap := make(map[string][]string)
|
||||
itr := attrs.Iter()
|
||||
for itr.Next() {
|
||||
kv := itr.Attribute()
|
||||
key := strings.Map(sanitizeRune, string(kv.Key))
|
||||
if _, ok := keysMap[key]; !ok {
|
||||
keysMap[key] = []string{kv.Value.Emit()}
|
||||
} else {
|
||||
// if the sanitized key is a duplicate, append to the list of keys
|
||||
keysMap[key] = append(keysMap[key], kv.Value.Emit())
|
||||
}
|
||||
}
|
||||
|
||||
// getAttrs converts the attribute.Set to two lists of matching Prometheus-style
|
||||
// keys and values.
|
||||
func getAttrs(attrs attribute.Set) ([]string, []string) {
|
||||
keys := make([]string, 0, attrs.Len())
|
||||
values := make([]string, 0, attrs.Len())
|
||||
for key, vals := range keysMap {
|
||||
keys = append(keys, key)
|
||||
slices.Sort(vals)
|
||||
values = append(values, strings.Join(vals, ";"))
|
||||
}
|
||||
itr := attrs.Iter()
|
||||
|
||||
if ks[0] != "" {
|
||||
keys = append(keys, ks[:]...)
|
||||
values = append(values, vs[:]...)
|
||||
if model.NameValidationScheme == model.UTF8Validation {
|
||||
// Do not perform sanitization if prometheus supports UTF-8.
|
||||
for itr.Next() {
|
||||
kv := itr.Attribute()
|
||||
keys = append(keys, string(kv.Key))
|
||||
values = append(values, kv.Value.Emit())
|
||||
}
|
||||
} else {
|
||||
// It sanitizes invalid characters and handles duplicate keys
|
||||
// (due to sanitization) by sorting and concatenating the values following the spec.
|
||||
keysMap := make(map[string][]string)
|
||||
for itr.Next() {
|
||||
kv := itr.Attribute()
|
||||
key := model.EscapeName(string(kv.Key), model.NameEscapingScheme)
|
||||
if _, ok := keysMap[key]; !ok {
|
||||
keysMap[key] = []string{kv.Value.Emit()}
|
||||
} else {
|
||||
// if the sanitized key is a duplicate, append to the list of keys
|
||||
keysMap[key] = append(keysMap[key], kv.Value.Emit())
|
||||
}
|
||||
}
|
||||
for key, vals := range keysMap {
|
||||
keys = append(keys, key)
|
||||
slices.Sort(vals)
|
||||
values = append(values, strings.Join(vals, ";"))
|
||||
}
|
||||
}
|
||||
|
||||
for idx := range resourceKV.keys {
|
||||
keys = append(keys, resourceKV.keys[idx])
|
||||
values = append(values, resourceKV.vals[idx])
|
||||
}
|
||||
|
||||
return keys, values
|
||||
}
|
||||
|
||||
func createInfoMetric(name, description string, res *resource.Resource) (prometheus.Metric, error) {
|
||||
keys, values := getAttrs(*res.Set(), [2]string{}, [2]string{}, keyVals{})
|
||||
keys, values := getAttrs(*res.Set())
|
||||
desc := prometheus.NewDesc(name, description, keys, nil)
|
||||
return prometheus.NewConstMetric(desc, prometheus.GaugeValue, float64(1), values...)
|
||||
}
|
||||
|
||||
func createScopeInfoMetric(scope instrumentation.Scope) (prometheus.Metric, error) {
|
||||
keys := scopeInfoKeys[:]
|
||||
desc := prometheus.NewDesc(scopeInfoMetricName, scopeInfoDescription, keys, nil)
|
||||
return prometheus.NewConstMetric(desc, prometheus.GaugeValue, float64(1), scope.Name, scope.Version)
|
||||
}
|
||||
attrs := make([]attribute.KeyValue, 0, scope.Attributes.Len()+2) // resource attrs + scope name + scope version
|
||||
attrs = append(attrs, scope.Attributes.ToSlice()...)
|
||||
attrs = append(attrs, attribute.String(scopeNameLabel, scope.Name))
|
||||
attrs = append(attrs, attribute.String(scopeVersionLabel, scope.Version))
|
||||
|
||||
func sanitizeRune(r rune) rune {
|
||||
if unicode.IsLetter(r) || unicode.IsDigit(r) || r == ':' || r == '_' {
|
||||
return r
|
||||
}
|
||||
return '_'
|
||||
keys, values := getAttrs(attribute.NewSet(attrs...))
|
||||
desc := prometheus.NewDesc(scopeInfoMetricName, scopeInfoDescription, keys, nil)
|
||||
return prometheus.NewConstMetric(desc, prometheus.GaugeValue, float64(1), values...)
|
||||
}
|
||||
|
||||
var unitSuffixes = map[string]string{
|
||||
|
|
@ -392,7 +404,11 @@ var unitSuffixes = map[string]string{
|
|||
|
||||
// getName returns the sanitized name, prefixed with the namespace and suffixed with unit.
|
||||
func (c *collector) getName(m metricdata.Metrics, typ *dto.MetricType) string {
|
||||
name := sanitizeName(m.Name)
|
||||
name := m.Name
|
||||
if model.NameValidationScheme != model.UTF8Validation {
|
||||
// Only sanitize if prometheus does not support UTF-8.
|
||||
name = model.EscapeName(name, model.NameEscapingScheme)
|
||||
}
|
||||
addCounterSuffix := !c.withoutCounterSuffixes && *typ == dto.MetricType_COUNTER
|
||||
if addCounterSuffix {
|
||||
// Remove the _total suffix here, as we will re-add the total suffix
|
||||
|
|
@ -411,59 +427,6 @@ func (c *collector) getName(m metricdata.Metrics, typ *dto.MetricType) string {
|
|||
return name
|
||||
}
|
||||
|
||||
func sanitizeName(n string) string {
|
||||
// This algorithm is based on strings.Map from Go 1.19.
|
||||
const replacement = '_'
|
||||
|
||||
valid := func(i int, r rune) bool {
|
||||
// Taken from
|
||||
// https://github.com/prometheus/common/blob/dfbc25bd00225c70aca0d94c3c4bb7744f28ace0/model/metric.go#L92-L102
|
||||
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || r == '_' || r == ':' || (r >= '0' && r <= '9' && i > 0) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// This output buffer b is initialized on demand, the first time a
|
||||
// character needs to be replaced.
|
||||
var b strings.Builder
|
||||
for i, c := range n {
|
||||
if valid(i, c) {
|
||||
continue
|
||||
}
|
||||
|
||||
if i == 0 && c >= '0' && c <= '9' {
|
||||
// Prefix leading number with replacement character.
|
||||
b.Grow(len(n) + 1)
|
||||
_ = b.WriteByte(byte(replacement))
|
||||
break
|
||||
}
|
||||
b.Grow(len(n))
|
||||
_, _ = b.WriteString(n[:i])
|
||||
_ = b.WriteByte(byte(replacement))
|
||||
width := utf8.RuneLen(c)
|
||||
n = n[i+width:]
|
||||
break
|
||||
}
|
||||
|
||||
// Fast path for unchanged input.
|
||||
if b.Cap() == 0 { // b.Grow was not called above.
|
||||
return n
|
||||
}
|
||||
|
||||
for _, c := range n {
|
||||
// Due to inlining, it is more performant to invoke WriteByte rather then
|
||||
// WriteRune.
|
||||
if valid(1, c) { // We are guaranteed to not be at the start.
|
||||
_ = b.WriteByte(byte(c))
|
||||
} else {
|
||||
_ = b.WriteByte(byte(replacement))
|
||||
}
|
||||
}
|
||||
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func (c *collector) metricType(m metricdata.Metrics) *dto.MetricType {
|
||||
switch v := m.Data.(type) {
|
||||
case metricdata.Histogram[int64], metricdata.Histogram[float64]:
|
||||
|
|
@ -489,7 +452,7 @@ func (c *collector) createResourceAttributes(res *resource.Resource) {
|
|||
defer c.mu.Unlock()
|
||||
|
||||
resourceAttrs, _ := res.Set().Filter(c.resourceAttributesFilter)
|
||||
resourceKeys, resourceValues := getAttrs(resourceAttrs, [2]string{}, [2]string{}, keyVals{})
|
||||
resourceKeys, resourceValues := getAttrs(resourceAttrs)
|
||||
c.resourceKeyVals = keyVals{keys: resourceKeys, vals: resourceValues}
|
||||
}
|
||||
|
||||
|
|
@ -584,7 +547,8 @@ func addExemplars[N int64 | float64](m prometheus.Metric, exemplars []metricdata
|
|||
func attributesToLabels(attrs []attribute.KeyValue) prometheus.Labels {
|
||||
labels := make(map[string]string)
|
||||
for _, attr := range attrs {
|
||||
labels[string(attr.Key)] = attr.Value.Emit()
|
||||
key := model.EscapeName(string(attr.Key), model.NameEscapingScheme)
|
||||
labels[key] = attr.Value.Emit()
|
||||
}
|
||||
return labels
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue