Skip to content
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

+tracing Instrument Invocation handlers using swift-distributed-tracing #1085

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

ktoso
Copy link
Member

@ktoso ktoso commented Nov 7, 2022

Fully functional, basic, swift-distributed-tracing integration... in just 20 lines of actual changed code (!): 80dd5a5 (#1085)

Further, this includes a complete sample app that illustrates this.

Screenshot 2022-11-07 at 15 12 10

Resolves #847 Instrument system with Swift Distributed Tracing
Resolves #476 Context propagation mechanism for actors: Baggage


The Samples project contains a full sample that showcases this end-to-end. I'll write some docs for it later, but also intend to include this sample in tracing documentation perhaps?

Short version:

We automatically get spans for distributed calls etc 🥳

distributed actor Cook { 
    // ... 
    distributed func makeDinner() async throws -> Meal {
        try await InstrumentationSystem.tracer.withSpan(#function) { _ in
            await noisySleep(for: .milliseconds(200))

            log.notice("Cooking dinner, but we need [2] vegetable choppers...! Suspend waiting for nodes to join.")
            let (first, second) = try await getChoppers()
            async let veggies = try chopVegetables(firstChopper: first, secondChopper: second)
            async let meat = marinateMeat()
            async let oven = preheatOven(temperature: 350)
            // ...
            return try await cook(veggies, meat, oven)
        }
    }

func chopVegetables(firstChopper: some Chopping,
                    secondChopper: some Chopping) async throws -> [Vegetable]
{
    try await InstrumentationSystem.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 firstChopper.chop(.carrot(chopped: false))
        async let potato = try secondChopper.chop(.potato(chopped: false))
        return try await [carrot, potato]
    }
}

and

protocol Chopping {
    func chop(_ vegetable: Vegetable) async throws -> Vegetable
}

distributed actor VegetableChopper: Chopping {
    @ActorID.Metadata(\.receptionID)
    var receptionID: String

    init(actorSystem: ActorSystem) async {
        self.actorSystem = actorSystem

        self.receptionID = "*" // default key for "all of this type"
        await actorSystem.receptionist.checkIn(self)
    }

    distributed func chop(_ vegetable: Vegetable) async throws -> Vegetable {
        await noisySleep(for: .seconds(5))

        return vegetable.asChopped
    }
}

Copy link
Member

@yim-lee yim-lee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<3

import NIO
import OpenTelemetry
import OtlpGRPCSpanExporting
import Tracing
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are all these imports needed?

init(actorSystem: ActorSystem) async {
self.actorSystem = actorSystem

self.receptionID = "*" // default key for "all of this type"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the only type that gets registered with the receptionist so it doesn't matter what receptionID is?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

* is by convention the "default key" which we use for "all the actors" #1084

@@ -12,6 +12,7 @@
//
//===----------------------------------------------------------------------===//

import _PrettyLogHandler
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Instrument system with Swift Distributed Tracing Context propagation mechanism for actors: Baggage
2 participants