From 372b74898ed11f533bd7697624e82957ee9dde7f Mon Sep 17 00:00:00 2001 From: Michal A Date: Thu, 2 Jul 2020 12:42:10 +0800 Subject: [PATCH 1/7] Generate trace ID in correct format (LocalLambda Server) --- .../Lambda+LocalServer.swift | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Sources/AWSLambdaRuntimeCore/Lambda+LocalServer.swift b/Sources/AWSLambdaRuntimeCore/Lambda+LocalServer.swift index 0d6a285b..979fb744 100644 --- a/Sources/AWSLambdaRuntimeCore/Lambda+LocalServer.swift +++ b/Sources/AWSLambdaRuntimeCore/Lambda+LocalServer.swift @@ -276,7 +276,7 @@ private enum LocalLambda { response.headers = [ (AmazonHeaders.requestID, self.requestID), (AmazonHeaders.invokedFunctionARN, "arn:aws:lambda:us-east-1:\(Int16.random(in: Int16.min ... Int16.max)):function:custom-runtime"), - (AmazonHeaders.traceID, "Root=\(Int16.random(in: Int16.min ... Int16.max));Parent=\(Int16.random(in: Int16.min ... Int16.max));Sampled=1"), + (AmazonHeaders.traceID, "Root=\(randomTraceID());Sampled=1"), (AmazonHeaders.deadline, "\(DispatchWallTime.distantFuture.millisSinceEpoch)"), ] return response @@ -294,5 +294,22 @@ private enum LocalLambda { case notReady case cantBind } + + static func randomTraceID() -> String { + // see: + // - [Generating trace IDs](https://docs.aws.amazon.com/xray/latest/devguide/xray-api-sendingdata.html#xray-api-traceids) + // - [Tracing header](https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-tracingheader) + // The version number, that is, 1. + let version: UInt = 1 + // The time of the original request, in Unix epoch time, in 8 hexadecimal digits. + let now = UInt32(DispatchWallTime.now().millisSinceEpoch / 1000) + let dateValue = String(now, radix: 16, uppercase: false) + let datePadding = String(repeating: "0", count: max(0, 8 - dateValue.count)) + // A 96-bit identifier for the trace, globally unique, in 24 hexadecimal digits. + let identifier = String(UInt64.random(in: UInt64.min ... UInt64.max) | 1 << 63, radix: 16, uppercase: false) + + String(UInt32.random(in: UInt32.min ... UInt32.max) | 1 << 31, radix: 16, uppercase: false) + return "\(version)-\(datePadding)\(dateValue)-\(identifier)" + } } + #endif From 76c7e25d7a2fa50bc712fa40b75852a44e73e0e9 Mon Sep 17 00:00:00 2001 From: Michal A Date: Thu, 2 Jul 2020 20:40:43 +0800 Subject: [PATCH 2/7] Move randomTraceID to Utils, rename to generateTraceID --- .../Lambda+LocalServer.swift | 18 +------------- Sources/AWSLambdaRuntimeCore/Utils.swift | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/Sources/AWSLambdaRuntimeCore/Lambda+LocalServer.swift b/Sources/AWSLambdaRuntimeCore/Lambda+LocalServer.swift index 979fb744..852b93b5 100644 --- a/Sources/AWSLambdaRuntimeCore/Lambda+LocalServer.swift +++ b/Sources/AWSLambdaRuntimeCore/Lambda+LocalServer.swift @@ -276,7 +276,7 @@ private enum LocalLambda { response.headers = [ (AmazonHeaders.requestID, self.requestID), (AmazonHeaders.invokedFunctionARN, "arn:aws:lambda:us-east-1:\(Int16.random(in: Int16.min ... Int16.max)):function:custom-runtime"), - (AmazonHeaders.traceID, "Root=\(randomTraceID());Sampled=1"), + (AmazonHeaders.traceID, "Root=\(generateTraceID());Sampled=1"), (AmazonHeaders.deadline, "\(DispatchWallTime.distantFuture.millisSinceEpoch)"), ] return response @@ -294,22 +294,6 @@ private enum LocalLambda { case notReady case cantBind } - - static func randomTraceID() -> String { - // see: - // - [Generating trace IDs](https://docs.aws.amazon.com/xray/latest/devguide/xray-api-sendingdata.html#xray-api-traceids) - // - [Tracing header](https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-tracingheader) - // The version number, that is, 1. - let version: UInt = 1 - // The time of the original request, in Unix epoch time, in 8 hexadecimal digits. - let now = UInt32(DispatchWallTime.now().millisSinceEpoch / 1000) - let dateValue = String(now, radix: 16, uppercase: false) - let datePadding = String(repeating: "0", count: max(0, 8 - dateValue.count)) - // A 96-bit identifier for the trace, globally unique, in 24 hexadecimal digits. - let identifier = String(UInt64.random(in: UInt64.min ... UInt64.max) | 1 << 63, radix: 16, uppercase: false) - + String(UInt32.random(in: UInt32.min ... UInt32.max) | 1 << 31, radix: 16, uppercase: false) - return "\(version)-\(datePadding)\(dateValue)-\(identifier)" - } } #endif diff --git a/Sources/AWSLambdaRuntimeCore/Utils.swift b/Sources/AWSLambdaRuntimeCore/Utils.swift index ae5db50f..cb9d57f7 100644 --- a/Sources/AWSLambdaRuntimeCore/Utils.swift +++ b/Sources/AWSLambdaRuntimeCore/Utils.swift @@ -104,3 +104,27 @@ extension String { bytes.append(UInt8(ascii: "\"")) } } + +/// Generates (X-Ray) trace ID. +/// # Trace ID Format +/// A `trace_id` consists of three numbers separated by hyphens. +/// For example, `1-58406520-a006649127e371903a2de979`. This includes: +/// - The version number, that is, 1. +/// - The time of the original request, in Unix epoch time, in **8 hexadecimal digits**. +/// For example, 10:00AM December 1st, 2016 PST in epoch time is `1480615200` seconds, or `58406520` in hexadecimal digits. +/// - A 96-bit identifier for the trace, globally unique, in **24 hexadecimal digits**. +/// # References +/// - [Generating trace IDs](https://docs.aws.amazon.com/xray/latest/devguide/xray-api-sendingdata.html#xray-api-traceids) +/// - [Tracing header](https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-tracingheader) +func generateTraceID() -> String { + // The version number, that is, 1. + let version: UInt = 1 + // The time of the original request, in Unix epoch time, in 8 hexadecimal digits. + let now = UInt32(DispatchWallTime.now().millisSinceEpoch / 1000) + let dateValue = String(now, radix: 16, uppercase: false) + let datePadding = String(repeating: "0", count: max(0, 8 - dateValue.count)) + // A 96-bit identifier for the trace, globally unique, in 24 hexadecimal digits. + let identifier = String(UInt64.random(in: UInt64.min ... UInt64.max) | 1 << 63, radix: 16, uppercase: false) + + String(UInt32.random(in: UInt32.min ... UInt32.max) | 1 << 31, radix: 16, uppercase: false) + return "\(version)-\(datePadding)\(dateValue)-\(identifier)" +} From 21aede061fd04566e17bfdac7e5e923bafd963d6 Mon Sep 17 00:00:00 2001 From: Michal A Date: Thu, 2 Jul 2020 20:41:08 +0800 Subject: [PATCH 3/7] Create generateTraceId test --- .../AWSLambdaRuntimeCoreTests/UtilsTest.swift | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 Tests/AWSLambdaRuntimeCoreTests/UtilsTest.swift diff --git a/Tests/AWSLambdaRuntimeCoreTests/UtilsTest.swift b/Tests/AWSLambdaRuntimeCoreTests/UtilsTest.swift new file mode 100644 index 00000000..d27749fa --- /dev/null +++ b/Tests/AWSLambdaRuntimeCoreTests/UtilsTest.swift @@ -0,0 +1,39 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftAWSLambdaRuntime open source project +// +// Copyright (c) 2017-2018 Apple Inc. and the SwiftAWSLambdaRuntime project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +@testable import AWSLambdaRuntimeCore +import XCTest + +class UtilsTest: XCTestCase { + func testGenerateTraceId() { + // the time and identifier should be in hexadecimal digits + let invalidCharacters = CharacterSet(charactersIn: "abcdef0123456789").inverted + let numTests = 1000 + var values = Set() + for _ in 0 ..< numTests { + // check the format, see https://docs.aws.amazon.com/xray/latest/devguide/xray-api-sendingdata.html#xray-api-traceids) + let traceId = generateTraceID() + let segments = traceId.split(separator: "-") + XCTAssertEqual(3, segments.count) + XCTAssertEqual("1", segments[0]) + XCTAssertEqual(8, segments[1].count) + XCTAssertNil(segments[1].rangeOfCharacter(from: invalidCharacters)) + XCTAssertEqual(24, segments[2].count) + XCTAssertNil(segments[2].rangeOfCharacter(from: invalidCharacters)) + values.insert(traceId) + } + // check that the generated values are different + XCTAssertEqual(values.count, numTests) + } +} From a59feb5b119cbb305e50b3cd56bc8a877ac13414 Mon Sep 17 00:00:00 2001 From: Michal A Date: Tue, 7 Jul 2020 15:06:54 +0800 Subject: [PATCH 4/7] Rename generateTraceID to AmazonHeaders::generateXRayTraceID --- .../Lambda+LocalServer.swift | 2 +- Sources/AWSLambdaRuntimeCore/Utils.swift | 47 ++++++++++--------- .../AWSLambdaRuntimeCoreTests/UtilsTest.swift | 2 +- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/Sources/AWSLambdaRuntimeCore/Lambda+LocalServer.swift b/Sources/AWSLambdaRuntimeCore/Lambda+LocalServer.swift index 852b93b5..f7e1b95a 100644 --- a/Sources/AWSLambdaRuntimeCore/Lambda+LocalServer.swift +++ b/Sources/AWSLambdaRuntimeCore/Lambda+LocalServer.swift @@ -276,7 +276,7 @@ private enum LocalLambda { response.headers = [ (AmazonHeaders.requestID, self.requestID), (AmazonHeaders.invokedFunctionARN, "arn:aws:lambda:us-east-1:\(Int16.random(in: Int16.min ... Int16.max)):function:custom-runtime"), - (AmazonHeaders.traceID, "Root=\(generateTraceID());Sampled=1"), + (AmazonHeaders.traceID, "Root=\(AmazonHeaders.generateXRayTraceID());Sampled=1"), (AmazonHeaders.deadline, "\(DispatchWallTime.distantFuture.millisSinceEpoch)"), ] return response diff --git a/Sources/AWSLambdaRuntimeCore/Utils.swift b/Sources/AWSLambdaRuntimeCore/Utils.swift index cb9d57f7..26fa8eb7 100644 --- a/Sources/AWSLambdaRuntimeCore/Utils.swift +++ b/Sources/AWSLambdaRuntimeCore/Utils.swift @@ -105,26 +105,29 @@ extension String { } } -/// Generates (X-Ray) trace ID. -/// # Trace ID Format -/// A `trace_id` consists of three numbers separated by hyphens. -/// For example, `1-58406520-a006649127e371903a2de979`. This includes: -/// - The version number, that is, 1. -/// - The time of the original request, in Unix epoch time, in **8 hexadecimal digits**. -/// For example, 10:00AM December 1st, 2016 PST in epoch time is `1480615200` seconds, or `58406520` in hexadecimal digits. -/// - A 96-bit identifier for the trace, globally unique, in **24 hexadecimal digits**. -/// # References -/// - [Generating trace IDs](https://docs.aws.amazon.com/xray/latest/devguide/xray-api-sendingdata.html#xray-api-traceids) -/// - [Tracing header](https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-tracingheader) -func generateTraceID() -> String { - // The version number, that is, 1. - let version: UInt = 1 - // The time of the original request, in Unix epoch time, in 8 hexadecimal digits. - let now = UInt32(DispatchWallTime.now().millisSinceEpoch / 1000) - let dateValue = String(now, radix: 16, uppercase: false) - let datePadding = String(repeating: "0", count: max(0, 8 - dateValue.count)) - // A 96-bit identifier for the trace, globally unique, in 24 hexadecimal digits. - let identifier = String(UInt64.random(in: UInt64.min ... UInt64.max) | 1 << 63, radix: 16, uppercase: false) - + String(UInt32.random(in: UInt32.min ... UInt32.max) | 1 << 31, radix: 16, uppercase: false) - return "\(version)-\(datePadding)\(dateValue)-\(identifier)" +extension AmazonHeaders { + /// Generates (X-Ray) trace ID. + /// # Trace ID Format + /// A `trace_id` consists of three numbers separated by hyphens. + /// For example, `1-58406520-a006649127e371903a2de979`. This includes: + /// - The version number, that is, 1. + /// - The time of the original request, in Unix epoch time, in **8 hexadecimal digits**. + /// For example, 10:00AM December 1st, 2016 PST in epoch time is `1480615200` seconds, or `58406520` in hexadecimal digits. + /// - A 96-bit identifier for the trace, globally unique, in **24 hexadecimal digits**. + /// # References + /// - [Generating trace IDs](https://docs.aws.amazon.com/xray/latest/devguide/xray-api-sendingdata.html#xray-api-traceids) + /// - [Tracing header](https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-tracingheader) + @inlinable + internal static func generateXRayTraceID() -> String { + // The version number, that is, 1. + let version: UInt = 1 + // The time of the original request, in Unix epoch time, in 8 hexadecimal digits. + let now = UInt32(DispatchWallTime.now().millisSinceEpoch / 1000) + let dateValue = String(now, radix: 16, uppercase: false) + let datePadding = String(repeating: "0", count: max(0, 8 - dateValue.count)) + // A 96-bit identifier for the trace, globally unique, in 24 hexadecimal digits. + let identifier = String(UInt64.random(in: UInt64.min ... UInt64.max) | 1 << 63, radix: 16, uppercase: false) + + String(UInt32.random(in: UInt32.min ... UInt32.max) | 1 << 31, radix: 16, uppercase: false) + return "\(version)-\(datePadding)\(dateValue)-\(identifier)" + } } diff --git a/Tests/AWSLambdaRuntimeCoreTests/UtilsTest.swift b/Tests/AWSLambdaRuntimeCoreTests/UtilsTest.swift index d27749fa..d026c577 100644 --- a/Tests/AWSLambdaRuntimeCoreTests/UtilsTest.swift +++ b/Tests/AWSLambdaRuntimeCoreTests/UtilsTest.swift @@ -23,7 +23,7 @@ class UtilsTest: XCTestCase { var values = Set() for _ in 0 ..< numTests { // check the format, see https://docs.aws.amazon.com/xray/latest/devguide/xray-api-sendingdata.html#xray-api-traceids) - let traceId = generateTraceID() + let traceId = AmazonHeaders.generateXRayTraceID() let segments = traceId.split(separator: "-") XCTAssertEqual(3, segments.count) XCTAssertEqual("1", segments[0]) From e99002920cdc265ce1f36695c6cfd63ba6e73ded Mon Sep 17 00:00:00 2001 From: Michal A Date: Tue, 7 Jul 2020 15:17:30 +0800 Subject: [PATCH 5/7] Generate XRay trace ID in LambdaRuntimeClientTest --- Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift | 4 ++-- Tests/AWSLambdaRuntimeCoreTests/MockLambdaServer.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift b/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift index 728672e6..94c8ac62 100644 --- a/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift +++ b/Tests/AWSLambdaRuntimeCoreTests/LambdaRuntimeClientTest.swift @@ -257,7 +257,7 @@ class LambdaRuntimeClientTest: XCTestCase { (AmazonHeaders.requestID, "test"), (AmazonHeaders.deadline, String(Date(timeIntervalSinceNow: 60).millisSinceEpoch)), (AmazonHeaders.invokedFunctionARN, "arn:aws:lambda:us-east-1:123456789012:function:custom-runtime"), - (AmazonHeaders.traceID, "Root=1-5bef4de7-ad49b0e87f6ef6c87fc2e700;Parent=9a9197af755a6419;Sampled=1"), + (AmazonHeaders.traceID, "Root=\(AmazonHeaders.generateXRayTraceID());Sampled=1"), ]) var inv: Lambda.Invocation? XCTAssertNoThrow(inv = try Lambda.Invocation(headers: header)) @@ -297,7 +297,7 @@ class LambdaRuntimeClientTest: XCTestCase { (AmazonHeaders.requestID, "test"), (AmazonHeaders.deadline, String(Date(timeIntervalSinceNow: 60).millisSinceEpoch)), (AmazonHeaders.invokedFunctionARN, "arn:aws:lambda:us-east-1:123456789012:function:custom-runtime"), - (AmazonHeaders.traceID, "Root=1-5bef4de7-ad49b0e87f6ef6c87fc2e700;Parent=9a9197af755a6419;Sampled=1"), + (AmazonHeaders.traceID, "Root=\(AmazonHeaders.generateXRayTraceID());Sampled=1"), ]) var inv: Lambda.Invocation? XCTAssertNoThrow(inv = try Lambda.Invocation(headers: header)) diff --git a/Tests/AWSLambdaRuntimeCoreTests/MockLambdaServer.swift b/Tests/AWSLambdaRuntimeCoreTests/MockLambdaServer.swift index b2f671a6..9708ccc1 100644 --- a/Tests/AWSLambdaRuntimeCoreTests/MockLambdaServer.swift +++ b/Tests/AWSLambdaRuntimeCoreTests/MockLambdaServer.swift @@ -144,7 +144,7 @@ internal final class HTTPHandler: ChannelInboundHandler { responseHeaders = [ (AmazonHeaders.requestID, requestId), (AmazonHeaders.invokedFunctionARN, "arn:aws:lambda:us-east-1:123456789012:function:custom-runtime"), - (AmazonHeaders.traceID, "Root=1-5bef4de7-ad49b0e87f6ef6c87fc2e700;Parent=9a9197af755a6419;Sampled=1"), + (AmazonHeaders.traceID, "Root=\(AmazonHeaders.generateXRayTraceID());Sampled=1"), (AmazonHeaders.deadline, String(deadline)), ] case .failure(let error): From ee79bfd4169e09e9b062a4e922c54b02a1ad3fca Mon Sep 17 00:00:00 2001 From: Michal A Date: Tue, 7 Jul 2020 15:25:40 +0800 Subject: [PATCH 6/7] Rename testGenerateTraceId to match tested function name --- Tests/AWSLambdaRuntimeCoreTests/UtilsTest.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/AWSLambdaRuntimeCoreTests/UtilsTest.swift b/Tests/AWSLambdaRuntimeCoreTests/UtilsTest.swift index d026c577..c5fc4ab5 100644 --- a/Tests/AWSLambdaRuntimeCoreTests/UtilsTest.swift +++ b/Tests/AWSLambdaRuntimeCoreTests/UtilsTest.swift @@ -16,7 +16,7 @@ import XCTest class UtilsTest: XCTestCase { - func testGenerateTraceId() { + func testGenerateXRayTraceID() { // the time and identifier should be in hexadecimal digits let invalidCharacters = CharacterSet(charactersIn: "abcdef0123456789").inverted let numTests = 1000 From cefb7bc5c35ee56d99d705c3f4a590c6bfd4d178 Mon Sep 17 00:00:00 2001 From: Michal A Date: Wed, 8 Jul 2020 08:59:13 +0800 Subject: [PATCH 7/7] Remove @inlinable from generateXRayTraceID --- Sources/AWSLambdaRuntimeCore/Utils.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Sources/AWSLambdaRuntimeCore/Utils.swift b/Sources/AWSLambdaRuntimeCore/Utils.swift index 26fa8eb7..5e7ffa6e 100644 --- a/Sources/AWSLambdaRuntimeCore/Utils.swift +++ b/Sources/AWSLambdaRuntimeCore/Utils.swift @@ -117,7 +117,6 @@ extension AmazonHeaders { /// # References /// - [Generating trace IDs](https://docs.aws.amazon.com/xray/latest/devguide/xray-api-sendingdata.html#xray-api-traceids) /// - [Tracing header](https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-tracingheader) - @inlinable internal static func generateXRayTraceID() -> String { // The version number, that is, 1. let version: UInt = 1