@effect/opentelemetry 0.60.0 → 4.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/dist/{dts/Logger.d.ts → Logger.d.ts} +19 -13
- package/dist/Logger.d.ts.map +1 -0
- package/dist/Logger.js +76 -0
- package/dist/Logger.js.map +1 -0
- package/dist/Metrics.d.ts +76 -0
- package/dist/Metrics.d.ts.map +1 -0
- package/dist/Metrics.js +59 -0
- package/dist/Metrics.js.map +1 -0
- package/dist/{dts/NodeSdk.d.ts → NodeSdk.d.ts} +12 -9
- package/dist/NodeSdk.d.ts.map +1 -0
- package/dist/{esm/NodeSdk.js → NodeSdk.js} +23 -14
- package/dist/NodeSdk.js.map +1 -0
- package/dist/{dts/Resource.d.ts → Resource.d.ts} +10 -13
- package/dist/Resource.d.ts.map +1 -0
- package/dist/{esm/Resource.js → Resource.js} +12 -13
- package/dist/Resource.js.map +1 -0
- package/dist/Tracer.d.ts +129 -0
- package/dist/Tracer.d.ts.map +1 -0
- package/dist/Tracer.js +391 -0
- package/dist/Tracer.js.map +1 -0
- package/dist/{dts/WebSdk.d.ts → WebSdk.d.ts} +12 -9
- package/dist/WebSdk.d.ts.map +1 -0
- package/dist/WebSdk.js +41 -0
- package/dist/WebSdk.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/{esm/index.js → index.js} +4 -20
- package/dist/index.js.map +1 -0
- package/dist/internal/attributes.d.ts +2 -0
- package/dist/internal/attributes.d.ts.map +1 -0
- package/dist/internal/attributes.js +19 -0
- package/dist/internal/attributes.js.map +1 -0
- package/dist/{dts/internal → internal}/metrics.d.ts.map +1 -1
- package/dist/internal/metrics.js +406 -0
- package/dist/internal/metrics.js.map +1 -0
- package/dist/internal/utilities.d.ts +2 -0
- package/dist/internal/utilities.d.ts.map +1 -0
- package/dist/internal/utilities.js +3 -0
- package/dist/internal/utilities.js.map +1 -0
- package/package.json +70 -118
- package/src/Logger.ts +52 -55
- package/src/Metrics.ts +92 -18
- package/src/NodeSdk.ts +67 -64
- package/src/Resource.ts +16 -24
- package/src/Tracer.ts +469 -78
- package/src/WebSdk.ts +59 -51
- package/src/index.ts +7 -26
- package/src/internal/attributes.ts +21 -0
- package/src/internal/metrics.ts +381 -250
- package/src/internal/utilities.ts +5 -0
- package/Logger/package.json +0 -6
- package/Metrics/package.json +0 -6
- package/NodeSdk/package.json +0 -6
- package/Otlp/package.json +0 -6
- package/OtlpLogger/package.json +0 -6
- package/OtlpMetrics/package.json +0 -6
- package/OtlpResource/package.json +0 -6
- package/OtlpTracer/package.json +0 -6
- package/Resource/package.json +0 -6
- package/Tracer/package.json +0 -6
- package/WebSdk/package.json +0 -6
- package/dist/cjs/Logger.js +0 -85
- package/dist/cjs/Logger.js.map +0 -1
- package/dist/cjs/Metrics.js +0 -24
- package/dist/cjs/Metrics.js.map +0 -1
- package/dist/cjs/NodeSdk.js +0 -53
- package/dist/cjs/NodeSdk.js.map +0 -1
- package/dist/cjs/Otlp.js +0 -46
- package/dist/cjs/Otlp.js.map +0 -1
- package/dist/cjs/OtlpLogger.js +0 -158
- package/dist/cjs/OtlpLogger.js.map +0 -1
- package/dist/cjs/OtlpMetrics.js +0 -354
- package/dist/cjs/OtlpMetrics.js.map +0 -1
- package/dist/cjs/OtlpResource.js +0 -136
- package/dist/cjs/OtlpResource.js.map +0 -1
- package/dist/cjs/OtlpTracer.js +0 -229
- package/dist/cjs/OtlpTracer.js.map +0 -1
- package/dist/cjs/Resource.js +0 -75
- package/dist/cjs/Resource.js.map +0 -1
- package/dist/cjs/Tracer.js +0 -87
- package/dist/cjs/Tracer.js.map +0 -1
- package/dist/cjs/WebSdk.js +0 -42
- package/dist/cjs/WebSdk.js.map +0 -1
- package/dist/cjs/index.js +0 -30
- package/dist/cjs/index.js.map +0 -1
- package/dist/cjs/internal/metrics.js +0 -288
- package/dist/cjs/internal/metrics.js.map +0 -1
- package/dist/cjs/internal/otlpExporter.js +0 -81
- package/dist/cjs/internal/otlpExporter.js.map +0 -1
- package/dist/cjs/internal/tracer.js +0 -299
- package/dist/cjs/internal/tracer.js.map +0 -1
- package/dist/cjs/internal/utils.js +0 -34
- package/dist/cjs/internal/utils.js.map +0 -1
- package/dist/dts/Logger.d.ts.map +0 -1
- package/dist/dts/Metrics.d.ts +0 -29
- package/dist/dts/Metrics.d.ts.map +0 -1
- package/dist/dts/NodeSdk.d.ts.map +0 -1
- package/dist/dts/Otlp.d.ts +0 -31
- package/dist/dts/Otlp.d.ts.map +0 -1
- package/dist/dts/OtlpLogger.d.ts +0 -46
- package/dist/dts/OtlpLogger.d.ts.map +0 -1
- package/dist/dts/OtlpMetrics.d.ts +0 -40
- package/dist/dts/OtlpMetrics.d.ts.map +0 -1
- package/dist/dts/OtlpResource.d.ts +0 -104
- package/dist/dts/OtlpResource.d.ts.map +0 -1
- package/dist/dts/OtlpTracer.d.ts +0 -49
- package/dist/dts/OtlpTracer.d.ts.map +0 -1
- package/dist/dts/Resource.d.ts.map +0 -1
- package/dist/dts/Tracer.d.ts +0 -143
- package/dist/dts/Tracer.d.ts.map +0 -1
- package/dist/dts/WebSdk.d.ts.map +0 -1
- package/dist/dts/index.d.ts +0 -45
- package/dist/dts/index.d.ts.map +0 -1
- package/dist/dts/internal/otlpExporter.d.ts +0 -2
- package/dist/dts/internal/otlpExporter.d.ts.map +0 -1
- package/dist/dts/internal/tracer.d.ts +0 -2
- package/dist/dts/internal/tracer.d.ts.map +0 -1
- package/dist/dts/internal/utils.d.ts +0 -2
- package/dist/dts/internal/utils.d.ts.map +0 -1
- package/dist/esm/Logger.js +0 -75
- package/dist/esm/Logger.js.map +0 -1
- package/dist/esm/Metrics.js +0 -17
- package/dist/esm/Metrics.js.map +0 -1
- package/dist/esm/NodeSdk.js.map +0 -1
- package/dist/esm/Otlp.js +0 -38
- package/dist/esm/Otlp.js.map +0 -1
- package/dist/esm/OtlpLogger.js +0 -150
- package/dist/esm/OtlpLogger.js.map +0 -1
- package/dist/esm/OtlpMetrics.js +0 -346
- package/dist/esm/OtlpMetrics.js.map +0 -1
- package/dist/esm/OtlpResource.js +0 -124
- package/dist/esm/OtlpResource.js.map +0 -1
- package/dist/esm/OtlpTracer.js +0 -221
- package/dist/esm/OtlpTracer.js.map +0 -1
- package/dist/esm/Resource.js.map +0 -1
- package/dist/esm/Tracer.js +0 -80
- package/dist/esm/Tracer.js.map +0 -1
- package/dist/esm/WebSdk.js +0 -33
- package/dist/esm/WebSdk.js.map +0 -1
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/internal/metrics.js +0 -278
- package/dist/esm/internal/metrics.js.map +0 -1
- package/dist/esm/internal/otlpExporter.js +0 -74
- package/dist/esm/internal/otlpExporter.js.map +0 -1
- package/dist/esm/internal/tracer.js +0 -290
- package/dist/esm/internal/tracer.js.map +0 -1
- package/dist/esm/internal/utils.js +0 -23
- package/dist/esm/internal/utils.js.map +0 -1
- package/dist/esm/package.json +0 -4
- package/index/package.json +0 -6
- package/src/Otlp.ts +0 -66
- package/src/OtlpLogger.ts +0 -258
- package/src/OtlpMetrics.ts +0 -571
- package/src/OtlpResource.ts +0 -232
- package/src/OtlpTracer.ts +0 -349
- package/src/internal/otlpExporter.ts +0 -124
- package/src/internal/tracer.ts +0 -437
- package/src/internal/utils.ts +0 -31
- /package/dist/{dts/internal → internal}/metrics.d.ts +0 -0
package/src/internal/metrics.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import { ValueType } from "@opentelemetry/api"
|
|
1
|
+
import { type HrTime, ValueType } from "@opentelemetry/api"
|
|
3
2
|
import type * as Resources from "@opentelemetry/resources"
|
|
4
3
|
import type {
|
|
5
4
|
CollectionResult,
|
|
@@ -7,22 +6,14 @@ import type {
|
|
|
7
6
|
Histogram,
|
|
8
7
|
MetricCollectOptions,
|
|
9
8
|
MetricData,
|
|
10
|
-
MetricProducer
|
|
11
|
-
MetricReader
|
|
9
|
+
MetricProducer
|
|
12
10
|
} from "@opentelemetry/sdk-metrics"
|
|
13
11
|
import { AggregationTemporality, DataPointType, InstrumentType } from "@opentelemetry/sdk-metrics"
|
|
14
12
|
import type { InstrumentDescriptor } from "@opentelemetry/sdk-metrics/build/src/InstrumentDescriptor.js"
|
|
15
13
|
import * as Arr from "effect/Array"
|
|
16
|
-
import type { DurationInput } from "effect/Duration"
|
|
17
|
-
import * as Effect from "effect/Effect"
|
|
18
|
-
import type { LazyArg } from "effect/Function"
|
|
19
|
-
import * as Layer from "effect/Layer"
|
|
20
14
|
import * as Metric from "effect/Metric"
|
|
21
|
-
import type * as
|
|
22
|
-
import * as
|
|
23
|
-
import * as MetricState from "effect/MetricState"
|
|
24
|
-
import * as Option from "effect/Option"
|
|
25
|
-
import * as Resource from "../Resource.js"
|
|
15
|
+
import type * as ServiceMap from "effect/ServiceMap"
|
|
16
|
+
import type * as Metrics from "../Metrics.ts"
|
|
26
17
|
|
|
27
18
|
const sdkName = "@effect/opentelemetry/Metrics"
|
|
28
19
|
|
|
@@ -30,11 +21,48 @@ type MetricDataWithInstrumentDescriptor = MetricData & {
|
|
|
30
21
|
readonly descriptor: InstrumentDescriptor
|
|
31
22
|
}
|
|
32
23
|
|
|
24
|
+
interface PreviousHistogramState {
|
|
25
|
+
readonly count: number
|
|
26
|
+
readonly sum: number
|
|
27
|
+
readonly bucketCounts: ReadonlyArray<number>
|
|
28
|
+
readonly min: number
|
|
29
|
+
readonly max: number
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface PreviousSummaryState {
|
|
33
|
+
readonly count: number
|
|
34
|
+
readonly sum: number
|
|
35
|
+
}
|
|
36
|
+
|
|
33
37
|
/** @internal */
|
|
34
38
|
export class MetricProducerImpl implements MetricProducer {
|
|
35
|
-
|
|
39
|
+
resource: Resources.Resource
|
|
40
|
+
services: ServiceMap.ServiceMap<never>
|
|
41
|
+
temporality: Metrics.TemporalityPreference
|
|
42
|
+
startTimes: Map<string, HrTime>
|
|
43
|
+
startTimeNanos: HrTime
|
|
44
|
+
previousExportTimeNanos: HrTime
|
|
45
|
+
previousCounterState: Map<string, number | bigint>
|
|
46
|
+
previousHistogramState: Map<string, PreviousHistogramState>
|
|
47
|
+
previousFrequencyState: Map<string, Map<string, number>>
|
|
48
|
+
previousSummaryState: Map<string, PreviousSummaryState>
|
|
36
49
|
|
|
37
|
-
|
|
50
|
+
constructor(
|
|
51
|
+
resource: Resources.Resource,
|
|
52
|
+
services: ServiceMap.ServiceMap<never>,
|
|
53
|
+
temporality: Metrics.TemporalityPreference = "cumulative"
|
|
54
|
+
) {
|
|
55
|
+
this.resource = resource
|
|
56
|
+
this.services = services
|
|
57
|
+
this.temporality = temporality
|
|
58
|
+
this.startTimes = new Map()
|
|
59
|
+
this.startTimeNanos = currentHrTime()
|
|
60
|
+
this.previousExportTimeNanos = this.startTimeNanos
|
|
61
|
+
this.previousCounterState = new Map()
|
|
62
|
+
this.previousHistogramState = new Map()
|
|
63
|
+
this.previousFrequencyState = new Map()
|
|
64
|
+
this.previousSummaryState = new Map()
|
|
65
|
+
}
|
|
38
66
|
|
|
39
67
|
startTimeFor(name: string, hrTime: HrTime) {
|
|
40
68
|
if (this.startTimes.has(name)) {
|
|
@@ -45,7 +73,7 @@ export class MetricProducerImpl implements MetricProducer {
|
|
|
45
73
|
}
|
|
46
74
|
|
|
47
75
|
collect(_options?: MetricCollectOptions): Promise<CollectionResult> {
|
|
48
|
-
const snapshot = Metric.
|
|
76
|
+
const snapshot = Metric.snapshotUnsafe(this.services)
|
|
49
77
|
const hrTimeNow = currentHrTime()
|
|
50
78
|
const metricData: Array<MetricData> = []
|
|
51
79
|
const metricDataByName = new Map<string, MetricData>()
|
|
@@ -54,189 +82,320 @@ export class MetricProducerImpl implements MetricProducer {
|
|
|
54
82
|
metricDataByName.set(data.descriptor.name, data)
|
|
55
83
|
}
|
|
56
84
|
|
|
85
|
+
const isDelta = this.temporality === "delta"
|
|
86
|
+
const aggregationTemporality = isDelta
|
|
87
|
+
? AggregationTemporality.DELTA
|
|
88
|
+
: AggregationTemporality.CUMULATIVE
|
|
89
|
+
const intervalStartTime = isDelta
|
|
90
|
+
? this.previousExportTimeNanos
|
|
91
|
+
: this.startTimeNanos
|
|
92
|
+
|
|
57
93
|
for (let i = 0, len = snapshot.length; i < len; i++) {
|
|
58
|
-
const
|
|
59
|
-
const attributes =
|
|
60
|
-
acc[
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
94
|
+
const state = snapshot[i]
|
|
95
|
+
const attributes = state.attributes
|
|
96
|
+
? Arr.reduce(Object.entries(state.attributes), {} as Record<string, string>, (acc, [key, value]) => {
|
|
97
|
+
acc[key] = String(value)
|
|
98
|
+
return acc
|
|
99
|
+
})
|
|
100
|
+
: {}
|
|
101
|
+
const metricKey = makeMetricKey(state.id, state.attributes)
|
|
102
|
+
|
|
103
|
+
switch (state.type) {
|
|
104
|
+
case "Counter": {
|
|
105
|
+
const currentCount = state.state.count
|
|
106
|
+
let reportValue: number | bigint = currentCount
|
|
107
|
+
|
|
108
|
+
if (isDelta) {
|
|
109
|
+
const previousCount = this.previousCounterState.get(metricKey)
|
|
110
|
+
if (previousCount !== undefined) {
|
|
111
|
+
if (typeof currentCount === "bigint" && typeof previousCount === "bigint") {
|
|
112
|
+
reportValue = currentCount - previousCount
|
|
113
|
+
// Handle reset: if current < previous, report current value
|
|
114
|
+
if (reportValue < 0n) {
|
|
115
|
+
reportValue = currentCount
|
|
116
|
+
}
|
|
117
|
+
} else {
|
|
118
|
+
const curr = Number(currentCount)
|
|
119
|
+
const prev = Number(previousCount)
|
|
120
|
+
reportValue = curr - prev
|
|
121
|
+
// Handle reset
|
|
122
|
+
if (reportValue < 0) {
|
|
123
|
+
reportValue = curr
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
this.previousCounterState.set(metricKey, currentCount)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const descriptor = descriptorFromState(state, attributes)
|
|
131
|
+
const startTime = this.startTimeFor(descriptor.name, intervalStartTime)
|
|
132
|
+
const dataPoint: DataPoint<number> = {
|
|
133
|
+
startTime,
|
|
134
|
+
endTime: hrTimeNow,
|
|
135
|
+
attributes,
|
|
136
|
+
value: Number(reportValue)
|
|
137
|
+
}
|
|
138
|
+
if (metricDataByName.has(state.id)) {
|
|
139
|
+
metricDataByName.get(state.id)!.dataPoints.push(dataPoint as any)
|
|
140
|
+
} else {
|
|
141
|
+
addMetricData({
|
|
142
|
+
dataPointType: DataPointType.SUM,
|
|
143
|
+
descriptor,
|
|
144
|
+
isMonotonic: state.state.incremental,
|
|
145
|
+
aggregationTemporality,
|
|
146
|
+
dataPoints: [dataPoint]
|
|
147
|
+
})
|
|
112
148
|
}
|
|
113
|
-
|
|
114
|
-
prev = value
|
|
115
|
-
i++
|
|
149
|
+
break
|
|
116
150
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
151
|
+
case "Gauge": {
|
|
152
|
+
// Gauges don't have temporality - they always report current value
|
|
153
|
+
const descriptor = descriptorFromState(state, attributes)
|
|
154
|
+
const startTime = this.startTimeFor(descriptor.name, this.startTimeNanos)
|
|
155
|
+
const dataPoint: DataPoint<number> = {
|
|
156
|
+
startTime,
|
|
157
|
+
endTime: hrTimeNow,
|
|
158
|
+
attributes,
|
|
159
|
+
value: Number(state.state.value)
|
|
160
|
+
}
|
|
161
|
+
if (metricDataByName.has(state.id)) {
|
|
162
|
+
metricDataByName.get(state.id)!.dataPoints.push(dataPoint as any)
|
|
163
|
+
} else {
|
|
164
|
+
addMetricData({
|
|
165
|
+
dataPointType: DataPointType.GAUGE,
|
|
166
|
+
descriptor,
|
|
167
|
+
aggregationTemporality: AggregationTemporality.CUMULATIVE,
|
|
168
|
+
dataPoints: [dataPoint]
|
|
169
|
+
})
|
|
127
170
|
}
|
|
171
|
+
break
|
|
128
172
|
}
|
|
173
|
+
case "Histogram": {
|
|
174
|
+
const size = state.state.buckets.length
|
|
175
|
+
const currentBuckets = {
|
|
176
|
+
boundaries: Arr.allocate(size - 1) as Array<number>,
|
|
177
|
+
counts: Arr.allocate(size) as Array<number>
|
|
178
|
+
}
|
|
179
|
+
let idx = 0
|
|
180
|
+
let prev = 0
|
|
181
|
+
for (const [boundary, value] of state.state.buckets) {
|
|
182
|
+
if (idx < size - 1) {
|
|
183
|
+
currentBuckets.boundaries[idx] = boundary
|
|
184
|
+
}
|
|
185
|
+
currentBuckets.counts[idx] = value - prev
|
|
186
|
+
prev = value
|
|
187
|
+
idx++
|
|
188
|
+
}
|
|
129
189
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
190
|
+
let reportCount = state.state.count
|
|
191
|
+
let reportSum = state.state.sum
|
|
192
|
+
let reportBucketCounts = currentBuckets.counts
|
|
193
|
+
const reportMin = state.state.min
|
|
194
|
+
const reportMax = state.state.max
|
|
195
|
+
|
|
196
|
+
if (isDelta) {
|
|
197
|
+
const previousState = this.previousHistogramState.get(metricKey)
|
|
198
|
+
if (previousState !== undefined) {
|
|
199
|
+
reportCount = state.state.count - previousState.count
|
|
200
|
+
reportSum = state.state.sum - previousState.sum
|
|
201
|
+
reportBucketCounts = currentBuckets.counts.map((c, i) =>
|
|
202
|
+
Math.max(0, c - (previousState.bucketCounts[i] ?? 0))
|
|
203
|
+
)
|
|
204
|
+
}
|
|
205
|
+
this.previousHistogramState.set(metricKey, {
|
|
206
|
+
count: state.state.count,
|
|
207
|
+
sum: state.state.sum,
|
|
208
|
+
bucketCounts: currentBuckets.counts.slice(),
|
|
209
|
+
min: state.state.min,
|
|
210
|
+
max: state.state.max
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const descriptor = descriptorFromState(state, attributes)
|
|
215
|
+
const startTime = this.startTimeFor(descriptor.name, intervalStartTime)
|
|
216
|
+
const dataPoint: DataPoint<Histogram> = {
|
|
144
217
|
startTime,
|
|
145
218
|
endTime: hrTimeNow,
|
|
146
|
-
attributes
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
219
|
+
attributes,
|
|
220
|
+
value: {
|
|
221
|
+
buckets: {
|
|
222
|
+
boundaries: currentBuckets.boundaries,
|
|
223
|
+
counts: reportBucketCounts
|
|
224
|
+
},
|
|
225
|
+
count: reportCount,
|
|
226
|
+
min: reportMin,
|
|
227
|
+
max: reportMax,
|
|
228
|
+
sum: reportSum
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (metricDataByName.has(state.id)) {
|
|
233
|
+
metricDataByName.get(state.id)!.dataPoints.push(dataPoint as any)
|
|
234
|
+
} else {
|
|
235
|
+
addMetricData({
|
|
236
|
+
dataPointType: DataPointType.HISTOGRAM,
|
|
237
|
+
descriptor,
|
|
238
|
+
aggregationTemporality,
|
|
239
|
+
dataPoints: [dataPoint]
|
|
240
|
+
})
|
|
241
|
+
}
|
|
242
|
+
break
|
|
152
243
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
244
|
+
case "Frequency": {
|
|
245
|
+
const dataPoints: Array<DataPoint<number>> = []
|
|
246
|
+
const currentOccurrences = new Map<string, number>()
|
|
247
|
+
|
|
248
|
+
for (const [freqKey, value] of state.state.occurrences) {
|
|
249
|
+
currentOccurrences.set(freqKey, value)
|
|
250
|
+
let reportValue = value
|
|
251
|
+
|
|
252
|
+
if (isDelta) {
|
|
253
|
+
const previousOccurrences = this.previousFrequencyState.get(metricKey)
|
|
254
|
+
if (previousOccurrences !== undefined) {
|
|
255
|
+
const previousValue = previousOccurrences.get(freqKey) ?? 0
|
|
256
|
+
reportValue = Math.max(0, value - previousValue)
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const descriptor = descriptorFromState(state, attributes)
|
|
261
|
+
const startTime = this.startTimeFor(descriptor.name, intervalStartTime)
|
|
262
|
+
dataPoints.push({
|
|
263
|
+
startTime,
|
|
264
|
+
endTime: hrTimeNow,
|
|
265
|
+
attributes: {
|
|
266
|
+
...attributes,
|
|
267
|
+
key: freqKey
|
|
268
|
+
},
|
|
269
|
+
value: reportValue
|
|
270
|
+
})
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (isDelta) {
|
|
274
|
+
this.previousFrequencyState.set(metricKey, currentOccurrences)
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (metricDataByName.has(state.id)) {
|
|
278
|
+
// oxlint-disable-next-line no-restricted-syntax
|
|
279
|
+
metricDataByName.get(state.id)!.dataPoints.push(...dataPoints as any)
|
|
280
|
+
} else {
|
|
281
|
+
const descriptor = descriptorFromState(state, attributes)
|
|
282
|
+
addMetricData({
|
|
283
|
+
dataPointType: DataPointType.SUM,
|
|
284
|
+
descriptor,
|
|
285
|
+
aggregationTemporality,
|
|
286
|
+
isMonotonic: true,
|
|
287
|
+
dataPoints
|
|
288
|
+
})
|
|
289
|
+
}
|
|
290
|
+
break
|
|
164
291
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
292
|
+
case "Summary": {
|
|
293
|
+
// Quantiles are always computed fresh from the sliding window
|
|
294
|
+
const dataPoints: Array<DataPoint<number>> = [{
|
|
295
|
+
startTime: intervalStartTime,
|
|
296
|
+
endTime: hrTimeNow,
|
|
297
|
+
attributes: { ...attributes, quantile: "min" },
|
|
298
|
+
value: state.state.min
|
|
299
|
+
}]
|
|
300
|
+
for (const [quantile, value] of state.state.quantiles) {
|
|
301
|
+
dataPoints.push({
|
|
302
|
+
startTime: intervalStartTime,
|
|
303
|
+
endTime: hrTimeNow,
|
|
304
|
+
attributes: { ...attributes, quantile: quantile.toString() },
|
|
305
|
+
value: value ?? 0
|
|
306
|
+
})
|
|
307
|
+
}
|
|
173
308
|
dataPoints.push({
|
|
174
|
-
startTime,
|
|
309
|
+
startTime: intervalStartTime,
|
|
175
310
|
endTime: hrTimeNow,
|
|
176
|
-
attributes: { ...attributes, quantile:
|
|
177
|
-
value:
|
|
311
|
+
attributes: { ...attributes, quantile: "max" },
|
|
312
|
+
value: state.state.max
|
|
178
313
|
})
|
|
179
|
-
}
|
|
180
|
-
dataPoints.push({
|
|
181
|
-
startTime,
|
|
182
|
-
endTime: hrTimeNow,
|
|
183
|
-
attributes: { ...attributes, quantile: "max" },
|
|
184
|
-
value: metricState.max
|
|
185
|
-
})
|
|
186
|
-
const countDataPoint: DataPoint<number> = {
|
|
187
|
-
startTime,
|
|
188
|
-
endTime: hrTimeNow,
|
|
189
|
-
attributes,
|
|
190
|
-
value: metricState.count
|
|
191
|
-
}
|
|
192
|
-
const sumDataPoint: DataPoint<number> = {
|
|
193
|
-
startTime,
|
|
194
|
-
endTime: hrTimeNow,
|
|
195
|
-
attributes,
|
|
196
|
-
value: metricState.sum
|
|
197
|
-
}
|
|
198
314
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
315
|
+
let reportCount = state.state.count
|
|
316
|
+
let reportSum = state.state.sum
|
|
317
|
+
|
|
318
|
+
if (isDelta) {
|
|
319
|
+
const previousState = this.previousSummaryState.get(metricKey)
|
|
320
|
+
if (previousState !== undefined) {
|
|
321
|
+
reportCount = state.state.count - previousState.count
|
|
322
|
+
reportSum = state.state.sum - previousState.sum
|
|
323
|
+
}
|
|
324
|
+
this.previousSummaryState.set(metricKey, {
|
|
325
|
+
count: state.state.count,
|
|
326
|
+
sum: state.state.sum
|
|
327
|
+
})
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const countDataPoint: DataPoint<number> = {
|
|
331
|
+
startTime: intervalStartTime,
|
|
332
|
+
endTime: hrTimeNow,
|
|
333
|
+
attributes,
|
|
334
|
+
value: reportCount
|
|
335
|
+
}
|
|
336
|
+
const sumDataPoint: DataPoint<number> = {
|
|
337
|
+
startTime: intervalStartTime,
|
|
338
|
+
endTime: hrTimeNow,
|
|
339
|
+
attributes,
|
|
340
|
+
value: reportSum
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (metricDataByName.has(`${state.id}_quantiles`)) {
|
|
344
|
+
// oxlint-disable-next-line no-restricted-syntax
|
|
345
|
+
metricDataByName.get(`${state.id}_quantiles`)!.dataPoints.push(...dataPoints as any)
|
|
346
|
+
metricDataByName.get(`${state.id}_count`)!.dataPoints.push(countDataPoint as any)
|
|
347
|
+
metricDataByName.get(`${state.id}_sum`)!.dataPoints.push(sumDataPoint as any)
|
|
348
|
+
} else {
|
|
349
|
+
const descriptor = descriptorFromState(state, attributes)
|
|
350
|
+
addMetricData({
|
|
351
|
+
dataPointType: DataPointType.SUM,
|
|
352
|
+
descriptor: {
|
|
353
|
+
...descriptor,
|
|
354
|
+
name: `${descriptor.name}_quantiles`
|
|
355
|
+
},
|
|
356
|
+
aggregationTemporality,
|
|
357
|
+
isMonotonic: false,
|
|
358
|
+
dataPoints
|
|
359
|
+
})
|
|
360
|
+
addMetricData({
|
|
361
|
+
dataPointType: DataPointType.SUM,
|
|
362
|
+
descriptor: {
|
|
363
|
+
name: `${state.id}_count`,
|
|
364
|
+
description: state.description ?? "",
|
|
365
|
+
unit: "1",
|
|
366
|
+
type: InstrumentType.COUNTER,
|
|
367
|
+
valueType: ValueType.INT,
|
|
368
|
+
advice: {}
|
|
369
|
+
},
|
|
370
|
+
aggregationTemporality,
|
|
371
|
+
isMonotonic: true,
|
|
372
|
+
dataPoints: [countDataPoint]
|
|
373
|
+
})
|
|
374
|
+
addMetricData({
|
|
375
|
+
dataPointType: DataPointType.SUM,
|
|
376
|
+
descriptor: {
|
|
377
|
+
name: `${state.id}_sum`,
|
|
378
|
+
description: state.description ?? "",
|
|
379
|
+
unit: "1",
|
|
380
|
+
type: InstrumentType.COUNTER,
|
|
381
|
+
valueType: ValueType.DOUBLE,
|
|
382
|
+
advice: {}
|
|
383
|
+
},
|
|
384
|
+
aggregationTemporality,
|
|
385
|
+
isMonotonic: true,
|
|
386
|
+
dataPoints: [sumDataPoint]
|
|
387
|
+
})
|
|
388
|
+
}
|
|
389
|
+
break
|
|
236
390
|
}
|
|
237
391
|
}
|
|
238
392
|
}
|
|
239
393
|
|
|
394
|
+
// Update the previous export time for delta calculations
|
|
395
|
+
if (isDelta) {
|
|
396
|
+
this.previousExportTimeNanos = hrTimeNow
|
|
397
|
+
}
|
|
398
|
+
|
|
240
399
|
return Promise.resolve({
|
|
241
400
|
resourceMetrics: {
|
|
242
401
|
resource: this.resource,
|
|
@@ -250,38 +409,13 @@ export class MetricProducerImpl implements MetricProducer {
|
|
|
250
409
|
}
|
|
251
410
|
}
|
|
252
411
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
name: suffix ? `${metricKey.name}_${suffix}` : metricKey.name,
|
|
258
|
-
description: Option.getOrElse(metricKey.description, () => ""),
|
|
259
|
-
advice: {}
|
|
260
|
-
})
|
|
261
|
-
|
|
262
|
-
const descriptorFromKey = (
|
|
263
|
-
metricKey: MetricKey.MetricKey.Untyped,
|
|
264
|
-
tags: Record<string, string>,
|
|
265
|
-
suffix?: string
|
|
266
|
-
): InstrumentDescriptor => ({
|
|
267
|
-
...descriptorMeta(metricKey, suffix),
|
|
268
|
-
unit: tags.unit ?? tags.time_unit ?? "1",
|
|
269
|
-
type: instrumentTypeFromKey(metricKey),
|
|
270
|
-
valueType: "bigint" in metricKey.keyType && metricKey.keyType.bigint === true ? ValueType.INT : ValueType.DOUBLE
|
|
271
|
-
})
|
|
272
|
-
|
|
273
|
-
const instrumentTypeFromKey = (key: MetricKey.MetricKey.Untyped): InstrumentType => {
|
|
274
|
-
if (MetricKeyType.isHistogramKey(key.keyType)) {
|
|
275
|
-
return InstrumentType.HISTOGRAM
|
|
276
|
-
} else if (MetricKeyType.isGaugeKey(key.keyType)) {
|
|
277
|
-
return InstrumentType.OBSERVABLE_GAUGE
|
|
278
|
-
} else if (MetricKeyType.isFrequencyKey(key.keyType)) {
|
|
279
|
-
return InstrumentType.COUNTER
|
|
280
|
-
} else if (MetricKeyType.isCounterKey(key.keyType) && key.keyType.incremental) {
|
|
281
|
-
return InstrumentType.COUNTER
|
|
412
|
+
/** Creates a unique key for a metric including its attributes */
|
|
413
|
+
const makeMetricKey = (id: string, attributes: Metric.Metric.AttributeSet | undefined): string => {
|
|
414
|
+
if (attributes === undefined || Object.keys(attributes).length === 0) {
|
|
415
|
+
return id
|
|
282
416
|
}
|
|
283
|
-
|
|
284
|
-
return
|
|
417
|
+
const sortedEntries = Object.entries(attributes).sort((a, b) => a[0].localeCompare(b[0]))
|
|
418
|
+
return `${id}:${JSON.stringify(sortedEntries)}`
|
|
285
419
|
}
|
|
286
420
|
|
|
287
421
|
const currentHrTime = (): HrTime => {
|
|
@@ -289,44 +423,41 @@ const currentHrTime = (): HrTime => {
|
|
|
289
423
|
return [Math.floor(now / 1000), (now % 1000) * 1000000]
|
|
290
424
|
}
|
|
291
425
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
426
|
+
const descriptorFromState = (
|
|
427
|
+
state: Metric.Metric.Snapshot,
|
|
428
|
+
attributes: Record<string, string>
|
|
429
|
+
): InstrumentDescriptor => {
|
|
430
|
+
const unit = attributes.unit ?? attributes.time_unit ?? "1"
|
|
431
|
+
return {
|
|
432
|
+
name: state.id,
|
|
433
|
+
description: state.description ?? "",
|
|
434
|
+
unit,
|
|
435
|
+
type: instrumentTypeFromSnapshot(state),
|
|
436
|
+
valueType: determineValueType(state),
|
|
437
|
+
advice: {}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
297
440
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
441
|
+
const instrumentTypeFromSnapshot = (state: Metric.Metric.Snapshot): InstrumentType => {
|
|
442
|
+
switch (state.type) {
|
|
443
|
+
case "Histogram":
|
|
444
|
+
return InstrumentType.HISTOGRAM
|
|
445
|
+
case "Gauge":
|
|
446
|
+
return InstrumentType.OBSERVABLE_GAUGE
|
|
447
|
+
case "Frequency":
|
|
448
|
+
return InstrumentType.COUNTER
|
|
449
|
+
case "Counter":
|
|
450
|
+
return state.state.incremental ? InstrumentType.COUNTER : InstrumentType.UP_DOWN_COUNTER
|
|
451
|
+
case "Summary":
|
|
452
|
+
return InstrumentType.COUNTER
|
|
304
453
|
}
|
|
305
|
-
|
|
306
|
-
Effect.acquireRelease(
|
|
307
|
-
Effect.sync(() => {
|
|
308
|
-
const reader = metricReader()
|
|
309
|
-
const readers: Array<MetricReader> = Array.isArray(reader) ? reader : [reader] as any
|
|
310
|
-
readers.forEach((reader) => reader.setMetricProducer(self))
|
|
311
|
-
return readers
|
|
312
|
-
}),
|
|
313
|
-
(readers) =>
|
|
314
|
-
Effect.promise(() =>
|
|
315
|
-
Promise.all(
|
|
316
|
-
readers.map((reader) => reader.shutdown())
|
|
317
|
-
)
|
|
318
|
-
).pipe(
|
|
319
|
-
Effect.ignoreLogged,
|
|
320
|
-
Effect.interruptible,
|
|
321
|
-
Effect.timeoutOption(options?.shutdownTimeout ?? 3000)
|
|
322
|
-
)
|
|
323
|
-
)
|
|
454
|
+
}
|
|
324
455
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
})
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
456
|
+
const determineValueType = (state: Metric.Metric.Snapshot): ValueType => {
|
|
457
|
+
if (state.type === "Counter") {
|
|
458
|
+
return typeof state.state.count === "bigint" ? ValueType.INT : ValueType.DOUBLE
|
|
459
|
+
} else if (state.type === "Gauge") {
|
|
460
|
+
return typeof state.state.value === "bigint" ? ValueType.INT : ValueType.DOUBLE
|
|
461
|
+
}
|
|
462
|
+
return ValueType.DOUBLE
|
|
463
|
+
}
|