Skip to content

Commit

Permalink
Merge pull request #487 from iRevive/sdk-trace/testkit
Browse files Browse the repository at this point in the history
Add `sdk-trace-testkit` module
  • Loading branch information
iRevive authored Feb 9, 2024
2 parents ca1f452 + 134426c commit bb87551
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 7 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ jobs:
- name: Submit Dependencies
uses: scalacenter/sbt-dependency-submission@v2
with:
modules-ignore: otel4s-sdk-exporter-common_sjs1_2.13 otel4s-sdk-exporter-common_sjs1_3 otel4s-sdk-common_native0.4_2.13 otel4s-sdk-common_native0.4_3 otel4s-benchmarks_2.13 otel4s-benchmarks_3 otel4s-examples_2.13 otel4s-examples_3 otel4s-sdk-common_sjs1_2.13 otel4s-sdk-common_sjs1_3 otel4s-sdk-exporter_2.13 otel4s-sdk-exporter_3 otel4s-sdk-trace_sjs1_2.13 otel4s-sdk-trace_sjs1_3 otel4s-sdk-exporter-common_native0.4_2.13 otel4s-sdk-exporter-common_native0.4_3 otel4s-sdk-exporter-trace_2.13 otel4s-sdk-exporter-trace_3 otel4s_2.13 otel4s_3 docs_2.13 docs_3 scalafix-output_2.13 scalafix-input_2.13 otel4s-sdk-exporter-proto_2.13 otel4s-sdk-exporter-proto_3 otel4s-sdk-exporter-proto_sjs1_2.13 otel4s-sdk-exporter-proto_sjs1_3 otel4s-sdk_native0.4_2.13 otel4s-sdk_native0.4_3 otel4s-sdk-exporter-trace_native0.4_2.13 otel4s-sdk-exporter-trace_native0.4_3 otel4s-sdk-common_2.13 otel4s-sdk-common_3 otel4s_2.13 otel4s_3 otel4s_2.13 otel4s_3 otel4s-sdk-trace_native0.4_2.13 otel4s-sdk-trace_native0.4_3 otel4s-sdk-exporter-proto_native0.4_2.13 otel4s-sdk-exporter-proto_native0.4_3 otel4s-sdk-exporter-common_2.13 otel4s-sdk-exporter-common_3 otel4s-sdk-exporter-trace_sjs1_2.13 otel4s-sdk-exporter-trace_sjs1_3 scalafix-tests_2.13 otel4s-sdk-exporter_sjs1_2.13 otel4s-sdk-exporter_sjs1_3 otel4s-sdk_sjs1_2.13 otel4s-sdk_sjs1_3 otel4s-sdk_2.13 otel4s-sdk_3 otel4s-sdk-exporter_native0.4_2.13 otel4s-sdk-exporter_native0.4_3 otel4s-sdk-trace_2.13 otel4s-sdk-trace_3
modules-ignore: otel4s-sdk-exporter-common_sjs1_2.13 otel4s-sdk-exporter-common_sjs1_3 otel4s-sdk-common_native0.4_2.13 otel4s-sdk-common_native0.4_3 otel4s-benchmarks_2.13 otel4s-benchmarks_3 otel4s-examples_2.13 otel4s-examples_3 otel4s-sdk-common_sjs1_2.13 otel4s-sdk-common_sjs1_3 otel4s-sdk-exporter_2.13 otel4s-sdk-exporter_3 otel4s-sdk-trace_sjs1_2.13 otel4s-sdk-trace_sjs1_3 otel4s-sdk-exporter-common_native0.4_2.13 otel4s-sdk-exporter-common_native0.4_3 otel4s-sdk-exporter-trace_2.13 otel4s-sdk-exporter-trace_3 otel4s_2.13 otel4s_3 docs_2.13 docs_3 otel4s-sdk-trace-testkit_2.13 otel4s-sdk-trace-testkit_3 scalafix-output_2.13 otel4s-sdk-trace-testkit_native0.4_2.13 otel4s-sdk-trace-testkit_native0.4_3 scalafix-input_2.13 otel4s-sdk-exporter-proto_2.13 otel4s-sdk-exporter-proto_3 otel4s-sdk-exporter-proto_sjs1_2.13 otel4s-sdk-exporter-proto_sjs1_3 otel4s-sdk_native0.4_2.13 otel4s-sdk_native0.4_3 otel4s-sdk-exporter-trace_native0.4_2.13 otel4s-sdk-exporter-trace_native0.4_3 otel4s-sdk-common_2.13 otel4s-sdk-common_3 otel4s_2.13 otel4s_3 otel4s_2.13 otel4s_3 otel4s-sdk-trace_native0.4_2.13 otel4s-sdk-trace_native0.4_3 otel4s-sdk-exporter-proto_native0.4_2.13 otel4s-sdk-exporter-proto_native0.4_3 otel4s-sdk-exporter-common_2.13 otel4s-sdk-exporter-common_3 otel4s-sdk-exporter-trace_sjs1_2.13 otel4s-sdk-exporter-trace_sjs1_3 otel4s-sdk-trace-testkit_sjs1_2.13 otel4s-sdk-trace-testkit_sjs1_3 scalafix-tests_2.13 otel4s-sdk-exporter_sjs1_2.13 otel4s-sdk-exporter_sjs1_3 otel4s-sdk_sjs1_2.13 otel4s-sdk_sjs1_3 otel4s-sdk_2.13 otel4s-sdk_3 otel4s-sdk-exporter_native0.4_2.13 otel4s-sdk-exporter_native0.4_3 otel4s-sdk-trace_2.13 otel4s-sdk-trace_3
configs-ignore: test scala-tool scala-doc-tool test-internal

