diff --git a/Sources/Hummingbird/Application.swift b/Sources/Hummingbird/Application.swift index b42961232..9785d583d 100644 --- a/Sources/Hummingbird/Application.swift +++ b/Sources/Hummingbird/Application.swift @@ -12,7 +12,6 @@ // //===----------------------------------------------------------------------===// -import Atomics import HummingbirdCore import Logging import NIOCore @@ -145,8 +144,7 @@ extension HBApplicationProtocol { } public func loggerWithRequestId(_ logger: Logger) -> Logger { - let requestId = globalRequestID.loadThenWrappingIncrement(by: 1, ordering: .relaxed) - return logger.with(metadataKey: "hb_id", value: .stringConvertible(requestId)) + return logger.with(metadataKey: "hb_id", value: .stringConvertible(RequestID())) } /// Application class. Brings together all the components of Hummingbird together @@ -238,6 +236,3 @@ extension Logger { return logger } } - -/// Current global request ID -private let globalRequestID = ManagedAtomic(0) diff --git a/Sources/Hummingbird/Server/RequestID.swift b/Sources/Hummingbird/Server/RequestID.swift new file mode 100644 index 000000000..86a75d3f3 --- /dev/null +++ b/Sources/Hummingbird/Server/RequestID.swift @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Hummingbird server framework project +// +// Copyright (c) 2023-2024 the Hummingbird authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See hummingbird/CONTRIBUTORS.txt for the list of Hummingbird authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +import Atomics + +/// Generate Unique ID for each request +struct RequestID: CustomStringConvertible { + let low: UInt64 + + init() { + self.low = Self.globalRequestID.loadThenWrappingIncrement(by: 1, ordering: .relaxed) + } + + var description: String { + Self.high + self.formatAsHexWithLeadingZeros(self.low) + } + + func formatAsHexWithLeadingZeros(_ value: UInt64) -> String { + let string = String(value, radix: 16) + if string.count < 16 { + return String(repeating: "0", count: 16 - string.count) + string + } else { + return string + } + } + + private static let high = String(UInt64.random(in: .min ... .max), radix: 16) + private static let globalRequestID = ManagedAtomic(UInt64.random(in: .min ... .max)) +} diff --git a/Tests/HummingbirdRouterTests/RouterTests.swift b/Tests/HummingbirdRouterTests/RouterTests.swift index 500e9b1ad..6d3007cb2 100644 --- a/Tests/HummingbirdRouterTests/RouterTests.swift +++ b/Tests/HummingbirdRouterTests/RouterTests.swift @@ -399,15 +399,14 @@ final class RouterTests: XCTestCase { } let app = HBApplication(responder: router) try await app.test(.router) { client in - let idString = try await client.XCTExecute(uri: "/id", method: .get) { response -> String in + let id = try await client.XCTExecute(uri: "/id", method: .get) { response -> String in let body = try XCTUnwrap(response.body) return String(buffer: body) } - let id = try XCTUnwrap(Int(idString)) try await client.XCTExecute(uri: "/id", method: .get) { response in let body = try XCTUnwrap(response.body) - let id2 = Int(String(buffer: body)) - XCTAssertEqual(id2, id + 1) + let id2 = String(buffer: body) + XCTAssertNotEqual(id2, id) } } } diff --git a/Tests/HummingbirdTests/RouterTests.swift b/Tests/HummingbirdTests/RouterTests.swift index 15d571309..6aaa3fbd4 100644 --- a/Tests/HummingbirdTests/RouterTests.swift +++ b/Tests/HummingbirdTests/RouterTests.swift @@ -341,15 +341,14 @@ final class RouterTests: XCTestCase { } let app = HBApplication(responder: router.buildResponder()) try await app.test(.router) { client in - let idString = try await client.XCTExecute(uri: "/id", method: .get) { response -> String in + let id = try await client.XCTExecute(uri: "/id", method: .get) { response -> String in let body = try XCTUnwrap(response.body) return String(buffer: body) } - let id = try XCTUnwrap(Int(idString)) try await client.XCTExecute(uri: "/id", method: .get) { response in let body = try XCTUnwrap(response.body) - let id2 = Int(String(buffer: body)) - XCTAssertEqual(id2, id + 1) + let id2 = String(buffer: body) + XCTAssertNotEqual(id, id2) } } }