Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Exponential Histgoram metrics #525

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -152,12 +152,57 @@
protoMetric.histogram.aggregationTemporality = stableMetric.data.aggregationTemporality.convertToProtoEnum()
protoMetric.histogram.dataPoints.append(protoDataPoint)
case .ExponentialHistogram:
// TODO: implement
break
guard let exponentialHistogramData = $0 as? ExponentialHistogramPointData else {
break

Check warning on line 156 in Sources/Exporters/OpenTelemetryProtocolCommon/metric/MetricsAdapter.swift

View check run for this annotation

Codecov / codecov/patch

Sources/Exporters/OpenTelemetryProtocolCommon/metric/MetricsAdapter.swift#L156

Added line #L156 was not covered by tests
}
var protoDataPoint = Opentelemetry_Proto_Metrics_V1_ExponentialHistogramDataPoint()
injectPointData(protoExponentialHistogramPoint: &protoDataPoint, pointData: exponentialHistogramData)
protoDataPoint.scale = Int32(exponentialHistogramData.scale)
protoDataPoint.sum = Double(exponentialHistogramData.sum)
protoDataPoint.count = UInt64(exponentialHistogramData.count)
protoDataPoint.zeroCount = UInt64(exponentialHistogramData.zeroCount)
protoDataPoint.max = exponentialHistogramData.max
protoDataPoint.min = exponentialHistogramData.min

var positiveBuckets = Opentelemetry_Proto_Metrics_V1_ExponentialHistogramDataPoint.Buckets()
positiveBuckets.offset = Int32(exponentialHistogramData.positiveBuckets.offset)
positiveBuckets.bucketCounts = exponentialHistogramData.positiveBuckets.bucketCounts.map { UInt64($0) }

var negativeBuckets = Opentelemetry_Proto_Metrics_V1_ExponentialHistogramDataPoint.Buckets()
negativeBuckets.offset = Int32(exponentialHistogramData.negativeBuckets.offset)
negativeBuckets.bucketCounts = exponentialHistogramData.negativeBuckets.bucketCounts.map { UInt64($0) }

protoDataPoint.positive = positiveBuckets
protoDataPoint.negative = negativeBuckets

protoMetric.exponentialHistogram.aggregationTemporality = stableMetric.data.aggregationTemporality.convertToProtoEnum()
protoMetric.exponentialHistogram.dataPoints.append(protoDataPoint)
}
}
return protoMetric
}

static func injectPointData(protoExponentialHistogramPoint protoPoint: inout Opentelemetry_Proto_Metrics_V1_ExponentialHistogramDataPoint, pointData: PointData) {
protoPoint.timeUnixNano = pointData.endEpochNanos
protoPoint.startTimeUnixNano = pointData.startEpochNanos

pointData.attributes.forEach {
protoPoint.attributes.append(CommonAdapter.toProtoAttribute(key: $0.key, attributeValue: $0.value))
}

Check warning on line 191 in Sources/Exporters/OpenTelemetryProtocolCommon/metric/MetricsAdapter.swift

View check run for this annotation

Codecov / codecov/patch

Sources/Exporters/OpenTelemetryProtocolCommon/metric/MetricsAdapter.swift#L190-L191

Added lines #L190 - L191 were not covered by tests

pointData.exemplars.forEach {
var protoExemplar = Opentelemetry_Proto_Metrics_V1_Exemplar()
protoExemplar.timeUnixNano = $0.epochNanos

$0.filteredAttributes.forEach {
protoExemplar.filteredAttributes.append(CommonAdapter.toProtoAttribute(key: $0.key, attributeValue: $0.value))
}
if let spanContext = $0.spanContext {
protoExemplar.spanID = TraceProtoUtils.toProtoSpanId(spanId: spanContext.spanId)
protoExemplar.traceID = TraceProtoUtils.toProtoTraceId(traceId: spanContext.traceId)
}
}

Check warning on line 204 in Sources/Exporters/OpenTelemetryProtocolCommon/metric/MetricsAdapter.swift

View check run for this annotation

Codecov / codecov/patch

Sources/Exporters/OpenTelemetryProtocolCommon/metric/MetricsAdapter.swift#L194-L204

Added lines #L194 - L204 were not covered by tests
}

