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

A Natchez-like "continuation" API to avoid MonadCancelThrow leakage? #85

Closed
rossabaker opened this issue Jan 23, 2023 · 6 comments
Closed
Labels
enhancement New feature or request tracing Improvements to tracing module

Comments

@rossabaker
Copy link
Member

Compared to natchez.Trace, a library instrumented with org.typelevel.otel4s.trace.Tracer may require stronger constraints.

Natchez

The Natchez Trace API includes:

  /** Create a new span, and within it run the continuation `k`. */
  def span[A](name: String, options: Span.Options = Span.Options.Defaults)(k: F[A]): F[A]

Typical usage is:

Trace[F].span("child") {
  someEffect
}

Spanning someEffect only requires a Trace constraint.

Otel4s

As of #37, our Tracer provides the following API, via TracerMacro:

  def span(name: String, attributes: Attribute[_]*): Resource[F, Span[F]]

We might do:

Tracer[F].span("child").use { span =>
  someEffect
}

Or, equivalently, and closer to Natchez:

Tracer[F].span("child").surround {
  someEffect
}

.use and .surround both introduce a MonadCancelThrow constraint on spanned code, even if the concrete tracer is the simple, applicative noop. It's nice to have the full power of resource, but it's also now difficult to instrument an existing library without constraints rippling beyond Tracer.

@rossabaker rossabaker added the tracing Improvements to tracing module label Jan 23, 2023
@rossabaker
Copy link
Member Author

I think the spanK on natchez.Trace is awfully neat, returning an F ~> F. It possibly costs a few nanoseconds more.

@rossabaker rossabaker added the enhancement New feature or request label Jan 23, 2023
@rossabaker
Copy link
Member Author

rossabaker commented Jan 26, 2023

I added a naive spanK to Tracer:

  def spanK(name: String, attributes: Attribute[_]*): F ~> F =
    macro TracerMacro.spanK

But the macro inlines the implementation, and thus need for a MonadCancelThrow, at the call site. Drat.

@iRevive
Copy link
Contributor

iRevive commented Jan 26, 2023

@rossabaker
Copy link
Member Author

rossabaker commented Jan 26, 2023

That spanK is like surround. For the current TracingExample, we also need something like use, or a way to augment the contextual span without referencing it directly. I'm afraid we're writing macros for many of the methods of Resource, or writing forwarders for most of the methods of Span.

        Tracer[F].span("Work.DoWork").use { span =>
          span.addEvent("Starting the work.") *>
            doWorkInternal *>
            span.addEvent("Finished working.")
        }

@rossabaker
Copy link
Member Author

This is an uphill climb, because childScope and rootScope and noopScope also return Resource. Even if we replace span with something that hides the MonadCancelThrow, we have to deal with all of those.

@rossabaker
Copy link
Member Author

We still need a MonadCancelThrow to construct even a noop instance, but we've removed the need from the use sites. I'm declaring victory.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request tracing Improvements to tracing module
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants