@@ -26,14 +26,18 @@ get set up with everything you need.
2626
2727### Example Application
2828
29- The following example uses a basic [ Phoenix ] ( https://www.phoenixframework.org/ )
30- web application. For reference, a complete example of the code you will build
31- can be found here:
32- [ opentelemetry-erlang-contrib/examples/dice_game ] ( https://github.com/open-telemetry/opentelemetry-erlang-contrib/tree/main/examples/dice_game ) .
33- You can git clone that project or just follow along in your browser .
29+ The following example will take you through creating a basic
30+ [ Phoenix ] ( https://www.phoenixframework.org/ ) web application and instrumenting
31+ it with OpenTelemetry. For reference, a complete example of the code you will
32+ build can be found here:
33+ [ opentelemetry-erlang-contrib/examples/roll_dice ] ( https://github.com/open-telemetry/opentelemetry-erlang-contrib/tree/main/examples/roll_dice ) .
3434
3535Additional examples can be found [ here] ( /docs/languages/erlang/examples/ ) .
3636
37+ ### Initial Setup
38+
39+ Run ` mix phx.new roll_dice ` . Type "y" to install dependencies.
40+
3741### Dependencies
3842
3943We'll need a few other dependencies that Phoenix doesn't come with.
@@ -60,6 +64,7 @@ We'll need a few other dependencies that Phoenix doesn't come with.
6064# mix.exs
6165def deps do
6266 [
67+ # other default deps...
6368 {:opentelemetry , " ~> {{% param versions.otelSdk %}}" },
6469 {:opentelemetry_api , " ~> {{% param versions.otelApi %}}" },
6570 {:opentelemetry_exporter , " ~> {{% param versions.otelExporter %}}" },
@@ -68,11 +73,12 @@ def deps do
6873 {:opentelemetry_cowboy , " ~> {{% param versions.otelCowboy %}}" }
6974 # for Bandit
7075 {:opentelemetry_bandit , " ~> {{% version-from-registry instrumentation-erlang-bandit %}}" },
76+ {:opentelemetry_ecto , " ~> {{% param versions.otelEcto %}}" } # if using ecto
7177 ]
7278end
7379```
7480
75- The last two also need to be setup when your application starts:
81+ The last three also need to be setup when your application starts:
7682
7783``` elixir
7884# application.ex
@@ -84,27 +90,32 @@ def start(_type, _args) do
8490 # or
8591 OpentelemetryBandit .setup ()
8692 OpentelemetryPhoenix .setup (adapter: :bandit )
93+ OpentelemetryEcto .setup ([:dice_game , :repo ]) # if using ecto
8794end
8895```
8996
90- If you're using ecto, you'll also want to add
91- ` OpentelemetryEcto.setup([:dice_game, :repo]) ` .
97+ Also, make sure your ` endpoint.ex ` file contains the following line:
98+
99+ ``` elixir
100+ # endpoint.ex
101+ plug Plug .Telemetry , event_prefix: [:phoenix , :endpoint ]
102+ ```
92103
93104We also need to configure the ` opentelemetry ` application as temporary by adding
94105a ` releases ` section to your project configuration. This will ensure that if it
95- terminates, even abnormally, the ` dice_game ` application will be terminated.
106+ terminates, even abnormally, the ` roll_dice ` application will be terminated.
96107
97108``` elixir
98109# mix.exs
99110def project do
100111 [
101- app: :dice_game ,
112+ app: :roll_dice ,
102113 version: " 0.1.0" ,
103114 elixir: " ~> 1.14" ,
104115 elixirc_paths: elixirc_paths (Mix .env ()),
105116 start_permanent: Mix .env () == :prod ,
106117 releases: [
107- dice_game : [
118+ roll_dice : [
108119 applications: [opentelemetry: :temporary ]
109120 ]
110121 ],
@@ -114,20 +125,22 @@ def project do
114125end
115126```
116127
117- Now we can use the new ` mix setup ` command to install the dependencies, build
118- the assets, and create and migrate the database.
119-
120- ### Try It Out
121-
122- We can ensure everything is working by setting the stdout exporter as
123- OpenTelemetry's ` traces_exporter ` and then starting the app with
124- ` mix phx.server ` .
128+ The last thing you'll need is to configure the exporter. For development, we can
129+ use the stdout exporter to ensure everything is working properly. Configure
130+ OpenTelemetry's ` traces_exporter ` like so:
125131
126132``` elixir
127133# config/dev.exs
128134config :opentelemetry , traces_exporter: {:otel_exporter_stdout , []}
129135```
130136
137+ Now we can use the new ` mix setup ` command to install the dependencies, build
138+ the assets, and create and migrate the database.
139+
140+ ### Try It Out
141+
142+ Run ` mix phx.server ` .
143+
131144If everything went well, you should be able to visit
132145[ ` localhost:4000 ` ] ( http://localhost:4000 ) in your browser and see quite a few
133146lines that look like this in your terminal.
@@ -157,7 +170,7 @@ fields are.)
157170 'net.sock.peer.addr' => <<"127.0.0.1">>,
158171 'http.route' => <<"/">>,'phoenix.action' => home,
159172 'phoenix.plug' =>
160- 'Elixir.DiceGameWeb .PageController'}},
173+ 'Elixir.RollDiceWeb .PageController'}},
161174 {events,128,128,infinity,0,[]},
162175 {links,128,128,infinity,0,[]},
163176 undefined,1,false,
@@ -170,18 +183,54 @@ configure the exporter for your preferred service.
170183
171184### Rolling The Dice
172185
173- Now we'll check out the API endpoint that will let us roll the dice and return a
186+ Now we'll create the API endpoint that will let us roll the dice and return a
174187random number between 1 and 6.
175188
176- Before we call our API, let's add our first bit of manual instrumentation. In
177- our `DiceController` we call a private `dice_roll` method that generates our
189+ ```elixir
190+ # router.ex
191+ scope "/api", RollDiceWeb do
192+ pipe_through :api
193+
194+ get "/rolldice", DiceController, :roll
195+ end
196+ ```
197+
198+ And create a bare `DiceController` without any instrumentation:
199+
200+ ```elixir
201+ # lib/roll_dice_web/controllers/dice_controller.ex
202+ defmodule RollDiceWeb.DiceController do
203+ use RollDiceWeb, :controller
204+
205+ def roll(conn, _params) do
206+ send_resp(conn, 200, roll_dice())
207+ end
208+
209+ defp roll_dice do
210+ to_string(Enum.random(1..6))
211+ end
212+ end
213+ ```
214+
215+ If you like, call the route to see the result. You'll still see some telemetry
216+ pop up in your terminal. Now it's time to enrich that telemetry by instrumenting
217+ our `roll` function by hand
218+
219+ In our `DiceController` we call a private `dice_roll` method that generates our
178220random number. This seems like a pretty important operation, so in order to
179221capture it in our trace we'll need to wrap it in a span.
180222
181223```elixir
182- defp dice_roll do
183- Tracer.with_span("dice_roll") do
184- to_string(Enum.random(1..6))
224+ defmodule RollDiceWeb.DiceController do
225+ use RollDiceWeb, :controller
226+ require OpenTelemetry.Tracer, as: Tracer
227+
228+ # ...snip
229+
230+ defp roll_dice do
231+ Tracer.with_span("dice_roll") do
232+ to_string(Enum.random(1..6))
233+ end
185234 end
186235end
187236```
@@ -190,7 +239,7 @@ It would also be nice to know what number it generated, so we can extract it as
190239a local variable and add it as an attribute on the span.
191240
192241```elixir
193- defp dice_roll do
242+ defp roll_dice do
194243 Tracer.with_span("dice_roll") do
195244 roll = Enum.random(1..6)
196245
@@ -228,7 +277,7 @@ get a random number in response, and 3 spans in your console.
228277 'net.transport' => 'IP.TCP',
229278 'http.route' => <<"/api/rolldice">>,
230279 'phoenix.action' => roll,
231- 'phoenix.plug' => 'Elixir.DiceGameWeb .DiceController'}},
280+ 'phoenix.plug' => 'Elixir.RollDiceWeb .DiceController'}},
232281 {events,128,128,infinity,0,[]},
233282 {links,128,128,infinity,0,[]},
234283 undefined,1,false,
0 commit comments