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

trace: add @span macro #1

Merged
merged 3 commits into from
Jul 9, 2024
Merged

trace: add @span macro #1

merged 3 commits into from
Jul 9, 2024

Conversation

iRevive
Copy link
Contributor

@iRevive iRevive commented Jun 12, 2024

An experimental implementation of the typelevel/otel4s#550.
OpenTelemetry Java offers similar functionality using reflections and AOP https://opentelemetry.io/docs/languages/java/automatic/annotations/.

Before we start

The functionality exists in a separate otel4s-core-trace-experimental module.

How it works

The body of a method annotated with @span will be wrapped into a span:

@span
def findUser(
  @attribute userId: Long, 
  @attribute("user.hash") hash: String
): F[User] = ???

// expands into

def findUser(
    userId: Long, 
    hash: String
): F[User] = 
  Tracer[F].span(
    "findUser", 
    Attribute("userId", userId), Attribute("user.hash", hash)
  ).surround(???)

The macro works with variables too:

@span("custom_name")
val findUser: IO[User] = ???

// expands into

val findUser: IO[User] = 
  Tracer[IO].span("custom_name").surround(???)

Summary

Pros

  1. Separate tracing from the business layer
  2. Relatively easy to add tracing to the existing methods
  3. Generates boilerplate for you: the name of the span and attributes can be derived automatically
  4. Since the result type remains the same, IDEs should be fine

Cons

  1. It's macros
  2. @attribute contributes to the visual noise
  3. Spring-like

Questions

1) Why @withSpan and @spanAttribute instead of @span and @attribute?

If I recall correctly, problems can arise in case-insensitive systems because we already have Span and Attribute.

However, if that is not the case, I would prefer @span and @attribute.

2) Should the macro capture source information?

We can easily add source attributes to the span, such as Attribute("source.file", "some/path/Service.scala") and Attribute("source.line", 123L).

@iRevive
Copy link
Contributor Author

iRevive commented Jun 12, 2024

@NthPortal I moved the PR to the new repo. I also renamed @withSpan to @span. Let's see how it goes.

ensureImplicitExist(
q"_root_.org.typelevel.otel4s.AttributeKey.KeySelect[$tpt]",
e =>
s"the argument [${name.decodedName}] cannot be used as an attribute. The type [$tpt] is not supported.${e.getMessage}"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

* the custom name of the attribute to use. If not specified, the name of the parameter will be
* used
*/
class attribute(@unused name: String = "") extends StaticAnnotation {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@NthPortal I guess we can add @compileTimeOnly annotation there, but then I need to change the expand logic slightly.

I will check.

@iRevive iRevive merged commit ff0e83d into main Jul 9, 2024
17 checks passed
@iRevive iRevive deleted the span-macro branch July 9, 2024 17:44
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.

1 participant