Coder Social home page Coder Social logo

bugsnag-elixir's Introduction

Bugsnag Elixir

Elixir CI Bugsnag Version Hex Docs Total Download License Last Updated

Capture exceptions and send them to the Bugsnag API!

๐Ÿ”— See also: Plugsnag, to snag exceptions in your Phoenix application.

Installation

# mix.exs
defp deps do
  [
    {:bugsnag, "~> 3.0.2"},
    # pick ONE of these JSON encoding libraries:
    {:jason, "~> 1.0"},
    {:poison, "~> 4.0"}
    # add your http client of choice
    # or use httpoison for the default adapter:
    {:httpoison, "~> 1.0"},
  ]
end
# config/config.exs
config :bugsnag,
  api_key: "0123456789abcdef0123456789abcdef"

The :bugsnag application must be started to report errors โ€” this should be done automatically by application inference, as long as the application function in your mix.exs does not contain an applications key. If it does, you'll want to add :bugsnag to the list of applications.

By default, the application adds an Erlang :error_logger handler on startup that will report most process crashes automatically. If you only want to report errors manually, this can be configured via the use_logger option (see below).

Umbrella apps

To work with umbrella apps, it's necessary add :bugsnag as extra application in each application.

# apps/my_awesome_umbrella_app/mix.exs
defmodule MyAwesomeUmbrellaApp.MixProject do
  # ...

  defp extra_applications(:test), do: extra_applications(:default) ++ [:cowboy, :plug]
  defp extra_applications(_), do: [:logger, :runtime_tools, :httpoison, :bugsnag]

  # ...
end

# apps/my_awesome_umbrella_proxy/mix.exs
defmodule MyAwesomeUmbrellaProxy.MixProject do
  # ...

  defp extra_applications(:test), do: extra_applications(:default) ++ [:cowboy, :plug]
  defp extra_applications(_), do: [:logger, :runtime_tools, :httpoison, :bugsnag]

  # ...
end

Configuration

Although errors will be reported even if you only set an API key, some Bugsnag features (like release stage and app version tagging, or marking stack frames as "in-project") require additional configuration.

All configuration options support {:system, "ENV_VAR"} tuples for retrieving values from environment variables at application startup. You can also specify a default value using {:system, "ENV_VAR", "default_value"}.

Example

This config uses all available features. It assumes your project is a single application whose code is in lib/my_app_name, and you have an environment variable MY_APP_ENV set to values like "staging" or "production" depending on the runtime environment.

# config/config.exs
config :bugsnag,
  api_key: "0123456789abcdef0123456789abcdef",
  app_type: "elixir",
  app_version: Mix.Project.config[:version],
  endpoint_url: "https://self-hosted-bugsnag.myapp",
  hostname: {:system, "HOST", "unknown"},
  http_client: MyApp.BugsnagHTTPAdapter,
  http_client_opts: [ssl: [cacertfile: "/path/to/cacertfile.pem"]],
  in_project: "lib/my_app_name",
  json_library: Jason,
  notify_release_stages: ["staging", "production"],
  release_stage: {:system, "MY_APP_ENV", "production"},
  sanitizer: {MyModule, :my_function},
  use_logger: true

See below for explanations of each option, including some options not used here.

api_key

Default: nil

Must be set to report errors.

release_stage

Default: "production"

Sets the default "release stage" for reported errors. If set to a value that is not included in notify_release_stages, all reports will be silently discarded.

notify_release_stages

Default: ["production"]

If the configured release_stage is not in this list, all error reports are silently discarded. This allows ignoring errors in release stages you don't want to clutter your Bugsnag dashboard, e.g. development or test.

To accommodate configuration via environment variables, if set to a string, the string will be split on commas (,).

hostname

Default: "unknown"

Sets the default hostname for reported errors.

app_type

Default: "elixir"

Sets the default application type for reported errors.

app_version

Default: nil

Sets the default application version for reported errors.

sanitizer

Default: nil

A function to be applied over contents of stack traces.

Example

defmodule MyModule do
  def my_func(word) do
    Regex.replace(~r/fail/, word, "pass")
  end
end

config :bugsnag, sanitizer: {MyModule, :my_func}
raise "123fail123"

Produces the failure message

123pass123

If a sanitizer function throws an exception while running, it will log out a warning and return the string [CENSORED DUE TO SANITIZER EXCEPTION]

application

Default: nil

Sets the application name to generate a smart default for the in_project value. Set this to the name of your application with the following:

config :bugsnag, application: Mix.Project.config[:app]

in_project

Default: nil

