From e8dd3517e0ad8b46bad0b2d0ebe906e0be1e2185 Mon Sep 17 00:00:00 2001 From: Jorge Aliss Date: Fri, 28 Jul 2023 05:39:15 -0300 Subject: [PATCH] Add required traces to the http package (#2326) * Add required traces to the http package * removed comments --- zio-http/src/main/scala/zio/http/Body.scala | 9 ++-- .../src/main/scala/zio/http/Boundary.scala | 5 ++- .../src/main/scala/zio/http/Channel.scala | 5 ++- .../main/scala/zio/http/ClientDriver.scala | 6 ++- .../src/main/scala/zio/http/DnsResolver.scala | 45 ++++++++++++------- zio-http/src/main/scala/zio/http/Driver.scala | 2 +- zio-http/src/main/scala/zio/http/Form.scala | 9 ++-- .../src/main/scala/zio/http/FormField.scala | 12 ++--- .../src/main/scala/zio/http/Handler.scala | 24 ++++++---- .../main/scala/zio/http/HandlerAspect.scala | 2 +- .../src/main/scala/zio/http/Headers.scala | 4 +- .../src/main/scala/zio/http/HttpApp.scala | 9 ++-- .../src/main/scala/zio/http/HttpError.scala | 2 + .../src/main/scala/zio/http/Middleware.scala | 8 +++- .../main/scala/zio/http/ProtocolStack.scala | 42 +++++++++-------- .../src/main/scala/zio/http/Request.scala | 9 ++-- .../src/main/scala/zio/http/Response.scala | 25 ++++++----- .../src/main/scala/zio/http/ZClient.scala | 2 +- .../zio/http/internal/HeaderModifier.scala | 4 +- .../test/scala/zio/http/DnsResolverSpec.scala | 2 +- 20 files changed, 136 insertions(+), 90 deletions(-) diff --git a/zio-http/src/main/scala/zio/http/Body.scala b/zio-http/src/main/scala/zio/http/Body.scala index fd0fa9a930..5db47ac0d4 100644 --- a/zio-http/src/main/scala/zio/http/Body.scala +++ b/zio-http/src/main/scala/zio/http/Body.scala @@ -21,6 +21,7 @@ import java.nio.charset._ import java.nio.file._ import zio._ +import zio.stacktracer.TracingImplicits.disableAutoTrace import zio.stream.ZStream @@ -161,7 +162,7 @@ object Body { def fromMultipartForm( form: Form, specificBoundary: Boundary, - ): Body = { + )(implicit trace: Trace): Body = { val bytes = form.multipartBytes(specificBoundary) StreamBody(bytes, Some(MediaType.multipart.`form-data`), Some(specificBoundary)) @@ -174,7 +175,7 @@ object Body { */ def fromMultipartFormUUID( form: Form, - ): UIO[Body] = + )(implicit trace: Trace): UIO[Body] = form.multipartBytesUUID.map { case (boundary, bytes) => StreamBody(bytes, Some(MediaType.multipart.`form-data`), Some(boundary)) } @@ -331,8 +332,8 @@ object Body { copy(mediaType = Some(newMediaType), boundary = boundary.orElse(newBoundary)) } - private val zioEmptyArray = ZIO.succeed(Array.empty[Byte]) + private val zioEmptyArray = ZIO.succeed(Array.empty[Byte])(Trace.empty) - private val zioEmptyChunk = ZIO.succeed(Chunk.empty[Byte]) + private val zioEmptyChunk = ZIO.succeed(Chunk.empty[Byte])(Trace.empty) } diff --git a/zio-http/src/main/scala/zio/http/Boundary.scala b/zio-http/src/main/scala/zio/http/Boundary.scala index 4171e20db0..90993f0059 100644 --- a/zio-http/src/main/scala/zio/http/Boundary.scala +++ b/zio-http/src/main/scala/zio/http/Boundary.scala @@ -18,7 +18,8 @@ package zio.http import java.nio.charset.Charset -import zio.Chunk +import zio.stacktracer.TracingImplicits.disableAutoTrace +import zio.{Chunk, Trace} /** * A multipart boundary, which consists of both the boundary and its charset. @@ -72,7 +73,7 @@ object Boundary { def fromString(content: String, charset: Charset): Option[Boundary] = fromContent(Chunk.fromArray(content.getBytes(charset)), charset) - def randomUUID: zio.UIO[Boundary] = + def randomUUID(implicit trace: Trace): zio.UIO[Boundary] = zio.Random.nextUUID.map { id => Boundary(s"(((${id.toString()})))") } diff --git a/zio-http/src/main/scala/zio/http/Channel.scala b/zio-http/src/main/scala/zio/http/Channel.scala index e729629feb..edfcb37f98 100644 --- a/zio-http/src/main/scala/zio/http/Channel.scala +++ b/zio-http/src/main/scala/zio/http/Channel.scala @@ -17,6 +17,7 @@ package zio.http import zio._ +import zio.stacktracer.TracingImplicits.disableAutoTrace /** * A `Channel` is an asynchronous communication channel that supports receiving @@ -72,7 +73,7 @@ trait Channel[-In, +Out] { self => * Constructs a new channel that automatically transforms messages received * from this channel using the specified function. */ - final def map[Out2](f: Out => Out2): Channel[In, Out2] = + final def map[Out2](f: Out => Out2)(implicit trace: Trace): Channel[In, Out2] = new Channel[In, Out2] { def awaitShutdown: UIO[Unit] = self.awaitShutdown @@ -90,6 +91,6 @@ trait Channel[-In, +Out] { self => * Reads all messages from the channel, handling them with the specified * function. */ - final def receiveAll[Env](f: Out => ZIO[Env, Throwable, Any]): ZIO[Env, Throwable, Nothing] = + final def receiveAll[Env](f: Out => ZIO[Env, Throwable, Any])(implicit trace: Trace): ZIO[Env, Throwable, Nothing] = receive.flatMap(f).forever } diff --git a/zio-http/src/main/scala/zio/http/ClientDriver.scala b/zio-http/src/main/scala/zio/http/ClientDriver.scala index 8908441800..48e2bdfe72 100644 --- a/zio-http/src/main/scala/zio/http/ClientDriver.scala +++ b/zio-http/src/main/scala/zio/http/ClientDriver.scala @@ -16,11 +16,11 @@ package zio.http +import zio.stacktracer.TracingImplicits.disableAutoTrace import zio.{Promise, Scope, Trace, ZIO, ZLayer} import zio.http.ClientDriver.ChannelInterface import zio.http.netty.client.ChannelState - trait ClientDriver { type Connection @@ -46,11 +46,13 @@ object ClientDriver { def interrupt: ZIO[Any, Throwable, Unit] } - val shared: ZLayer[Driver, Throwable, ClientDriver] = + val shared: ZLayer[Driver, Throwable, ClientDriver] = { + implicit val trace: Trace = Trace.empty ZLayer.scoped { for { driver <- ZIO.service[Driver] clientDriver <- driver.createClientDriver() } yield clientDriver } + } } diff --git a/zio-http/src/main/scala/zio/http/DnsResolver.scala b/zio-http/src/main/scala/zio/http/DnsResolver.scala index e8156cc2bb..7122d0726f 100644 --- a/zio-http/src/main/scala/zio/http/DnsResolver.scala +++ b/zio-http/src/main/scala/zio/http/DnsResolver.scala @@ -20,17 +20,18 @@ import java.net.{InetAddress, UnknownHostException} import java.time.Instant import zio._ +import zio.stacktracer.TracingImplicits.disableAutoTrace trait DnsResolver { - def resolve(host: String): ZIO[Any, UnknownHostException, Chunk[InetAddress]] + def resolve(host: String)(implicit trace: Trace): ZIO[Any, UnknownHostException, Chunk[InetAddress]] } object DnsResolver { - def resolve(host: String): ZIO[DnsResolver, UnknownHostException, Chunk[InetAddress]] = + def resolve(host: String)(implicit trace: Trace): ZIO[DnsResolver, UnknownHostException, Chunk[InetAddress]] = ZIO.serviceWithZIO(_.resolve(host)) private final case class SystemResolver() extends DnsResolver { - override def resolve(host: String): ZIO[Any, UnknownHostException, Chunk[InetAddress]] = + override def resolve(host: String)(implicit trace: Trace): ZIO[Any, UnknownHostException, Chunk[InetAddress]] = ZIO .attemptBlocking(InetAddress.getAllByName(host)) .refineToOrDie[UnknownHostException] @@ -71,7 +72,7 @@ object DnsResolver { semaphore: Semaphore, entries: Ref[Map[String, CacheEntry]], ) extends DnsResolver { - override def resolve(host: String): ZIO[Any, UnknownHostException, Chunk[InetAddress]] = + override def resolve(host: String)(implicit trace: Trace): ZIO[Any, UnknownHostException, Chunk[InetAddress]] = for { now <- Clock.instant fiberId <- ZIO.fiberId @@ -102,18 +103,18 @@ object DnsResolver { } yield result /** Gets a snapshot of the cache state, for testing only */ - private[http] def snapshot(): ZIO[DnsResolver, Nothing, Map[String, CacheEntry]] = + private[http] def snapshot()(implicit trace: Trace): ZIO[DnsResolver, Nothing, Map[String, CacheEntry]] = entries.get private def startResolvingHost( host: String, targetPromise: Promise[UnknownHostException, Chunk[InetAddress]], - ): ZIO[Any, Nothing, Unit] = + )(implicit trace: Trace): ZIO[Any, Nothing, Unit] = semaphore.withPermit { resolver.resolve(host).intoPromise(targetPromise) }.fork.unit - private def refreshAndCleanup(): ZIO[Any, Nothing, Unit] = + private def refreshAndCleanup()(implicit trace: Trace): ZIO[Any, Nothing, Unit] = // Resolve only adds new entries for unseen hosts, so it is safe to do this non-atomically for { fiberId <- ZIO.fiberId @@ -126,7 +127,7 @@ object DnsResolver { private def refreshOrDropEntries( fiberId: FiberId, entries: Map[String, CacheEntry], - ): ZIO[Any, Nothing, Chunk[CachePatch]] = + )(implicit trace: Trace): ZIO[Any, Nothing, Chunk[CachePatch]] = Clock.instant.flatMap { now => ZIO .foreach(Chunk.fromIterable(entries)) { case (host, entry) => @@ -177,7 +178,9 @@ object DnsResolver { .map(_.flatten) } - private def ensureMaxSize(entries: Map[String, CacheEntry]): ZIO[Any, Nothing, Chunk[CachePatch]] = + private def ensureMaxSize( + entries: Map[String, CacheEntry], + )(implicit trace: Trace): ZIO[Any, Nothing, Chunk[CachePatch]] = if (entries.size > maxCount) { val toDrop = Chunk.fromIterable(entries).sortBy(_._2.lastUpdatedAt).take(entries.size - maxCount) ZIO @@ -208,7 +211,7 @@ object DnsResolver { maxConcurrentResolutions: Int, expireAction: ExpireAction, refreshRate: Duration, - ): ZIO[Scope, Nothing, DnsResolver] = + )(implicit trace: Trace): ZIO[Scope, Nothing, DnsResolver] = for { semaphore <- Semaphore.make(maxConcurrentResolutions) entries <- Ref.make(Map.empty[String, CacheEntry]) @@ -217,7 +220,7 @@ object DnsResolver { } yield cachingResolver } - private[http] def snapshot(): ZIO[DnsResolver, Nothing, Map[String, CacheEntry]] = + private[http] def snapshot()(implicit trace: Trace): ZIO[DnsResolver, Nothing, Map[String, CacheEntry]] = ZIO.service[DnsResolver].flatMap { case cachingResolver: CachingResolver => cachingResolver.snapshot() case _ => ZIO.dieMessage(s"Unexpected DnsResolver implementation: ${getClass.getName}") @@ -256,11 +259,13 @@ object DnsResolver { def configured( path: NonEmptyChunk[String] = NonEmptyChunk("zio", "http", "dns"), - ): ZLayer[Any, zio.Config.Error, DnsResolver] = + )(implicit trace: Trace): ZLayer[Any, zio.Config.Error, DnsResolver] = ZLayer(ZIO.config(Config.config.nested(path.head, path.tail: _*))) >>> live - val default: ZLayer[Any, Nothing, DnsResolver] = + val default: ZLayer[Any, Nothing, DnsResolver] = { + implicit val trace: Trace = Trace.empty ZLayer.succeed(Config.default) >>> live + } private[http] def explicit( ttl: Duration = 10.minutes, @@ -270,7 +275,8 @@ object DnsResolver { expireAction: ExpireAction = ExpireAction.Refresh, refreshRate: Duration = 2.seconds, implementation: DnsResolver = SystemResolver(), - ): ZLayer[Any, Nothing, DnsResolver] = + ): ZLayer[Any, Nothing, DnsResolver] = { + implicit val trace: Trace = Trace.empty ZLayer.scoped { CachingResolver .make( @@ -283,8 +289,11 @@ object DnsResolver { refreshRate, ) } + } + + lazy val live: ZLayer[DnsResolver.Config, Nothing, DnsResolver] = { + implicit val trace: Trace = Trace.empty - lazy val live: ZLayer[DnsResolver.Config, Nothing, DnsResolver] = ZLayer.scoped { for { config <- ZIO.service[Config] @@ -299,6 +308,10 @@ object DnsResolver { ) } yield resolver } + } - val system: ZLayer[Any, Nothing, DnsResolver] = ZLayer.succeed(SystemResolver()) + val system: ZLayer[Any, Nothing, DnsResolver] = { + implicit val trace: Trace = Trace.empty + ZLayer.succeed(SystemResolver()) + } } diff --git a/zio-http/src/main/scala/zio/http/Driver.scala b/zio-http/src/main/scala/zio/http/Driver.scala index 144a2a3f04..e88542fb5a 100644 --- a/zio-http/src/main/scala/zio/http/Driver.scala +++ b/zio-http/src/main/scala/zio/http/Driver.scala @@ -19,10 +19,10 @@ package zio.http import java.util.concurrent.atomic.LongAdder import zio._ +import zio.stacktracer.TracingImplicits.disableAutoTrace import zio.http.Driver.StartResult import zio.http.netty.server.NettyDriver - trait Driver { def start(implicit trace: Trace): RIO[Scope, StartResult] diff --git a/zio-http/src/main/scala/zio/http/Form.scala b/zio-http/src/main/scala/zio/http/Form.scala index 93047272e4..8c1068f280 100644 --- a/zio-http/src/main/scala/zio/http/Form.scala +++ b/zio-http/src/main/scala/zio/http/Form.scala @@ -20,6 +20,7 @@ import java.io.UnsupportedEncodingException import java.nio.charset.Charset import zio._ +import zio.stacktracer.TracingImplicits.disableAutoTrace import zio.stream._ @@ -46,7 +47,7 @@ final case class Form(formData: Chunk[FormField]) { * Runs all streaming form data and stores them in memory, returning a Form * that has no streaming parts. */ - def collectAll: ZIO[Any, Throwable, Form] = + def collectAll(implicit trace: Trace): ZIO[Any, Throwable, Form] = ZIO .foreach(formData) { case streamingBinary: StreamingBinary => @@ -71,7 +72,7 @@ final case class Form(formData: Chunk[FormField]) { * Encodes the form using multipart encoding, choosing a random UUID as the * boundary. */ - def multipartBytesUUID: zio.UIO[(Boundary, ZStream[Any, Nothing, Byte])] = + def multipartBytesUUID(implicit trace: Trace): zio.UIO[(Boundary, ZStream[Any, Nothing, Byte])] = Boundary.randomUUID.map { boundary => boundary -> multipartBytes(boundary) } @@ -81,7 +82,7 @@ final case class Form(formData: Chunk[FormField]) { */ def multipartBytes( boundary: Boundary, - ): ZStream[Any, Nothing, Byte] = { + )(implicit trace: Trace): ZStream[Any, Nothing, Byte] = { val encapsulatingBoundary = FormAST.EncapsulatingBoundary(boundary) val closingBoundary = FormAST.ClosingBoundary(boundary) @@ -201,7 +202,7 @@ object Form { def fromMultipartBytes( bytes: Chunk[Byte], charset: Charset = Charsets.Utf8, - ): ZIO[Any, Throwable, Form] = + )(implicit trace: Trace): ZIO[Any, Throwable, Form] = for { boundary <- ZIO .fromOption(Boundary.fromContent(bytes, charset)) diff --git a/zio-http/src/main/scala/zio/http/FormField.scala b/zio-http/src/main/scala/zio/http/FormField.scala index 3d059f9a3a..41bd786337 100644 --- a/zio-http/src/main/scala/zio/http/FormField.scala +++ b/zio-http/src/main/scala/zio/http/FormField.scala @@ -15,10 +15,10 @@ */ package zio.http - import java.nio.charset._ import zio._ +import zio.stacktracer.TracingImplicits.disableAutoTrace import zio.stream.{Take, ZPipeline, ZStream} @@ -49,7 +49,7 @@ sealed trait FormField { * Gets the value of this form field as a String. If it is a binary field, the * value is interpreted as an UTF-8 byte stream. */ - final def asText: ZIO[Any, CharacterCodingException, String] = this match { + final def asText(implicit trace: Trace): ZIO[Any, CharacterCodingException, String] = this match { case FormField.Text(_, value, _, _) => ZIO.succeed(value) case FormField.Binary(_, value, _, _, _) => @@ -64,7 +64,7 @@ sealed trait FormField { * Gets the value of this form field as a chunk of bytes. If it is a text * field, the value gets encoded as an UTF-8 byte stream. */ - final def asChunk: ZIO[Any, Nothing, Chunk[Byte]] = this match { + final def asChunk(implicit trace: Trace): ZIO[Any, Nothing, Chunk[Byte]] = this match { case FormField.Text(_, value, _, _) => ZIO.succeed(Chunk.fromArray(value.getBytes(Charsets.Utf8))) case FormField.Binary(_, value, _, _, _) => @@ -123,7 +123,7 @@ object FormField { filename: Option[String] = None, data: ZStream[Any, Nothing, Byte], ) extends FormField { - def collect: ZIO[Any, Nothing, Binary] = { + def collect(implicit trace: Trace): ZIO[Any, Nothing, Binary] = { data.runCollect.map { bytes => Binary(name, bytes, contentType, transferEncoding, filename) } @@ -145,7 +145,7 @@ object FormField { private[http] def fromFormAST( ast: Chunk[FormAST], defaultCharset: Charset = StandardCharsets.UTF_8, - ): ZIO[Any, FormDecodingError, FormField] = { + )(implicit trace: Trace): ZIO[Any, FormDecodingError, FormField] = { val extract = ast.foldLeft( ( @@ -197,7 +197,7 @@ object FormField { private[http] def incomingStreamingBinary( ast: Chunk[FormAST], queue: Queue[Take[Nothing, Byte]], - ): ZIO[Any, FormDecodingError, FormField] = { + )(implicit trace: Trace): ZIO[Any, FormDecodingError, FormField] = { val extract = ast.foldLeft((Option.empty[FormAST.Header], Option.empty[FormAST.Header], Option.empty[FormAST.Header])) { case (accum, header: FormAST.Header) if header.name == "Content-Disposition" => diff --git a/zio-http/src/main/scala/zio/http/Handler.scala b/zio-http/src/main/scala/zio/http/Handler.scala index 11101b1054..5c07e8642f 100644 --- a/zio-http/src/main/scala/zio/http/Handler.scala +++ b/zio-http/src/main/scala/zio/http/Handler.scala @@ -28,7 +28,7 @@ import java.nio.file.{AccessDeniedException, NotDirectoryException} import scala.reflect.ClassTag import scala.util.control.NonFatal // scalafix:ok; import java.util.zip.ZipFile - +import zio.stacktracer.TracingImplicits.disableAutoTrace sealed trait Handler[-R, +Err, -In, +Out] { self => def @@[Env1 <: R, Ctx, In1 <: In](aspect: HandlerAspect[Env1, Unit])(implicit @@ -45,6 +45,7 @@ sealed trait Handler[-R, +Err, -In, +Out] { self => def @@[Env1 <: R, Ctx, In1 <: In](aspect: HandlerAspect[Env1, Ctx])(implicit zippable: Zippable.Out[Ctx, Request, In1], res: Out <:< Response, + trace: Trace, ): Handler[Env1, Response, Request, Response] = { def convert(handler: Handler[R, Err, In, Out]): Handler[R, Response, In1, Response] = handler.asInstanceOf[Handler[R, Response, In1, Response]] @@ -156,7 +157,7 @@ sealed trait Handler[-R, +Err, -In, +Out] { self => final def asOutType[Out2](implicit ev: Out <:< Out2): Handler[R, Err, In, Out2] = self.asInstanceOf[Handler[R, Err, In, Out2]] - final def body(implicit ev: Out <:< Response): Handler[R, Err, In, Body] = + final def body(implicit ev: Out <:< Response, trace: Trace): Handler[R, Err, In, Body] = self.map(_.body) /** @@ -238,7 +239,11 @@ sealed trait Handler[-R, +Err, -In, +Out] { self => def connect( url: URL, headers: Headers, - )(implicit ev1: Err <:< Throwable, ev2: WebSocketChannel <:< In): ZIO[R with Client with Scope, Throwable, Response] = + )(implicit + ev1: Err <:< Throwable, + ev2: WebSocketChannel <:< In, + trace: Trace, + ): ZIO[R with Client with Scope, Throwable, Response] = ZIO.serviceWithZIO[Client] { client => val client2 = if (url.isAbsolute) client.url(url) else client.addUrl(url) @@ -344,11 +349,12 @@ sealed trait Handler[-R, +Err, -In, +Out] { self => onSuccess, ) - final def headers(implicit ev: Out <:< Response): Handler[R, Err, In, Headers] = + final def headers(implicit ev: Out <:< Response, trace: Trace): Handler[R, Err, In, Headers] = self.map(_.headers) final def header(headerType: HeaderType)(implicit ev: Out <:< Response, + trace: Trace, ): Handler[R, Err, In, Option[headerType.HeaderValue]] = self.headers.map(_.get(headerType)) @@ -548,10 +554,10 @@ sealed trait Handler[-R, +Err, -In, +Out] { self => final def runZIO(in: In): ZIO[R, Err, Out] = self(in) - final def sandbox: Handler[R, Response, In, Out] = + final def sandbox(implicit trace: Trace): Handler[R, Response, In, Out] = self.mapErrorCause(Response.fromCause(_)) - final def status(implicit ev: Out <:< Response): Handler[R, Err, In, Status] = + final def status(implicit ev: Out <:< Response, trace: Trace): Handler[R, Err, In, Status] = self.map(_.status) /** @@ -615,7 +621,7 @@ sealed trait Handler[-R, +Err, -In, +Out] { self => HttpApp(Routes.singleton(handler.contramap[(Path, Request)](_._2))) } - def toHttpAppWS(implicit err: Err <:< Throwable, in: WebSocketChannel <:< In): HttpApp[R] = + def toHttpAppWS(implicit err: Err <:< Throwable, in: WebSocketChannel <:< In, trace: Trace): HttpApp[R] = Handler.fromZIO(self.toResponse).toHttpApp /** @@ -756,7 +762,7 @@ object Handler { def firstSuccessOf[R, Err, In, Out]( handlers: NonEmptyChunk[Handler[R, Err, In, Out]], isRecoverable: Cause[Err] => Boolean = (cause: Cause[Err]) => !cause.isDie, - ): Handler[R, Err, In, Out] = + )(implicit trace: Trace): Handler[R, Err, In, Out] = handlers.tail.foldLeft[Handler[R, Err, In, Out]](handlers.head) { (acc, handler) => acc.catchAllCause { cause => if (isRecoverable(cause)) { @@ -1109,7 +1115,7 @@ object Handler { * Updates the current Headers with new one, using the provided update * function passed. */ - override def updateHeaders(update: Headers => Headers): RequestHandler[R, Err] = + override def updateHeaders(update: Headers => Headers)(implicit trace: Trace): RequestHandler[R, Err] = self.map(_.updateHeaders(update)) } diff --git a/zio-http/src/main/scala/zio/http/HandlerAspect.scala b/zio-http/src/main/scala/zio/http/HandlerAspect.scala index 8b0a62fa2b..d1bb313723 100644 --- a/zio-http/src/main/scala/zio/http/HandlerAspect.scala +++ b/zio-http/src/main/scala/zio/http/HandlerAspect.scala @@ -795,7 +795,7 @@ private[http] trait HandlerAspects extends zio.http.internal.HeaderModifier[Hand /** * Creates middleware that will update the headers of the response. */ - override def updateHeaders(update: Headers => Headers): HandlerAspect[Any, Unit] = + override def updateHeaders(update: Headers => Headers)(implicit trace: Trace): HandlerAspect[Any, Unit] = updateResponse(_.updateHeaders(update)) /** diff --git a/zio-http/src/main/scala/zio/http/Headers.scala b/zio-http/src/main/scala/zio/http/Headers.scala index 941e9c3d5a..0409d5105b 100644 --- a/zio-http/src/main/scala/zio/http/Headers.scala +++ b/zio-http/src/main/scala/zio/http/Headers.scala @@ -16,7 +16,7 @@ package zio.http -import zio.Chunk +import zio.{Chunk, Trace} import zio.http.internal.{CaseMode, CharSequenceExtensions, HeaderOps} @@ -60,7 +60,7 @@ sealed trait Headers extends HeaderOps[Headers] with Iterable[Header] { final def modify(f: Header => Header): Headers = Headers.FromIterable(self.map(f)) - override final def updateHeaders(update: Headers => Headers): Headers = update(self) + override final def updateHeaders(update: Headers => Headers)(implicit trace: Trace): Headers = update(self) final def when(cond: Boolean): Headers = if (cond) self else Headers.Empty diff --git a/zio-http/src/main/scala/zio/http/HttpApp.scala b/zio-http/src/main/scala/zio/http/HttpApp.scala index e807f1704a..f6d5ab9cd4 100644 --- a/zio-http/src/main/scala/zio/http/HttpApp.scala +++ b/zio-http/src/main/scala/zio/http/HttpApp.scala @@ -17,6 +17,7 @@ package zio.http import zio._ +import zio.stacktracer.TracingImplicits.disableAutoTrace /** * An HTTP application is a collection of routes, all of whose errors have been @@ -84,13 +85,14 @@ final case class HttpApp[-Env](routes: Routes[Env, Response]) * Returns a new HTTP application whose requests will be timed out after the * specified duration elapses. */ - def timeout(duration: Duration): HttpApp[Env] = + def timeout(duration: Duration)(implicit trace: Trace): HttpApp[Env] = self @@ Middleware.timeout(duration) /** * Converts the HTTP application into a request handler. */ - val toHandler: Handler[Env, Nothing, Request, Response] = + val toHandler: Handler[Env, Nothing, Request, Response] = { + implicit val trace: Trace = Trace.empty Handler .fromFunctionHandler[Request] { req => val chunk = tree.get(req.method, req.path) @@ -108,6 +110,7 @@ final case class HttpApp[-Env](routes: Routes[Env, Response]) } } .merge + } /** * Accesses the underlying tree that provides fast dispatch to handlers. @@ -133,7 +136,7 @@ object HttpApp { * HTTP, you should instead look at the new way of defining routes using * [[zio.http.Routes]]. */ - def collectZIO[R](pf: PartialFunction[Request, ZIO[R, Response, Response]]): HttpApp[R] = + def collectZIO[R](pf: PartialFunction[Request, ZIO[R, Response, Response]])(implicit trace: Trace): HttpApp[R] = HttpApp( Routes.singleton { Handler.fromFunctionZIO[(Path, Request)] { case (_: Path, request: Request) => diff --git a/zio-http/src/main/scala/zio/http/HttpError.scala b/zio-http/src/main/scala/zio/http/HttpError.scala index 860713536c..b79ce70145 100644 --- a/zio-http/src/main/scala/zio/http/HttpError.scala +++ b/zio-http/src/main/scala/zio/http/HttpError.scala @@ -16,6 +16,8 @@ package zio.http +import zio.stacktracer.TracingImplicits.disableAutoTrace + import zio.http.HttpError.HTTPErrorWithCause import zio.http.Response import zio.http.internal.OutputEncoder diff --git a/zio-http/src/main/scala/zio/http/Middleware.scala b/zio-http/src/main/scala/zio/http/Middleware.scala index 9f7fc75037..ef02428edc 100644 --- a/zio-http/src/main/scala/zio/http/Middleware.scala +++ b/zio-http/src/main/scala/zio/http/Middleware.scala @@ -16,6 +16,7 @@ package zio.http import zio._ +import zio.stacktracer.TracingImplicits.disableAutoTrace trait Middleware[-UpperEnv] { self => def apply[Env1 <: UpperEnv, Err]( @@ -129,7 +130,9 @@ object Middleware extends HandlerAspects { response.addHeaders(headers) }) - val optionsRoute = + val optionsRoute = { + implicit val trace: Trace = Trace.empty + Method.OPTIONS / trailing -> handler { (_: Path, request: Request) => val originHeader = request.header(Header.Origin) val acrmHeader = request.header(Header.AccessControlRequestMethod) @@ -154,6 +157,7 @@ object Middleware extends HandlerAspects { Response.notFound } } + } new Middleware[Any] { def apply[Env1, Err](routes: Routes[Env1, Err]): Routes[Env1, Err] = @@ -161,7 +165,7 @@ object Middleware extends HandlerAspects { } } - def timeout(duration: Duration): Middleware[Any] = + def timeout(duration: Duration)(implicit trace: Trace): Middleware[Any] = new Middleware[Any] { def apply[Env1 <: Any, Err](routes: Routes[Env1, Err]): Routes[Env1, Err] = routes.transform[Env1] { handler => diff --git a/zio-http/src/main/scala/zio/http/ProtocolStack.scala b/zio-http/src/main/scala/zio/http/ProtocolStack.scala index 53358bf130..d539248775 100644 --- a/zio-http/src/main/scala/zio/http/ProtocolStack.scala +++ b/zio-http/src/main/scala/zio/http/ProtocolStack.scala @@ -17,6 +17,7 @@ package zio.http import zio._ +import zio.stacktracer.TracingImplicits.disableAutoTrace /** * A [[zio.http.ProtocolStack]] represents a linear stack of protocol layers, @@ -59,7 +60,7 @@ sealed trait ProtocolStack[-Env, -IncomingIn, +IncomingOut, -OutgoingIn, +Outgoi final def apply[Env1 <: Env, Err >: OutgoingOut, IncomingOut1 >: IncomingOut, OutgoingIn1 <: OutgoingIn]( handler: Handler[Env1, Err, IncomingOut1, OutgoingIn1], - ): Handler[Env1, Err, IncomingIn, OutgoingOut] = + )(implicit trace: Trace): Handler[Env1, Err, IncomingIn, OutgoingOut] = Handler.fromFunctionZIO[IncomingIn] { incomingIn => incoming(incomingIn).flatMap { case (state, incomingOut) => handler(incomingOut).flatMap { outgoingIn => @@ -68,11 +69,11 @@ sealed trait ProtocolStack[-Env, -IncomingIn, +IncomingOut, -OutgoingIn, +Outgoi } } - private[http] def incoming(in: IncomingIn): ZIO[Env, OutgoingOut, (State, IncomingOut)] + private[http] def incoming(in: IncomingIn)(implicit trace: Trace): ZIO[Env, OutgoingOut, (State, IncomingOut)] // TODO: Make this the one true representation and delete `incoming` lazy val incomingHandler: Handler[Env, OutgoingOut, IncomingIn, (State, IncomingOut)] = - Handler.fromFunctionZIO[IncomingIn](incoming(_)) + Handler.fromFunctionZIO[IncomingIn](incoming(_)(Trace.empty)) def mapIncoming[IncomingOut2]( f: IncomingOut => IncomingOut2, @@ -84,15 +85,17 @@ sealed trait ProtocolStack[-Env, -IncomingIn, +IncomingOut, -OutgoingIn, +Outgoi ): ProtocolStack[Env, IncomingIn, IncomingOut, OutgoingIn, OutgoingOut2] = ProtocolStack.interceptOutgoingHandler(Handler.fromFunction(f)) ++ self - private[http] def outgoing(state: State, in: OutgoingIn): ZIO[Env, Nothing, OutgoingOut] + private[http] def outgoing(state: State, in: OutgoingIn)(implicit trace: Trace): ZIO[Env, Nothing, OutgoingOut] // TODO: Make this the one true representation and delete `outgoing` lazy val outgoingHandler: Handler[Env, Nothing, (State, OutgoingIn), OutgoingOut] = Handler.fromFunctionZIO[(State, OutgoingIn)] { case (state, in) => - outgoing(state, in) + outgoing(state, in)(Trace.empty) } - def provideEnvironment(env: ZEnvironment[Env]): ProtocolStack[Any, IncomingIn, IncomingOut, OutgoingIn, OutgoingOut] = + def provideEnvironment(env: ZEnvironment[Env])(implicit + trace: Trace, + ): ProtocolStack[Any, IncomingIn, IncomingOut, OutgoingIn, OutgoingOut] = ProtocolStack.interceptHandlerStateful(incomingHandler.provideEnvironment(env))( outgoingHandler.provideEnvironment(env), ) @@ -121,7 +124,7 @@ object ProtocolStack incoming0: Handler[Env, OutgoingOut, IncomingIn, IncomingOut], )( outgoing0: Handler[Env, Nothing, OutgoingIn, OutgoingOut], - ): ProtocolStack[Env, IncomingIn, IncomingOut, OutgoingIn, OutgoingOut] = + )(implicit trace: Trace): ProtocolStack[Env, IncomingIn, IncomingOut, OutgoingIn, OutgoingOut] = interceptHandlerStateful(incoming0.map(((), _)))(outgoing0.contramap[(Unit, OutgoingIn)](_._2)) def interceptHandlerStateful[Env, State0, IncomingIn, IncomingOut, OutgoingIn, OutgoingOut]( @@ -146,10 +149,10 @@ object ProtocolStack ) extends ProtocolStack[Env, IncomingIn, IncomingOut, Outgoing, Outgoing] { type State = Unit - def incoming(in: IncomingIn): ZIO[Env, Outgoing, (State, IncomingOut)] = + def incoming(in: IncomingIn)(implicit trace: Trace): ZIO[Env, Outgoing, (State, IncomingOut)] = handler(in).map(() -> _) - def outgoing(state: State, in: Outgoing): ZIO[Env, Nothing, Outgoing] = + def outgoing(state: State, in: Outgoing)(implicit trace: Trace): ZIO[Env, Nothing, Outgoing] = Exit.succeed(in) } private[http] final case class Outgoing[Env, Incoming, OutgoingIn, OutgoingOut]( @@ -157,9 +160,9 @@ object ProtocolStack ) extends ProtocolStack[Env, Incoming, Incoming, OutgoingIn, OutgoingOut] { type State = Unit - def incoming(in: Incoming): ZIO[Env, OutgoingOut, (State, Incoming)] = Exit.succeed(() -> in) + def incoming(in: Incoming)(implicit trace: Trace): ZIO[Env, OutgoingOut, (State, Incoming)] = Exit.succeed(() -> in) - def outgoing(state: State, in: OutgoingIn): ZIO[Env, Nothing, OutgoingOut] = + def outgoing(state: State, in: OutgoingIn)(implicit trace: Trace): ZIO[Env, Nothing, OutgoingOut] = handler(in) } private[http] final case class Concat[ @@ -176,14 +179,14 @@ object ProtocolStack ) extends ProtocolStack[Env, IncomingIn, IncomingOut, OutgoingIn, OutgoingOut] { type State = (left.State, right.State) - def incoming(in: IncomingIn): ZIO[Env, OutgoingOut, (State, IncomingOut)] = + def incoming(in: IncomingIn)(implicit trace: Trace): ZIO[Env, OutgoingOut, (State, IncomingOut)] = left.incoming(in).flatMap { case (leftState, middleIn) => right.incoming(middleIn).catchAll(out => left.outgoing(leftState, out).flip).map { case (rightState, incomingOut) => (leftState -> rightState) -> incomingOut } } - def outgoing(state: State, in: OutgoingIn): ZIO[Env, Nothing, OutgoingOut] = + def outgoing(state: State, in: OutgoingIn)(implicit trace: Trace): ZIO[Env, Nothing, OutgoingOut] = right.outgoing(state._2, in).flatMap { middleOut => left.outgoing(state._1, middleOut) } @@ -194,9 +197,10 @@ object ProtocolStack ) extends ProtocolStack[Env, IncomingIn, IncomingOut, OutgoingIn, OutgoingOut] { type State = State0 - def incoming(in: IncomingIn): ZIO[Env, OutgoingOut, (State, IncomingOut)] = incoming0(in) + def incoming(in: IncomingIn)(implicit trace: Trace): ZIO[Env, OutgoingOut, (State, IncomingOut)] = incoming0(in) - def outgoing(state: State, in: OutgoingIn): ZIO[Env, Nothing, OutgoingOut] = outgoing0(state, in) + def outgoing(state: State, in: OutgoingIn)(implicit trace: Trace): ZIO[Env, Nothing, OutgoingOut] = + outgoing0(state, in) } private[http] final case class Cond[Env, IncomingIn, IncomingOut, OutgoingIn, OutgoingOut]( predicate: IncomingIn => Boolean, @@ -205,11 +209,11 @@ object ProtocolStack ) extends ProtocolStack[Env, IncomingIn, IncomingOut, OutgoingIn, OutgoingOut] { type State = Either[ifTrue.State, ifFalse.State] - def incoming(in: IncomingIn): ZIO[Env, OutgoingOut, (State, IncomingOut)] = + def incoming(in: IncomingIn)(implicit trace: Trace): ZIO[Env, OutgoingOut, (State, IncomingOut)] = if (predicate(in)) ifTrue.incoming(in).map { case (state, out) => (Left(state), out) } else ifFalse.incoming(in).map { case (state, out) => (Right(state), out) } - def outgoing(state: State, in: OutgoingIn): ZIO[Env, Nothing, OutgoingOut] = + def outgoing(state: State, in: OutgoingIn)(implicit trace: Trace): ZIO[Env, Nothing, OutgoingOut] = state match { case Left(state) => ifTrue.outgoing(state, in) case Right(state) => ifFalse.outgoing(state, in) @@ -222,13 +226,13 @@ object ProtocolStack ) extends ProtocolStack[Env, IncomingIn, IncomingOut, OutgoingIn, OutgoingOut] { type State = Either[ifTrue.State, ifFalse.State] - def incoming(in: IncomingIn): ZIO[Env, OutgoingOut, (State, IncomingOut)] = + def incoming(in: IncomingIn)(implicit trace: Trace): ZIO[Env, OutgoingOut, (State, IncomingOut)] = predicate(in).flatMap { case true => ifTrue.incoming(in).map { case (state, out) => (Left(state), out) } case false => ifFalse.incoming(in).map { case (state, out) => (Right(state), out) } } - def outgoing(state: State, in: OutgoingIn): ZIO[Env, Nothing, OutgoingOut] = + def outgoing(state: State, in: OutgoingIn)(implicit trace: Trace): ZIO[Env, Nothing, OutgoingOut] = state match { case Left(state) => ifTrue.outgoing(state, in) case Right(state) => ifFalse.outgoing(state, in) diff --git a/zio-http/src/main/scala/zio/http/Request.scala b/zio-http/src/main/scala/zio/http/Request.scala index 19ab34304b..8faa450f74 100644 --- a/zio-http/src/main/scala/zio/http/Request.scala +++ b/zio-http/src/main/scala/zio/http/Request.scala @@ -18,7 +18,8 @@ package zio.http import java.net.InetAddress -import zio.ZIO +import zio.stacktracer.TracingImplicits.disableAutoTrace +import zio.{Trace, ZIO} import zio.http.internal.HeaderOps @@ -66,7 +67,7 @@ final case class Request( /** * Collects the potentially streaming body of the request into a single chunk. */ - def collect: ZIO[Any, Throwable, Request] = + def collect(implicit trace: Trace): ZIO[Any, Throwable, Request] = if (self.body.isComplete) ZIO.succeed(self) else self.body.asChunk.map { bytes => @@ -81,7 +82,7 @@ final case class Request( def dropTrailingSlash: Request = updateURL(_.dropTrailingSlash) /** Consumes the streaming body fully and then drops it */ - def ignoreBody: ZIO[Any, Throwable, Request] = + def ignoreBody(implicit trace: Trace): ZIO[Any, Throwable, Request] = self.collect.map(_.copy(body = Body.empty)) def patch(p: Request.Patch): Request = @@ -94,7 +95,7 @@ final case class Request( /** * Updates the headers using the provided function */ - override def updateHeaders(update: Headers => Headers): Request = + override def updateHeaders(update: Headers => Headers)(implicit trace: Trace): Request = self.copy(headers = update(self.headers)) def updateURL(f: URL => URL): Request = copy(url = f(url)) diff --git a/zio-http/src/main/scala/zio/http/Response.scala b/zio-http/src/main/scala/zio/http/Response.scala index 4bd5f7efb5..675a5f7a3e 100644 --- a/zio-http/src/main/scala/zio/http/Response.scala +++ b/zio-http/src/main/scala/zio/http/Response.scala @@ -22,6 +22,7 @@ import java.util.IllegalFormatException import scala.annotation.tailrec import zio._ +import zio.stacktracer.TracingImplicits.disableAutoTrace import zio.stream.ZStream @@ -39,7 +40,7 @@ sealed trait Response extends HeaderOps[Response] { self => * Collects the potentially streaming body of the response into a single * chunk. */ - def collect: ZIO[Any, Throwable, Response] = + def collect(implicit trace: Trace): ZIO[Any, Throwable, Response] = if (self.body.isComplete) ZIO.succeed(self) else self.body.asChunk.map { bytes => @@ -100,7 +101,7 @@ sealed trait Response extends HeaderOps[Response] { self => } /** Consumes the streaming body fully and then drops it */ - final def ignoreBody: ZIO[Any, Throwable, Response] = + final def ignoreBody(implicit trace: Trace): ZIO[Any, Throwable, Response] = self.collect.map(_.copy(body = Body.empty)) final def isWebSocket: Boolean = self match { @@ -108,7 +109,7 @@ sealed trait Response extends HeaderOps[Response] { self => case _ => false } - final def patch(p: Response.Patch): Response = p.apply(self) + final def patch(p: Response.Patch)(implicit trace: Trace): Response = p.apply(self) private[zio] def addServerTime: Boolean = false @@ -182,7 +183,8 @@ object Response { override def toString(): String = s"Response(status = $status, headers = $headers, body = $body)" - override def updateHeaders(update: Headers => Headers): Response = copy(headers = update(headers)) + override def updateHeaders(update: Headers => Headers)(implicit trace: Trace): Response = + copy(headers = update(headers)) override def serverTime: Response = new BasicResponse(body, headers, status) with InternalState { @@ -216,7 +218,8 @@ object Response { override final def toString(): String = s"SocketAppResponse(status = $status, headers = $headers, body = $body, socketApp = $socketApp0)" - override final def updateHeaders(update: Headers => Headers): Response = copy(headers = update(headers)) + override final def updateHeaders(update: Headers => Headers)(implicit trace: Trace): Response = + copy(headers = update(headers)) override final def serverTime: Response = new SocketAppResponse(body, headers, socketApp0, status) with InternalState { @@ -244,7 +247,8 @@ object Response { override def toString(): String = s"ErrorResponse(status = $status, headers = $headers, body = $body, error = $httpError0)" - override final def updateHeaders(update: Headers => Headers): Response = copy(headers = update(headers)) + override final def updateHeaders(update: Headers => Headers)(implicit trace: Trace): Response = + copy(headers = update(headers)) override final def serverTime: Response = new ErrorResponse(body, headers, httpError0, status) with InternalState { @@ -276,7 +280,8 @@ object Response { override final def toString(): String = s"NativeResponse(status = $status, headers = $headers, body = $body)" - override final def updateHeaders(update: Headers => Headers): Response = copy(headers = update(headers)) + override final def updateHeaders(update: Headers => Headers)(implicit trace: Trace): Response = + copy(headers = update(headers)) override final def serverTime: Response = new NativeResponse(body, headers, status, onClose) with InternalState { override val parent: Response = self @@ -289,8 +294,8 @@ object Response { * Models the set of operations that one would want to apply on a Response. */ sealed trait Patch { self => - def ++(that: Patch): Patch = Patch.Combine(self, that) - def apply(res: Response): Response = { + def ++(that: Patch): Patch = Patch.Combine(self, that) + def apply(res: Response)(implicit trace: Trace): Response = { @tailrec def loop(res: Response, patch: Patch): Response = @@ -390,7 +395,7 @@ object Response { * @param data * \- stream of data to be sent as Server Sent Events */ - def fromServerSentEvents(data: ZStream[Any, Nothing, ServerSentEvent]): Response = + def fromServerSentEvents(data: ZStream[Any, Nothing, ServerSentEvent])(implicit trace: Trace): Response = new BasicResponse(Body.fromStream(data.map(_.encode)), contentTypeEventStream, Status.Ok) /** diff --git a/zio-http/src/main/scala/zio/http/ZClient.scala b/zio-http/src/main/scala/zio/http/ZClient.scala index bf794ebf98..0f32687c7c 100644 --- a/zio-http/src/main/scala/zio/http/ZClient.scala +++ b/zio-http/src/main/scala/zio/http/ZClient.scala @@ -37,7 +37,7 @@ final case class ZClient[-Env, -In, +Err, +Out]( def apply(request: Request)(implicit ev: Body <:< In, trace: Trace): ZIO[Env & Scope, Err, Out] = self.request(request) - override def updateHeaders(update: Headers => Headers): ZClient[Env, In, Err, Out] = + override def updateHeaders(update: Headers => Headers)(implicit trace: Trace): ZClient[Env, In, Err, Out] = copy(headers = update(headers)) /** diff --git a/zio-http/src/main/scala/zio/http/internal/HeaderModifier.scala b/zio-http/src/main/scala/zio/http/internal/HeaderModifier.scala index fa19ef726e..255358d8c5 100644 --- a/zio-http/src/main/scala/zio/http/internal/HeaderModifier.scala +++ b/zio-http/src/main/scala/zio/http/internal/HeaderModifier.scala @@ -16,6 +16,8 @@ package zio.http.internal +import zio.Trace + import zio.http.Header.HeaderType import zio.http._ @@ -50,5 +52,5 @@ trait HeaderModifier[+A] { self => * Updates the current Headers with new one, using the provided update * function passed. */ - def updateHeaders(update: Headers => Headers): A + def updateHeaders(update: Headers => Headers)(implicit trace: Trace): A } diff --git a/zio-http/src/test/scala/zio/http/DnsResolverSpec.scala b/zio-http/src/test/scala/zio/http/DnsResolverSpec.scala index 81319210d3..633c3b9688 100644 --- a/zio-http/src/test/scala/zio/http/DnsResolverSpec.scala +++ b/zio-http/src/test/scala/zio/http/DnsResolverSpec.scala @@ -145,7 +145,7 @@ object DnsResolverSpec extends ZIOSpecDefault { } private final case class TestResolver() extends DnsResolver { - override def resolve(host: String): ZIO[Any, UnknownHostException, Chunk[InetAddress]] = + override def resolve(host: String)(implicit trace: Trace): ZIO[Any, UnknownHostException, Chunk[InetAddress]] = if (host.startsWith("host")) ZIO.succeed(Chunk(InetAddress.getByAddress(Array(127, 0, 0, host.stripPrefix("host").toByte)))) else