Skip to content

Commit

Permalink
Implement Exponential Histgoram metrics (#525)
Browse files Browse the repository at this point in the history
Implement Exponential Histgoram metrics
  • Loading branch information
jhoongo authored Mar 23, 2024
1 parent 1535a05 commit 7fabc89
Show file tree
Hide file tree
Showing 22 changed files with 1,314 additions and 237 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -152,12 +152,57 @@ public enum MetricsAdapter {
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
}
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))
}

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)
}
}
}

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
}
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()
} 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)
}

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

0 comments on commit 7fabc89

Please sign in to comment.