Add the `golines` golangci-lint formatter (#6513)
Ensure consistent line wrapping (<= 120 characters) within the project.
This commit is contained in:
		
							parent
							
								
									b59d0591cf
								
							
						
					
					
						commit
						7512a2be2e
					
				| 
						 | 
				
			
			@ -235,10 +235,13 @@ formatters:
 | 
			
		|||
  enable:
 | 
			
		||||
    - gofumpt
 | 
			
		||||
    - goimports
 | 
			
		||||
    - golines
 | 
			
		||||
  settings:
 | 
			
		||||
    goimports:
 | 
			
		||||
      local-prefixes:
 | 
			
		||||
        - go.opentelemetry.io
 | 
			
		||||
    golines:
 | 
			
		||||
      max-len: 120
 | 
			
		||||
  exclusions:
 | 
			
		||||
    generated: lax
 | 
			
		||||
    paths:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,14 +43,47 @@ func TestSetDedup(t *testing.T) {
 | 
			
		|||
	cases := []testCase{
 | 
			
		||||
		expect("A=B", attribute.String("A", "2"), attribute.String("A", "B")),
 | 
			
		||||
		expect("A=B", attribute.String("A", "2"), attribute.Int("A", 1), attribute.String("A", "B")),
 | 
			
		||||
		expect("A=B", attribute.String("A", "B"), attribute.String("A", "C"), attribute.String("A", "D"), attribute.String("A", "B")),
 | 
			
		||||
		expect(
 | 
			
		||||
			"A=B",
 | 
			
		||||
			attribute.String("A", "B"),
 | 
			
		||||
			attribute.String("A", "C"),
 | 
			
		||||
			attribute.String("A", "D"),
 | 
			
		||||
			attribute.String("A", "B"),
 | 
			
		||||
		),
 | 
			
		||||
 | 
			
		||||
		expect("A=B,C=D", attribute.String("A", "1"), attribute.String("C", "D"), attribute.String("A", "B")),
 | 
			
		||||
		expect("A=B,C=D", attribute.String("A", "2"), attribute.String("A", "B"), attribute.String("C", "D")),
 | 
			
		||||
		expect("A=B,C=D", attribute.Float64("C", 1.2), attribute.String("A", "2"), attribute.String("A", "B"), attribute.String("C", "D")),
 | 
			
		||||
		expect("A=B,C=D", attribute.String("C", "D"), attribute.String("A", "B"), attribute.String("A", "C"), attribute.String("A", "D"), attribute.String("A", "B")),
 | 
			
		||||
		expect("A=B,C=D", attribute.String("A", "B"), attribute.String("C", "D"), attribute.String("A", "C"), attribute.String("A", "D"), attribute.String("A", "B")),
 | 
			
		||||
		expect("A=B,C=D", attribute.String("A", "B"), attribute.String("A", "C"), attribute.String("A", "D"), attribute.String("A", "B"), attribute.String("C", "D")),
 | 
			
		||||
		expect(
 | 
			
		||||
			"A=B,C=D",
 | 
			
		||||
			attribute.Float64("C", 1.2),
 | 
			
		||||
			attribute.String("A", "2"),
 | 
			
		||||
			attribute.String("A", "B"),
 | 
			
		||||
			attribute.String("C", "D"),
 | 
			
		||||
		),
 | 
			
		||||
		expect(
 | 
			
		||||
			"A=B,C=D",
 | 
			
		||||
			attribute.String("C", "D"),
 | 
			
		||||
			attribute.String("A", "B"),
 | 
			
		||||
			attribute.String("A", "C"),
 | 
			
		||||
			attribute.String("A", "D"),
 | 
			
		||||
			attribute.String("A", "B"),
 | 
			
		||||
		),
 | 
			
		||||
		expect(
 | 
			
		||||
			"A=B,C=D",
 | 
			
		||||
			attribute.String("A", "B"),
 | 
			
		||||
			attribute.String("C", "D"),
 | 
			
		||||
			attribute.String("A", "C"),
 | 
			
		||||
			attribute.String("A", "D"),
 | 
			
		||||
			attribute.String("A", "B"),
 | 
			
		||||
		),
 | 
			
		||||
		expect(
 | 
			
		||||
			"A=B,C=D",
 | 
			
		||||
			attribute.String("A", "B"),
 | 
			
		||||
			attribute.String("A", "C"),
 | 
			
		||||
			attribute.String("A", "D"),
 | 
			
		||||
			attribute.String("A", "B"),
 | 
			
		||||
			attribute.String("C", "D"),
 | 
			
		||||
		),
 | 
			
		||||
	}
 | 
			
		||||
	enc := attribute.DefaultEncoder()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1173,7 +1173,9 @@ func BenchmarkParse(b *testing.B) {
 | 
			
		|||
	b.ReportAllocs()
 | 
			
		||||
 | 
			
		||||
	for i := 0; i < b.N; i++ {
 | 
			
		||||
		benchBaggage, _ = Parse("userId=alice,serverNode = DF28 , isProduction = false,hasProp=stuff;propKey;propWValue=value, invalidUtf8=pr%ffo%ffp%fcValue")
 | 
			
		||||
		benchBaggage, _ = Parse(
 | 
			
		||||
			"userId=alice,serverNode = DF28 , isProduction = false,hasProp=stuff;propKey;propWValue=value, invalidUtf8=pr%ffo%ffp%fcValue",
 | 
			
		||||
		)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,7 +56,11 @@ func TestAttributesFromMap(t *testing.T) {
 | 
			
		|||
	gotAttributeSet := attribute.NewSet(got...)
 | 
			
		||||
	wantAttributeSet := attribute.NewSet(want...)
 | 
			
		||||
	if !gotAttributeSet.Equals(&wantAttributeSet) {
 | 
			
		||||
		t.Errorf("Attributes conversion want %v, got %v", wantAttributeSet.Encoded(attribute.DefaultEncoder()), gotAttributeSet.Encoded(attribute.DefaultEncoder()))
 | 
			
		||||
		t.Errorf(
 | 
			
		||||
			"Attributes conversion want %v, got %v",
 | 
			
		||||
			wantAttributeSet.Encoded(attribute.DefaultEncoder()),
 | 
			
		||||
			gotAttributeSet.Encoded(attribute.DefaultEncoder()),
 | 
			
		||||
		)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,7 +26,9 @@ var (
 | 
			
		|||
	errNegativeCount                = errors.New("distribution or summary count is negative")
 | 
			
		||||
	errNegativeBucketCount          = errors.New("distribution bucket count is negative")
 | 
			
		||||
	errMismatchedAttributeKeyValues = errors.New("mismatched number of attribute keys and values")
 | 
			
		||||
	errInvalidExemplarSpanContext   = errors.New("span context exemplar attachment does not contain an OpenCensus SpanContext")
 | 
			
		||||
	errInvalidExemplarSpanContext   = errors.New(
 | 
			
		||||
		"span context exemplar attachment does not contain an OpenCensus SpanContext",
 | 
			
		||||
	)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ConvertMetrics converts metric data from OpenCensus to OpenTelemetry.
 | 
			
		||||
| 
						 | 
				
			
			@ -76,20 +78,29 @@ func convertAggregation(metric *ocmetricdata.Metric) (metricdata.Aggregation, er
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// convertGauge converts an OpenCensus gauge to an OpenTelemetry gauge aggregation.
 | 
			
		||||
func convertGauge[N int64 | float64](labelKeys []ocmetricdata.LabelKey, ts []*ocmetricdata.TimeSeries) (metricdata.Gauge[N], error) {
 | 
			
		||||
func convertGauge[N int64 | float64](
 | 
			
		||||
	labelKeys []ocmetricdata.LabelKey,
 | 
			
		||||
	ts []*ocmetricdata.TimeSeries,
 | 
			
		||||
) (metricdata.Gauge[N], error) {
 | 
			
		||||
	points, err := convertNumberDataPoints[N](labelKeys, ts)
 | 
			
		||||
	return metricdata.Gauge[N]{DataPoints: points}, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// convertSum converts an OpenCensus cumulative to an OpenTelemetry sum aggregation.
 | 
			
		||||
func convertSum[N int64 | float64](labelKeys []ocmetricdata.LabelKey, ts []*ocmetricdata.TimeSeries) (metricdata.Sum[N], error) {
 | 
			
		||||
func convertSum[N int64 | float64](
 | 
			
		||||
	labelKeys []ocmetricdata.LabelKey,
 | 
			
		||||
	ts []*ocmetricdata.TimeSeries,
 | 
			
		||||
) (metricdata.Sum[N], error) {
 | 
			
		||||
	points, err := convertNumberDataPoints[N](labelKeys, ts)
 | 
			
		||||
	// OpenCensus sums are always Cumulative
 | 
			
		||||
	return metricdata.Sum[N]{DataPoints: points, Temporality: metricdata.CumulativeTemporality, IsMonotonic: true}, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// convertNumberDataPoints converts OpenCensus TimeSeries to OpenTelemetry DataPoints.
 | 
			
		||||
func convertNumberDataPoints[N int64 | float64](labelKeys []ocmetricdata.LabelKey, ts []*ocmetricdata.TimeSeries) ([]metricdata.DataPoint[N], error) {
 | 
			
		||||
func convertNumberDataPoints[N int64 | float64](
 | 
			
		||||
	labelKeys []ocmetricdata.LabelKey,
 | 
			
		||||
	ts []*ocmetricdata.TimeSeries,
 | 
			
		||||
) ([]metricdata.DataPoint[N], error) {
 | 
			
		||||
	var points []metricdata.DataPoint[N]
 | 
			
		||||
	var err error
 | 
			
		||||
	for _, t := range ts {
 | 
			
		||||
| 
						 | 
				
			
			@ -117,7 +128,10 @@ func convertNumberDataPoints[N int64 | float64](labelKeys []ocmetricdata.LabelKe
 | 
			
		|||
 | 
			
		||||
// convertHistogram converts OpenCensus Distribution timeseries to an
 | 
			
		||||
// OpenTelemetry Histogram aggregation.
 | 
			
		||||
func convertHistogram(labelKeys []ocmetricdata.LabelKey, ts []*ocmetricdata.TimeSeries) (metricdata.Histogram[float64], error) {
 | 
			
		||||
func convertHistogram(
 | 
			
		||||
	labelKeys []ocmetricdata.LabelKey,
 | 
			
		||||
	ts []*ocmetricdata.TimeSeries,
 | 
			
		||||
) (metricdata.Histogram[float64], error) {
 | 
			
		||||
	points := make([]metricdata.HistogramDataPoint[float64], 0, len(ts))
 | 
			
		||||
	var err error
 | 
			
		||||
	for _, t := range ts {
 | 
			
		||||
| 
						 | 
				
			
			@ -390,7 +404,12 @@ func convertQuantiles(snapshot ocmetricdata.Snapshot) []metricdata.QuantileValue
 | 
			
		|||
// OpenTelemetry attribute Set.
 | 
			
		||||
func convertAttrs(keys []ocmetricdata.LabelKey, values []ocmetricdata.LabelValue) (attribute.Set, error) {
 | 
			
		||||
	if len(keys) != len(values) {
 | 
			
		||||
		return attribute.NewSet(), fmt.Errorf("%w: keys(%q) values(%q)", errMismatchedAttributeKeyValues, len(keys), len(values))
 | 
			
		||||
		return attribute.NewSet(), fmt.Errorf(
 | 
			
		||||
			"%w: keys(%q) values(%q)",
 | 
			
		||||
			errMismatchedAttributeKeyValues,
 | 
			
		||||
			len(keys),
 | 
			
		||||
			len(values),
 | 
			
		||||
		)
 | 
			
		||||
	}
 | 
			
		||||
	attrs := []attribute.KeyValue{}
 | 
			
		||||
	for i, lv := range values {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -989,10 +989,22 @@ func TestConvertAttributes(t *testing.T) {
 | 
			
		|||
		t.Run(tc.desc, func(t *testing.T) {
 | 
			
		||||
			output, err := convertAttrs(tc.inputKeys, tc.inputValues)
 | 
			
		||||
			if !errors.Is(err, tc.expectedErr) {
 | 
			
		||||
				t.Errorf("convertAttrs(keys: %v, values: %v) = err(%v), want err(%v)", tc.inputKeys, tc.inputValues, err, tc.expectedErr)
 | 
			
		||||
				t.Errorf(
 | 
			
		||||
					"convertAttrs(keys: %v, values: %v) = err(%v), want err(%v)",
 | 
			
		||||
					tc.inputKeys,
 | 
			
		||||
					tc.inputValues,
 | 
			
		||||
					err,
 | 
			
		||||
					tc.expectedErr,
 | 
			
		||||
				)
 | 
			
		||||
			}
 | 
			
		||||
			if !output.Equals(tc.expected) {
 | 
			
		||||
				t.Errorf("convertAttrs(keys: %v, values: %v) = %+v, want %+v", tc.inputKeys, tc.inputValues, output.ToSlice(), tc.expected.ToSlice())
 | 
			
		||||
				t.Errorf(
 | 
			
		||||
					"convertAttrs(keys: %v, values: %v) = %+v, want %+v",
 | 
			
		||||
					tc.inputKeys,
 | 
			
		||||
					tc.inputValues,
 | 
			
		||||
					output.ToSlice(),
 | 
			
		||||
					tc.expected.ToSlice(),
 | 
			
		||||
				)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -124,10 +124,18 @@ func TestSpanSetStatus(t *testing.T) {
 | 
			
		|||
			ocS.SetStatus(status)
 | 
			
		||||
 | 
			
		||||
			if s.sCode != tt.wantCode {
 | 
			
		||||
				t.Errorf("span.SetStatus failed to set OpenTelemetry status code. Expected %d, got %d", tt.wantCode, s.sCode)
 | 
			
		||||
				t.Errorf(
 | 
			
		||||
					"span.SetStatus failed to set OpenTelemetry status code. Expected %d, got %d",
 | 
			
		||||
					tt.wantCode,
 | 
			
		||||
					s.sCode,
 | 
			
		||||
				)
 | 
			
		||||
			}
 | 
			
		||||
			if s.sMsg != tt.message {
 | 
			
		||||
				t.Errorf("span.SetStatus failed to set OpenTelemetry status description. Expected %s, got %s", tt.message, s.sMsg)
 | 
			
		||||
				t.Errorf(
 | 
			
		||||
					"span.SetStatus failed to set OpenTelemetry status description. Expected %s, got %s",
 | 
			
		||||
					tt.message,
 | 
			
		||||
					s.sMsg,
 | 
			
		||||
				)
 | 
			
		||||
			}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -295,12 +303,22 @@ func TestSpanAddLinkFails(t *testing.T) {
 | 
			
		|||
 | 
			
		||||
	for i, l := range s.links {
 | 
			
		||||
		if !l.SpanContext.Equal(wantLinks[i].SpanContext) {
 | 
			
		||||
			t.Errorf("link[%v] has the wrong span context; want %+v, got %+v", i, wantLinks[i].SpanContext, l.SpanContext)
 | 
			
		||||
			t.Errorf(
 | 
			
		||||
				"link[%v] has the wrong span context; want %+v, got %+v",
 | 
			
		||||
				i,
 | 
			
		||||
				wantLinks[i].SpanContext,
 | 
			
		||||
				l.SpanContext,
 | 
			
		||||
			)
 | 
			
		||||
		}
 | 
			
		||||
		gotAttributeSet := attribute.NewSet(l.Attributes...)
 | 
			
		||||
		wantAttributeSet := attribute.NewSet(wantLinks[i].Attributes...)
 | 
			
		||||
		if !gotAttributeSet.Equals(&wantAttributeSet) {
 | 
			
		||||
			t.Errorf("link[%v] has the wrong attributes; want %v, got %v", i, wantAttributeSet.Encoded(attribute.DefaultEncoder()), gotAttributeSet.Encoded(attribute.DefaultEncoder()))
 | 
			
		||||
			t.Errorf(
 | 
			
		||||
				"link[%v] has the wrong attributes; want %v, got %v",
 | 
			
		||||
				i,
 | 
			
		||||
				wantAttributeSet.Encoded(attribute.DefaultEncoder()),
 | 
			
		||||
				gotAttributeSet.Encoded(attribute.DefaultEncoder()),
 | 
			
		||||
			)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,7 +25,11 @@ func NewTracer(tracer trace.Tracer) octrace.Tracer {
 | 
			
		|||
 | 
			
		||||
// StartSpan starts a new child span of the current span in the context. If
 | 
			
		||||
// there is no span in the context, it creates a new trace and span.
 | 
			
		||||
func (o *Tracer) StartSpan(ctx context.Context, name string, s ...octrace.StartOption) (context.Context, *octrace.Span) {
 | 
			
		||||
func (o *Tracer) StartSpan(
 | 
			
		||||
	ctx context.Context,
 | 
			
		||||
	name string,
 | 
			
		||||
	s ...octrace.StartOption,
 | 
			
		||||
) (context.Context, *octrace.Span) {
 | 
			
		||||
	otelOpts, err := oc2otel.StartOptions(s)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		Handle(fmt.Errorf("starting span %q: %w", name, err))
 | 
			
		||||
| 
						 | 
				
			
			@ -36,7 +40,12 @@ func (o *Tracer) StartSpan(ctx context.Context, name string, s ...octrace.StartO
 | 
			
		|||
 | 
			
		||||
// StartSpanWithRemoteParent starts a new child span of the span from the
 | 
			
		||||
// given parent.
 | 
			
		||||
func (o *Tracer) StartSpanWithRemoteParent(ctx context.Context, name string, parent octrace.SpanContext, s ...octrace.StartOption) (context.Context, *octrace.Span) {
 | 
			
		||||
func (o *Tracer) StartSpanWithRemoteParent(
 | 
			
		||||
	ctx context.Context,
 | 
			
		||||
	name string,
 | 
			
		||||
	parent octrace.SpanContext,
 | 
			
		||||
	s ...octrace.StartOption,
 | 
			
		||||
) (context.Context, *octrace.Span) {
 | 
			
		||||
	// make sure span context is zeroed out so we use the remote parent
 | 
			
		||||
	ctx = trace.ContextWithSpan(ctx, nil)
 | 
			
		||||
	ctx = trace.ContextWithRemoteSpanContext(ctx, oc2otel.SpanContext(parent))
 | 
			
		||||
| 
						 | 
				
			
			@ -53,6 +62,8 @@ func (o *Tracer) NewContext(parent context.Context, s *octrace.Span) context.Con
 | 
			
		|||
	if otSpan, ok := s.Internal().(*Span); ok {
 | 
			
		||||
		return trace.ContextWithSpan(parent, otSpan.otelSpan)
 | 
			
		||||
	}
 | 
			
		||||
	Handle(fmt.Errorf("unable to create context with span %q, since it was created using a different tracer", s.String()))
 | 
			
		||||
	Handle(
 | 
			
		||||
		fmt.Errorf("unable to create context with span %q, since it was created using a different tracer", s.String()),
 | 
			
		||||
	)
 | 
			
		||||
	return parent
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -92,7 +92,11 @@ func TestStartSpanWithRemoteParent(t *testing.T) {
 | 
			
		|||
	ctx := context.Background()
 | 
			
		||||
	ctx, parent := tracer.Start(ctx, "OpenTelemetrySpan1")
 | 
			
		||||
 | 
			
		||||
	_, span := octrace.StartSpanWithRemoteParent(ctx, "OpenCensusSpan", ocbridge.OTelSpanContextToOC(parent.SpanContext()))
 | 
			
		||||
	_, span := octrace.StartSpanWithRemoteParent(
 | 
			
		||||
		ctx,
 | 
			
		||||
		"OpenCensusSpan",
 | 
			
		||||
		ocbridge.OTelSpanContextToOC(parent.SpanContext()),
 | 
			
		||||
	)
 | 
			
		||||
	span.End()
 | 
			
		||||
 | 
			
		||||
	spans := sr.Ended()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -283,7 +283,9 @@ type bridgeSetTracer struct {
 | 
			
		|||
func (s *bridgeSetTracer) tracer() trace.Tracer {
 | 
			
		||||
	if !s.isSet {
 | 
			
		||||
		s.warnOnce.Do(func() {
 | 
			
		||||
			s.warningHandler("The OpenTelemetry tracer is not set, default no-op tracer is used! Call SetOpenTelemetryTracer to set it up.\n")
 | 
			
		||||
			s.warningHandler(
 | 
			
		||||
				"The OpenTelemetry tracer is not set, default no-op tracer is used! Call SetOpenTelemetryTracer to set it up.\n",
 | 
			
		||||
			)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	return s.otelTracer
 | 
			
		||||
| 
						 | 
				
			
			@ -362,7 +364,9 @@ func (t *BridgeTracer) baggageSetHook(ctx context.Context, list iBaggage.List) c
 | 
			
		|||
	}
 | 
			
		||||
	bSpan, ok := span.(*bridgeSpan)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		t.warningHandler("Encountered a foreign OpenTracing span, will not propagate the baggage items from OpenTelemetry context\n")
 | 
			
		||||
		t.warningHandler(
 | 
			
		||||
			"Encountered a foreign OpenTracing span, will not propagate the baggage items from OpenTelemetry context\n",
 | 
			
		||||
		)
 | 
			
		||||
		return ctx
 | 
			
		||||
	}
 | 
			
		||||
	for k, v := range list {
 | 
			
		||||
| 
						 | 
				
			
			@ -374,12 +378,16 @@ func (t *BridgeTracer) baggageSetHook(ctx context.Context, list iBaggage.List) c
 | 
			
		|||
func (t *BridgeTracer) baggageGetHook(ctx context.Context, list iBaggage.List) iBaggage.List {
 | 
			
		||||
	span := ot.SpanFromContext(ctx)
 | 
			
		||||
	if span == nil {
 | 
			
		||||
		t.warningHandler("No active OpenTracing span, can not propagate the baggage items from OpenTracing span context\n")
 | 
			
		||||
		t.warningHandler(
 | 
			
		||||
			"No active OpenTracing span, can not propagate the baggage items from OpenTracing span context\n",
 | 
			
		||||
		)
 | 
			
		||||
		return list
 | 
			
		||||
	}
 | 
			
		||||
	bSpan, ok := span.(*bridgeSpan)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		t.warningHandler("Encountered a foreign OpenTracing span, will not propagate the baggage items from OpenTracing span context\n")
 | 
			
		||||
		t.warningHandler(
 | 
			
		||||
			"Encountered a foreign OpenTracing span, will not propagate the baggage items from OpenTracing span context\n",
 | 
			
		||||
		)
 | 
			
		||||
		return list
 | 
			
		||||
	}
 | 
			
		||||
	items := bSpan.extraBaggageItems
 | 
			
		||||
| 
						 | 
				
			
			@ -427,7 +435,9 @@ func (t *BridgeTracer) StartSpan(operationName string, opts ...ot.StartSpanOptio
 | 
			
		|||
	)
 | 
			
		||||
	if ot.SpanFromContext(checkCtx2) != nil {
 | 
			
		||||
		t.warnOnce.Do(func() {
 | 
			
		||||
			t.warningHandler("SDK should have deferred the context setup, see the documentation of go.opentelemetry.io/otel/bridge/opentracing/migration\n")
 | 
			
		||||
			t.warningHandler(
 | 
			
		||||
				"SDK should have deferred the context setup, see the documentation of go.opentelemetry.io/otel/bridge/opentracing/migration\n",
 | 
			
		||||
			)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	if hadTrueErrorTag {
 | 
			
		||||
| 
						 | 
				
			
			@ -473,7 +483,9 @@ func (t *BridgeTracer) ContextWithBridgeSpan(ctx context.Context, span trace.Spa
 | 
			
		|||
func (t *BridgeTracer) ContextWithSpanHook(ctx context.Context, span ot.Span) context.Context {
 | 
			
		||||
	bSpan, ok := span.(*bridgeSpan)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		t.warningHandler("Encountered a foreign OpenTracing span, will not run a possible deferred context setup hook\n")
 | 
			
		||||
		t.warningHandler(
 | 
			
		||||
			"Encountered a foreign OpenTracing span, will not run a possible deferred context setup hook\n",
 | 
			
		||||
		)
 | 
			
		||||
		return ctx
 | 
			
		||||
	}
 | 
			
		||||
	if bSpan.skipDeferHook {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -368,7 +368,11 @@ type nonDeferWrapperTracer struct {
 | 
			
		|||
	*WrapperTracer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *nonDeferWrapperTracer) Start(ctx context.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
 | 
			
		||||
func (t *nonDeferWrapperTracer) Start(
 | 
			
		||||
	ctx context.Context,
 | 
			
		||||
	name string,
 | 
			
		||||
	opts ...trace.SpanStartOption,
 | 
			
		||||
) (context.Context, trace.Span) {
 | 
			
		||||
	// Run start on the parent wrapper with a brand new context
 | 
			
		||||
	// so `WithDeferredSetup` hasn't been called, and the OpenTracing context is injected.
 | 
			
		||||
	return t.WrapperTracer.Start(context.Background(), name, opts...)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -63,7 +63,11 @@ func NewMockTracer() *MockTracer {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *MockTracer) Start(ctx context.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
 | 
			
		||||
func (t *MockTracer) Start(
 | 
			
		||||
	ctx context.Context,
 | 
			
		||||
	name string,
 | 
			
		||||
	opts ...trace.SpanStartOption,
 | 
			
		||||
) (context.Context, trace.Span) {
 | 
			
		||||
	config := trace.NewSpanStartConfig(opts...)
 | 
			
		||||
	startTime := config.Timestamp()
 | 
			
		||||
	if startTime.IsZero() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -177,20 +177,38 @@ func (cast *currentActiveSpanTest) setup(t *testing.T, tracer *internal.MockTrac
 | 
			
		|||
func (cast *currentActiveSpanTest) check(t *testing.T, tracer *internal.MockTracer) {
 | 
			
		||||
	checkTraceAndSpans(t, tracer, cast.traceID, cast.spanIDs)
 | 
			
		||||
	if len(cast.recordedCurrentOtelSpanIDs) != len(cast.spanIDs) {
 | 
			
		||||
		t.Errorf("Expected to have %d recorded Otel current spans, got %d", len(cast.spanIDs), len(cast.recordedCurrentOtelSpanIDs))
 | 
			
		||||
		t.Errorf(
 | 
			
		||||
			"Expected to have %d recorded Otel current spans, got %d",
 | 
			
		||||
			len(cast.spanIDs),
 | 
			
		||||
			len(cast.recordedCurrentOtelSpanIDs),
 | 
			
		||||
		)
 | 
			
		||||
	}
 | 
			
		||||
	if len(cast.recordedActiveOTSpanIDs) != len(cast.spanIDs) {
 | 
			
		||||
		t.Errorf("Expected to have %d recorded OT active spans, got %d", len(cast.spanIDs), len(cast.recordedActiveOTSpanIDs))
 | 
			
		||||
		t.Errorf(
 | 
			
		||||
			"Expected to have %d recorded OT active spans, got %d",
 | 
			
		||||
			len(cast.spanIDs),
 | 
			
		||||
			len(cast.recordedActiveOTSpanIDs),
 | 
			
		||||
		)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	minLen := min(len(cast.recordedCurrentOtelSpanIDs), len(cast.spanIDs))
 | 
			
		||||
	minLen = min(minLen, len(cast.recordedActiveOTSpanIDs))
 | 
			
		||||
	for i := 0; i < minLen; i++ {
 | 
			
		||||
		if cast.recordedCurrentOtelSpanIDs[i] != cast.spanIDs[i] {
 | 
			
		||||
			t.Errorf("Expected span idx %d (%d) to be recorded as current span in Otel, got %d", i, cast.spanIDs[i], cast.recordedCurrentOtelSpanIDs[i])
 | 
			
		||||
			t.Errorf(
 | 
			
		||||
				"Expected span idx %d (%d) to be recorded as current span in Otel, got %d",
 | 
			
		||||
				i,
 | 
			
		||||
				cast.spanIDs[i],
 | 
			
		||||
				cast.recordedCurrentOtelSpanIDs[i],
 | 
			
		||||
			)
 | 
			
		||||
		}
 | 
			
		||||
		if cast.recordedActiveOTSpanIDs[i] != cast.spanIDs[i] {
 | 
			
		||||
			t.Errorf("Expected span idx %d (%d) to be recorded as active span in OT, got %d", i, cast.spanIDs[i], cast.recordedActiveOTSpanIDs[i])
 | 
			
		||||
			t.Errorf(
 | 
			
		||||
				"Expected span idx %d (%d) to be recorded as active span in OT, got %d",
 | 
			
		||||
				i,
 | 
			
		||||
				cast.spanIDs[i],
 | 
			
		||||
				cast.recordedActiveOTSpanIDs[i],
 | 
			
		||||
			)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -264,7 +282,11 @@ func (coin *contextIntactTest) setup(t *testing.T, tracer *internal.MockTracer)
 | 
			
		|||
 | 
			
		||||
func (coin *contextIntactTest) check(t *testing.T, tracer *internal.MockTracer) {
 | 
			
		||||
	if len(coin.recordedContextValues) != len(coin.contextKeyValues) {
 | 
			
		||||
		t.Errorf("Expected to have %d recorded context values, got %d", len(coin.contextKeyValues), len(coin.recordedContextValues))
 | 
			
		||||
		t.Errorf(
 | 
			
		||||
			"Expected to have %d recorded context values, got %d",
 | 
			
		||||
			len(coin.contextKeyValues),
 | 
			
		||||
			len(coin.recordedContextValues),
 | 
			
		||||
		)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	minLen := min(len(coin.recordedContextValues), len(coin.contextKeyValues))
 | 
			
		||||
| 
						 | 
				
			
			@ -344,7 +366,12 @@ func (bip *baggageItemsPreservationTest) check(t *testing.T, tracer *internal.Mo
 | 
			
		|||
	for i := 0; i < minLen; i++ {
 | 
			
		||||
		recordedItems := bip.recordedBaggage[i]
 | 
			
		||||
		if len(recordedItems) != i+1 {
 | 
			
		||||
			t.Errorf("Expected %d recorded baggage items in recording %d, got %d", i+1, i+1, len(bip.recordedBaggage[i]))
 | 
			
		||||
			t.Errorf(
 | 
			
		||||
				"Expected %d recorded baggage items in recording %d, got %d",
 | 
			
		||||
				i+1,
 | 
			
		||||
				i+1,
 | 
			
		||||
				len(bip.recordedBaggage[i]),
 | 
			
		||||
			)
 | 
			
		||||
		}
 | 
			
		||||
		minItemLen := min(len(bip.baggageItems), i+1)
 | 
			
		||||
		for j := 0; j < minItemLen; j++ {
 | 
			
		||||
| 
						 | 
				
			
			@ -452,7 +479,13 @@ func checkBIORecording(t *testing.T, apiDesc string, initialItems []bipBaggage,
 | 
			
		|||
		recordedItems := recordings[i]
 | 
			
		||||
		expectedItemsInStep := (i + 1) * 2
 | 
			
		||||
		if expectedItemsInStep != len(recordedItems) {
 | 
			
		||||
			t.Errorf("Expected %d recorded items in recording %d from %s, got %d", expectedItemsInStep, i, apiDesc, len(recordedItems))
 | 
			
		||||
			t.Errorf(
 | 
			
		||||
				"Expected %d recorded items in recording %d from %s, got %d",
 | 
			
		||||
				expectedItemsInStep,
 | 
			
		||||
				i,
 | 
			
		||||
				apiDesc,
 | 
			
		||||
				len(recordedItems),
 | 
			
		||||
			)
 | 
			
		||||
		}
 | 
			
		||||
		recordedItemsCopy := make(map[string]string, len(recordedItems))
 | 
			
		||||
		for k, v := range recordedItems {
 | 
			
		||||
| 
						 | 
				
			
			@ -464,7 +497,14 @@ func checkBIORecording(t *testing.T, apiDesc string, initialItems []bipBaggage,
 | 
			
		|||
			for _, k := range []string{otKey, otelKey} {
 | 
			
		||||
				if v, ok := recordedItemsCopy[k]; ok {
 | 
			
		||||
					if value != v {
 | 
			
		||||
						t.Errorf("Expected value %s under key %s in recording %d from %s, got %s", value, k, i, apiDesc, v)
 | 
			
		||||
						t.Errorf(
 | 
			
		||||
							"Expected value %s under key %s in recording %d from %s, got %s",
 | 
			
		||||
							value,
 | 
			
		||||
							k,
 | 
			
		||||
							i,
 | 
			
		||||
							apiDesc,
 | 
			
		||||
							v,
 | 
			
		||||
						)
 | 
			
		||||
					}
 | 
			
		||||
					delete(recordedItemsCopy, k)
 | 
			
		||||
				} else {
 | 
			
		||||
| 
						 | 
				
			
			@ -537,7 +577,12 @@ func generateBaggageKeys(key string) (otKey, otelKey string) {
 | 
			
		|||
 | 
			
		||||
// helpers
 | 
			
		||||
 | 
			
		||||
func checkTraceAndSpans(t *testing.T, tracer *internal.MockTracer, expectedTraceID trace.TraceID, expectedSpanIDs []trace.SpanID) {
 | 
			
		||||
func checkTraceAndSpans(
 | 
			
		||||
	t *testing.T,
 | 
			
		||||
	tracer *internal.MockTracer,
 | 
			
		||||
	expectedTraceID trace.TraceID,
 | 
			
		||||
	expectedSpanIDs []trace.SpanID,
 | 
			
		||||
) {
 | 
			
		||||
	expectedSpanCount := len(expectedSpanIDs)
 | 
			
		||||
 | 
			
		||||
	// reverse spanIDs, since first span ID belongs to root, that
 | 
			
		||||
| 
						 | 
				
			
			@ -562,7 +607,13 @@ func checkTraceAndSpans(t *testing.T, tracer *internal.MockTracer, expectedTrace
 | 
			
		|||
	for idx, span := range tracer.FinishedSpans {
 | 
			
		||||
		sctx := span.SpanContext()
 | 
			
		||||
		if sctx.TraceID() != expectedTraceID {
 | 
			
		||||
			t.Errorf("Expected trace ID %v in span %d (%d), got %v", expectedTraceID, idx, sctx.SpanID(), sctx.TraceID())
 | 
			
		||||
			t.Errorf(
 | 
			
		||||
				"Expected trace ID %v in span %d (%d), got %v",
 | 
			
		||||
				expectedTraceID,
 | 
			
		||||
				idx,
 | 
			
		||||
				sctx.SpanID(),
 | 
			
		||||
				sctx.TraceID(),
 | 
			
		||||
			)
 | 
			
		||||
		}
 | 
			
		||||
		expectedSpanID := spanIDs[idx]
 | 
			
		||||
		expectedParentSpanID := parentSpanIDs[idx]
 | 
			
		||||
| 
						 | 
				
			
			@ -570,10 +621,22 @@ func checkTraceAndSpans(t *testing.T, tracer *internal.MockTracer, expectedTrace
 | 
			
		|||
			t.Errorf("Expected finished span %d to have span ID %d, but got %d", idx, expectedSpanID, sctx.SpanID())
 | 
			
		||||
		}
 | 
			
		||||
		if span.ParentSpanID != expectedParentSpanID {
 | 
			
		||||
			t.Errorf("Expected finished span %d (span ID: %d) to have parent span ID %d, but got %d", idx, sctx.SpanID(), expectedParentSpanID, span.ParentSpanID)
 | 
			
		||||
			t.Errorf(
 | 
			
		||||
				"Expected finished span %d (span ID: %d) to have parent span ID %d, but got %d",
 | 
			
		||||
				idx,
 | 
			
		||||
				sctx.SpanID(),
 | 
			
		||||
				expectedParentSpanID,
 | 
			
		||||
				span.ParentSpanID,
 | 
			
		||||
			)
 | 
			
		||||
		}
 | 
			
		||||
		if span.SpanKind != sks[span.SpanContext().SpanID()] {
 | 
			
		||||
			t.Errorf("Expected finished span %d (span ID: %d) to have span.kind to be '%v' but was '%v'", idx, sctx.SpanID(), sks[span.SpanContext().SpanID()], span.SpanKind)
 | 
			
		||||
			t.Errorf(
 | 
			
		||||
				"Expected finished span %d (span ID: %d) to have span.kind to be '%v' but was '%v'",
 | 
			
		||||
				idx,
 | 
			
		||||
				sctx.SpanID(),
 | 
			
		||||
				sks[span.SpanContext().SpanID()],
 | 
			
		||||
				span.SpanKind,
 | 
			
		||||
			)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -600,7 +663,12 @@ func simpleSpanIDs(count int) []trace.SpanID {
 | 
			
		|||
	return base[:count]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func runOtelOTOtel(t *testing.T, ctx context.Context, name string, callback func(*testing.T, context.Context) context.Context) {
 | 
			
		||||
func runOtelOTOtel(
 | 
			
		||||
	t *testing.T,
 | 
			
		||||
	ctx context.Context,
 | 
			
		||||
	name string,
 | 
			
		||||
	callback func(*testing.T, context.Context) context.Context,
 | 
			
		||||
) {
 | 
			
		||||
	tr := otel.Tracer("")
 | 
			
		||||
	ctx, span := tr.Start(ctx, fmt.Sprintf("%s_Otel_OTOtel", name), trace.WithSpanKind(trace.SpanKindClient))
 | 
			
		||||
	defer span.End()
 | 
			
		||||
| 
						 | 
				
			
			@ -610,16 +678,29 @@ func runOtelOTOtel(t *testing.T, ctx context.Context, name string, callback func
 | 
			
		|||
		defer span.Finish()
 | 
			
		||||
		ctx2 = callback(t, ctx2)
 | 
			
		||||
		func(ctx3 context.Context) {
 | 
			
		||||
			ctx3, span := tr.Start(ctx3, fmt.Sprintf("%sOtelOT_Otel_", name), trace.WithSpanKind(trace.SpanKindProducer))
 | 
			
		||||
			ctx3, span := tr.Start(
 | 
			
		||||
				ctx3,
 | 
			
		||||
				fmt.Sprintf("%sOtelOT_Otel_", name),
 | 
			
		||||
				trace.WithSpanKind(trace.SpanKindProducer),
 | 
			
		||||
			)
 | 
			
		||||
			defer span.End()
 | 
			
		||||
			_ = callback(t, ctx3)
 | 
			
		||||
		}(ctx2)
 | 
			
		||||
	}(ctx)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func runOTOtelOT(t *testing.T, ctx context.Context, name string, callback func(*testing.T, context.Context) context.Context) {
 | 
			
		||||
func runOTOtelOT(
 | 
			
		||||
	t *testing.T,
 | 
			
		||||
	ctx context.Context,
 | 
			
		||||
	name string,
 | 
			
		||||
	callback func(*testing.T, context.Context) context.Context,
 | 
			
		||||
) {
 | 
			
		||||
	tr := otel.Tracer("")
 | 
			
		||||
	span, ctx := ot.StartSpanFromContext(ctx, fmt.Sprintf("%s_OT_OtelOT", name), ot.Tag{Key: "span.kind", Value: "client"})
 | 
			
		||||
	span, ctx := ot.StartSpanFromContext(
 | 
			
		||||
		ctx,
 | 
			
		||||
		fmt.Sprintf("%s_OT_OtelOT", name),
 | 
			
		||||
		ot.Tag{Key: "span.kind", Value: "client"},
 | 
			
		||||
	)
 | 
			
		||||
	defer span.Finish()
 | 
			
		||||
	ctx = callback(t, ctx)
 | 
			
		||||
	func(ctx2 context.Context) {
 | 
			
		||||
| 
						 | 
				
			
			@ -627,7 +708,11 @@ func runOTOtelOT(t *testing.T, ctx context.Context, name string, callback func(*
 | 
			
		|||
		defer span.End()
 | 
			
		||||
		ctx2 = callback(t, ctx2)
 | 
			
		||||
		func(ctx3 context.Context) {
 | 
			
		||||
			span, ctx3 := ot.StartSpanFromContext(ctx3, fmt.Sprintf("%sOTOtel_OT_", name), ot.Tag{Key: "span.kind", Value: "producer"})
 | 
			
		||||
			span, ctx3 := ot.StartSpanFromContext(
 | 
			
		||||
				ctx3,
 | 
			
		||||
				fmt.Sprintf("%sOTOtel_OT_", name),
 | 
			
		||||
				ot.Tag{Key: "span.kind", Value: "producer"},
 | 
			
		||||
			)
 | 
			
		||||
			defer span.Finish()
 | 
			
		||||
			_ = callback(t, ctx3)
 | 
			
		||||
		}(ctx2)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -73,7 +73,11 @@ func TestTracerProvider(t *testing.T) {
 | 
			
		|||
				return provider.Tracer(foobar, trace.WithInstrumentationAttributes(attribute.String("foo", "bar")))
 | 
			
		||||
			},
 | 
			
		||||
			func() trace.Tracer {
 | 
			
		||||
				return provider.Tracer(foobar, trace.WithSchemaURL("https://opentelemetry.io/schemas/1.2.0"), trace.WithInstrumentationAttributes(attribute.String("foo", "bar")))
 | 
			
		||||
				return provider.Tracer(
 | 
			
		||||
					foobar,
 | 
			
		||||
					trace.WithSchemaURL("https://opentelemetry.io/schemas/1.2.0"),
 | 
			
		||||
					trace.WithInstrumentationAttributes(attribute.String("foo", "bar")),
 | 
			
		||||
				)
 | 
			
		||||
			},
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,7 +25,10 @@ func NewTracerPair(tracer trace.Tracer) (*BridgeTracer, *WrapperTracerProvider)
 | 
			
		|||
// NewTracerPairWithContext is a convenience function. It calls NewTracerPair
 | 
			
		||||
// and returns a hooked version of ctx with the created BridgeTracer along
 | 
			
		||||
// with the BridgeTracer and WrapperTracerProvider.
 | 
			
		||||
func NewTracerPairWithContext(ctx context.Context, tracer trace.Tracer) (context.Context, *BridgeTracer, *WrapperTracerProvider) {
 | 
			
		||||
func NewTracerPairWithContext(
 | 
			
		||||
	ctx context.Context,
 | 
			
		||||
	tracer trace.Tracer,
 | 
			
		||||
) (context.Context, *BridgeTracer, *WrapperTracerProvider) {
 | 
			
		||||
	bridgeTracer, wrapperProvider := NewTracerPair(tracer)
 | 
			
		||||
	ctx = bridgeTracer.NewHookedContext(ctx)
 | 
			
		||||
	return ctx, bridgeTracer, wrapperProvider
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -76,7 +76,11 @@ func (t *WrapperTracer) otelTracer() trace.Tracer {
 | 
			
		|||
// Start forwards the call to the wrapped tracer. It also tries to
 | 
			
		||||
// override the tracer of the returned span if the span implements the
 | 
			
		||||
// OverrideTracerSpanExtension interface.
 | 
			
		||||
func (t *WrapperTracer) Start(ctx context.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
 | 
			
		||||
func (t *WrapperTracer) Start(
 | 
			
		||||
	ctx context.Context,
 | 
			
		||||
	name string,
 | 
			
		||||
	opts ...trace.SpanStartOption,
 | 
			
		||||
) (context.Context, trace.Span) {
 | 
			
		||||
	ctx, span := t.otelTracer().Start(ctx, name, opts...)
 | 
			
		||||
	if spanWithExtension, ok := span.(migration.OverrideTracerSpanExtension); ok {
 | 
			
		||||
		spanWithExtension.OverrideTracer(t)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -427,7 +427,10 @@ func newGRPCCollector(endpoint string, resultCh <-chan exportResult) (*grpcColle
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// Export handles the export req.
 | 
			
		||||
func (c *grpcCollector) Export(ctx context.Context, req *collogpb.ExportLogsServiceRequest) (*collogpb.ExportLogsServiceResponse, error) {
 | 
			
		||||
func (c *grpcCollector) Export(
 | 
			
		||||
	ctx context.Context,
 | 
			
		||||
	req *collogpb.ExportLogsServiceRequest,
 | 
			
		||||
) (*collogpb.ExportLogsServiceResponse, error) {
 | 
			
		||||
	c.storage.Add(req)
 | 
			
		||||
 | 
			
		||||
	if h, ok := metadata.FromIncomingContext(ctx); ok {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -229,7 +229,11 @@ type httpCollector struct {
 | 
			
		|||
// If errCh is not nil, the collector will respond to HTTP requests with errors
 | 
			
		||||
// sent on that channel. This means that if errCh is not nil Export calls will
 | 
			
		||||
// block until an error is received.
 | 
			
		||||
func newHTTPCollector(endpoint string, resultCh <-chan exportResult, opts ...func(*httpCollector)) (*httpCollector, error) {
 | 
			
		||||
func newHTTPCollector(
 | 
			
		||||
	endpoint string,
 | 
			
		||||
	resultCh <-chan exportResult,
 | 
			
		||||
	opts ...func(*httpCollector),
 | 
			
		||||
) (*httpCollector, error) {
 | 
			
		||||
	u, err := url.Parse(endpoint)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -80,8 +80,16 @@ func getOptionsFromEnv() []GenericOption {
 | 
			
		|||
		}),
 | 
			
		||||
		envconfig.WithCertPool("CERTIFICATE", func(p *x509.CertPool) { tlsConf.RootCAs = p }),
 | 
			
		||||
		envconfig.WithCertPool("METRICS_CERTIFICATE", func(p *x509.CertPool) { tlsConf.RootCAs = p }),
 | 
			
		||||
		envconfig.WithClientCert("CLIENT_CERTIFICATE", "CLIENT_KEY", func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} }),
 | 
			
		||||
		envconfig.WithClientCert("METRICS_CLIENT_CERTIFICATE", "METRICS_CLIENT_KEY", func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} }),
 | 
			
		||||
		envconfig.WithClientCert(
 | 
			
		||||
			"CLIENT_CERTIFICATE",
 | 
			
		||||
			"CLIENT_KEY",
 | 
			
		||||
			func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} },
 | 
			
		||||
		),
 | 
			
		||||
		envconfig.WithClientCert(
 | 
			
		||||
			"METRICS_CLIENT_CERTIFICATE",
 | 
			
		||||
			"METRICS_CLIENT_KEY",
 | 
			
		||||
			func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} },
 | 
			
		||||
		),
 | 
			
		||||
		envconfig.WithBool("INSECURE", func(b bool) { opts = append(opts, withInsecure(b)) }),
 | 
			
		||||
		envconfig.WithBool("METRICS_INSECURE", func(b bool) { opts = append(opts, withInsecure(b)) }),
 | 
			
		||||
		withTLSConfig(tlsConf, func(c *tls.Config) { opts = append(opts, WithTLSClientConfig(c)) }),
 | 
			
		||||
| 
						 | 
				
			
			@ -91,8 +99,14 @@ func getOptionsFromEnv() []GenericOption {
 | 
			
		|||
		WithEnvCompression("METRICS_COMPRESSION", func(c Compression) { opts = append(opts, WithCompression(c)) }),
 | 
			
		||||
		envconfig.WithDuration("TIMEOUT", func(d time.Duration) { opts = append(opts, WithTimeout(d)) }),
 | 
			
		||||
		envconfig.WithDuration("METRICS_TIMEOUT", func(d time.Duration) { opts = append(opts, WithTimeout(d)) }),
 | 
			
		||||
		withEnvTemporalityPreference("METRICS_TEMPORALITY_PREFERENCE", func(t metric.TemporalitySelector) { opts = append(opts, WithTemporalitySelector(t)) }),
 | 
			
		||||
		withEnvAggPreference("METRICS_DEFAULT_HISTOGRAM_AGGREGATION", func(a metric.AggregationSelector) { opts = append(opts, WithAggregationSelector(a)) }),
 | 
			
		||||
		withEnvTemporalityPreference(
 | 
			
		||||
			"METRICS_TEMPORALITY_PREFERENCE",
 | 
			
		||||
			func(t metric.TemporalitySelector) { opts = append(opts, WithTemporalitySelector(t)) },
 | 
			
		||||
		),
 | 
			
		||||
		withEnvAggPreference(
 | 
			
		||||
			"METRICS_DEFAULT_HISTOGRAM_AGGREGATION",
 | 
			
		||||
			func(a metric.AggregationSelector) { opts = append(opts, WithAggregationSelector(a)) },
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	return opts
 | 
			
		||||
| 
						 | 
				
			
			@ -157,7 +171,11 @@ func withEnvTemporalityPreference(n string, fn func(metric.TemporalitySelector))
 | 
			
		|||
			case "lowmemory":
 | 
			
		||||
				fn(lowMemory)
 | 
			
		||||
			default:
 | 
			
		||||
				global.Warn("OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE is set to an invalid value, ignoring.", "value", s)
 | 
			
		||||
				global.Warn(
 | 
			
		||||
					"OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE is set to an invalid value, ignoring.",
 | 
			
		||||
					"value",
 | 
			
		||||
					s,
 | 
			
		||||
				)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -203,7 +221,11 @@ func withEnvAggPreference(n string, fn func(metric.AggregationSelector)) func(e
 | 
			
		|||
					return metric.DefaultAggregationSelector(kind)
 | 
			
		||||
				})
 | 
			
		||||
			default:
 | 
			
		||||
				global.Warn("OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION is set to an invalid value, ignoring.", "value", s)
 | 
			
		||||
				global.Warn(
 | 
			
		||||
					"OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION is set to an invalid value, ignoring.",
 | 
			
		||||
					"value",
 | 
			
		||||
					s,
 | 
			
		||||
				)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -113,12 +113,24 @@ func TestWithEnvAggPreference(t *testing.T) {
 | 
			
		|||
			name:     "explicit_bucket_histogram",
 | 
			
		||||
			envValue: "explicit_bucket_histogram",
 | 
			
		||||
			want: map[metric.InstrumentKind]metric.Aggregation{
 | 
			
		||||
				metric.InstrumentKindCounter:                 metric.DefaultAggregationSelector(metric.InstrumentKindCounter),
 | 
			
		||||
				metric.InstrumentKindHistogram:               metric.DefaultAggregationSelector(metric.InstrumentKindHistogram),
 | 
			
		||||
				metric.InstrumentKindUpDownCounter:           metric.DefaultAggregationSelector(metric.InstrumentKindUpDownCounter),
 | 
			
		||||
				metric.InstrumentKindObservableCounter:       metric.DefaultAggregationSelector(metric.InstrumentKindObservableCounter),
 | 
			
		||||
				metric.InstrumentKindObservableUpDownCounter: metric.DefaultAggregationSelector(metric.InstrumentKindObservableUpDownCounter),
 | 
			
		||||
				metric.InstrumentKindObservableGauge:         metric.DefaultAggregationSelector(metric.InstrumentKindObservableGauge),
 | 
			
		||||
				metric.InstrumentKindCounter: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindCounter,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindHistogram: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindHistogram,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindUpDownCounter: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindUpDownCounter,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindObservableCounter: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindObservableCounter,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindObservableUpDownCounter: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindObservableUpDownCounter,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindObservableGauge: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindObservableGauge,
 | 
			
		||||
				),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			@ -131,10 +143,18 @@ func TestWithEnvAggPreference(t *testing.T) {
 | 
			
		|||
					MaxScale: 20,
 | 
			
		||||
					NoMinMax: false,
 | 
			
		||||
				},
 | 
			
		||||
				metric.InstrumentKindUpDownCounter:           metric.DefaultAggregationSelector(metric.InstrumentKindUpDownCounter),
 | 
			
		||||
				metric.InstrumentKindObservableCounter:       metric.DefaultAggregationSelector(metric.InstrumentKindObservableCounter),
 | 
			
		||||
				metric.InstrumentKindObservableUpDownCounter: metric.DefaultAggregationSelector(metric.InstrumentKindObservableUpDownCounter),
 | 
			
		||||
				metric.InstrumentKindObservableGauge:         metric.DefaultAggregationSelector(metric.InstrumentKindObservableGauge),
 | 
			
		||||
				metric.InstrumentKindUpDownCounter: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindUpDownCounter,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindObservableCounter: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindObservableCounter,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindObservableUpDownCounter: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindObservableUpDownCounter,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindObservableGauge: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindObservableGauge,
 | 
			
		||||
				),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -142,7 +142,10 @@ func (c *GRPCCollector) Headers() map[string][]string {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// Export handles the export req.
 | 
			
		||||
func (c *GRPCCollector) Export(ctx context.Context, req *collpb.ExportMetricsServiceRequest) (*collpb.ExportMetricsServiceResponse, error) {
 | 
			
		||||
func (c *GRPCCollector) Export(
 | 
			
		||||
	ctx context.Context,
 | 
			
		||||
	req *collpb.ExportMetricsServiceRequest,
 | 
			
		||||
) (*collpb.ExportMetricsServiceResponse, error) {
 | 
			
		||||
	c.storage.Add(req)
 | 
			
		||||
 | 
			
		||||
	if h, ok := metadata.FromIncomingContext(ctx); ok {
 | 
			
		||||
| 
						 | 
				
			
			@ -208,7 +211,11 @@ type HTTPCollector struct {
 | 
			
		|||
// If errCh is not nil, the collector will respond to HTTP requests with errors
 | 
			
		||||
// sent on that channel. This means that if errCh is not nil Export calls will
 | 
			
		||||
// block until an error is received.
 | 
			
		||||
func NewHTTPCollector(endpoint string, resultCh <-chan ExportResult, opts ...func(*HTTPCollector)) (*HTTPCollector, error) {
 | 
			
		||||
func NewHTTPCollector(
 | 
			
		||||
	endpoint string,
 | 
			
		||||
	resultCh <-chan ExportResult,
 | 
			
		||||
	opts ...func(*HTTPCollector),
 | 
			
		||||
) (*HTTPCollector, error) {
 | 
			
		||||
	u, err := url.Parse(endpoint)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,6 +28,10 @@ func requireErrorString(t *testing.T, expect string, err error) {
 | 
			
		|||
func TestPartialSuccessFormat(t *testing.T) {
 | 
			
		||||
	requireErrorString(t, "empty message (0 metric data points rejected)", MetricPartialSuccessError(0, ""))
 | 
			
		||||
	requireErrorString(t, "help help (0 metric data points rejected)", MetricPartialSuccessError(0, "help help"))
 | 
			
		||||
	requireErrorString(t, "what happened (10 metric data points rejected)", MetricPartialSuccessError(10, "what happened"))
 | 
			
		||||
	requireErrorString(
 | 
			
		||||
		t,
 | 
			
		||||
		"what happened (10 metric data points rejected)",
 | 
			
		||||
		MetricPartialSuccessError(10, "what happened"),
 | 
			
		||||
	)
 | 
			
		||||
	requireErrorString(t, "what happened (15 spans rejected)", TracePartialSuccessError(15, "what happened"))
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -203,7 +203,9 @@ func HistogramDataPoints[N int64 | float64](dPts []metricdata.HistogramDataPoint
 | 
			
		|||
 | 
			
		||||
// ExponentialHistogram returns an OTLP Metric_ExponentialHistogram generated from h. An error is
 | 
			
		||||
// returned if the temporality of h is unknown.
 | 
			
		||||
func ExponentialHistogram[N int64 | float64](h metricdata.ExponentialHistogram[N]) (*mpb.Metric_ExponentialHistogram, error) {
 | 
			
		||||
func ExponentialHistogram[N int64 | float64](
 | 
			
		||||
	h metricdata.ExponentialHistogram[N],
 | 
			
		||||
) (*mpb.Metric_ExponentialHistogram, error) {
 | 
			
		||||
	t, err := Temporality(h.Temporality)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
| 
						 | 
				
			
			@ -218,7 +220,9 @@ func ExponentialHistogram[N int64 | float64](h metricdata.ExponentialHistogram[N
 | 
			
		|||
 | 
			
		||||
// ExponentialHistogramDataPoints returns a slice of OTLP ExponentialHistogramDataPoint generated
 | 
			
		||||
// from dPts.
 | 
			
		||||
func ExponentialHistogramDataPoints[N int64 | float64](dPts []metricdata.ExponentialHistogramDataPoint[N]) []*mpb.ExponentialHistogramDataPoint {
 | 
			
		||||
func ExponentialHistogramDataPoints[N int64 | float64](
 | 
			
		||||
	dPts []metricdata.ExponentialHistogramDataPoint[N],
 | 
			
		||||
) []*mpb.ExponentialHistogramDataPoint {
 | 
			
		||||
	out := make([]*mpb.ExponentialHistogramDataPoint, 0, len(dPts))
 | 
			
		||||
	for _, dPt := range dPts {
 | 
			
		||||
		sum := float64(dPt.Sum)
 | 
			
		||||
| 
						 | 
				
			
			@ -250,7 +254,9 @@ func ExponentialHistogramDataPoints[N int64 | float64](dPts []metricdata.Exponen
 | 
			
		|||
 | 
			
		||||
// ExponentialHistogramDataPointBuckets returns an OTLP ExponentialHistogramDataPoint_Buckets generated
 | 
			
		||||
// from bucket.
 | 
			
		||||
func ExponentialHistogramDataPointBuckets(bucket metricdata.ExponentialBucket) *mpb.ExponentialHistogramDataPoint_Buckets {
 | 
			
		||||
func ExponentialHistogramDataPointBuckets(
 | 
			
		||||
	bucket metricdata.ExponentialBucket,
 | 
			
		||||
) *mpb.ExponentialHistogramDataPoint_Buckets {
 | 
			
		||||
	return &mpb.ExponentialHistogramDataPoint_Buckets{
 | 
			
		||||
		Offset:       bucket.Offset,
 | 
			
		||||
		BucketCounts: bucket.Counts,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -80,8 +80,16 @@ func getOptionsFromEnv() []GenericOption {
 | 
			
		|||
		}),
 | 
			
		||||
		envconfig.WithCertPool("CERTIFICATE", func(p *x509.CertPool) { tlsConf.RootCAs = p }),
 | 
			
		||||
		envconfig.WithCertPool("METRICS_CERTIFICATE", func(p *x509.CertPool) { tlsConf.RootCAs = p }),
 | 
			
		||||
		envconfig.WithClientCert("CLIENT_CERTIFICATE", "CLIENT_KEY", func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} }),
 | 
			
		||||
		envconfig.WithClientCert("METRICS_CLIENT_CERTIFICATE", "METRICS_CLIENT_KEY", func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} }),
 | 
			
		||||
		envconfig.WithClientCert(
 | 
			
		||||
			"CLIENT_CERTIFICATE",
 | 
			
		||||
			"CLIENT_KEY",
 | 
			
		||||
			func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} },
 | 
			
		||||
		),
 | 
			
		||||
		envconfig.WithClientCert(
 | 
			
		||||
			"METRICS_CLIENT_CERTIFICATE",
 | 
			
		||||
			"METRICS_CLIENT_KEY",
 | 
			
		||||
			func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} },
 | 
			
		||||
		),
 | 
			
		||||
		envconfig.WithBool("INSECURE", func(b bool) { opts = append(opts, withInsecure(b)) }),
 | 
			
		||||
		envconfig.WithBool("METRICS_INSECURE", func(b bool) { opts = append(opts, withInsecure(b)) }),
 | 
			
		||||
		withTLSConfig(tlsConf, func(c *tls.Config) { opts = append(opts, WithTLSClientConfig(c)) }),
 | 
			
		||||
| 
						 | 
				
			
			@ -91,8 +99,14 @@ func getOptionsFromEnv() []GenericOption {
 | 
			
		|||
		WithEnvCompression("METRICS_COMPRESSION", func(c Compression) { opts = append(opts, WithCompression(c)) }),
 | 
			
		||||
		envconfig.WithDuration("TIMEOUT", func(d time.Duration) { opts = append(opts, WithTimeout(d)) }),
 | 
			
		||||
		envconfig.WithDuration("METRICS_TIMEOUT", func(d time.Duration) { opts = append(opts, WithTimeout(d)) }),
 | 
			
		||||
		withEnvTemporalityPreference("METRICS_TEMPORALITY_PREFERENCE", func(t metric.TemporalitySelector) { opts = append(opts, WithTemporalitySelector(t)) }),
 | 
			
		||||
		withEnvAggPreference("METRICS_DEFAULT_HISTOGRAM_AGGREGATION", func(a metric.AggregationSelector) { opts = append(opts, WithAggregationSelector(a)) }),
 | 
			
		||||
		withEnvTemporalityPreference(
 | 
			
		||||
			"METRICS_TEMPORALITY_PREFERENCE",
 | 
			
		||||
			func(t metric.TemporalitySelector) { opts = append(opts, WithTemporalitySelector(t)) },
 | 
			
		||||
		),
 | 
			
		||||
		withEnvAggPreference(
 | 
			
		||||
			"METRICS_DEFAULT_HISTOGRAM_AGGREGATION",
 | 
			
		||||
			func(a metric.AggregationSelector) { opts = append(opts, WithAggregationSelector(a)) },
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	return opts
 | 
			
		||||
| 
						 | 
				
			
			@ -157,7 +171,11 @@ func withEnvTemporalityPreference(n string, fn func(metric.TemporalitySelector))
 | 
			
		|||
			case "lowmemory":
 | 
			
		||||
				fn(lowMemory)
 | 
			
		||||
			default:
 | 
			
		||||
				global.Warn("OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE is set to an invalid value, ignoring.", "value", s)
 | 
			
		||||
				global.Warn(
 | 
			
		||||
					"OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE is set to an invalid value, ignoring.",
 | 
			
		||||
					"value",
 | 
			
		||||
					s,
 | 
			
		||||
				)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -203,7 +221,11 @@ func withEnvAggPreference(n string, fn func(metric.AggregationSelector)) func(e
 | 
			
		|||
					return metric.DefaultAggregationSelector(kind)
 | 
			
		||||
				})
 | 
			
		||||
			default:
 | 
			
		||||
				global.Warn("OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION is set to an invalid value, ignoring.", "value", s)
 | 
			
		||||
				global.Warn(
 | 
			
		||||
					"OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION is set to an invalid value, ignoring.",
 | 
			
		||||
					"value",
 | 
			
		||||
					s,
 | 
			
		||||
				)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -113,12 +113,24 @@ func TestWithEnvAggPreference(t *testing.T) {
 | 
			
		|||
			name:     "explicit_bucket_histogram",
 | 
			
		||||
			envValue: "explicit_bucket_histogram",
 | 
			
		||||
			want: map[metric.InstrumentKind]metric.Aggregation{
 | 
			
		||||
				metric.InstrumentKindCounter:                 metric.DefaultAggregationSelector(metric.InstrumentKindCounter),
 | 
			
		||||
				metric.InstrumentKindHistogram:               metric.DefaultAggregationSelector(metric.InstrumentKindHistogram),
 | 
			
		||||
				metric.InstrumentKindUpDownCounter:           metric.DefaultAggregationSelector(metric.InstrumentKindUpDownCounter),
 | 
			
		||||
				metric.InstrumentKindObservableCounter:       metric.DefaultAggregationSelector(metric.InstrumentKindObservableCounter),
 | 
			
		||||
				metric.InstrumentKindObservableUpDownCounter: metric.DefaultAggregationSelector(metric.InstrumentKindObservableUpDownCounter),
 | 
			
		||||
				metric.InstrumentKindObservableGauge:         metric.DefaultAggregationSelector(metric.InstrumentKindObservableGauge),
 | 
			
		||||
				metric.InstrumentKindCounter: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindCounter,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindHistogram: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindHistogram,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindUpDownCounter: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindUpDownCounter,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindObservableCounter: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindObservableCounter,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindObservableUpDownCounter: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindObservableUpDownCounter,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindObservableGauge: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindObservableGauge,
 | 
			
		||||
				),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			@ -131,10 +143,18 @@ func TestWithEnvAggPreference(t *testing.T) {
 | 
			
		|||
					MaxScale: 20,
 | 
			
		||||
					NoMinMax: false,
 | 
			
		||||
				},
 | 
			
		||||
				metric.InstrumentKindUpDownCounter:           metric.DefaultAggregationSelector(metric.InstrumentKindUpDownCounter),
 | 
			
		||||
				metric.InstrumentKindObservableCounter:       metric.DefaultAggregationSelector(metric.InstrumentKindObservableCounter),
 | 
			
		||||
				metric.InstrumentKindObservableUpDownCounter: metric.DefaultAggregationSelector(metric.InstrumentKindObservableUpDownCounter),
 | 
			
		||||
				metric.InstrumentKindObservableGauge:         metric.DefaultAggregationSelector(metric.InstrumentKindObservableGauge),
 | 
			
		||||
				metric.InstrumentKindUpDownCounter: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindUpDownCounter,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindObservableCounter: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindObservableCounter,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindObservableUpDownCounter: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindObservableUpDownCounter,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindObservableGauge: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindObservableGauge,
 | 
			
		||||
				),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -142,7 +142,10 @@ func (c *GRPCCollector) Headers() map[string][]string {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// Export handles the export req.
 | 
			
		||||
func (c *GRPCCollector) Export(ctx context.Context, req *collpb.ExportMetricsServiceRequest) (*collpb.ExportMetricsServiceResponse, error) {
 | 
			
		||||
func (c *GRPCCollector) Export(
 | 
			
		||||
	ctx context.Context,
 | 
			
		||||
	req *collpb.ExportMetricsServiceRequest,
 | 
			
		||||
) (*collpb.ExportMetricsServiceResponse, error) {
 | 
			
		||||
	c.storage.Add(req)
 | 
			
		||||
 | 
			
		||||
	if h, ok := metadata.FromIncomingContext(ctx); ok {
 | 
			
		||||
| 
						 | 
				
			
			@ -208,7 +211,11 @@ type HTTPCollector struct {
 | 
			
		|||
// If errCh is not nil, the collector will respond to HTTP requests with errors
 | 
			
		||||
// sent on that channel. This means that if errCh is not nil Export calls will
 | 
			
		||||
// block until an error is received.
 | 
			
		||||
func NewHTTPCollector(endpoint string, resultCh <-chan ExportResult, opts ...func(*HTTPCollector)) (*HTTPCollector, error) {
 | 
			
		||||
func NewHTTPCollector(
 | 
			
		||||
	endpoint string,
 | 
			
		||||
	resultCh <-chan ExportResult,
 | 
			
		||||
	opts ...func(*HTTPCollector),
 | 
			
		||||
) (*HTTPCollector, error) {
 | 
			
		||||
	u, err := url.Parse(endpoint)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,6 +28,10 @@ func requireErrorString(t *testing.T, expect string, err error) {
 | 
			
		|||
func TestPartialSuccessFormat(t *testing.T) {
 | 
			
		||||
	requireErrorString(t, "empty message (0 metric data points rejected)", MetricPartialSuccessError(0, ""))
 | 
			
		||||
	requireErrorString(t, "help help (0 metric data points rejected)", MetricPartialSuccessError(0, "help help"))
 | 
			
		||||
	requireErrorString(t, "what happened (10 metric data points rejected)", MetricPartialSuccessError(10, "what happened"))
 | 
			
		||||
	requireErrorString(
 | 
			
		||||
		t,
 | 
			
		||||
		"what happened (10 metric data points rejected)",
 | 
			
		||||
		MetricPartialSuccessError(10, "what happened"),
 | 
			
		||||
	)
 | 
			
		||||
	requireErrorString(t, "what happened (15 spans rejected)", TracePartialSuccessError(15, "what happened"))
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -203,7 +203,9 @@ func HistogramDataPoints[N int64 | float64](dPts []metricdata.HistogramDataPoint
 | 
			
		|||
 | 
			
		||||
// ExponentialHistogram returns an OTLP Metric_ExponentialHistogram generated from h. An error is
 | 
			
		||||
// returned if the temporality of h is unknown.
 | 
			
		||||
func ExponentialHistogram[N int64 | float64](h metricdata.ExponentialHistogram[N]) (*mpb.Metric_ExponentialHistogram, error) {
 | 
			
		||||
func ExponentialHistogram[N int64 | float64](
 | 
			
		||||
	h metricdata.ExponentialHistogram[N],
 | 
			
		||||
) (*mpb.Metric_ExponentialHistogram, error) {
 | 
			
		||||
	t, err := Temporality(h.Temporality)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
| 
						 | 
				
			
			@ -218,7 +220,9 @@ func ExponentialHistogram[N int64 | float64](h metricdata.ExponentialHistogram[N
 | 
			
		|||
 | 
			
		||||
// ExponentialHistogramDataPoints returns a slice of OTLP ExponentialHistogramDataPoint generated
 | 
			
		||||
// from dPts.
 | 
			
		||||
func ExponentialHistogramDataPoints[N int64 | float64](dPts []metricdata.ExponentialHistogramDataPoint[N]) []*mpb.ExponentialHistogramDataPoint {
 | 
			
		||||
func ExponentialHistogramDataPoints[N int64 | float64](
 | 
			
		||||
	dPts []metricdata.ExponentialHistogramDataPoint[N],
 | 
			
		||||
) []*mpb.ExponentialHistogramDataPoint {
 | 
			
		||||
	out := make([]*mpb.ExponentialHistogramDataPoint, 0, len(dPts))
 | 
			
		||||
	for _, dPt := range dPts {
 | 
			
		||||
		sum := float64(dPt.Sum)
 | 
			
		||||
| 
						 | 
				
			
			@ -250,7 +254,9 @@ func ExponentialHistogramDataPoints[N int64 | float64](dPts []metricdata.Exponen
 | 
			
		|||
 | 
			
		||||
// ExponentialHistogramDataPointBuckets returns an OTLP ExponentialHistogramDataPoint_Buckets generated
 | 
			
		||||
// from bucket.
 | 
			
		||||
func ExponentialHistogramDataPointBuckets(bucket metricdata.ExponentialBucket) *mpb.ExponentialHistogramDataPoint_Buckets {
 | 
			
		||||
func ExponentialHistogramDataPointBuckets(
 | 
			
		||||
	bucket metricdata.ExponentialBucket,
 | 
			
		||||
) *mpb.ExponentialHistogramDataPoint_Buckets {
 | 
			
		||||
	return &mpb.ExponentialHistogramDataPoint_Buckets{
 | 
			
		||||
		Offset:       bucket.Offset,
 | 
			
		||||
		BucketCounts: bucket.Counts,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -94,8 +94,21 @@ func TestSpanEvent(t *testing.T) {
 | 
			
		|||
	eventTimestamp := uint64(1589932800 * 1e9)
 | 
			
		||||
	assert.Equal(t, &tracepb.Span_Event{Name: "test 1", Attributes: nil, TimeUnixNano: eventTimestamp}, got[0])
 | 
			
		||||
	// Do not test Attributes directly, just that the return value goes to the correct field.
 | 
			
		||||
	assert.Equal(t, &tracepb.Span_Event{Name: "test 2", Attributes: KeyValues(attrs), TimeUnixNano: eventTimestamp, DroppedAttributesCount: 2}, got[1])
 | 
			
		||||
	assert.Equal(t, &tracepb.Span_Event{Name: "test 3", Attributes: KeyValues(attrs), TimeUnixNano: 0, DroppedAttributesCount: 2}, got[2])
 | 
			
		||||
	assert.Equal(
 | 
			
		||||
		t,
 | 
			
		||||
		&tracepb.Span_Event{
 | 
			
		||||
			Name:                   "test 2",
 | 
			
		||||
			Attributes:             KeyValues(attrs),
 | 
			
		||||
			TimeUnixNano:           eventTimestamp,
 | 
			
		||||
			DroppedAttributesCount: 2,
 | 
			
		||||
		},
 | 
			
		||||
		got[1],
 | 
			
		||||
	)
 | 
			
		||||
	assert.Equal(
 | 
			
		||||
		t,
 | 
			
		||||
		&tracepb.Span_Event{Name: "test 3", Attributes: KeyValues(attrs), TimeUnixNano: 0, DroppedAttributesCount: 2},
 | 
			
		||||
		got[2],
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNilLinks(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -220,12 +233,18 @@ func TestSpanData(t *testing.T) {
 | 
			
		|||
	traceState, _ := trace.ParseTraceState("key1=val1,key2=val2")
 | 
			
		||||
	spanData := tracetest.SpanStub{
 | 
			
		||||
		SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
			TraceID:    trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
			TraceID: trace.TraceID{
 | 
			
		||||
				0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
				0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
			},
 | 
			
		||||
			SpanID:     trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
 | 
			
		||||
			TraceState: traceState,
 | 
			
		||||
		}),
 | 
			
		||||
		Parent: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
			TraceID:    trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
			TraceID: trace.TraceID{
 | 
			
		||||
				0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
				0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
			},
 | 
			
		||||
			SpanID:     trace.SpanID{0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8},
 | 
			
		||||
			TraceState: traceState,
 | 
			
		||||
			Remote:     true,
 | 
			
		||||
| 
						 | 
				
			
			@ -251,7 +270,10 @@ func TestSpanData(t *testing.T) {
 | 
			
		|||
		Links: []tracesdk.Link{
 | 
			
		||||
			{
 | 
			
		||||
				SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
					TraceID:    trace.TraceID{0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF},
 | 
			
		||||
					TraceID: trace.TraceID{
 | 
			
		||||
						0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
 | 
			
		||||
						0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
 | 
			
		||||
					},
 | 
			
		||||
					SpanID:     trace.SpanID{0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7},
 | 
			
		||||
					TraceFlags: 0,
 | 
			
		||||
				}),
 | 
			
		||||
| 
						 | 
				
			
			@ -262,7 +284,10 @@ func TestSpanData(t *testing.T) {
 | 
			
		|||
			},
 | 
			
		||||
			{
 | 
			
		||||
				SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
					TraceID:    trace.TraceID{0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF},
 | 
			
		||||
					TraceID: trace.TraceID{
 | 
			
		||||
						0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
 | 
			
		||||
						0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
 | 
			
		||||
					},
 | 
			
		||||
					SpanID:     trace.SpanID{0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7},
 | 
			
		||||
					TraceFlags: 0,
 | 
			
		||||
				}),
 | 
			
		||||
| 
						 | 
				
			
			@ -299,7 +324,10 @@ func TestSpanData(t *testing.T) {
 | 
			
		|||
	// ordering impossible to guarantee on the output. The Resource
 | 
			
		||||
	// transform function has unit tests that should suffice.
 | 
			
		||||
	expectedSpan := &tracepb.Span{
 | 
			
		||||
		TraceId:                []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
		TraceId: []byte{
 | 
			
		||||
			0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
			0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
		},
 | 
			
		||||
		SpanId:                 []byte{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
 | 
			
		||||
		ParentSpanId:           []byte{0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8},
 | 
			
		||||
		TraceState:             "key1=val1,key2=val2",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,7 +39,11 @@ func TestMain(m *testing.M) {
 | 
			
		|||
 | 
			
		||||
var roSpans = tracetest.SpanStubs{{Name: "Span 0"}}.Snapshots()
 | 
			
		||||
 | 
			
		||||
func contextWithTimeout(parent context.Context, t *testing.T, timeout time.Duration) (context.Context, context.CancelFunc) {
 | 
			
		||||
func contextWithTimeout(
 | 
			
		||||
	parent context.Context,
 | 
			
		||||
	t *testing.T,
 | 
			
		||||
	timeout time.Duration,
 | 
			
		||||
) (context.Context, context.CancelFunc) {
 | 
			
		||||
	d, ok := t.Deadline()
 | 
			
		||||
	if !ok {
 | 
			
		||||
		d = time.Now().Add(timeout)
 | 
			
		||||
| 
						 | 
				
			
			@ -110,7 +114,12 @@ func TestWithEndpointURL(t *testing.T) {
 | 
			
		|||
	otlptracetest.RunEndToEndTest(ctx, t, exp, mc)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newGRPCExporter(t *testing.T, ctx context.Context, endpoint string, additionalOpts ...otlptracegrpc.Option) *otlptrace.Exporter {
 | 
			
		||||
func newGRPCExporter(
 | 
			
		||||
	t *testing.T,
 | 
			
		||||
	ctx context.Context,
 | 
			
		||||
	endpoint string,
 | 
			
		||||
	additionalOpts ...otlptracegrpc.Option,
 | 
			
		||||
) *otlptrace.Exporter {
 | 
			
		||||
	opts := []otlptracegrpc.Option{
 | 
			
		||||
		otlptracegrpc.WithInsecure(),
 | 
			
		||||
		otlptracegrpc.WithEndpoint(endpoint),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -77,8 +77,16 @@ func getOptionsFromEnv() []GenericOption {
 | 
			
		|||
		}),
 | 
			
		||||
		envconfig.WithCertPool("CERTIFICATE", func(p *x509.CertPool) { tlsConf.RootCAs = p }),
 | 
			
		||||
		envconfig.WithCertPool("TRACES_CERTIFICATE", func(p *x509.CertPool) { tlsConf.RootCAs = p }),
 | 
			
		||||
		envconfig.WithClientCert("CLIENT_CERTIFICATE", "CLIENT_KEY", func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} }),
 | 
			
		||||
		envconfig.WithClientCert("TRACES_CLIENT_CERTIFICATE", "TRACES_CLIENT_KEY", func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} }),
 | 
			
		||||
		envconfig.WithClientCert(
 | 
			
		||||
			"CLIENT_CERTIFICATE",
 | 
			
		||||
			"CLIENT_KEY",
 | 
			
		||||
			func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} },
 | 
			
		||||
		),
 | 
			
		||||
		envconfig.WithClientCert(
 | 
			
		||||
			"TRACES_CLIENT_CERTIFICATE",
 | 
			
		||||
			"TRACES_CLIENT_KEY",
 | 
			
		||||
			func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} },
 | 
			
		||||
		),
 | 
			
		||||
		withTLSConfig(tlsConf, func(c *tls.Config) { opts = append(opts, WithTLSClientConfig(c)) }),
 | 
			
		||||
		envconfig.WithBool("INSECURE", func(b bool) { opts = append(opts, withInsecure(b)) }),
 | 
			
		||||
		envconfig.WithBool("TRACES_INSECURE", func(b bool) { opts = append(opts, withInsecure(b)) }),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,6 +28,10 @@ func requireErrorString(t *testing.T, expect string, err error) {
 | 
			
		|||
func TestPartialSuccessFormat(t *testing.T) {
 | 
			
		||||
	requireErrorString(t, "empty message (0 metric data points rejected)", MetricPartialSuccessError(0, ""))
 | 
			
		||||
	requireErrorString(t, "help help (0 metric data points rejected)", MetricPartialSuccessError(0, "help help"))
 | 
			
		||||
	requireErrorString(t, "what happened (10 metric data points rejected)", MetricPartialSuccessError(10, "what happened"))
 | 
			
		||||
	requireErrorString(
 | 
			
		||||
		t,
 | 
			
		||||
		"what happened (10 metric data points rejected)",
 | 
			
		||||
		MetricPartialSuccessError(10, "what happened"),
 | 
			
		||||
	)
 | 
			
		||||
	requireErrorString(t, "what happened (15 spans rejected)", TracePartialSuccessError(15, "what happened"))
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,7 +61,10 @@ func (mts *mockTraceService) getResourceSpans() []*tracepb.ResourceSpans {
 | 
			
		|||
	return mts.storage.GetResourceSpans()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (mts *mockTraceService) Export(ctx context.Context, exp *collectortracepb.ExportTraceServiceRequest) (*collectortracepb.ExportTraceServiceResponse, error) {
 | 
			
		||||
func (mts *mockTraceService) Export(
 | 
			
		||||
	ctx context.Context,
 | 
			
		||||
	exp *collectortracepb.ExportTraceServiceRequest,
 | 
			
		||||
) (*collectortracepb.ExportTraceServiceResponse, error) {
 | 
			
		||||
	mts.mu.Lock()
 | 
			
		||||
	defer func() {
 | 
			
		||||
		mts.requests++
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -271,7 +271,11 @@ func TestNoRetry(t *testing.T) {
 | 
			
		|||
	assert.True(t, strings.HasPrefix(err.Error(), "traces export: "))
 | 
			
		||||
 | 
			
		||||
	unwrapped := errors.Unwrap(err)
 | 
			
		||||
	assert.Contains(t, unwrapped.Error(), fmt.Sprintf("failed to send to http://%s/v1/traces: 400 Bad Request", mc.endpoint))
 | 
			
		||||
	assert.Contains(
 | 
			
		||||
		t,
 | 
			
		||||
		unwrapped.Error(),
 | 
			
		||||
		fmt.Sprintf("failed to send to http://%s/v1/traces: 400 Bad Request", mc.endpoint),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	unwrapped2 := errors.Unwrap(unwrapped)
 | 
			
		||||
	assert.Contains(t, unwrapped2.Error(), "missing required attribute aaa")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -77,8 +77,16 @@ func getOptionsFromEnv() []GenericOption {
 | 
			
		|||
		}),
 | 
			
		||||
		envconfig.WithCertPool("CERTIFICATE", func(p *x509.CertPool) { tlsConf.RootCAs = p }),
 | 
			
		||||
		envconfig.WithCertPool("TRACES_CERTIFICATE", func(p *x509.CertPool) { tlsConf.RootCAs = p }),
 | 
			
		||||
		envconfig.WithClientCert("CLIENT_CERTIFICATE", "CLIENT_KEY", func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} }),
 | 
			
		||||
		envconfig.WithClientCert("TRACES_CLIENT_CERTIFICATE", "TRACES_CLIENT_KEY", func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} }),
 | 
			
		||||
		envconfig.WithClientCert(
 | 
			
		||||
			"CLIENT_CERTIFICATE",
 | 
			
		||||
			"CLIENT_KEY",
 | 
			
		||||
			func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} },
 | 
			
		||||
		),
 | 
			
		||||
		envconfig.WithClientCert(
 | 
			
		||||
			"TRACES_CLIENT_CERTIFICATE",
 | 
			
		||||
			"TRACES_CLIENT_KEY",
 | 
			
		||||
			func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} },
 | 
			
		||||
		),
 | 
			
		||||
		withTLSConfig(tlsConf, func(c *tls.Config) { opts = append(opts, WithTLSClientConfig(c)) }),
 | 
			
		||||
		envconfig.WithBool("INSECURE", func(b bool) { opts = append(opts, withInsecure(b)) }),
 | 
			
		||||
		envconfig.WithBool("TRACES_INSECURE", func(b bool) { opts = append(opts, withInsecure(b)) }),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,6 +28,10 @@ func requireErrorString(t *testing.T, expect string, err error) {
 | 
			
		|||
func TestPartialSuccessFormat(t *testing.T) {
 | 
			
		||||
	requireErrorString(t, "empty message (0 metric data points rejected)", MetricPartialSuccessError(0, ""))
 | 
			
		||||
	requireErrorString(t, "help help (0 metric data points rejected)", MetricPartialSuccessError(0, "help help"))
 | 
			
		||||
	requireErrorString(t, "what happened (10 metric data points rejected)", MetricPartialSuccessError(10, "what happened"))
 | 
			
		||||
	requireErrorString(
 | 
			
		||||
		t,
 | 
			
		||||
		"what happened (10 metric data points rejected)",
 | 
			
		||||
		MetricPartialSuccessError(10, "what happened"),
 | 
			
		||||
	)
 | 
			
		||||
	requireErrorString(t, "what happened (15 spans rejected)", TracePartialSuccessError(15, "what happened"))
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,7 +28,9 @@ type config struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
var logDeprecatedLegacyScheme = sync.OnceFunc(func() {
 | 
			
		||||
	global.Warn("prometheus exporter legacy scheme deprecated: support for the legacy NameValidationScheme will be removed in the next release")
 | 
			
		||||
	global.Warn(
 | 
			
		||||
		"prometheus exporter legacy scheme deprecated: support for the legacy NameValidationScheme will be removed in the next release",
 | 
			
		||||
	)
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// newConfig creates a validated config configured with options.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -254,7 +254,13 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func addHistogramMetric[N int64 | float64](ch chan<- prometheus.Metric, histogram metricdata.Histogram[N], m metricdata.Metrics, name string, kv 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)
 | 
			
		||||
		keys = append(keys, kv.keys...)
 | 
			
		||||
| 
						 | 
				
			
			@ -278,7 +284,13 @@ 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, name string, kv 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
 | 
			
		||||
| 
						 | 
				
			
			@ -304,7 +316,13 @@ func addSumMetric[N int64 | float64](ch chan<- prometheus.Metric, sum metricdata
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func addGaugeMetric[N int64 | float64](ch chan<- prometheus.Metric, gauge metricdata.Gauge[N], m metricdata.Metrics, name string, kv 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)
 | 
			
		||||
		keys = append(keys, kv.keys...)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -234,15 +234,24 @@ func TestPrometheusExporter(t *testing.T) {
 | 
			
		|||
				gauge.Add(ctx, -25, opt)
 | 
			
		||||
 | 
			
		||||
				// Invalid, will be renamed.
 | 
			
		||||
				gauge, err = meter.Float64UpDownCounter("invalid.gauge.name", otelmetric.WithDescription("a gauge with an invalid name"))
 | 
			
		||||
				gauge, err = meter.Float64UpDownCounter(
 | 
			
		||||
					"invalid.gauge.name",
 | 
			
		||||
					otelmetric.WithDescription("a gauge with an invalid name"),
 | 
			
		||||
				)
 | 
			
		||||
				require.NoError(t, err)
 | 
			
		||||
				gauge.Add(ctx, 100, opt)
 | 
			
		||||
 | 
			
		||||
				counter, err := meter.Float64Counter("0invalid.counter.name", otelmetric.WithDescription("a counter with an invalid name"))
 | 
			
		||||
				counter, err := meter.Float64Counter(
 | 
			
		||||
					"0invalid.counter.name",
 | 
			
		||||
					otelmetric.WithDescription("a counter with an invalid name"),
 | 
			
		||||
				)
 | 
			
		||||
				require.ErrorIs(t, err, metric.ErrInstrumentName)
 | 
			
		||||
				counter.Add(ctx, 100, opt)
 | 
			
		||||
 | 
			
		||||
				histogram, err := meter.Float64Histogram("invalid.hist.name", otelmetric.WithDescription("a histogram with an invalid name"))
 | 
			
		||||
				histogram, err := meter.Float64Histogram(
 | 
			
		||||
					"invalid.hist.name",
 | 
			
		||||
					otelmetric.WithDescription("a histogram with an invalid name"),
 | 
			
		||||
				)
 | 
			
		||||
				require.NoError(t, err)
 | 
			
		||||
				histogram.Record(ctx, 23, opt)
 | 
			
		||||
			},
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -194,7 +194,11 @@ func getPrettyJSON(now *time.Time) string {
 | 
			
		|||
	var timestamps string
 | 
			
		||||
	if now != nil {
 | 
			
		||||
		serializedNow, _ := json.Marshal(now)
 | 
			
		||||
		timestamps = "\n\t\"Timestamp\": " + string(serializedNow) + ",\n\t\"ObservedTimestamp\": " + string(serializedNow) + ","
 | 
			
		||||
		timestamps = "\n\t\"Timestamp\": " + string(
 | 
			
		||||
			serializedNow,
 | 
			
		||||
		) + ",\n\t\"ObservedTimestamp\": " + string(
 | 
			
		||||
			serializedNow,
 | 
			
		||||
		) + ","
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return `{` + timestamps + `
 | 
			
		||||
| 
						 | 
				
			
			@ -318,7 +322,11 @@ func getRecord(now time.Time) sdklog.Record {
 | 
			
		|||
			"https://example.com/custom-resource-schema",
 | 
			
		||||
			attribute.String("foo", "bar"),
 | 
			
		||||
		),
 | 
			
		||||
		InstrumentationScope: &instrumentation.Scope{Name: "name", Version: "version", SchemaURL: "https://example.com/custom-schema"},
 | 
			
		||||
		InstrumentationScope: &instrumentation.Scope{
 | 
			
		||||
			Name:      "name",
 | 
			
		||||
			Version:   "version",
 | 
			
		||||
			SchemaURL: "https://example.com/custom-schema",
 | 
			
		||||
		},
 | 
			
		||||
		DroppedAttributes: 10,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -131,7 +131,9 @@ func redactAggregationTimestamps(orig metricdata.Aggregation) metricdata.Aggrega
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func redactHistogramTimestamps[T int64 | float64](hdp []metricdata.HistogramDataPoint[T]) []metricdata.HistogramDataPoint[T] {
 | 
			
		||||
func redactHistogramTimestamps[T int64 | float64](
 | 
			
		||||
	hdp []metricdata.HistogramDataPoint[T],
 | 
			
		||||
) []metricdata.HistogramDataPoint[T] {
 | 
			
		||||
	out := make([]metricdata.HistogramDataPoint[T], len(hdp))
 | 
			
		||||
	for i, dp := range hdp {
 | 
			
		||||
		out[i] = metricdata.HistogramDataPoint[T]{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,11 +38,17 @@ func TestModelConversion(t *testing.T) {
 | 
			
		|||
		// typical span data with UNSET status
 | 
			
		||||
		{
 | 
			
		||||
			SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
 | 
			
		||||
			}),
 | 
			
		||||
			Parent: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38},
 | 
			
		||||
			}),
 | 
			
		||||
			SpanKind:  trace.SpanKindServer,
 | 
			
		||||
| 
						 | 
				
			
			@ -80,11 +86,17 @@ func TestModelConversion(t *testing.T) {
 | 
			
		|||
		// typical span data with OK status
 | 
			
		||||
		{
 | 
			
		||||
			SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
 | 
			
		||||
			}),
 | 
			
		||||
			Parent: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38},
 | 
			
		||||
			}),
 | 
			
		||||
			SpanKind:  trace.SpanKindServer,
 | 
			
		||||
| 
						 | 
				
			
			@ -119,11 +131,17 @@ func TestModelConversion(t *testing.T) {
 | 
			
		|||
		// typical span data with ERROR status
 | 
			
		||||
		{
 | 
			
		||||
			SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
 | 
			
		||||
			}),
 | 
			
		||||
			Parent: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38},
 | 
			
		||||
			}),
 | 
			
		||||
			SpanKind:  trace.SpanKindServer,
 | 
			
		||||
| 
						 | 
				
			
			@ -159,7 +177,10 @@ func TestModelConversion(t *testing.T) {
 | 
			
		|||
		// invalid parent)
 | 
			
		||||
		{
 | 
			
		||||
			SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
 | 
			
		||||
			}),
 | 
			
		||||
			SpanKind:  trace.SpanKindServer,
 | 
			
		||||
| 
						 | 
				
			
			@ -193,11 +214,17 @@ func TestModelConversion(t *testing.T) {
 | 
			
		|||
		// span data of unspecified kind
 | 
			
		||||
		{
 | 
			
		||||
			SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
 | 
			
		||||
			}),
 | 
			
		||||
			Parent: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38},
 | 
			
		||||
			}),
 | 
			
		||||
			SpanKind:  trace.SpanKindUnspecified,
 | 
			
		||||
| 
						 | 
				
			
			@ -231,11 +258,17 @@ func TestModelConversion(t *testing.T) {
 | 
			
		|||
		// span data of internal kind
 | 
			
		||||
		{
 | 
			
		||||
			SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
 | 
			
		||||
			}),
 | 
			
		||||
			Parent: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38},
 | 
			
		||||
			}),
 | 
			
		||||
			SpanKind:  trace.SpanKindInternal,
 | 
			
		||||
| 
						 | 
				
			
			@ -269,11 +302,17 @@ func TestModelConversion(t *testing.T) {
 | 
			
		|||
		// span data of client kind
 | 
			
		||||
		{
 | 
			
		||||
			SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
 | 
			
		||||
			}),
 | 
			
		||||
			Parent: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38},
 | 
			
		||||
			}),
 | 
			
		||||
			SpanKind:  trace.SpanKindClient,
 | 
			
		||||
| 
						 | 
				
			
			@ -310,11 +349,17 @@ func TestModelConversion(t *testing.T) {
 | 
			
		|||
		// span data of producer kind
 | 
			
		||||
		{
 | 
			
		||||
			SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
 | 
			
		||||
			}),
 | 
			
		||||
			Parent: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38},
 | 
			
		||||
			}),
 | 
			
		||||
			SpanKind:  trace.SpanKindProducer,
 | 
			
		||||
| 
						 | 
				
			
			@ -348,11 +393,17 @@ func TestModelConversion(t *testing.T) {
 | 
			
		|||
		// span data of consumer kind
 | 
			
		||||
		{
 | 
			
		||||
			SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
 | 
			
		||||
			}),
 | 
			
		||||
			Parent: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38},
 | 
			
		||||
			}),
 | 
			
		||||
			SpanKind:  trace.SpanKindConsumer,
 | 
			
		||||
| 
						 | 
				
			
			@ -386,11 +437,17 @@ func TestModelConversion(t *testing.T) {
 | 
			
		|||
		// span data with no events
 | 
			
		||||
		{
 | 
			
		||||
			SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
 | 
			
		||||
			}),
 | 
			
		||||
			Parent: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38},
 | 
			
		||||
			}),
 | 
			
		||||
			SpanKind:  trace.SpanKindServer,
 | 
			
		||||
| 
						 | 
				
			
			@ -411,11 +468,17 @@ func TestModelConversion(t *testing.T) {
 | 
			
		|||
		// span data with an "error" attribute set to "false"
 | 
			
		||||
		{
 | 
			
		||||
			SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
 | 
			
		||||
			}),
 | 
			
		||||
			Parent: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38},
 | 
			
		||||
			}),
 | 
			
		||||
			SpanKind:  trace.SpanKindServer,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -201,7 +201,10 @@ func TestExportSpans(t *testing.T) {
 | 
			
		|||
		// parent
 | 
			
		||||
		{
 | 
			
		||||
			SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
 | 
			
		||||
			}),
 | 
			
		||||
			SpanKind:   trace.SpanKindServer,
 | 
			
		||||
| 
						 | 
				
			
			@ -219,11 +222,17 @@ func TestExportSpans(t *testing.T) {
 | 
			
		|||
		// child
 | 
			
		||||
		{
 | 
			
		||||
			SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0xDF, 0xDE, 0xDD, 0xDC, 0xDB, 0xDA, 0xD9, 0xD8},
 | 
			
		||||
			}),
 | 
			
		||||
			Parent: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
 | 
			
		||||
			}),
 | 
			
		||||
			SpanKind:   trace.SpanKindServer,
 | 
			
		||||
| 
						 | 
				
			
			@ -394,7 +403,10 @@ func TestWithHeaders(t *testing.T) {
 | 
			
		|||
	spans := tracetest.SpanStubs{
 | 
			
		||||
		{
 | 
			
		||||
			SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
				TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
 | 
			
		||||
				TraceID: trace.TraceID{
 | 
			
		||||
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
 | 
			
		||||
					0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 | 
			
		||||
				},
 | 
			
		||||
				SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
 | 
			
		||||
			}),
 | 
			
		||||
		},
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -110,7 +110,10 @@ func (am *altMeter) Int64Counter(name string, _ ...metric.Int64CounterOption) (m
 | 
			
		|||
	return noop.NewMeterProvider().Meter("noop").Int64Counter(name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (am *altMeter) Int64UpDownCounter(name string, _ ...metric.Int64UpDownCounterOption) (metric.Int64UpDownCounter, error) {
 | 
			
		||||
func (am *altMeter) Int64UpDownCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	_ ...metric.Int64UpDownCounterOption,
 | 
			
		||||
) (metric.Int64UpDownCounter, error) {
 | 
			
		||||
	return noop.NewMeterProvider().Meter("noop").Int64UpDownCounter(name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -122,19 +125,28 @@ func (am *altMeter) Int64Gauge(name string, _ ...metric.Int64GaugeOption) (metri
 | 
			
		|||
	return noop.NewMeterProvider().Meter("noop").Int64Gauge(name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (am *altMeter) Int64ObservableCounter(name string, options ...metric.Int64ObservableCounterOption) (metric.Int64ObservableCounter, error) {
 | 
			
		||||
func (am *altMeter) Int64ObservableCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Int64ObservableCounterOption,
 | 
			
		||||
) (metric.Int64ObservableCounter, error) {
 | 
			
		||||
	return &testAiCounter{
 | 
			
		||||
		meter: am,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (am *altMeter) Int64ObservableUpDownCounter(name string, options ...metric.Int64ObservableUpDownCounterOption) (metric.Int64ObservableUpDownCounter, error) {
 | 
			
		||||
func (am *altMeter) Int64ObservableUpDownCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Int64ObservableUpDownCounterOption,
 | 
			
		||||
) (metric.Int64ObservableUpDownCounter, error) {
 | 
			
		||||
	return &testAiUpDownCounter{
 | 
			
		||||
		meter: am,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (am *altMeter) Int64ObservableGauge(name string, options ...metric.Int64ObservableGaugeOption) (metric.Int64ObservableGauge, error) {
 | 
			
		||||
func (am *altMeter) Int64ObservableGauge(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Int64ObservableGaugeOption,
 | 
			
		||||
) (metric.Int64ObservableGauge, error) {
 | 
			
		||||
	return &testAiGauge{
 | 
			
		||||
		meter: am,
 | 
			
		||||
	}, nil
 | 
			
		||||
| 
						 | 
				
			
			@ -144,11 +156,17 @@ func (am *altMeter) Float64Counter(name string, _ ...metric.Float64CounterOption
 | 
			
		|||
	return noop.NewMeterProvider().Meter("noop").Float64Counter(name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (am *altMeter) Float64UpDownCounter(name string, _ ...metric.Float64UpDownCounterOption) (metric.Float64UpDownCounter, error) {
 | 
			
		||||
func (am *altMeter) Float64UpDownCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	_ ...metric.Float64UpDownCounterOption,
 | 
			
		||||
) (metric.Float64UpDownCounter, error) {
 | 
			
		||||
	return noop.NewMeterProvider().Meter("noop").Float64UpDownCounter(name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (am *altMeter) Float64Histogram(name string, options ...metric.Float64HistogramOption) (metric.Float64Histogram, error) {
 | 
			
		||||
func (am *altMeter) Float64Histogram(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Float64HistogramOption,
 | 
			
		||||
) (metric.Float64Histogram, error) {
 | 
			
		||||
	return noop.NewMeterProvider().Meter("noop").Float64Histogram(name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -156,19 +174,28 @@ func (am *altMeter) Float64Gauge(name string, options ...metric.Float64GaugeOpti
 | 
			
		|||
	return noop.NewMeterProvider().Meter("noop").Float64Gauge(name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (am *altMeter) Float64ObservableCounter(name string, options ...metric.Float64ObservableCounterOption) (metric.Float64ObservableCounter, error) {
 | 
			
		||||
func (am *altMeter) Float64ObservableCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Float64ObservableCounterOption,
 | 
			
		||||
) (metric.Float64ObservableCounter, error) {
 | 
			
		||||
	return &testAfCounter{
 | 
			
		||||
		meter: am,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (am *altMeter) Float64ObservableUpDownCounter(name string, options ...metric.Float64ObservableUpDownCounterOption) (metric.Float64ObservableUpDownCounter, error) {
 | 
			
		||||
func (am *altMeter) Float64ObservableUpDownCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Float64ObservableUpDownCounterOption,
 | 
			
		||||
) (metric.Float64ObservableUpDownCounter, error) {
 | 
			
		||||
	return &testAfUpDownCounter{
 | 
			
		||||
		meter: am,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (am *altMeter) Float64ObservableGauge(name string, options ...metric.Float64ObservableGaugeOption) (metric.Float64ObservableGauge, error) {
 | 
			
		||||
func (am *altMeter) Float64ObservableGauge(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Float64ObservableGaugeOption,
 | 
			
		||||
) (metric.Float64ObservableGauge, error) {
 | 
			
		||||
	return &testAfGauge{
 | 
			
		||||
		meter: am,
 | 
			
		||||
	}, nil
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -169,7 +169,10 @@ func (m *meter) Int64Counter(name string, options ...metric.Int64CounterOption)
 | 
			
		|||
	return i, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *meter) Int64UpDownCounter(name string, options ...metric.Int64UpDownCounterOption) (metric.Int64UpDownCounter, error) {
 | 
			
		||||
func (m *meter) Int64UpDownCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Int64UpDownCounterOption,
 | 
			
		||||
) (metric.Int64UpDownCounter, error) {
 | 
			
		||||
	m.mtx.Lock()
 | 
			
		||||
	defer m.mtx.Unlock()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -238,7 +241,10 @@ func (m *meter) Int64Gauge(name string, options ...metric.Int64GaugeOption) (met
 | 
			
		|||
	return i, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *meter) Int64ObservableCounter(name string, options ...metric.Int64ObservableCounterOption) (metric.Int64ObservableCounter, error) {
 | 
			
		||||
func (m *meter) Int64ObservableCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Int64ObservableCounterOption,
 | 
			
		||||
) (metric.Int64ObservableCounter, error) {
 | 
			
		||||
	m.mtx.Lock()
 | 
			
		||||
	defer m.mtx.Unlock()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -261,7 +267,10 @@ func (m *meter) Int64ObservableCounter(name string, options ...metric.Int64Obser
 | 
			
		|||
	return i, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *meter) Int64ObservableUpDownCounter(name string, options ...metric.Int64ObservableUpDownCounterOption) (metric.Int64ObservableUpDownCounter, error) {
 | 
			
		||||
func (m *meter) Int64ObservableUpDownCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Int64ObservableUpDownCounterOption,
 | 
			
		||||
) (metric.Int64ObservableUpDownCounter, error) {
 | 
			
		||||
	m.mtx.Lock()
 | 
			
		||||
	defer m.mtx.Unlock()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -284,7 +293,10 @@ func (m *meter) Int64ObservableUpDownCounter(name string, options ...metric.Int6
 | 
			
		|||
	return i, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *meter) Int64ObservableGauge(name string, options ...metric.Int64ObservableGaugeOption) (metric.Int64ObservableGauge, error) {
 | 
			
		||||
func (m *meter) Int64ObservableGauge(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Int64ObservableGaugeOption,
 | 
			
		||||
) (metric.Int64ObservableGauge, error) {
 | 
			
		||||
	m.mtx.Lock()
 | 
			
		||||
	defer m.mtx.Unlock()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -330,7 +342,10 @@ func (m *meter) Float64Counter(name string, options ...metric.Float64CounterOpti
 | 
			
		|||
	return i, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *meter) Float64UpDownCounter(name string, options ...metric.Float64UpDownCounterOption) (metric.Float64UpDownCounter, error) {
 | 
			
		||||
func (m *meter) Float64UpDownCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Float64UpDownCounterOption,
 | 
			
		||||
) (metric.Float64UpDownCounter, error) {
 | 
			
		||||
	m.mtx.Lock()
 | 
			
		||||
	defer m.mtx.Unlock()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -353,7 +368,10 @@ func (m *meter) Float64UpDownCounter(name string, options ...metric.Float64UpDow
 | 
			
		|||
	return i, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *meter) Float64Histogram(name string, options ...metric.Float64HistogramOption) (metric.Float64Histogram, error) {
 | 
			
		||||
func (m *meter) Float64Histogram(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Float64HistogramOption,
 | 
			
		||||
) (metric.Float64Histogram, error) {
 | 
			
		||||
	m.mtx.Lock()
 | 
			
		||||
	defer m.mtx.Unlock()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -399,7 +417,10 @@ func (m *meter) Float64Gauge(name string, options ...metric.Float64GaugeOption)
 | 
			
		|||
	return i, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *meter) Float64ObservableCounter(name string, options ...metric.Float64ObservableCounterOption) (metric.Float64ObservableCounter, error) {
 | 
			
		||||
func (m *meter) Float64ObservableCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Float64ObservableCounterOption,
 | 
			
		||||
) (metric.Float64ObservableCounter, error) {
 | 
			
		||||
	m.mtx.Lock()
 | 
			
		||||
	defer m.mtx.Unlock()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -422,7 +443,10 @@ func (m *meter) Float64ObservableCounter(name string, options ...metric.Float64O
 | 
			
		|||
	return i, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *meter) Float64ObservableUpDownCounter(name string, options ...metric.Float64ObservableUpDownCounterOption) (metric.Float64ObservableUpDownCounter, error) {
 | 
			
		||||
func (m *meter) Float64ObservableUpDownCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Float64ObservableUpDownCounterOption,
 | 
			
		||||
) (metric.Float64ObservableUpDownCounter, error) {
 | 
			
		||||
	m.mtx.Lock()
 | 
			
		||||
	defer m.mtx.Unlock()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -445,7 +469,10 @@ func (m *meter) Float64ObservableUpDownCounter(name string, options ...metric.Fl
 | 
			
		|||
	return i, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *meter) Float64ObservableGauge(name string, options ...metric.Float64ObservableGaugeOption) (metric.Float64ObservableGauge, error) {
 | 
			
		||||
func (m *meter) Float64ObservableGauge(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Float64ObservableGaugeOption,
 | 
			
		||||
) (metric.Float64ObservableGauge, error) {
 | 
			
		||||
	m.mtx.Lock()
 | 
			
		||||
	defer m.mtx.Unlock()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -125,7 +125,10 @@ func TestUnregisterConcurrentSafe(t *testing.T) {
 | 
			
		|||
	<-done
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testSetupAllInstrumentTypes(t *testing.T, m metric.Meter) (metric.Float64Counter, metric.Float64ObservableCounter) {
 | 
			
		||||
func testSetupAllInstrumentTypes(
 | 
			
		||||
	t *testing.T,
 | 
			
		||||
	m metric.Meter,
 | 
			
		||||
) (metric.Float64Counter, metric.Float64ObservableCounter) {
 | 
			
		||||
	afcounter, err := m.Float64ObservableCounter("test_Async_Counter")
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
	_, err = m.Float64ObservableUpDownCounter("test_Async_UpDownCounter")
 | 
			
		||||
| 
						 | 
				
			
			@ -439,7 +442,10 @@ type failingRegisterCallbackMeter struct {
 | 
			
		|||
	noop.Meter
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *failingRegisterCallbackMeter) RegisterCallback(metric.Callback, ...metric.Observable) (metric.Registration, error) {
 | 
			
		||||
func (m *failingRegisterCallbackMeter) RegisterCallback(
 | 
			
		||||
	metric.Callback,
 | 
			
		||||
	...metric.Observable,
 | 
			
		||||
) (metric.Registration, error) {
 | 
			
		||||
	return nil, errors.New("an error occurred")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,7 +51,10 @@ func (m *testMeter) Int64Counter(name string, options ...metric.Int64CounterOpti
 | 
			
		|||
	return &testCountingIntInstrument{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *testMeter) Int64UpDownCounter(name string, options ...metric.Int64UpDownCounterOption) (metric.Int64UpDownCounter, error) {
 | 
			
		||||
func (m *testMeter) Int64UpDownCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Int64UpDownCounterOption,
 | 
			
		||||
) (metric.Int64UpDownCounter, error) {
 | 
			
		||||
	m.siUDCount++
 | 
			
		||||
	return &testCountingIntInstrument{}, nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -66,17 +69,26 @@ func (m *testMeter) Int64Gauge(name string, options ...metric.Int64GaugeOption)
 | 
			
		|||
	return &testCountingIntInstrument{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *testMeter) Int64ObservableCounter(name string, options ...metric.Int64ObservableCounterOption) (metric.Int64ObservableCounter, error) {
 | 
			
		||||
func (m *testMeter) Int64ObservableCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Int64ObservableCounterOption,
 | 
			
		||||
) (metric.Int64ObservableCounter, error) {
 | 
			
		||||
	m.aiCount++
 | 
			
		||||
	return &testCountingIntInstrument{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *testMeter) Int64ObservableUpDownCounter(name string, options ...metric.Int64ObservableUpDownCounterOption) (metric.Int64ObservableUpDownCounter, error) {
 | 
			
		||||
func (m *testMeter) Int64ObservableUpDownCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Int64ObservableUpDownCounterOption,
 | 
			
		||||
) (metric.Int64ObservableUpDownCounter, error) {
 | 
			
		||||
	m.aiUDCount++
 | 
			
		||||
	return &testCountingIntInstrument{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *testMeter) Int64ObservableGauge(name string, options ...metric.Int64ObservableGaugeOption) (metric.Int64ObservableGauge, error) {
 | 
			
		||||
func (m *testMeter) Int64ObservableGauge(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Int64ObservableGaugeOption,
 | 
			
		||||
) (metric.Int64ObservableGauge, error) {
 | 
			
		||||
	m.aiGauge++
 | 
			
		||||
	return &testCountingIntInstrument{}, nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -86,12 +98,18 @@ func (m *testMeter) Float64Counter(name string, options ...metric.Float64Counter
 | 
			
		|||
	return &testCountingFloatInstrument{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *testMeter) Float64UpDownCounter(name string, options ...metric.Float64UpDownCounterOption) (metric.Float64UpDownCounter, error) {
 | 
			
		||||
func (m *testMeter) Float64UpDownCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Float64UpDownCounterOption,
 | 
			
		||||
) (metric.Float64UpDownCounter, error) {
 | 
			
		||||
	m.sfUDCount++
 | 
			
		||||
	return &testCountingFloatInstrument{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *testMeter) Float64Histogram(name string, options ...metric.Float64HistogramOption) (metric.Float64Histogram, error) {
 | 
			
		||||
func (m *testMeter) Float64Histogram(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Float64HistogramOption,
 | 
			
		||||
) (metric.Float64Histogram, error) {
 | 
			
		||||
	m.sfHist++
 | 
			
		||||
	return &testCountingFloatInstrument{}, nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -101,17 +119,26 @@ func (m *testMeter) Float64Gauge(name string, options ...metric.Float64GaugeOpti
 | 
			
		|||
	return &testCountingFloatInstrument{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *testMeter) Float64ObservableCounter(name string, options ...metric.Float64ObservableCounterOption) (metric.Float64ObservableCounter, error) {
 | 
			
		||||
func (m *testMeter) Float64ObservableCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Float64ObservableCounterOption,
 | 
			
		||||
) (metric.Float64ObservableCounter, error) {
 | 
			
		||||
	m.afCount++
 | 
			
		||||
	return &testCountingFloatInstrument{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *testMeter) Float64ObservableUpDownCounter(name string, options ...metric.Float64ObservableUpDownCounterOption) (metric.Float64ObservableUpDownCounter, error) {
 | 
			
		||||
func (m *testMeter) Float64ObservableUpDownCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Float64ObservableUpDownCounterOption,
 | 
			
		||||
) (metric.Float64ObservableUpDownCounter, error) {
 | 
			
		||||
	m.afUDCount++
 | 
			
		||||
	return &testCountingFloatInstrument{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *testMeter) Float64ObservableGauge(name string, options ...metric.Float64ObservableGaugeOption) (metric.Float64ObservableGauge, error) {
 | 
			
		||||
func (m *testMeter) Float64ObservableGauge(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Float64ObservableGaugeOption,
 | 
			
		||||
) (metric.Float64ObservableGauge, error) {
 | 
			
		||||
	m.afGauge++
 | 
			
		||||
	return &testCountingFloatInstrument{}, nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -164,7 +164,12 @@ var autoInstEnabled = new(bool)
 | 
			
		|||
// "noinline" pragma prevents the method from ever being inlined.
 | 
			
		||||
//
 | 
			
		||||
//go:noinline
 | 
			
		||||
func (t *tracer) newSpan(ctx context.Context, autoSpan *bool, name string, opts []trace.SpanStartOption) (context.Context, trace.Span) {
 | 
			
		||||
func (t *tracer) newSpan(
 | 
			
		||||
	ctx context.Context,
 | 
			
		||||
	autoSpan *bool,
 | 
			
		||||
	name string,
 | 
			
		||||
	opts []trace.SpanStartOption,
 | 
			
		||||
) (context.Context, trace.Span) {
 | 
			
		||||
	// autoInstEnabled is passed to newSpan via the autoSpan parameter. This is
 | 
			
		||||
	// so the auto-instrumentation can define a uprobe for (*t).newSpan and be
 | 
			
		||||
	// provided with the address of the bool autoInstEnabled points to. It
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,7 +34,11 @@ type fnTracer struct {
 | 
			
		|||
	start func(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (fn fnTracer) Start(ctx context.Context, spanName string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
 | 
			
		||||
func (fn fnTracer) Start(
 | 
			
		||||
	ctx context.Context,
 | 
			
		||||
	spanName string,
 | 
			
		||||
	opts ...trace.SpanStartOption,
 | 
			
		||||
) (context.Context, trace.Span) {
 | 
			
		||||
	return fn.start(ctx, spanName, opts...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -80,8 +80,16 @@ func getOptionsFromEnv() []GenericOption {
 | 
			
		|||
		}),
 | 
			
		||||
		envconfig.WithCertPool("CERTIFICATE", func(p *x509.CertPool) { tlsConf.RootCAs = p }),
 | 
			
		||||
		envconfig.WithCertPool("METRICS_CERTIFICATE", func(p *x509.CertPool) { tlsConf.RootCAs = p }),
 | 
			
		||||
		envconfig.WithClientCert("CLIENT_CERTIFICATE", "CLIENT_KEY", func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} }),
 | 
			
		||||
		envconfig.WithClientCert("METRICS_CLIENT_CERTIFICATE", "METRICS_CLIENT_KEY", func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} }),
 | 
			
		||||
		envconfig.WithClientCert(
 | 
			
		||||
			"CLIENT_CERTIFICATE",
 | 
			
		||||
			"CLIENT_KEY",
 | 
			
		||||
			func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} },
 | 
			
		||||
		),
 | 
			
		||||
		envconfig.WithClientCert(
 | 
			
		||||
			"METRICS_CLIENT_CERTIFICATE",
 | 
			
		||||
			"METRICS_CLIENT_KEY",
 | 
			
		||||
			func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} },
 | 
			
		||||
		),
 | 
			
		||||
		envconfig.WithBool("INSECURE", func(b bool) { opts = append(opts, withInsecure(b)) }),
 | 
			
		||||
		envconfig.WithBool("METRICS_INSECURE", func(b bool) { opts = append(opts, withInsecure(b)) }),
 | 
			
		||||
		withTLSConfig(tlsConf, func(c *tls.Config) { opts = append(opts, WithTLSClientConfig(c)) }),
 | 
			
		||||
| 
						 | 
				
			
			@ -91,8 +99,14 @@ func getOptionsFromEnv() []GenericOption {
 | 
			
		|||
		WithEnvCompression("METRICS_COMPRESSION", func(c Compression) { opts = append(opts, WithCompression(c)) }),
 | 
			
		||||
		envconfig.WithDuration("TIMEOUT", func(d time.Duration) { opts = append(opts, WithTimeout(d)) }),
 | 
			
		||||
		envconfig.WithDuration("METRICS_TIMEOUT", func(d time.Duration) { opts = append(opts, WithTimeout(d)) }),
 | 
			
		||||
		withEnvTemporalityPreference("METRICS_TEMPORALITY_PREFERENCE", func(t metric.TemporalitySelector) { opts = append(opts, WithTemporalitySelector(t)) }),
 | 
			
		||||
		withEnvAggPreference("METRICS_DEFAULT_HISTOGRAM_AGGREGATION", func(a metric.AggregationSelector) { opts = append(opts, WithAggregationSelector(a)) }),
 | 
			
		||||
		withEnvTemporalityPreference(
 | 
			
		||||
			"METRICS_TEMPORALITY_PREFERENCE",
 | 
			
		||||
			func(t metric.TemporalitySelector) { opts = append(opts, WithTemporalitySelector(t)) },
 | 
			
		||||
		),
 | 
			
		||||
		withEnvAggPreference(
 | 
			
		||||
			"METRICS_DEFAULT_HISTOGRAM_AGGREGATION",
 | 
			
		||||
			func(a metric.AggregationSelector) { opts = append(opts, WithAggregationSelector(a)) },
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	return opts
 | 
			
		||||
| 
						 | 
				
			
			@ -157,7 +171,11 @@ func withEnvTemporalityPreference(n string, fn func(metric.TemporalitySelector))
 | 
			
		|||
			case "lowmemory":
 | 
			
		||||
				fn(lowMemory)
 | 
			
		||||
			default:
 | 
			
		||||
				global.Warn("OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE is set to an invalid value, ignoring.", "value", s)
 | 
			
		||||
				global.Warn(
 | 
			
		||||
					"OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE is set to an invalid value, ignoring.",
 | 
			
		||||
					"value",
 | 
			
		||||
					s,
 | 
			
		||||
				)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -203,7 +221,11 @@ func withEnvAggPreference(n string, fn func(metric.AggregationSelector)) func(e
 | 
			
		|||
					return metric.DefaultAggregationSelector(kind)
 | 
			
		||||
				})
 | 
			
		||||
			default:
 | 
			
		||||
				global.Warn("OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION is set to an invalid value, ignoring.", "value", s)
 | 
			
		||||
				global.Warn(
 | 
			
		||||
					"OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION is set to an invalid value, ignoring.",
 | 
			
		||||
					"value",
 | 
			
		||||
					s,
 | 
			
		||||
				)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -113,12 +113,24 @@ func TestWithEnvAggPreference(t *testing.T) {
 | 
			
		|||
			name:     "explicit_bucket_histogram",
 | 
			
		||||
			envValue: "explicit_bucket_histogram",
 | 
			
		||||
			want: map[metric.InstrumentKind]metric.Aggregation{
 | 
			
		||||
				metric.InstrumentKindCounter:                 metric.DefaultAggregationSelector(metric.InstrumentKindCounter),
 | 
			
		||||
				metric.InstrumentKindHistogram:               metric.DefaultAggregationSelector(metric.InstrumentKindHistogram),
 | 
			
		||||
				metric.InstrumentKindUpDownCounter:           metric.DefaultAggregationSelector(metric.InstrumentKindUpDownCounter),
 | 
			
		||||
				metric.InstrumentKindObservableCounter:       metric.DefaultAggregationSelector(metric.InstrumentKindObservableCounter),
 | 
			
		||||
				metric.InstrumentKindObservableUpDownCounter: metric.DefaultAggregationSelector(metric.InstrumentKindObservableUpDownCounter),
 | 
			
		||||
				metric.InstrumentKindObservableGauge:         metric.DefaultAggregationSelector(metric.InstrumentKindObservableGauge),
 | 
			
		||||
				metric.InstrumentKindCounter: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindCounter,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindHistogram: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindHistogram,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindUpDownCounter: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindUpDownCounter,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindObservableCounter: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindObservableCounter,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindObservableUpDownCounter: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindObservableUpDownCounter,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindObservableGauge: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindObservableGauge,
 | 
			
		||||
				),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
| 
						 | 
				
			
			@ -131,10 +143,18 @@ func TestWithEnvAggPreference(t *testing.T) {
 | 
			
		|||
					MaxScale: 20,
 | 
			
		||||
					NoMinMax: false,
 | 
			
		||||
				},
 | 
			
		||||
				metric.InstrumentKindUpDownCounter:           metric.DefaultAggregationSelector(metric.InstrumentKindUpDownCounter),
 | 
			
		||||
				metric.InstrumentKindObservableCounter:       metric.DefaultAggregationSelector(metric.InstrumentKindObservableCounter),
 | 
			
		||||
				metric.InstrumentKindObservableUpDownCounter: metric.DefaultAggregationSelector(metric.InstrumentKindObservableUpDownCounter),
 | 
			
		||||
				metric.InstrumentKindObservableGauge:         metric.DefaultAggregationSelector(metric.InstrumentKindObservableGauge),
 | 
			
		||||
				metric.InstrumentKindUpDownCounter: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindUpDownCounter,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindObservableCounter: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindObservableCounter,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindObservableUpDownCounter: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindObservableUpDownCounter,
 | 
			
		||||
				),
 | 
			
		||||
				metric.InstrumentKindObservableGauge: metric.DefaultAggregationSelector(
 | 
			
		||||
					metric.InstrumentKindObservableGauge,
 | 
			
		||||
				),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -142,7 +142,10 @@ func (c *GRPCCollector) Headers() map[string][]string {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// Export handles the export req.
 | 
			
		||||
func (c *GRPCCollector) Export(ctx context.Context, req *collpb.ExportMetricsServiceRequest) (*collpb.ExportMetricsServiceResponse, error) {
 | 
			
		||||
func (c *GRPCCollector) Export(
 | 
			
		||||
	ctx context.Context,
 | 
			
		||||
	req *collpb.ExportMetricsServiceRequest,
 | 
			
		||||
) (*collpb.ExportMetricsServiceResponse, error) {
 | 
			
		||||
	c.storage.Add(req)
 | 
			
		||||
 | 
			
		||||
	if h, ok := metadata.FromIncomingContext(ctx); ok {
 | 
			
		||||
| 
						 | 
				
			
			@ -208,7 +211,11 @@ type HTTPCollector struct {
 | 
			
		|||
// If errCh is not nil, the collector will respond to HTTP requests with errors
 | 
			
		||||
// sent on that channel. This means that if errCh is not nil Export calls will
 | 
			
		||||
// block until an error is received.
 | 
			
		||||
func NewHTTPCollector(endpoint string, resultCh <-chan ExportResult, opts ...func(*HTTPCollector)) (*HTTPCollector, error) {
 | 
			
		||||
func NewHTTPCollector(
 | 
			
		||||
	endpoint string,
 | 
			
		||||
	resultCh <-chan ExportResult,
 | 
			
		||||
	opts ...func(*HTTPCollector),
 | 
			
		||||
) (*HTTPCollector, error) {
 | 
			
		||||
	u, err := url.Parse(endpoint)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -203,7 +203,9 @@ func HistogramDataPoints[N int64 | float64](dPts []metricdata.HistogramDataPoint
 | 
			
		|||
 | 
			
		||||
// ExponentialHistogram returns an OTLP Metric_ExponentialHistogram generated from h. An error is
 | 
			
		||||
// returned if the temporality of h is unknown.
 | 
			
		||||
func ExponentialHistogram[N int64 | float64](h metricdata.ExponentialHistogram[N]) (*mpb.Metric_ExponentialHistogram, error) {
 | 
			
		||||
func ExponentialHistogram[N int64 | float64](
 | 
			
		||||
	h metricdata.ExponentialHistogram[N],
 | 
			
		||||
) (*mpb.Metric_ExponentialHistogram, error) {
 | 
			
		||||
	t, err := Temporality(h.Temporality)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
| 
						 | 
				
			
			@ -218,7 +220,9 @@ func ExponentialHistogram[N int64 | float64](h metricdata.ExponentialHistogram[N
 | 
			
		|||
 | 
			
		||||
// ExponentialHistogramDataPoints returns a slice of OTLP ExponentialHistogramDataPoint generated
 | 
			
		||||
// from dPts.
 | 
			
		||||
func ExponentialHistogramDataPoints[N int64 | float64](dPts []metricdata.ExponentialHistogramDataPoint[N]) []*mpb.ExponentialHistogramDataPoint {
 | 
			
		||||
func ExponentialHistogramDataPoints[N int64 | float64](
 | 
			
		||||
	dPts []metricdata.ExponentialHistogramDataPoint[N],
 | 
			
		||||
) []*mpb.ExponentialHistogramDataPoint {
 | 
			
		||||
	out := make([]*mpb.ExponentialHistogramDataPoint, 0, len(dPts))
 | 
			
		||||
	for _, dPt := range dPts {
 | 
			
		||||
		sum := float64(dPt.Sum)
 | 
			
		||||
| 
						 | 
				
			
			@ -250,7 +254,9 @@ func ExponentialHistogramDataPoints[N int64 | float64](dPts []metricdata.Exponen
 | 
			
		|||
 | 
			
		||||
// ExponentialHistogramDataPointBuckets returns an OTLP ExponentialHistogramDataPoint_Buckets generated
 | 
			
		||||
// from bucket.
 | 
			
		||||
func ExponentialHistogramDataPointBuckets(bucket metricdata.ExponentialBucket) *mpb.ExponentialHistogramDataPoint_Buckets {
 | 
			
		||||
func ExponentialHistogramDataPointBuckets(
 | 
			
		||||
	bucket metricdata.ExponentialBucket,
 | 
			
		||||
) *mpb.ExponentialHistogramDataPoint_Buckets {
 | 
			
		||||
	return &mpb.ExponentialHistogramDataPoint_Buckets{
 | 
			
		||||
		Offset:       bucket.Offset,
 | 
			
		||||
		BucketCounts: bucket.Counts,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -77,8 +77,16 @@ func getOptionsFromEnv() []GenericOption {
 | 
			
		|||
		}),
 | 
			
		||||
		envconfig.WithCertPool("CERTIFICATE", func(p *x509.CertPool) { tlsConf.RootCAs = p }),
 | 
			
		||||
		envconfig.WithCertPool("TRACES_CERTIFICATE", func(p *x509.CertPool) { tlsConf.RootCAs = p }),
 | 
			
		||||
		envconfig.WithClientCert("CLIENT_CERTIFICATE", "CLIENT_KEY", func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} }),
 | 
			
		||||
		envconfig.WithClientCert("TRACES_CLIENT_CERTIFICATE", "TRACES_CLIENT_KEY", func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} }),
 | 
			
		||||
		envconfig.WithClientCert(
 | 
			
		||||
			"CLIENT_CERTIFICATE",
 | 
			
		||||
			"CLIENT_KEY",
 | 
			
		||||
			func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} },
 | 
			
		||||
		),
 | 
			
		||||
		envconfig.WithClientCert(
 | 
			
		||||
			"TRACES_CLIENT_CERTIFICATE",
 | 
			
		||||
			"TRACES_CLIENT_KEY",
 | 
			
		||||
			func(c tls.Certificate) { tlsConf.Certificates = []tls.Certificate{c} },
 | 
			
		||||
		),
 | 
			
		||||
		withTLSConfig(tlsConf, func(c *tls.Config) { opts = append(opts, WithTLSClientConfig(c)) }),
 | 
			
		||||
		envconfig.WithBool("INSECURE", func(b bool) { opts = append(opts, withInsecure(b)) }),
 | 
			
		||||
		envconfig.WithBool("TRACES_INSECURE", func(b bool) { opts = append(opts, withInsecure(b)) }),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,6 +28,10 @@ func requireErrorString(t *testing.T, expect string, err error) {
 | 
			
		|||
func TestPartialSuccessFormat(t *testing.T) {
 | 
			
		||||
	requireErrorString(t, "empty message (0 metric data points rejected)", MetricPartialSuccessError(0, ""))
 | 
			
		||||
	requireErrorString(t, "help help (0 metric data points rejected)", MetricPartialSuccessError(0, "help help"))
 | 
			
		||||
	requireErrorString(t, "what happened (10 metric data points rejected)", MetricPartialSuccessError(10, "what happened"))
 | 
			
		||||
	requireErrorString(
 | 
			
		||||
		t,
 | 
			
		||||
		"what happened (10 metric data points rejected)",
 | 
			
		||||
		MetricPartialSuccessError(10, "what happened"),
 | 
			
		||||
	)
 | 
			
		||||
	requireErrorString(t, "what happened (15 spans rejected)", TracePartialSuccessError(15, "what happened"))
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,11 @@ func AssertRecordEqual(t testing.TB, want, got log.Record) bool {
 | 
			
		|||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	if !want.ObservedTimestamp().Equal(got.ObservedTimestamp()) {
 | 
			
		||||
		t.Errorf("ObservedTimestamp value is not equal:\nwant: %v\ngot:  %v", want.ObservedTimestamp(), got.ObservedTimestamp())
 | 
			
		||||
		t.Errorf(
 | 
			
		||||
			"ObservedTimestamp value is not equal:\nwant: %v\ngot:  %v",
 | 
			
		||||
			want.ObservedTimestamp(),
 | 
			
		||||
			got.ObservedTimestamp(),
 | 
			
		||||
		)
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	if want.Severity() != got.Severity() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -106,7 +106,9 @@ type Float64ObservableUpDownCounterConfig struct {
 | 
			
		|||
 | 
			
		||||
// NewFloat64ObservableUpDownCounterConfig returns a new
 | 
			
		||||
// [Float64ObservableUpDownCounterConfig] with all opts applied.
 | 
			
		||||
func NewFloat64ObservableUpDownCounterConfig(opts ...Float64ObservableUpDownCounterOption) Float64ObservableUpDownCounterConfig {
 | 
			
		||||
func NewFloat64ObservableUpDownCounterConfig(
 | 
			
		||||
	opts ...Float64ObservableUpDownCounterOption,
 | 
			
		||||
) Float64ObservableUpDownCounterConfig {
 | 
			
		||||
	var config Float64ObservableUpDownCounterConfig
 | 
			
		||||
	for _, o := range opts {
 | 
			
		||||
		config = o.applyFloat64ObservableUpDownCounter(config)
 | 
			
		||||
| 
						 | 
				
			
			@ -239,12 +241,16 @@ type float64CallbackOpt struct {
 | 
			
		|||
	cback Float64Callback
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o float64CallbackOpt) applyFloat64ObservableCounter(cfg Float64ObservableCounterConfig) Float64ObservableCounterConfig {
 | 
			
		||||
func (o float64CallbackOpt) applyFloat64ObservableCounter(
 | 
			
		||||
	cfg Float64ObservableCounterConfig,
 | 
			
		||||
) Float64ObservableCounterConfig {
 | 
			
		||||
	cfg.callbacks = append(cfg.callbacks, o.cback)
 | 
			
		||||
	return cfg
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o float64CallbackOpt) applyFloat64ObservableUpDownCounter(cfg Float64ObservableUpDownCounterConfig) Float64ObservableUpDownCounterConfig {
 | 
			
		||||
func (o float64CallbackOpt) applyFloat64ObservableUpDownCounter(
 | 
			
		||||
	cfg Float64ObservableUpDownCounterConfig,
 | 
			
		||||
) Float64ObservableUpDownCounterConfig {
 | 
			
		||||
	cfg.callbacks = append(cfg.callbacks, o.cback)
 | 
			
		||||
	return cfg
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -105,7 +105,9 @@ type Int64ObservableUpDownCounterConfig struct {
 | 
			
		|||
 | 
			
		||||
// NewInt64ObservableUpDownCounterConfig returns a new
 | 
			
		||||
// [Int64ObservableUpDownCounterConfig] with all opts applied.
 | 
			
		||||
func NewInt64ObservableUpDownCounterConfig(opts ...Int64ObservableUpDownCounterOption) Int64ObservableUpDownCounterConfig {
 | 
			
		||||
func NewInt64ObservableUpDownCounterConfig(
 | 
			
		||||
	opts ...Int64ObservableUpDownCounterOption,
 | 
			
		||||
) Int64ObservableUpDownCounterConfig {
 | 
			
		||||
	var config Int64ObservableUpDownCounterConfig
 | 
			
		||||
	for _, o := range opts {
 | 
			
		||||
		config = o.applyInt64ObservableUpDownCounter(config)
 | 
			
		||||
| 
						 | 
				
			
			@ -242,7 +244,9 @@ func (o int64CallbackOpt) applyInt64ObservableCounter(cfg Int64ObservableCounter
 | 
			
		|||
	return cfg
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o int64CallbackOpt) applyInt64ObservableUpDownCounter(cfg Int64ObservableUpDownCounterConfig) Int64ObservableUpDownCounterConfig {
 | 
			
		||||
func (o int64CallbackOpt) applyInt64ObservableUpDownCounter(
 | 
			
		||||
	cfg Int64ObservableUpDownCounterConfig,
 | 
			
		||||
) Int64ObservableUpDownCounterConfig {
 | 
			
		||||
	cfg.callbacks = append(cfg.callbacks, o.cback)
 | 
			
		||||
	return cfg
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -63,7 +63,9 @@ func (o descOpt) applyFloat64ObservableCounter(c Float64ObservableCounterConfig)
 | 
			
		|||
	return c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o descOpt) applyFloat64ObservableUpDownCounter(c Float64ObservableUpDownCounterConfig) Float64ObservableUpDownCounterConfig {
 | 
			
		||||
func (o descOpt) applyFloat64ObservableUpDownCounter(
 | 
			
		||||
	c Float64ObservableUpDownCounterConfig,
 | 
			
		||||
) Float64ObservableUpDownCounterConfig {
 | 
			
		||||
	c.description = string(o)
 | 
			
		||||
	return c
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -98,7 +100,9 @@ func (o descOpt) applyInt64ObservableCounter(c Int64ObservableCounterConfig) Int
 | 
			
		|||
	return c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o descOpt) applyInt64ObservableUpDownCounter(c Int64ObservableUpDownCounterConfig) Int64ObservableUpDownCounterConfig {
 | 
			
		||||
func (o descOpt) applyInt64ObservableUpDownCounter(
 | 
			
		||||
	c Int64ObservableUpDownCounterConfig,
 | 
			
		||||
) Int64ObservableUpDownCounterConfig {
 | 
			
		||||
	c.description = string(o)
 | 
			
		||||
	return c
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -138,7 +142,9 @@ func (o unitOpt) applyFloat64ObservableCounter(c Float64ObservableCounterConfig)
 | 
			
		|||
	return c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o unitOpt) applyFloat64ObservableUpDownCounter(c Float64ObservableUpDownCounterConfig) Float64ObservableUpDownCounterConfig {
 | 
			
		||||
func (o unitOpt) applyFloat64ObservableUpDownCounter(
 | 
			
		||||
	c Float64ObservableUpDownCounterConfig,
 | 
			
		||||
) Float64ObservableUpDownCounterConfig {
 | 
			
		||||
	c.unit = string(o)
 | 
			
		||||
	return c
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -173,7 +179,9 @@ func (o unitOpt) applyInt64ObservableCounter(c Int64ObservableCounterConfig) Int
 | 
			
		|||
	return c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (o unitOpt) applyInt64ObservableUpDownCounter(c Int64ObservableUpDownCounterConfig) Int64ObservableUpDownCounterConfig {
 | 
			
		||||
func (o unitOpt) applyInt64ObservableUpDownCounter(
 | 
			
		||||
	c Int64ObservableUpDownCounterConfig,
 | 
			
		||||
) Int64ObservableUpDownCounterConfig {
 | 
			
		||||
	c.unit = string(o)
 | 
			
		||||
	return c
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -110,7 +110,10 @@ type Meter interface {
 | 
			
		|||
	// The name needs to conform to the OpenTelemetry instrument name syntax.
 | 
			
		||||
	// See the Instrument Name section of the package documentation for more
 | 
			
		||||
	// information.
 | 
			
		||||
	Int64ObservableUpDownCounter(name string, options ...Int64ObservableUpDownCounterOption) (Int64ObservableUpDownCounter, error)
 | 
			
		||||
	Int64ObservableUpDownCounter(
 | 
			
		||||
		name string,
 | 
			
		||||
		options ...Int64ObservableUpDownCounterOption,
 | 
			
		||||
	) (Int64ObservableUpDownCounter, error)
 | 
			
		||||
 | 
			
		||||
	// Int64ObservableGauge returns a new Int64ObservableGauge instrument
 | 
			
		||||
	// identified by name and configured with options. The instrument is used
 | 
			
		||||
| 
						 | 
				
			
			@ -194,7 +197,10 @@ type Meter interface {
 | 
			
		|||
	// The name needs to conform to the OpenTelemetry instrument name syntax.
 | 
			
		||||
	// See the Instrument Name section of the package documentation for more
 | 
			
		||||
	// information.
 | 
			
		||||
	Float64ObservableUpDownCounter(name string, options ...Float64ObservableUpDownCounterOption) (Float64ObservableUpDownCounter, error)
 | 
			
		||||
	Float64ObservableUpDownCounter(
 | 
			
		||||
		name string,
 | 
			
		||||
		options ...Float64ObservableUpDownCounterOption,
 | 
			
		||||
	) (Float64ObservableUpDownCounter, error)
 | 
			
		||||
 | 
			
		||||
	// Float64ObservableGauge returns a new Float64ObservableGauge instrument
 | 
			
		||||
	// identified by name and configured with options. The instrument is used
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -86,13 +86,19 @@ func (Meter) Int64Gauge(string, ...metric.Int64GaugeOption) (metric.Int64Gauge,
 | 
			
		|||
 | 
			
		||||
// Int64ObservableCounter returns an ObservableCounter used to record int64
 | 
			
		||||
// measurements that produces no telemetry.
 | 
			
		||||
func (Meter) Int64ObservableCounter(string, ...metric.Int64ObservableCounterOption) (metric.Int64ObservableCounter, error) {
 | 
			
		||||
func (Meter) Int64ObservableCounter(
 | 
			
		||||
	string,
 | 
			
		||||
	...metric.Int64ObservableCounterOption,
 | 
			
		||||
) (metric.Int64ObservableCounter, error) {
 | 
			
		||||
	return Int64ObservableCounter{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Int64ObservableUpDownCounter returns an ObservableUpDownCounter used to
 | 
			
		||||
// record int64 measurements that produces no telemetry.
 | 
			
		||||
func (Meter) Int64ObservableUpDownCounter(string, ...metric.Int64ObservableUpDownCounterOption) (metric.Int64ObservableUpDownCounter, error) {
 | 
			
		||||
func (Meter) Int64ObservableUpDownCounter(
 | 
			
		||||
	string,
 | 
			
		||||
	...metric.Int64ObservableUpDownCounterOption,
 | 
			
		||||
) (metric.Int64ObservableUpDownCounter, error) {
 | 
			
		||||
	return Int64ObservableUpDownCounter{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -128,19 +134,28 @@ func (Meter) Float64Gauge(string, ...metric.Float64GaugeOption) (metric.Float64G
 | 
			
		|||
 | 
			
		||||
// Float64ObservableCounter returns an ObservableCounter used to record int64
 | 
			
		||||
// measurements that produces no telemetry.
 | 
			
		||||
func (Meter) Float64ObservableCounter(string, ...metric.Float64ObservableCounterOption) (metric.Float64ObservableCounter, error) {
 | 
			
		||||
func (Meter) Float64ObservableCounter(
 | 
			
		||||
	string,
 | 
			
		||||
	...metric.Float64ObservableCounterOption,
 | 
			
		||||
) (metric.Float64ObservableCounter, error) {
 | 
			
		||||
	return Float64ObservableCounter{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Float64ObservableUpDownCounter returns an ObservableUpDownCounter used to
 | 
			
		||||
// record int64 measurements that produces no telemetry.
 | 
			
		||||
func (Meter) Float64ObservableUpDownCounter(string, ...metric.Float64ObservableUpDownCounterOption) (metric.Float64ObservableUpDownCounter, error) {
 | 
			
		||||
func (Meter) Float64ObservableUpDownCounter(
 | 
			
		||||
	string,
 | 
			
		||||
	...metric.Float64ObservableUpDownCounterOption,
 | 
			
		||||
) (metric.Float64ObservableUpDownCounter, error) {
 | 
			
		||||
	return Float64ObservableUpDownCounter{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Float64ObservableGauge returns an ObservableGauge used to record int64
 | 
			
		||||
// measurements that produces no telemetry.
 | 
			
		||||
func (Meter) Float64ObservableGauge(string, ...metric.Float64ObservableGaugeOption) (metric.Float64ObservableGauge, error) {
 | 
			
		||||
func (Meter) Float64ObservableGauge(
 | 
			
		||||
	string,
 | 
			
		||||
	...metric.Float64ObservableGaugeOption,
 | 
			
		||||
) (metric.Float64ObservableGauge, error) {
 | 
			
		||||
	return Float64ObservableGauge{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,7 +34,9 @@ func CheckFileFormatField(fileFormat string, supportedFormatMajor, supportedForm
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	// Check that the major version number in the file is the same as what we expect.
 | 
			
		||||
	if fileFormatParsed.Major() != uint64(supportedFormatMajor) { // nolint:gosec // Version can't be negative (overflow checked).
 | 
			
		||||
	if fileFormatParsed.Major() != uint64(
 | 
			
		||||
		supportedFormatMajor,
 | 
			
		||||
	) { // nolint:gosec // Version can't be negative (overflow checked).
 | 
			
		||||
		return fmt.Errorf(
 | 
			
		||||
			"this library cannot parse file formats with major version other than %v",
 | 
			
		||||
			supportedFormatMajor,
 | 
			
		||||
| 
						 | 
				
			
			@ -43,7 +45,9 @@ func CheckFileFormatField(fileFormat string, supportedFormatMajor, supportedForm
 | 
			
		|||
 | 
			
		||||
	// Check that the file minor version number is not greater than
 | 
			
		||||
	// what is requested supports.
 | 
			
		||||
	if fileFormatParsed.Minor() > uint64(supportedFormatMinor) { // nolint:gosec // Version can't be negative (overflow checked).
 | 
			
		||||
	if fileFormatParsed.Minor() > uint64(
 | 
			
		||||
		supportedFormatMinor,
 | 
			
		||||
	) { // nolint:gosec // Version can't be negative (overflow checked).
 | 
			
		||||
		supportedFormatMajorMinor := strconv.Itoa(supportedFormatMajor) + "." +
 | 
			
		||||
			strconv.Itoa(supportedFormatMinor) // 1.0
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,11 +47,14 @@ func TestLoggerEmit(t *testing.T) {
 | 
			
		|||
	rWithNoObservedTimestamp := r
 | 
			
		||||
	rWithNoObservedTimestamp.SetObservedTimestamp(time.Time{})
 | 
			
		||||
 | 
			
		||||
	contextWithSpanContext := trace.ContextWithSpanContext(context.Background(), trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
	contextWithSpanContext := trace.ContextWithSpanContext(
 | 
			
		||||
		context.Background(),
 | 
			
		||||
		trace.NewSpanContext(trace.SpanContextConfig{
 | 
			
		||||
			TraceID:    trace.TraceID{0o1},
 | 
			
		||||
			SpanID:     trace.SpanID{0o2},
 | 
			
		||||
			TraceFlags: 0x1,
 | 
			
		||||
	}))
 | 
			
		||||
		}),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	testCases := []struct {
 | 
			
		||||
		name            string
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -73,6 +73,8 @@ func (f RecordFactory) NewRecord() sdklog.Record {
 | 
			
		|||
func set(r *sdklog.Record, name string, value any) {
 | 
			
		||||
	rVal := reflect.ValueOf(r).Elem()
 | 
			
		||||
	rf := rVal.FieldByName(name)
 | 
			
		||||
	rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem() // nolint: gosec  // conversion of uintptr -> unsafe.Pointer.
 | 
			
		||||
	rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).
 | 
			
		||||
		Elem()
 | 
			
		||||
		// nolint: gosec  // conversion of uintptr -> unsafe.Pointer.
 | 
			
		||||
	rf.Set(reflect.ValueOf(value))
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -203,8 +203,14 @@ func TestWithResource(t *testing.T) {
 | 
			
		|||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "explicit resource",
 | 
			
		||||
			options: []LoggerProviderOption{WithResource(resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5)))},
 | 
			
		||||
			want:    mergeResource(t, resource.Environment(), resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5))),
 | 
			
		||||
			options: []LoggerProviderOption{
 | 
			
		||||
				WithResource(resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5))),
 | 
			
		||||
			},
 | 
			
		||||
			want: mergeResource(
 | 
			
		||||
				t,
 | 
			
		||||
				resource.Environment(),
 | 
			
		||||
				resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5)),
 | 
			
		||||
			),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "last resource wins",
 | 
			
		||||
| 
						 | 
				
			
			@ -212,12 +218,22 @@ func TestWithResource(t *testing.T) {
 | 
			
		|||
				WithResource(resource.NewSchemaless(attribute.String("rk1", "vk1"), attribute.Int64("rk2", 5))),
 | 
			
		||||
				WithResource(resource.NewSchemaless(attribute.String("rk3", "rv3"), attribute.Int64("rk4", 10))),
 | 
			
		||||
			},
 | 
			
		||||
			want: mergeResource(t, resource.Environment(), resource.NewSchemaless(attribute.String("rk3", "rv3"), attribute.Int64("rk4", 10))),
 | 
			
		||||
			want: mergeResource(
 | 
			
		||||
				t,
 | 
			
		||||
				resource.Environment(),
 | 
			
		||||
				resource.NewSchemaless(attribute.String("rk3", "rv3"), attribute.Int64("rk4", 10)),
 | 
			
		||||
			),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "overlapping attributes with environment resource",
 | 
			
		||||
			options: []LoggerProviderOption{WithResource(resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk5", 10)))},
 | 
			
		||||
			want:    mergeResource(t, resource.Environment(), resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk5", 10))),
 | 
			
		||||
			options: []LoggerProviderOption{
 | 
			
		||||
				WithResource(resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk5", 10))),
 | 
			
		||||
			},
 | 
			
		||||
			want: mergeResource(
 | 
			
		||||
				t,
 | 
			
		||||
				resource.Environment(),
 | 
			
		||||
				resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk5", 10)),
 | 
			
		||||
			),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tc := range cases {
 | 
			
		||||
| 
						 | 
				
			
			@ -296,12 +312,26 @@ func TestLoggerProviderLogger(t *testing.T) {
 | 
			
		|||
	t.Run("SameLoggers", func(t *testing.T) {
 | 
			
		||||
		p := NewLoggerProvider()
 | 
			
		||||
 | 
			
		||||
		l0, l1, l2 := p.Logger("l0"), p.Logger("l1"), p.Logger("l0", log.WithInstrumentationAttributes(attribute.String("foo", "bar")))
 | 
			
		||||
		l0, l1, l2 := p.Logger(
 | 
			
		||||
			"l0",
 | 
			
		||||
		), p.Logger(
 | 
			
		||||
			"l1",
 | 
			
		||||
		), p.Logger(
 | 
			
		||||
			"l0",
 | 
			
		||||
			log.WithInstrumentationAttributes(attribute.String("foo", "bar")),
 | 
			
		||||
		)
 | 
			
		||||
		assert.NotSame(t, l0, l1)
 | 
			
		||||
		assert.NotSame(t, l0, l2)
 | 
			
		||||
		assert.NotSame(t, l1, l2)
 | 
			
		||||
 | 
			
		||||
		l3, l4, l5 := p.Logger("l0"), p.Logger("l1"), p.Logger("l0", log.WithInstrumentationAttributes(attribute.String("foo", "bar")))
 | 
			
		||||
		l3, l4, l5 := p.Logger(
 | 
			
		||||
			"l0",
 | 
			
		||||
		), p.Logger(
 | 
			
		||||
			"l1",
 | 
			
		||||
		), p.Logger(
 | 
			
		||||
			"l0",
 | 
			
		||||
			log.WithInstrumentationAttributes(attribute.String("foo", "bar")),
 | 
			
		||||
		)
 | 
			
		||||
		assert.Same(t, l0, l3)
 | 
			
		||||
		assert.Same(t, l1, l4)
 | 
			
		||||
		assert.Same(t, l2, l5)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,7 +33,9 @@ const envVarResourceAttributes = "OTEL_RESOURCE_ATTRIBUTES"
 | 
			
		|||
 | 
			
		||||
var _ Reader = (*reader)(nil)
 | 
			
		||||
 | 
			
		||||
func (r *reader) aggregation(kind InstrumentKind) Aggregation { // nolint:revive  // import-shadow for method scoped by type.
 | 
			
		||||
func (r *reader) aggregation(
 | 
			
		||||
	kind InstrumentKind,
 | 
			
		||||
) Aggregation { // nolint:revive  // import-shadow for method scoped by type.
 | 
			
		||||
	return r.aggregationFunc(kind)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -149,8 +151,14 @@ func TestWithResource(t *testing.T) {
 | 
			
		|||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "explicit resource",
 | 
			
		||||
			options: []Option{WithResource(resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5)))},
 | 
			
		||||
			want:    mergeResource(t, resource.Environment(), resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5))),
 | 
			
		||||
			options: []Option{
 | 
			
		||||
				WithResource(resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5))),
 | 
			
		||||
			},
 | 
			
		||||
			want: mergeResource(
 | 
			
		||||
				t,
 | 
			
		||||
				resource.Environment(),
 | 
			
		||||
				resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5)),
 | 
			
		||||
			),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "last resource wins",
 | 
			
		||||
| 
						 | 
				
			
			@ -158,12 +166,22 @@ func TestWithResource(t *testing.T) {
 | 
			
		|||
				WithResource(resource.NewSchemaless(attribute.String("rk1", "vk1"), attribute.Int64("rk2", 5))),
 | 
			
		||||
				WithResource(resource.NewSchemaless(attribute.String("rk3", "rv3"), attribute.Int64("rk4", 10))),
 | 
			
		||||
			},
 | 
			
		||||
			want: mergeResource(t, resource.Environment(), resource.NewSchemaless(attribute.String("rk3", "rv3"), attribute.Int64("rk4", 10))),
 | 
			
		||||
			want: mergeResource(
 | 
			
		||||
				t,
 | 
			
		||||
				resource.Environment(),
 | 
			
		||||
				resource.NewSchemaless(attribute.String("rk3", "rv3"), attribute.Int64("rk4", 10)),
 | 
			
		||||
			),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "overlapping attributes with environment resource",
 | 
			
		||||
			options: []Option{WithResource(resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk5", 10)))},
 | 
			
		||||
			want:    mergeResource(t, resource.Environment(), resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk5", 10))),
 | 
			
		||||
			options: []Option{
 | 
			
		||||
				WithResource(resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk5", 10))),
 | 
			
		||||
			},
 | 
			
		||||
			want: mergeResource(
 | 
			
		||||
				t,
 | 
			
		||||
				resource.Environment(),
 | 
			
		||||
				resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk5", 10)),
 | 
			
		||||
			),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tc := range cases {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,10 @@ type ExemplarReservoirProviderSelector func(Aggregation) exemplar.ReservoirProvi
 | 
			
		|||
 | 
			
		||||
// reservoirFunc returns the appropriately configured exemplar reservoir
 | 
			
		||||
// creation func based on the passed InstrumentKind and filter configuration.
 | 
			
		||||
func reservoirFunc[N int64 | float64](provider exemplar.ReservoirProvider, filter exemplar.Filter) func(attribute.Set) aggregate.FilteredExemplarReservoir[N] {
 | 
			
		||||
func reservoirFunc[N int64 | float64](
 | 
			
		||||
	provider exemplar.ReservoirProvider,
 | 
			
		||||
	filter exemplar.Filter,
 | 
			
		||||
) func(attribute.Set) aggregate.FilteredExemplarReservoir[N] {
 | 
			
		||||
	return func(attrs attribute.Set) aggregate.FilteredExemplarReservoir[N] {
 | 
			
		||||
		return aggregate.NewFilteredExemplarReservoir[N](filter, provider(attrs))
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -208,7 +208,11 @@ func (i *int64Inst) Enabled(_ context.Context) bool {
 | 
			
		|||
	return len(i.measures) != 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (i *int64Inst) aggregate(ctx context.Context, val int64, s attribute.Set) { // nolint:revive  // okay to shadow pkg with method.
 | 
			
		||||
func (i *int64Inst) aggregate(
 | 
			
		||||
	ctx context.Context,
 | 
			
		||||
	val int64,
 | 
			
		||||
	s attribute.Set,
 | 
			
		||||
) { // nolint:revive  // okay to shadow pkg with method.
 | 
			
		||||
	for _, in := range i.measures {
 | 
			
		||||
		in(ctx, val, s)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -121,7 +121,10 @@ func (b Builder[N]) Sum(monotonic bool) (Measure[N], ComputeAggregation) {
 | 
			
		|||
 | 
			
		||||
// ExplicitBucketHistogram returns a histogram aggregate function input and
 | 
			
		||||
// output.
 | 
			
		||||
func (b Builder[N]) ExplicitBucketHistogram(boundaries []float64, noMinMax, noSum bool) (Measure[N], ComputeAggregation) {
 | 
			
		||||
func (b Builder[N]) ExplicitBucketHistogram(
 | 
			
		||||
	boundaries []float64,
 | 
			
		||||
	noMinMax, noSum bool,
 | 
			
		||||
) (Measure[N], ComputeAggregation) {
 | 
			
		||||
	h := newHistogram[N](boundaries, noMinMax, noSum, b.AggregationLimit, b.resFunc())
 | 
			
		||||
	switch b.Temporality {
 | 
			
		||||
	case metricdata.DeltaTemporality:
 | 
			
		||||
| 
						 | 
				
			
			@ -133,7 +136,10 @@ func (b Builder[N]) ExplicitBucketHistogram(boundaries []float64, noMinMax, noSu
 | 
			
		|||
 | 
			
		||||
// ExponentialBucketHistogram returns a histogram aggregate function input and
 | 
			
		||||
// output.
 | 
			
		||||
func (b Builder[N]) ExponentialBucketHistogram(maxSize, maxScale int32, noMinMax, noSum bool) (Measure[N], ComputeAggregation) {
 | 
			
		||||
func (b Builder[N]) ExponentialBucketHistogram(
 | 
			
		||||
	maxSize, maxScale int32,
 | 
			
		||||
	noMinMax, noSum bool,
 | 
			
		||||
) (Measure[N], ComputeAggregation) {
 | 
			
		||||
	h := newExponentialHistogram[N](maxSize, maxScale, noMinMax, noSum, b.AggregationLimit, b.resFunc())
 | 
			
		||||
	switch b.Temporality {
 | 
			
		||||
	case metricdata.DeltaTemporality:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,7 +48,12 @@ type expoHistogramDataPoint[N int64 | float64] struct {
 | 
			
		|||
	zeroCount  uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newExpoHistogramDataPoint[N int64 | float64](attrs attribute.Set, maxSize int, maxScale int32, noMinMax, noSum bool) *expoHistogramDataPoint[N] { // nolint:revive // we need this control flag
 | 
			
		||||
func newExpoHistogramDataPoint[N int64 | float64](
 | 
			
		||||
	attrs attribute.Set,
 | 
			
		||||
	maxSize int,
 | 
			
		||||
	maxScale int32,
 | 
			
		||||
	noMinMax, noSum bool,
 | 
			
		||||
) *expoHistogramDataPoint[N] { // nolint:revive // we need this control flag
 | 
			
		||||
	f := math.MaxFloat64
 | 
			
		||||
	ma := N(f) // if N is int64, max will overflow to -9223372036854775808
 | 
			
		||||
	mi := N(-f)
 | 
			
		||||
| 
						 | 
				
			
			@ -283,7 +288,12 @@ func (b *expoBuckets) downscale(delta int32) {
 | 
			
		|||
// newExponentialHistogram returns an Aggregator that summarizes a set of
 | 
			
		||||
// measurements as an exponential histogram. Each histogram is scoped by attributes
 | 
			
		||||
// and the aggregation cycle the measurements were made in.
 | 
			
		||||
func newExponentialHistogram[N int64 | float64](maxSize, maxScale int32, noMinMax, noSum bool, limit int, r func(attribute.Set) FilteredExemplarReservoir[N]) *expoHistogram[N] {
 | 
			
		||||
func newExponentialHistogram[N int64 | float64](
 | 
			
		||||
	maxSize, maxScale int32,
 | 
			
		||||
	noMinMax, noSum bool,
 | 
			
		||||
	limit int,
 | 
			
		||||
	r func(attribute.Set) FilteredExemplarReservoir[N],
 | 
			
		||||
) *expoHistogram[N] {
 | 
			
		||||
	return &expoHistogram[N]{
 | 
			
		||||
		noSum:    noSum,
 | 
			
		||||
		noMinMax: noMinMax,
 | 
			
		||||
| 
						 | 
				
			
			@ -314,7 +324,12 @@ type expoHistogram[N int64 | float64] struct {
 | 
			
		|||
	start time.Time
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *expoHistogram[N]) measure(ctx context.Context, value N, fltrAttr attribute.Set, droppedAttr []attribute.KeyValue) {
 | 
			
		||||
func (e *expoHistogram[N]) measure(
 | 
			
		||||
	ctx context.Context,
 | 
			
		||||
	value N,
 | 
			
		||||
	fltrAttr attribute.Set,
 | 
			
		||||
	droppedAttr []attribute.KeyValue,
 | 
			
		||||
) {
 | 
			
		||||
	// Ignore NaN and infinity.
 | 
			
		||||
	if math.IsInf(float64(value), 0) || math.IsNaN(float64(value)) {
 | 
			
		||||
		return
 | 
			
		||||
| 
						 | 
				
			
			@ -360,11 +375,19 @@ func (e *expoHistogram[N]) delta(dest *metricdata.Aggregation) int {
 | 
			
		|||
		hDPts[i].ZeroThreshold = 0.0
 | 
			
		||||
 | 
			
		||||
		hDPts[i].PositiveBucket.Offset = val.posBuckets.startBin
 | 
			
		||||
		hDPts[i].PositiveBucket.Counts = reset(hDPts[i].PositiveBucket.Counts, len(val.posBuckets.counts), len(val.posBuckets.counts))
 | 
			
		||||
		hDPts[i].PositiveBucket.Counts = reset(
 | 
			
		||||
			hDPts[i].PositiveBucket.Counts,
 | 
			
		||||
			len(val.posBuckets.counts),
 | 
			
		||||
			len(val.posBuckets.counts),
 | 
			
		||||
		)
 | 
			
		||||
		copy(hDPts[i].PositiveBucket.Counts, val.posBuckets.counts)
 | 
			
		||||
 | 
			
		||||
		hDPts[i].NegativeBucket.Offset = val.negBuckets.startBin
 | 
			
		||||
		hDPts[i].NegativeBucket.Counts = reset(hDPts[i].NegativeBucket.Counts, len(val.negBuckets.counts), len(val.negBuckets.counts))
 | 
			
		||||
		hDPts[i].NegativeBucket.Counts = reset(
 | 
			
		||||
			hDPts[i].NegativeBucket.Counts,
 | 
			
		||||
			len(val.negBuckets.counts),
 | 
			
		||||
			len(val.negBuckets.counts),
 | 
			
		||||
		)
 | 
			
		||||
		copy(hDPts[i].NegativeBucket.Counts, val.negBuckets.counts)
 | 
			
		||||
 | 
			
		||||
		if !e.noSum {
 | 
			
		||||
| 
						 | 
				
			
			@ -413,11 +436,19 @@ func (e *expoHistogram[N]) cumulative(dest *metricdata.Aggregation) int {
 | 
			
		|||
		hDPts[i].ZeroThreshold = 0.0
 | 
			
		||||
 | 
			
		||||
		hDPts[i].PositiveBucket.Offset = val.posBuckets.startBin
 | 
			
		||||
		hDPts[i].PositiveBucket.Counts = reset(hDPts[i].PositiveBucket.Counts, len(val.posBuckets.counts), len(val.posBuckets.counts))
 | 
			
		||||
		hDPts[i].PositiveBucket.Counts = reset(
 | 
			
		||||
			hDPts[i].PositiveBucket.Counts,
 | 
			
		||||
			len(val.posBuckets.counts),
 | 
			
		||||
			len(val.posBuckets.counts),
 | 
			
		||||
		)
 | 
			
		||||
		copy(hDPts[i].PositiveBucket.Counts, val.posBuckets.counts)
 | 
			
		||||
 | 
			
		||||
		hDPts[i].NegativeBucket.Offset = val.negBuckets.startBin
 | 
			
		||||
		hDPts[i].NegativeBucket.Counts = reset(hDPts[i].NegativeBucket.Counts, len(val.negBuckets.counts), len(val.negBuckets.counts))
 | 
			
		||||
		hDPts[i].NegativeBucket.Counts = reset(
 | 
			
		||||
			hDPts[i].NegativeBucket.Counts,
 | 
			
		||||
			len(val.negBuckets.counts),
 | 
			
		||||
			len(val.negBuckets.counts),
 | 
			
		||||
		)
 | 
			
		||||
		copy(hDPts[i].NegativeBucket.Counts, val.negBuckets.counts)
 | 
			
		||||
 | 
			
		||||
		if !e.noSum {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1073,10 +1073,22 @@ func FuzzGetBin(f *testing.F) {
 | 
			
		|||
		p.scale = (scale%31+31)%31 - 10
 | 
			
		||||
		got := p.getBin(v)
 | 
			
		||||
		if v <= lowerBound(got, p.scale) {
 | 
			
		||||
			t.Errorf("v=%x scale =%d had bin %d, but was below lower bound %x", v, p.scale, got, lowerBound(got, p.scale))
 | 
			
		||||
			t.Errorf(
 | 
			
		||||
				"v=%x scale =%d had bin %d, but was below lower bound %x",
 | 
			
		||||
				v,
 | 
			
		||||
				p.scale,
 | 
			
		||||
				got,
 | 
			
		||||
				lowerBound(got, p.scale),
 | 
			
		||||
			)
 | 
			
		||||
		}
 | 
			
		||||
		if v > lowerBound(got+1, p.scale) {
 | 
			
		||||
			t.Errorf("v=%x scale =%d had bin %d, but was above upper bound %x", v, p.scale, got, lowerBound(got+1, p.scale))
 | 
			
		||||
			t.Errorf(
 | 
			
		||||
				"v=%x scale =%d had bin %d, but was above upper bound %x",
 | 
			
		||||
				v,
 | 
			
		||||
				p.scale,
 | 
			
		||||
				got,
 | 
			
		||||
				lowerBound(got+1, p.scale),
 | 
			
		||||
			)
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,7 +33,10 @@ type filteredExemplarReservoir[N int64 | float64] struct {
 | 
			
		|||
 | 
			
		||||
// NewFilteredExemplarReservoir creates a [FilteredExemplarReservoir] which only offers values
 | 
			
		||||
// that are allowed by the filter.
 | 
			
		||||
func NewFilteredExemplarReservoir[N int64 | float64](f exemplar.Filter, r exemplar.Reservoir) FilteredExemplarReservoir[N] {
 | 
			
		||||
func NewFilteredExemplarReservoir[N int64 | float64](
 | 
			
		||||
	f exemplar.Filter,
 | 
			
		||||
	r exemplar.Reservoir,
 | 
			
		||||
) FilteredExemplarReservoir[N] {
 | 
			
		||||
	return &filteredExemplarReservoir[N]{
 | 
			
		||||
		filter:    f,
 | 
			
		||||
		reservoir: r,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,7 +53,12 @@ type histValues[N int64 | float64] struct {
 | 
			
		|||
	valuesMu sync.Mutex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newHistValues[N int64 | float64](bounds []float64, noSum bool, limit int, r func(attribute.Set) FilteredExemplarReservoir[N]) *histValues[N] {
 | 
			
		||||
func newHistValues[N int64 | float64](
 | 
			
		||||
	bounds []float64,
 | 
			
		||||
	noSum bool,
 | 
			
		||||
	limit int,
 | 
			
		||||
	r func(attribute.Set) FilteredExemplarReservoir[N],
 | 
			
		||||
) *histValues[N] {
 | 
			
		||||
	// The responsibility of keeping all buckets correctly associated with the
 | 
			
		||||
	// passed boundaries is ultimately this type's responsibility. Make a copy
 | 
			
		||||
	// here so we can always guarantee this. Or, in the case of failure, have
 | 
			
		||||
| 
						 | 
				
			
			@ -71,7 +76,12 @@ func newHistValues[N int64 | float64](bounds []float64, noSum bool, limit int, r
 | 
			
		|||
 | 
			
		||||
// Aggregate records the measurement value, scoped by attr, and aggregates it
 | 
			
		||||
// into a histogram.
 | 
			
		||||
func (s *histValues[N]) measure(ctx context.Context, value N, fltrAttr attribute.Set, droppedAttr []attribute.KeyValue) {
 | 
			
		||||
func (s *histValues[N]) measure(
 | 
			
		||||
	ctx context.Context,
 | 
			
		||||
	value N,
 | 
			
		||||
	fltrAttr attribute.Set,
 | 
			
		||||
	droppedAttr []attribute.KeyValue,
 | 
			
		||||
) {
 | 
			
		||||
	// This search will return an index in the range [0, len(s.bounds)], where
 | 
			
		||||
	// it will return len(s.bounds) if value is greater than the last element
 | 
			
		||||
	// of s.bounds. This aligns with the buckets in that the length of buckets
 | 
			
		||||
| 
						 | 
				
			
			@ -108,7 +118,12 @@ func (s *histValues[N]) measure(ctx context.Context, value N, fltrAttr attribute
 | 
			
		|||
 | 
			
		||||
// newHistogram returns an Aggregator that summarizes a set of measurements as
 | 
			
		||||
// an histogram.
 | 
			
		||||
func newHistogram[N int64 | float64](boundaries []float64, noMinMax, noSum bool, limit int, r func(attribute.Set) FilteredExemplarReservoir[N]) *histogram[N] {
 | 
			
		||||
func newHistogram[N int64 | float64](
 | 
			
		||||
	boundaries []float64,
 | 
			
		||||
	noMinMax, noSum bool,
 | 
			
		||||
	limit int,
 | 
			
		||||
	r func(attribute.Set) FilteredExemplarReservoir[N],
 | 
			
		||||
) *histogram[N] {
 | 
			
		||||
	return &histogram[N]{
 | 
			
		||||
		histValues: newHistValues[N](boundaries, noSum, limit, r),
 | 
			
		||||
		noMinMax:   noMinMax,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -225,7 +225,12 @@ func testCumulativeHist[N int64 | float64](c conf[N]) func(t *testing.T) {
 | 
			
		|||
 | 
			
		||||
// hPointSummed returns an HistogramDataPoint that started and ended now with
 | 
			
		||||
// multi number of measurements values v. It includes a min and max (set to v).
 | 
			
		||||
func hPointSummed[N int64 | float64](a attribute.Set, v N, multi uint64, start, t time.Time) metricdata.HistogramDataPoint[N] {
 | 
			
		||||
func hPointSummed[N int64 | float64](
 | 
			
		||||
	a attribute.Set,
 | 
			
		||||
	v N,
 | 
			
		||||
	multi uint64,
 | 
			
		||||
	start, t time.Time,
 | 
			
		||||
) metricdata.HistogramDataPoint[N] {
 | 
			
		||||
	idx := sort.SearchFloat64s(bounds, float64(v))
 | 
			
		||||
	counts := make([]uint64, len(bounds)+1)
 | 
			
		||||
	counts[idx] += multi
 | 
			
		||||
| 
						 | 
				
			
			@ -244,7 +249,12 @@ func hPointSummed[N int64 | float64](a attribute.Set, v N, multi uint64, start,
 | 
			
		|||
 | 
			
		||||
// hPoint returns an HistogramDataPoint that started and ended now with multi
 | 
			
		||||
// number of measurements values v. It includes a min and max (set to v).
 | 
			
		||||
func hPoint[N int64 | float64](a attribute.Set, v N, multi uint64, start, t time.Time) metricdata.HistogramDataPoint[N] {
 | 
			
		||||
func hPoint[N int64 | float64](
 | 
			
		||||
	a attribute.Set,
 | 
			
		||||
	v N,
 | 
			
		||||
	multi uint64,
 | 
			
		||||
	start, t time.Time,
 | 
			
		||||
) metricdata.HistogramDataPoint[N] {
 | 
			
		||||
	idx := sort.SearchFloat64s(bounds, float64(v))
 | 
			
		||||
	counts := make([]uint64, len(bounds)+1)
 | 
			
		||||
	counts[idx] += multi
 | 
			
		||||
| 
						 | 
				
			
			@ -339,7 +349,12 @@ func TestCumulativeHistogramImmutableCounts(t *testing.T) {
 | 
			
		|||
	cpCounts := make([]uint64, len(hdp.BucketCounts))
 | 
			
		||||
	copy(cpCounts, hdp.BucketCounts)
 | 
			
		||||
	hdp.BucketCounts[0] = 10
 | 
			
		||||
	assert.Equal(t, cpCounts, h.values[alice.Equivalent()].counts, "modifying the Aggregator bucket counts should not change the Aggregator")
 | 
			
		||||
	assert.Equal(
 | 
			
		||||
		t,
 | 
			
		||||
		cpCounts,
 | 
			
		||||
		h.values[alice.Equivalent()].counts,
 | 
			
		||||
		"modifying the Aggregator bucket counts should not change the Aggregator",
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDeltaHistogramReset(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -114,7 +114,10 @@ func (s *lastValue[N]) copyDpts(dest *[]metricdata.DataPoint[N], t time.Time) in
 | 
			
		|||
 | 
			
		||||
// newPrecomputedLastValue returns an aggregator that summarizes a set of
 | 
			
		||||
// observations as the last one made.
 | 
			
		||||
func newPrecomputedLastValue[N int64 | float64](limit int, r func(attribute.Set) FilteredExemplarReservoir[N]) *precomputedLastValue[N] {
 | 
			
		||||
func newPrecomputedLastValue[N int64 | float64](
 | 
			
		||||
	limit int,
 | 
			
		||||
	r func(attribute.Set) FilteredExemplarReservoir[N],
 | 
			
		||||
) *precomputedLastValue[N] {
 | 
			
		||||
	return &precomputedLastValue[N]{lastValue: newLastValue[N](limit, r)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -143,7 +143,11 @@ func (s *sum[N]) cumulative(dest *metricdata.Aggregation) int {
 | 
			
		|||
// newPrecomputedSum returns an aggregator that summarizes a set of
 | 
			
		||||
// observations as their arithmetic sum. Each sum is scoped by attributes and
 | 
			
		||||
// the aggregation cycle the measurements were made in.
 | 
			
		||||
func newPrecomputedSum[N int64 | float64](monotonic bool, limit int, r func(attribute.Set) FilteredExemplarReservoir[N]) *precomputedSum[N] {
 | 
			
		||||
func newPrecomputedSum[N int64 | float64](
 | 
			
		||||
	monotonic bool,
 | 
			
		||||
	limit int,
 | 
			
		||||
	r func(attribute.Set) FilteredExemplarReservoir[N],
 | 
			
		||||
) *precomputedSum[N] {
 | 
			
		||||
	return &precomputedSum[N]{
 | 
			
		||||
		valueMap:  newValueMap[N](limit, r),
 | 
			
		||||
		monotonic: monotonic,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -58,7 +58,9 @@ func (mr *ManualReader) temporality(kind InstrumentKind) metricdata.Temporality
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// aggregation returns what Aggregation to use for kind.
 | 
			
		||||
func (mr *ManualReader) aggregation(kind InstrumentKind) Aggregation { // nolint:revive  // import-shadow for method scoped by type.
 | 
			
		||||
func (mr *ManualReader) aggregation(
 | 
			
		||||
	kind InstrumentKind,
 | 
			
		||||
) Aggregation { // nolint:revive  // import-shadow for method scoped by type.
 | 
			
		||||
	return mr.aggregationSelector(kind)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -82,7 +82,10 @@ func (m *meter) Int64Counter(name string, options ...metric.Int64CounterOption)
 | 
			
		|||
// Int64UpDownCounter returns a new instrument identified by name and
 | 
			
		||||
// configured with options. The instrument is used to synchronously record
 | 
			
		||||
// int64 measurements during a computational operation.
 | 
			
		||||
func (m *meter) Int64UpDownCounter(name string, options ...metric.Int64UpDownCounterOption) (metric.Int64UpDownCounter, error) {
 | 
			
		||||
func (m *meter) Int64UpDownCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Int64UpDownCounterOption,
 | 
			
		||||
) (metric.Int64UpDownCounter, error) {
 | 
			
		||||
	cfg := metric.NewInt64UpDownCounterConfig(options...)
 | 
			
		||||
	const kind = InstrumentKindUpDownCounter
 | 
			
		||||
	p := int64InstProvider{m}
 | 
			
		||||
| 
						 | 
				
			
			@ -174,7 +177,10 @@ func (m *meter) int64ObservableInstrument(id Instrument, callbacks []metric.Int6
 | 
			
		|||
// Description, and Unit, only the first set of callbacks provided are used.
 | 
			
		||||
// Use meter.RegisterCallback and Registration.Unregister to manage callbacks
 | 
			
		||||
// if instrumentation can be created multiple times with different callbacks.
 | 
			
		||||
func (m *meter) Int64ObservableCounter(name string, options ...metric.Int64ObservableCounterOption) (metric.Int64ObservableCounter, error) {
 | 
			
		||||
func (m *meter) Int64ObservableCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Int64ObservableCounterOption,
 | 
			
		||||
) (metric.Int64ObservableCounter, error) {
 | 
			
		||||
	cfg := metric.NewInt64ObservableCounterConfig(options...)
 | 
			
		||||
	id := Instrument{
 | 
			
		||||
		Name:        name,
 | 
			
		||||
| 
						 | 
				
			
			@ -195,7 +201,10 @@ func (m *meter) Int64ObservableCounter(name string, options ...metric.Int64Obser
 | 
			
		|||
// Description, and Unit, only the first set of callbacks provided are used.
 | 
			
		||||
// Use meter.RegisterCallback and Registration.Unregister to manage callbacks
 | 
			
		||||
// if instrumentation can be created multiple times with different callbacks.
 | 
			
		||||
func (m *meter) Int64ObservableUpDownCounter(name string, options ...metric.Int64ObservableUpDownCounterOption) (metric.Int64ObservableUpDownCounter, error) {
 | 
			
		||||
func (m *meter) Int64ObservableUpDownCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Int64ObservableUpDownCounterOption,
 | 
			
		||||
) (metric.Int64ObservableUpDownCounter, error) {
 | 
			
		||||
	cfg := metric.NewInt64ObservableUpDownCounterConfig(options...)
 | 
			
		||||
	id := Instrument{
 | 
			
		||||
		Name:        name,
 | 
			
		||||
| 
						 | 
				
			
			@ -216,7 +225,10 @@ func (m *meter) Int64ObservableUpDownCounter(name string, options ...metric.Int6
 | 
			
		|||
// Description, and Unit, only the first set of callbacks provided are used.
 | 
			
		||||
// Use meter.RegisterCallback and Registration.Unregister to manage callbacks
 | 
			
		||||
// if instrumentation can be created multiple times with different callbacks.
 | 
			
		||||
func (m *meter) Int64ObservableGauge(name string, options ...metric.Int64ObservableGaugeOption) (metric.Int64ObservableGauge, error) {
 | 
			
		||||
func (m *meter) Int64ObservableGauge(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Int64ObservableGaugeOption,
 | 
			
		||||
) (metric.Int64ObservableGauge, error) {
 | 
			
		||||
	cfg := metric.NewInt64ObservableGaugeConfig(options...)
 | 
			
		||||
	id := Instrument{
 | 
			
		||||
		Name:        name,
 | 
			
		||||
| 
						 | 
				
			
			@ -246,7 +258,10 @@ func (m *meter) Float64Counter(name string, options ...metric.Float64CounterOpti
 | 
			
		|||
// Float64UpDownCounter returns a new instrument identified by name and
 | 
			
		||||
// configured with options. The instrument is used to synchronously record
 | 
			
		||||
// float64 measurements during a computational operation.
 | 
			
		||||
func (m *meter) Float64UpDownCounter(name string, options ...metric.Float64UpDownCounterOption) (metric.Float64UpDownCounter, error) {
 | 
			
		||||
func (m *meter) Float64UpDownCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Float64UpDownCounterOption,
 | 
			
		||||
) (metric.Float64UpDownCounter, error) {
 | 
			
		||||
	cfg := metric.NewFloat64UpDownCounterConfig(options...)
 | 
			
		||||
	const kind = InstrumentKindUpDownCounter
 | 
			
		||||
	p := float64InstProvider{m}
 | 
			
		||||
| 
						 | 
				
			
			@ -261,7 +276,10 @@ func (m *meter) Float64UpDownCounter(name string, options ...metric.Float64UpDow
 | 
			
		|||
// Float64Histogram returns a new instrument identified by name and configured
 | 
			
		||||
// with options. The instrument is used to synchronously record the
 | 
			
		||||
// distribution of float64 measurements during a computational operation.
 | 
			
		||||
func (m *meter) Float64Histogram(name string, options ...metric.Float64HistogramOption) (metric.Float64Histogram, error) {
 | 
			
		||||
func (m *meter) Float64Histogram(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Float64HistogramOption,
 | 
			
		||||
) (metric.Float64Histogram, error) {
 | 
			
		||||
	cfg := metric.NewFloat64HistogramConfig(options...)
 | 
			
		||||
	p := float64InstProvider{m}
 | 
			
		||||
	i, err := p.lookupHistogram(name, cfg)
 | 
			
		||||
| 
						 | 
				
			
			@ -289,7 +307,10 @@ func (m *meter) Float64Gauge(name string, options ...metric.Float64GaugeOption)
 | 
			
		|||
 | 
			
		||||
// float64ObservableInstrument returns a new observable identified by the Instrument.
 | 
			
		||||
// It registers callbacks for each reader's pipeline.
 | 
			
		||||
func (m *meter) float64ObservableInstrument(id Instrument, callbacks []metric.Float64Callback) (float64Observable, error) {
 | 
			
		||||
func (m *meter) float64ObservableInstrument(
 | 
			
		||||
	id Instrument,
 | 
			
		||||
	callbacks []metric.Float64Callback,
 | 
			
		||||
) (float64Observable, error) {
 | 
			
		||||
	key := instID{
 | 
			
		||||
		Name:        id.Name,
 | 
			
		||||
		Description: id.Description,
 | 
			
		||||
| 
						 | 
				
			
			@ -338,7 +359,10 @@ func (m *meter) float64ObservableInstrument(id Instrument, callbacks []metric.Fl
 | 
			
		|||
// Description, and Unit, only the first set of callbacks provided are used.
 | 
			
		||||
// Use meter.RegisterCallback and Registration.Unregister to manage callbacks
 | 
			
		||||
// if instrumentation can be created multiple times with different callbacks.
 | 
			
		||||
func (m *meter) Float64ObservableCounter(name string, options ...metric.Float64ObservableCounterOption) (metric.Float64ObservableCounter, error) {
 | 
			
		||||
func (m *meter) Float64ObservableCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Float64ObservableCounterOption,
 | 
			
		||||
) (metric.Float64ObservableCounter, error) {
 | 
			
		||||
	cfg := metric.NewFloat64ObservableCounterConfig(options...)
 | 
			
		||||
	id := Instrument{
 | 
			
		||||
		Name:        name,
 | 
			
		||||
| 
						 | 
				
			
			@ -359,7 +383,10 @@ func (m *meter) Float64ObservableCounter(name string, options ...metric.Float64O
 | 
			
		|||
// Description, and Unit, only the first set of callbacks provided are used.
 | 
			
		||||
// Use meter.RegisterCallback and Registration.Unregister to manage callbacks
 | 
			
		||||
// if instrumentation can be created multiple times with different callbacks.
 | 
			
		||||
func (m *meter) Float64ObservableUpDownCounter(name string, options ...metric.Float64ObservableUpDownCounterOption) (metric.Float64ObservableUpDownCounter, error) {
 | 
			
		||||
func (m *meter) Float64ObservableUpDownCounter(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Float64ObservableUpDownCounterOption,
 | 
			
		||||
) (metric.Float64ObservableUpDownCounter, error) {
 | 
			
		||||
	cfg := metric.NewFloat64ObservableUpDownCounterConfig(options...)
 | 
			
		||||
	id := Instrument{
 | 
			
		||||
		Name:        name,
 | 
			
		||||
| 
						 | 
				
			
			@ -380,7 +407,10 @@ func (m *meter) Float64ObservableUpDownCounter(name string, options ...metric.Fl
 | 
			
		|||
// Description, and Unit, only the first set of callbacks provided are used.
 | 
			
		||||
// Use meter.RegisterCallback and Registration.Unregister to manage callbacks
 | 
			
		||||
// if instrumentation can be created multiple times with different callbacks.
 | 
			
		||||
func (m *meter) Float64ObservableGauge(name string, options ...metric.Float64ObservableGaugeOption) (metric.Float64ObservableGauge, error) {
 | 
			
		||||
func (m *meter) Float64ObservableGauge(
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...metric.Float64ObservableGaugeOption,
 | 
			
		||||
) (metric.Float64ObservableGauge, error) {
 | 
			
		||||
	cfg := metric.NewFloat64ObservableGaugeConfig(options...)
 | 
			
		||||
	id := Instrument{
 | 
			
		||||
		Name:        name,
 | 
			
		||||
| 
						 | 
				
			
			@ -426,8 +456,10 @@ func warnRepeatedObservableCallbacks(id Instrument) {
 | 
			
		|||
		"Instrument{Name: %q, Description: %q, Kind: %q, Unit: %q}",
 | 
			
		||||
		id.Name, id.Description, "InstrumentKind"+id.Kind.String(), id.Unit,
 | 
			
		||||
	)
 | 
			
		||||
	global.Warn("Repeated observable instrument creation with callbacks. Ignoring new callbacks. Use meter.RegisterCallback and Registration.Unregister to manage callbacks.",
 | 
			
		||||
		"instrument", inst,
 | 
			
		||||
	global.Warn(
 | 
			
		||||
		"Repeated observable instrument creation with callbacks. Ignoring new callbacks. Use meter.RegisterCallback and Registration.Unregister to manage callbacks.",
 | 
			
		||||
		"instrument",
 | 
			
		||||
		inst,
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -613,7 +645,10 @@ func (p int64InstProvider) aggs(kind InstrumentKind, name, desc, u string) ([]ag
 | 
			
		|||
	return p.int64Resolver.Aggregators(inst)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p int64InstProvider) histogramAggs(name string, cfg metric.Int64HistogramConfig) ([]aggregate.Measure[int64], error) {
 | 
			
		||||
func (p int64InstProvider) histogramAggs(
 | 
			
		||||
	name string,
 | 
			
		||||
	cfg metric.Int64HistogramConfig,
 | 
			
		||||
) ([]aggregate.Measure[int64], error) {
 | 
			
		||||
	boundaries := cfg.ExplicitBucketBoundaries()
 | 
			
		||||
	aggError := AggregationExplicitBucketHistogram{Boundaries: boundaries}.err()
 | 
			
		||||
	if aggError != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -671,7 +706,10 @@ func (p float64InstProvider) aggs(kind InstrumentKind, name, desc, u string) ([]
 | 
			
		|||
	return p.float64Resolver.Aggregators(inst)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p float64InstProvider) histogramAggs(name string, cfg metric.Float64HistogramConfig) ([]aggregate.Measure[float64], error) {
 | 
			
		||||
func (p float64InstProvider) histogramAggs(
 | 
			
		||||
	name string,
 | 
			
		||||
	cfg metric.Float64HistogramConfig,
 | 
			
		||||
) ([]aggregate.Measure[float64], error) {
 | 
			
		||||
	boundaries := cfg.ExplicitBucketBoundaries()
 | 
			
		||||
	aggError := AggregationExplicitBucketHistogram{Boundaries: boundaries}.err()
 | 
			
		||||
	if aggError != nil {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -443,7 +443,10 @@ func TestMeterCreatesInstruments(t *testing.T) {
 | 
			
		|||
						{
 | 
			
		||||
							Attributes: attribute.Set{},
 | 
			
		||||
							Count:      1,
 | 
			
		||||
							Bounds:       []float64{0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000},
 | 
			
		||||
							Bounds: []float64{
 | 
			
		||||
								0, 5, 10, 25, 50, 75, 100, 250, 500,
 | 
			
		||||
								750, 1000, 2500, 5000, 7500, 10000,
 | 
			
		||||
							},
 | 
			
		||||
							BucketCounts: []uint64{0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
 | 
			
		||||
							Min:          metricdata.NewExtrema[int64](7),
 | 
			
		||||
							Max:          metricdata.NewExtrema[int64](7),
 | 
			
		||||
| 
						 | 
				
			
			@ -513,7 +516,10 @@ func TestMeterCreatesInstruments(t *testing.T) {
 | 
			
		|||
						{
 | 
			
		||||
							Attributes: attribute.Set{},
 | 
			
		||||
							Count:      1,
 | 
			
		||||
							Bounds:       []float64{0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000},
 | 
			
		||||
							Bounds: []float64{
 | 
			
		||||
								0, 5, 10, 25, 50, 75, 100, 250, 500,
 | 
			
		||||
								750, 1000, 2500, 5000, 7500, 10000,
 | 
			
		||||
							},
 | 
			
		||||
							BucketCounts: []uint64{0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
 | 
			
		||||
							Min:          metricdata.NewExtrema[float64](7.),
 | 
			
		||||
							Max:          metricdata.NewExtrema[float64](7.),
 | 
			
		||||
| 
						 | 
				
			
			@ -1577,7 +1583,10 @@ func testAttributeFilter(temporality metricdata.Temporality) func(*testing.T) {
 | 
			
		|||
					DataPoints: []metricdata.HistogramDataPoint[float64]{
 | 
			
		||||
						{
 | 
			
		||||
							Attributes: fooBar,
 | 
			
		||||
							Bounds:       []float64{0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000},
 | 
			
		||||
							Bounds: []float64{
 | 
			
		||||
								0, 5, 10, 25, 50, 75, 100, 250, 500,
 | 
			
		||||
								750, 1000, 2500, 5000, 7500, 10000,
 | 
			
		||||
							},
 | 
			
		||||
							BucketCounts: []uint64{0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
 | 
			
		||||
							Count:        2,
 | 
			
		||||
							Min:          metricdata.NewExtrema(1.),
 | 
			
		||||
| 
						 | 
				
			
			@ -1653,7 +1662,10 @@ func testAttributeFilter(temporality metricdata.Temporality) func(*testing.T) {
 | 
			
		|||
					DataPoints: []metricdata.HistogramDataPoint[int64]{
 | 
			
		||||
						{
 | 
			
		||||
							Attributes: fooBar,
 | 
			
		||||
							Bounds:       []float64{0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000},
 | 
			
		||||
							Bounds: []float64{
 | 
			
		||||
								0, 5, 10, 25, 50, 75, 100, 250, 500,
 | 
			
		||||
								750, 1000, 2500, 5000, 7500, 10000,
 | 
			
		||||
							},
 | 
			
		||||
							BucketCounts: []uint64{0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
 | 
			
		||||
							Count:        2,
 | 
			
		||||
							Min:          metricdata.NewExtrema[int64](1),
 | 
			
		||||
| 
						 | 
				
			
			@ -1689,7 +1701,12 @@ func testAttributeFilter(temporality metricdata.Temporality) func(*testing.T) {
 | 
			
		|||
				require.Len(t, m.ScopeMetrics, 1)
 | 
			
		||||
				require.Len(t, m.ScopeMetrics[0].Metrics, 1)
 | 
			
		||||
 | 
			
		||||
				metricdatatest.AssertEqual(t, tt.wantMetric, m.ScopeMetrics[0].Metrics[0], metricdatatest.IgnoreTimestamp())
 | 
			
		||||
				metricdatatest.AssertEqual(
 | 
			
		||||
					t,
 | 
			
		||||
					tt.wantMetric,
 | 
			
		||||
					m.ScopeMetrics[0].Metrics[0],
 | 
			
		||||
					metricdatatest.IgnoreTimestamp(),
 | 
			
		||||
				)
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -2119,7 +2136,15 @@ func TestMalformedSelectors(t *testing.T) {
 | 
			
		|||
				obs.ObserveFloat64(afGauge, 1)
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
			_, err = meter.RegisterCallback(callback, aiCounter, aiUpDownCounter, aiGauge, afCounter, afUpDownCounter, afGauge)
 | 
			
		||||
			_, err = meter.RegisterCallback(
 | 
			
		||||
				callback,
 | 
			
		||||
				aiCounter,
 | 
			
		||||
				aiUpDownCounter,
 | 
			
		||||
				aiGauge,
 | 
			
		||||
				afCounter,
 | 
			
		||||
				afUpDownCounter,
 | 
			
		||||
				afGauge,
 | 
			
		||||
			)
 | 
			
		||||
			require.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
			siCounter.Add(context.Background(), 1)
 | 
			
		||||
| 
						 | 
				
			
			@ -2182,7 +2207,10 @@ func TestHistogramBucketPrecedenceOrdering(t *testing.T) {
 | 
			
		|||
		},
 | 
			
		||||
	} {
 | 
			
		||||
		t.Run(tt.desc, func(t *testing.T) {
 | 
			
		||||
			meter := NewMeterProvider(WithView(tt.views...), WithReader(tt.reader)).Meter("TestHistogramBucketPrecedenceOrdering")
 | 
			
		||||
			meter := NewMeterProvider(
 | 
			
		||||
				WithView(tt.views...),
 | 
			
		||||
				WithReader(tt.reader),
 | 
			
		||||
			).Meter("TestHistogramBucketPrecedenceOrdering")
 | 
			
		||||
			sfHistogram, err := meter.Float64Histogram("sync.float64.histogram", tt.histogramOpts...)
 | 
			
		||||
			require.NoError(t, err)
 | 
			
		||||
			sfHistogram.Record(context.Background(), 1)
 | 
			
		||||
| 
						 | 
				
			
			@ -2508,7 +2536,15 @@ func TestDuplicateInstrumentCreation(t *testing.T) {
 | 
			
		|||
			internalMeter, ok := m.(*meter)
 | 
			
		||||
			require.True(t, ok)
 | 
			
		||||
			// check that multiple calls to create the same instrument only create 1 instrument
 | 
			
		||||
			numInstruments := len(internalMeter.int64Insts.data) + len(internalMeter.float64Insts.data) + len(internalMeter.int64ObservableInsts.data) + len(internalMeter.float64ObservableInsts.data)
 | 
			
		||||
			numInstruments := len(
 | 
			
		||||
				internalMeter.int64Insts.data,
 | 
			
		||||
			) + len(
 | 
			
		||||
				internalMeter.float64Insts.data,
 | 
			
		||||
			) + len(
 | 
			
		||||
				internalMeter.int64ObservableInsts.data,
 | 
			
		||||
			) + len(
 | 
			
		||||
				internalMeter.float64ObservableInsts.data,
 | 
			
		||||
			)
 | 
			
		||||
			require.Equal(t, 1, numInstruments)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -680,18 +680,44 @@ func TestAssertEqual(t *testing.T) {
 | 
			
		|||
	t.Run("SumFloat64", testDatatype(sumFloat64A, sumFloat64B, equalSums[float64]))
 | 
			
		||||
	t.Run("GaugeInt64", testDatatype(gaugeInt64A, gaugeInt64B, equalGauges[int64]))
 | 
			
		||||
	t.Run("GaugeFloat64", testDatatype(gaugeFloat64A, gaugeFloat64B, equalGauges[float64]))
 | 
			
		||||
	t.Run("HistogramDataPointInt64", testDatatype(histogramDataPointInt64A, histogramDataPointInt64B, equalHistogramDataPoints[int64]))
 | 
			
		||||
	t.Run("HistogramDataPointFloat64", testDatatype(histogramDataPointFloat64A, histogramDataPointFloat64B, equalHistogramDataPoints[float64]))
 | 
			
		||||
	t.Run(
 | 
			
		||||
		"HistogramDataPointInt64",
 | 
			
		||||
		testDatatype(histogramDataPointInt64A, histogramDataPointInt64B, equalHistogramDataPoints[int64]),
 | 
			
		||||
	)
 | 
			
		||||
	t.Run(
 | 
			
		||||
		"HistogramDataPointFloat64",
 | 
			
		||||
		testDatatype(histogramDataPointFloat64A, histogramDataPointFloat64B, equalHistogramDataPoints[float64]),
 | 
			
		||||
	)
 | 
			
		||||
	t.Run("DataPointInt64", testDatatype(dataPointInt64A, dataPointInt64B, equalDataPoints[int64]))
 | 
			
		||||
	t.Run("DataPointFloat64", testDatatype(dataPointFloat64A, dataPointFloat64B, equalDataPoints[float64]))
 | 
			
		||||
	t.Run("ExtremaInt64", testDatatype(minInt64A, minInt64B, equalExtrema[int64]))
 | 
			
		||||
	t.Run("ExtremaFloat64", testDatatype(minFloat64A, minFloat64B, equalExtrema[float64]))
 | 
			
		||||
	t.Run("ExemplarInt64", testDatatype(exemplarInt64A, exemplarInt64B, equalExemplars[int64]))
 | 
			
		||||
	t.Run("ExemplarFloat64", testDatatype(exemplarFloat64A, exemplarFloat64B, equalExemplars[float64]))
 | 
			
		||||
	t.Run("ExponentialHistogramInt64", testDatatype(exponentialHistogramInt64A, exponentialHistogramInt64B, equalExponentialHistograms[int64]))
 | 
			
		||||
	t.Run("ExponentialHistogramFloat64", testDatatype(exponentialHistogramFloat64A, exponentialHistogramFloat64B, equalExponentialHistograms[float64]))
 | 
			
		||||
	t.Run("ExponentialHistogramDataPointInt64", testDatatype(exponentialHistogramDataPointInt64A, exponentialHistogramDataPointInt64B, equalExponentialHistogramDataPoints[int64]))
 | 
			
		||||
	t.Run("ExponentialHistogramDataPointFloat64", testDatatype(exponentialHistogramDataPointFloat64A, exponentialHistogramDataPointFloat64B, equalExponentialHistogramDataPoints[float64]))
 | 
			
		||||
	t.Run(
 | 
			
		||||
		"ExponentialHistogramInt64",
 | 
			
		||||
		testDatatype(exponentialHistogramInt64A, exponentialHistogramInt64B, equalExponentialHistograms[int64]),
 | 
			
		||||
	)
 | 
			
		||||
	t.Run(
 | 
			
		||||
		"ExponentialHistogramFloat64",
 | 
			
		||||
		testDatatype(exponentialHistogramFloat64A, exponentialHistogramFloat64B, equalExponentialHistograms[float64]),
 | 
			
		||||
	)
 | 
			
		||||
	t.Run(
 | 
			
		||||
		"ExponentialHistogramDataPointInt64",
 | 
			
		||||
		testDatatype(
 | 
			
		||||
			exponentialHistogramDataPointInt64A,
 | 
			
		||||
			exponentialHistogramDataPointInt64B,
 | 
			
		||||
			equalExponentialHistogramDataPoints[int64],
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
	t.Run(
 | 
			
		||||
		"ExponentialHistogramDataPointFloat64",
 | 
			
		||||
		testDatatype(
 | 
			
		||||
			exponentialHistogramDataPointFloat64A,
 | 
			
		||||
			exponentialHistogramDataPointFloat64B,
 | 
			
		||||
			equalExponentialHistogramDataPoints[float64],
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
	t.Run("ExponentialBuckets", testDatatype(exponentialBucket2, exponentialBucket3, equalExponentialBuckets))
 | 
			
		||||
	t.Run("Summary", testDatatype(summaryA, summaryB, equalSummary))
 | 
			
		||||
	t.Run("SummaryDataPoint", testDatatype(summaryDataPointA, summaryDataPointB, equalSummaryDataPoint))
 | 
			
		||||
| 
						 | 
				
			
			@ -708,18 +734,56 @@ func TestAssertEqualIgnoreTime(t *testing.T) {
 | 
			
		|||
	t.Run("SumFloat64", testDatatypeIgnoreTime(sumFloat64A, sumFloat64C, equalSums[float64]))
 | 
			
		||||
	t.Run("GaugeInt64", testDatatypeIgnoreTime(gaugeInt64A, gaugeInt64C, equalGauges[int64]))
 | 
			
		||||
	t.Run("GaugeFloat64", testDatatypeIgnoreTime(gaugeFloat64A, gaugeFloat64C, equalGauges[float64]))
 | 
			
		||||
	t.Run("HistogramDataPointInt64", testDatatypeIgnoreTime(histogramDataPointInt64A, histogramDataPointInt64C, equalHistogramDataPoints[int64]))
 | 
			
		||||
	t.Run("HistogramDataPointFloat64", testDatatypeIgnoreTime(histogramDataPointFloat64A, histogramDataPointFloat64C, equalHistogramDataPoints[float64]))
 | 
			
		||||
	t.Run(
 | 
			
		||||
		"HistogramDataPointInt64",
 | 
			
		||||
		testDatatypeIgnoreTime(histogramDataPointInt64A, histogramDataPointInt64C, equalHistogramDataPoints[int64]),
 | 
			
		||||
	)
 | 
			
		||||
	t.Run(
 | 
			
		||||
		"HistogramDataPointFloat64",
 | 
			
		||||
		testDatatypeIgnoreTime(
 | 
			
		||||
			histogramDataPointFloat64A,
 | 
			
		||||
			histogramDataPointFloat64C,
 | 
			
		||||
			equalHistogramDataPoints[float64],
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
	t.Run("DataPointInt64", testDatatypeIgnoreTime(dataPointInt64A, dataPointInt64C, equalDataPoints[int64]))
 | 
			
		||||
	t.Run("DataPointFloat64", testDatatypeIgnoreTime(dataPointFloat64A, dataPointFloat64C, equalDataPoints[float64]))
 | 
			
		||||
	t.Run("ExtremaInt64", testDatatypeIgnoreTime(minInt64A, minInt64C, equalExtrema[int64]))
 | 
			
		||||
	t.Run("ExtremaFloat64", testDatatypeIgnoreTime(minFloat64A, minFloat64C, equalExtrema[float64]))
 | 
			
		||||
	t.Run("ExemplarInt64", testDatatypeIgnoreTime(exemplarInt64A, exemplarInt64C, equalExemplars[int64]))
 | 
			
		||||
	t.Run("ExemplarFloat64", testDatatypeIgnoreTime(exemplarFloat64A, exemplarFloat64C, equalExemplars[float64]))
 | 
			
		||||
	t.Run("ExponentialHistogramInt64", testDatatypeIgnoreTime(exponentialHistogramInt64A, exponentialHistogramInt64C, equalExponentialHistograms[int64]))
 | 
			
		||||
	t.Run("ExponentialHistogramFloat64", testDatatypeIgnoreTime(exponentialHistogramFloat64A, exponentialHistogramFloat64C, equalExponentialHistograms[float64]))
 | 
			
		||||
	t.Run("ExponentialHistogramDataPointInt64", testDatatypeIgnoreTime(exponentialHistogramDataPointInt64A, exponentialHistogramDataPointInt64C, equalExponentialHistogramDataPoints[int64]))
 | 
			
		||||
	t.Run("ExponentialHistogramDataPointFloat64", testDatatypeIgnoreTime(exponentialHistogramDataPointFloat64A, exponentialHistogramDataPointFloat64C, equalExponentialHistogramDataPoints[float64]))
 | 
			
		||||
	t.Run(
 | 
			
		||||
		"ExponentialHistogramInt64",
 | 
			
		||||
		testDatatypeIgnoreTime(
 | 
			
		||||
			exponentialHistogramInt64A,
 | 
			
		||||
			exponentialHistogramInt64C,
 | 
			
		||||
			equalExponentialHistograms[int64],
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
	t.Run(
 | 
			
		||||
		"ExponentialHistogramFloat64",
 | 
			
		||||
		testDatatypeIgnoreTime(
 | 
			
		||||
			exponentialHistogramFloat64A,
 | 
			
		||||
			exponentialHistogramFloat64C,
 | 
			
		||||
			equalExponentialHistograms[float64],
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
	t.Run(
 | 
			
		||||
		"ExponentialHistogramDataPointInt64",
 | 
			
		||||
		testDatatypeIgnoreTime(
 | 
			
		||||
			exponentialHistogramDataPointInt64A,
 | 
			
		||||
			exponentialHistogramDataPointInt64C,
 | 
			
		||||
			equalExponentialHistogramDataPoints[int64],
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
	t.Run(
 | 
			
		||||
		"ExponentialHistogramDataPointFloat64",
 | 
			
		||||
		testDatatypeIgnoreTime(
 | 
			
		||||
			exponentialHistogramDataPointFloat64A,
 | 
			
		||||
			exponentialHistogramDataPointFloat64C,
 | 
			
		||||
			equalExponentialHistogramDataPoints[float64],
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
	t.Run("Summary", testDatatypeIgnoreTime(summaryA, summaryC, equalSummary))
 | 
			
		||||
	t.Run("SummaryDataPoint", testDatatypeIgnoreTime(summaryDataPointA, summaryDataPointC, equalSummaryDataPoint))
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -727,11 +791,17 @@ func TestAssertEqualIgnoreTime(t *testing.T) {
 | 
			
		|||
func TestAssertEqualIgnoreExemplars(t *testing.T) {
 | 
			
		||||
	hdpInt64 := histogramDataPointInt64A
 | 
			
		||||
	hdpInt64.Exemplars = []metricdata.Exemplar[int64]{exemplarInt64B}
 | 
			
		||||
	t.Run("HistogramDataPointInt64", testDatatypeIgnoreExemplars(histogramDataPointInt64A, hdpInt64, equalHistogramDataPoints[int64]))
 | 
			
		||||
	t.Run(
 | 
			
		||||
		"HistogramDataPointInt64",
 | 
			
		||||
		testDatatypeIgnoreExemplars(histogramDataPointInt64A, hdpInt64, equalHistogramDataPoints[int64]),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	hdpFloat64 := histogramDataPointFloat64A
 | 
			
		||||
	hdpFloat64.Exemplars = []metricdata.Exemplar[float64]{exemplarFloat64B}
 | 
			
		||||
	t.Run("HistogramDataPointFloat64", testDatatypeIgnoreExemplars(histogramDataPointFloat64A, hdpFloat64, equalHistogramDataPoints[float64]))
 | 
			
		||||
	t.Run(
 | 
			
		||||
		"HistogramDataPointFloat64",
 | 
			
		||||
		testDatatypeIgnoreExemplars(histogramDataPointFloat64A, hdpFloat64, equalHistogramDataPoints[float64]),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	dpInt64 := dataPointInt64A
 | 
			
		||||
	dpInt64.Exemplars = []metricdata.Exemplar[int64]{exemplarInt64B}
 | 
			
		||||
| 
						 | 
				
			
			@ -743,11 +813,25 @@ func TestAssertEqualIgnoreExemplars(t *testing.T) {
 | 
			
		|||
 | 
			
		||||
	ehdpInt64 := exponentialHistogramDataPointInt64A
 | 
			
		||||
	ehdpInt64.Exemplars = []metricdata.Exemplar[int64]{exemplarInt64B}
 | 
			
		||||
	t.Run("ExponentialHistogramDataPointInt64", testDatatypeIgnoreExemplars(exponentialHistogramDataPointInt64A, ehdpInt64, equalExponentialHistogramDataPoints[int64]))
 | 
			
		||||
	t.Run(
 | 
			
		||||
		"ExponentialHistogramDataPointInt64",
 | 
			
		||||
		testDatatypeIgnoreExemplars(
 | 
			
		||||
			exponentialHistogramDataPointInt64A,
 | 
			
		||||
			ehdpInt64,
 | 
			
		||||
			equalExponentialHistogramDataPoints[int64],
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	ehdpFloat64 := exponentialHistogramDataPointFloat64A
 | 
			
		||||
	ehdpFloat64.Exemplars = []metricdata.Exemplar[float64]{exemplarFloat64B}
 | 
			
		||||
	t.Run("ExponentialHistogramDataPointFloat64", testDatatypeIgnoreExemplars(exponentialHistogramDataPointFloat64A, ehdpFloat64, equalExponentialHistogramDataPoints[float64]))
 | 
			
		||||
	t.Run(
 | 
			
		||||
		"ExponentialHistogramDataPointFloat64",
 | 
			
		||||
		testDatatypeIgnoreExemplars(
 | 
			
		||||
			exponentialHistogramDataPointFloat64A,
 | 
			
		||||
			ehdpFloat64,
 | 
			
		||||
			equalExponentialHistogramDataPoints[float64],
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAssertEqualIgnoreValue(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -760,16 +844,54 @@ func TestAssertEqualIgnoreValue(t *testing.T) {
 | 
			
		|||
	t.Run("SumFloat64", testDatatypeIgnoreValue(sumFloat64A, sumFloat64D, equalSums[float64]))
 | 
			
		||||
	t.Run("GaugeInt64", testDatatypeIgnoreValue(gaugeInt64A, gaugeInt64D, equalGauges[int64]))
 | 
			
		||||
	t.Run("GaugeFloat64", testDatatypeIgnoreValue(gaugeFloat64A, gaugeFloat64D, equalGauges[float64]))
 | 
			
		||||
	t.Run("HistogramDataPointInt64", testDatatypeIgnoreValue(histogramDataPointInt64A, histogramDataPointInt64D, equalHistogramDataPoints[int64]))
 | 
			
		||||
	t.Run("HistogramDataPointFloat64", testDatatypeIgnoreValue(histogramDataPointFloat64A, histogramDataPointFloat64D, equalHistogramDataPoints[float64]))
 | 
			
		||||
	t.Run(
 | 
			
		||||
		"HistogramDataPointInt64",
 | 
			
		||||
		testDatatypeIgnoreValue(histogramDataPointInt64A, histogramDataPointInt64D, equalHistogramDataPoints[int64]),
 | 
			
		||||
	)
 | 
			
		||||
	t.Run(
 | 
			
		||||
		"HistogramDataPointFloat64",
 | 
			
		||||
		testDatatypeIgnoreValue(
 | 
			
		||||
			histogramDataPointFloat64A,
 | 
			
		||||
			histogramDataPointFloat64D,
 | 
			
		||||
			equalHistogramDataPoints[float64],
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
	t.Run("DataPointInt64", testDatatypeIgnoreValue(dataPointInt64A, dataPointInt64D, equalDataPoints[int64]))
 | 
			
		||||
	t.Run("DataPointFloat64", testDatatypeIgnoreValue(dataPointFloat64A, dataPointFloat64D, equalDataPoints[float64]))
 | 
			
		||||
	t.Run("ExemplarInt64", testDatatypeIgnoreValue(exemplarInt64A, exemplarInt64D, equalExemplars[int64]))
 | 
			
		||||
	t.Run("ExemplarFloat64", testDatatypeIgnoreValue(exemplarFloat64A, exemplarFloat64D, equalExemplars[float64]))
 | 
			
		||||
	t.Run("ExponentialHistogramInt64", testDatatypeIgnoreValue(exponentialHistogramInt64A, exponentialHistogramInt64D, equalExponentialHistograms[int64]))
 | 
			
		||||
	t.Run("ExponentialHistogramFloat64", testDatatypeIgnoreValue(exponentialHistogramFloat64A, exponentialHistogramFloat64D, equalExponentialHistograms[float64]))
 | 
			
		||||
	t.Run("ExponentialHistogramDataPointInt64", testDatatypeIgnoreValue(exponentialHistogramDataPointInt64A, exponentialHistogramDataPointInt64D, equalExponentialHistogramDataPoints[int64]))
 | 
			
		||||
	t.Run("ExponentialHistogramDataPointFloat64", testDatatypeIgnoreValue(exponentialHistogramDataPointFloat64A, exponentialHistogramDataPointFloat64D, equalExponentialHistogramDataPoints[float64]))
 | 
			
		||||
	t.Run(
 | 
			
		||||
		"ExponentialHistogramInt64",
 | 
			
		||||
		testDatatypeIgnoreValue(
 | 
			
		||||
			exponentialHistogramInt64A,
 | 
			
		||||
			exponentialHistogramInt64D,
 | 
			
		||||
			equalExponentialHistograms[int64],
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
	t.Run(
 | 
			
		||||
		"ExponentialHistogramFloat64",
 | 
			
		||||
		testDatatypeIgnoreValue(
 | 
			
		||||
			exponentialHistogramFloat64A,
 | 
			
		||||
			exponentialHistogramFloat64D,
 | 
			
		||||
			equalExponentialHistograms[float64],
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
	t.Run(
 | 
			
		||||
		"ExponentialHistogramDataPointInt64",
 | 
			
		||||
		testDatatypeIgnoreValue(
 | 
			
		||||
			exponentialHistogramDataPointInt64A,
 | 
			
		||||
			exponentialHistogramDataPointInt64D,
 | 
			
		||||
			equalExponentialHistogramDataPoints[int64],
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
	t.Run(
 | 
			
		||||
		"ExponentialHistogramDataPointFloat64",
 | 
			
		||||
		testDatatypeIgnoreValue(
 | 
			
		||||
			exponentialHistogramDataPointFloat64A,
 | 
			
		||||
			exponentialHistogramDataPointFloat64D,
 | 
			
		||||
			equalExponentialHistogramDataPoints[float64],
 | 
			
		||||
		),
 | 
			
		||||
	)
 | 
			
		||||
	t.Run("Summary", testDatatypeIgnoreValue(summaryA, summaryD, equalSummary))
 | 
			
		||||
	t.Run("SummaryDataPoint", testDatatypeIgnoreValue(summaryDataPointA, summaryDataPointD, equalSummaryDataPoint))
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -854,7 +976,13 @@ func TestAssertAggregationsEqual(t *testing.T) {
 | 
			
		|||
	assert.Empty(t, r, "value should be ignored: %v == %v", histogramFloat64A, histogramFloat64D)
 | 
			
		||||
 | 
			
		||||
	r = equalAggregations(exponentialHistogramInt64A, exponentialHistogramInt64B, config{})
 | 
			
		||||
	assert.NotEmptyf(t, r, "exponential histograms should not be equal: %v == %v", exponentialHistogramInt64A, exponentialHistogramInt64B)
 | 
			
		||||
	assert.NotEmptyf(
 | 
			
		||||
		t,
 | 
			
		||||
		r,
 | 
			
		||||
		"exponential histograms should not be equal: %v == %v",
 | 
			
		||||
		exponentialHistogramInt64A,
 | 
			
		||||
		exponentialHistogramInt64B,
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	r = equalAggregations(exponentialHistogramInt64A, exponentialHistogramInt64C, config{ignoreTimestamp: true})
 | 
			
		||||
	assert.Empty(t, r, "exponential histograms should be equal: %v", r)
 | 
			
		||||
| 
						 | 
				
			
			@ -863,7 +991,13 @@ func TestAssertAggregationsEqual(t *testing.T) {
 | 
			
		|||
	assert.Empty(t, r, "value should be ignored: %v == %v", exponentialHistogramInt64A, exponentialHistogramInt64D)
 | 
			
		||||
 | 
			
		||||
	r = equalAggregations(exponentialHistogramFloat64A, exponentialHistogramFloat64B, config{})
 | 
			
		||||
	assert.NotEmptyf(t, r, "exponential histograms should not be equal: %v == %v", exponentialHistogramFloat64A, exponentialHistogramFloat64B)
 | 
			
		||||
	assert.NotEmptyf(
 | 
			
		||||
		t,
 | 
			
		||||
		r,
 | 
			
		||||
		"exponential histograms should not be equal: %v == %v",
 | 
			
		||||
		exponentialHistogramFloat64A,
 | 
			
		||||
		exponentialHistogramFloat64B,
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	r = equalAggregations(exponentialHistogramFloat64A, exponentialHistogramFloat64C, config{ignoreTimestamp: true})
 | 
			
		||||
	assert.Empty(t, r, "exponential histograms should be equal: %v", r)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -230,7 +230,10 @@ func equalHistograms[N int64 | float64](a, b metricdata.Histogram[N], cfg config
 | 
			
		|||
 | 
			
		||||
// equalDataPoints returns reasons DataPoints are not equal. If they are
 | 
			
		||||
// equal, the returned reasons will be empty.
 | 
			
		||||
func equalDataPoints[N int64 | float64](a, b metricdata.DataPoint[N], cfg config) (reasons []string) { // nolint: revive // Intentional internal control flag
 | 
			
		||||
func equalDataPoints[N int64 | float64](
 | 
			
		||||
	a, b metricdata.DataPoint[N],
 | 
			
		||||
	cfg config,
 | 
			
		||||
) (reasons []string) { // nolint: revive // Intentional internal control flag
 | 
			
		||||
	if !a.Attributes.Equals(&b.Attributes) {
 | 
			
		||||
		reasons = append(reasons, notEqualStr(
 | 
			
		||||
			"Attributes",
 | 
			
		||||
| 
						 | 
				
			
			@ -272,7 +275,10 @@ func equalDataPoints[N int64 | float64](a, b metricdata.DataPoint[N], cfg config
 | 
			
		|||
 | 
			
		||||
// equalHistogramDataPoints returns reasons HistogramDataPoints are not equal.
 | 
			
		||||
// If they are equal, the returned reasons will be empty.
 | 
			
		||||
func equalHistogramDataPoints[N int64 | float64](a, b metricdata.HistogramDataPoint[N], cfg config) (reasons []string) { // nolint: revive // Intentional internal control flag
 | 
			
		||||
func equalHistogramDataPoints[N int64 | float64](
 | 
			
		||||
	a, b metricdata.HistogramDataPoint[N],
 | 
			
		||||
	cfg config,
 | 
			
		||||
) (reasons []string) { // nolint: revive // Intentional internal control flag
 | 
			
		||||
	if !a.Attributes.Equals(&b.Attributes) {
 | 
			
		||||
		reasons = append(reasons, notEqualStr(
 | 
			
		||||
			"Attributes",
 | 
			
		||||
| 
						 | 
				
			
			@ -329,7 +335,10 @@ func equalHistogramDataPoints[N int64 | float64](a, b metricdata.HistogramDataPo
 | 
			
		|||
//
 | 
			
		||||
// The DataPoints each Histogram contains are compared based on containing the
 | 
			
		||||
// same HistogramDataPoint, not the order they are stored in.
 | 
			
		||||
func equalExponentialHistograms[N int64 | float64](a, b metricdata.ExponentialHistogram[N], cfg config) (reasons []string) {
 | 
			
		||||
func equalExponentialHistograms[N int64 | float64](
 | 
			
		||||
	a, b metricdata.ExponentialHistogram[N],
 | 
			
		||||
	cfg config,
 | 
			
		||||
) (reasons []string) {
 | 
			
		||||
	if a.Temporality != b.Temporality {
 | 
			
		||||
		reasons = append(reasons, notEqualStr("Temporality", a.Temporality, b.Temporality))
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -350,7 +359,10 @@ func equalExponentialHistograms[N int64 | float64](a, b metricdata.ExponentialHi
 | 
			
		|||
 | 
			
		||||
// equalExponentialHistogramDataPoints returns reasons HistogramDataPoints are not equal.
 | 
			
		||||
// If they are equal, the returned reasons will be empty.
 | 
			
		||||
func equalExponentialHistogramDataPoints[N int64 | float64](a, b metricdata.ExponentialHistogramDataPoint[N], cfg config) (reasons []string) { // nolint: revive // Intentional internal control flag
 | 
			
		||||
func equalExponentialHistogramDataPoints[N int64 | float64](
 | 
			
		||||
	a, b metricdata.ExponentialHistogramDataPoint[N],
 | 
			
		||||
	cfg config,
 | 
			
		||||
) (reasons []string) { // nolint: revive // Intentional internal control flag
 | 
			
		||||
	if !a.Attributes.Equals(&b.Attributes) {
 | 
			
		||||
		reasons = append(reasons, notEqualStr(
 | 
			
		||||
			"Attributes",
 | 
			
		||||
| 
						 | 
				
			
			@ -637,7 +649,10 @@ func missingAttrStr(name string) string {
 | 
			
		|||
	return "missing attribute " + name
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func hasAttributesExemplars[T int64 | float64](exemplar metricdata.Exemplar[T], attrs ...attribute.KeyValue) (reasons []string) {
 | 
			
		||||
func hasAttributesExemplars[T int64 | float64](
 | 
			
		||||
	exemplar metricdata.Exemplar[T],
 | 
			
		||||
	attrs ...attribute.KeyValue,
 | 
			
		||||
) (reasons []string) {
 | 
			
		||||
	s := attribute.NewSet(exemplar.FilteredAttributes...)
 | 
			
		||||
	for _, attr := range attrs {
 | 
			
		||||
		val, ok := s.Value(attr.Key)
 | 
			
		||||
| 
						 | 
				
			
			@ -652,7 +667,10 @@ func hasAttributesExemplars[T int64 | float64](exemplar metricdata.Exemplar[T],
 | 
			
		|||
	return reasons
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func hasAttributesDataPoints[T int64 | float64](dp metricdata.DataPoint[T], attrs ...attribute.KeyValue) (reasons []string) {
 | 
			
		||||
func hasAttributesDataPoints[T int64 | float64](
 | 
			
		||||
	dp metricdata.DataPoint[T],
 | 
			
		||||
	attrs ...attribute.KeyValue,
 | 
			
		||||
) (reasons []string) {
 | 
			
		||||
	for _, attr := range attrs {
 | 
			
		||||
		val, ok := dp.Attributes.Value(attr.Key)
 | 
			
		||||
		if !ok {
 | 
			
		||||
| 
						 | 
				
			
			@ -688,7 +706,10 @@ func hasAttributesSum[T int64 | float64](sum metricdata.Sum[T], attrs ...attribu
 | 
			
		|||
	return reasons
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func hasAttributesHistogramDataPoints[T int64 | float64](dp metricdata.HistogramDataPoint[T], attrs ...attribute.KeyValue) (reasons []string) {
 | 
			
		||||
func hasAttributesHistogramDataPoints[T int64 | float64](
 | 
			
		||||
	dp metricdata.HistogramDataPoint[T],
 | 
			
		||||
	attrs ...attribute.KeyValue,
 | 
			
		||||
) (reasons []string) {
 | 
			
		||||
	for _, attr := range attrs {
 | 
			
		||||
		val, ok := dp.Attributes.Value(attr.Key)
 | 
			
		||||
		if !ok {
 | 
			
		||||
| 
						 | 
				
			
			@ -702,7 +723,10 @@ func hasAttributesHistogramDataPoints[T int64 | float64](dp metricdata.Histogram
 | 
			
		|||
	return reasons
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func hasAttributesHistogram[T int64 | float64](histogram metricdata.Histogram[T], attrs ...attribute.KeyValue) (reasons []string) {
 | 
			
		||||
func hasAttributesHistogram[T int64 | float64](
 | 
			
		||||
	histogram metricdata.Histogram[T],
 | 
			
		||||
	attrs ...attribute.KeyValue,
 | 
			
		||||
) (reasons []string) {
 | 
			
		||||
	for n, dp := range histogram.DataPoints {
 | 
			
		||||
		reas := hasAttributesHistogramDataPoints(dp, attrs...)
 | 
			
		||||
		if len(reas) > 0 {
 | 
			
		||||
| 
						 | 
				
			
			@ -713,7 +737,10 @@ func hasAttributesHistogram[T int64 | float64](histogram metricdata.Histogram[T]
 | 
			
		|||
	return reasons
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func hasAttributesExponentialHistogramDataPoints[T int64 | float64](dp metricdata.ExponentialHistogramDataPoint[T], attrs ...attribute.KeyValue) (reasons []string) {
 | 
			
		||||
func hasAttributesExponentialHistogramDataPoints[T int64 | float64](
 | 
			
		||||
	dp metricdata.ExponentialHistogramDataPoint[T],
 | 
			
		||||
	attrs ...attribute.KeyValue,
 | 
			
		||||
) (reasons []string) {
 | 
			
		||||
	for _, attr := range attrs {
 | 
			
		||||
		val, ok := dp.Attributes.Value(attr.Key)
 | 
			
		||||
		if !ok {
 | 
			
		||||
| 
						 | 
				
			
			@ -727,7 +754,10 @@ func hasAttributesExponentialHistogramDataPoints[T int64 | float64](dp metricdat
 | 
			
		|||
	return reasons
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func hasAttributesExponentialHistogram[T int64 | float64](histogram metricdata.ExponentialHistogram[T], attrs ...attribute.KeyValue) (reasons []string) {
 | 
			
		||||
func hasAttributesExponentialHistogram[T int64 | float64](
 | 
			
		||||
	histogram metricdata.ExponentialHistogram[T],
 | 
			
		||||
	attrs ...attribute.KeyValue,
 | 
			
		||||
) (reasons []string) {
 | 
			
		||||
	for n, dp := range histogram.DataPoints {
 | 
			
		||||
		reas := hasAttributesExponentialHistogramDataPoints(dp, attrs...)
 | 
			
		||||
		if len(reas) > 0 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -193,7 +193,9 @@ func (r *PeriodicReader) temporality(kind InstrumentKind) metricdata.Temporality
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// aggregation returns what Aggregation to use for kind.
 | 
			
		||||
func (r *PeriodicReader) aggregation(kind InstrumentKind) Aggregation { // nolint:revive  // import-shadow for method scoped by type.
 | 
			
		||||
func (r *PeriodicReader) aggregation(
 | 
			
		||||
	kind InstrumentKind,
 | 
			
		||||
) Aggregation { // nolint:revive  // import-shadow for method scoped by type.
 | 
			
		||||
	return r.exporter.Aggregation(kind)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -347,7 +347,12 @@ func (i *inserter[N]) readerDefaultAggregation(kind InstrumentKind) Aggregation
 | 
			
		|||
//
 | 
			
		||||
// If the instrument defines an unknown or incompatible aggregation, an error
 | 
			
		||||
// is returned.
 | 
			
		||||
func (i *inserter[N]) cachedAggregator(scope instrumentation.Scope, kind InstrumentKind, stream Stream, readerAggregation Aggregation) (meas aggregate.Measure[N], aggID uint64, err error) {
 | 
			
		||||
func (i *inserter[N]) cachedAggregator(
 | 
			
		||||
	scope instrumentation.Scope,
 | 
			
		||||
	kind InstrumentKind,
 | 
			
		||||
	stream Stream,
 | 
			
		||||
	readerAggregation Aggregation,
 | 
			
		||||
) (meas aggregate.Measure[N], aggID uint64, err error) {
 | 
			
		||||
	switch stream.Aggregation.(type) {
 | 
			
		||||
	case nil:
 | 
			
		||||
		// The aggregation was not overridden with a view. Use the aggregation
 | 
			
		||||
| 
						 | 
				
			
			@ -380,7 +385,10 @@ func (i *inserter[N]) cachedAggregator(scope instrumentation.Scope, kind Instrum
 | 
			
		|||
	cv := i.aggregators.Lookup(normID, func() aggVal[N] {
 | 
			
		||||
		b := aggregate.Builder[N]{
 | 
			
		||||
			Temporality: i.pipeline.reader.temporality(kind),
 | 
			
		||||
			ReservoirFunc: reservoirFunc[N](stream.ExemplarReservoirProviderSelector(stream.Aggregation), i.pipeline.exemplarFilter),
 | 
			
		||||
			ReservoirFunc: reservoirFunc[N](
 | 
			
		||||
				stream.ExemplarReservoirProviderSelector(stream.Aggregation),
 | 
			
		||||
				i.pipeline.exemplarFilter,
 | 
			
		||||
			),
 | 
			
		||||
		}
 | 
			
		||||
		b.Filter = stream.AttributeFilter
 | 
			
		||||
		// A value less than or equal to zero will disable the aggregation
 | 
			
		||||
| 
						 | 
				
			
			@ -471,7 +479,11 @@ func (i *inserter[N]) instID(kind InstrumentKind, stream Stream) instID {
 | 
			
		|||
// aggregateFunc returns new aggregate functions matching agg, kind, and
 | 
			
		||||
// monotonic. If the agg is unknown or temporality is invalid, an error is
 | 
			
		||||
// returned.
 | 
			
		||||
func (i *inserter[N]) aggregateFunc(b aggregate.Builder[N], agg Aggregation, kind InstrumentKind) (meas aggregate.Measure[N], comp aggregate.ComputeAggregation, err error) {
 | 
			
		||||
func (i *inserter[N]) aggregateFunc(
 | 
			
		||||
	b aggregate.Builder[N],
 | 
			
		||||
	agg Aggregation,
 | 
			
		||||
	kind InstrumentKind,
 | 
			
		||||
) (meas aggregate.Measure[N], comp aggregate.ComputeAggregation, err error) {
 | 
			
		||||
	switch a := agg.(type) {
 | 
			
		||||
	case AggregationDefault:
 | 
			
		||||
		return i.aggregateFunc(b, DefaultAggregationSelector(kind), kind)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,14 +34,25 @@ func (invalidAggregation) err() error {
 | 
			
		|||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func requireN[N int64 | float64](t *testing.T, n int, m []aggregate.Measure[N], comps []aggregate.ComputeAggregation, err error) {
 | 
			
		||||
func requireN[N int64 | float64](
 | 
			
		||||
	t *testing.T,
 | 
			
		||||
	n int,
 | 
			
		||||
	m []aggregate.Measure[N],
 | 
			
		||||
	comps []aggregate.ComputeAggregation,
 | 
			
		||||
	err error,
 | 
			
		||||
) {
 | 
			
		||||
	t.Helper()
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	require.Len(t, m, n)
 | 
			
		||||
	require.Len(t, comps, n)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func assertSum[N int64 | float64](n int, temp metricdata.Temporality, mono bool, v [2]N) func(*testing.T, []aggregate.Measure[N], []aggregate.ComputeAggregation, error) {
 | 
			
		||||
func assertSum[N int64 | float64](
 | 
			
		||||
	n int,
 | 
			
		||||
	temp metricdata.Temporality,
 | 
			
		||||
	mono bool,
 | 
			
		||||
	v [2]N,
 | 
			
		||||
) func(*testing.T, []aggregate.Measure[N], []aggregate.ComputeAggregation, error) {
 | 
			
		||||
	return func(t *testing.T, meas []aggregate.Measure[N], comps []aggregate.ComputeAggregation, err error) {
 | 
			
		||||
		t.Helper()
 | 
			
		||||
		requireN[N](t, n, meas, comps, err)
 | 
			
		||||
| 
						 | 
				
			
			@ -71,7 +82,9 @@ func assertSum[N int64 | float64](n int, temp metricdata.Temporality, mono bool,
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func assertHist[N int64 | float64](temp metricdata.Temporality) func(*testing.T, []aggregate.Measure[N], []aggregate.ComputeAggregation, error) {
 | 
			
		||||
func assertHist[N int64 | float64](
 | 
			
		||||
	temp metricdata.Temporality,
 | 
			
		||||
) func(*testing.T, []aggregate.Measure[N], []aggregate.ComputeAggregation, error) {
 | 
			
		||||
	return func(t *testing.T, meas []aggregate.Measure[N], comps []aggregate.ComputeAggregation, err error) {
 | 
			
		||||
		t.Helper()
 | 
			
		||||
		requireN[N](t, 1, meas, comps, err)
 | 
			
		||||
| 
						 | 
				
			
			@ -116,7 +129,12 @@ func assertHist[N int64 | float64](temp metricdata.Temporality) func(*testing.T,
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func assertLastValue[N int64 | float64](t *testing.T, meas []aggregate.Measure[N], comps []aggregate.ComputeAggregation, err error) {
 | 
			
		||||
func assertLastValue[N int64 | float64](
 | 
			
		||||
	t *testing.T,
 | 
			
		||||
	meas []aggregate.Measure[N],
 | 
			
		||||
	comps []aggregate.ComputeAggregation,
 | 
			
		||||
	err error,
 | 
			
		||||
) {
 | 
			
		||||
	t.Helper()
 | 
			
		||||
	requireN[N](t, 1, meas, comps, err)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -165,7 +183,9 @@ func testCreateAggregators[N int64 | float64](t *testing.T) {
 | 
			
		|||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			name: "Default/Drop",
 | 
			
		||||
			reader: NewManualReader(WithAggregationSelector(func(ik InstrumentKind) Aggregation { return AggregationDrop{} })),
 | 
			
		||||
			reader: NewManualReader(
 | 
			
		||||
				WithAggregationSelector(func(ik InstrumentKind) Aggregation { return AggregationDrop{} }),
 | 
			
		||||
			),
 | 
			
		||||
			inst: instruments[InstrumentKindCounter],
 | 
			
		||||
			validate: func(t *testing.T, meas []aggregate.Measure[N], comps []aggregate.ComputeAggregation, err error) {
 | 
			
		||||
				t.Helper()
 | 
			
		||||
| 
						 | 
				
			
			@ -305,43 +325,57 @@ func testCreateAggregators[N int64 | float64](t *testing.T) {
 | 
			
		|||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "Reader/Default/Cumulative/Sum/Monotonic",
 | 
			
		||||
			reader:   NewManualReader(WithAggregationSelector(func(ik InstrumentKind) Aggregation { return AggregationDefault{} })),
 | 
			
		||||
			reader: NewManualReader(
 | 
			
		||||
				WithAggregationSelector(func(ik InstrumentKind) Aggregation { return AggregationDefault{} }),
 | 
			
		||||
			),
 | 
			
		||||
			inst:     instruments[InstrumentKindCounter],
 | 
			
		||||
			validate: assertSum[N](1, metricdata.CumulativeTemporality, true, [2]N{1, 4}),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "Reader/Default/Cumulative/Sum/NonMonotonic",
 | 
			
		||||
			reader:   NewManualReader(WithAggregationSelector(func(ik InstrumentKind) Aggregation { return AggregationDefault{} })),
 | 
			
		||||
			reader: NewManualReader(
 | 
			
		||||
				WithAggregationSelector(func(ik InstrumentKind) Aggregation { return AggregationDefault{} }),
 | 
			
		||||
			),
 | 
			
		||||
			inst:     instruments[InstrumentKindUpDownCounter],
 | 
			
		||||
			validate: assertSum[N](1, metricdata.CumulativeTemporality, false, [2]N{1, 4}),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "Reader/Default/Cumulative/ExplicitBucketHistogram",
 | 
			
		||||
			reader:   NewManualReader(WithAggregationSelector(func(ik InstrumentKind) Aggregation { return AggregationDefault{} })),
 | 
			
		||||
			reader: NewManualReader(
 | 
			
		||||
				WithAggregationSelector(func(ik InstrumentKind) Aggregation { return AggregationDefault{} }),
 | 
			
		||||
			),
 | 
			
		||||
			inst:     instruments[InstrumentKindHistogram],
 | 
			
		||||
			validate: assertHist[N](metricdata.CumulativeTemporality),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "Reader/Default/Cumulative/Gauge",
 | 
			
		||||
			reader:   NewManualReader(WithAggregationSelector(func(ik InstrumentKind) Aggregation { return AggregationDefault{} })),
 | 
			
		||||
			reader: NewManualReader(
 | 
			
		||||
				WithAggregationSelector(func(ik InstrumentKind) Aggregation { return AggregationDefault{} }),
 | 
			
		||||
			),
 | 
			
		||||
			inst:     instruments[InstrumentKindGauge],
 | 
			
		||||
			validate: assertLastValue[N],
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "Reader/Default/Cumulative/PrecomputedSum/Monotonic",
 | 
			
		||||
			reader:   NewManualReader(WithAggregationSelector(func(ik InstrumentKind) Aggregation { return AggregationDefault{} })),
 | 
			
		||||
			reader: NewManualReader(
 | 
			
		||||
				WithAggregationSelector(func(ik InstrumentKind) Aggregation { return AggregationDefault{} }),
 | 
			
		||||
			),
 | 
			
		||||
			inst:     instruments[InstrumentKindObservableCounter],
 | 
			
		||||
			validate: assertSum[N](1, metricdata.CumulativeTemporality, true, [2]N{1, 3}),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "Reader/Default/Cumulative/PrecomputedSum/NonMonotonic",
 | 
			
		||||
			reader:   NewManualReader(WithAggregationSelector(func(ik InstrumentKind) Aggregation { return AggregationDefault{} })),
 | 
			
		||||
			reader: NewManualReader(
 | 
			
		||||
				WithAggregationSelector(func(ik InstrumentKind) Aggregation { return AggregationDefault{} }),
 | 
			
		||||
			),
 | 
			
		||||
			inst:     instruments[InstrumentKindObservableUpDownCounter],
 | 
			
		||||
			validate: assertSum[N](1, metricdata.CumulativeTemporality, false, [2]N{1, 3}),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "Reader/Default/Gauge",
 | 
			
		||||
			reader:   NewManualReader(WithAggregationSelector(func(ik InstrumentKind) Aggregation { return AggregationDefault{} })),
 | 
			
		||||
			reader: NewManualReader(
 | 
			
		||||
				WithAggregationSelector(func(ik InstrumentKind) Aggregation { return AggregationDefault{} }),
 | 
			
		||||
			),
 | 
			
		||||
			inst:     instruments[InstrumentKindObservableGauge],
 | 
			
		||||
			validate: assertLastValue[N],
 | 
			
		||||
		},
 | 
			
		||||
| 
						 | 
				
			
			@ -418,7 +452,9 @@ func TestPipelinesAggregatorForEachReader(t *testing.T) {
 | 
			
		|||
func TestPipelineRegistryCreateAggregators(t *testing.T) {
 | 
			
		||||
	renameView := NewView(Instrument{Name: "foo"}, Stream{Name: "bar"})
 | 
			
		||||
	testRdr := NewManualReader()
 | 
			
		||||
	testRdrHistogram := NewManualReader(WithAggregationSelector(func(ik InstrumentKind) Aggregation { return AggregationExplicitBucketHistogram{} }))
 | 
			
		||||
	testRdrHistogram := NewManualReader(
 | 
			
		||||
		WithAggregationSelector(func(ik InstrumentKind) Aggregation { return AggregationExplicitBucketHistogram{} }),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	testCases := []struct {
 | 
			
		||||
		name      string
 | 
			
		||||
| 
						 | 
				
			
			@ -529,7 +565,9 @@ func TestPipelineRegistryResource(t *testing.T) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func TestPipelineRegistryCreateAggregatorsIncompatibleInstrument(t *testing.T) {
 | 
			
		||||
	testRdrHistogram := NewManualReader(WithAggregationSelector(func(ik InstrumentKind) Aggregation { return AggregationSum{} }))
 | 
			
		||||
	testRdrHistogram := NewManualReader(
 | 
			
		||||
		WithAggregationSelector(func(ik InstrumentKind) Aggregation { return AggregationSum{} }),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	readers := []Reader{testRdrHistogram}
 | 
			
		||||
	views := []View{defaultView}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -146,7 +146,10 @@ type AggregationSelector func(InstrumentKind) Aggregation
 | 
			
		|||
// Histogram ⇨ ExplicitBucketHistogram.
 | 
			
		||||
func DefaultAggregationSelector(ik InstrumentKind) Aggregation {
 | 
			
		||||
	switch ik {
 | 
			
		||||
	case InstrumentKindCounter, InstrumentKindUpDownCounter, InstrumentKindObservableCounter, InstrumentKindObservableUpDownCounter:
 | 
			
		||||
	case InstrumentKindCounter,
 | 
			
		||||
		InstrumentKindUpDownCounter,
 | 
			
		||||
		InstrumentKindObservableCounter,
 | 
			
		||||
		InstrumentKindObservableUpDownCounter:
 | 
			
		||||
		return AggregationSum{}
 | 
			
		||||
	case InstrumentKindObservableGauge, InstrumentKindGauge:
 | 
			
		||||
		return AggregationLastValue{}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -287,7 +287,14 @@ func benchReaderCollectFunc(r Reader) func(*testing.B) {
 | 
			
		|||
 | 
			
		||||
		for n := 0; n < b.N; n++ {
 | 
			
		||||
			err = r.Collect(ctx, &collectedMetrics)
 | 
			
		||||
			assert.Equalf(b, testResourceMetricsA, collectedMetrics, "unexpected Collect response: (%#v, %v)", collectedMetrics, err)
 | 
			
		||||
			assert.Equalf(
 | 
			
		||||
				b,
 | 
			
		||||
				testResourceMetricsA,
 | 
			
		||||
				collectedMetrics,
 | 
			
		||||
				"unexpected Collect response: (%#v, %v)",
 | 
			
		||||
				collectedMetrics,
 | 
			
		||||
				err,
 | 
			
		||||
			)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -69,11 +69,26 @@ func TestGetFirstAvailableFile(t *testing.T) {
 | 
			
		|||
	}{
 | 
			
		||||
		{"Gets first, skip second candidate", []string{filename1, filename2}, filename1, ""},
 | 
			
		||||
		{"Skips first, gets second candidate", []string{"does_not_exists", filename2}, filename2, ""},
 | 
			
		||||
		{"Skips first, gets second, ignores third candidate", []string{"does_not_exists", filename2, filename1}, filename2, ""},
 | 
			
		||||
		{
 | 
			
		||||
			"Skips first, gets second, ignores third candidate",
 | 
			
		||||
			[]string{"does_not_exists", filename2, filename1},
 | 
			
		||||
			filename2,
 | 
			
		||||
			"",
 | 
			
		||||
		},
 | 
			
		||||
		{"No candidates (empty slice)", []string{}, "", "no candidate file available: []"},
 | 
			
		||||
		{"No candidates (nil slice)", nil, "", "no candidate file available: []"},
 | 
			
		||||
		{"Single nonexisting candidate", []string{"does_not_exists"}, "", "no candidate file available: [does_not_exists]"},
 | 
			
		||||
		{"Multiple nonexisting candidates", []string{"does_not_exists", "this_either"}, "", "no candidate file available: [does_not_exists this_either]"},
 | 
			
		||||
		{
 | 
			
		||||
			"Single nonexisting candidate",
 | 
			
		||||
			[]string{"does_not_exists"},
 | 
			
		||||
			"",
 | 
			
		||||
			"no candidate file available: [does_not_exists]",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"Multiple nonexisting candidates",
 | 
			
		||||
			[]string{"does_not_exists", "this_either"},
 | 
			
		||||
			"",
 | 
			
		||||
			"no candidate file available: [does_not_exists this_either]",
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tc := range tt {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,7 +29,10 @@ func TestDefaultExperimental(t *testing.T) {
 | 
			
		|||
 | 
			
		||||
	serviceInstanceID, ok := res.Set().Value(semconv.ServiceInstanceIDKey)
 | 
			
		||||
	require.True(t, ok)
 | 
			
		||||
	matched, err := regexp.MatchString("^[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}$", serviceInstanceID.AsString())
 | 
			
		||||
	matched, err := regexp.MatchString(
 | 
			
		||||
		"^[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}$",
 | 
			
		||||
		serviceInstanceID.AsString(),
 | 
			
		||||
	)
 | 
			
		||||
	require.NoError(t, err)
 | 
			
		||||
	require.True(t, matched)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -409,7 +409,11 @@ func TestNew(t *testing.T) {
 | 
			
		|||
			options: []resource.Option{
 | 
			
		||||
				resource.WithDetectors(
 | 
			
		||||
					resource.StringDetector("https://opentelemetry.io/schemas/1.0.0", semconv.HostNameKey, os.Hostname),
 | 
			
		||||
					resource.StringDetector("https://opentelemetry.io/schemas/1.1.0", semconv.HostNameKey, func() (string, error) { return "", errors.New("fail") }),
 | 
			
		||||
					resource.StringDetector(
 | 
			
		||||
						"https://opentelemetry.io/schemas/1.1.0",
 | 
			
		||||
						semconv.HostNameKey,
 | 
			
		||||
						func() (string, error) { return "", errors.New("fail") },
 | 
			
		||||
					),
 | 
			
		||||
				),
 | 
			
		||||
				resource.WithSchemaURL("https://opentelemetry.io/schemas/1.2.0"),
 | 
			
		||||
			},
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -169,7 +169,17 @@ func (p *TracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.T
 | 
			
		|||
		//   slowing down all tracing consumers.
 | 
			
		||||
		// - Logging code may be instrumented with tracing and deadlock because it could try
 | 
			
		||||
		//   acquiring the same non-reentrant mutex.
 | 
			
		||||
		global.Info("Tracer created", "name", name, "version", is.Version, "schemaURL", is.SchemaURL, "attributes", is.Attributes)
 | 
			
		||||
		global.Info(
 | 
			
		||||
			"Tracer created",
 | 
			
		||||
			"name",
 | 
			
		||||
			name,
 | 
			
		||||
			"version",
 | 
			
		||||
			is.Version,
 | 
			
		||||
			"schemaURL",
 | 
			
		||||
			is.SchemaURL,
 | 
			
		||||
			"attributes",
 | 
			
		||||
			is.Attributes,
 | 
			
		||||
		)
 | 
			
		||||
	}
 | 
			
		||||
	return t
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -374,12 +374,26 @@ func testStoredError(t *testing.T, target interface{}) {
 | 
			
		|||
func TestTracerProviderReturnsSameTracer(t *testing.T) {
 | 
			
		||||
	p := NewTracerProvider()
 | 
			
		||||
 | 
			
		||||
	t0, t1, t2 := p.Tracer("t0"), p.Tracer("t1"), p.Tracer("t0", trace.WithInstrumentationAttributes(attribute.String("foo", "bar")))
 | 
			
		||||
	t0, t1, t2 := p.Tracer(
 | 
			
		||||
		"t0",
 | 
			
		||||
	), p.Tracer(
 | 
			
		||||
		"t1",
 | 
			
		||||
	), p.Tracer(
 | 
			
		||||
		"t0",
 | 
			
		||||
		trace.WithInstrumentationAttributes(attribute.String("foo", "bar")),
 | 
			
		||||
	)
 | 
			
		||||
	assert.NotSame(t, t0, t1)
 | 
			
		||||
	assert.NotSame(t, t0, t2)
 | 
			
		||||
	assert.NotSame(t, t1, t2)
 | 
			
		||||
 | 
			
		||||
	t3, t4, t5 := p.Tracer("t0"), p.Tracer("t1"), p.Tracer("t0", trace.WithInstrumentationAttributes(attribute.String("foo", "bar")))
 | 
			
		||||
	t3, t4, t5 := p.Tracer(
 | 
			
		||||
		"t0",
 | 
			
		||||
	), p.Tracer(
 | 
			
		||||
		"t1",
 | 
			
		||||
	), p.Tracer(
 | 
			
		||||
		"t0",
 | 
			
		||||
		trace.WithInstrumentationAttributes(attribute.String("foo", "bar")),
 | 
			
		||||
	)
 | 
			
		||||
	assert.Same(t, t0, t3)
 | 
			
		||||
	assert.Same(t, t1, t4)
 | 
			
		||||
	assert.Same(t, t2, t5)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -151,7 +151,10 @@ func (ts *testSampler) ShouldSample(p SamplingParameters) SamplingResult {
 | 
			
		|||
	if strings.HasPrefix(p.Name, ts.prefix) {
 | 
			
		||||
		decision = RecordAndSample
 | 
			
		||||
	}
 | 
			
		||||
	return SamplingResult{Decision: decision, Attributes: []attribute.KeyValue{attribute.Int("callCount", ts.callCount)}}
 | 
			
		||||
	return SamplingResult{
 | 
			
		||||
		Decision:   decision,
 | 
			
		||||
		Attributes: []attribute.KeyValue{attribute.Int("callCount", ts.callCount)},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ts testSampler) Description() string {
 | 
			
		||||
| 
						 | 
				
			
			@ -374,13 +377,21 @@ func TestStartSpanNewRootNotSampled(t *testing.T) {
 | 
			
		|||
 | 
			
		||||
	_, s2 := neverSampledTr.Start(ctx, "span2-no-newroot")
 | 
			
		||||
	if !s2.SpanContext().IsSampled() {
 | 
			
		||||
		t.Error(fmt.Errorf("got child span is not sampled, want child span with sampler: ParentBased(NeverSample()) to be sampled"))
 | 
			
		||||
		t.Error(
 | 
			
		||||
			fmt.Errorf(
 | 
			
		||||
				"got child span is not sampled, want child span with sampler: ParentBased(NeverSample()) to be sampled",
 | 
			
		||||
			),
 | 
			
		||||
		)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Adding WithNewRoot causes child spans to not sample based on parent context
 | 
			
		||||
	_, s3 := neverSampledTr.Start(ctx, "span3-newroot", trace.WithNewRoot())
 | 
			
		||||
	if s3.SpanContext().IsSampled() {
 | 
			
		||||
		t.Error(fmt.Errorf("got child span is sampled, want child span WithNewRoot() and with sampler: ParentBased(NeverSample()) to not be sampled"))
 | 
			
		||||
		t.Error(
 | 
			
		||||
			fmt.Errorf(
 | 
			
		||||
				"got child span is sampled, want child span WithNewRoot() and with sampler: ParentBased(NeverSample()) to not be sampled",
 | 
			
		||||
			),
 | 
			
		||||
		)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -731,8 +742,12 @@ func TestLinks(t *testing.T) {
 | 
			
		|||
	k2v2 := attribute.String("key2", "value2")
 | 
			
		||||
	k3v3 := attribute.String("key3", "value3")
 | 
			
		||||
 | 
			
		||||
	sc1 := trace.NewSpanContext(trace.SpanContextConfig{TraceID: trace.TraceID([16]byte{1, 1}), SpanID: trace.SpanID{3}})
 | 
			
		||||
	sc2 := trace.NewSpanContext(trace.SpanContextConfig{TraceID: trace.TraceID([16]byte{1, 1}), SpanID: trace.SpanID{3}})
 | 
			
		||||
	sc1 := trace.NewSpanContext(
 | 
			
		||||
		trace.SpanContextConfig{TraceID: trace.TraceID([16]byte{1, 1}), SpanID: trace.SpanID{3}},
 | 
			
		||||
	)
 | 
			
		||||
	sc2 := trace.NewSpanContext(
 | 
			
		||||
		trace.SpanContextConfig{TraceID: trace.TraceID([16]byte{1, 1}), SpanID: trace.SpanID{3}},
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	l1 := trace.Link{SpanContext: sc1, Attributes: []attribute.KeyValue{k1v1}}
 | 
			
		||||
	l2 := trace.Link{SpanContext: sc2, Attributes: []attribute.KeyValue{k2v2, k3v3}}
 | 
			
		||||
| 
						 | 
				
			
			@ -773,9 +788,15 @@ func TestLinks(t *testing.T) {
 | 
			
		|||
func TestLinksOverLimit(t *testing.T) {
 | 
			
		||||
	te := NewTestExporter()
 | 
			
		||||
 | 
			
		||||
	sc1 := trace.NewSpanContext(trace.SpanContextConfig{TraceID: trace.TraceID([16]byte{1, 1}), SpanID: trace.SpanID{3}})
 | 
			
		||||
	sc2 := trace.NewSpanContext(trace.SpanContextConfig{TraceID: trace.TraceID([16]byte{1, 1}), SpanID: trace.SpanID{3}})
 | 
			
		||||
	sc3 := trace.NewSpanContext(trace.SpanContextConfig{TraceID: trace.TraceID([16]byte{1, 1}), SpanID: trace.SpanID{3}})
 | 
			
		||||
	sc1 := trace.NewSpanContext(
 | 
			
		||||
		trace.SpanContextConfig{TraceID: trace.TraceID([16]byte{1, 1}), SpanID: trace.SpanID{3}},
 | 
			
		||||
	)
 | 
			
		||||
	sc2 := trace.NewSpanContext(
 | 
			
		||||
		trace.SpanContextConfig{TraceID: trace.TraceID([16]byte{1, 1}), SpanID: trace.SpanID{3}},
 | 
			
		||||
	)
 | 
			
		||||
	sc3 := trace.NewSpanContext(
 | 
			
		||||
		trace.SpanContextConfig{TraceID: trace.TraceID([16]byte{1, 1}), SpanID: trace.SpanID{3}},
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	sl := NewSpanLimits()
 | 
			
		||||
	sl.LinkCountLimit = 2
 | 
			
		||||
| 
						 | 
				
			
			@ -951,7 +972,12 @@ func startNamedSpan(tp *TracerProvider, trName, name string, args ...trace.SpanS
 | 
			
		|||
// passed name and with the passed context. The context is returned
 | 
			
		||||
// along with the span so this parent can be used to create child
 | 
			
		||||
// spans.
 | 
			
		||||
func startLocalSpan(ctx context.Context, tp *TracerProvider, trName, name string, args ...trace.SpanStartOption) (context.Context, trace.Span) {
 | 
			
		||||
func startLocalSpan(
 | 
			
		||||
	ctx context.Context,
 | 
			
		||||
	tp *TracerProvider,
 | 
			
		||||
	trName, name string,
 | 
			
		||||
	args ...trace.SpanStartOption,
 | 
			
		||||
) (context.Context, trace.Span) {
 | 
			
		||||
	ctx, span := tp.Tracer(trName).Start(
 | 
			
		||||
		ctx,
 | 
			
		||||
		name,
 | 
			
		||||
| 
						 | 
				
			
			@ -1299,8 +1325,21 @@ func TestRecordErrorWithStackTrace(t *testing.T) {
 | 
			
		|||
	assert.Equal(t, got.events[0].Attributes[1].Value.AsString(), want.events[0].Attributes[1].Value.AsString())
 | 
			
		||||
	gotStackTraceFunctionName := strings.Split(got.events[0].Attributes[2].Value.AsString(), "\n")
 | 
			
		||||
 | 
			
		||||
	assert.Truef(t, strings.HasPrefix(gotStackTraceFunctionName[1], "go.opentelemetry.io/otel/sdk/trace.recordStackTrace"), "%q not prefixed with go.opentelemetry.io/otel/sdk/trace.recordStackTrace", gotStackTraceFunctionName[1])
 | 
			
		||||
	assert.Truef(t, strings.HasPrefix(gotStackTraceFunctionName[3], "go.opentelemetry.io/otel/sdk/trace.(*recordingSpan).RecordError"), "%q not prefixed with go.opentelemetry.io/otel/sdk/trace.(*recordingSpan).RecordError", gotStackTraceFunctionName[3])
 | 
			
		||||
	assert.Truef(
 | 
			
		||||
		t,
 | 
			
		||||
		strings.HasPrefix(gotStackTraceFunctionName[1], "go.opentelemetry.io/otel/sdk/trace.recordStackTrace"),
 | 
			
		||||
		"%q not prefixed with go.opentelemetry.io/otel/sdk/trace.recordStackTrace",
 | 
			
		||||
		gotStackTraceFunctionName[1],
 | 
			
		||||
	)
 | 
			
		||||
	assert.Truef(
 | 
			
		||||
		t,
 | 
			
		||||
		strings.HasPrefix(
 | 
			
		||||
			gotStackTraceFunctionName[3],
 | 
			
		||||
			"go.opentelemetry.io/otel/sdk/trace.(*recordingSpan).RecordError",
 | 
			
		||||
		),
 | 
			
		||||
		"%q not prefixed with go.opentelemetry.io/otel/sdk/trace.(*recordingSpan).RecordError",
 | 
			
		||||
		gotStackTraceFunctionName[3],
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRecordErrorNil(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1346,7 +1385,11 @@ func TestWithSpanKind(t *testing.T) {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if spanData.SpanKind() != trace.SpanKindInternal {
 | 
			
		||||
		t.Errorf("Default value of Spankind should be Internal: got %+v, want %+v\n", spanData.SpanKind(), trace.SpanKindInternal)
 | 
			
		||||
		t.Errorf(
 | 
			
		||||
			"Default value of Spankind should be Internal: got %+v, want %+v\n",
 | 
			
		||||
			spanData.SpanKind(),
 | 
			
		||||
			trace.SpanKindInternal,
 | 
			
		||||
		)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sks := []trace.SpanKind{
 | 
			
		||||
| 
						 | 
				
			
			@ -1398,8 +1441,14 @@ func TestWithResource(t *testing.T) {
 | 
			
		|||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "explicit resource",
 | 
			
		||||
			options: []TracerProviderOption{WithResource(resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5)))},
 | 
			
		||||
			want:    mergeResource(t, resource.Environment(), resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5))),
 | 
			
		||||
			options: []TracerProviderOption{
 | 
			
		||||
				WithResource(resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5))),
 | 
			
		||||
			},
 | 
			
		||||
			want: mergeResource(
 | 
			
		||||
				t,
 | 
			
		||||
				resource.Environment(),
 | 
			
		||||
				resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk2", 5)),
 | 
			
		||||
			),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "last resource wins",
 | 
			
		||||
| 
						 | 
				
			
			@ -1407,12 +1456,22 @@ func TestWithResource(t *testing.T) {
 | 
			
		|||
				WithResource(resource.NewSchemaless(attribute.String("rk1", "vk1"), attribute.Int64("rk2", 5))),
 | 
			
		||||
				WithResource(resource.NewSchemaless(attribute.String("rk3", "rv3"), attribute.Int64("rk4", 10))),
 | 
			
		||||
			},
 | 
			
		||||
			want: mergeResource(t, resource.Environment(), resource.NewSchemaless(attribute.String("rk3", "rv3"), attribute.Int64("rk4", 10))),
 | 
			
		||||
			want: mergeResource(
 | 
			
		||||
				t,
 | 
			
		||||
				resource.Environment(),
 | 
			
		||||
				resource.NewSchemaless(attribute.String("rk3", "rv3"), attribute.Int64("rk4", 10)),
 | 
			
		||||
			),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name: "overlapping attributes with environment resource",
 | 
			
		||||
			options: []TracerProviderOption{WithResource(resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk5", 10)))},
 | 
			
		||||
			want:    mergeResource(t, resource.Environment(), resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk5", 10))),
 | 
			
		||||
			options: []TracerProviderOption{
 | 
			
		||||
				WithResource(resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk5", 10))),
 | 
			
		||||
			},
 | 
			
		||||
			want: mergeResource(
 | 
			
		||||
				t,
 | 
			
		||||
				resource.Environment(),
 | 
			
		||||
				resource.NewSchemaless(attribute.String("rk1", "rv1"), attribute.Int64("rk5", 10)),
 | 
			
		||||
			),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tc := range cases {
 | 
			
		||||
| 
						 | 
				
			
			@ -1527,8 +1586,18 @@ func TestSpanCapturesPanicWithStackTrace(t *testing.T) {
 | 
			
		|||
	assert.Equal(t, "error message", spans[0].Events()[0].Attributes[1].Value.AsString())
 | 
			
		||||
 | 
			
		||||
	gotStackTraceFunctionName := strings.Split(spans[0].Events()[0].Attributes[2].Value.AsString(), "\n")
 | 
			
		||||
	assert.Truef(t, strings.HasPrefix(gotStackTraceFunctionName[1], "go.opentelemetry.io/otel/sdk/trace.recordStackTrace"), "%q not prefixed with go.opentelemetry.io/otel/sdk/trace.recordStackTrace", gotStackTraceFunctionName[1])
 | 
			
		||||
	assert.Truef(t, strings.HasPrefix(gotStackTraceFunctionName[3], "go.opentelemetry.io/otel/sdk/trace.(*recordingSpan).End"), "%q not prefixed with go.opentelemetry.io/otel/sdk/trace.(*recordingSpan).End", gotStackTraceFunctionName[3])
 | 
			
		||||
	assert.Truef(
 | 
			
		||||
		t,
 | 
			
		||||
		strings.HasPrefix(gotStackTraceFunctionName[1], "go.opentelemetry.io/otel/sdk/trace.recordStackTrace"),
 | 
			
		||||
		"%q not prefixed with go.opentelemetry.io/otel/sdk/trace.recordStackTrace",
 | 
			
		||||
		gotStackTraceFunctionName[1],
 | 
			
		||||
	)
 | 
			
		||||
	assert.Truef(
 | 
			
		||||
		t,
 | 
			
		||||
		strings.HasPrefix(gotStackTraceFunctionName[3], "go.opentelemetry.io/otel/sdk/trace.(*recordingSpan).End"),
 | 
			
		||||
		"%q not prefixed with go.opentelemetry.io/otel/sdk/trace.(*recordingSpan).End",
 | 
			
		||||
		gotStackTraceFunctionName[3],
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestReadOnlySpan(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1930,7 +1999,9 @@ func TestSpanAddLink(t *testing.T) {
 | 
			
		|||
			name:               "AddLinkWithInvalidSpanContext",
 | 
			
		||||
			attrLinkCountLimit: 128,
 | 
			
		||||
			link: trace.Link{
 | 
			
		||||
				SpanContext: trace.NewSpanContext(trace.SpanContextConfig{TraceID: trace.TraceID([16]byte{}), SpanID: [8]byte{}}),
 | 
			
		||||
				SpanContext: trace.NewSpanContext(
 | 
			
		||||
					trace.SpanContextConfig{TraceID: trace.TraceID([16]byte{}), SpanID: [8]byte{}},
 | 
			
		||||
				),
 | 
			
		||||
			},
 | 
			
		||||
			want: &snapshot{
 | 
			
		||||
				name: "span0",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,7 +26,11 @@ var _ trace.Tracer = &tracer{}
 | 
			
		|||
// The Span is created with the provided name and as a child of any existing
 | 
			
		||||
// span context found in the passed context. The created Span will be
 | 
			
		||||
// configured appropriately by any SpanOption passed.
 | 
			
		||||
func (tr *tracer) Start(ctx context.Context, name string, options ...trace.SpanStartOption) (context.Context, trace.Span) {
 | 
			
		||||
func (tr *tracer) Start(
 | 
			
		||||
	ctx context.Context,
 | 
			
		||||
	name string,
 | 
			
		||||
	options ...trace.SpanStartOption,
 | 
			
		||||
) (context.Context, trace.Span) {
 | 
			
		||||
	config := trace.NewSpanStartConfig(options...)
 | 
			
		||||
 | 
			
		||||
	if ctx == nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -112,7 +116,12 @@ func (tr *tracer) newSpan(ctx context.Context, name string, config *trace.SpanCo
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// newRecordingSpan returns a new configured recordingSpan.
 | 
			
		||||
func (tr *tracer) newRecordingSpan(psc, sc trace.SpanContext, name string, sr SamplingResult, config *trace.SpanConfig) *recordingSpan {
 | 
			
		||||
func (tr *tracer) newRecordingSpan(
 | 
			
		||||
	psc, sc trace.SpanContext,
 | 
			
		||||
	name string,
 | 
			
		||||
	sr SamplingResult,
 | 
			
		||||
	config *trace.SpanConfig,
 | 
			
		||||
) *recordingSpan {
 | 
			
		||||
	startTime := config.Timestamp()
 | 
			
		||||
	if startTime.IsZero() {
 | 
			
		||||
		startTime = time.Now()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,7 +50,10 @@ type SemanticConventions struct {
 | 
			
		|||
// namespace as specified by the OpenTelemetry specification for a
 | 
			
		||||
// span.  The network parameter is a string that net.Dial function
 | 
			
		||||
// from standard library can understand.
 | 
			
		||||
func (sc *SemanticConventions) NetAttributesFromHTTPRequest(network string, request *http.Request) []attribute.KeyValue {
 | 
			
		||||
func (sc *SemanticConventions) NetAttributesFromHTTPRequest(
 | 
			
		||||
	network string,
 | 
			
		||||
	request *http.Request,
 | 
			
		||||
) []attribute.KeyValue {
 | 
			
		||||
	attrs := []attribute.KeyValue{}
 | 
			
		||||
 | 
			
		||||
	switch network {
 | 
			
		||||
| 
						 | 
				
			
			@ -200,7 +203,10 @@ func (sc *SemanticConventions) httpBasicAttributesFromHTTPRequest(request *http.
 | 
			
		|||
 | 
			
		||||
// HTTPServerMetricAttributesFromHTTPRequest generates low-cardinality attributes
 | 
			
		||||
// to be used with server-side HTTP metrics.
 | 
			
		||||
func (sc *SemanticConventions) HTTPServerMetricAttributesFromHTTPRequest(serverName string, request *http.Request) []attribute.KeyValue {
 | 
			
		||||
func (sc *SemanticConventions) HTTPServerMetricAttributesFromHTTPRequest(
 | 
			
		||||
	serverName string,
 | 
			
		||||
	request *http.Request,
 | 
			
		||||
) []attribute.KeyValue {
 | 
			
		||||
	attrs := []attribute.KeyValue{}
 | 
			
		||||
	if serverName != "" {
 | 
			
		||||
		attrs = append(attrs, sc.HTTPServerNameKey.String(serverName))
 | 
			
		||||
| 
						 | 
				
			
			@ -212,7 +218,10 @@ func (sc *SemanticConventions) HTTPServerMetricAttributesFromHTTPRequest(serverN
 | 
			
		|||
// http namespace as specified by the OpenTelemetry specification for
 | 
			
		||||
// a span on the server side. Currently, only basic authentication is
 | 
			
		||||
// supported.
 | 
			
		||||
func (sc *SemanticConventions) HTTPServerAttributesFromHTTPRequest(serverName, route string, request *http.Request) []attribute.KeyValue {
 | 
			
		||||
func (sc *SemanticConventions) HTTPServerAttributesFromHTTPRequest(
 | 
			
		||||
	serverName, route string,
 | 
			
		||||
	request *http.Request,
 | 
			
		||||
) []attribute.KeyValue {
 | 
			
		||||
	attrs := []attribute.KeyValue{
 | 
			
		||||
		sc.HTTPTargetKey.String(request.RequestURI),
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -961,7 +961,12 @@ func assertElementsMatch(t *testing.T, expected, got []attribute.KeyValue, forma
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testRequest(method, requestURI, proto, remoteAddr, host string, u *url.URL, header http.Header, tlsopt tlsOption) *http.Request {
 | 
			
		||||
func testRequest(
 | 
			
		||||
	method, requestURI, proto, remoteAddr, host string,
 | 
			
		||||
	u *url.URL,
 | 
			
		||||
	header http.Header,
 | 
			
		||||
	tlsopt tlsOption,
 | 
			
		||||
) *http.Request {
 | 
			
		||||
	major, minor := protoToInts(proto)
 | 
			
		||||
	var tlsConn *tls.ConnectionState
 | 
			
		||||
	switch tlsopt {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -816,12 +816,24 @@ func TestSpanAttributeValueLimits(t *testing.T) {
 | 
			
		|||
			assert.Truef(t, eq(want, s.span.Attrs), "set span attributes: got %#v, want %#v", s.span.Attrs, want)
 | 
			
		||||
 | 
			
		||||
			s.AddEvent("test", WithAttributes(aStr, aStrSlice))
 | 
			
		||||
			assert.Truef(t, eq(want, s.span.Events[0].Attrs), "span event attributes: got %#v, want %#v", s.span.Events[0].Attrs, want)
 | 
			
		||||
			assert.Truef(
 | 
			
		||||
				t,
 | 
			
		||||
				eq(want, s.span.Events[0].Attrs),
 | 
			
		||||
				"span event attributes: got %#v, want %#v",
 | 
			
		||||
				s.span.Events[0].Attrs,
 | 
			
		||||
				want,
 | 
			
		||||
			)
 | 
			
		||||
 | 
			
		||||
			s.AddLink(Link{
 | 
			
		||||
				Attributes: []attribute.KeyValue{aStr, aStrSlice},
 | 
			
		||||
			})
 | 
			
		||||
			assert.Truef(t, eq(want, s.span.Links[0].Attrs), "span link attributes: got %#v, want %#v", s.span.Links[0].Attrs, want)
 | 
			
		||||
			assert.Truef(
 | 
			
		||||
				t,
 | 
			
		||||
				eq(want, s.span.Links[0].Attrs),
 | 
			
		||||
				"span link attributes: got %#v, want %#v",
 | 
			
		||||
				s.span.Links[0].Attrs,
 | 
			
		||||
				want,
 | 
			
		||||
			)
 | 
			
		||||
 | 
			
		||||
			builder.Options = []SpanStartOption{
 | 
			
		||||
				WithAttributes(aStr, aStrSlice),
 | 
			
		||||
| 
						 | 
				
			
			@ -831,7 +843,13 @@ func TestSpanAttributeValueLimits(t *testing.T) {
 | 
			
		|||
			}
 | 
			
		||||
			s = builder.Build()
 | 
			
		||||
			assert.Truef(t, eq(want, s.span.Attrs), "new span attributes: got %#v, want %#v", s.span.Attrs, want)
 | 
			
		||||
			assert.Truef(t, eq(want, s.span.Links[0].Attrs), "new span link attributes: got %#v, want %#v", s.span.Attrs, want)
 | 
			
		||||
			assert.Truef(
 | 
			
		||||
				t,
 | 
			
		||||
				eq(want, s.span.Links[0].Attrs),
 | 
			
		||||
				"new span link attributes: got %#v, want %#v",
 | 
			
		||||
				s.span.Attrs,
 | 
			
		||||
				want,
 | 
			
		||||
			)
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue