Skip to content

Commit

Permalink
Merge pull request #578 from iRevive/sdk-exporter/otlp-custom-client
Browse files Browse the repository at this point in the history
sdk-exporter: allow passing a custom client to the `OtlpSpanExporterAutoConfigure`
  • Loading branch information
iRevive authored Apr 9, 2024
2 parents 0829ba7 + 7c8fe64 commit 48f1152
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 20 deletions.
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[
F[_]: Async: Network: Compression: Console
](client: Client[F]): AutoConfigure.Named[F, SpanExporter[F]] =
new OtlpSpanExporterAutoConfigure[F](Some(client))

}

0 comments on commit 48f1152

Please sign in to comment.