246 lines
7.1 KiB
Elixir
246 lines
7.1 KiB
Elixir
|
defmodule OpentelemetryBanditTest do
|
||
|
use ExUnit.Case, async: true
|
||
|
|
||
|
require OpenTelemetry.Tracer
|
||
|
require OpenTelemetry.Span
|
||
|
require Record
|
||
|
|
||
|
use ServerHelper
|
||
|
|
||
|
for {name, spec} <- Record.extract_all(from_lib: "opentelemetry/include/otel_span.hrl") do
|
||
|
Record.defrecord(name, spec)
|
||
|
end
|
||
|
|
||
|
describe "http integration" do
|
||
|
test "default span generation for 200" do
|
||
|
Req.get("http://localhost:4000/hello")
|
||
|
|
||
|
assert_receive {:span,
|
||
|
span(
|
||
|
name: "HTTP GET /hello",
|
||
|
kind: :server,
|
||
|
status: {:status, :ok, _},
|
||
|
attributes: attributes
|
||
|
)}
|
||
|
|
||
|
assert %{
|
||
|
"net.peer.name": "localhost",
|
||
|
"http.method": "GET",
|
||
|
"http.target": "/hello",
|
||
|
"http.scheme": :http,
|
||
|
"http.status_code": 200
|
||
|
} = :otel_attributes.map(attributes)
|
||
|
end
|
||
|
|
||
|
test "default span generation for 200 without user-agent" do
|
||
|
{:ok, {{_, 200, _}, _, _}} =
|
||
|
:httpc.request(:get, {~c"http://localhost:4000/hello", []}, [], [])
|
||
|
|
||
|
assert_receive {:span,
|
||
|
span(
|
||
|
name: "HTTP GET /hello",
|
||
|
kind: :server,
|
||
|
status: {:status, :ok, _},
|
||
|
attributes: attributes
|
||
|
)}
|
||
|
|
||
|
assert %{
|
||
|
"net.peer.name": "localhost",
|
||
|
"http.method": "GET",
|
||
|
"http.target": "/hello",
|
||
|
"http.scheme": :http,
|
||
|
"http.status_code": 200,
|
||
|
"http.client_ip": "127.0.0.1"
|
||
|
} = :otel_attributes.map(attributes)
|
||
|
end
|
||
|
|
||
|
test "default span generation for 200 with x-forwarded-for" do
|
||
|
Req.get("http://localhost:4000/hello", headers: %{x_forwarded_for: "127.0.0.1"})
|
||
|
|
||
|
assert_receive {:span,
|
||
|
span(
|
||
|
name: "HTTP GET /hello",
|
||
|
kind: :server,
|
||
|
status: {:status, :ok, _},
|
||
|
attributes: attributes
|
||
|
)}
|
||
|
|
||
|
assert %{
|
||
|
"net.peer.name": "localhost",
|
||
|
"http.method": "GET",
|
||
|
"http.target": "/hello",
|
||
|
"http.scheme": :http,
|
||
|
"http.status_code": 200,
|
||
|
"http.client_ip": "127.0.0.1"
|
||
|
} = :otel_attributes.map(attributes)
|
||
|
end
|
||
|
|
||
|
test "default span generation for halted connection" do
|
||
|
Req.get("http://localhost:4000/fail", retry: false)
|
||
|
|
||
|
assert_receive {:span,
|
||
|
span(
|
||
|
name: "HTTP GET /fail",
|
||
|
kind: :server,
|
||
|
status: {:status, :ok, _},
|
||
|
attributes: attributes
|
||
|
)}
|
||
|
|
||
|
assert %{
|
||
|
"net.peer.name": "localhost",
|
||
|
"http.method": "GET",
|
||
|
"http.target": "/fail",
|
||
|
"http.scheme": :http,
|
||
|
"http.status_code": 500
|
||
|
} = :otel_attributes.map(attributes)
|
||
|
end
|
||
|
|
||
|
test "default span generation for 500 response" do
|
||
|
:telemetry.execute(
|
||
|
[:bandit, :request, :stop],
|
||
|
%{duration: 444, resp_body_bytes: 10},
|
||
|
%{
|
||
|
conn: nil,
|
||
|
status: 500,
|
||
|
error: "Internal Server Error",
|
||
|
method: "GET",
|
||
|
request_target: {nil, nil, nil, "/not_existing_route"}
|
||
|
}
|
||
|
)
|
||
|
|
||
|
assert_receive {:span,
|
||
|
span(
|
||
|
name: "HTTP GET /not_existing_route",
|
||
|
kind: :error,
|
||
|
status: {:status, :error, "Internal Server Error"},
|
||
|
attributes: attributes
|
||
|
)}
|
||
|
|
||
|
assert %{
|
||
|
"http.url": _,
|
||
|
"http.method": "GET",
|
||
|
"http.status_code": 500,
|
||
|
"http.response_content_length": 10,
|
||
|
"net.transport": :"IP.TCP"
|
||
|
} = :otel_attributes.map(attributes)
|
||
|
end
|
||
|
|
||
|
test "span when request_target is empty" do
|
||
|
:telemetry.execute(
|
||
|
[:bandit, :request, :stop],
|
||
|
%{duration: 444, resp_body_bytes: 10},
|
||
|
%{
|
||
|
conn: nil,
|
||
|
status: 500,
|
||
|
error: "Internal Server Error",
|
||
|
method: "GET",
|
||
|
request_target: nil
|
||
|
}
|
||
|
)
|
||
|
|
||
|
assert_receive {:span,
|
||
|
span(
|
||
|
name: "HTTP GET",
|
||
|
kind: :error,
|
||
|
status: {:status, :error, "Internal Server Error"},
|
||
|
attributes: attributes
|
||
|
)}
|
||
|
|
||
|
assert %{
|
||
|
"http.url": _,
|
||
|
"http.method": "GET",
|
||
|
"http.status_code": 500,
|
||
|
"http.response_content_length": 10,
|
||
|
"net.transport": :"IP.TCP"
|
||
|
} = :otel_attributes.map(attributes)
|
||
|
end
|
||
|
|
||
|
test "exception catch span" do
|
||
|
Req.get("http://localhost:4000/exception", retry: false)
|
||
|
|
||
|
assert_receive {:span,
|
||
|
span(
|
||
|
name: "HTTP exception RuntimeError",
|
||
|
kind: :error,
|
||
|
status: {:status, :error, _}
|
||
|
)}
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe "websocket integration" do
|
||
|
test "span when request finished successfully" do
|
||
|
:telemetry.execute(
|
||
|
[:bandit, :websocket, :stop],
|
||
|
%{
|
||
|
duration: 444,
|
||
|
send_binary_frame_bytes: 10,
|
||
|
recv_binary_frame_bytes: 15
|
||
|
},
|
||
|
%{}
|
||
|
)
|
||
|
|
||
|
assert_receive {:span,
|
||
|
span(
|
||
|
name: "Websocket",
|
||
|
kind: :server,
|
||
|
status: {:status, :ok, _},
|
||
|
attributes: attributes
|
||
|
)}
|
||
|
|
||
|
assert %{
|
||
|
"net.transport": :websocket,
|
||
|
"websocket.recv.binary.frame.bytes": 10,
|
||
|
"websocket.send.binary.frame.bytes": 15
|
||
|
} = :otel_attributes.map(attributes)
|
||
|
end
|
||
|
|
||
|
test "span when error is set" do
|
||
|
:telemetry.execute(
|
||
|
[:bandit, :websocket, :stop],
|
||
|
%{
|
||
|
duration: 444,
|
||
|
send_binary_frame_bytes: 10,
|
||
|
recv_binary_frame_bytes: 15
|
||
|
},
|
||
|
%{error: "Internal Server Error"}
|
||
|
)
|
||
|
|
||
|
assert_receive {:span,
|
||
|
span(
|
||
|
name: "Websocket",
|
||
|
kind: :error,
|
||
|
status: {:status, :error, _},
|
||
|
attributes: attributes
|
||
|
)}
|
||
|
|
||
|
assert %{
|
||
|
"net.transport": :websocket,
|
||
|
"websocket.recv.binary.frame.bytes": 10,
|
||
|
"websocket.send.binary.frame.bytes": 15
|
||
|
} = :otel_attributes.map(attributes)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
setup do
|
||
|
:otel_simple_processor.set_exporter(:otel_exporter_pid, self())
|
||
|
|
||
|
{:ok, _} = start_supervised({Bandit, plug: __MODULE__, port: 4000, startup_log: false})
|
||
|
|
||
|
OpentelemetryBandit.setup()
|
||
|
|
||
|
:ok
|
||
|
end
|
||
|
|
||
|
def hello(conn) do
|
||
|
conn |> send_resp(200, "OK")
|
||
|
end
|
||
|
|
||
|
def fail(conn) do
|
||
|
conn |> send_resp(500, "Internal Server Error") |> halt()
|
||
|
end
|
||
|
|
||
|
def exception(_conn) do
|
||
|
raise "boom"
|
||
|
end
|
||
|
end
|