For Phoenix developers, maintaining the health of your applications is critical. AppSignal offers a powerful solution to gain deep insights into your application's performance and stability.
In this introductory guide, we'll walk through the process of setting up AppSignal in your Phoenix app, instrumenting your code for detailed monitoring, handling errors effectively, and utilizing AppSignal's features to maintain and improve your application's performance. The lessons you learn from this article will help you get started using AppSignal to monitor your Phoenix app.
But before proceeding, let's see what you'll need to follow along effectively.
Prerequisites
- An AppSignal account — you can sign up for a free 30-day trial.
- A Phoenix app to work with. If you don't have one, you can fork this one that we'll use throughout the tutorial.
- Some experience working with Elixir/Phoenix applications.
Let's get started by learning how to add AppSignal to an existing Phoenix application.
Adding AppSignal to a Phoenix Application
Adding AppSignal's Phoenix package is very easy — just open up mix.exs
and add the package as shown below:
# mix.exs ... defp deps do [ {:phoenix, "~> 1.7.14"}, {:phoenix_ecto, "~> 4.5"}, ... {:appsignal_phoenix, "~> 2.0"} ] end ...
After that, run mix deps.get
to add the package to the application, then run the command below to install it:
mix appsignal.install <YOUR API KEY HERE>
Tip: You can find your API key in the AppSignal dashboard.
When you run the installer, you'll be prompted for an application name — go ahead and enter an appropriate name:
Validating Push API key: Valid! 🎉 What is your application's name? [counter_live_app]: Counter Live App
Next up, you'll need to choose how you want the AppSignal configuration handled for your app:
There are two methods of configuring AppSignal in your application. Option 1: Using a "config/appsignal.exs" file. (1) Option 2: Using system environment variables. (2)
You can choose whatever suits you, but I prefer option 1, which uses a config file that you can customize to your liking. Once you make your choice, the AppSignal configuration should now be working, and if you visit the dashboard, you can see some default graphs (these might be empty initially as it takes a little bit of time for your app's data to be sent over).
Before moving on, let's take a look at how you can customize the AppSignal config file.
Customizing the AppSignal Config File
A config file tells AppSignal which app and environment to instrument.
The code snippet below shows a minimal configuration:
# config/appsignal.exs import Config config :appsignal, :config, otp_app: :counter_live_app, name: "Counter Live App", push_api_key: "API KEY HERE", env: Mix.env
As you can see, the most important settings include:
- Your application's OTP name.
- The name of the app as you want it to appear on AppSignal.
- Your AppSignal API key.
- The environment you want to instrument for, which could be development, production, or test environments.
The config file can be further customized using a variety of other options.
With the installation and configuration working, let's shift gears to monitor our Phoenix app's performance.
Monitoring the Performance of a Phoenix App
When you add the AppSignal package to your Phoenix application, the package will take care of default HTTP instrumentation needs and send data to a dashboard:
And part of the automatic instrumentation includes performance monitoring:
The default instrumentation will also include important details for slow-performing requests, like what's shown below:
And all of this is possible without any extra work from you.
Next up, let's see how you can customize some of the performance instrumentation. For example, we can add a custom slow function to the Posts index and see the same on the AppSignal dashboard.
First, let's edit the index action in the posts controller as shown below:
# lib/counter_live_app_web/controllers/posts_controller.ex defmodule CounterLiveAppWeb.PostController do ... def index(conn, params) do really_slow() ... end ... def really_slow do Appsignal.instrument("really slow index request", fn -> :timer.sleep(1000) end) end end
And with that, we can visualize the instrumentation on the dashboard:
Tracking Phoenix App Errors Using AppSignal
In the previous section, we saw how adding AppSignal to our Phoenix app provides us with a lot of information about app performance. We also went ahead and added some simple custom instrumentation to simulate a really slow request to the posts index action, and visualized the results on the AppSignal dashboard. Now, let's see how we can view and track Phoenix errors using AppSignal.
Our first example will be a simple call to a non-existent route, as shown below:
Again, as with the default performance metrics, without extra work on our part, AppSignal is able to pick up this error and display it on the dashboard:
If you click on the error, you can see more detailed information, which is really helpful for debugging purposes:
I won't go into more detail on how you can customize exception instrumentation in the scope of this post. If you are interested in going down that rabbit hole, check out the AppSignal for Elixir documentation on exception handling.
Next up, let's set up alerts and notifications.
Setting up Effective Alerts and Notifications
As useful as an application performance monitoring solution like AppSignal is, you wouldn't want to spend all your time staring at dashboards. Instead, it would be better if you received automated alerts for any significant events.
By default, whenever an error or performance event happens, it's recorded as an error or performance incident by AppSignal. Depending on the notification settings you've set up, you'll get an email (the default notification channel) or a message through any of the other available notification channels.
You can customize how AppSignal will notify you of events and errors by setting up any of the five notification defaults available:
- Never notify - when set to this, AppSignal will not notify you whenever an error or incident occurs. This setting is useful for non-critical incidents.
- Every occurrence - Let's say you'd like to be notified every time an incident happens. This is the setting you would use. You can use this setting for incidents that are critical in nature.
- First in deploy - Here, a notification will be sent whenever an incident occurs when you first deploy your app. You will need to set up deploy markers that will tell AppSignal when a deployment occurs. For example, let's say you've set up post-deploy hooks of some kind. In that case, this setting helps you catch errors if these hooks don't work as expected.
- First after close - This setting tells AppSignal to send a notification after an incident recurs, immediately after you close a previous similar one. This setting would be useful for incidents that are not entirely due to a bug in your code, (for example, third-party API connection issues and so forth).
- Every nth hour or day - Here, you tell AppSignal not to send a notification every nth hour or day. This could be very useful if you are facing an increased bill due to an increase in notification events.
So far, everything we've looked at is quite basic, but your AppSignal setup is capable of a lot more.
Next, let's briefly look at one or two examples of custom monitoring and alert notification setups.
Custom Alert Notification Setup
By default, every application that is being monitored by AppSignal will have an email notifier set up automatically.
Even so, you might want to be notified via other channels, and with AppSignal, these are a breeze to set up. The first step is to click on the "Add integration" button.
For example, if you wanted a Discord notifier, just choose it from the list of integrations and input the required information in the resulting dialog like this:
Even with all the bells and whistles that AppSignal makes available for alerting and notifications, it's important to really think about the kinds of notifications you would like to receive and the ones you'd be safe ignoring.
Some good rules of thumb to guide your decision in this would include:
- Consider error thresholds for critical versus non-critical errors. For non-critical errors, you could set very high thresholds. For critical errors, you might set finer thresholds (for example, send an alert if a critical error exceeds 5% and lasts for more than 3 minutes).
- Set up alerts and notifications for memory consumption. One of the key resources any app uses is memory. If an app is consuming more-than-normal memory, you want to make sure an alert is sent to you early.
- Uptime and availability notifications. This is self-explanatory, but you definitely want to be notified any time your app is unavailable.
- It would also make sense to set up alerts for custom events that are key to the functionality of your app, or to the user experience (for example, a bunch of failed payments over a certain amount of time).
With these rules in mind, and considering AppSignal's robust alerting infrastructure, you have all you need to be notified whenever things go wrong. If you need further information, go through AppSignal's documentation on setting up notifications and alerts.
Monitoring of a Phoenix App Using AppSignal: An Example
We'll use AppSignal's function decorators to set up a custom error span that will be fired when we try to request a non-existent post.
First, we modify the posts controller to use AppSignal decorators like this:
# lib/counter_live_app_web/controllers/post_controller.ex defmodule CounterLiveAppWeb.PostController do use CounterLiveAppWeb, :controller use Appsignal.Instrumentation.Decorators # add this line ... end
Then we modify the show action with the custom instrumentation as shown below:
# lib/counter_live_app_web/controllers/post_controller.ex ... def show(conn, %{"id" => id}) do try do post = Blog.get_post!(id) render(conn, :show, post: post) rescue e in Ecto.NoResultsError -> Appsignal.send_error(e, __STACKTRACE__, fn span -> Appsignal.Span.set_name(span, "Custom Post Not Found Error") Appsignal.Span.set_sample_data(span, "custom_data", %{ post_id: id, controller: "PostController", action: "show" }) end) conn |> put_status(:not_found) |> put_view(CounterLiveAppWeb.ErrorView) |> render("404.html") end end ...
Here, we use AppSignal's send_error/3
to define a custom span with the name "Custom Post Not Found Error", which is called if we make a request to a non-existent post.
As you can see from the screenshots below, the error is captured as expected on AppSignal:
Clicking on the error link gives you access to the error details:
And that's it!
Wrapping Up
In this article, we've looked at how to set up AppSignal to monitor a Phoenix application. We also covered how errors and performance incidences are instrumented and displayed on the dashboard.
Even though this is enough to get you started with monitoring your Phoenix application, AppSignal offers a lot more options for you to explore (such as Ecto-specific monitoring to cover your app's Ecto queries, plug monitoring, and even in-depth custom instrumentation to cover almost any monitoring scenario you might have).
Until next time, happy coding!
P.S. If you'd like to read Elixir Alchemy posts as soon as they get off the press, subscribe to our Elixir Alchemy newsletter and never miss a single post!