Skip to content

Commit

Permalink
documentation updates
Browse files Browse the repository at this point in the history
  • Loading branch information
apreifsteck committed Jun 7, 2024
1 parent 788509e commit 4347eea
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 35 deletions.
1 change: 1 addition & 0 deletions content/en/docs/languages/erlang/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ cascade:
otelExporter: 1.6
otelPhoenix: 1.1
otelCowboy: 0.2
otelEcto: 1.2
---

{{% docs/languages/index-intro erlang %}}
Expand Down
82 changes: 74 additions & 8 deletions content/en/docs/languages/erlang/exporters.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,64 @@ collector, which can then export Spans to a self-hosted service like Zipkin or
Jaeger, as well as commercial services. For a full list of available exporters,
see the [registry](/ecosystem/registry/?component=exporter).

For testing purposes the `opentelemetry-erlang` repository has a Collector
configuration,
[config/otel-collector-config.yaml](https://github.com/open-telemetry/opentelemetry-erlang/blob/main/config/otel-collector-config.yaml)
that can be used as a starting point. This configuration is used in
## Setting up the Collector
For testing purposes, you can start with the following Collector configuration at the root of your project:
```yaml
# otel-collector-config.yaml

# OpenTelemetry Collector config that receives OTLP and exports to Jager
receivers:
otlp:
protocols:
grpc:
endpoint: "0.0.0.0:4317"
http:
endpoint: "0.0.0.0:4318"
processors:
batch:
send_batch_size: 1024
timeout: 5s
exporters:
otlp/jaeger:
endpoint: jaeger-all-in-one:4317
tls:
insecure: true
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [logging, otlp/jaeger]
```
For a more detailed example, you can view the [config](https://github.com/open-telemetry/opentelemetry-erlang/blob/main/config/otel-collector-config.yaml)
that `opentelemetry-erlang` uses for testing.

For the purposes of this tutorial, we'll start the Collector as a docker image along side our app.
For this tutorial, we'll continue along with the Dice Roll example from the [Getting Started](/docs/languages/erlang/getting-started) guide


Add this docker-compose file to the root of your app:
```yaml
# docker-compose.yml
version: "3"
services:
otel:
image: otel/opentelemetry-collector-contrib:0.98.0
command: ["--config=/conf/otel-collector-config.yaml"]
ports:
- 4317:4317
- 4318:4318
volumes:
- ./otel-collector-config.yaml:/conf/otel-collector-config.yaml
links:
- jaeger-all-in-one
jaeger-all-in-one:
image: jaegertracing/all-in-one:latest
ports:
- "16686:16686"
```
This configuration is used in
[docker-compose.yml](https://github.com/open-telemetry/opentelemetry-erlang/blob/main/docker-compose.yml)
to start the Collector with receivers for both HTTP and gRPC that then export to
Zipkin also run by [docker-compose](https://docs.docker.com/compose/).
Expand Down Expand Up @@ -90,9 +144,10 @@ end
Finally, the runtime configuration of the `opentelemetry` and
`opentelemetry_exporter` Applications are set to export to the Collector. The
configurations below show the defaults that are used if none are set, which are
the HTTP protocol with endpoint of `localhost` on port `4318`. If using `grpc`
for the `otlp_protocol` the endpoint should be changed to
`http://localhost:4317`.
the HTTP protocol with endpoint of `localhost` on port `4318`. Note:
- If using `grpc` for the `otlp_protocol` the endpoint should be changed to
`http://localhost:4317`.
- If you're using the docker compose file from above, you should replace `localhost` with `otel`.

{{< tabpane text=true >}} {{% tab Erlang %}}

Expand All @@ -112,14 +167,25 @@ for the `otlp_protocol` the endpoint should be changed to
{{% /tab %}} {{% tab Elixir %}}

```elixir
# config/runtime.exs
# config/config.exs
config :opentelemetry,
resource: %{service: %{name: "roll_dice_app"}},
span_processor: :batch,
traces_exporter: :otlp
config :opentelemetry_exporter,
otlp_protocol: :http_protobuf,
otlp_endpoint: "http://localhost:4318"
# otlp_endpoint: "http://otel:4318" if using docker compose file
```

{{% /tab %}} {{< /tabpane >}}

You can see your traces by running `docker compose up` in one terminal, then `mix phx.server` in another.
After sending some requests through the app, go to `http://localhost:16686` and select `roll_dice_app` from the Service drop down,
then click "Find Traces".

## Gotchas
Some environments do not allow containers to execute as root users. If you
work in an environment like this, you can add `user: "1001"` as a top-level key/value
to the `otel` service in the `docker-compose.yml` file used in this tutorial.
98 changes: 71 additions & 27 deletions content/en/docs/languages/erlang/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ get set up with everything you need.

### Example Application

The following example uses a basic [Phoenix](https://www.phoenixframework.org/)
web application. For reference, a complete example of the code you will build
The following example will take you through creating a basic [Phoenix](https://www.phoenixframework.org/)
web application and instrumenting it with OpenTelemetry. For reference, a complete example of the code you will build
can be found here:
[opentelemetry-erlang-contrib/examples/dice_game](https://github.com/open-telemetry/opentelemetry-erlang-contrib/tree/main/examples/dice_game).
You can git clone that project or just follow along in your browser.
[opentelemetry-erlang-contrib/examples/roll_dice](https://github.com/open-telemetry/opentelemetry-erlang-contrib/tree/main/examples/roll_dice).

Additional examples can be found [here](/docs/languages/erlang/examples/).

### Initial Setup
Run `mix phx.new roll_dice`. Type "y" to install dependencies.
### Dependencies

We'll need a few other dependencies that Phoenix doesn't come with.
Expand All @@ -60,6 +61,7 @@ We'll need a few other dependencies that Phoenix doesn't come with.
# mix.exs
def deps do
[
# other default deps...
{:opentelemetry, "~> {{% param versions.otelSdk %}}"},
{:opentelemetry_api, "~> {{% param versions.otelApi %}}"},
{:opentelemetry_exporter, "~> {{% param versions.otelExporter %}}"},
Expand All @@ -68,11 +70,12 @@ def deps do
{:opentelemetry_cowboy, "~> {{% param versions.otelCowboy %}}"}
# for Bandit
{:opentelemetry_bandit, "~> {{% version-from-registry instrumentation-erlang-bandit %}}"},
{:opentelemetry_ecto, "~> {{% param versions.otelEcto %}}"} # if using ecto
]
end
```

The last two also need to be setup when your application starts:
The last three also need to be setup when your application starts:

```elixir
# application.ex
Expand All @@ -84,27 +87,31 @@ def start(_type, _args) do
# or
OpentelemetryBandit.setup()
OpentelemetryPhoenix.setup(adapter: :bandit)
OpentelemetryEcto.setup([:dice_game, :repo]) # if using ecto
end
```

If you're using ecto, you'll also want to add
`OpentelemetryEcto.setup([:dice_game, :repo])`.
Also, make sure your `endpoint.ex` file contains the following line:
```elixir
# endpoint.ex
plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint]
```

We also need to configure the `opentelemetry` application as temporary by adding
a `releases` section to your project configuration. This will ensure that if it
terminates, even abnormally, the `dice_game` application will be terminated.
terminates, even abnormally, the `roll_dice` application will be terminated.

```elixir
# mix.exs
def project do
[
app: :dice_game,
app: :roll_dice,
version: "0.1.0",
elixir: "~> 1.14",
elixirc_paths: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
releases: [
dice_game: [
roll_dice: [
applications: [opentelemetry: :temporary]
]
],
Expand All @@ -114,20 +121,21 @@ def project do
end
```

Now we can use the new `mix setup` command to install the dependencies, build
the assets, and create and migrate the database.

### Try It Out

We can ensure everything is working by setting the stdout exporter as
OpenTelemetry's `traces_exporter` and then starting the app with
`mix phx.server`.
The last thing you'll need is to configure the exporter. For development,
we can use the stdout exporter to ensure everything is working properly.
Configure OpenTelemetry's `traces_exporter` like so:

```elixir
# config/dev.exs
config :opentelemetry, traces_exporter: {:otel_exporter_stdout, []}
```

Now we can use the new `mix setup` command to install the dependencies, build
the assets, and create and migrate the database.

### Try It Out
Run `mix phx.server`.

If everything went well, you should be able to visit
[`localhost:4000`](http://localhost:4000) in your browser and see quite a few
lines that look like this in your terminal.
Expand Down Expand Up @@ -157,7 +165,7 @@ fields are.)
'net.sock.peer.addr' => <<"127.0.0.1">>,
'http.route' => <<"/">>,'phoenix.action' => home,
'phoenix.plug' =>
'Elixir.DiceGameWeb.PageController'}},
'Elixir.RollDiceWeb.PageController'}},
{events,128,128,infinity,0,[]},
{links,128,128,infinity,0,[]},
undefined,1,false,
Expand All @@ -170,18 +178,54 @@ configure the exporter for your preferred service.
### Rolling The Dice
Now we'll check out the API endpoint that will let us roll the dice and return a
Now we'll create the API endpoint that will let us roll the dice and return a
random number between 1 and 6.
Before we call our API, let's add our first bit of manual instrumentation. In
our `DiceController` we call a private `dice_roll` method that generates our
```elixir
# router.ex
scope "/api", RollDiceWeb do
pipe_through :api
get "/rolldice", DiceController, :roll
end
```
And create a bare `DiceController` without any instrumentation:
```elixir
# lib/roll_dice_web/controllers/dice_controller.ex
defmodule RollDiceWeb.DiceController do
use RollDiceWeb, :controller
def roll(conn, _params) do
send_resp(conn, 200, roll_dice())
end
defp roll_dice do
to_string(Enum.random(1..6))
end
end
```
If you like, call the route to see the result. You'll still see some telemetry
pop up in your terminal. Now it's time to enrich that telemetry by instrumenting
our `roll` function by hand
In our `DiceController` we call a private `dice_roll` method that generates our
random number. This seems like a pretty important operation, so in order to
capture it in our trace we'll need to wrap it in a span.
```elixir
defp dice_roll do
Tracer.with_span("dice_roll") do
to_string(Enum.random(1..6))
defmodule RollDiceWeb.DiceController do
use RollDiceWeb, :controller
require OpenTelemetry.Tracer, as: Tracer
# ...snip
defp roll_dice do
Tracer.with_span("dice_roll") do
to_string(Enum.random(1..6))
end
end
end
```
Expand All @@ -190,7 +234,7 @@ It would also be nice to know what number it generated, so we can extract it as
a local variable and add it as an attribute on the span.
```elixir
defp dice_roll do
defp roll_dice do
Tracer.with_span("dice_roll") do
roll = Enum.random(1..6)
Expand Down Expand Up @@ -228,7 +272,7 @@ get a random number in response, and 3 spans in your console.
'net.transport' => 'IP.TCP',
'http.route' => <<"/api/rolldice">>,
'phoenix.action' => roll,
'phoenix.plug' => 'Elixir.DiceGameWeb.DiceController'}},
'phoenix.plug' => 'Elixir.RollDiceWeb.DiceController'}},
{events,128,128,infinity,0,[]},
{links,128,128,infinity,0,[]},
undefined,1,false,
Expand Down
9 changes: 9 additions & 0 deletions content/en/docs/languages/erlang/instrumentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,18 @@ Add the following dependencies to your project:
- `opentelemetry`: contains the SDK that implements the interfaces defined in
the API. Without it, all the functions in the API are no-ops.

Optionally, you may choose to include the `open_telemetry_decorator` library.
Note that this library is not officially supported by the opentelemetry project,

Check failure on line 21 in content/en/docs/languages/erlang/instrumentation.md

View workflow job for this annotation

GitHub Actions / TEXT linter

textlint terminology error

Incorrect usage of the term: “opentelemetry”, use “OpenTelemetry” instead
but it's handy for wrapping fuctions up in spans.

Check warning on line 22 in content/en/docs/languages/erlang/instrumentation.md

View workflow job for this annotation

GitHub Actions / SPELLING check

Unknown word (fuctions)

```elixir
# mix.exs
def deps do
[
{:opentelemetry, "~> 1.3"},
{:opentelemetry_api, "~> 1.2"},
# optionally
{:open_telemetry_decorator, "~> 1.4"}
]
end
```
Expand Down Expand Up @@ -139,6 +145,9 @@ def child_function() do
end
```

If you are using `OpenTelemetryDecorator`, see its [usage docs](https://hexdocs.pm/open_telemetry_decorator/OpenTelemetryDecorator.html)
for examples of how it can be used.

{{% /tab %}} {{< /tabpane >}}

### Spans in Separate Processes
Expand Down

0 comments on commit 4347eea

Please sign in to comment.