🤷‍♀️ The easiest way to monitor your app in production is email?
Tags: email, beginners, tutorial, ruby
Published: 2021-10-19 11:37:16

It's really helpful to have a way to track what's going on with your application in production, things like: number of user sign ups, status of user accounts, number of X new database entries etc. Out of the box dashboards like [Rails Admin](https://github.com/sferik/rails_admin) are great but only go so far, eventually you will want significant customizations.

You could spend time coding a beautiful, custom dashboard to show you a summary of everything in real time. On top of coding it you'll spend time designing, testing, securing and deploying it. Plus digging into problems that pop up (what is monitoring your monitoring dashboard?). You might instead plug-in a 3rd party dashboard and query using that, which can be expensive and just as time consuming. 

**There's an easier way, which doesn't take away time from building your app or product: __email__**. Specifically through email daily digests & notifications.

Compared to building a dashboard the advantages are numerous:

- Faster to code
- Doesn't consume any resources
- Minimal DevOps required
- Very easy to extend / customize
- Reuses your existing tech stack
- Almost no maintenance
- Regular notifications (you won't forget to check the dashboard)
- Everything is timestamped and archived by default

The main disadvantage is that it's not real time/interactive. But if you spot anything that requires a detailed drill down, you'll probably want to go in and do a detailed investigation through your app anyway.

*Ultimately you should have several different tools monitoring your app to ensure things stay smooth e.g. external uptime monitors, exception trackers, log analysis, CPU/Memory usage tracking etc. This is an additional one you can add on for business logic monitoring*

## An example in Rails

To show you how easy this is, we'll create an example that sends the latest count of users every day to ourselves at the same time. You could extend this to send updates on anything tracked in your database (e.g. most popular article, unusual user behavior etc.)

Prerequisites:

- A Rails 6+ app
- A transactional email provider (e.g. Amazon SES, Postmark etc.) I recommend [OhMySMTP](https://ohmysmtp.com) and the associated Rails Gem: https://github.com/ohmysmtp/ohmysmtp-rails.

### Email setup

Add this line to your application's Gemfile:

```ruby
gem 'ohmysmtp-rails'
```

And then execute:
```bash
$ bundle
```

### Configure your API Token

Retrieve your API token for your sending domain from [OhMySMTP](https://app.ohmysmtp.com). You can find it under Organization -> Domain -> API Tokens

Open the credentials editor:

```bash
rails secret
rails credentials:edit
```

Then add your token:

```yaml
ohmysmtp_api_token: "TOKEN_GOES_HERE"
```

Finally set OhMySMTP as your mailer in `config/application.rb`:

```ruby
config.action_mailer.delivery_method = :ohmysmtp
config.action_mailer.ohmysmtp_settings = { api_token: Rails.application.credentials.ohmysmtp_api_token }
```

### Setup our email template

We'll prepare an email template to send to ourselves or our team:

```bash
rails generate mailer monitoring
```
Which will create our mailer and folders to place our email templates in. 

Modify the `app/mailers/monitoring_mailer.rb` file to include our daily notification and override our ApplicationMailer defaults:

```ruby
class MonitoringMailer < ApplicationMailer
  def daily_update
    mail(to: "your-email-address@example.com", subject: "User Count Update")
  end
end
```

When this is called ActionMailer will look for a `daily_update` template to use. So let's go ahead and create that. 

Create a file called `daily_update.html.erb` in ` app/views/monitoring_mailer` with the email contents (note the placeholder for our User Count, `count_of_users`):

```erb
<!DOCTYPE html>
<html>
  <head>
    <meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
  </head>
  <body>
    <p>Total users: <%= count_of_users %></p>
  </body>
</html>

```
Our email is ready to go, now we need to calculate the `count_of_users` variable and trigger the email regularly.

### Create a Rake Task

A rake task is basically script that can be called from another location. We'll put our simple monitoring logic and email trigger here.

> TIP: For a more complex example in Rails put your monitoring logic in a Job, and call the job from the Rake task. Jobs can be run asynchronously by Sidekiq or another queue manager and are much more easily tested

```bash
rails generate task monitor_my_app
```

This will generate a file `lib/tasks/monitor_my_app.rake` - change the contents to the following (and here is where you'll make most customizations to fit your app):

```ruby
namespace :monitor_my_app do
  task email_latest_stats: [:environment] do
     # Count number of new users
     @count_of_users = User.where("created_at > ?", 24.hours.ago).count

     ## Send the email with latest count
     MonitoringMailer.with(count_of_users: @count_of_users).daily_update.deliver_now
  end
end
```

### Test it by running our Rake task

We can call this locally with:

`rake monitor_my_app:email_latest_stats`

Or if you're using Capistrano for deployments you can run this on production:

`bundle exec cap production invoke:rake TASK=monitor_my_app:email_latest_stats`

In your development environment an email should pop up in the browser, in production you'll see it arrive in your inbox in a couple of seconds.

### Schedule it to run every day

Rake tasks can be called from Cron, so we'll use the [Whenever Gem](https://github.com/javan/whenever) to automatically add our job to our Crontab during deployment, and keep our schedule in change control. 

After setting up Whenever, add the following to your `schedule.rb` file:

```ruby
every 1.days do
  rake "monitor_my_app:email_latest_stats"
end
```

That's it, after you deploy you'll get an email every day with the total number of users in your app. You can keep extending this with more concepts and daily digest emails - much much easier than building a custom dashboard!