When reporting the stack trace of an exception, Bugsnag allows marking each stack frame as being "in your project" or not. This enables grouping errors by the deepest stack frame that is in your project. Unfortunately it's hard to do this automatically in Elixir, because file paths in stack traces are relative to the application the file is part of (i.e. all start with lib/some_app/...). Since we don't know which apps are "yours", this option must be set to enable marking stack frames as in-project.

This option can be set in several ways:

String Matching

config :bugsnag, in_project: "lib/my_app_name"

If a stack frame's file path contains the string, it will be marked in-project.

Regex Matching

config :bugsnag, in_project: ~r(my_app_name|my_other_app)

If a stack frame's file path matches the regex, it will be marked in-project.

Custom Function

config :bugsnag, in_project: fn({module, function, arguments, file_path}) ->
  module in [SomeMod, OtherMod] or file_path =~ ~r(^lib/my_project)
end

If the function returns a truthy value when called with the stack frame as an argument, the stack frame will be marked in-project. You can also specify a function as a {Module, :function, [extra_args]} tuple (the stack frame tuple will be prepended as the first argument to the function).

endpoint_url

Default: "https://notify.bugsnag.com"

Allows sending reports to a different URL (e.g. if using Bugsnag On-premise).

use_logger

Default: true

Controls whether the default Erlang :error_logger handler is added on application startup. This will automatically report most process crashes.

exception_filter

Default: nil

Optional module that allows filtering of log messages. For example

defmodule MyApp.ExceptionFilter do
  def should_notify({{%{plug_status: resp_status},_},_}, _stacktrace) when is_integer(resp_status) do
    #structure used by cowboy 2.0
    resp_status < 400 or resp_status >= 500
  end
  def should_notify(_e, _s), do: true
end

json_library

Default: Jason

The JSON encoding library.

http_client

Default Bugsnag.HTTPClient.Adapters.HTTPoison

An adapter implementing the Bugsnag.HTTPClient behaviour.

http_client_opts

Default []

A keyword list of options passed to the calls made with an adapter implementing the Bugsnag.HTTPClient behaviour.

Usage

In the default configuration, unhandled exceptions that crash a process will be automatically reported to Bugsnag. If you want to report a rescued exception, or have use_logger disabled, you can send reports manually.

Manual Reporting

Use Bugsnag.report to report an exception:

try do
  raise "heck"
rescue exception ->
  Bugsnag.report(exception)
end

This reports the exception in a separate process so your application code will not be held up. However, this means reporting could fail silently. If you want to wait on the report in your own process (and potentially crash, if reporting fails), use Bugsnag.sync_report:

try do
  raise "heck"
rescue exception ->
  :ok = Bugsnag.sync_report(exception)
end

Reporting Options

Both report and sync_report accept an optional second argument to add more data to the report or override the application configuration:

try do
  raise "heck"
rescue exception ->
  Bugsnag.report(exception, severity: "warning", context: "worker")
end

The following options override their corresponding app config values:

  • api_key
  • release_stage
  • notify_release_stages
  • hostname
  • app_type
  • app_version