validate-steward:
Expand Down
24 changes: 24 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ lazy val root = tlCrossRootProject
core,
`sdk-common`,
`sdk-trace`,
`sdk-trace-testkit`,
sdk,
`sdk-exporter-common`,
`sdk-exporter-proto`,
Expand All @@ -116,6 +117,10 @@ lazy val root = tlCrossRootProject
)
.settings(name := "otel4s")

//
// Core
//

lazy val `core-common` = crossProject(JVMPlatform, JSPlatform, NativePlatform)
.crossType(CrossType.Pure)
.in(file("core/common"))
Expand Down Expand Up @@ -177,6 +182,10 @@ lazy val core = crossProject(JVMPlatform, JSPlatform, NativePlatform)
)
.settings(scalafixSettings)

//
// SDK
//

lazy val `sdk-common` = crossProject(JVMPlatform, JSPlatform, NativePlatform)
.crossType(CrossType.Pure)
.enablePlugins(BuildInfoPlugin)
Expand Down Expand Up @@ -221,6 +230,19 @@ lazy val `sdk-trace` = crossProject(JVMPlatform, JSPlatform, NativePlatform)
),
)
.settings(munitDependencies)
.settings(scalafixSettings)

lazy val `sdk-trace-testkit` =
crossProject(JVMPlatform, JSPlatform, NativePlatform)
.crossType(CrossType.Pure)
.enablePlugins(NoPublishPlugin)
.in(file("sdk/trace-testkit"))
.dependsOn(`sdk-trace`)
.settings(
name := "otel4s-sdk-trace-testkit",
startYear := Some(2024)
)
.settings(scalafixSettings)

lazy val sdk = crossProject(JVMPlatform, JSPlatform, NativePlatform)
.crossType(CrossType.Pure)
Expand Down Expand Up @@ -257,6 +279,7 @@ lazy val `sdk-exporter-proto` =
"io.opentelemetry.proto" % "opentelemetry-proto" % OpenTelemetryProtoVersion % "protobuf-src" intransitive ()
)
)
.settings(scalafixSettings)

lazy val `sdk-exporter-common` =
crossProject(JVMPlatform, JSPlatform, NativePlatform)
Expand Down Expand Up @@ -534,6 +557,7 @@ lazy val unidocs = project
core.jvm,
`sdk-common`.jvm,
`sdk-trace`.jvm,
`sdk-trace-testkit`.jvm,
sdk.jvm,
`sdk-exporter-common`.jvm,
`sdk-exporter-trace`.jvm,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ package org.typelevel.otel4s.sdk

import cats.mtl.Ask
import cats.mtl.Local
import org.typelevel.otel4s.context.LocalProvider

