Skip to content
This repository was archived by the owner on Jul 11, 2025. It is now read-only.

Conversation

porglezomp
Copy link
Contributor

This provides a @Traced macro which adds a tracing span around the body of the function. This macro allows customizing the operationName, the context, and the kind of the span, same as the withSpan function. It also exposes the span itself into the scope of the function, with a customizable name.

This doesn't attempt to support automatically adding parameters as attributes, because the scoping rules of attached macros aren't very amenable to controlling that. That could be added in the future if it's judged necessary.

Examples:

@Traced("preheat oven")
func preheatOven(temperature: Int) async throws -> Oven {
    span.attributes["oven.targetTemperature"] = temperature
    await sleep(for: .seconds(6))
    return Oven()
}

expands to:

func preheatOven(temperature: Int) async throws -> Oven {
    withSpan("preheat oven") { span in
        span.attributes["oven.targetTemperature"] = temperature
        await sleep(for: .seconds(6))
        return Oven()
    }
}

Notes:

This places the macros into a separate product so that users who don't want to pay the compile-time cost of macros don't have to use it, you opt-in to that cost by depending on the TracingMacros module.

This is an alternative to apple/swift-distributed-tracing#157 to avoid a semver major bump, since the minimum platform versions are already set here.

Resolves apple/swift-distributed-tracing#125

**Motivation:**

Adding tracing to functions can be a slightly invasive modification
because using `withSpan` requires re-indenting the whole function. It
also requires some duplicated modifications when modifying the effects
signatures of functions. We want a macro to perform this transformation.

**Modifications:**

Introduce a TracingMacros module to provide macros for the Tracing
package. Add a `@Traced` macro that performs the transformation.

This is defined as a separate product so that users who don't want to
pay the compile-time cost of macros don't have to use it, you opt-in to
that cost by depending on the TracingMacros module.

The `@Traced` macro is only available in Swift 6.0 compilers since
function body macros were introduced in Swift 6.0.
**Motivation:**

We need to support `@Traced` on async and throws functions to make it
compatible with everywhere people want to use them.

**Modifications:**

Based on the effects signature of the attached function we apply
try/await as appropriate. But, if the function is async/throws but those
effects aren't actually used in the function body, this causes a new
warning because the closure isn't inferred to be async and/or throws. To
avoid those warnings, we also apply matching effects specifiers to the
withSpan closure.

**Result:**

The `@Traced` macro is now usable on all functions.
**Motivation:**

The `@Traced` macro isn't sufficient for all cases of `withSpan` because
it doesn't allow the same customization of the span. We need to expose
those parameters to the macro.

**Modifications:**

First, allow overriding the regular parameters of the withSpan call:
setting the operationName, the context, and the kind. If it's not
specified, it's not passed to the function, which means the function
remains the source of truth for default arguments.

Also allow overriding the span name, which controls the variable binding
in the closure body. This is primarily useful for avoiding shadowing an
outer "span" variable.

**Result:**

Users of the macro can use the operationName, context, and kind
parameters to customize the span like `withSpan`, and can use the span
parameter to customize the variable introduced by the macro's expansion.
**Motivation:**

We want to allow richer customization of the operation name in the
`@Traced` macro, in particular the difference between the different ways
you can view a function name.

**Modifications:**

- Add a TracedOperationName type that represents the kinds of operation
  names we want to support.
- Change the `@Traced` macro interface and expansion to use the new
  operation name type.

**Result:**

Now you can write `@Traced(.baseName)`, `@Traced(.fullName)` as well as
`@Traced("custom name here")`, giving more flexibility between types of
operation names.
This didn't need to be `@_exported import`, this change cleans up the
docs
@ktoso ktoso added the 🆕 semver/minor Adds new public API. label Nov 26, 2024
@ktoso
Copy link
Member

ktoso commented Nov 26, 2024

Ok, awesome! Let's include this in the extras repo then rather the main then. As folks indicated bumping the required OS would have been technically breaking. Thanks @Lukasa for chiming in

@ktoso ktoso merged commit c36625e into apple:main Nov 26, 2024
26 of 27 checks passed
@ktoso
Copy link
Member

ktoso commented Nov 26, 2024

We want to give folks a moment to debate the swift-syntax issue before cutting a release.

But imho there's nothing we as a package can do to improve the situation; the package manager and how swift deals with macros needs to improve really to avoid these issues, unless we'd say we don't do any macros anywhere until then -- but that's not ok either tbh, we literarily developed a language feature for this specific macro, so let's have it available as opt in to folks.

assertMacroExpansion(
"""
@Traced
func syncThrowingExample(param: Int) throws {
Copy link

@rauhul rauhul Nov 26, 2024

Choose a reason for hiding this comment

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

Will you get a warning in the expanded macro if the traced function is marked as throws but doesn't actually try anywhere?

Copy link

Choose a reason for hiding this comment

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

same with async/await

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nope—this is what motivated doing the extra work to copy over the effect specifier on the closure instead of leaving it inferred. See the commit message on 3951ba2 for a discussion of that.

@ktoso ktoso added semver/none No version bump required. and removed 🆕 semver/minor Adds new public API. labels Nov 26, 2024
@ktoso
Copy link
Member

ktoso commented Nov 26, 2024

marking this as semver/none because we reverted the change.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
semver/none No version bump required.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Offer @traced macro when macros gain function body replacement capabilities
3 participants