-
Notifications
You must be signed in to change notification settings - Fork 564
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
234 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package runtime // import "go.opentelemetry.io/contrib/instrumentation/runtime" | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"math" | ||
"runtime/metrics" | ||
"time" | ||
|
||
"go.opentelemetry.io/otel/attribute" | ||
"go.opentelemetry.io/otel/sdk/instrumentation" | ||
"go.opentelemetry.io/otel/sdk/metric" | ||
"go.opentelemetry.io/otel/sdk/metric/metricdata" | ||
) | ||
|
||
var startTime time.Time | ||
|
||
func init() { | ||
startTime = time.Now() | ||
} | ||
|
||
var histogramMetrics = []string{goSchedLatencies} | ||
|
||
type Producer struct { | ||
collector *goCollector | ||
} | ||
|
||
var _ metric.Producer = (*Producer)(nil) | ||
|
||
func NewProducer(opts ...ProducerOption) *Producer { | ||
c := newProducerConfig(opts...) | ||
return &Producer{ | ||
collector: newCollector(c.MinimumReadMemStatsInterval, histogramMetrics), | ||
} | ||
} | ||
|
||
func (p *Producer) Produce(context.Context) ([]metricdata.ScopeMetrics, error) { | ||
p.collector.refresh() | ||
// Use the last collection time (which may or may not be now) for the timestamp. | ||
histDp := convertRuntimeHistogram(p.collector.getHistogram(goSchedLatencies), p.collector.lastCollect) | ||
if len(histDp) == 0 { | ||
return nil, fmt.Errorf("unable to obtain go.schedule.duration metric from the runtime") | ||
} | ||
return []metricdata.ScopeMetrics{ | ||
{ | ||
Scope: instrumentation.Scope{ | ||
Name: ScopeName, | ||
Version: Version(), | ||
}, | ||
Metrics: []metricdata.Metrics{ | ||
{ | ||
Name: "go.schedule.duration", | ||
Description: "The time goroutines have spent in the scheduler in a runnable state before actually running.", | ||
Unit: "s", | ||
Data: metricdata.Histogram[float64]{ | ||
Temporality: metricdata.CumulativeTemporality, | ||
DataPoints: histDp, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, nil | ||
} | ||
|
||
var emptySet = attribute.EmptySet() | ||
|
||
func convertRuntimeHistogram(runtimeHist *metrics.Float64Histogram, ts time.Time) []metricdata.HistogramDataPoint[float64] { | ||
if runtimeHist == nil { | ||
return nil | ||
} | ||
bounds := runtimeHist.Buckets | ||
counts := runtimeHist.Counts | ||
if len(bounds) < 2 { | ||
// runtime histograms are guaranteed to have at least two bucket boundaries. | ||
return nil | ||
} | ||
// trim the first bucket since it is a lower bound. OTel histogram boundaries only have an upper bound. | ||
bounds = bounds[1:] | ||
if bounds[len(bounds)-1] == math.Inf(1) { | ||
// trim the last bucket if it is +Inf, since the +Inf boundary is implicit in OTel. | ||
bounds = bounds[:len(bounds)-1] | ||
} else { | ||
// if the last bucket is not +Inf, append an extra zero count since | ||
// the implicit +Inf bucket won't have any observations. | ||
counts = append(counts, 0) | ||
} | ||
count := uint64(0) | ||
sum := float64(0) | ||
for i, c := range counts { | ||
count += c | ||
// This computed sum is an underestimate, since it assumes each | ||
// observation happens at the bucket's lower bound. | ||
if i > 0 && count != 0 { | ||
sum += bounds[i-1] * float64(count) | ||
} | ||
} | ||
|
||
return []metricdata.HistogramDataPoint[float64]{ | ||
{ | ||
StartTime: startTime, | ||
Count: count, | ||
Sum: sum, | ||
Time: ts, | ||
Bounds: bounds, | ||
BucketCounts: counts, | ||
Attributes: *emptySet, | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.