package object context {

type AskContext[F[_]] = Ask[F, Context]
type LocalContext[F[_]] = Local[F, Context]
type LocalContextProvider[F[_]] = LocalProvider[F, Context]

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright 2024 Typelevel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.typelevel.otel4s.sdk.testkit.trace

import cats.Foldable
import cats.Monad
import cats.effect.Concurrent
import cats.effect.std.Queue
import cats.syntax.foldable._
import cats.syntax.functor._
import org.typelevel.otel4s.sdk.trace.data.SpanData
import org.typelevel.otel4s.sdk.trace.exporter.SpanExporter

final class InMemorySpanExporter[F[_]: Monad] private (
queue: Queue[F, SpanData]
) extends SpanExporter[F] {
val name: String = "InMemorySpanExporter"

def exportSpans[G[_]: Foldable](spans: G[SpanData]): F[Unit] =
spans.traverse_(span => queue.offer(span))

def flush: F[Unit] =
Monad[F].unit

def finishedSpans: F[List[SpanData]] =
queue.tryTakeN(None)

}

object InMemorySpanExporter {

def create[F[_]: Concurrent](
capacity: Option[Int]
): F[InMemorySpanExporter[F]] =
for {
queue <- capacity.fold(Queue.unbounded[F, SpanData])(Queue.bounded(_))
} yield new InMemorySpanExporter[F](queue)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright 2024 Typelevel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.typelevel.otel4s.sdk.testkit.trace

import cats.FlatMap
import cats.Parallel
import cats.effect.Async
import cats.effect.Resource
import cats.effect.std.Console
import cats.effect.std.Random
import cats.syntax.flatMap._
import org.typelevel.otel4s.context.LocalProvider
import org.typelevel.otel4s.sdk.context.Context
import org.typelevel.otel4s.sdk.context.LocalContext
import org.typelevel.otel4s.sdk.context.LocalContextProvider
import org.typelevel.otel4s.sdk.trace.SdkTracerProvider
import org.typelevel.otel4s.sdk.trace.data.SpanData
import org.typelevel.otel4s.sdk.trace.processor.BatchSpanProcessor
import org.typelevel.otel4s.sdk.trace.processor.SpanProcessor
import org.typelevel.otel4s.trace.TracerProvider

trait TracesTestkit[F[_]] {

/** The [[org.typelevel.otel4s.trace.TracerProvider TracerProvider]].
*/
def tracerProvider: TracerProvider[F]

/** The list of finished spans.
*
* @note
* each invocation cleans up the internal buffer.
*/
def finishedSpans: F[List[SpanData]]
}

object TracesTestkit {

/** Creates [[TracesTestkit]] that keeps spans in-memory.
*
* @param customize
* the customization of the builder
*/
def inMemory[F[_]: Async: Parallel: Console: LocalContextProvider](
customize: SdkTracerProvider.Builder[F] => SdkTracerProvider.Builder[F] =
(b: SdkTracerProvider.Builder[F]) => b
): Resource[F, TracesTestkit[F]] = {
def createTracerProvider(
processor: SpanProcessor[F]
)(implicit local: LocalContext[F]): F[TracerProvider[F]] =
Random.scalaUtilRandom[F].flatMap { implicit random =>
val builder = SdkTracerProvider.builder[F].addSpanProcessor(processor)
customize(builder).build
}

for {
local <- Resource.eval(LocalProvider[F, Context].local)
exporter <- Resource.eval(InMemorySpanExporter.create[F](None))
processor <- BatchSpanProcessor.builder(exporter).build
tracerProvider <- Resource.eval(createTracerProvider(processor)(local))
} yield new Impl(tracerProvider, processor, exporter)
}

private final class Impl[F[_]: FlatMap](
val tracerProvider: TracerProvider[F],
processor: SpanProcessor[F],
exporter: InMemorySpanExporter[F]
) extends TracesTestkit[F] {
def finishedSpans: F[List[SpanData]] =
processor.forceFlush >> exporter.finishedSpans
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,15 @@ trait SpanExporter[F[_]] {
* multi-error scenario.
*
* @see
* [[SpanExporter.ExporterFailure]]
* [[org.typelevel.otel4s.sdk.trace.exporter.SpanExporter.ExporterFailure SpanExporter.ExporterFailure]]
*
* @see
* [[SpanExporter.CompositeExporterFailure]]
* [[org.typelevel.otel4s.sdk.trace.exporter.SpanExporter.CompositeExporterFailure SpanExporter.CompositeExporterFailure]]
*/
def name: String

/** Called to export sampled [[data.SpanData SpanData]].
/** Called to export sampled
* [[org.typelevel.otel4s.sdk.trace.data.SpanData SpanData]].
*
* @note
* the export operations can be performed simultaneously depending on the
Expand All @@ -62,7 +63,8 @@ trait SpanExporter[F[_]] {
*/
def exportSpans[G[_]: Foldable](spans: G[SpanData]): F[Unit]

/** Exports the collection of sampled [[data.SpanData SpanData]] that have not
/** Exports the collection of sampled
* [[org.typelevel.otel4s.sdk.trace.data.SpanData SpanData]] that have not
* yet been exported.
*
* @note
Expand Down Expand Up @@ -130,7 +132,7 @@ object SpanExporter {
failure
)

/** An composite failure, when '''at least 2''' exporters have failed.
/** A composite failure, when '''at least 2''' exporters have failed.
*
* @param first
* the first occurred error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ object SpanProcessor {
failure
)

/** An composite failure, when '''at least 2''' processors have failed.
/** A composite failure, when '''at least 2''' processors have failed.
*
* @param first
* the first occurred error
Expand Down

0 comments on commit bb87551

Please sign in to comment.