Heroku is a PaaS for running web applications. Here we will introduce and talk about how to monitor applications on Heroku using Mackerel.
Monitoring Dyno
Heroku automatically increases and decreases hosts (Dyno), so we’ll use the configurations in Using Mackerel in Auto Scaling environments in arrangement with Heroku.
With the Procfile which launches your application in Heroku, we will make it so that the shell script start.sh is launched, and do a variety of configurations in start.sh.
Please fill in <API-KEY> , <SERVICE>, and <ROLE> in start.sh appropriately.
Replace <RUN-APP> with the command to launch your application (for example, node index.js if node.js, etc.).
- Procfile
web: ./start.sh
- start.sh
#!/bin/sh set -x # install mackerel-agent mackerel_agent=/app/mackerel-agent/mackerel-agent mackerel_agent_conf=/app/mackerel-agent/mackerel-agent.conf cd /app/ && \ curl -O http://file.mackerel.io/agent/tgz/mackerel-agent-latest.tar.gz && \ tar xvfz mackerel-agent-latest.tar.gz sh << SCRIPT cat > $mackerel_agent_conf <<'EOF'; pidfile = "/app/mackerel-agent/mackerel-agent.pid" root = "/app/mackerel-agent" apikey = "<API-KEY>" roles = [ "<SERVICE>:<ROLE>" ] EOF SCRIPT trap "$mackerel_agent retire -conf $mackerel_agent_conf -force" TERM $mackerel_agent -conf $mackerel_agent_conf -v & <RUN-APP>
Posting service metrics
In Heroku, it’s possible to get a variety of logs including the access log by using Log Drains.
Here we will talk about how to calculate response time and error rate from the Rails log on Heroku, and how to post them to Mackerel’s service metrics.
Please also refer to the official guide Getting Started with Rails 4.x on Heroku.
Outputting JSON format logs with Rails
We will use lograge.
# Gemfile gem 'lograge'
# config/application.rb
module Testapp
class Application < Rails::Application
...
config.log_level = :info
config.lograge.enabled = true
config.lograge.formatter = Lograge::Formatters::Json.new
...
end
end
Configuring rsyslog
Next we will prepare the host that will run rsyslog and fluentd. First we’ll configure rsyslog. We will receive the log from Heroku on port 5140, so please open port 5140 in your firewall settings.
# /etc/rsyslog.conf $ModLoad imtcp $InputTCPServerRun 5140
Setting up Heroku Drains
Replace <IPADDR> with the IP address of the host that will run rsyslog and fluentd.
# heroku drains:add syslog://<IPADDR>:5140 Successfully added drain syslog://<IPADDR>:5140
Configuring fluentd
First we will install td-agent. Please follow the instructions in the official guide.
Next we will install the necessary plugins.
# /usr/sbin/td-agent-gem install fluent-plugin-mackerel fluent-plugin-numeric-monitor fluent-plugin-datacounter
We will append the following in the settings file for td-agent. Replace <API-KEY> with the API key and <APP> with the name of the service it will be posted in.
Refer to Posting Service Metrics with fluentd for how to use the fluent-plugin-mackerel which is used in the second half of the settings file below.
# /etc/td-agent/td-agent.conf
<source>
@type tail
path /var/log/heroku
pos_file /var/log/td-agent/posfile_heroku.pos
format /^(?<time>[^ ]*\s+[^ ]*\s+[^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[a-zA-Z0-9\.]+)\])? *(?<message>.*)$/
time_format %b %d %H:%M:%S
tag heroku.syslog
</source>
<match heroku.syslog>
@type rewrite_tag_filter
rewriterule1 message ^{" raw.heroku.access_log
</match>
<match raw.heroku.access_log>
@type parser
remove_prefix raw
key_name message
format json
reserve_data true
</match>
<match heroku.access_log>
@type copy
<store>
@type numeric_monitor
count_interval 60s
monitor_key duration
output_per_tag yes
percentiles 90,99
tag_prefix aggregated
input_tag_remove_prefix heroku
</store>
<store>
@type datacounter
count_interval 60s
count_key status
output_per_tag yes
pattern1 2xx ^2\d\d$
pattern2 3xx ^3\d\d$
pattern3 4xx ^4\d\d$
pattern4 5xx ^5\d\d$
outcast_unmatched yes
tag_prefix status_aggregated
input_tag_remove_prefix heroku
</store>
</match>
<match status_aggregated.access_log>
@type copy
<store>
@type rewrite_tag_filter
capitalize_regex_backreference yes
rewriterule1 2xx_count .+ status_count.access_log
rewriterule2 3xx_count .+ status_count.access_log
rewriterule3 4xx_count .+ status_count.access_log
rewriterule4 5xx_count .+ status_count.access_log
</store>
<store>
@type rewrite_tag_filter
capitalize_regex_backreference yes
rewriterule3 4xx_percentage .+ error_status_percentage.access_log
rewriterule4 5xx_percentage .+ error_status_percentage.access_log
</store>
</match>
<match status_count.access_log>
@type mackerel
flush_interval 60s
api_key <API-KEY>
out_keys 2xx_count,3xx_count,4xx_count,5xx_count
remove_prefix
service <APP>
metrics_name access_num.${out_key}
</match>
<match aggregated.access_log>
@type mackerel
flush_interval 60s
api_key <API-KEY>
out_keys avg,percentile_90,percentile_99
remove_prefix
service <APP>
metrics_name access_latency.${out_key}
</match>
<match error_status_percentage.access_log>
@type mackerel
flush_interval 60s
api_key <API-KEY>
out_keys 4xx_percentage,5xx_percentage
remove_prefix
service <APP>
metrics_name error_access_rate.${out_key}
</match>
Adding service metric monitoring rules
Finally, let’s add monitoring rules for each of the response time and error rate service metrics we’ve configured.
For specific instructions please refer to Setting up monitoring and alerts and Using the mkr CLI tool.

