diff --git a/core/src/main/scala/org/http4s/otel4s/middleware/TypedAttributes.scala b/core/src/main/scala/org/http4s/otel4s/middleware/TypedAttributes.scala index bab07c5..f9e08ee 100644 --- a/core/src/main/scala/org/http4s/otel4s/middleware/TypedAttributes.scala +++ b/core/src/main/scala/org/http4s/otel4s/middleware/TypedAttributes.scala @@ -34,6 +34,11 @@ import java.util.Locale /** Methods for creating appropriate `Attribute`s from typed HTTP objects. */ object TypedAttributes { private[this] lazy val knownMethods: Set[Method] = Method.all.toSet + private[middleware] val middlewareVersion: Attribute[String] = + Attribute( + "org.http4s.otel4s.middleware.version", + org.http4s.otel4s.middleware.BuildInfo.version, + ) /** The http.request.method `Attribute` with the special value _OTHER */ val httpRequestMethodOther: Attribute[String] = diff --git a/trace/client/src/main/scala/org/http4s/otel4s/middleware/trace/client/AttributeProvider.scala b/trace/client/src/main/scala/org/http4s/otel4s/middleware/trace/client/AttributeProvider.scala index d122f4c..445a100 100644 --- a/trace/client/src/main/scala/org/http4s/otel4s/middleware/trace/client/AttributeProvider.scala +++ b/trace/client/src/main/scala/org/http4s/otel4s/middleware/trace/client/AttributeProvider.scala @@ -89,3 +89,21 @@ trait AttributeProvider { self => that.responseAttributes(response, headersAllowedAsAttributes) } } + +object AttributeProvider { + + /** Provides an `Attribute` containing this middleware's version. */ + val middlewareVersion: AttributeProvider = + new AttributeProvider { + def requestAttributes[F[_]]( + request: Request[F], + urlTemplateClassifier: UriTemplateClassifier, + urlRedactor: UriRedactor, + headersAllowedAsAttributes: Set[AuthScheme], + ): Attributes = Attributes(TypedAttributes.middlewareVersion) + def responseAttributes[F[_]]( + response: Response[F], + headersAllowedAsAttributes: Set[AuthScheme], + ): Attributes = Attributes.empty + } +} diff --git a/trace/client/src/main/scala/org/http4s/otel4s/middleware/trace/client/SpanDataProvider.scala b/trace/client/src/main/scala/org/http4s/otel4s/middleware/trace/client/SpanDataProvider.scala index d49d7f0..90e0d23 100644 --- a/trace/client/src/main/scala/org/http4s/otel4s/middleware/trace/client/SpanDataProvider.scala +++ b/trace/client/src/main/scala/org/http4s/otel4s/middleware/trace/client/SpanDataProvider.scala @@ -150,9 +150,6 @@ trait SpanDataProvider extends AttributeProvider { self => object SpanDataProvider { - /** The default provider, which follows OpenTelemetry semantic conventions. */ - def default: SpanDataProvider = openTelemetry - /** A `SpanAndAttributeProvider` following OpenTelemetry semantic conventions. */ val openTelemetry: SpanDataProvider = { final case class Data(httpRequestMethod: Attribute[String]) { @@ -240,4 +237,9 @@ object SpanDataProvider { } } } + + /** The default provider, which follows OpenTelemetry semantic conventions + * and includes this middleware's version. + */ + val default: SpanDataProvider = openTelemetry.and(AttributeProvider.middlewareVersion) } diff --git a/trace/server/src/main/scala/org/http4s/otel4s/middleware/trace/server/AttributeProvider.scala b/trace/server/src/main/scala/org/http4s/otel4s/middleware/trace/server/AttributeProvider.scala index 75b0cf5..b886b9b 100644 --- a/trace/server/src/main/scala/org/http4s/otel4s/middleware/trace/server/AttributeProvider.scala +++ b/trace/server/src/main/scala/org/http4s/otel4s/middleware/trace/server/AttributeProvider.scala @@ -89,3 +89,21 @@ trait AttributeProvider { self => that.responseAttributes(response, headersAllowedAsAttributes) } } + +object AttributeProvider { + + /** Provides an `Attribute` containing this middleware's version. */ + val middlewareVersion: AttributeProvider = + new AttributeProvider { + def requestAttributes[F[_]]( + request: Request[F], + routeClassifier: RouteClassifier, + redactor: PathAndQueryRedactor, + headersAllowedAsAttributes: Set[AuthScheme], + ): Attributes = Attributes(TypedAttributes.middlewareVersion) + def responseAttributes[F[_]]( + response: Response[F], + headersAllowedAsAttributes: Set[AuthScheme], + ): Attributes = Attributes.empty + } +} diff --git a/trace/server/src/main/scala/org/http4s/otel4s/middleware/trace/server/SpanDataProvider.scala b/trace/server/src/main/scala/org/http4s/otel4s/middleware/trace/server/SpanDataProvider.scala index 4068f9f..31d04b4 100644 --- a/trace/server/src/main/scala/org/http4s/otel4s/middleware/trace/server/SpanDataProvider.scala +++ b/trace/server/src/main/scala/org/http4s/otel4s/middleware/trace/server/SpanDataProvider.scala @@ -151,9 +151,6 @@ trait SpanDataProvider extends AttributeProvider { self => object SpanDataProvider { - /** The default provider, which follows OpenTelemetry semantic conventions. */ - def default: SpanDataProvider = openTelemetry - /** A `SpanAndAttributeProvider` following OpenTelemetry semantic conventions. */ val openTelemetry: SpanDataProvider = { final case class Data( @@ -255,4 +252,9 @@ object SpanDataProvider { } } } + + /** The default provider, which follows OpenTelemetry semantic conventions + * and includes this middleware's version. + */ + val default: SpanDataProvider = openTelemetry.and(AttributeProvider.middlewareVersion) }