### Example Trace Logging with Custom Fields and Spans Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/backends/log.md Demonstrates creating a trace with custom fields and child spans using the Log entry point. This example logs the complete trace as a JSON object. ```scala import cats.effect._ import cats.effect.unsafe.implicits.global import cats.syntax.all._ import org.typelevel.log4cats.Logger import natchez.log.Log // mdoc can't see output from SLF4J so let's just hack up a logger implicit val log: Logger[IO] = new Logger[IO] { def debug(t: Throwable)(message: => String): cats.effect.IO[Unit] = ??? def error(t: Throwable)(message: => String): cats.effect.IO[Unit] = ??? def info(t: Throwable)(message: => String): cats.effect.IO[Unit] = ??? def trace(t: Throwable)(message: => String): cats.effect.IO[Unit] = ??? def warn(t: Throwable)(message: => String): cats.effect.IO[Unit] = ??? def debug(message: => String): cats.effect.IO[Unit] = ??? def error(message: => String): cats.effect.IO[Unit] = ??? def info(message: => String): cats.effect.IO[Unit] = IO(println(message)) def trace(message: => String): cats.effect.IO[Unit] = ??? def warn(message: => String): cats.effect.IO[Unit] = ??? } val prog = Log.entryPoint[IO]("example-service").root("root span").use { s => s.put("person.name" -> "bob", "person.age" -> 42) *> s.span("thing one").use { _ => IO.unit } *> s.span("thing two").use { _ => IO(ExitCode.Success) } } println("```json") prog.unsafeRunSync() println("```") ``` -------------------------------- ### Imports for Http4s Examples Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/reference/entrypoints.md Required imports for the subsequent Http4s routing examples. ```scala import cats.effect.IO import natchez.{ EntryPoint, Kernel } import org.http4s.HttpRoutes import org.http4s.dsl.io._ ``` -------------------------------- ### Run Traced Operation by Creating Trace[IO] from EntryPoint Source: https://context7.com/typelevel/natchez/llms.txt An alternative method to run traced operations in IO by directly creating a Trace[IO] instance from an EntryPoint. This approach is useful when you want to start tracing from the entry point. ```scala // Alternative: create Trace[IO] from EntryPoint directly def runWithEntryPointTrace(ep: EntryPoint[IO]): IO[Unit] = Trace.ioTraceForEntryPoint(ep).flatMap { implicit trace => processRequest[IO]("req-789") } ``` -------------------------------- ### Ambient Span Passing Example Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/reference/spans.md Shows how to use the Trace constraint for ambient span management. Suitable for tagless style programming or effects with reader capabilities. ```scala import cats.Monad import cats.effect.IO import cats.syntax.all._ import natchez.{ Span, Trace } def wibble[F[_]: Trace: Monad](name: String, age: Int): F[Unit] = Trace[F].span("wibble") { for { _ <- Trace[F].put("name" -> name, "age" -> age) // ... actual method logic in F } yield () } ``` -------------------------------- ### Explicit Span Passing Example Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/reference/spans.md Demonstrates passing a Span explicitly as an argument. Use this if your effect type lacks reader capabilities. ```scala import cats.Monad import cats.effect.IO import cats.syntax.all._ import natchez.{ Span, Trace } def wibble(name: String, age: Int, parent: Span[IO]): IO[Unit] = parent.span("wibble").use { span => for { _ <- span.put("name" -> name, "age" -> age) // ... actual method logic in IO } yield () } ``` -------------------------------- ### Configure Honeycomb EntryPoint Source: https://context7.com/typelevel/natchez/llms.txt Sets up a Honeycomb entry point for sending traces directly to Honeycomb. Requires Honeycomb API key and dataset configuration. ```scala import cats.effect.{IO, Resource, Sync} import natchez.EntryPoint import natchez.honeycomb.Honeycomb def honeycombEntryPoint[F[_]: Sync]: Resource[F, EntryPoint[F]] = Honeycomb.entryPoint[F]("my-service") { optionsBuilder => Sync[F].delay { optionsBuilder .setWriteKey("your-honeycomb-api-key") .setDataset("my-dataset") .build } } // Usage with full tracing val honeycombProgram: IO[Unit] = honeycombEntryPoint[IO].use { ep => ep.root("api-request").use { span => for { _ <- span.put( "http.method" -> "GET", "http.url" -> "/api/users", "user.authenticated" -> true ) _ <- span.span("database-query").use { dbSpan => dbSpan.put("db.statement" -> "SELECT * FROM users") *> dbSpan.log("Query executed") } } yield () } } ``` -------------------------------- ### Configure Log EntryPoint (Basic) Source: https://context7.com/typelevel/natchez/llms.txt Sets up a basic Log entry point for outputting traces as JSON to a log4cats Logger. Useful for local debugging. ```scala import cats.effect.IO import cats.syntax.all._ import natchez.EntryPoint import natchez.log.Log import org.typelevel.log4cats.Logger import org.typelevel.log4cats.slf4j.Slf4jLogger import io.circe.Json implicit val logger: Logger[IO] = Slf4jLogger.getLogger[IO] // Basic log entry point val logEntryPoint: EntryPoint[IO] = Log.entryPoint[IO]("my-service") // Custom JSON formatting val customLogEntryPoint: EntryPoint[IO] = Log.entryPoint[IO]( service = "my-service", format = (json: Json) => json.noSpaces // Compact JSON output ) // Example trace output (JSON): // { // "service": "my-service", // "name": "root-span", // "trace.trace_id": "abc123", // "trace.span_id": "def456", // "duration_ms": 150, // "exit.case": "completed", // "children": [ // { "name": "child-span", ... } // ] // } val logProgram: IO[Unit] = logEntryPoint.root("process-data").use { span => span.put("data.size" -> 1024) *> span.span("parse").use(_.log("Parsing complete")) *> span.span("transform").use(_.put("transform.type" -> "normalize")) } ``` -------------------------------- ### Constructing a Log EntryPoint Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/backends/log.md Shows how to create a `Log` EntryPoint with a specified service name and an implicit `Logger[F]`. The `format` parameter can be used to customize the JSON output. ```scala import cats.effect.IO import natchez.EntryPoint import natchez.log.Log import org.typelevel.log4cats.Logger import org.typelevel.log4cats.slf4j.Slf4jLogger implicit val log: Logger[IO] = Slf4jLogger.getLoggerFromName("example-logger") val ep: EntryPoint[IO] = Log.entryPoint[IO]("example-service") ``` -------------------------------- ### Configure OpenTelemetry EntryPoint Source: https://context7.com/typelevel/natchez/llms.txt Sets up an OpenTelemetry entry point using OTLP gRPC exporter. Requires OpenTelemetry SDK dependencies. Supports W3C trace context propagation. ```scala import cats.effect.{IO, Resource, Async, Sync} import cats.data.Kleisli import natchez.{EntryPoint, Span, Trace} import natchez.opentelemetry.OpenTelemetry import io.opentelemetry.api.common.Attributes import io.opentelemetry.sdk.resources.{Resource => OtelResource} import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator import io.opentelemetry.context.propagation.ContextPropagators import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter import io.opentelemetry.sdk.trace.SdkTracerProvider import io.opentelemetry.sdk.trace.`export`.BatchSpanProcessor import io.opentelemetry.semconv.ServiceAttributes def openTelemetryEntryPoint[F[_]: Async]: Resource[F, EntryPoint[F]] = for { exporter <- OpenTelemetry.lift( "OtlpGrpcSpanExporter", Sync[F].delay { OtlpGrpcSpanExporter.builder() .setEndpoint("http://localhost:4317") .build() } ) processor <- OpenTelemetry.lift( "BatchSpanProcessor", Sync[F].delay { BatchSpanProcessor.builder(exporter).build() } ) tracer <- OpenTelemetry.lift( "SdkTracerProvider", Sync[F].delay { SdkTracerProvider.builder() .setResource(OtelResource.create( Attributes.of(ServiceAttributes.SERVICE_NAME, "my-service") )) .addSpanProcessor(processor) .build() } ) ep <- OpenTelemetry.entryPoint(globallyRegister = true) { builder => Resource.eval(Sync[F].delay { builder .setTracerProvider(tracer) .setPropagators( ContextPropagators.create(W3CTraceContextPropagator.getInstance()) ) }) } } yield ep // Usage val program: IO[Unit] = openTelemetryEntryPoint[IO].use { ep => ep.root("main").use { span => span.put("service.name" -> "example") *> span.span("child-operation").use { child => child.put("operation.type" -> "compute") *> IO.println("Processing...") } } } ``` -------------------------------- ### Create and Continue Traces with EntryPoint Source: https://context7.com/typelevel/natchez/llms.txt Demonstrates initializing root spans and continuing traces from external kernels using the EntryPoint trait. ```scala import cats.effect.{IO, Resource} import natchez.{EntryPoint, Kernel, Span} // Create a root span (new trace) def createRootSpan(ep: EntryPoint[IO]): Resource[IO, Span[IO]] = ep.root("my-operation") // Continue a trace from incoming headers def continueTrace(ep: EntryPoint[IO], headers: Map[String, String]): Resource[IO, Span[IO]] = { val kernel = Kernel(headers.map { case (k, v) => org.typelevel.ci.CIString(k) -> v }) ep.continueOrElseRoot("incoming-request", kernel) } // Full example with Http4s import org.http4s.HttpRoutes import org.http4s.dsl.io._ def routes(ep: EntryPoint[IO]): HttpRoutes[IO] = HttpRoutes.of[IO] { case req @ (GET -> Root / "hello" / name) => val kernel = Kernel(req.headers.headers.map(h => org.typelevel.ci.CIString(h.name.toString) -> h.value ).toMap) ep.continueOrElseRoot("hello", kernel).use { span => span.put("user.name" -> name) *> Ok(s"Hello, $name.") } } ``` -------------------------------- ### Construct Honeycomb EntryPoint Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/backends/honeycomb.md Initialize a Honeycomb EntryPoint using the provided service name and configuration builder. ```scala import cats.effect.{ Resource, Sync } import natchez.EntryPoint import natchez.honeycomb.Honeycomb def entryPoint[F[_]: Sync]: Resource[F, EntryPoint[F]] = Honeycomb.entryPoint[F]("my-service") { ob => Sync[F].delay { ob.setWriteKey("") .setDataset("") .build } } ``` -------------------------------- ### Configure Datadog EntryPoint Source: https://context7.com/typelevel/natchez/llms.txt Initializes a Datadog tracer entry point or uses an existing global tracer. Requires the natchez-datadog dependency. ```scala import cats.effect.{IO, Resource, Sync} import natchez.EntryPoint import natchez.datadog.DDTracer import java.net.URI def datadogEntryPoint[F[_]: Sync]: Resource[F, EntryPoint[F]] = DDTracer.entryPoint[F]( uriPrefix = Some(new URI("https://app.datadoghq.com")) ) { builder => Sync[F].delay { builder .serviceName("my-scala-service") .build() } } // Use existing global tracer (e.g., from Java agent) def useGlobalTracer[F[_]: Sync]: F[Option[EntryPoint[F]]] = DDTracer.globalTracerEntryPoint[F]( Some(new URI("https://app.datadoghq.com")) ) val datadogProgram: IO[Unit] = datadogEntryPoint[IO].use { ep => ep.root("http-request").use { span => span.put( "http.method" -> "POST", "http.status_code" -> 200, "resource.name" -> "/api/orders" ) } } ``` -------------------------------- ### Construct Datadog EntryPoint Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/backends/datadog.md Build a Datadog tracer and return it as a Resource. The builder is mutable and requires wrapping in Sync[F].delay. ```scala import cats.effect.{Sync, Resource} import natchez.datadog.DDTracer import natchez.EntryPoint def entryPoint[F[_]: Sync]: Resource[F, EntryPoint[F]] = DDTracer.entryPoint[F] { builder => Sync[F].delay { builder .serviceName("my-app") .build() } } ``` -------------------------------- ### Configure OpenTelemetry Entrypoint in Scala Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/backends/opentelemetry.md Constructs an OpenTelemetry entrypoint using OTLP exporter and batch span processing. Requires appropriate OpenTelemetry and Natchez dependencies. ```scala import natchez.EntryPoint import natchez.opentelemetry.OpenTelemetry import cats.effect._ import io.opentelemetry.api.common.Attributes import io.opentelemetry.semconv.ServiceAttributes import io.opentelemetry.sdk.resources.{Resource => OtelResource} import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator import io.opentelemetry.context.propagation.ContextPropagators import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter import io.opentelemetry.sdk.trace.SdkTracerProvider import io.opentelemetry.sdk.trace.`export`.BatchSpanProcessor def entryPoint[F[_]: Async]: Resource[F, EntryPoint[F]] = for { exporter <- OpenTelemetry.lift( "OtlpGrpcSpanExporter", Sync[F].delay { OtlpGrpcSpanExporter.builder() .setEndpoint("http://localhost:4317") .build() } ) processor <- OpenTelemetry.lift( "BatchSpanProcessor", Sync[F].delay { BatchSpanProcessor.builder(exporter).build() } ) tracer <- OpenTelemetry.lift( "Tracer", Sync[F].delay { SdkTracerProvider.builder() .setResource( OtelResource.create( Attributes.of(ServiceAttributes.SERVICE_NAME, "OpenTelemetryExample") ) ) .addSpanProcessor(processor) .build() } ) ep <- OpenTelemetry.entryPoint(globallyRegister = true) { builder => Resource.eval(Sync[F].delay { builder .setTracerProvider(tracer) .setPropagators( ContextPropagators.create(W3CTraceContextPropagator.getInstance()) ) } )} } yield ep ``` -------------------------------- ### Configure OpenTelemetry EntryPoint Source: https://github.com/typelevel/natchez/blob/main/modules/opentelemetry/README.md Use a Resource to manage the lifecycle of the OpenTelemetry SDK and register the Google Cloud Trace exporter. ```scala import cats.effect.{Resource, Sync} import io.opentelemetry.api.GlobalOpenTelemetry import natchez.opentelemetry.OpenTelemetry import io.opentelemetry.sdk.OpenTelemetrySdk import io.opentelemetry.sdk.trace.SdkTracerProvider import io.opentelemetry.sdk.trace.`export`.BatchSpanProcessor import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator import io.opentelemetry.context.propagation.{ContextPropagators, TextMapPropagator} import com.google.cloud.opentelemetry.trace.{TraceConfiguration, TraceExporter} import natchez.opentelemetry.OpenTelemetry def entrypoint[F[_] : Sync](projectId: String)(configure: TraceConfiguration.Builder => TraceConfiguration.Builder): Resource[F, EntryPoint[F]] = Resource .make( Sync[F].delay( OpenTelemetrySdk .builder() .setTracerProvider( SdkTracerProvider .builder() .addSpanProcessor( BatchSpanProcessor .builder( TraceExporter .createWithConfiguration( configure(TraceConfiguration.builder().setProjectId(projectId)).build() ) ) .build() ) .build() ).setPropagators( ContextPropagators.create( TextMapPropagator.composite(W3CTraceContextPropagator.getInstance(), W3CBaggagePropagator.getInstance()) ) ).build() ) )(sdk => Sync[F].blocking { sdk.getSdkTracerProvider.close() } ) .flatMap(sdk => Resource.eval(OpenTelemetry.entryPointForSdk[F](sdk))) ``` -------------------------------- ### Implement Kleisli Trace Integration Source: https://context7.com/typelevel/natchez/llms.txt Demonstrates using Kleisli for traced computations and configuring custom environments with lens support. ```scala import cats.data.Kleisli import cats.effect.{IO, MonadCancel} import cats.syntax.all._ import natchez.{Span, Trace, EntryPoint} // Type alias for traced computations type TracedIO[A] = Kleisli[IO, Span[IO], A] // Traced business logic def businessLogic: TracedIO[String] = for { _ <- Trace[TracedIO].span("step-1") { Trace[TracedIO].put("step" -> 1) } result <- Trace[TracedIO].span("step-2") { Trace[TracedIO].put("step" -> 2) *> Kleisli.pure[IO, Span[IO], String]("completed") } } yield result // Run the traced computation def runTracedProgram(ep: EntryPoint[IO]): IO[String] = ep.root("main-operation").use { span => businessLogic.run(span) } // Custom environment with span via lens case class AppEnv(span: Span[IO], config: String) def withCustomEnv(ep: EntryPoint[IO])( implicit ev: MonadCancel[IO, Throwable] ): IO[Unit] = { val traceInstance: Trace[Kleisli[IO, AppEnv, *]] = Trace.kleisliInstance[IO].lens[AppEnv]( _.span, (env, newSpan) => env.copy(span = newSpan) ) ep.root("custom-env-operation").use { span => val env = AppEnv(span, "production") given Trace[Kleisli[IO, AppEnv, *]] = traceInstance val program: Kleisli[IO, AppEnv, Unit] = for { _ <- Trace[Kleisli[IO, AppEnv, *]].put("env" -> "production") _ <- Kleisli.ask[IO, AppEnv].flatMap(e => Kleisli.liftF(IO.println(s"Config: ${e.config}")) ) } yield () program.run(env) } } ``` -------------------------------- ### Configure Span Options and SpanKind Source: https://context7.com/typelevel/natchez/llms.txt Demonstrates how to customize span behavior including setting SpanKind, suppressing child spans, coalescing, and linking to external trace kernels. ```scala import cats.effect.IO import natchez.{Span, Kernel, EntryPoint} import org.typelevel.ci.CIString def spanOptionsExample(ep: EntryPoint[IO]): IO[Unit] = ep.root("parent-span").use { parent => // Create a client span (outgoing call) val clientOptions = Span.Options.Defaults .withSpanKind(Span.SpanKind.Client) parent.span("http-call", clientOptions).use { clientSpan => clientSpan.put("http.url" -> "https://api.example.com") } *> // Create a server span (incoming request) parent.span("handle-request", Span.Options.Defaults.withSpanKind(Span.SpanKind.Server) ).use { serverSpan => serverSpan.put("http.method" -> "GET") } *> // Suppress child span creation (useful for high-frequency operations) parent.span("high-frequency-op", Span.Options.Suppress).use { span => // This span's children will be no-ops span.span("ignored-child").use(_ => IO.unit) } *> // Coalesce spans (children attach to parent instead) parent.span("coalesced-op", Span.Options.Coalesce).use { span => span.span("attached-to-parent").use(_.put("coalesced" -> true)) } *> // Link to another trace parent.span("linked-operation", Span.Options.Defaults.withLink( Kernel(Map(CIString("traceparent") -> "00-abc-def-01")) ) ).use { _ => IO.unit } } ``` -------------------------------- ### Combine Kernels from Multiple Parent Traces Source: https://context7.com/typelevel/natchez/llms.txt Illustrates how to combine multiple trace Kernels using the Monoid instance. This is useful for linking traces when a request originates from multiple parent traces. ```scala // Combine kernels from multiple parent traces (for linking) val kernel1 = Kernel(Map(CIString("X-Trace-Id") -> "abc123")) val kernel2 = Kernel(Map(CIString("X-Parent-Id") -> "def456")) val combined = kernel1 |+| kernel2 // Uses Monoid instance ``` -------------------------------- ### Cats-Effect 3 IO Trace Instance from EntryPoint Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/reference/trace.md Constructs a `Trace[IO]` for Cats-Effect 3 from an `EntryPoint[IO]`. This creates a root span for each requested child span and uses `IOLocal` to pass the span. ```scala import cats.effect.IO import natchez.EntryPoint def goIO(ep: EntryPoint[IO]): IO[Unit] = Trace.ioTraceForEntryPoint(ep).flatMap { implicit trace => wibble[IO]("bob", 42) } ``` -------------------------------- ### Import No-Op Trace Instance Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/backends/noop.md Import the no-op instance to provide a Trace implementation that performs no operations. ```scala import natchez.Trace.Implicits.noop ``` -------------------------------- ### Record Trace Information with Span Source: https://context7.com/typelevel/natchez/llms.txt Illustrates adding attributes, logging events, creating nested child spans, and handling errors within a Span. ```scala import cats.effect.IO import cats.syntax.all._ import natchez.Span def processOrder(span: Span[IO], orderId: String): IO[Unit] = span.span("process-order").use { orderSpan => for { // Add fields to the span _ <- orderSpan.put( "order.id" -> orderId, "order.type" -> "standard", "priority" -> 1 ) // Log an event _ <- orderSpan.log("Starting order processing") // Create nested child spans _ <- orderSpan.span("validate-order").use { validateSpan => validateSpan.put("validation.step" -> "schema") *> validateSpan.log("Validation complete") } _ <- orderSpan.span("charge-payment").use { paymentSpan => paymentSpan.put("payment.method" -> "credit_card") } // Get trace information for logging traceId <- orderSpan.traceId traceUri <- orderSpan.traceUri _ <- IO.println(s"Trace ID: $traceId, View at: $traceUri") } yield () } // Error handling with spans def riskyOperation(span: Span[IO]): IO[Unit] = span.span("risky-operation").use { s => IO.raiseError(new RuntimeException("Something failed")) .handleErrorWith { err => s.attachError(err, "error.context" -> "during processing") *> IO.raiseError(err) } } ``` -------------------------------- ### Configure Honeycomb Dependency Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/backends/honeycomb.md Add the required Natchez Honeycomb dependency to your build configuration. ```sbt libraryDependencies += "$org$" %% "natchez-honeycomb_2.13" % "$version$" ``` ```Maven $org$ natchez-honeycomb_2.13 $version$ ``` ```Gradle implementation "$org$:natchez-honeycomb_2.13:$version$" ``` -------------------------------- ### No-Op Trace Instance for Development and Testing Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/reference/trace.md Provides a no-op `Trace[F]` instance for `F[_]: Applicative`. Useful for development and testing when tracing is not required. ```scala object NoTraceForYou { // In this scope we will ignore tracing import natchez.Trace.Implicits.noop // So this compiles fine def go[F[_]: Monad]: F[Unit] = wibble("bob", 42) } ``` -------------------------------- ### Run Traced Operation with Trace[IO] using IOLocal Source: https://context7.com/typelevel/natchez/llms.txt Demonstrates how to run a traced operation within IO, explicitly creating a Trace[IO] instance from a root span using IOLocal. This is suitable for Cats-Effect 3. ```scala // Using Trace[IO] with IOLocal (Cats-Effect 3) def runWithIOTrace(ep: EntryPoint[IO]): IO[Unit] = ep.root("main-operation").use { rootSpan => Trace.ioTrace(rootSpan).flatMap { implicit trace => processRequest[IO]("req-456") } } ``` -------------------------------- ### Add Google Cloud Trace dependencies Source: https://github.com/typelevel/natchez/blob/main/modules/opentelemetry/README.md Include these library dependencies in your build configuration to use the Google Cloud Trace exporter. ```scala libraryDependencies ++= Seq( "com.google.cloud.opentelemetry" % "exporter-trace" % "0.20.0", "com.google.cloud" % "google-cloud-trace" % "2.1.9" ) ``` -------------------------------- ### Cats-MTL Local Trace Instance Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/reference/trace.md Provides a `Trace[F]` instance given `MonadCancel[F, Throwable]` and `Local[F, Span[F]]`. This is more general than the Kleisli instance and requires the `natchez-mtl` module. ```scala def goLocal[F[_]]( implicit ev0: MonadCancel[F, Throwable], ev1: Local[F, Span[F]] ): F[Unit] = wibble("bob", 42) ``` -------------------------------- ### Run Operation Without Tracing using No-Op Trace Source: https://context7.com/typelevel/natchez/llms.txt Shows how to execute code without any tracing by using the no-op implementation of the Trace typeclass. This is useful for testing or environments where tracing is not desired. ```scala // No-op Trace for testing def runWithoutTracing: IO[Unit] = { import natchez.Trace.Implicits.noop processRequest[IO]("test-request") } ``` -------------------------------- ### Using Trace in Applicative Functors Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/backends/noop.md Demonstrates requiring a Trace instance for an applicative functor and invoking it with a supported type. ```scala import natchez.Trace def foo[F[_]: Trace]: F[Unit] = ??? // Trace[Option] is satisfied, for example. def go = foo[Option] ``` -------------------------------- ### Use Global Datadog Tracer Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/backends/datadog.md Access an already registered global Datadog tracer. Returns None if no tracer is currently registered. ```scala import java.net.URI // Will return `None` if there's no tracer registered already def entryPointUseGlobal[F[_]: Sync]: F[Option[EntryPoint[F]]] = DDTracer.globalTracerEntryPoint[F](Some(new URI(s"https://app.datadoghq.com"))) ``` -------------------------------- ### Add Datadog Dependency Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/backends/datadog.md Include the natchez-datadog dependency in your build configuration to enable Datadog tracing support. ```sbt libraryDependencies += "$org$" %% "natchez-datadog_2.13" % "$version$" ``` ```Maven $org$ natchez-datadog_2.13 $version$ ``` ```Gradle implementation "$org$:natchez-datadog_2.13:$version$" ``` -------------------------------- ### Propagate Trace Context in Outgoing HTTP Request Source: https://context7.com/typelevel/natchez/llms.txt Demonstrates how to extract trace context from a Span into a Kernel and then convert it into HTTP headers for propagation to a downstream service. Requires http4s client. ```scala import cats.effect.IO import cats.syntax.all._ import natchez.{Span, Kernel} import org.http4s.{Header, Uri} import org.http4s.Method.GET import org.http4s.client.Client import org.http4s.client.dsl.io._ import org.typelevel.ci.CIString // Propagate trace context in outgoing HTTP request def callDownstreamService( span: Span[IO], client: Client[IO], uri: Uri ): IO[String] = span.kernel.flatMap { kernel => // Convert kernel to HTTP headers val headers = kernel.toHeaders.map { case (k, v) => Header.Raw(CIString(k.toString), v) }.toSeq client.expect[String](GET(uri).withHeaders(headers)) } ``` -------------------------------- ### Continue Traces in Http4s Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/reference/entrypoints.md Attempts to continue a trace from incoming headers by constructing a Kernel, falling back to a root span if invalid. ```scala def continuedRoutes(ep: EntryPoint[IO]): HttpRoutes[IO] = HttpRoutes.of[IO] { case req@(GET -> Root / "hello" / name) => val k: Kernel = Kernel(req.headers.headers.map { h => h.name -> h.value }.toMap) ep.continueOrElseRoot("hello", k).use { span => span.put("the-name" -> name) *> Ok(s"Hello, $name.") } } ``` -------------------------------- ### Add Natchez Core Dependency Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/index.md Use this dependency if you wish to write library code that supports any tracing back-end. It is also available for Scala-JS. ```scala @@dependency[sbt,Maven,Gradle] { group = "$org$" artifact = "$core-dep$" version = "$version$" } ``` -------------------------------- ### Constructing TraceValue instances Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/reference/tracevalues.md Explicit construction of TraceValue types using the provided constructors. ```Scala Tracevalue.StringValue("foo") ``` ```Scala TraceValue.BooleanValue(true) ``` ```Scala TraceValue.NumberValue(1.23) ``` -------------------------------- ### Register OpenCensus Agent Trace Exporter Source: https://github.com/typelevel/natchez/blob/main/modules/opencensus/README.md Use this snippet to register the OpenCensus agent trace exporter within a Resource. It ensures proper registration and unregistration, managing the exporter's lifecycle automatically. Configure the service name and any other builder options as needed. ```scala def ocAgentEntryPoint[F[_]: Sync](system: String)( configure: OcAgentTraceExporterConfiguration.Builder => OcAgentTraceExporterConfiguration.Builder) : Resource[F, EntryPoint[F]] = Resource .make( Sync[F].delay( OcAgentTraceExporter.createAndRegister(configure( OcAgentTraceExporterConfiguration.builder().setServiceName(system)) .build())))(_ => Sync[F].delay( OcAgentTraceExporter.unregister() )) .flatMap(_ => Resource.liftF(entryPoint[F])) ``` -------------------------------- ### Kleisli Trace Instance for Tagless Applications Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/reference/trace.md Discharges a `Trace` constraint given `MonadCancel[F, Throwable]` and an initial `Span[F]`. The traced computation runs within `Kleisli[F, Span[F], *]`. ```scala // Given MonadCancel[F, Throwable] and a Span[F] we can call `wibble` def go[F[_]](span: Span[F])( implicit ev: MonadCancel[F, Throwable] ): F[Unit] = wibble[Kleisli[F, Span[F], *]]("bob", 42).run(span) ``` -------------------------------- ### Trace Http4s Requests with Root Spans Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/reference/entrypoints.md Constructs a new root span within an Http4s routing handler. ```scala def routes(ep: EntryPoint[IO]): HttpRoutes[IO] = HttpRoutes.of[IO] { case GET -> Root / "hello" / name => ep.root("hello").use { span => span.put("the-name" -> name) *> Ok(s"Hello, $name.") } } ``` -------------------------------- ### Define a traced computation with Span Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/reference/trace.md Use `Trace[F].span` to create a child span for a computation. Fields can be added to the span using `Trace[F].put`. ```scala import cats.{ Applicative, Monad } import cats.data.Kleisli import cats.effect.MonadCancel import cats.mtl.Local import cats.syntax.all._ import natchez.{ Span, Trace } import natchez.mtl._ def wibble[F[_]: Monad: Trace](name: String, age: Int): F[Unit] = Trace[F].span("wibble") { for { _ <- Trace[F].put("name" -> name, "age" -> age) // ... actual method logic in F } yield () } ``` -------------------------------- ### Cats-Effect 3 IO Trace Instance from Span Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/reference/trace.md Constructs a `Trace[IO]` directly from a `Span[IO]`. This also uses `IOLocal` to pass the span around. ```scala import cats.effect.IO def goIO(span: Span[IO]): IO[Unit] = Trace.ioTrace(span).flatMap { implicit trace => wibble[IO]("bob", 42) } ``` -------------------------------- ### Http4s Client Request with Span Kernel Source: https://github.com/typelevel/natchez/blob/main/modules/docs/src/main/paradox/reference/kernels.md Adds a Span's kernel to an outgoing Http4s Client request. This allows a remote server supporting the same tracing backend to extend the trace with child spans. Ensure necessary imports are present. ```scala import cats.effect.IO import natchez.{ Span } import org.http4s.{ EntityDecoder, Uri, Header } import org.http4s.Method.GET import org.http4s.client.Client import org.http4s.client.dsl.io._ def makeRequest[A](span: Span[IO], client: Client[IO], uri: Uri)( implicit ev: EntityDecoder[IO, A] ): IO[A] = span.kernel.flatMap { k => // turn a Map[String, String] into List[Header] val http4sHeaders = k.toHeaders.map { case (k, v) => Header.Raw(k, v) } .toSeq client.expect[A](GET(uri).withHeaders(http4sHeaders)) } ``` -------------------------------- ### Define Request Processing Function with Trace Typeclass Source: https://context7.com/typelevel/natchez/llms.txt Defines a function to process a request, incorporating tracing for the entire operation and nested calls. It demonstrates putting tags, logging, and accessing the trace ID. ```scala def processRequest[F[_]: Trace: Monad](requestId: String): F[Unit] = Trace[F].span("process-request") { for { _ <- Trace[F].put("request.id" -> requestId) user <- fetchUser[F]("user-123") _ <- Trace[F].put("result.user" -> user) traceId <- Trace[F].traceId _ <- Trace[F].log(s"Completed with trace: $traceId") } yield () } ``` -------------------------------- ### Define Generic Traced Function with Trace Typeclass Source: https://context7.com/typelevel/natchez/llms.txt Defines a generic function that requires a Trace instance for the effect type. Use this when tracing is a cross-cutting concern in tagless-final style. ```scala import cats.Monad import cats.effect.IO import cats.syntax.all._ import natchez.{Trace, Span, EntryPoint} // Generic traced function using Trace constraint def fetchUser[F[_]: Trace: Monad](userId: String): F[String] = Trace[F].span("fetch-user") { for { _ <- Trace[F].put("user.id" -> userId) _ <- Trace[F].log("Fetching user from database") // ... actual database call } yield s"User $userId" } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.