From 1373c5d00635f86875e41846f015ea3382070c07 Mon Sep 17 00:00:00 2001 From: Vladimir Kukushkin Date: Wed, 2 Sep 2026 09:59:21 +0100 Subject: [PATCH 01/11] move ServiceContext from SSC to SDT --- Package.swift | 10 +- .../CompatibilityShim.swift | 18 ++ .../Reference/AnyServiceContextKey.md | 8 - .../Docs.docc/Reference/ServiceContext.md | 28 -- .../Docs.docc/Reference/ServiceContextKey.md | 8 - .../ServiceContextModule/Docs.docc/index.md | 4 + .../ServiceContextModule/ServiceContext.swift | 287 ------------------ .../ServiceContextKey.swift | 110 ------- .../CompatibilityShimTests.swift | 47 +++ .../ServiceContextTests.swift | 155 ---------- 10 files changed, 78 insertions(+), 597 deletions(-) create mode 100644 Sources/ServiceContextModule/CompatibilityShim.swift delete mode 100644 Sources/ServiceContextModule/Docs.docc/Reference/AnyServiceContextKey.md delete mode 100644 Sources/ServiceContextModule/Docs.docc/Reference/ServiceContext.md delete mode 100644 Sources/ServiceContextModule/Docs.docc/Reference/ServiceContextKey.md delete mode 100644 Sources/ServiceContextModule/ServiceContext.swift delete mode 100644 Sources/ServiceContextModule/ServiceContextKey.swift create mode 100644 Tests/ServiceContextTests/CompatibilityShimTests.swift delete mode 100644 Tests/ServiceContextTests/ServiceContextTests.swift diff --git a/Package.swift b/Package.swift index 361772c..242ee67 100644 --- a/Package.swift +++ b/Package.swift @@ -20,8 +20,16 @@ let package = Package( ] ), ], + dependencies: [ + .package(url: "https://github.com/kukushechkin/swift-distributed-tracing.git", branch: "move-service-context-to-sdt") + ], targets: [ - .target(name: "ServiceContextModule"), + .target( + name: "ServiceContextModule", + dependencies: [ + .product(name: "ServiceContextCore", package: "swift-distributed-tracing") + ] + ), // Deprecated/legacy module .target( diff --git a/Sources/ServiceContextModule/CompatibilityShim.swift b/Sources/ServiceContextModule/CompatibilityShim.swift new file mode 100644 index 0000000..e965525 --- /dev/null +++ b/Sources/ServiceContextModule/CompatibilityShim.swift @@ -0,0 +1,18 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift Service Context open source project +// +// Copyright (c) 2020-2026 Apple Inc. and the Swift Service Context project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift Service Context project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +// `ServiceContext` now lives in the `swift-distributed-tracing` package's `ServiceContextCore` module. +// This module re-exports it under its original name so `import ServiceContextModule` keeps working +// unchanged for existing dependents of this package. +@_exported import ServiceContextCore diff --git a/Sources/ServiceContextModule/Docs.docc/Reference/AnyServiceContextKey.md b/Sources/ServiceContextModule/Docs.docc/Reference/AnyServiceContextKey.md deleted file mode 100644 index d036f03..0000000 --- a/Sources/ServiceContextModule/Docs.docc/Reference/AnyServiceContextKey.md +++ /dev/null @@ -1,8 +0,0 @@ -# ``ServiceContextModule/AnyServiceContextKey`` - -## Topics - -### Inspecting a generic service context key - -- ``name`` -- ``keyType`` diff --git a/Sources/ServiceContextModule/Docs.docc/Reference/ServiceContext.md b/Sources/ServiceContextModule/Docs.docc/Reference/ServiceContext.md deleted file mode 100644 index bec7bb9..0000000 --- a/Sources/ServiceContextModule/Docs.docc/Reference/ServiceContext.md +++ /dev/null @@ -1,28 +0,0 @@ -# ``ServiceContextModule/ServiceContext`` - -## Topics - -### Accessing the current service context - -- ``current`` -- ``withValue(_:operation:)-4f7xo`` -- ``withValue(_:isolation:operation:)`` -- ``TODO(_:function:file:line:)`` -- ``withValue(_:operation:)-3tddk`` - -### Creating a new top-level service context - -- ``topLevel`` - -### Inspecting a service context - -- ``count`` -- ``isEmpty`` - -### Accessing values from a service context - -- ``subscript(_:)`` - -### Iterating a service context - -- ``forEach(_:)`` diff --git a/Sources/ServiceContextModule/Docs.docc/Reference/ServiceContextKey.md b/Sources/ServiceContextModule/Docs.docc/Reference/ServiceContextKey.md deleted file mode 100644 index 4814015..0000000 --- a/Sources/ServiceContextModule/Docs.docc/Reference/ServiceContextKey.md +++ /dev/null @@ -1,8 +0,0 @@ -# ``ServiceContextModule/ServiceContextKey`` - -## Topics - -### Inspecting a service context key - -- ``nameOverride`` -- ``Value`` diff --git a/Sources/ServiceContextModule/Docs.docc/index.md b/Sources/ServiceContextModule/Docs.docc/index.md index 60e3bc4..2280a1c 100644 --- a/Sources/ServiceContextModule/Docs.docc/index.md +++ b/Sources/ServiceContextModule/Docs.docc/index.md @@ -18,6 +18,10 @@ More information can be found in the > Note: Automatic propagation through task-locals by using `ServiceContext.current` is supported in Swift version 5.5 or later. +> Note: `ServiceContext` itself is implemented in the `swift-distributed-tracing` package's `ServiceContextCore` +> module. This package re-exports it under the `ServiceContextModule` name so existing dependents keep working +> unchanged. New code that also needs tracing spans should depend on `Tracing` directly. + ## Getting started In order to depend on this library you can use the Swift Package Manager, and add the following dependency to your `Package.swift`: diff --git a/Sources/ServiceContextModule/ServiceContext.swift b/Sources/ServiceContextModule/ServiceContext.swift deleted file mode 100644 index d4c1407..0000000 --- a/Sources/ServiceContextModule/ServiceContext.swift +++ /dev/null @@ -1,287 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift Service Context open source project -// -// Copyright (c) 2020-2022 Apple Inc. and the Swift Service Context project authors -// Licensed under Apache License v2.0 -// -// See LICENSE.txt for license information -// See CONTRIBUTORS.txt for the list of Swift Service Context project authors -// -// SPDX-License-Identifier: Apache-2.0 -// -//===----------------------------------------------------------------------===// - -/// A Service Context is a heterogeneous storage type with value semantics that provides keyed values in a type-safe fashion. -/// -/// Its values are uniquely identified with ``ServiceContextKey``, by type identity. -/// These keys also dictate the type of value allowed for a specific key-value pair through their associated type `Value`. -/// -/// ### Defining keys and accessing values -/// Define ``ServiceContext`` keys as types which conform to the ``ServiceContextKey`` protocol: -/// Specify the types using case-less enums as no actual instances are required. -/// -/// ```swift -/// private enum TestIDKey: ServiceContextKey { -/// typealias Value = String -/// } -/// ``` -/// -/// When defining a key, also declare an extension on `ServiceContext` to allow convenient and discoverable ways to interact -/// with the context item. The extension should take the form of: -/// -/// ```swift -/// extension ServiceContext { -/// var testID: String? { -/// get { -/// self[TestIDKey.self] -/// } set { -/// self[TestIDKey.self] = newValue -/// } -/// } -/// } -/// ``` -/// -/// For consistency, name key types with a `...Key` suffix (for example, `SomethingKey`) and the property -/// used to access a value identifier by such key the prefix of the key (for example `something`). -/// Please also observe the usual Swift naming conventions, such as prefering `ID` to `Id`, and so on. -/// -/// ### Usage -/// Using a context container is fairly straight forward, as it boils down to using the prepared computed properties: -/// -/// ```swift -/// var context = ServiceContext.topLevel -/// -/// // set a new value -/// context.testID = "abc" -/// -/// // retrieve a stored value -/// let testID = context.testID ?? "default" -/// -/// // remove a stored value -/// context.testIDKey = nil -/// ``` -/// -/// Note that normally a context should not be "created" ad-hoc by user code, but rather passed to it from -/// a runtime. A `ServiceContext` may already be available to you through `ServiceContext.$current` when using structured concurrency. -/// Otherwise, for example when working in an HTTP server framework, it is most likely that the context is already passed -/// directly or indirectly (such as in a `FrameworkContext`). -/// -/// ### Accessing all values -/// -/// The only way to access "all" values in a context is the `forEach` function. -/// `ServiceContext` intentionally doesn't expose more functions to prevent abuse and developers treating it as too much of an -/// arbitrary value smuggling container. -/// This makes it convenient for tracing and instrumentation systems which need to access either specific or all items carried inside a context. -public struct ServiceContext: Sendable { - private var _storage = [AnyServiceContextKey: Sendable]() - - /// Internal on purpose, please use ``ServiceContext/TODO(_:function:file:line:)`` or ``ServiceContext/topLevel`` to create an "empty" context, - /// which carries more meaning to other developers why an empty context was used. - init() {} -} - -// MARK: - Creating ServiceContext - -extension ServiceContext { - /// Creates a new empty top level context. - /// - /// Generally used as an initial context to immediately be populated with some values by a framework or runtime. - /// - /// Another use case is for tasks starting in the "background" (such as on a timer), - /// which don't have a "request context" that they can pick up, and as such they have to create a "top level" - /// context for their work. - /// - /// ### Usage in frameworks and libraries - /// This function is intended to be used by frameworks and libraries, at the "top-level" where a request's, - /// message's, or task's processing is initiated. For example, a framework handling requests should create an empty - /// context when handling a request and immediately populate it with useful trace information extracted from a carrier, - /// such as an HTTP request and the request's headers. - /// - /// ### Usage in applications - /// Application code should never have to create an empty context during the processing lifetime of any request, - /// and only create context if some processing is performed in the background - thus the naming of this property. - /// - /// Usually, a framework such as an HTTP server or similar "request handler" would already provide users - /// with a context to pass along through subsequent calls, either implicitly through the task-local `ServiceContext.$current` - /// or explicitly as part of some kind of "FrameworkContext". - /// - /// If you are unsure where to obtain a context from, prefer using `.TODO("Not sure where I should get a context from here?")` - /// in order to inform other developers that the lack of context passing was not done on purpose, but rather because you either - /// weren't sure where to obtain a context from, or other framework limitations -- for example the outer framework not being - /// context aware just yet. - public static var topLevel: ServiceContext { - ServiceContext() - } -} - -extension ServiceContext { - /// A context intended as a placeholder until a real value can be passed through a function call. - /// - /// This type should ONLY be used while prototyping or when the passing of the proper context is not yet possible, - /// for example because an external library did not pass it correctly and has to be fixed before the proper context - /// can be obtained where the TO-DO is currently used. - /// - /// ### Crashing on TO-DO context creation - /// You may set the `SERVICE_CONTEXT_CRASH_TODOS` swift definition while compiling a project in order to make calls to this function crash - /// with a fatal error, which indicates where a to-do context is used. This comes in handy when you want to ensure that - /// a project never ends up using code which initially was written as "was lazy, did not pass context", yet the - /// project requires context passing to be done correctly throughout the application. Similar checks can be performed - /// at compile time easily using linters (not yet implemented), since it is always valid enough to detect a to-do context - /// being passed as illegal and warn or error when spotted. - /// - /// ### Example - /// - /// ```swift - /// let context = ServiceContext.TODO("The framework XYZ should be modified to pass us a context here, and we'd pass it along")) - /// ``` - /// - /// - Parameters: - /// - reason: Informational reason for developers, why a placeholder context was used instead of a proper one. - /// - function: The function to which the TODO refers. - /// - file: The file to which the TODO refers. - /// - line: The line to which the TODO refers. - /// - Returns: Empty "to-do" context which should be eventually replaced with a carried through one, or `topLevel`. - public static func TODO( - _ reason: StaticString? = "", - function: String = #function, - file: String = #file, - line: UInt = #line - ) -> ServiceContext { - var context = ServiceContext() - #if BAGGAGE_CRASH_TODOS - fatalError("BAGGAGE_CRASH_TODOS: at \(file):\(line) (function \(function)), reason: \(reason)") - #elseif SERVICE_CONTEXT_CRASH_TODOS - fatalError("SERVICE_CONTEXT_CRASH_TODOS: at \(file):\(line) (function \(function)), reason: \(reason)") - #else - context[TODOKey.self] = .init(file: file, line: line) - return context - #endif - } - - private enum TODOKey: ServiceContextKey { - typealias Value = TODOLocation - static var nameOverride: String? { - "todo" - } - } -} - -/// Carried automatically by a "to do" context. -/// -/// It can be used to track where a context originated and which "to do" context must be fixed into a real one to avoid this. -public struct TODOLocation: Sendable { - /// Source file location where the to-do ``ServiceContext`` was created - public let file: String - /// Source line location where the to-do ``ServiceContext`` was created - public let line: UInt -} - -// MARK: - Interacting with ServiceContext - -extension ServiceContext { - /// Provides type-safe access to the context's values. - /// - /// > Note: This API should ONLY be used inside of accessor implementations. - /// - /// End users should use "accessors" the key's author MUST define rather than using this subscript, following this pattern: - /// - /// ```swift - /// internal enum TestID: ServiceContext.Key { - /// typealias Value = TestID - /// } - /// - /// extension ServiceContext { - /// public internal(set) var testID: TestID? { - /// get { - /// self[TestIDKey.self] - /// } - /// set { - /// self[TestIDKey.self] = newValue - /// } - /// } - /// } - /// ``` - /// - /// This is in order to enforce a consistent style across projects and also allow for fine grained control over - /// who may set and who may get such property. Just access control to the Key type itself lacks sufficient fidelity. - /// - /// Specific context and context types may, and usually do, also offer a way to set context values. - /// However in the most general case it is not required, as some frameworks may only be able to offer reading. - public subscript(_ key: Key.Type) -> Key.Value? { - get { - guard let value = self._storage[AnyServiceContextKey(key)] else { return nil } - // safe to force-cast as this subscript is the only way to set a value. - return (value as! Key.Value) - } - set { - self._storage[AnyServiceContextKey(key)] = newValue - } - } -} - -extension ServiceContext { - /// The number of items in the context. - public var count: Int { - self._storage.count - } - - /// A Boolean value that indicates whether the context is empty. - public var isEmpty: Bool { - self._storage.isEmpty - } - - /// Iterate through all items in this service context by invoking the given closure for each item. - /// - /// The order of those invocations is NOT guaranteed and should not be relied on. - /// - /// - Parameter body: The closure to be invoked for each item stored in this `ServiceContext`, - /// passing the type-erased key and the associated value. - @preconcurrency - public func forEach(_ body: (AnyServiceContextKey, any Sendable) throws -> Void) rethrows { - // swift-format-ignore: ReplaceForEachWithForLoop - try self._storage.forEach { key, value in - try body(key, value) - } - } -} - -// MARK: - Propagating ServiceContext - -@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) -extension ServiceContext { - /// A Service Context is automatically propagated through task-local storage. - /// - /// This API enables binding a top-level `ServiceContext` and - /// implicitly passes it to child tasks when using structured concurrency. - @TaskLocal public static var current: ServiceContext? - - /// Bind the task-local ``ServiceContext/current`` to the passed `value`, and execute the passed `operation`. - /// - /// To access the task-local value, use `ServiceContext.current`. - /// - /// SeeAlso: [Swift Task Locals](https://developer.apple.com/documentation/swift/tasklocal) - public static func withValue(_ value: ServiceContext?, operation: () throws -> T) rethrows -> T { - try ServiceContext.$current.withValue(value, operation: operation) - } - - /// Bind the task-local ``ServiceContext/current`` to the passed `value`, and execute the passed `operation`. - /// - /// To access the task-local value, use `ServiceContext.current`. - /// - /// SeeAlso: [Swift Task Locals](https://developer.apple.com/documentation/swift/tasklocal) - public static func withValue( - _ value: ServiceContext?, - isolation: isolated (any Actor)? = #isolation, - operation: () async throws -> T - ) async rethrows -> T { - try await ServiceContext.$current.withValue(value, operation: { try await operation() }) - } - - @available(*, deprecated, message: "Use the method with the isolation parameter instead.") - // Deprecated trick to avoid executor hop here; 6.0 introduces the proper replacement: #isolation - @_disfavoredOverload - public static func withValue(_ value: ServiceContext?, operation: () async throws -> T) async rethrows -> T { - try await ServiceContext.$current.withValue(value, operation: operation) - } -} diff --git a/Sources/ServiceContextModule/ServiceContextKey.swift b/Sources/ServiceContextModule/ServiceContextKey.swift deleted file mode 100644 index 96234aa..0000000 --- a/Sources/ServiceContextModule/ServiceContextKey.swift +++ /dev/null @@ -1,110 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift Service Context open source project -// -// Copyright (c) 2020-2022 Apple Inc. and the Swift Service Context project authors -// Licensed under Apache License v2.0 -// -// See LICENSE.txt for license information -// See CONTRIBUTORS.txt for the list of Swift Service Context project authors -// -// SPDX-License-Identifier: Apache-2.0 -// -//===----------------------------------------------------------------------===// - -/// Context keys provide type-safe access to service contexts by declaring the type of value they key at compile-time. -/// -/// To give your `ServiceContextKey` an explicit name, override the ``ServiceContextKey/nameOverride-6shk1`` property. -/// -/// In general, any `ServiceContextKey` should be `internal` or `private` to the part of a system using it. -/// -/// All access to context items should be performed through an accessor computed property you define as shown below: -/// -/// ```swift -/// /// The Key type should be internal (or private). -/// enum TestIDKey: ServiceContextKey { -/// typealias Value = String -/// static var nameOverride: String? { "test-id" } -/// } -/// -/// extension ServiceContext { -/// /// This is some useful property documentation. -/// public internal(set) var testID: String? { -/// get { -/// self[TestIDKey.self] -/// } -/// set { -/// self[TestIDKey.self] = newValue -/// } -/// } -/// } -/// ``` -/// -/// This pattern allows library authors fine-grained control over which values may be set, and which only get by end-users. -public protocol ServiceContextKey: Sendable { - /// The type of value uniquely identified by this key. - associatedtype Value: Sendable - - /// The human-readable name of this key. - /// - /// This name will be used instead of the type name when a value is printed. - /// - /// It MAY also be picked up by an instrument (from Swift Tracing) which serializes context items, such as used as - /// header name for carried metadata. Though generally speaking header names are NOT required to use the nameOverride, - /// and MAY use their well known names for header names and so on, as it depends on the specific transport and instrument used. - /// - /// For example, a context key representing the W3C "trace-state" header may want to return "trace-state" here, - /// in order to achieve a consistent look and feel of this context item throughout logging and tracing systems. - /// - /// Defaults to `nil`. - static var nameOverride: String? { get } -} - -extension ServiceContextKey { - /// A human-readable name to use for this key instead of the type name. - public static var nameOverride: String? { nil } - - /// A human-readable String representation of the underlying key. - /// - /// If no explicit name is returned by `nameOverride`, the type name is used. - public static var name: String { AnyServiceContextKey(self).name } -} - -/// A type-erased service context key that you use when iterating through the service context. -/// -/// Iterate through a ``ServiceContext`` using its ``ServiceContext/forEach(_:)`` method. -public struct AnyServiceContextKey: Sendable { - /// The key's type erased to `Any.Type`. - public let keyType: Any.Type - - private let _nameOverride: String? - - /// A human-readable String representation of the underlying key. - /// - /// If no explicit name has been set on the wrapped key the type name is used. - public var name: String { - self._nameOverride ?? String(describing: self.keyType.self) - } - - init(_ keyType: Key.Type) { - self.keyType = keyType - self._nameOverride = keyType.nameOverride - } -} - -extension AnyServiceContextKey: Hashable { - /// A Boolean value that indicates whether two service context keys are equivalent. - /// - Parameters: - /// - lhs: The first service context key. - /// - rhs: The second service context key. - /// - Returns: `True` if equivalent; otherwise `false`. - public static func == (lhs: AnyServiceContextKey, rhs: AnyServiceContextKey) -> Bool { - ObjectIdentifier(lhs.keyType) == ObjectIdentifier(rhs.keyType) - } - - /// Hashes the essential components of this value by feeding them into the given hasher. - /// - Parameter hasher: The hasher to use when combining the components of this instance. - public func hash(into hasher: inout Hasher) { - hasher.combine(ObjectIdentifier(self.keyType)) - } -} diff --git a/Tests/ServiceContextTests/CompatibilityShimTests.swift b/Tests/ServiceContextTests/CompatibilityShimTests.swift new file mode 100644 index 0000000..55149c4 --- /dev/null +++ b/Tests/ServiceContextTests/CompatibilityShimTests.swift @@ -0,0 +1,47 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift Service Context open source project +// +// Copyright (c) 2020-2026 Apple Inc. and the Swift Service Context project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift Service Context project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +import Testing + +import ServiceContextModule + +// `ServiceContext`'s full behavior test suite now lives with its implementation in +// swift-distributed-tracing's `ServiceContextCoreTests`. These tests only confirm the +// backward-compatibility re-export shim still exposes a working, usable API. +@Suite("ServiceContextModule compatibility shim") +struct CompatibilityShimTests { + private enum TestKey: ServiceContextKey { + typealias Value = String + } + + @Test("ServiceContext is usable through the ServiceContextModule import") + func serviceContextUsableThroughShim() { + var context = ServiceContext.topLevel + #expect(context.isEmpty) + + context[TestKey.self] = "hello" + #expect(context[TestKey.self] == "hello") + #expect(context.count == 1) + } + + @Test("ServiceContext propagates through task-local current") + func taskLocalPropagation() { + var context = ServiceContext.topLevel + context[TestKey.self] = "propagated" + + ServiceContext.withValue(context) { + #expect(ServiceContext.current?[TestKey.self] == "propagated") + } + } +} diff --git a/Tests/ServiceContextTests/ServiceContextTests.swift b/Tests/ServiceContextTests/ServiceContextTests.swift deleted file mode 100644 index f0d84e4..0000000 --- a/Tests/ServiceContextTests/ServiceContextTests.swift +++ /dev/null @@ -1,155 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift Service Context open source project -// -// Copyright (c) 2020-2021 Apple Inc. and the Swift Service Context project authors -// Licensed under Apache License v2.0 -// -// See LICENSE.txt for license information -// See CONTRIBUTORS.txt for the list of Swift Service Context project authors -// -// SPDX-License-Identifier: Apache-2.0 -// -//===----------------------------------------------------------------------===// - -import Testing - -@testable import ServiceContextModule - -@Suite("ServiceContext Tests") -struct ServiceContextTests { - @Test("Top-level ServiceContext is empty") - func topLevelServiceContextIsEmpty() { - let context = ServiceContext.topLevel - - #expect(context.isEmpty) - #expect(context.count == 0) - } - - @Test("Read and write values through subscript") - func readAndWriteThroughSubscript() throws { - var context = ServiceContext.topLevel - #expect(context[FirstTestKey.self] == nil) - #expect(context[SecondTestKey.self] == nil) - - context[FirstTestKey.self] = 42 - context[SecondTestKey.self] = 42.0 - - #expect(!context.isEmpty) - #expect(context.count == 2) - #expect(context[FirstTestKey.self] == 42) - #expect(context[SecondTestKey.self] == 42.0) - } - - @Test("Context forEach iterates over all context items") - func forEachIteratesOverAllServiceContextItems() { - var context = ServiceContext.topLevel - - context[FirstTestKey.self] = 42 - context[SecondTestKey.self] = 42.0 - context[ThirdTestKey.self] = "test" - - var contextItems = [AnyServiceContextKey: Any]() - // swift-format-ignore: ReplaceForEachWithForLoop - context.forEach { key, value in - contextItems[key] = value - } - #expect(contextItems.count == 3) - #expect(contextItems.contains(where: { $0.key.name == "FirstTestKey" })) - #expect(contextItems.contains(where: { $0.value as? Int == 42 })) - #expect(contextItems.contains(where: { $0.key.name == "SecondTestKey" })) - #expect(contextItems.contains(where: { $0.value as? Double == 42.0 })) - #expect(contextItems.contains(where: { $0.key.name == "explicit" })) - #expect(contextItems.contains(where: { $0.value as? String == "test" })) - } - - @Test("TODO Context does not crash without explicit compiler flag") - func TODO_doesNotCrashWithoutExplicitCompilerFlag() { - _ = ServiceContext.TODO(#function) - } - - @Test("ServiceContextKey name defaults to type name without override") - func serviceContextKeyName_withoutOverride() { - let name = FirstTestKey.name - #expect(name == "FirstTestKey") - } - - @Test("ServiceContextKey name uses explicit override when provided") - func serviceContextKeyName_withOverride() { - let name = ThirdTestKey.name - #expect(name == "explicit") - } - - @Test("AnyServiceContextKey name defaults to type name without override") - func anyServiceContextKeyName_withoutOverride() { - let anyKey = AnyServiceContextKey(FirstTestKey.self) - #expect(anyKey.name == "FirstTestKey") - } - - @Test("AnyServiceContextKey name uses explicit override when provided") - func anyServiceContextKeyName_withOverride() { - let anyKey = AnyServiceContextKey(ThirdTestKey.self) - #expect(anyKey.name == "explicit") - } - - @Test("ServiceContextKey name matches AnyServiceContextKey name") - func serviceContextKeyName_matchesAnyServiceContextKeyName() { - #expect(FirstTestKey.name == AnyServiceContextKey(FirstTestKey.self).name) - #expect(SecondTestKey.name == AnyServiceContextKey(SecondTestKey.self).name) - #expect(ThirdTestKey.name == AnyServiceContextKey(ThirdTestKey.self).name) - } - - @Test("Automatic propagation through task-local storage") - func automaticPropagationThroughTaskLocal() throws { - guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { - #expect(Bool(true), "Task locals are not supported on this platform.") - return - } - - #expect(ServiceContext.current == nil) - - var context = ServiceContext.topLevel - context[FirstTestKey.self] = 42 - - var propagatedServiceContext: ServiceContext? - func exampleFunction() { - propagatedServiceContext = ServiceContext.current - } - - let c = ServiceContext.$current - c.withValue(context, operation: exampleFunction) - - #expect(propagatedServiceContext?.count == 1) - #expect(propagatedServiceContext?[FirstTestKey.self] == 42) - } - - actor SomeActor { - var value: Int = 0 - - func check() async { - ServiceContext.$current.withValue(.topLevel) { - value = 12 // should produce no warnings - } - ServiceContext.withValue(.topLevel) { - value = 12 // should produce no warnings - } - await ServiceContext.withValue(.topLevel) { () async in - value = 12 // should produce no warnings - } - } - } - - private enum FirstTestKey: ServiceContextKey { - typealias Value = Int - } - - private enum SecondTestKey: ServiceContextKey { - typealias Value = Double - } - - private enum ThirdTestKey: ServiceContextKey { - typealias Value = String - - static let nameOverride: String? = "explicit" - } -} From 0e967ae8213e340cd290900aca90a326b1350682 Mon Sep 17 00:00:00 2001 From: Vladimir Kukushkin Date: Wed, 2 Sep 2026 13:31:45 +0100 Subject: [PATCH 02/11] rename to ContextStorage --- Package.swift | 2 +- Sources/ServiceContextModule/CompatibilityShim.swift | 4 ++-- Sources/ServiceContextModule/Docs.docc/index.md | 2 +- Tests/ServiceContextTests/CompatibilityShimTests.swift | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Package.swift b/Package.swift index 242ee67..3475c63 100644 --- a/Package.swift +++ b/Package.swift @@ -27,7 +27,7 @@ let package = Package( .target( name: "ServiceContextModule", dependencies: [ - .product(name: "ServiceContextCore", package: "swift-distributed-tracing") + .product(name: "ContextStorage", package: "swift-distributed-tracing") ] ), diff --git a/Sources/ServiceContextModule/CompatibilityShim.swift b/Sources/ServiceContextModule/CompatibilityShim.swift index e965525..0c98de0 100644 --- a/Sources/ServiceContextModule/CompatibilityShim.swift +++ b/Sources/ServiceContextModule/CompatibilityShim.swift @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -// `ServiceContext` now lives in the `swift-distributed-tracing` package's `ServiceContextCore` module. +// `ServiceContext` now lives in the `swift-distributed-tracing` package's `ContextStorage` module. // This module re-exports it under its original name so `import ServiceContextModule` keeps working // unchanged for existing dependents of this package. -@_exported import ServiceContextCore +@_exported import ContextStorage diff --git a/Sources/ServiceContextModule/Docs.docc/index.md b/Sources/ServiceContextModule/Docs.docc/index.md index 2280a1c..3f77128 100644 --- a/Sources/ServiceContextModule/Docs.docc/index.md +++ b/Sources/ServiceContextModule/Docs.docc/index.md @@ -18,7 +18,7 @@ More information can be found in the > Note: Automatic propagation through task-locals by using `ServiceContext.current` is supported in Swift version 5.5 or later. -> Note: `ServiceContext` itself is implemented in the `swift-distributed-tracing` package's `ServiceContextCore` +> Note: `ServiceContext` itself is implemented in the `swift-distributed-tracing` package's `ContextStorage` > module. This package re-exports it under the `ServiceContextModule` name so existing dependents keep working > unchanged. New code that also needs tracing spans should depend on `Tracing` directly. diff --git a/Tests/ServiceContextTests/CompatibilityShimTests.swift b/Tests/ServiceContextTests/CompatibilityShimTests.swift index 55149c4..f5932de 100644 --- a/Tests/ServiceContextTests/CompatibilityShimTests.swift +++ b/Tests/ServiceContextTests/CompatibilityShimTests.swift @@ -17,7 +17,7 @@ import Testing import ServiceContextModule // `ServiceContext`'s full behavior test suite now lives with its implementation in -// swift-distributed-tracing's `ServiceContextCoreTests`. These tests only confirm the +// swift-distributed-tracing's `ContextStorageTests`. These tests only confirm the // backward-compatibility re-export shim still exposes a working, usable API. @Suite("ServiceContextModule compatibility shim") struct CompatibilityShimTests { From 5ec980c55ab623c1eb0543161b0cda5277ba1873 Mon Sep 17 00:00:00 2001 From: Vladimir Kukushkin Date: Mon, 7 Sep 2026 09:40:53 +0100 Subject: [PATCH 03/11] Rename to Context --- Sources/ServiceContextModule/CompatibilityShim.swift | 12 +++++++++--- Sources/ServiceContextModule/Docs.docc/index.md | 9 ++++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Sources/ServiceContextModule/CompatibilityShim.swift b/Sources/ServiceContextModule/CompatibilityShim.swift index 0c98de0..ab837eb 100644 --- a/Sources/ServiceContextModule/CompatibilityShim.swift +++ b/Sources/ServiceContextModule/CompatibilityShim.swift @@ -12,7 +12,13 @@ // //===----------------------------------------------------------------------===// -// `ServiceContext` now lives in the `swift-distributed-tracing` package's `ContextStorage` module. -// This module re-exports it under its original name so `import ServiceContextModule` keeps working -// unchanged for existing dependents of this package. +// `ServiceContext`, `ServiceContextKey`, and `AnyServiceContextKey` now live in the +// `swift-distributed-tracing` package's `ContextStorage` module, renamed to `Context`, `ContextKey`, +// and `AnyContextKey`. This module re-exports the module and declares its own, non-deprecated +// names so `import ServiceContextModule` keeps working unchanged, with no deprecation notice, for +// existing dependents of this package. @_exported import ContextStorage + +public typealias ServiceContext = ContextStorage.Context +public typealias ServiceContextKey = ContextStorage.ContextKey +public typealias AnyServiceContextKey = ContextStorage.AnyContextKey diff --git a/Sources/ServiceContextModule/Docs.docc/index.md b/Sources/ServiceContextModule/Docs.docc/index.md index 3f77128..5479b92 100644 --- a/Sources/ServiceContextModule/Docs.docc/index.md +++ b/Sources/ServiceContextModule/Docs.docc/index.md @@ -18,9 +18,12 @@ More information can be found in the > Note: Automatic propagation through task-locals by using `ServiceContext.current` is supported in Swift version 5.5 or later. -> Note: `ServiceContext` itself is implemented in the `swift-distributed-tracing` package's `ContextStorage` -> module. This package re-exports it under the `ServiceContextModule` name so existing dependents keep working -> unchanged. New code that also needs tracing spans should depend on `Tracing` directly. +> Note: `ServiceContext`, `ServiceContextKey`, and `AnyServiceContextKey` are implemented in the +> `swift-distributed-tracing` package's `ContextStorage` module, where the types themselves are named +> `Context`, `ContextKey`, and `AnyContextKey`. This package declares its own, non-deprecated names so +> existing dependents keep working unchanged, with no deprecation notice. New code that also needs +> tracing spans should depend on `Tracing` directly, and new code with no existing dependents to keep +> compatible should prefer `Context`, `ContextKey`, and `AnyContextKey`. ## Getting started From df6161a6cf6d8ddf5d9e8df4bc4fec2c1cca6d42 Mon Sep 17 00:00:00 2001 From: Vladimir Kukushkin Date: Mon, 7 Sep 2026 17:08:09 +0100 Subject: [PATCH 04/11] Rename to TracingContext --- .../ServiceContextModule/CompatibilityShim.swift | 14 +++++++------- Sources/ServiceContextModule/Docs.docc/index.md | 9 +++++---- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Sources/ServiceContextModule/CompatibilityShim.swift b/Sources/ServiceContextModule/CompatibilityShim.swift index ab837eb..2024f01 100644 --- a/Sources/ServiceContextModule/CompatibilityShim.swift +++ b/Sources/ServiceContextModule/CompatibilityShim.swift @@ -13,12 +13,12 @@ //===----------------------------------------------------------------------===// // `ServiceContext`, `ServiceContextKey`, and `AnyServiceContextKey` now live in the -// `swift-distributed-tracing` package's `ContextStorage` module, renamed to `Context`, `ContextKey`, -// and `AnyContextKey`. This module re-exports the module and declares its own, non-deprecated -// names so `import ServiceContextModule` keeps working unchanged, with no deprecation notice, for -// existing dependents of this package. +// `swift-distributed-tracing` package's `ContextStorage` module, renamed to `TracingContext`, +// `TracingContextKey`, and `AnyTracingContextKey`. This module re-exports the module and declares its +// own, non-deprecated names so `import ServiceContextModule` keeps working unchanged, with no +// deprecation notice, for existing dependents of this package. @_exported import ContextStorage -public typealias ServiceContext = ContextStorage.Context -public typealias ServiceContextKey = ContextStorage.ContextKey -public typealias AnyServiceContextKey = ContextStorage.AnyContextKey +public typealias ServiceContext = ContextStorage.TracingContext +public typealias ServiceContextKey = ContextStorage.TracingContextKey +public typealias AnyServiceContextKey = ContextStorage.AnyTracingContextKey diff --git a/Sources/ServiceContextModule/Docs.docc/index.md b/Sources/ServiceContextModule/Docs.docc/index.md index 5479b92..4b680af 100644 --- a/Sources/ServiceContextModule/Docs.docc/index.md +++ b/Sources/ServiceContextModule/Docs.docc/index.md @@ -20,10 +20,11 @@ More information can be found in the > Note: `ServiceContext`, `ServiceContextKey`, and `AnyServiceContextKey` are implemented in the > `swift-distributed-tracing` package's `ContextStorage` module, where the types themselves are named -> `Context`, `ContextKey`, and `AnyContextKey`. This package declares its own, non-deprecated names so -> existing dependents keep working unchanged, with no deprecation notice. New code that also needs -> tracing spans should depend on `Tracing` directly, and new code with no existing dependents to keep -> compatible should prefer `Context`, `ContextKey`, and `AnyContextKey`. +> `TracingContext`, `TracingContextKey`, and `AnyTracingContextKey`. This package declares its own, +> non-deprecated names so existing dependents keep working unchanged, with no deprecation notice. New +> code that also needs tracing spans should depend on `Tracing` directly, and new code with no existing +> dependents to keep compatible should prefer `TracingContext`, `TracingContextKey`, and +> `AnyTracingContextKey`. ## Getting started From 6d8ea48cdb53ce3656912b600ca95c5130e6fcbc Mon Sep 17 00:00:00 2001 From: Vladimir Kukushkin Date: Thu, 10 Sep 2026 15:17:56 +0100 Subject: [PATCH 05/11] update README --- README.md | 81 +++++++++++++++++++++++-------------------------------- 1 file changed, 34 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 319d64b..e8ca9d7 100644 --- a/README.md +++ b/README.md @@ -5,73 +5,60 @@ [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fapple%2Fswift-service-context%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/apple/swift-service-context) [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fapple%2Fswift-service-context%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/apple/swift-service-context) -`ServiceContext` is a minimal (zero-dependency) context propagation container, intended to "carry" items for purposes of cross-cutting tools to be built on top of it. +> **This package is now a thin compatibility layer.** The implementation of `ServiceContext` moved into +> [swift-distributed-tracing](https://github.com/apple/swift-distributed-tracing), where the type is named +> `TracingContext`. `import ServiceContextModule` keeps compiling and behaving exactly as it does today, +> with no code changes required. +> +> New projects, and existing ones that can freely update their code, should depend on +> swift-distributed-tracing directly and use `TracingContext` (or `Tracing`, if they also need spans) +> instead of adding this package. + +`ServiceContext` is a minimal context propagation container: a value type, propagated through task-local +storage, that carries arbitrary key-value pairs across concurrent Swift code. -It is modeled after the concepts explained in [W3C Baggage](https://w3c.github.io/baggage/) and -in the spirit of [Tracing Plane](https://cs.brown.edu/~jcmace/papers/mace18universal.pdf) 's "Baggage Context" type, -although by itself it does not define a specific serialization format. - -See https://github.com/apple/swift-distributed-tracing for actual instrument types and implementations which can be used to -deploy various cross-cutting instruments all reusing the same baggage type. More information can be found in the -[SSWG meeting notes](https://gist.github.com/ktoso/4d160232407e4d5835b5ba700c73de37#swift-baggage-context--distributed-tracing). - -## Overview - -`ServiceContext` serves as currency type for carrying around additional contextual information between Swift tasks and functions. +## Dependency -One generally starts from a "top level" (empty) or the "current" (`ServiceContext.current`) context and then adds values to it. +If you already depend on this package, you do not need to change anything. -The context is a value type and is propagated using task-local values so it can be safely used from concurrent contexts like this: +For new code, depend on +[swift-distributed-tracing](https://github.com/apple/swift-distributed-tracing) directly instead: ```swift -var context = ServiceContext.topLevel -context[FirstTestKey.self] = 42 - -func exampleFunction() async -> Int { - guard let context = ServiceContext.current else { - return 0 - } - guard let value = context[FirstTestKey.self] else { - return 0 - } - print("test = \(value)") // test = 42 - return value -} - -let c = await ServiceContext.withValue(context) { - await exampleFunction() -} -assert(c == 42) +dependencies: [ + .package(url: "https://github.com/apple/swift-distributed-tracing.git", from: "1.0.0") +] ``` -`ServiceContext` is a fundamental building block for how distributed tracing propagates trace identifiers. +```swift +targets: [ + .target( + name: "MyAwesomeApp", + dependencies: [ + .product(name: "Tracing", package: "swift-distributed-tracing") + ] + ) +] +``` -## Dependency +Depend on the `ContextStorage` product instead of `Tracing` if you only need context propagation, with no +tracing spans. -In order to depend on this library you can use the Swift Package Manager, and add the following dependency to your `Package.swift`: +### Existing dependents ```swift dependencies: [ - .package( - url: "https://github.com/apple/swift-service-context.git", - from: "1.0.0" - ) + .package(url: "https://github.com/apple/swift-service-context.git", from: "1.0.0") ] ``` -and depend on the module in your target: - ```swift targets: [ .target( name: "MyAwesomeApp", dependencies: [ - .product( - name: "ServiceContextModule", - package: "swift-service-context" - ), + .product(name: "ServiceContextModule", package: "swift-service-context") ] - ), - // ... + ) ] ``` From f778ef308ec07d829a2d8992a29a0ac300f5f36f Mon Sep 17 00:00:00 2001 From: Vladimir Kukushkin Date: Wed, 23 Sep 2026 14:50:32 +0100 Subject: [PATCH 06/11] formatting fix --- Package.swift | 5 ++++- Tests/ServiceContextTests/CompatibilityShimTests.swift | 3 +-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Package.swift b/Package.swift index 3475c63..1b515f5 100644 --- a/Package.swift +++ b/Package.swift @@ -21,7 +21,10 @@ let package = Package( ), ], dependencies: [ - .package(url: "https://github.com/kukushechkin/swift-distributed-tracing.git", branch: "move-service-context-to-sdt") + .package( + url: "https://github.com/kukushechkin/swift-distributed-tracing.git", + branch: "move-service-context-to-sdt" + ) ], targets: [ .target( diff --git a/Tests/ServiceContextTests/CompatibilityShimTests.swift b/Tests/ServiceContextTests/CompatibilityShimTests.swift index f5932de..5f0bb32 100644 --- a/Tests/ServiceContextTests/CompatibilityShimTests.swift +++ b/Tests/ServiceContextTests/CompatibilityShimTests.swift @@ -12,9 +12,8 @@ // //===----------------------------------------------------------------------===// -import Testing - import ServiceContextModule +import Testing // `ServiceContext`'s full behavior test suite now lives with its implementation in // swift-distributed-tracing's `ContextStorageTests`. These tests only confirm the From d06aa9fee83045a4453629616f848ae39cf08ac2 Mon Sep 17 00:00:00 2001 From: Vladimir Kukushkin Date: Wed, 23 Sep 2026 15:17:57 +0100 Subject: [PATCH 07/11] fixup! formatting fix --- Sources/ServiceContextModule/Docs.docc/index.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Sources/ServiceContextModule/Docs.docc/index.md b/Sources/ServiceContextModule/Docs.docc/index.md index 4b680af..56b9be5 100644 --- a/Sources/ServiceContextModule/Docs.docc/index.md +++ b/Sources/ServiceContextModule/Docs.docc/index.md @@ -26,7 +26,7 @@ More information can be found in the > dependents to keep compatible should prefer `TracingContext`, `TracingContextKey`, and > `AnyTracingContextKey`. -## Getting started +### Getting started In order to depend on this library you can use the Swift Package Manager, and add the following dependency to your `Package.swift`: @@ -65,7 +65,6 @@ Please refer to in-depth discussion and documentation in the [Swift Distributed - ``ServiceContext`` - ``ServiceContextKey`` - ``AnyServiceContextKey`` -- ``TODOLocation`` ### Contribute to the project From 3fadc5452618aae62d8504519c546302c9ccee24 Mon Sep 17 00:00:00 2001 From: Vladimir Kukushkin Date: Thu, 24 Sep 2026 13:11:10 +0100 Subject: [PATCH 08/11] TODOLocation symbol should still be present --- .../ServiceContextModule/CompatibilityShim.swift | 4 +++- Sources/ServiceContextModule/Docs.docc/index.md | 15 ++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Sources/ServiceContextModule/CompatibilityShim.swift b/Sources/ServiceContextModule/CompatibilityShim.swift index 2024f01..2e70fab 100644 --- a/Sources/ServiceContextModule/CompatibilityShim.swift +++ b/Sources/ServiceContextModule/CompatibilityShim.swift @@ -16,9 +16,11 @@ // `swift-distributed-tracing` package's `ContextStorage` module, renamed to `TracingContext`, // `TracingContextKey`, and `AnyTracingContextKey`. This module re-exports the module and declares its // own, non-deprecated names so `import ServiceContextModule` keeps working unchanged, with no -// deprecation notice, for existing dependents of this package. +// deprecation notice, for existing dependents of this package. `TODOLocation` kept its name, so this +// typealias just makes it reachable under this module too. @_exported import ContextStorage public typealias ServiceContext = ContextStorage.TracingContext public typealias ServiceContextKey = ContextStorage.TracingContextKey public typealias AnyServiceContextKey = ContextStorage.AnyTracingContextKey +public typealias TODOLocation = ContextStorage.TODOLocation diff --git a/Sources/ServiceContextModule/Docs.docc/index.md b/Sources/ServiceContextModule/Docs.docc/index.md index 56b9be5..774a1a7 100644 --- a/Sources/ServiceContextModule/Docs.docc/index.md +++ b/Sources/ServiceContextModule/Docs.docc/index.md @@ -18,13 +18,13 @@ More information can be found in the > Note: Automatic propagation through task-locals by using `ServiceContext.current` is supported in Swift version 5.5 or later. -> Note: `ServiceContext`, `ServiceContextKey`, and `AnyServiceContextKey` are implemented in the -> `swift-distributed-tracing` package's `ContextStorage` module, where the types themselves are named -> `TracingContext`, `TracingContextKey`, and `AnyTracingContextKey`. This package declares its own, -> non-deprecated names so existing dependents keep working unchanged, with no deprecation notice. New -> code that also needs tracing spans should depend on `Tracing` directly, and new code with no existing -> dependents to keep compatible should prefer `TracingContext`, `TracingContextKey`, and -> `AnyTracingContextKey`. +> Note: `ServiceContext`, `ServiceContextKey`, `AnyServiceContextKey`, and `TODOLocation` are +> implemented in the `swift-distributed-tracing` package's `ContextStorage` module, where the first +> three types are named `TracingContext`, `TracingContextKey`, and `AnyTracingContextKey`. +> `TODOLocation` keeps its name. This package declares its own, non-deprecated names so existing +> dependents keep working unchanged, with no deprecation notice. New code that also needs tracing +> spans should depend on `Tracing` directly, and new code with no existing dependents to keep +> compatible should prefer `TracingContext`, `TracingContextKey`, and `AnyTracingContextKey`. ### Getting started @@ -65,6 +65,7 @@ Please refer to in-depth discussion and documentation in the [Swift Distributed - ``ServiceContext`` - ``ServiceContextKey`` - ``AnyServiceContextKey`` +- ``TODOLocation`` ### Contribute to the project From 1ec9b4a83a27d54a352299b215a5dee12d4a1d3e Mon Sep 17 00:00:00 2001 From: Vladimir Kukushkin Date: Mon, 28 Sep 2026 17:30:49 +0100 Subject: [PATCH 09/11] Renamed to InstrumentationContext --- Package.swift | 2 +- README.md | 10 +++++----- .../ServiceContextModule/CompatibilityShim.swift | 16 ++++++++-------- Sources/ServiceContextModule/Docs.docc/index.md | 13 +++++++------ .../CompatibilityShimTests.swift | 2 +- 5 files changed, 22 insertions(+), 21 deletions(-) diff --git a/Package.swift b/Package.swift index 1b515f5..0e42a5b 100644 --- a/Package.swift +++ b/Package.swift @@ -30,7 +30,7 @@ let package = Package( .target( name: "ServiceContextModule", dependencies: [ - .product(name: "ContextStorage", package: "swift-distributed-tracing") + .product(name: "Instrumentation", package: "swift-distributed-tracing") ] ), diff --git a/README.md b/README.md index e8ca9d7..3302d69 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,12 @@ > **This package is now a thin compatibility layer.** The implementation of `ServiceContext` moved into > [swift-distributed-tracing](https://github.com/apple/swift-distributed-tracing), where the type is named -> `TracingContext`. `import ServiceContextModule` keeps compiling and behaving exactly as it does today, -> with no code changes required. +> `InstrumentationContext`. `import ServiceContextModule` keeps compiling and behaving exactly as it does +> today, with no code changes required. > > New projects, and existing ones that can freely update their code, should depend on -> swift-distributed-tracing directly and use `TracingContext` (or `Tracing`, if they also need spans) -> instead of adding this package. +> swift-distributed-tracing directly and use `InstrumentationContext` (or `Tracing`, if they also need +> spans) instead of adding this package. `ServiceContext` is a minimal context propagation container: a value type, propagated through task-local storage, that carries arbitrary key-value pairs across concurrent Swift code. @@ -41,7 +41,7 @@ targets: [ ] ``` -Depend on the `ContextStorage` product instead of `Tracing` if you only need context propagation, with no +Depend on the `Instrumentation` product instead of `Tracing` if you only need context propagation, with no tracing spans. ### Existing dependents diff --git a/Sources/ServiceContextModule/CompatibilityShim.swift b/Sources/ServiceContextModule/CompatibilityShim.swift index 2e70fab..ac55f91 100644 --- a/Sources/ServiceContextModule/CompatibilityShim.swift +++ b/Sources/ServiceContextModule/CompatibilityShim.swift @@ -13,14 +13,14 @@ //===----------------------------------------------------------------------===// // `ServiceContext`, `ServiceContextKey`, and `AnyServiceContextKey` now live in the -// `swift-distributed-tracing` package's `ContextStorage` module, renamed to `TracingContext`, -// `TracingContextKey`, and `AnyTracingContextKey`. This module re-exports the module and declares its -// own, non-deprecated names so `import ServiceContextModule` keeps working unchanged, with no +// `swift-distributed-tracing` package's `Instrumentation` module, renamed to `InstrumentationContext`, +// `InstrumentationContextKey`, and `AnyInstrumentationContextKey`. This module re-exports the module and +// declares its own, non-deprecated names so `import ServiceContextModule` keeps working unchanged, with no // deprecation notice, for existing dependents of this package. `TODOLocation` kept its name, so this // typealias just makes it reachable under this module too. -@_exported import ContextStorage +@_exported import Instrumentation -public typealias ServiceContext = ContextStorage.TracingContext -public typealias ServiceContextKey = ContextStorage.TracingContextKey -public typealias AnyServiceContextKey = ContextStorage.AnyTracingContextKey -public typealias TODOLocation = ContextStorage.TODOLocation +public typealias ServiceContext = Instrumentation.InstrumentationContext +public typealias ServiceContextKey = Instrumentation.InstrumentationContextKey +public typealias AnyServiceContextKey = Instrumentation.AnyInstrumentationContextKey +public typealias TODOLocation = Instrumentation.TODOLocation diff --git a/Sources/ServiceContextModule/Docs.docc/index.md b/Sources/ServiceContextModule/Docs.docc/index.md index 774a1a7..e3944e4 100644 --- a/Sources/ServiceContextModule/Docs.docc/index.md +++ b/Sources/ServiceContextModule/Docs.docc/index.md @@ -19,12 +19,13 @@ More information can be found in the > Note: Automatic propagation through task-locals by using `ServiceContext.current` is supported in Swift version 5.5 or later. > Note: `ServiceContext`, `ServiceContextKey`, `AnyServiceContextKey`, and `TODOLocation` are -> implemented in the `swift-distributed-tracing` package's `ContextStorage` module, where the first -> three types are named `TracingContext`, `TracingContextKey`, and `AnyTracingContextKey`. -> `TODOLocation` keeps its name. This package declares its own, non-deprecated names so existing -> dependents keep working unchanged, with no deprecation notice. New code that also needs tracing -> spans should depend on `Tracing` directly, and new code with no existing dependents to keep -> compatible should prefer `TracingContext`, `TracingContextKey`, and `AnyTracingContextKey`. +> implemented in the `swift-distributed-tracing` package's `Instrumentation` module, where the first +> three types are named `InstrumentationContext`, `InstrumentationContextKey`, and +> `AnyInstrumentationContextKey`. `TODOLocation` keeps its name. This package declares its own, +> non-deprecated names so existing dependents keep working unchanged, with no deprecation notice. New +> code that also needs tracing spans should depend on `Tracing` directly, and new code with no existing +> dependents to keep compatible should prefer `InstrumentationContext`, `InstrumentationContextKey`, and +> `AnyInstrumentationContextKey`. ### Getting started diff --git a/Tests/ServiceContextTests/CompatibilityShimTests.swift b/Tests/ServiceContextTests/CompatibilityShimTests.swift index 5f0bb32..34544a6 100644 --- a/Tests/ServiceContextTests/CompatibilityShimTests.swift +++ b/Tests/ServiceContextTests/CompatibilityShimTests.swift @@ -16,7 +16,7 @@ import ServiceContextModule import Testing // `ServiceContext`'s full behavior test suite now lives with its implementation in -// swift-distributed-tracing's `ContextStorageTests`. These tests only confirm the +// swift-distributed-tracing's `InstrumentationContextTests`. These tests only confirm the // backward-compatibility re-export shim still exposes a working, usable API. @Suite("ServiceContextModule compatibility shim") struct CompatibilityShimTests { From 789833f2bae8920d58588957bbb57687cf69a0e8 Mon Sep 17 00:00:00 2001 From: Vladimir Kukushkin Date: Tue, 29 Sep 2026 10:44:27 +0100 Subject: [PATCH 10/11] remove note annotations --- .../ServiceContextModule/Docs.docc/index.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Sources/ServiceContextModule/Docs.docc/index.md b/Sources/ServiceContextModule/Docs.docc/index.md index e3944e4..47f3c5a 100644 --- a/Sources/ServiceContextModule/Docs.docc/index.md +++ b/Sources/ServiceContextModule/Docs.docc/index.md @@ -16,16 +16,16 @@ and implementations you can use to deploy various cross-cutting instruments that More information can be found in the [SSWG meeting notes](https://gist.github.com/ktoso/4d160232407e4d5835b5ba700c73de37#swift-baggage-context--distributed-tracing). -> Note: Automatic propagation through task-locals by using `ServiceContext.current` is supported in Swift version 5.5 or later. - -> Note: `ServiceContext`, `ServiceContextKey`, `AnyServiceContextKey`, and `TODOLocation` are -> implemented in the `swift-distributed-tracing` package's `Instrumentation` module, where the first -> three types are named `InstrumentationContext`, `InstrumentationContextKey`, and -> `AnyInstrumentationContextKey`. `TODOLocation` keeps its name. This package declares its own, -> non-deprecated names so existing dependents keep working unchanged, with no deprecation notice. New -> code that also needs tracing spans should depend on `Tracing` directly, and new code with no existing -> dependents to keep compatible should prefer `InstrumentationContext`, `InstrumentationContextKey`, and -> `AnyInstrumentationContextKey`. +Automatic propagation through task-locals by using `ServiceContext.current` is supported in Swift version 5.5 or later. + +`ServiceContext`, `ServiceContextKey`, `AnyServiceContextKey`, and `TODOLocation` are +implemented in the `swift-distributed-tracing` package's `Instrumentation` module, where the first +three types are named `InstrumentationContext`, `InstrumentationContextKey`, and +`AnyInstrumentationContextKey`. `TODOLocation` keeps its name. This package declares its own, +non-deprecated names so existing dependents keep working unchanged, with no deprecation notice. New +code that also needs tracing spans should depend on `Tracing` directly, and new code with no existing +dependents to keep compatible should prefer `InstrumentationContext`, `InstrumentationContextKey`, and +`AnyInstrumentationContextKey`. ### Getting started From 9929b2e2cb55b61e82ef5ce13797c7c05dea704e Mon Sep 17 00:00:00 2001 From: Vladimir Kukushkin Date: Mon, 12 Oct 2026 16:38:09 +0100 Subject: [PATCH 11/11] SDT 1.6.0 --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 0e42a5b..e2f54fb 100644 --- a/Package.swift +++ b/Package.swift @@ -22,8 +22,8 @@ let package = Package( ], dependencies: [ .package( - url: "https://github.com/kukushechkin/swift-distributed-tracing.git", - branch: "move-service-context-to-sdt" + url: "https://github.com/apple/swift-distributed-tracing.git", + from: "1.6.0" ) ], targets: [