Skip to content

Commit

Permalink
added http metric compression
Browse files Browse the repository at this point in the history
  • Loading branch information
mamunto committed Nov 6, 2024
1 parent 784a4e6 commit 09e14b1
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//

import DataCompression
import Foundation
import OpenTelemetryProtocolExporterCommon
import SwiftProtobuf
Expand Down Expand Up @@ -44,14 +45,34 @@ public class StableOtlpHTTPExporterBase {
}

do {
let rawData = try body.serializedData()
request.httpMethod = "POST"
request.httpBody = try body.serializedData()
request.setValue(Headers.getUserAgentHeader(), forHTTPHeaderField: Constants.HTTP.userAgent)
request.setValue("application/x-protobuf", forHTTPHeaderField: "Content-Type")

var compressedData = rawData
switch config.compression {
case .gzip:
if let data = rawData.gzip() {
compressedData = data
request.setValue("gzip", forHTTPHeaderField: "Content-Encoding")
}

case .deflate:
if let data = rawData.deflate() {
compressedData = data
request.setValue("deflate", forHTTPHeaderField: "Content-Encoding")
}

case .none:
break
}
// Apply final data. Could be compressed or raw
// but it doesn't matter here
request.httpBody = compressedData
} catch {
print("Error serializing body: \(error)")
}

return request
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
//
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
//

import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
import Logging
import NIO
import NIOHTTP1
import NIOTestUtils
import OpenTelemetryApi
import OpenTelemetryProtocolExporterCommon
import DataCompression
@testable import OpenTelemetryProtocolExporterHttp
@testable import OpenTelemetrySdk
import XCTest

class StableOtlpHTTPExporterBaseTests: XCTestCase {

var exporter: StableOtlpHTTPExporterBase!
var spans: [SpanData] = []

override func setUp() {
super.setUp()

spans = []
let endpointName1 = "/api/foo" + String(Int.random(in: 1...100))
let endpointName2 = "/api/bar" + String(Int.random(in: 100...500))
spans.append(generateFakeSpan(endpointName: endpointName1))
spans.append(generateFakeSpan(endpointName: endpointName2))
}

// Test for .gzip compression
func testCreateRequestWithGzipCompression() {
let config = OtlpConfiguration(compression: .gzip)

exporter = StableOtlpHTTPExporterBase(
endpoint: URL(string: "http://example.com")!,
config: config
)

let body = Opentelemetry_Proto_Collector_Trace_V1_ExportTraceServiceRequest.with {
$0.resourceSpans = SpanAdapter.toProtoResourceSpans(spanDataList: spans)
}

let request = exporter.createRequest(body: body, endpoint: URL(string: "http://example.com")!)

/// gzip
let data = try! body.serializedData().gzip()

// Verify Content-Encoding header is set to "gzip"
XCTAssertEqual(request.value(forHTTPHeaderField: "Content-Encoding"), "gzip")
XCTAssertNotNil(request.httpBody)
XCTAssertEqual(request.httpBody!.count, data!.count)
}

// Test for .deflate compression
func testCreateRequestWithDeflateCompression() {
let config = OtlpConfiguration(compression: .deflate)

exporter = StableOtlpHTTPExporterBase(
endpoint: URL(string: "http://example.com")!,
config: config
)

let body = Opentelemetry_Proto_Collector_Trace_V1_ExportTraceServiceRequest.with {
$0.resourceSpans = SpanAdapter.toProtoResourceSpans(spanDataList: spans)
}

let request = exporter.createRequest(body: body, endpoint: URL(string: "http://example.com")!)

/// deflate
let data = try! body.serializedData().deflate()

// Verify Content-Encoding header is set to "deflate"
XCTAssertEqual(request.value(forHTTPHeaderField: "Content-Encoding"), "deflate")
XCTAssertNotNil(request.httpBody)
XCTAssertEqual(request.httpBody!.count, data!.count)
}

// Test for .none compression (no compression)
func testCreateRequestWithNoCompression() {
let config = OtlpConfiguration(compression: .none)

exporter = StableOtlpHTTPExporterBase(
endpoint: URL(string: "http://example.com")!,
config: config
)

let body = Opentelemetry_Proto_Collector_Trace_V1_ExportTraceServiceRequest.with {
$0.resourceSpans = SpanAdapter.toProtoResourceSpans(spanDataList: spans)
}

let request = exporter.createRequest(body: body, endpoint: URL(string: "http://example.com")!)

let data = try! body.serializedData()

// Verify Content-Encoding header is set to "deflate"
XCTAssertEqual(request.value(forHTTPHeaderField: "Content-Encoding"), nil)
XCTAssertNotNil(request.httpBody)
XCTAssertEqual(request.httpBody!.count, data.count)
}

private func generateFakeSpan(endpointName: String = "/api/endpoint") -> SpanData {
let duration = 0.9
let start = Date()
let end = start.addingTimeInterval(duration)
let testattributes: [String: AttributeValue] = ["foo": AttributeValue("bar")!, "fizz": AttributeValue("buzz")!]

var testData = SpanData(traceId: TraceId.random(),
spanId: SpanId.random(),
name: "GET " + endpointName,
kind: SpanKind.server,
startTime: start,
endTime: end,
totalAttributeCount: 2)
testData.settingAttributes(testattributes)
testData.settingTotalAttributeCount(2)
testData.settingHasEnded(true)
testData.settingTotalRecordedEvents(0)
testData.settingLinks([SpanData.Link]())
testData.settingTotalRecordedLinks(0)
testData.settingStatus(.ok)

return testData
}
}

0 comments on commit 09e14b1

Please sign in to comment.