Skip to content

Commit

Permalink
Slack notifier implementation (#1)
Browse files Browse the repository at this point in the history
* Initial commit

* Replace receive do with assert_receive in test

* Move lib modules to lib/boom_slack_notifier

* Make behaviour return types generic to allow user-defined http adapters

* Add error logging when request fails and testing for it

* Readme improvements

* Move test process registration to helper module

* Improve logger formatting to allow error objects

* Rename HttpAdapter into SlackAdapter, removed nesting and updated docs

* Move out HTTPoisonAdapter to lib folder

* Remove unnecessary Application.put_env in tests

* Fix format

* Rename slack adapater references in documentation

* Rename cache key
  • Loading branch information
joulei authored May 3, 2022
1 parent ab88c31 commit 44e6370
Show file tree
Hide file tree
Showing 18 changed files with 897 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
102 changes: 102 additions & 0 deletions .github/workflows/elixir.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
name: Elixir CI

on: [push, pull_request]

jobs:
build:

name: Build and test
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
include:
- elixir: '1.8'
otp: '21'
- elixir: '1.8'
otp: '22'
- elixir: '1.9'
otp: '21'
- elixir: '1.9'
otp: '22'
- elixir: '1.10'
otp: '21'
- elixir: '1.10'
otp: '22'
- elixir: '1.10'
otp: '23'
- elixir: '1.11'
otp: '21'
- elixir: '1.11'
otp: '22'
- elixir: '1.11'
otp: '23'
- elixir: '1.11'
otp: '24'
- elixir: '1.12'
otp: '22'
- elixir: '1.12'
otp: '23'
- elixir: '1.12'
otp: '24'
- elixir: '1.12'
otp: '24'
- elixir: '1.13'
otp: '22'
- elixir: '1.13'
otp: '23'
- elixir: '1.13'
otp: '24'
lint: lint
- elixir: '1.13'
otp: '24'
deps: latest

steps:
- uses: actions/checkout@v2

- name: Set up Elixir
uses: erlef/setup-beam@v1
with:
elixir-version: ${{ matrix.elixir }}
otp-version: ${{ matrix.otp }}

- name: Retrieve Mix Dependencies Cache
if: matrix.deps != 'latest'
uses: actions/cache@v1
id: mix-cache
with:
path: deps
key: ${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-mix-${{ hashFiles('mix.lock') }}

- name: Remove mix.lock
if: matrix.deps == 'latest'
run: rm mix.lock

- name: Install dependencies
if: steps.mix-cache.outputs.cache-hit != 'true'
run: mix deps.get

- name: Retrieve PLT Cache
uses: actions/cache@v1
id: plt-cache
with:
path: priv/plts
key: ${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-plts-${{ hashFiles('mix.lock') }}
if: ${{ matrix.lint }}

- name: Create PLTs
run: |
mkdir -p priv/plts
mix dialyzer --plt
if: ${{ matrix.lint }}

- name: Check quality
run: |
mix format --check-formatted
mix dialyzer --no-check
if: ${{ matrix.lint }}

- name: Run tests
run: mix test
28 changes: 28 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# The directory Mix will write compiled artifacts to.
/_build/

# If you run "mix test --cover", coverage assets end up here.
/cover/

# The directory Mix downloads your dependencies sources to.
/deps/

# Where third-party dependencies like ExDoc output generated docs.
/doc/

# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch

# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump

# Also ignore archive artifacts (built via "mix archive.build").
*.ez

# Ignore package tarball (built via "mix hex.build").
boom_slack_notifier-*.tar

# Temporary files, for example, from tests.
/tmp/

priv/
80 changes: 80 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# BoomSlackNotifier

Provides a Slack notifier for the [BoomNotifier](https://github.com/wyeworks/boom) exception notification package.

You can read the full documentation at [https://hexdocs.pm/boom_slack_notifier](https://hexdocs.pm/boom_slack_notifier).

## Installation

The package can be installed by adding `boom_slack_notifier` to your list of dependencies in
`mix.exs`:

```elixir
def deps do
[
{:boom_notifier, "~> 0.8.0"},
{:boom_slack_notifier, "~> 0.1.0"}
]
end
```

## How to use it

```elixir
defmodule YourApp.Router do
use Phoenix.Router

use BoomNotifier,
notifier: BoomSlackNotifier.SlackNotifier,
options: [
webhook_url: "<your-slack-generated-url>",
]

# ...
```

To configure it, you need to set the `webhook_url` in the `options` keyword list. A `POST` request with a `json` will be made to that webhook when an error ocurrs with the relevant information.

### Setting up a Slack webhook

If you don't already have a webhook setup for Slack, you can follow the steps below:

1. Go to [Slack API](https://api.slack.com/) > My Apps
2. Create a new application
3. Inside your new application go to > Add features and functionality > Incoming Webhooks
4. Activate incoming webhooks for your application
5. Scroll down to 'Webhook URLs for Your Workspace' and create a new Webhook URL for a given channel.

## Http client

By default BoomSlackNotifier uses [HTTPoison](https://github.com/edgurgel/httpoison) as the http client.

You can setup your favorite client by warpping it with the `SlackAdapter` behaviour, for example:

```
#mojito_http_adapter.ex
@impl BoomSlackNotifier.SlackAdapter
@spec post(any, binary, any) :: {:ok, any} | {:error, any}
def post(body, url, headers) do
{:ok, response} = Mojito.request(body: body, method: :post, url: url, headers: headers)
# ...
end
```

And then specifying it in your application configuration:

```
#config.exs
config :boom_slack_notifier, :slack_adapter, MyApp.MojitoHttpAdapter
```

Default configuration (not required):
```
config :boom_slack_notifier, :slack_adapter, BoomSlackNotifier.SlackClient.HTTPoisonAdapter
```
## License

BoomSlackNotifier is released under the terms of the [MIT License](https://github.com/wyeworks/boom/blob/master/LICENSE).
5 changes: 5 additions & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use Mix.Config

config :phoenix, :json_library, Jason

import_config "#{Mix.env()}.exs"
3 changes: 3 additions & 0 deletions config/dev.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
use Mix.Config

config :boom_slack_notifier, :slack_adapter, BoomSlackNotifier.HTTPoisonAdapter
3 changes: 3 additions & 0 deletions config/test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
use Mix.Config

config :boom_slack_notifier, :slack_adapter, Support.HttpAdapterMock
16 changes: 16 additions & 0 deletions lib/boom_slack_notifier/httpoison_adapter.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
defmodule BoomSlackNotifier.HTTPoisonAdapter do
@moduledoc false

@behaviour BoomSlackNotifier.SlackAdapter

HTTPoison.start()

@impl BoomSlackNotifier.SlackAdapter
@spec post(any, binary, HTTPoison.Base.headers()) ::
{:ok,
HTTPoison.Response.t() | HTTPoison.AsyncResponse.t() | HTTPoison.MaybeRedirect.t()}
| {:error, HTTPoison.Error.t()}
def post(body, url, headers) do
HTTPoison.post(url, body, headers, [])
end
end
38 changes: 38 additions & 0 deletions lib/boom_slack_notifier/slack_adapter.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
defmodule BoomSlackNotifier.SlackAdapter do
@moduledoc """
By default BoomSlackNotifier uses [HTTPoison](https://github.com/edgurgel/httpoison) as the http client.
You can setup your favorite client by warpping it with the `SlackAdapter` behaviour, for example:
```
#mojito_http_adapter.ex
@impl BoomSlackNotifier.SlackAdapter
@spec post(any, binary, any) :: {:ok, any} | {:error, any}
def post(body, url, headers) do
{:ok, response} = Mojito.request(body: body, method: :post, url: url, headers: headers)
# ...
end
```
And then specifying it in your application configuration:
```
#config.exs
config :boom_slack_notifier, :slack_adapter, MyApp.MojitoHttpAdapter
```
Default configuration (not required):
```
config :boom_slack_notifier, :slack_adapter, BoomSlackNotifier.SlackClient.HTTPoisonAdapter
```
"""

@doc """
Defines a callback to be used by the http adapters
"""
@callback post(any, binary, any) :: {:ok, any} | {:error, any}
end
Loading

0 comments on commit 44e6370

Please sign in to comment.