Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions lib/mix/tasks/sentry.send_test_event.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@ defmodule Mix.Tasks.Sentry.SendTestEvent do

def run(_args) do
Application.ensure_all_started(:sentry)
{endpoint, public_key, secret_key} = case Application.fetch_env(:sentry, :dsn) do
{:ok, dsn} when is_binary(dsn) -> Sentry.Client.parse_dsn!(dsn)
_ ->
Mix.raise "Sentry DSN is not configured in :sentry, :dsn"
end
{endpoint, public_key, secret_key} = Sentry.Client.get_dsn!

included_environments = case Application.fetch_env(:sentry, :included_environments) do
{:ok, envs} when is_list(envs) -> envs
Expand All @@ -30,11 +26,15 @@ defmodule Mix.Tasks.Sentry.SendTestEvent do
maybe_send_event(environment_name, included_environments)
end

def maybe_send_event(env_name, included_envs) do
defp maybe_send_event(env_name, included_envs) do
if env_name in included_envs do
Mix.shell.info "Sending test event..."
Sentry.capture_exception(RuntimeError.exception("Testing sending Sentry event"))
|> Task.await()

"Testing sending Sentry event"
|> RuntimeError.exception
|> Sentry.capture_exception
|> Task.await

Mix.shell.info "Test event sent!"
else
Mix.shell.info "#{inspect env_name} is not in #{inspect included_envs} so no test event will be sent"
Expand Down
19 changes: 13 additions & 6 deletions lib/sentry/client.ex
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule Sentry.Client do
alias Sentry.{Event, Util}
require Logger
@type parsed_dsn :: {String.t, String.t, Integer.t}
@type get_dsn :: {String.t, String.t, Integer.t}
@sentry_version 5
@max_attempts 4

Expand All @@ -21,7 +21,7 @@ defmodule Sentry.Client do
"""
@spec send_event(%Event{}) :: {:ok, String.t} | :error
def send_event(%Event{} = event) do
Copy link
Contributor Author

@rafaeljesus rafaeljesus Jan 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically we should be injecting dependences in function signature so we can easily test and move private functions to its own module which we can also test independently so it could be like:

def send_event(%Event{} = event, dsn_parser \\ DsnParser) do
{endpoint, public_key, secret_key} = dsn_parser.parse!
# ....
end

Unfortunately I don't have time to implement it yet, but we can refactor it soon

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that that would be necessary. This kind of pattern would usually come along with specifying a Behaviour, which might be overkill at this point 🙂

{endpoint, public_key, secret_key} = parse_dsn!(Application.fetch_env!(:sentry, :dsn))
{endpoint, public_key, secret_key} = get_dsn!

auth_headers = authorization_headers(public_key, secret_key)
body = Poison.encode!(event)
Expand Down Expand Up @@ -94,12 +94,12 @@ defmodule Sentry.Client do
end

@doc """
Parses a Sentry DSN which is simply a URI.
Get a Sentry DSN which is simply a URI.
"""
@spec parse_dsn!(String.t) :: parsed_dsn
def parse_dsn!(dsn) do
@spec get_dsn! :: get_dsn
def get_dsn! do
# {PROTOCOL}://{PUBLIC_KEY}:{SECRET_KEY}@{HOST}/{PATH}{PROJECT_ID}
%URI{userinfo: userinfo, host: host, port: port, path: path, scheme: protocol} = URI.parse(dsn)
%URI{userinfo: userinfo, host: host, port: port, path: path, scheme: protocol} = URI.parse(fetch_dsn)
[public_key, secret_key] = String.split(userinfo, ":", parts: 2)
[_, binary_project_id] = String.split(path, "/")
project_id = String.to_integer(binary_project_id)
Expand All @@ -108,6 +108,13 @@ defmodule Sentry.Client do
{endpoint, public_key, secret_key}
end

defp fetch_dsn do
case Application.fetch_env!(:sentry, :dsn) do
{:system, env_var} -> System.get_env(env_var)
value -> value
end
end

defp log_api_error(body) do
Logger.warn(fn ->
["Failed to send sentry event.", ?\n, body]
Expand Down
23 changes: 16 additions & 7 deletions test/client_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,25 @@ defmodule Sentry.ClientTest do
alias Sentry.Client
@sentry_dsn "https://public:secret@app.getsentry.com/1"

setup do
Application.put_env(:sentry, :dsn, @sentry_dsn)
end

test "authorization" do
{_endpoint, public_key, private_key} = Client.parse_dsn!("https://public:secret@app.getsentry.com/1")
{_endpoint, public_key, private_key} = Client.get_dsn!
assert Client.authorization_header(public_key, private_key) =~ ~r/Sentry sentry_version=5, sentry_client=sentry-elixir\/#{Application.spec(:sentry, :vsn)}, sentry_timestamp=\d{10}, sentry_key=public, sentry_secret=secret/
end

test "parsing dsn" do
assert {"https://app.getsentry.com:443/api/1/store/", "public", "secret"} =
Sentry.Client.parse_dsn!("https://public:secret@app.getsentry.com/1")
test "get dsn with default config" do
assert {"https://app.getsentry.com:443/api/1/store/", "public", "secret"} = Sentry.Client.get_dsn!
end

test "get dsn with system config" do
System.put_env("SYSTEM_KEY", @sentry_dsn)
Application.put_env(:sentry, :dsn, {:system, "SYSTEM_KEY"})
assert {"https://app.getsentry.com:443/api/1/store/", "public", "secret"} = Sentry.Client.get_dsn!

assert {"http://app.getsentry.com:9000/api/1/store/", "public", "secret"} =
Sentry.Client.parse_dsn!("http://public:secret@app.getsentry.com:9000/1")
System.delete_env("SYSTEM_KEY")
end

test "logs api errors" do
Expand All @@ -24,7 +32,8 @@ defmodule Sentry.ClientTest do
{:ok, _body, conn} = Plug.Conn.read_body(conn)
assert conn.request_path == "/api/1/store/"
assert conn.method == "POST"
Plug.Conn.put_resp_header(conn, "X-Sentry-Error", "Creation of this event was denied due to rate limiting.")
conn
|> Plug.Conn.put_resp_header("X-Sentry-Error", "Creation of this event was denied due to rate limiting.")
|> Plug.Conn.resp(400, "Something bad happened")
end

Expand Down
2 changes: 1 addition & 1 deletion test/support/test_client.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
defmodule Sentry.TestClient do
def send_event(%Sentry.Event{} = event) do
{endpoint, _public_key, _secret_key} = Sentry.Client.parse_dsn!(Application.fetch_env!(:sentry, :dsn))
{endpoint, _public_key, _secret_key} = Sentry.Client.get_dsn!
body = Poison.encode!(event)
Sentry.Client.request(:post, endpoint, [], body)
end
Expand Down