Skip to content

Adopt ServiceContext 1.0 #127

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Docs/SwiftDistributedTracing/empty.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
// This module is left purposefully empty of any source files, as it serves
// only as a "landing page" for the documentation. This is in-place until docc
// gains the ability to support package-wide documentation.
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ fi

"$here/../../allocation-counter-tests-framework/run-allocation-counter.sh" \
-p "$here/../../.." \
-m Baggage \
-m ServiceContext \
-m Instrumentation \
-m NIOInstrumentation \
-s "$here/shared.swift" \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
//===----------------------------------------------------------------------===//

import Foundation
import InstrumentationBaggage
import ServiceContextModule

@inline(never)
func take1(context: BaggageContext) -> Int {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
//
//===----------------------------------------------------------------------===//

import InstrumentationBaggage
import ServiceContextModule

func run(identifier: String) {
measure(identifier: identifier) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
//
//===----------------------------------------------------------------------===//

import InstrumentationBaggage
import ServiceContextModule

func run(identifier: String) {
measure(identifier: identifier) {
Expand Down
7 changes: 4 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ let package = Package(
.library(name: "Tracing", targets: ["Tracing"]),
],
dependencies: [
.package(url: "https://github.com/apple/swift-distributed-tracing-baggage.git", .upToNextMinor(from: "0.4.1")),
// .package(url: "https://github.com/apple/swift-service-context.git", from: "1.0.0"),
.package(url: "https://github.com/apple/swift-service-context.git", branch: "main"),
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"),
],
targets: [
Expand All @@ -24,7 +25,7 @@ let package = Package(
.target(
name: "Instrumentation",
dependencies: [
.product(name: "InstrumentationBaggage", package: "swift-distributed-tracing-baggage"),
.product(name: "ServiceContextModule", package: "swift-service-context"),
]
),
.testTarget(
Expand Down Expand Up @@ -56,7 +57,7 @@ let package = Package(
.executableTarget(
name: "_TracingBenchmarks",
dependencies: [
.product(name: "InstrumentationBaggage", package: "swift-distributed-tracing-baggage"),
.product(name: "ServiceContextModule", package: "swift-service-context"),
.target(name: "Tracing"),
.target(name: "_TracingBenchmarkTools"),
]
Expand Down
563 changes: 15 additions & 548 deletions README.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Samples/Dinner/Sources/Onboarding/Clock+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@
//===----------------------------------------------------------------------===//

func sleep(for duration: ContinuousClock.Duration) async {
try? await Task.sleep(until: ContinuousClock.now + duration, clock: .continuous)
}
try? await Task.sleep(until: ContinuousClock.now + duration, clock: .continuous)
}
85 changes: 42 additions & 43 deletions Samples/Dinner/Sources/Onboarding/Dinner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,67 +24,66 @@
//
//===----------------------------------------------------------------------===//


import Tracing

func makeDinner() async throws -> Meal {
try await InstrumentationSystem.tracer.withSpan("makeDinner") { _ in
await sleep(for: .milliseconds(200))
try await InstrumentationSystem.tracer.withSpan("makeDinner") { _ in
await sleep(for: .milliseconds(200))

async let veggies = try chopVegetables()
async let meat = marinateMeat()
async let oven = preheatOven(temperature: 350)
// ...
return try await cook(veggies, meat, oven)
}
async let veggies = try chopVegetables()
async let meat = marinateMeat()
async let oven = preheatOven(temperature: 350)
// ...
return try await cook(veggies, meat, oven)
}
}

func chopVegetables() async throws -> [Vegetable] {
try await otelChopping1.tracer().withSpan("chopVegetables") { _ in
// Chop the vegetables...!
//
// However, since chopping is a very difficult operation,
// one chopping task can be performed at the same time on a single service!
// (Imagine that... we cannot parallelize these two tasks, and need to involve another service).
async let carrot = try chop(.carrot, tracer: otelChopping1.tracer())
async let potato = try chop(.potato, tracer: otelChopping2.tracer())
return try await [carrot, potato]
}
try await otelChopping1.tracer().withSpan("chopVegetables") { _ in
// Chop the vegetables...!
//
// However, since chopping is a very difficult operation,
// one chopping task can be performed at the same time on a single service!
// (Imagine that... we cannot parallelize these two tasks, and need to involve another service).
async let carrot = try chop(.carrot, tracer: otelChopping1.tracer())
async let potato = try chop(.potato, tracer: otelChopping2.tracer())
return try await [carrot, potato]
}
}

func chop(_ vegetable: Vegetable, tracer: any Tracer) async throws -> Vegetable {
await tracer.withSpan("chop-\(vegetable)") { _ in
await sleep(for: .seconds(5))
// ...
return vegetable // "chopped"
}
await tracer.withSpan("chop-\(vegetable)") { _ in
await sleep(for: .seconds(5))
// ...
return vegetable // "chopped"
}
}

func marinateMeat() async -> Meat {
await sleep(for: .milliseconds(620))
await sleep(for: .milliseconds(620))

return await InstrumentationSystem.tracer.withSpan("marinateMeat") { _ in
await sleep(for: .seconds(3))
// ...
return Meat()
}
return await InstrumentationSystem.tracer.withSpan("marinateMeat") { _ in
await sleep(for: .seconds(3))
// ...
return Meat()
}
}

func preheatOven(temperature: Int) async -> Oven {
await InstrumentationSystem.tracer.withSpan("preheatOven") { _ in
// ...
await sleep(for: .seconds(6))
return Oven()
}
await InstrumentationSystem.tracer.withSpan("preheatOven") { _ in
// ...
await sleep(for: .seconds(6))
return Oven()
}
}

func cook(_: Any, _: Any, _: Any) async -> Meal {
await InstrumentationSystem.tracer.withSpan("cook") { span in
span.addEvent("children-asking-if-done-already")
await sleep(for: .seconds(3))
span.addEvent("children-asking-if-done-already-again")
await sleep(for: .seconds(2))
// ...
return Meal()
}
await InstrumentationSystem.tracer.withSpan("cook") { span in
span.addEvent("children-asking-if-done-already")
await sleep(for: .seconds(3))
span.addEvent("children-asking-if-done-already-again")
await sleep(for: .seconds(2))
// ...
return Meal()
}
}
6 changes: 2 additions & 4 deletions Samples/Dinner/Sources/Onboarding/Model.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,10 @@
//
//===----------------------------------------------------------------------===//


struct Meal: Sendable {}
struct Meat: Sendable {}
struct Oven: Sendable {}
enum Vegetable: Sendable {
case potato
case carrot
case potato
case carrot
}

7 changes: 3 additions & 4 deletions Samples/Dinner/Sources/Onboarding/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
//
//===----------------------------------------------------------------------===//


import Logging
import NIO
import OpenTelemetry
Expand All @@ -36,9 +35,9 @@ import Tracing
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)

LoggingSystem.bootstrap { label in
var handler = StreamLogHandler.standardOutput(label: label)
handler.logLevel = .trace
return handler
var handler = StreamLogHandler.standardOutput(label: label)
handler.logLevel = .trace
return handler
}

// ==== ----------------------------------------------------------------------------------------------------------------
Expand Down
16 changes: 8 additions & 8 deletions Sources/Instrumentation/Instrument.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//

import InstrumentationBaggage
import ServiceContextModule

/// Typealias used to simplify Support of old Swift versions which do not have `Sendable` defined.
#if swift(>=5.6.0)
Expand Down Expand Up @@ -51,22 +51,22 @@ public protocol Injector: _SwiftInstrumentationSendable {
/// Conforming types are usually cross-cutting tools like tracers. They are agnostic of what specific `Carrier` is used
/// to propagate metadata across boundaries, but instead just specify what values to use for which keys.
public protocol Instrument: _SwiftInstrumentationSendable {
/// Extract values from a `Carrier` by using the given extractor and inject them into the given `Baggage`.
/// Extract values from a `Carrier` by using the given extractor and inject them into the given `ServiceContext`.
/// It's quite common for `Instrument`s to come up with new values if they weren't passed along in the given `Carrier`.
///
/// - Parameters:
/// - carrier: The `Carrier` that was used to propagate values across boundaries.
/// - baggage: The `Baggage` into which these values should be injected.
/// - context: The `ServiceContext` into which these values should be injected.
/// - extractor: The ``Extractor`` that extracts values from the given `Carrier`.
func extract<Carrier, Extract>(_ carrier: Carrier, into baggage: inout Baggage, using extractor: Extract)
func extract<Carrier, Extract>(_ carrier: Carrier, into context: inout ServiceContext, using extractor: Extract)
where Extract: Extractor, Extract.Carrier == Carrier

/// Extract values from a `Baggage` and inject them into the given `Carrier` using the given ``Injector``.
/// Extract values from a `ServiceContext` and inject them into the given `Carrier` using the given ``Injector``.
///
/// - Parameters:
/// - baggage: The `Baggage` from which relevant information will be extracted.
/// - context: The `ServiceContext` from which relevant information will be extracted.
/// - carrier: The `Carrier` into which this information will be injected.
/// - injector: The ``Injector`` used to inject extracted `Baggage` into the given `Carrier`.
func inject<Carrier, Inject>(_ baggage: Baggage, into carrier: inout Carrier, using injector: Inject)
/// - injector: The ``Injector`` used to inject extracted `ServiceContext` into the given `Carrier`.
func inject<Carrier, Inject>(_ context: ServiceContext, into carrier: inout Carrier, using injector: Inject)
where Inject: Injector, Inject.Carrier == Carrier
}
8 changes: 4 additions & 4 deletions Sources/Instrumentation/InstrumentationSystem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//

import InstrumentationBaggage
import ServiceContextModule

/// `InstrumentationSystem` is a global facility where the default cross-cutting tool can be configured.
/// It is set up just once in a given program to select the desired ``Instrument`` implementation.
Expand All @@ -22,7 +22,7 @@ import InstrumentationBaggage
///
/// # Access the Instrument
/// ``instrument``: Returns whatever you passed to ``bootstrap(_:)`` as an ``Instrument``.
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal Baggage
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal ServiceContext
public enum InstrumentationSystem {
private static let lock = ReadWriteLock()
private static var _instrument: Instrument = NoOpInstrument()
Expand Down Expand Up @@ -62,9 +62,9 @@ public enum InstrumentationSystem {
}
}

@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal Baggage
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) // for TaskLocal ServiceContext
extension InstrumentationSystem {
/// :nodoc: INTERNAL API: Do Not Use
/// INTERNAL API: Do Not Use
public static func _findInstrument(where predicate: (Instrument) -> Bool) -> Instrument? {
self.lock.withReaderLock {
if let multiplex = self._instrument as? MultiplexInstrument {
Expand Down
14 changes: 7 additions & 7 deletions Sources/Instrumentation/MultiplexInstrument.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@
//
//===----------------------------------------------------------------------===//

import InstrumentationBaggage
import ServiceContextModule

/// A pseudo-``Instrument`` that may be used to instrument using multiple other ``Instrument``s across a
/// common `Baggage`.
/// common `ServiceContext`.
public struct MultiplexInstrument {
private var instruments: [Instrument]

/// Create a ``MultiplexInstrument``.
///
/// - Parameter instruments: An array of ``Instrument``s, each of which will be used to ``Instrument/inject(_:into:using:)`` or ``Instrument/extract(_:into:using:)``
/// through the same `Baggage`.
/// through the same `ServiceContext`.
public init(_ instruments: [Instrument]) {
self.instruments = instruments
}
Expand All @@ -35,15 +35,15 @@ extension MultiplexInstrument {
}

extension MultiplexInstrument: Instrument {
public func inject<Carrier, Inject>(_ baggage: Baggage, into carrier: inout Carrier, using injector: Inject)
public func inject<Carrier, Inject>(_ context: ServiceContext, into carrier: inout Carrier, using injector: Inject)
where Inject: Injector, Carrier == Inject.Carrier
{
self.instruments.forEach { $0.inject(baggage, into: &carrier, using: injector) }
self.instruments.forEach { $0.inject(context, into: &carrier, using: injector) }
}

public func extract<Carrier, Extract>(_ carrier: Carrier, into baggage: inout Baggage, using extractor: Extract)
public func extract<Carrier, Extract>(_ carrier: Carrier, into context: inout ServiceContext, using extractor: Extract)
where Extract: Extractor, Carrier == Extract.Carrier
{
self.instruments.forEach { $0.extract(carrier, into: &baggage, using: extractor) }
self.instruments.forEach { $0.extract(carrier, into: &context, using: extractor) }
}
}
6 changes: 3 additions & 3 deletions Sources/Instrumentation/NoOpInstrument.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@
//
//===----------------------------------------------------------------------===//

import InstrumentationBaggage
import ServiceContextModule

/// A "no op" implementation of an ``Instrument``.
public struct NoOpInstrument: Instrument {
public init() {}

public func inject<Carrier, Inject>(_ baggage: Baggage, into carrier: inout Carrier, using injector: Inject)
public func inject<Carrier, Inject>(_ context: ServiceContext, into carrier: inout Carrier, using injector: Inject)
where Inject: Injector, Carrier == Inject.Carrier
{
// no-op
}

public func extract<Carrier, Extract>(_ carrier: Carrier, into baggage: inout Baggage, using extractor: Extract)
public func extract<Carrier, Extract>(_ carrier: Carrier, into context: inout ServiceContext, using extractor: Extract)
where Extract: Extractor, Carrier == Extract.Carrier
{
// no-op
Expand Down
Loading