Current section

22 Versions

Jump to

Compare versions

6 files changed
+102 additions
-27 deletions
  @@ -1,6 +1,4 @@
1 - ### This project is looking for a maintainer. As much as I love the language, ecosystem, community around Elixir, I'm not currently lucky enough to be doing any serious work in the language. If someone would like to take some responsibility for the project I would hugely appreciate it.
2 -
3 - # Bugsnag Elixir
1 + # Bugsnag Elixir [![Build Status](https://travis-ci.org/jarednorman/bugsnag-elixir.svg?branch=master)](https://travis-ci.org/jarednorman/bugsnag-elixir)
4 2
5 3 Capture exceptions and send them to the [Bugsnag](http://bugsnag.com) API!
6 4
  @@ -19,6 +17,9 @@ end
19 17
20 18 # Open up your config/config.exs (or appropriate project config)
21 19 config :bugsnag, api_key: "bbf085fc54ff99498ebd18ab49a832dd"
20 +
21 + # Set the release stage in your environment configs (e.g. config/prod.exs)
22 + config :bugsnag, release_stage: "prod"
22 23 ```
23 24
24 25 ## Usage
  @@ -3,19 +3,19 @@
3 3 {<<"description">>,<<"An Elixir interface to the Bugsnag API">>}.
4 4 {<<"elixir">>,<<"~> 1.0">>}.
5 5 {<<"files">>,
6 - [<<"lib/bugsnag.ex">>,<<"lib/bugsnag/payload.ex">>,<<"mix.exs">>,
7 - <<"README.md">>,<<"LICENSE">>]}.
6 + [<<"lib/bugsnag.ex">>,<<"lib/bugsnag/logger.ex">>,
7 + <<"lib/bugsnag/payload.ex">>,<<"mix.exs">>,<<"README.md">>,<<"LICENSE">>]}.
8 8 {<<"licenses">>,[<<"MIT">>]}.
9 9 {<<"links">>,
10 10 [{<<"github">>,<<"https://github.com/jarednorman/bugsnag-elixir">>}]}.
11 11 {<<"name">>,<<"bugsnag">>}.
12 12 {<<"requirements">>,
13 - [{<<"httpoison">>,
14 - [{<<"app">>,<<"httpoison">>},
15 - {<<"optional">>,false},
16 - {<<"requirement">>,<<"~> 0.6">>}]},
17 - {<<"poison">>,
18 - [{<<"app">>,<<"poison">>},
19 - {<<"optional">>,false},
20 - {<<"requirement">>,<<"~> 1.3">>}]}]}.
21 - {<<"version">>,<<"1.2.0">>}.
13 + [[{<<"app">>,<<"httpoison">>},
14 + {<<"name">>,<<"httpoison">>},
15 + {<<"optional">>,false},
16 + {<<"requirement">>,<<"~> 0.6">>}],
17 + [{<<"app">>,<<"poison">>},
18 + {<<"name">>,<<"poison">>},
19 + {<<"optional">>,false},
20 + {<<"requirement">>,<<"~> 1.5 or ~> 2.0">>}]]}.
21 + {<<"version">>,<<"1.3.0">>}.
  @@ -1,21 +1,44 @@
1 1 defmodule Bugsnag do
2 + use Application
3 +
4 + alias Bugsnag.Payload
5 +
2 6 @notify_url "https://notify.bugsnag.com"
3 7 @request_headers [{"Content-Type", "application/json"}]
4 8
5 - alias Bugsnag.Payload
6 - use HTTPoison.Base
9 + def start do
10 + config = Keyword.merge default_config, Application.get_all_env(:bugsnag)
11 +
12 + if config[:use_logger] do
13 + :error_logger.add_report_handler(Bugsnag.Logger)
14 + end
15 +
16 + # put normalized api key to application config
17 + Application.put_env(:bugsnag, :api_key, config[:api_key])
18 + end
7 19
8 20 def report(exception, options \\ []) do
9 - stacktrace = System.stacktrace
21 + stacktrace = options[:stacktrace] || System.stacktrace
22 +
10 23 spawn fn ->
11 - post(@notify_url,
12 - Payload.new(exception, stacktrace, options) |> to_json,
13 - @request_headers)
24 + Payload.new(exception, stacktrace, options)
25 + |> to_json
26 + |> send_notification
14 27 end
15 28 end
16 29
17 30 def to_json(payload) do
18 - payload
19 - |> Poison.encode!
31 + payload |> Poison.encode!
32 + end
33 +
34 + defp send_notification(body) do
35 + HTTPoison.post @notify_url, body, @request_headers
36 + end
37 +
38 + defp default_config do
39 + [
40 + api_key: System.get_env("BUGSNAG_API_KEY") || "FAKEKEY",
41 + use_logger: true
42 + ]
20 43 end
21 44 end
  @@ -0,0 +1,46 @@
1 + defmodule Bugsnag.Logger do
2 + require Bugsnag
3 + require Logger
4 +
5 + use GenEvent
6 +
7 + def init(_mod, []), do: {:ok, []}
8 +
9 + def handle_call({:configure, new_keys}, _state) do
10 + {:ok, :ok, new_keys}
11 + end
12 +
13 + def handle_event({_level, gl, _event}, state)
14 + when node(gl) != node() do
15 + {:ok, state}
16 + end
17 +
18 + def handle_event({:error_report, _gl, {_pid, _type, [message | _]}}, state)
19 + when is_list(message) do
20 + try do
21 + error_info = message[:error_info]
22 +
23 + case error_info do
24 + {_kind, {exception, stacktrace}, _stack} when is_list(stacktrace) ->
25 + Bugsnag.report(exception, stacktrace: stacktrace)
26 + {_kind, exception, stacktrace} ->
27 + Bugsnag.report(exception, stacktrace: stacktrace)
28 + end
29 + rescue
30 + ex ->
31 + error_type = Exception.normalize(:error, ex).__struct__
32 + |> Atom.to_string
33 + |> String.replace(~r{\AElixir\.}, "")
34 +
35 + reason = Exception.message(ex)
36 +
37 + Logger.warn "Unable to notify Bugsnag #{error_type}: #{reason}"
38 + end
39 +
40 + {:ok, state}
41 + end
42 +
43 + def handle_event({_level, _gl, _event}, state) do
44 + {:ok, state}
45 + end
46 + end
  @@ -4,6 +4,7 @@ defmodule Bugsnag.Payload do
4 4 version: Bugsnag.Mixfile.project[:version],
5 5 url: Bugsnag.Mixfile.project[:package][:links][:github],
6 6 }
7 + @release_stage Application.get_env(:bugsnag, :release_stage) || "test"
7 8
8 9 defstruct api_key: nil, notifier: @notifier_info, events: nil
9 10
  @@ -18,15 +19,17 @@ defmodule Bugsnag.Payload do
18 19 end
19 20
20 21 defp add_event(payload, exception, stacktrace, options) do
22 + error = Exception.normalize(:error, exception)
23 +
21 24 event =
22 25 Map.new
23 26 |> add_payload_version
24 - |> add_exception(exception, stacktrace)
27 + |> add_exception(error, stacktrace)
25 28 |> add_severity(Keyword.get(options, :severity))
26 29 |> add_context(Keyword.get(options, :context))
27 30 |> add_user(Keyword.get(options, :user))
28 31 |> add_metadata(Keyword.get(options, :metadata))
29 - |> add_release_stage(Keyword.get(options, :release_stage, to_string Mix.env))
32 + |> add_release_stage(Keyword.get(options, :release_stage, @release_stage))
30 33
31 34 Map.put payload, :events, [event]
32 35 end
Loading more files…