Skip to content

Commit 3161c2b

Browse files
author
Ignacio Bonafonte
authored
Merge pull request #108 from bryce-b/bryce/otelp-metrics
- Made MeterSdkProvider init mimic the TraceProvider init I decided to change the MetricSdkProvider.init method to take shared state objects as parameters, since this is how the TraceProvider operates. Alternatively, I could have move the default values into the MeterSharedState construction, but that would require making the NoopMetricProcessor & NoopMetricExporter public, which I'm not against, but seemed intentionally private. - replaced MeterRegisteryKey with InstrumentationLibraryInfo - Injected Resource into the MetricSdk stack I followed the same pattern as with the Trace Sdk.
2 parents aed9e44 + 42987f1 commit 3161c2b

File tree

23 files changed

+465
-76
lines changed

23 files changed

+465
-76
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Xcode
22
#
33
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4+
## Jetbrain
5+
.idea/
46

57
## User settings
68
xcuserdata/

Examples/Datadog Sample/main.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,7 @@ func childSpan() {
8181
func testMetrics() {
8282
let processor = UngroupedBatcher()
8383

84-
let state = MeterSharedState(metricProcessor: processor, metricExporter: datadogExporter, metricPushInterval: 0.1)
85-
let meterProvider = MeterSdkProvider(meterSharedState: state)
84+
let meterProvider = MeterSdkProvider(metricProcessor: processor, metricExporter: datadogExporter, metricPushInterval: 0.1)
8685

8786
let meter = meterProvider.get(instrumentationName: "MyMeter")
8887

Examples/Prometheus Sample/main.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ DispatchQueue.global(qos: .default).async {
3434

3535
let processor = UngroupedBatcher()
3636

37-
let state = MeterSharedState(metricProcessor: processor, metricExporter: promExporter, metricPushInterval: 0.1)
38-
let meterProvider = MeterSdkProvider(meterSharedState: state)
37+
38+
let meterProvider = MeterSdkProvider(metricProcessor: processor, metricExporter: promExporter, metricPushInterval: 0.1)
3939

4040
var meter = meterProvider.get(instrumentationName: "MyMeter")
4141

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
// Copyright 2020, OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
import Foundation
16+
import OpenTelemetryApi
17+
import OpenTelemetrySdk
18+
19+
20+
struct MetricsAdapter {
21+
static func toProtoResourceMetrics(metricDataList: [Metric]) -> [Opentelemetry_Proto_Metrics_V1_ResourceMetrics] {
22+
let resourceAndLibraryMap = groupByResouceAndLibrary(metricDataList: metricDataList)
23+
var resourceMetrics = [Opentelemetry_Proto_Metrics_V1_ResourceMetrics]()
24+
25+
resourceAndLibraryMap.forEach { resMap in
26+
var instrumentationLibraryMetrics = [Opentelemetry_Proto_Metrics_V1_InstrumentationLibraryMetrics]()
27+
resMap.value.forEach { instLibrary in
28+
var protoInst =
29+
Opentelemetry_Proto_Metrics_V1_InstrumentationLibraryMetrics()
30+
protoInst.instrumentationLibrary =
31+
CommonAdapter.toProtoInstrumentationLibrary(instrumentationLibraryInfo: instLibrary.key)
32+
instLibrary.value.forEach {
33+
protoInst.metrics.append($0)
34+
}
35+
instrumentationLibraryMetrics.append(protoInst)
36+
}
37+
var resourceMetric = Opentelemetry_Proto_Metrics_V1_ResourceMetrics()
38+
resourceMetric.resource = ResourceAdapter.toProtoResource(resource: resMap.key)
39+
resourceMetric.instrumentationLibraryMetrics.append(contentsOf: instrumentationLibraryMetrics)
40+
resourceMetrics.append(resourceMetric)
41+
42+
}
43+
44+
45+
46+
return resourceMetrics
47+
}
48+
49+
private static func groupByResouceAndLibrary(metricDataList: [Metric]) -> [Resource :[InstrumentationLibraryInfo : [Opentelemetry_Proto_Metrics_V1_Metric]]] {
50+
var results = [Resource : [InstrumentationLibraryInfo : [Opentelemetry_Proto_Metrics_V1_Metric]]]()
51+
52+
metricDataList.forEach {
53+
results[$0.resource, default:[InstrumentationLibraryInfo : [Opentelemetry_Proto_Metrics_V1_Metric]]()][$0.instrumentationLibraryInfo,default:[Opentelemetry_Proto_Metrics_V1_Metric]()]
54+
.append(toProtoMetric(metric: $0))
55+
}
56+
57+
return results
58+
}
59+
60+
static func toProtoMetric(metric: Metric) -> Opentelemetry_Proto_Metrics_V1_Metric {
61+
62+
var protoMetric = Opentelemetry_Proto_Metrics_V1_Metric()
63+
protoMetric.name = metric.name
64+
protoMetric.description_p = metric.description
65+
66+
67+
metric.data.forEach {
68+
switch metric.aggregationType {
69+
case .doubleSum:
70+
guard let sumData = $0 as? SumData<Double> else {
71+
break
72+
}
73+
var protoDataPoint = Opentelemetry_Proto_Metrics_V1_DoubleDataPoint()
74+
protoDataPoint.value = sumData.sum
75+
sumData.labels.forEach {
76+
var kvp = Opentelemetry_Proto_Common_V1_StringKeyValue()
77+
kvp.key = $0.key
78+
kvp.value = $0.value
79+
protoDataPoint.labels.append(kvp)
80+
}
81+
82+
protoMetric.doubleSum.dataPoints.append(protoDataPoint)
83+
break
84+
case .doubleSummary:
85+
86+
guard let summaryData = $0 as? SummaryData<Double> else {
87+
break
88+
}
89+
var protoDataPoint = Opentelemetry_Proto_Metrics_V1_DoubleHistogramDataPoint()
90+
protoDataPoint.sum = summaryData.sum
91+
protoDataPoint.count = UInt64(summaryData.count)
92+
protoDataPoint.explicitBounds = [summaryData.min, summaryData.max]
93+
94+
protoDataPoint.startTimeUnixNano = summaryData.startTimestamp.timeIntervalSince1970.toNanoseconds
95+
protoDataPoint.timeUnixNano = summaryData.timestamp.timeIntervalSince1970.toNanoseconds
96+
97+
summaryData.labels.forEach {
98+
var kvp = Opentelemetry_Proto_Common_V1_StringKeyValue()
99+
kvp.key = $0.key
100+
kvp.value = $0.value
101+
protoDataPoint.labels.append(kvp)
102+
}
103+
104+
protoMetric.doubleHistogram.dataPoints.append(protoDataPoint)
105+
106+
break
107+
case .intSum:
108+
guard let sumData = $0 as? SumData<Int> else {
109+
break;
110+
}
111+
var protoDataPoint = Opentelemetry_Proto_Metrics_V1_IntDataPoint()
112+
protoDataPoint.value = Int64(sumData.sum)
113+
sumData.labels.forEach {
114+
var kvp = Opentelemetry_Proto_Common_V1_StringKeyValue()
115+
kvp.key = $0.key
116+
kvp.value = $0.value
117+
protoDataPoint.labels.append(kvp)
118+
}
119+
120+
protoMetric.intSum.dataPoints.append(protoDataPoint)
121+
122+
break
123+
case .intSummary:
124+
guard let summaryData = $0 as? SummaryData<Int> else {
125+
break
126+
}
127+
var protoDataPoint = Opentelemetry_Proto_Metrics_V1_IntHistogramDataPoint()
128+
protoDataPoint.sum = Int64(summaryData.sum)
129+
protoDataPoint.count = UInt64(summaryData.count)
130+
protoDataPoint.bucketCounts = [UInt64(summaryData.min), UInt64(summaryData.max)]
131+
protoDataPoint.startTimeUnixNano = summaryData.startTimestamp.timeIntervalSince1970.toNanoseconds
132+
protoDataPoint.timeUnixNano = summaryData.timestamp.timeIntervalSince1970.toNanoseconds
133+
134+
summaryData.labels.forEach {
135+
var kvp = Opentelemetry_Proto_Common_V1_StringKeyValue()
136+
kvp.key = $0.key
137+
kvp.value = $0.value
138+
protoDataPoint.labels.append(kvp)
139+
}
140+
141+
protoMetric.intHistogram.dataPoints.append(protoDataPoint)
142+
143+
break
144+
}
145+
}
146+
return protoMetric
147+
}
148+
149+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright 2020, OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
16+
import Foundation
17+
import GRPC
18+
import OpenTelemetryApi
19+
import OpenTelemetrySdk
20+
21+
public class OtelpMetricExporter : MetricExporter {
22+
23+
let channel : GRPCChannel
24+
let metricClient: Opentelemetry_Proto_Collector_Metrics_V1_MetricsServiceClient
25+
let deadlineMS : Int
26+
27+
public init(channel: GRPCChannel, timeoutMS: Int = 0) {
28+
self.channel = channel
29+
self.deadlineMS = timeoutMS
30+
self.metricClient = Opentelemetry_Proto_Collector_Metrics_V1_MetricsServiceClient(channel: self.channel)
31+
}
32+
33+
34+
public func export(metrics: [Metric], shouldCancel: (() -> Bool)?) -> MetricExporterResultCode {
35+
let exportRequest = Opentelemetry_Proto_Collector_Metrics_V1_ExportMetricsServiceRequest
36+
.with {
37+
$0.resourceMetrics = MetricsAdapter.toProtoResourceMetrics(metricDataList: metrics)
38+
}
39+
40+
if deadlineMS > 0 {
41+
metricClient.defaultCallOptions.timeout = try! GRPCTimeout.milliseconds(deadlineMS)
42+
}
43+
44+
let export = metricClient.export(exportRequest)
45+
46+
47+
do {
48+
_ = try export.response.wait()
49+
return .success
50+
} catch {
51+
return .failureRetryable
52+
}
53+
}
54+
55+
public func flush() -> SpanExporterResultCode {
56+
return .success
57+
}
58+
59+
public func shutdown() {
60+
_ = channel.close()
61+
}
62+
63+
64+
}

0 commit comments

Comments
 (0)