Skip to content

Conversation

@satabin
Copy link

@satabin satabin commented Jan 23, 2026

This is an attempt at #1127 and an opportunity to align the existing traces with the ones defined in semantic conventions.

The current PR:

  • improves existing spans by adding as many semantic convention attributes as possible
  • includes available details in attributes in case we receive a PostgresErrorException
  • creates client spans with custom finalizer to implement the above point
  • records the operation duration on each exchange, adding as many attributes as possible

There currently are some limitations with this implementation:

  • we do not have direct access to low-cardinality query summary, or I did not find how to get access to it
  • span names are still the same generic names as before (e.g. query or execute)
  • database name or query operation is not easily available on a query and is not added to the attributes
    • if there is a way to get these pieces of information easily that would be great, maybe I missed something
  • this PR does not add the metrics which are still in development (e.g. the db.client.response.returned_rows or connection pool metrics are not added)
    • this could be added in a follow-up PR maybe
  • it breaks the source and binary compatibility as the Histogram has to be propagated, I think it is not an issue, correct me if I'm wrong.

object Otel {

// TODO the current snapshot used does not have the new `From` instance,
// and I cannot update the otel4s dependency since skunk depends on SN 0.5
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 still true with the snapshot we just upgraded to last week?

Copy link
Author

Choose a reason for hiding this comment

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

I rebased on main yesterday and it was still the case. Maybe we need another snapshot @iRevive?

Copy link
Contributor

Choose a reason for hiding this comment

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

Here are updated snapshots:

lazy val otel4sVersion = "0.16-83b6f7b-SNAPSHOT"
lazy val otel4sSdkVersion = "0.17-c767f1d-SNAPSHOT"


trait FTest extends CatsEffectSuite with FTestPlatform {

implicit val meter: Meter[IO] = Meter.noop
Copy link
Member

Choose a reason for hiding this comment

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

Can we tie this in with the other test machinery (withinSpan, tracedTest, etc)

* @param parseCacheSize size of the pool-level cache for parsing statements; defaults to 2048
*/
final class Builder[F[_]: Temporal: Network: Console] private (
final class Builder[F[_]: Temporal: Meter: Network: Console] private (
Copy link
Member

Choose a reason for hiding this comment

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

Curious if we should just take a Tracer here too and drop support for explicitly passing a Tracer? Or alternatively, should we support explicitly passing a Meter using a similar pattern? Explicit passing was added back when tracing was done via Natchez: #650

Copy link
Author

Choose a reason for hiding this comment

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

I think the implicit Tracer is the more idiomatic way of doing it in otel4s. This could be done in a follow-up PR?

Copy link
Member

Choose a reason for hiding this comment

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

Yep for sure

Copy link
Contributor

@iRevive iRevive Jan 25, 2026

Choose a reason for hiding this comment

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

It would be nice to use MeterProvider so you can explicitly define and control the instrumentation scope. Then, you can create a Meter inside the pooled / single:

val meter: F[Meter] = MeterProvider[F].tracer("skunk").withVersion(BuildInfo.version).get

OpenTelemetry generally recommends that libraries own their instrumentation scopes.
We follow a similar approach in http4s-otel4s-middleware or fs2-grpc-otel4s.

If possible, I would do the same with Tracer.


If users don't need tracing or metering capabilities, they can use given MeterProvider[F] = MeterProvider.noop.

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.

3 participants