The following options allow adding more data to the report:

  • severity โ€” Sets the severity of the report (error, warning, or info)
  • context โ€” Sets the "context" string (e.g. controller#action in Phoenix)
  • user โ€” Map of information about the user who encountered the error:
    • id - String ID for the user
    • name - Full name of the user
    • email - Email address of the user
  • os_version โ€” Sets the reported OS version of the error
  • stacktrace โ€” Allows passing in a stack trace, e.g. from __STACKTRACE__
  • metadata - Map of arbitrary metadata to include with the report
  • error_class - Allows passing in the error type instead of inferring from the error struct

See the Bugsnag docs for more information on these fields.

License

This source code is licensed under the MIT license found in the LICENSE file. Copyright (C) 2014-present Jared Norman

bugsnag-elixir's People

Contributors

arcz avatar balena avatar behe avatar camshaft avatar coburncoburn avatar davich avatar dnsbty avatar ephe-meral avatar grantovich avatar isaacsanders avatar isaacseymour avatar jarednorman avatar jbodah avatar jeffrom avatar jgittler avatar jhahn avatar jonrowe avatar kianmeng avatar luisfmcalado avatar manukall avatar mitchellhenke avatar mootpointer avatar nathan-cruz77 avatar nirev avatar pavlos avatar smaximov avatar sprql avatar stephanos avatar tsubery avatar zillou avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

bugsnag-elixir's Issues

Bugsnag logger removed when using lager

Hi Jared,

I don't think that the problem is with bugsnag-elixir, but I felt like I would be doing a disservice by not writing about an issue I saw here. The reason it's particularly nasty is that I didn't know it was busted, as plugsnag still works fine.

I am using elixometer which requires lager for some reason (haven't dug into this). lager adds in an error reporter automatically, but seems to remove all other error reporters.

We can test if Bugsnag.Logger SASL logger is in our project by running :gen_event.which_handlers(:error_logger) in an iex -S mix session. If it's not there, lager might be removing it.

My solution was to remove lager error reporter in a config:

config :lager,
  error_logger_redirect: false

However, an engineer could re-add Bugsnag.Logger in their application setup with :error_logger.add_report_handler(Bugsnag.Logger) or setup Bugsnag application to load after lager application.

Offer to Maintain

I'd be happy to take over maintenance of the package. I'm currently using this package in a production environment, so it's actually quite critical to my needs.

hackney_manager no process

I've added the following code to a controller action

try do
  :foo = :bar
rescue
  exception -> Bugsnag.sync_report(exception)
end

to test my bugsnag integration. But when I hit it, I get

exited in: :gen_server.call(:hackney_manager, {:new_request, #PID<0.615.0>, #Reference<0.0.2.2941>, {:client, :undefined, {:metrics_ng, :metrics_dummy}, :hackney_ssl, 'notify.bugsnag.com', 443, "notify.bugsnag.com", [], nil, nil, nil, true, :hackney_pool, 5000, false, 5, false, 5, nil, nil, nil, {0, {:dict, 0, 16, 16, 8, 80, 48, {[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []}, {{[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []}}}}, :undefined, :start, nil, :normal, false, false, false, :undefined, false, nil, :waiting, nil, 4096, "", [], :undefined, nil, nil, nil, nil, :undefined, nil}}, :infinity) ** 
(EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started

Any ideas what I'm doing wrong?
I integrated bugsnag-elixir in another application yesterday and it just worked, so I'm unsure what's going wrong here.
Thanks in advance!

I'm on version 1.5.0, by the way.

use GenEvent is deprecated

==> bugsnag
Compiling 3 files (.ex)
warning: use GenEvent is deprecated, use one of the alternatives described in the documentation for the GenEvent module
  lib/bugsnag/logger.ex:5

warning: the GenEvent module is deprecated, see its documentation for alternatives
  lib/bugsnag/logger.ex:5

UndefinedFunctionError not being captured?

Hello!

We recently noticed that most errors are successfully captured and sent to Bugsnag, however, UndefinedFunctionError doesn't seem to be one of them. I can trigger an ArithmeticError, for example, and see it makes its way to Bugsnag. But when I call a function with more/less arguments, it doesn't get to Bugsnag.

I tried adding logs everywhere but came up empty handed.

Is there an explanation for this?

Use ConfigExt for more flexible configuration.

As suggested in #37, this would give great helpers (check the docs) which I found useful in dynamic environments like AWS ECS or Kubernetes clusters.

I wanted to get your opinion on this first, if it's ok I can add PR for it ๐Ÿ‘

WDYS?

deprecated function warning with elixir 1.10.1/OTP 22

% iex -S mix   
Erlang/OTP 22 [erts-10.6] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [hipe]

warning: :restart and :shutdown options in Task.Supervisor.start_link/1 are deprecated. Please pass those options on start_child/3 instead
  (elixir 1.10.1) lib/task/supervisor.ex:86: Task.Supervisor.start_link/1
  (stdlib 3.11) supervisor.erl:379: :supervisor.do_start_child_i/3
  (stdlib 3.11) supervisor.erl:365: :supervisor.do_start_child/2
  (stdlib 3.11) supervisor.erl:349: anonymous fn/3 in :supervisor.start_children/2
  (stdlib 3.11) supervisor.erl:1157: :supervisor.children_map/4

Preventing Duplicate Errors

I setup a testing scenario with Bugsnag-elixir and Plugsnag by making an invalid function. I get a correctly logged error as well as an Elixir.ErlangError that contains the contents of the error:

image

I've had this issue across a few projects. I've varied between living with it (current plan), and trying to fix it manually with exception filters. I realized today that my exception filters actually could have been ignoring real errors.

Can't get Mix Tasks to report exceptions

defmodule Mix.Tasks.MyTask.TestException do
  use Mix.Task

  @shortdoc "Test Exception"

  def run(_args) do
    {:ok, _started} = Application.ensure_all_started(:my_app, :permanent)

    raise "Another Test Exception"
  end
end

Any idea how do I actually get that raised error to be reported on Bugsnag automatically?

Hard-coded criteria for whether a stack frame is "in-project"

#17 added detailed reporting of stack frames to Bugsnag. The platform has a notion of whether a given stack frame is "in-project" (i.e. part of your app's code, vs. part of a library), and uses this to control the grouping of error reports.

bugsnag-elixir currently makes this call based on whether the file path starts with the hard-coded strings lib or web. This makes some assumptions about a project's file structure that may not hold true everywhere. At the very least, we should probably make this configurable.

Update dependencies to current versions

Use newer poison version:

Failed to use "poison" (version 3.1.0) because
  bugsnag (version 1.4.0) requires ~> 1.5 or ~> 2.0
  exq (version 0.8.7) requires >= 1.2.0 or ~> 2.0
  phoenix (version 1.3.0-rc.1) requires ~> 2.2 or ~> 3.0
  mix.lock specifies 3.1.0

** (Mix) Hex dependency resolution failed, relax the version requirements of your dependencies or unlock them (by using mix deps.update or mix deps.unlock). If you are unable to resolve the conflicts you can try overriding with {:dependency, "~> 1.0", override: true}

New version

Any chance to release a new version with all the fixes?

Erlang error %Phoenix.Router.NoRouteError reported on 404 after upgrade to plug_cowboy 2

I am copying this bug report from bugsnex library since the issue is the same. It was reported by @adamniedzielski:

After upgrade to plug_cowboy 2, 404 responses started to appear as errors in Bugsnag:

Erlang error: {{%Phoenix.Router.NoRouteError{conn: %Plug.Conn{adapter: {Plug.Cowboy.Conn, :...}, assigns: %{}, before_send: [#Function<1.1812729/1 in Plug.Logger.call/2>], body_params: %{}, cookies: %Plug.Conn.Unfetched{aspect: :cookies}, halted: false, host: "fulfillment-staging.liefery.com", method: "GET", owner: #PID<0.2309.0>, params: %{}, path_info: ["css", "vendor.css"], path_params: %{}, port: 80, private: %{Fulfillment.Router => {[], %{}}, :phoenix_endpoint => Fulfillment.Endpoint, :phoenix_router => Fulfillment.Router, :plug_session_fetch => #Function<1.58261320/1 in Plug.Session.fetch_session/1>}, query_params: %{}, query_string: "", remote_ip: {10, 10, 1, 5}, req_cookies: %Plug.Conn.Unfetched{aspect: :cookies}, req_headers: [{"accept", "text/css,*/*;q=0.1"}, {"accept-encoding", "gzip, deflate, br"}, {"accept-language", "en-US,en;q=0.9,de;q=0.8"}

This didn't happen when using plug_cowboy 1.

It looks like multiple other libraries for error tracking services experienced the similar problem:

appsignal/appsignal-elixir#417
getsentry/sentry-elixir#328
honeybadger-io/honeybadger-elixir#193
I found the content in appsignal/appsignal-elixir#417 particularly informative. Here is the explanation and here is a suggestion to switch from listening to Erlang's error_logger to listening to Elixir's Logger.

Possibility to use `Bugsnag.report` outside a try/rescue block

Hey,

Is it possible to use Bugsnag.report outside a try/rescue block? We're building a consumer and we want to log some stuff, but it seems we can only do that with this dirty hack:

try do
rescue _ -> Bugsnag.report(%FakeException{foo: "bar"})
end

It works that way, but if I just use:

Bugsnag.report(%FakeException{foo: "bar"})

There's no error and nothing on Bugsnag.

Any hints on why this is happening? The FakeException has the structure of a basic exception.

Bugsnag stoped sending information on OTP23

Bugsnag is using HTTPoison to send information to https://notify.bugsnag.com, after the upgrade of OTP to v23 this is causing some SSL issues, better described here: benoitc/hackney#619

To solve this on our projects we are using the most recent hackney version {:hackney, "~> 1.16"},

I believe this is something to be dealt on HTTPoison, but since Bugsnag silently stopped sending information, might be wort to consider

HTTPoison issue: edgurgel/httpoison#411

Uncaught exception with log level :error not :error_report.

If I faced an uncaught exception on my elixir/phoenix application, then it doesn't reported by bugsnag logger because the log level is not :error_report but :error.

For very simple example, if server raises an ArithmeticError by dividing some value by zero, then it matches handle_event({_level, _gl, _event}, state) function of Bugsnag.Logger so it just returns {:ok, state}.

Isn't it should be reported to bugsnag as an uncaught exception?

documentation

Hey all,
I've added credo to the project, to keep some coding standards.
The main warning is missing documentation..
I'm not the best guy to write this.. so if anyone is comfortable in @moduledoc's and English, it will be a great addition.

Potential out-of-memory condition with high error volume

Bugsnag is plugging into error_logger which does not have overload protection. This means when your application triggers many errors, maybe because an API or the database went offline, many messages are sent quickly to the error_logger but those messages are consumed slowly since Bugsnag needs to contact an external API. As errors continue to occur, memory continues to grow, and eventually the node runs out of memory.

There are also other mistakes on Bugsnag usage of error_logger. For example, if Bugsnag handler fails, it will be removed from error_logger and never added back. That means that node will no longer report further errors to bugsnag.

I would recommend to use Elixir's Logger. It provides overload protection from both error_logger messages and Logger messages. It also makes sure your handlers are reattached in case of failures up to some limit.

Elixir Umbrella application

Hello,

I'm using this package for a simple elixir application in production which is working well.

I'm currently building an umbrella application project - it doesn't seem to report uncaught exception - It's working when I send exception manually. Does anyone have an idea?

Best regards :)

Intermittent test failures

Due to the async nature of the reporter, testing the app requires no async tests and sending messages between process. However currently the project has intermittent test failures.

Fix Elixir 1.1.1 warning

Should fix this warning when installing dependencies in Elixir 1.1.1:

warning: the dependency :bugsnag requires Elixir "~> 1.0.2" but you are running on v1.1.1

How to use the Bugsnag.Logger?

I'm trying to send unexpected errors (such as when a process dies) to bugsnag. Is that possible with Bugsnag.Logger? If not how would I go about it?

I've set bugsnag up like this in my config:

config :bugsnag, api_key: System.get_env("BUGSNAG_API_KEY")
config :bugsnag, release_stage: "#{Mix.env}"
config :bugsnag, use_logger: true

Is that the right way to enable Bugsnag.Logger? Also how can I simulate/trigger an error that Bugsnag.Logger will send? I've tried sending an unknown message to a process, but the resulting error does not match the pattern for handle_event({:error_report, _gl, {_pid, _type, [message | _]}}, state) when is_list(message).

Release New Version to Hex

I'd love to be able to use different release stages with Bugsnag, which was added to the library last June (in 9a3e15d). Would you consider releasing a new version to Hex?

`use_logger` is Compulsory

tl;dr
Expected:

# stop bugsnag from collecting test errors (it's always running locally so we can see the errors anyway)
config :bugsnag, use_logger: false

Actual

** (Mix) Could not start application bugsnag: exited in: Bugsnag.start(:normal, [])
    ** (EXIT) an exception was raised:
        ** (CaseClauseError) no case clause matching: "false"
            (bugsnag) lib/bugsnag.ex:15: Bugsnag.start/2
            (kernel) application_master.erl:273: :application_master.start_it_old/4

So, it doesn't matter if you set it to false, it MUST be true, the process will fail to start otherwise:

https://github.com/jarednorman/bugsnag-elixir/blob/master/lib/bugsnag.ex#L15-L17

My only question, was this intended?
If yes, why bother giving the option in the first place if it's mandatory? Why not give it an actual human-readable error message?
else, can we change it to ignore ?

Customize errorClass

I often use Bugsnag to log caught exceptions / edge cases that I want to know about. If I use Bugsnag.report("something"), the errorClass appears as "Elixir.ErlangError" because of the error normalization.

Is there a way to easily have this appear as a custom named exception? I know it's possible to do with a custom module like:

  defmodule Custom.ValidationErrors do
    # tricks normalize into thinking it's an exception
    defstruct errs: [], __exception__: true

    def new(errs) do
      %__MODULE__{errs: errs}
    end

    def message(errs) do
      inspect(errs)
    end

But I'm hoping there's a lighter way

Add a `notify_release_stages` option

Hey @jarednorman,

Thnx for building this package!
The official Ruby package has an option called notify_release_stages which states in what rack environments it is going to report errors.

Is there such an option in this package? If not, I'd be willing to do it through a pull request, just wondering if you're interested in merging it in.

Thnx.

Repository config

Would be nice to enable the ability to configure the code repository in Bugsnag.

Not working for me

Hello Bugsnag user,

I've tried all the possibility, I can't manage to make bugsnag-elixir work to report all uncaught exceptions.

I've tried on a simple elixir app and simple phoenix app, it didn't work as expected. I can manually report exception but not uncaught ones.

I'm using Elixir 1.5.3, Erlang OTP 20 [erts-9.2.1].

I've created a test example repository to help you see what is not working properly..

Feel free to help ๐Ÿ™ Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.