Skip to content

Commit

Permalink
Module pattern 2.0 (#586)
Browse files Browse the repository at this point in the history
* Change return type of Tracing.spanFromUnsafe

* Migrate opentracing module

* Migrate opencensus module

* Refactoring: unify creation of components

* Refactoring: continue unification (opentelemetry)

* add override to the methods

* tidy up docs of methods

* Prettify Dependencies

* Remove accessor methods, unify API

* Use TextMapAdapter in tests

* Migrate opentracing-example

* Migrate opentelemetry-example

* Fix tests

* Fix warning

* Refactor Clients from examples

* Add zio Trace to all methods of opentelemetry module

* Add zio Trace to all methods of opentracing module

* Add zio Trace to all methods of opencensus module

* Use case class instead of type alias for ErrorMapper

* Add aspects as replacement for syntax in opentelemetry

* Use aspects in opentelemetry example

* Add aspects as replacement for syntax in opencensus

* Add aspects as replacement for syntax in opentracing

* Use aspects in opentracing example

* Use aspect in tests of opentelemetry

* Use aspects in tests of opentracing

* Improve methods API

* Update usecases docs

* Update opentelemetry docs

* Update opentracing docs

* Add inject aspect in opentracing

* Update opencensus docs
  • Loading branch information
grouzen authored Nov 15, 2022
1 parent 876bddb commit d214536
Show file tree
Hide file tree
Showing 54 changed files with 2,074 additions and 1,820 deletions.
67 changes: 42 additions & 25 deletions docs/overview/opencensus.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,39 @@ First, add the following dependency to your build.sbt:

To use ZIO Telemetry, you will need a `Tracing` service in your environment. You also need to provide a `tracer` implementation:

After importing `import zio.telemetry.opencensus._`, additional combinators
```scala
import zio.telemetry.opencensus.Tracing
import zio.telemetry.opencensus.implicits._
import zio._
import io.opencensus.trace.Status

val tracerLayer = ZLayer.succeed(io.opencensus.trace.Tracing.getTracer)

val errorMapper = ErrorMapper[Throwable] { case _ => Status.UNKNOWN }

val app =
ZIO.serviceWithZIO[Tracing] { tracing =>
import tracing.aspects._

(for {
_ <- tracing.putAttributes(Map("foo" -> "bar"))
message <- Console.readline
} yield message) @@ root("/app")
}.provide(Tracing.live, tracerLayer)
```

After importing `import tracing.aspects._`, additional `ZIOAspect` combinators
on `ZIO`s are available to support starting child spans and adding attributes.

```scala
// start a new root span and set some attributes
val zio = ZIO.unit
.root("root span", attributes = ("foo", "bar))
// start a child of the current span
val zio = ZIO.unit
.span("child span", attributes = Map.empty)
ZIO.serviceWithZIO[Tracing] { tracing =>
import tracing.aspects._

// start a new root span and set some attributes
val zio1 = ZIO.unit @@ root("root span", attributes = ("foo", "bar))
// start a child of the current span
val zio2 = ZIO.unit @@ span("child span", attributes = Map.empty)
}
```

To propagate contexts across process boundaries, extraction and injection can be
Expand All @@ -39,7 +62,10 @@ are not referentially transparent.


```scala
val textFormat = Tracing.getPropagationComponent().getB3Format()
ZIO.serviceWithZIO[Tracing] { tracing =>
import tracing.aspects._
val textFormat = Tracing.getPropagationComponent().getB3Format()
val carrier: mutable.Map[String, String] = mutable.Map().empty

val getter: TextFormat.Getter[mutable.Map[String, String]] = new TextFormat.Getter[mutable.Map[String, String]] {
Expand All @@ -54,21 +80,12 @@ val textFormat = Tracing.getPropagationComponent().get
override def put(carrier: mutable.Map[String, String], key: String, value: String): Unit =
carrier.update(key, value)
}

val injectExtract =
inject(
textFormat,
carrier,
setter
).root("root span", attributes = Map.empty)
fromRootSpan(
textFormat,
carrier,
getter,
"foo",
attributes = Map.empty
) {
ZIO.unit
.span("child span", attributes = Map(("foo", "bar")))
}
val zio1 = tracing.inject(textFormat, carrier, setter) @@
root("root span", attributes = Map.empty)
val zio2 = ZIO.unit @@
span("child span", attributes = Map(("foo", "bar"))) @@
fromRootSpan(textFormat, carrier, getter, "foo", attributes = Map.empty)
}
```
94 changes: 49 additions & 45 deletions docs/overview/opentelemetry.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,44 +15,50 @@ First, add the following dependency to your build.sbt:

## Usage

To use ZIO Telemetry, you will need a `Tracing` service in your environment. You also need to provide a `tracer` implementation:
To use ZIO Telemetry, you will need a `Tracing` service in your environment. You also need to provide a `tracer`
(for this example we use `JaegerTracer.live` from `opentelemetry-example` module) implementation:

```scala
import zio.telemetry.opentelemetry.Tracing
import zio.telemetry.opentelemetry.example.JaegerTracer
import io.opentelemetry.api.trace.{ SpanKind, StatusCode }
import zio._
import zio.telemetry.opentelemetry.Tracing
import zio.telemetry.opentelemetry.Tracing.root

val errorMapper = { case _ => StatusCode.UNSET }
val errorMapper = ErrorMapper[Throwable]{ case _ => StatusCode.UNSET }

val app =
//start root span that lasts until the effect finishes
root("root span", SpanKind.INTERNAL, errorMapper) {
for {
val app =
ZIO.serviceWithZIO[Tracing] { tracing =>
import tracing.aspects._

(for {
//sets an attribute to the current span
_ <- Tracing.setAttribute("foo", "bar")
_ <- tracing.setAttribute("foo", "bar")
//adds an event to the current span
_ <- Tracing.addEvent("foo")
_ <- tracing.addEvent("foo")
message <- Console.readline
_ <- Tracing.addEvent("bar")
} yield message
}.provideLayer(tracer >>> Tracing.live)
_ <- tracing.addEvent("bar")
} yield message) @@ root("root span", SpanKind.INTERNAL, errorMapper)
}.provide(Tracing.live, JaegerTracer.live)
```

After importing `import zio.telemetry.opentelemetry._`, additional combinators
After importing `import tracing.aspects._`, additional `ZIOAspect` combinators
on `ZIO`s are available to support starting child spans, adding events and setting attributes.

```scala
// start a new root span and set some attribute
val zio = ZIO.unit
.setAttribute("foo", "bar")
.root("root span")

// start a child of the current span, set an attribute and add an event
val zio = ZIO.unit
.setAttribute("http.status_code", 200)
.addEvent("doing some serious work here!")
.span("child span")
ZIO.serviceWithZIO[Tracing] { tracing =>
import tracing.aspects._

// start a new root span and set some attribute
val zio1 = ZIO.unit @@
setAttribute("foo", "bar") @@
root("root span")

// start a child of the current span, set an attribute and add an event
val zio2 = ZIO.unit @@
setAttribute("http.status_code", 200) @@
addEvent("doing some serious work here!") @@
span("child span")
}
```

To propagate contexts across process boundaries, extraction and injection can be
Expand All @@ -64,28 +70,26 @@ Due to the use of the (mutable) OpenTelemetry carrier APIs, injection and extrac
are not referentially transparent.

```scala
val propagator = W3CTraceContextPropagator.getInstance()
val carrier: mutable.Map[String, String] = mutable.Map().empty

val getter: TextMapGetter[mutable.Map[String, String]] = new TextMapGetter[mutable.Map[String, String]] {
override def keys(carrier: mutable.Map[String, String]): lang.Iterable[String] =
carrier.keys.asJava

override def get(carrier: mutable.Map[String, String], key: String): String =
carrier.get(key).orNull
ZIO.serviceWithZIO[Tracing] { tracing =>
import tracing.aspects._

val propagator = W3CTraceContextPropagator.getInstance()
val carrier: mutable.Map[String, String] = mutable.Map().empty

val getter: TextMapGetter[mutable.Map[String, String]] = new TextMapGetter[mutable.Map[String, String]] {
override def keys(carrier: mutable.Map[String, String]): lang.Iterable[String] =
carrier.keys.asJava

override def get(carrier: mutable.Map[String, String], key: String): String =
carrier.get(key).orNull
}

val setter: TextMapSetter[mutable.Map[String, String]] =
(carrier, key, value) => carrier.update(key, value)

tracing.inject(propagator, carrier, setter) @@ span("foo") *>
ZIO.unit @@ spanFrom(propagator, carrier, getter, "baz") @@ span("bar")
}

val setter: TextMapSetter[mutable.Map[String, String]] =
(carrier, key, value) => carrier.update(key, value)

val injectExtract =
inject(
propagator,
carrier,
setter
).span("foo") *> ZIO.unit
.spanFrom(propagator, carrier, getter, "baz")
.span("bar")
```

### [Experimental] Usage with OpenTelemetry automatic instrumentation
Expand Down
61 changes: 39 additions & 22 deletions docs/overview/opentracing.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,47 @@ First, add the following dependency to your build.sbt:
## Usage

To use ZIO Telemetry, you will need an `OpenTracing` service in your
environment:
environment. You also need to provide a `tracer` (for this example we use `JaegerTracer.live` from `opentracing-example` module) implementation:

```scala
import io.opentracing.mock.MockTracer
import io.opentracing.propagation._
import zio.telemetry.opentracing.OpenTracing
import zio.telemetry.opentracing.example.JaegerTracer
import zio._
import zio.telemetry.opentracing._
import io.opentracing.tag.Tags

val tracer = new MockTracer
val app =
ZIO.serviceWithZIO[OpenTracing] { tracing =>
import tracing.aspects._

val layer = OpenTracing.live(tracer)
(for {
_ <- ZIO.unit @@ tag(Tags.SPAN_KIND.getKey, Tags.SPAN_KIND_CLIENT)
_ <- ZIO.unit @@ tag(Tags.HTTP_METHOD.getKey, "GET")
_ <- ZIO.unit @@ setBaggageItem("proxy-baggage-item-key", "proxy-baggage-item-value")
message <- Console.readline
_ <- ZIO.unit @@ log("Message has been read")
} yield message) @@ root("/app")
}.provide(OpenTracing.live, JaegerTracer.live("my-app"))
```

After importing `import zio.telemetry.opentracing._`, additional combinators
After importing `import tracing.aspects._`, additional `ZIOAspect` combinators
on `ZIO`s are available to support starting child spans, tagging, logging and
managing baggage.

```scala
// start a new root span and set some baggage item
val zio = ZIO.unit
.setBaggage("foo", "bar")
.root("root span")

// start a child of the current span, set a tag and log a message
val zio = ZIO.unit
.tag("http.status_code", 200)
.log("doing some serious work here!")
.span("child span")
ZIO.serviceWithZIO[OpenTracing] { tracing =>
import tracing.aspects._

// start a new root span and set some baggage item
val zio1 = ZIO.unit @@
setBaggage("foo", "bar") @@
root("root span")

// start a child of the current span, set a tag and log a message
val zio2 = ZIO.unit @@
tag("http.status_code", 200) @@
log("doing some serious work here!") @@
span("child span")
}
```

To propagate contexts across process boundaries, extraction and injection can be
Expand All @@ -58,9 +71,13 @@ Due to the use of the (mutable) OpenTracing carrier APIs, injection and extracti
are not referentially transparent.

```scala
val buffer = new TextMapAdapter(mutable.Map.empty.asJava)
for {
_ <- zio.inject(Format.Builtin.TEXT_MAP, buffer)
_ <- zio.spanFrom(Format.Builtin.TEXT_MAP, buffer, "child of remote span")
} yield buffer
ZIO.serviceWithZIO[OpenTracing] { tracing =>
import tracing.aspects._

val buffer = new TextMapAdapter(mutable.Map.empty.asJava)
for {
_ <- ZIO.unit @@ inject(Format.Builtin.TEXT_MAP, buffer)
_ <- ZIO.unit @@ spanFrom(Format.Builtin.TEXT_MAP, buffer, "child of remote span")
} yield buffer
}
```
8 changes: 4 additions & 4 deletions docs/usecases/opentelemetry_example.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ docker run --rm -it \
jaegertracing/all-in-one:1.36
```

Then start the proxy server
Then start the proxy application
```bash
sbt "opentelemetryExample/runMain zio.telemetry.opentelemetry.example.ProxyServer"
sbt "opentelemetryExample/runMain zio.telemetry.opentelemetry.example.ProxyApp"
```
and the backend server
and the backend application

```bash
sbt "opentelemetryExample/runMain zio.telemetry.opentelemetry.example.BackendServer"
sbt "opentelemetryExample/runMain zio.telemetry.opentelemetry.example.BackendApp"
```
Now perform the following request:
```bash
Expand Down
29 changes: 16 additions & 13 deletions docs/usecases/opentracing_example.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,54 +23,57 @@ To check if it's running properly visit [Jaeger UI](http://localhost:16686/).
More info can be found [here](https://www.jaegertracing.io/docs/1.6/getting-started/#all-in-one-docker-image).

Our application contains two services:
1. [Proxy](https://github.com/zio/zio-telemetry/blob/master/opentracing-example/src/main/scala/zio/telemetry/opentracing/example/ProxyServer.scala) service
2. [Backend](https://github.com/zio/zio-telemetry/blob/master/opentracing-example/src/main/scala/zio/telemetry/opentracing/example/BackendServer.scala) service
1. [Proxy](https://github.com/zio/zio-telemetry/blob/master/opentracing-example/src/main/scala/zio/telemetry/opentracing/example/ProxyApp.scala) service
2. [Backend](https://github.com/zio/zio-telemetry/blob/master/opentracing-example/src/main/scala/zio/telemetry/opentracing/example/BackendApp.scala) service

### Proxy Service

Represents the entry point of the distributed system example. It exposes the `/statuses` endpoint which returns a list of system's services statuses.

The service consists of `ProxyServer` and `ProxyApp`.
The service consists of `ProxyHttpServer` and `ProxyHttpApp`.

#### ProxyServer
#### ProxyApp

In order to start the service run:
```bash
sbt "opentracingExample/runMain zio.telemetry.opentracing.example.ProxyServer"
sbt "opentracingExample/runMain zio.telemetry.opentracing.example.ProxyApp"
```

The console should output
```bash
ProxyServer started on port 8080
running zio.telemetry.opentracing.example.ProxyApp
```
if the server has been started properly.

#### ProxyApp
#### ProxyHttpApp

Provides the implementation of the service, which returns the status of the backend service and the proxy service itself. `Client` is used to retrieve the status of the backend service.
Provides the implementation of the service, which returns the status of the backend service and the proxy service itself.
`Client` is used to retrieve the status of the backend service.

This is also where the tracing of the application is done, by collecting the timings and logging things such as the span type and the HTTP method. The context is injected into a carrier, and passed along to the backend through `Client`, where a child span is created, and logging of the backend service is done.
This is also where the tracing of the application is done, by collecting the timings and logging things such as the span
type and the HTTP method. The context is injected into a carrier, and passed along to the backend through `Client`,
where a child span is created, and logging of the backend service is done.

### Backend Service

Represents the "internal" service of the system. It exposes the `/status` endpoint which returns the status of the backend service.

The service consists of `BackendServer` and `BackendApp`.

#### BackendServer
#### BackendApp

In order to start the service run:
```bash
sbt "opentracingExample/runMain zio.telemetry.opentracing.example.BackendServer"
sbt "opentracingExample/runMain zio.telemetry.opentracing.example.BackendApp"
```

The console should output
```bash
BackendServer started on port 9000
running zio.telemetry.opentracing.example.BackendApp
```
if the server has been started properly.

#### BackendApp
#### BackendHttpApp

Provides the implementation of the service, which is to simply return the status of the backend service.

Expand Down
Loading

0 comments on commit d214536

Please sign in to comment.