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

sdk-exporter: allow passing a custom client to the OtlpSpanExporterAutoConfigure #578

Merged
merged 1 commit into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ThisBuild / tlBaseVersion := "0.5"
ThisBuild / tlBaseVersion := "0.6"

ThisBuild / organization := "org.typelevel"
ThisBuild / organizationName := "Typelevel"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,16 +162,32 @@ private[otlp] object OtlpHttpClient {
headers: Headers,
gzipCompression: Boolean,
retryPolicy: RetryPolicy,
tlsContext: Option[TLSContext[F]]
tlsContext: Option[TLSContext[F]],
customClient: Option[Client[F]]
)(implicit
encoder: ProtoEncoder.Message[List[A]],
printer: Printer
): Resource[F, OtlpHttpClient[F, A]] = {
val config = Config(encoding, endpoint, timeout, headers, gzipCompression)

val builder = EmberClientBuilder
.default[F]
.withTimeout(config.timeout)
def createClient: Resource[F, Client[F]] =
customClient match {
case Some(client) =>
Resource
.eval(
Console[F].println(
"You are using a custom http4s client with OtlpHttpClient. 'timeout' and 'tlsContext' settings are ignored."
)
)
.as(client)

case None =>
val builder = EmberClientBuilder
.default[F]
.withTimeout(timeout)

tlsContext.foldLeft(builder)(_.withTLSContext(_)).build
}

val gzip: Client[F] => Client[F] =
if (gzipCompression) GZip[F]() else identity
Expand Down Expand Up @@ -207,7 +223,7 @@ private[otlp] object OtlpHttpClient {
val policy = HttpRetryPolicy[F](backoff, (_, res) => shouldRetry(res))

for {
client <- tlsContext.foldLeft(builder)(_.withTLSContext(_)).build
client <- createClient
} yield new OtlpHttpClient[F, A](Retry(policy)(gzip(client)), config)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import fs2.io.net.Network
import org.http4s.Header
import org.http4s.Headers
import org.http4s.Uri
import org.http4s.client.Client
import org.typelevel.ci.CIString
import org.typelevel.otel4s.sdk.autoconfigure.AutoConfigure
import org.typelevel.otel4s.sdk.autoconfigure.Config
Expand Down Expand Up @@ -71,6 +72,7 @@ private final class OtlpHttpClientAutoConfigure[
](
specific: OtlpHttpClientAutoConfigure.ConfigKeys.Keys,
defaults: OtlpHttpClientAutoConfigure.Defaults,
customClient: Option[Client[F]],
configKeys: Set[Config.Key[_]]
)(implicit encoder: ProtoEncoder.Message[List[A]], printer: Printer)
extends AutoConfigure.WithHint[F, OtlpHttpClient[F, A]](
Expand Down Expand Up @@ -125,7 +127,8 @@ private final class OtlpHttpClientAutoConfigure[
headers,
compression.isDefined,
RetryPolicy.default,
None
None,
customClient
)

tryLoad match {
Expand Down Expand Up @@ -205,14 +208,16 @@ private[exporter] object OtlpHttpClientAutoConfigure {
* config
*/
def traces[F[_]: Async: Network: Compression: Console, A](
defaults: Defaults
defaults: Defaults,
customClient: Option[Client[F]]
)(implicit
encoder: ProtoEncoder.Message[List[A]],
printer: Printer
): AutoConfigure[F, OtlpHttpClient[F, A]] =
new OtlpHttpClientAutoConfigure[F, A](
ConfigKeys.Traces,
defaults,
customClient,
ConfigKeys.General.All ++ ConfigKeys.Traces.All
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class OtlpHttpClientAutoConfigureSuite
"headers={}}"

OtlpHttpClientAutoConfigure
.traces[IO, Payload](tracesDefaults)
.traces[IO, Payload](tracesDefaults, None)
.configure(config)
.use(client => IO(assertEquals(client.toString, expected)))
}
Expand Down Expand Up @@ -92,7 +92,7 @@ class OtlpHttpClientAutoConfigureSuite
"headers={}}"

OtlpHttpClientAutoConfigure
.traces[IO, Payload](tracesDefaults)
.traces[IO, Payload](tracesDefaults, None)
.configure(config)
.use(client => IO(assertEquals(client.toString, expected)))
}
Expand All @@ -116,7 +116,7 @@ class OtlpHttpClientAutoConfigureSuite
"headers={header1: value1}}"

OtlpHttpClientAutoConfigure
.traces[IO, Payload](tracesDefaults)
.traces[IO, Payload](tracesDefaults, None)
.configure(config)
.use(client => IO(assertEquals(client.toString, expected)))
}
Expand Down Expand Up @@ -144,7 +144,7 @@ class OtlpHttpClientAutoConfigureSuite
"headers={header2: value2}}"

OtlpHttpClientAutoConfigure
.traces[IO, Payload](tracesDefaults)
.traces[IO, Payload](tracesDefaults, None)
.configure(config)
.use(client => IO(assertEquals(client.toString, expected)))
}
Expand Down Expand Up @@ -204,7 +204,7 @@ class OtlpHttpClientAutoConfigureSuite
s"Cannot autoconfigure [OtlpHttpClient].\nCause: $cause.\nConfig:\n$prettyConfig"

OtlpHttpClientAutoConfigure
.traces[IO, Payload](tracesDefaults)
.traces[IO, Payload](tracesDefaults, None)
.configure(config)
.use_
.attempt
Expand All @@ -218,7 +218,7 @@ class OtlpHttpClientAutoConfigureSuite
Config.ofProps(Map("otel.exporter.otlp.headers" -> "non-header"))

OtlpHttpClientAutoConfigure
.traces[IO, Payload](tracesDefaults)
.traces[IO, Payload](tracesDefaults, None)
.configure(config)
.use_
.attempt
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import fs2.io.net.Network
import fs2.io.net.tls.TLSContext
import org.http4s.Headers
import org.http4s.Uri
import org.http4s.client.Client
import org.http4s.syntax.literals._
import org.typelevel.otel4s.sdk.trace.data.SpanData
import org.typelevel.otel4s.sdk.trace.exporter.SpanExporter
Expand Down Expand Up @@ -130,7 +131,8 @@ object OtlpHttpSpanExporter {
timeout = Defaults.Timeout,
headers = Headers.empty,
retryPolicy = RetryPolicy.default,
tlsContext = None
tlsContext = None,
client = None
)

private final case class BuilderImpl[
Expand All @@ -142,7 +144,8 @@ object OtlpHttpSpanExporter {
timeout: FiniteDuration,
headers: Headers,
retryPolicy: RetryPolicy,
tlsContext: Option[TLSContext[F]]
tlsContext: Option[TLSContext[F]],
client: Option[Client[F]]
) extends Builder[F] {

def withTimeout(timeout: FiniteDuration): Builder[F] =
Expand All @@ -169,6 +172,9 @@ object OtlpHttpSpanExporter {
def withEncoding(encoding: HttpPayloadEncoding): Builder[F] =
copy(encoding = encoding)

def withClient(client: Client[F]): Builder[F] =
copy(client = Some(client))

def build: Resource[F, SpanExporter[F]] = {
import SpansProtoEncoder.spanDataToRequest
import SpansProtoEncoder.jsonPrinter
Expand All @@ -181,7 +187,8 @@ object OtlpHttpSpanExporter {
headers,
gzipCompression,
retryPolicy,
tlsContext
tlsContext,
client
)
} yield new OtlpHttpSpanExporter[F](client)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import cats.effect.std.Console
import fs2.compression.Compression
import fs2.io.net.Network
import org.http4s.Headers
import org.http4s.client.Client
import org.typelevel.otel4s.sdk.autoconfigure.AutoConfigure
import org.typelevel.otel4s.sdk.autoconfigure.Config
import org.typelevel.otel4s.sdk.autoconfigure.ConfigurationError
Expand Down Expand Up @@ -56,7 +57,8 @@ import org.typelevel.otel4s.sdk.trace.exporter.SpanExporter
*/
private final class OtlpSpanExporterAutoConfigure[
F[_]: Async: Network: Compression: Console
] extends AutoConfigure.WithHint[F, SpanExporter[F]](
](customClient: Option[Client[F]])
extends AutoConfigure.WithHint[F, SpanExporter[F]](
"OtlpSpanExporter",
OtlpSpanExporterAutoConfigure.ConfigKeys.All
)
Expand Down Expand Up @@ -93,7 +95,7 @@ private final class OtlpSpanExporterAutoConfigure[
)

OtlpHttpClientAutoConfigure
.traces[F, SpanData](defaults)
.traces[F, SpanData](defaults, customClient)
.configure(config)
.map(client => new OtlpHttpSpanExporter[F](client))

Expand Down Expand Up @@ -161,6 +163,49 @@ object OtlpSpanExporterAutoConfigure {
def apply[
F[_]: Async: Network: Compression: Console
]: AutoConfigure.Named[F, SpanExporter[F]] =
new OtlpSpanExporterAutoConfigure[F]
new OtlpSpanExporterAutoConfigure[F](None)

/** Autoconfigures OTLP
* [[org.typelevel.otel4s.sdk.trace.exporter.SpanExporter SpanExporter]]
* using the given client.
*
* The configuration depends on the `otel.exporter.otlp.protocol` or
* `otel.exporter.otlp.traces.protocol`.
*
* The supported protocols: `http/json`, `http/protobuf`.
*
* @see
* `OtlpHttpClientAutoConfigure` for the configuration details of the OTLP
* HTTP client
*
* @note
* the 'timeout' and 'tlsContext' context settings will be ignored. You
* must preconfigure the client manually.
*
* @example
* {{{
* import java.net.{InetSocketAddress, ProxySelector}
* import java.net.http.HttpClient
* import org.http4s.jdkhttpclient.JdkHttpClient
*
* val jdkHttpClient = HttpClient
* .newBuilder()
* .proxy(ProxySelector.of(InetSocketAddress.createUnresolved("localhost", 3312)))
* .build()
*
* OpenTelemetrySdk.autoConfigured[IO](
* _.addSpanExporterConfigurer(
* OtlpSpanExporterAutoConfigure.customClient[IO](JdkHttpClient(jdkHttpClient))
* )
* )
* }}}
*
* @param client
* the custom http4s client to use
*/
def customClient[
Copy link
Contributor Author

Choose a reason for hiding this comment

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

customClient vs overloaded apply 🤔

Copy link

Choose a reason for hiding this comment

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

I like customClient

F[_]: Async: Network: Compression: Console
](client: Client[F]): AutoConfigure.Named[F, SpanExporter[F]] =
new OtlpSpanExporterAutoConfigure[F](Some(client))

}