static func injectPointData(protoHistogramPoint protoPoint: inout Opentelemetry_Proto_Metrics_V1_HistogramDataPoint, pointData: PointData) {
protoPoint.timeUnixNano = pointData.endEpochNanos
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
//
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
//

import Foundation

class AdaptingCircularBufferCounter: NSCopying {
func copy(with zone: NSZone? = nil) -> Any {
let copy = AdaptingCircularBufferCounter(maxSize: maxSize)
copy.startIndex = startIndex
copy.endIndex = endIndex
copy.baseIndex = baseIndex
copy.backing = backing.copy() as! AdaptingIntegerArray
return copy
}

public private(set) var endIndex = Int.nullIndex
public private(set) var startIndex = Int.nullIndex
private var baseIndex = Int.nullIndex
private var backing: AdaptingIntegerArray
private let maxSize: Int

init(maxSize: Int) {
backing = AdaptingIntegerArray(size: maxSize)
self.maxSize = maxSize
}

@discardableResult func increment(index: Int, delta: Int64) -> Bool{
if baseIndex == Int.min {
startIndex = index
endIndex = index
baseIndex = index
backing.increment(index: 0, count: delta)
return true
}

if index > endIndex {
if (index - startIndex + 1) > backing.length() {
return false
}
endIndex = index
} else if index < startIndex {
if (endIndex - index + 1) > backing.length() {
return false

Check warning on line 45 in Sources/OpenTelemetrySdk/Metrics/Stable/Aggregation/AdaptingCircularBufferCounter.swift

View check run for this annotation

Codecov / codecov/patch

Sources/OpenTelemetrySdk/Metrics/Stable/Aggregation/AdaptingCircularBufferCounter.swift#L45

Added line #L45 was not covered by tests
}
self.startIndex = index
}

let realIndex = toBufferIndex(index: index)
backing.increment(index: realIndex, count: delta)
return true
}

func get(index: Int) -> Int64 {
if (index < startIndex || index > endIndex) {
return 0
} else {
return backing.get(index: toBufferIndex(index: index))
}
}

func isEmpty() -> Bool {
return baseIndex == Int.nullIndex
}

func getMaxSize() -> Int {
return backing.length()
}

func clear() {
backing.clear()
baseIndex = Int.nullIndex
startIndex = Int.nullIndex
endIndex = Int.nullIndex
}

private func toBufferIndex(index: Int) -> Int {
var result = index - baseIndex
if (result >= backing.length()) {
result -= backing.length()

Check warning on line 81 in Sources/OpenTelemetrySdk/Metrics/Stable/Aggregation/AdaptingCircularBufferCounter.swift

View check run for this annotation

Codecov / codecov/patch

Sources/OpenTelemetrySdk/Metrics/Stable/Aggregation/AdaptingCircularBufferCounter.swift#L81

Added line #L81 was not covered by tests
} else if (result < 0) {
result += backing.length()
}
return result
}
}

extension Int {
static let nullIndex = Int.min
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
//
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
//

import Foundation

class AdaptingIntegerArray: NSCopying {

func copy(with zone: NSZone? = nil) -> Any {
let copy = AdaptingIntegerArray(size: size)
copy.cellSize = cellSize
switch (cellSize) {
case .byte:
copy.byteBacking = byteBacking
case .short:
copy.shortBacking = shortBacking
case .int:
copy.intBacking = intBacking
case .long:
copy.longBacking = longBacking
}
return copy
}

var byteBacking: Array<Int8>?
var shortBacking: Array<Int16>?
var intBacking: Array<Int32>?
var longBacking: Array<Int64>?
var size: Int

enum ArrayCellSize {
case byte
case short
case int
case long
}

var cellSize: ArrayCellSize

init(size: Int) {
self.size = size
cellSize = ArrayCellSize.byte
byteBacking = Array<Int8>(repeating: Int8(0), count: size)
}

func increment(index: Int, count: Int64) {

if cellSize == .byte, var byteBacking = self.byteBacking {
let result = Int64(byteBacking[index]) + count
if result > Int8.max {
resizeToShort()
increment(index: index, count: count)
} else {
byteBacking[index] = Int8(result)
self.byteBacking = byteBacking
}
} else if cellSize == .short, var shortBacking = self.shortBacking {
let result = Int64(shortBacking[index]) + count
if result > Int16.max {
resizeToInt()
increment(index: index, count: count)
} else {
shortBacking[index] = Int16(result)
self.shortBacking = shortBacking
}
} else if cellSize == .int, var intBacking = self.intBacking {
let result = Int64(intBacking[index]) + count
if result > Int32.max {
resizeToLong()
increment(index: index, count: count)
} else {
intBacking[index] = Int32(result)
self.intBacking = intBacking
}
} else if cellSize == .long, var longBacking = self.longBacking {
let result = longBacking[index] + count
longBacking[index] = result
self.longBacking = longBacking
}
}

func get(index: Int) -> Int64 {

if cellSize == .byte, let byteBacking = self.byteBacking, index < byteBacking.count {
return Int64(byteBacking[index])
} else if cellSize == .short, let shortBacking = self.shortBacking, index < shortBacking.count {
return Int64(shortBacking[index])
} else if cellSize == .int, let intBacking = self.intBacking, index < intBacking.count {
return Int64(intBacking[index])
} else if cellSize == .long, let longBacking = self.longBacking, index < longBacking.count {
return longBacking[index]
}

return Int64(0)

Check warning on line 95 in Sources/OpenTelemetrySdk/Metrics/Stable/Aggregation/AdaptingIntegerArray.swift

View check run for this annotation

Codecov / codecov/patch

Sources/OpenTelemetrySdk/Metrics/Stable/Aggregation/AdaptingIntegerArray.swift#L94-L95

Added lines #L94 - L95 were not covered by tests
}

func length() -> Int {
var length = 0

if cellSize == .byte, let byteBacking = self.byteBacking {
length = byteBacking.count
} else if cellSize == .short, let shortBacking = self.shortBacking {
length = shortBacking.count
} else if cellSize == .int, let intBacking = self.intBacking {
length = intBacking.count
} else if cellSize == .long, let longBacking = self.longBacking {
length = longBacking.count
}

return length
}

func clear() {
switch (cellSize) {
case .byte:
byteBacking = Array(repeating: Int8(0), count: byteBacking?.count ?? 0)
case .short:
shortBacking = Array(repeating: Int16(0), count: shortBacking?.count ?? 0)
case .int:
intBacking = Array(repeating: Int32(0), count: intBacking?.count ?? 0)
case .long:
longBacking = Array(repeating: Int64(0), count: longBacking?.count ?? 0)
}
}

private func resizeToShort() {
guard let byteBacking = byteBacking else { return }
var tmpShortBacking: Array<Int16> = Array<Int16>(repeating: Int16(0), count: byteBacking.count)

for (index, value) in byteBacking.enumerated() {
tmpShortBacking[index] = Int16(value)
}
cellSize = ArrayCellSize.short
shortBacking = tmpShortBacking
self.byteBacking = nil
}

private func resizeToInt() {
guard let shortBacking = shortBacking else { return }
var tmpIntBacking: Array<Int32> = Array<Int32>(repeating: Int32(0), count: shortBacking.count)

for (index, value) in shortBacking.enumerated() {
tmpIntBacking[index] = Int32(value)
}
cellSize = ArrayCellSize.int
intBacking = tmpIntBacking
self.shortBacking = nil
}

private func resizeToLong() {
guard let intBacking = intBacking else { return }
var tmpLongBacking: Array<Int64> = Array<Int64>(repeating: Int64(0), count: intBacking.count)

for (index, value) in intBacking.enumerated() {
tmpLongBacking[index] = Int64(value)
}
cellSize = ArrayCellSize.long
longBacking = tmpLongBacking
self.intBacking = nil
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ public enum Aggregations {
ExplicitBucketHistogramAggregation(bucketBoundaries: buckets)
}

static func base2ExponentialBucketHistogram() {
// todo
static func base2ExponentialBucketHistogram() -> Aggregation {
Base2ExponentialHistogramAggregation.instance
}

static func base2ExponentialBucketHistogram(maxBuckets: Int, maxScale: Int) {
// todo
static func base2ExponentialBucketHistogram(maxBuckets: Int, maxScale: Int) -> Aggregation {
Base2ExponentialHistogramAggregation(maxBuckets: maxBuckets, maxScale: maxScale)
}
}

This file was deleted.

Loading
Loading