From a949fa0329197e942ed29fd92bf63ee4a4d8c28e Mon Sep 17 00:00:00 2001 From: Jian Yang Date: Thu, 7 Mar 2024 09:38:39 +0800 Subject: [PATCH] Update attribute processor for stable metrics Previously AttribtueProcessor is a class and not open. It can't be customized externally. Now it's changed to procotol and its static functions are moved into SimpleAttributeProcessor (now it's public). Also duplicated NoopAttributesProcessor is removed and more tests are added. --- .../Stable/NoopAttributesProcessor.swift | 17 ----- .../Stable/View/AttributeProcessor.swift | 63 +++++++++---------- .../Metrics/Stable/View/ViewBuilder.swift | 7 ++- .../AttributeProcessorTests.swift | 44 +++++++++++++ .../NoopAttributesProcessorTests.swift | 17 ----- 5 files changed, 78 insertions(+), 70 deletions(-) delete mode 100644 Sources/OpenTelemetrySdk/Metrics/Stable/NoopAttributesProcessor.swift create mode 100644 Tests/OpenTelemetrySdkTests/Metrics/StableMetrics/AttributeProcessorTests.swift delete mode 100644 Tests/OpenTelemetrySdkTests/Metrics/StableMetrics/NoopAttributesProcessorTests.swift diff --git a/Sources/OpenTelemetrySdk/Metrics/Stable/NoopAttributesProcessor.swift b/Sources/OpenTelemetrySdk/Metrics/Stable/NoopAttributesProcessor.swift deleted file mode 100644 index 71fce2d97..000000000 --- a/Sources/OpenTelemetrySdk/Metrics/Stable/NoopAttributesProcessor.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 -// - -import Foundation -import OpenTelemetryApi - - -class NoopAttributesProcessor : AttributeProcessorProtocol { - - func process(incoming attributes: [String : OpenTelemetryApi.AttributeValue]) -> [String: OpenTelemetryApi.AttributeValue] { - return attributes - } - - public static let noop = NoopAttributesProcessor() -} diff --git a/Sources/OpenTelemetrySdk/Metrics/Stable/View/AttributeProcessor.swift b/Sources/OpenTelemetrySdk/Metrics/Stable/View/AttributeProcessor.swift index f50166c55..e78cac63b 100644 --- a/Sources/OpenTelemetrySdk/Metrics/Stable/View/AttributeProcessor.swift +++ b/Sources/OpenTelemetrySdk/Metrics/Stable/View/AttributeProcessor.swift @@ -6,12 +6,12 @@ import Foundation import OpenTelemetryApi -public protocol AttributeProcessorProtocol { +public protocol AttributeProcessor { func process(incoming : [String: AttributeValue]) -> [String: AttributeValue] } -public class AttributeProcessor : AttributeProcessorProtocol { - - public func then(other : AttributeProcessor) -> AttributeProcessor { + +public extension AttributeProcessor { + func then(other : AttributeProcessor) -> AttributeProcessor { if type(of: other) == NoopAttributeProcessor.self { return self } @@ -19,18 +19,29 @@ public class AttributeProcessor : AttributeProcessorProtocol { return other } - if type(of: other) == JoinedAttributeProcessor.self { - return (other as! JoinedAttributeProcessor).prepend(processor:self) + if let joined = self as? JoinedAttributeProcessor { + return joined.append(processor:self) } + if let joined = other as? JoinedAttributeProcessor { + return joined.prepend(processor:self) + } + return JoinedAttributeProcessor([self, other]) } +} + +public class SimpleAttributeProcessor : AttributeProcessor { + let attributeProcessor : ([String: AttributeValue]) -> [String:AttributeValue] + init(attributeProcessor : @escaping ([String: AttributeValue]) -> [String: AttributeValue]) { + self.attributeProcessor = attributeProcessor + } public func process(incoming: [String : AttributeValue]) -> [String : AttributeValue] { - return incoming + return attributeProcessor(incoming) } - public static func filterByKeyName( nameFilter : @escaping (String) -> Bool) -> AttributeProcessor { + static func filterByKeyName( nameFilter : @escaping (String) -> Bool) -> AttributeProcessor { return SimpleAttributeProcessor { attributes in attributes.filter { key, value in nameFilter(key) @@ -38,37 +49,19 @@ public class AttributeProcessor : AttributeProcessorProtocol { } } - public static func append(attributes: [String : AttributeValue]) -> AttributeProcessor { + static func append(attributes: [String : AttributeValue]) -> AttributeProcessor { SimpleAttributeProcessor { incoming in incoming.merging(attributes) { a, b in b } } } - - -} - -internal class SimpleAttributeProcessor : AttributeProcessor { - - let attributeProcessor : ([String: AttributeValue]) -> [String:AttributeValue] - - init(attributeProcessor : @escaping ([String: AttributeValue]) -> [String: AttributeValue]) { - self.attributeProcessor = attributeProcessor - - } - - override func process(incoming: [String : OpenTelemetryApi.AttributeValue]) -> [String : OpenTelemetryApi.AttributeValue] { - return attributeProcessor(incoming) - } - - } public class JoinedAttributeProcessor : AttributeProcessor { - override public func process(incoming: [String : OpenTelemetryApi.AttributeValue]) -> [String : OpenTelemetryApi.AttributeValue] { + public func process(incoming: [String : AttributeValue]) -> [String : AttributeValue] { var result = incoming for processor in processors { result = processor.process(incoming: result) @@ -76,17 +69,17 @@ public class JoinedAttributeProcessor : AttributeProcessor { return result } - override public func then(other: AttributeProcessor) -> AttributeProcessor { + public func append(processor: AttributeProcessor) -> JoinedAttributeProcessor { var newList = processors - if let otherJoined = other as? JoinedAttributeProcessor { - newList.append(contentsOf: otherJoined.processors) + if let joinedProcessor = processor as? JoinedAttributeProcessor { + newList.append(contentsOf: joinedProcessor.processors) } else { - newList.append(other) + newList.append(processor) } return JoinedAttributeProcessor(newList) } - public func prepend(processor: AttributeProcessor) -> AttributeProcessor { + public func prepend(processor: AttributeProcessor) -> JoinedAttributeProcessor { var newProcessors = [processor] newProcessors.append(contentsOf: processors) return JoinedAttributeProcessor(newProcessors) @@ -101,8 +94,8 @@ public class JoinedAttributeProcessor : AttributeProcessor { public class NoopAttributeProcessor : AttributeProcessor { static let noop = NoopAttributeProcessor() - private override init() {} - override public func process(incoming: [String : AttributeValue]) -> [String : AttributeValue] { + private init() {} + public func process(incoming: [String : AttributeValue]) -> [String : AttributeValue] { return incoming } } diff --git a/Sources/OpenTelemetrySdk/Metrics/Stable/View/ViewBuilder.swift b/Sources/OpenTelemetrySdk/Metrics/Stable/View/ViewBuilder.swift index 14098d3f4..46dc459c4 100644 --- a/Sources/OpenTelemetrySdk/Metrics/Stable/View/ViewBuilder.swift +++ b/Sources/OpenTelemetrySdk/Metrics/Stable/View/ViewBuilder.swift @@ -30,8 +30,13 @@ public class ViewBuilder { return self } + public func withAttributeProcessor(processor: AttributeProcessor) -> Self { + self.processor = processor + return self + } + public func addAttributeFilter(keyFilter: @escaping (String) -> Bool) -> Self { - addAttributeProcessor(processor: AttributeProcessor.filterByKeyName(nameFilter: keyFilter)) + addAttributeProcessor(processor: SimpleAttributeProcessor.filterByKeyName(nameFilter: keyFilter)) } public func addAttributeProcessor(processor: AttributeProcessor) -> Self { diff --git a/Tests/OpenTelemetrySdkTests/Metrics/StableMetrics/AttributeProcessorTests.swift b/Tests/OpenTelemetrySdkTests/Metrics/StableMetrics/AttributeProcessorTests.swift new file mode 100644 index 000000000..a1fbaa4e7 --- /dev/null +++ b/Tests/OpenTelemetrySdkTests/Metrics/StableMetrics/AttributeProcessorTests.swift @@ -0,0 +1,44 @@ +// +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 +// + +import Foundation + +import OpenTelemetryApi +@testable import OpenTelemetrySdk +import XCTest + +class AttributeProcessorTests : XCTestCase { + func testStaticNoop() { + XCTAssertNotNil(NoopAttributeProcessor.noop) + XCTAssertEqual(NoopAttributeProcessor.noop.process(incoming: ["hello": AttributeValue.string("world")]), ["hello" : AttributeValue.string("world")]) + } + + func testSimpleProcessor() { + let incoming = ["hello": AttributeValue("world")] + + var processor: AttributeProcessor = SimpleAttributeProcessor.append(attributes: ["foo" : .string("bar")]) + XCTAssertEqual(processor.process(incoming: incoming), ["hello" : .string("world"), "foo": .string("bar")]) + + processor = processor.then(other: SimpleAttributeProcessor.filterByKeyName(nameFilter: { $0 == "foo" })) + XCTAssertEqual(processor.process(incoming: incoming), ["foo": .string("bar")]) + } + + func testJoinedProcessor() { + let incoming = ["hello": AttributeValue("world")] + + let processor0 = SimpleAttributeProcessor.append(attributes: ["foo" : .string("bar0")]) + let processor1 = SimpleAttributeProcessor.append(attributes: ["foo" : .string("bar1")]) + let processor2 = SimpleAttributeProcessor.append(attributes: ["foo" : .string("bar2")]) + + var processor = JoinedAttributeProcessor([processor0]) + XCTAssertEqual(processor.process(incoming: incoming), ["hello" : .string("world"), "foo": .string("bar0")]) + + processor = processor.prepend(processor: processor1) + XCTAssertEqual(processor.process(incoming: incoming), ["hello" : .string("world"), "foo": .string("bar0")]) + + processor = processor.append(processor: processor2) + XCTAssertEqual(processor.process(incoming: incoming), ["hello" : .string("world"), "foo": .string("bar2")]) + } +} diff --git a/Tests/OpenTelemetrySdkTests/Metrics/StableMetrics/NoopAttributesProcessorTests.swift b/Tests/OpenTelemetrySdkTests/Metrics/StableMetrics/NoopAttributesProcessorTests.swift deleted file mode 100644 index 433ae3c4d..000000000 --- a/Tests/OpenTelemetrySdkTests/Metrics/StableMetrics/NoopAttributesProcessorTests.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 -// - -import Foundation - -import OpenTelemetryApi -@testable import OpenTelemetrySdk -import XCTest - -class NoopAttributesProcessorTests : XCTestCase { - func testStaticNoop() { - XCTAssertNotNil(NoopAttributeProcessor.noop) - XCTAssertEqual(NoopAttributeProcessor.noop.process(incoming: ["hello": AttributeValue.string("world")]), ["hello" : AttributeValue.string("world")]) - } -}