Skip to content

Commit 9abb55e

Browse files
committed
Add a custom OTel filtered sampler
1 parent 444bbf1 commit 9abb55e

File tree

5 files changed

+119
-30
lines changed

5 files changed

+119
-30
lines changed

config/dev.exs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,5 +112,3 @@ config :nerves_hub, NervesHub.RateLimit, limit: 10
112112

113113
config :nerves_hub,
114114
open_for_registrations: true
115-
116-
config :opentelemetry, traces_exporter: :none

config/runtime.exs

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -387,26 +387,25 @@ config :sentry,
387387
]
388388
]
389389

390-
if otlp_endpoint = System.get_env("OTLP_ENDPOINT") do
391-
config :opentelemetry, :resource, service: %{name: nerves_hub_app}
390+
config :opentelemetry, :resource, service: %{name: nerves_hub_app}
392391

392+
if otlp_endpoint = System.get_env("OTLP_ENDPOINT") do
393393
config :opentelemetry_exporter,
394394
otlp_protocol: :http_protobuf,
395395
otlp_endpoint: otlp_endpoint,
396396
otlp_headers: [{System.get_env("OTLP_AUTH_HEADER"), System.get_env("OTLP_AUTH_HEADER_VALUE")}]
397397

398-
if otlp_sampler_ratio = System.get_env("OTLP_SAMPLER_RATIO") do
399-
config :opentelemetry,
400-
sampler:
401-
{:parent_based,
402-
%{
403-
root: {:trace_id_ratio_based, String.to_float(otlp_sampler_ratio)},
404-
remote_parent_sampled: :always_on,
405-
remote_parent_not_sampled: :always_off,
406-
local_parent_sampled: :always_on,
407-
local_parent_not_sampled: :always_off
408-
}}
409-
end
398+
otlp_sampler_ratio =
399+
if ratio = System.get_env("OTLP_SAMPLER_RATIO") do
400+
String.to_float(ratio)
401+
else
402+
nil
403+
end
404+
405+
config :opentelemetry,
406+
sampler: {:parent_based, %{root: {NervesHub.Telemetry.FilteredSampler, otlp_sampler_ratio}}}
407+
else
408+
config :opentelemetry, traces_exporter: :none
410409
end
411410

412411
if host = System.get_env("STATSD_HOST") do

config/test.exs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,5 +91,3 @@ config :phoenix_test, :endpoint, NervesHubWeb.Endpoint
9191

9292
# Initialize plugs at runtime for faster test compilation
9393
config :phoenix, :plug_init_mode, :runtime
94-
95-
config :opentelemetry, traces_exporter: :none

lib/nerves_hub/application.ex

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,7 @@ defmodule NervesHub.Application do
1212
raise "fwup could not be found in the $PATH. This is a requirement of NervesHubWeb and cannot start otherwise"
1313
end
1414

15-
if System.get_env("ECTO_IPV6") do
16-
:httpc.set_option(:ipfamily, :inet6fb4)
17-
end
18-
19-
:ok = OpentelemetryBandit.setup()
20-
:ok = OpentelemetryPhoenix.setup(adapter: :bandit)
21-
:ok = OpentelemetryOban.setup(trace: [:jobs])
22-
23-
:ok =
24-
NervesHub.Repo.config()
25-
|> Keyword.fetch!(:telemetry_prefix)
26-
|> OpentelemetryEcto.setup(db_statement: :enabled)
15+
setup_open_telemetry()
2716

2817
_ =
2918
:logger.add_handler(:my_sentry_handler, Sentry.LoggerHandler, %{
@@ -60,6 +49,23 @@ defmodule NervesHub.Application do
6049
Supervisor.start_link(children, opts)
6150
end
6251

52+
defp setup_open_telemetry() do
53+
if System.get_env("ECTO_IPV6") do
54+
:httpc.set_option(:ipfamily, :inet6fb4)
55+
end
56+
57+
:ok = OpentelemetryBandit.setup()
58+
:ok = OpentelemetryPhoenix.setup(adapter: :bandit)
59+
:ok = OpentelemetryOban.setup(trace: [:jobs])
60+
61+
:ok =
62+
NervesHub.Repo.config()
63+
|> Keyword.fetch!(:telemetry_prefix)
64+
|> OpentelemetryEcto.setup(db_statement: :enabled)
65+
66+
:ok
67+
end
68+
6369
def config_change(changed, _new, removed) do
6470
NervesHubWeb.Endpoint.config_change(changed, removed)
6571
:ok
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
defmodule NervesHub.Telemetry.FilteredSampler do
2+
# Inspired by https://arathunku.com/b/2024/notes-on-adding-opentelemetry-to-an-elixir-app/
3+
4+
# TODO: Add ratio sampling support
5+
6+
require OpenTelemetry.Tracer, as: Tracer
7+
require Logger
8+
9+
@behaviour :otel_sampler
10+
11+
@ignored_static_paths ~r/^\/(assets|fonts|images)\/.*/
12+
13+
@ignored_url_paths [
14+
"/status/alive",
15+
"/favicon.ico",
16+
"/phoenix/live_reload/socket/websocket",
17+
# "/live/websocket",
18+
"/"
19+
]
20+
21+
@ignored_span_names [
22+
"Channels.DeviceSocket.heartbeat",
23+
"nerves_hub.repo.query:schema_migrations"
24+
]
25+
26+
@impl :otel_sampler
27+
def setup(probability \\ nil) do
28+
if probability do
29+
[ratio_sampler_config: :otel_sampler_trace_id_ratio_based.setup(probability)]
30+
else
31+
[]
32+
end
33+
end
34+
35+
@impl :otel_sampler
36+
def description(_sampler_config), do: "NervesHub.Sampler"
37+
38+
@impl :otel_sampler
39+
def should_sample(
40+
ctx,
41+
trace_id,
42+
links,
43+
span_name,
44+
span_kind,
45+
attributes,
46+
sampler_config
47+
) do
48+
result = drop_trace?(span_name, attributes)
49+
50+
tracestate = Tracer.current_span_ctx(ctx) |> OpenTelemetry.Span.tracestate()
51+
52+
case result do
53+
true ->
54+
{:drop, [], tracestate}
55+
56+
false ->
57+
if config = sampler_config[:ratio_sampler_config] do
58+
:otel_sampler_trace_id_ratio_based.should_sample(
59+
ctx,
60+
trace_id,
61+
links,
62+
span_name,
63+
span_kind,
64+
attributes,
65+
config
66+
)
67+
else
68+
{:record_and_sample, [], tracestate}
69+
end
70+
end
71+
end
72+
73+
def drop_trace?(span_name, attributes) do
74+
cond do
75+
Enum.member?(@ignored_span_names, span_name) ->
76+
true
77+
78+
span_name == :GET && Enum.member?(@ignored_url_paths, attributes[:"url.path"]) ->
79+
true
80+
81+
span_name == :GET && (attributes[:"url.path"] || "") =~ @ignored_static_paths ->
82+
true
83+
84+
true ->
85+
false
86+
end
87+
end
88+
end

0 commit comments

Comments
 (0)