Last updated February 16, 2022
Table of Contents
A Heroku app’s logs come from the output streams of all of its running processes, system components, and backing services. Heroku’s Logplex routes log streams from all sources into a single channel, providing a foundation for comprehensive logging.
Private Space Logging in Shield Spaces doesn’t use Logplex. See Private Space Logging for more info.
Heroku aggregates the following categories of logs for a deployed app:
- App logs - Logging output from the application itself, including logs generated by your app’s code and dependencies. (Filter:
- System logs - Messages about actions taken by the Heroku platform infrastructure on behalf of your app, such as: restarting a crashed process, sleeping or waking a web dyno, or serving an error page due to a problem in your app. (Filter:
- API logs - Messages about administrative actions taken by you and other developers working on your app, such as: deploying new code, scaling the process formation, or toggling maintenance mode. (Filter:
--source app --dyno api)
- Add-on logs - Messages from add-on services. See the add-on’s Dev Center article for details. (Filter varies by add-on)
The logs generated while building and deploying your app are separate from the app’s runtime logs. Logs for both successful and unsuccessful builds are available from your app’s
Activity tab in the Heroku Dashboard:
View build log for any build event in the Activity Feed to see its logs:
Log History Limits
Logplex is designed for collating and routing log messages, not for storage. It retains the most recent 1,500 lines of your consolidated logs, which expire after 1 week.
For more production-ready persistence of logs, add one of the Heroku platform’s available logging add-ons to your app. Most of these add-ons offer a free plan to get started.
Alternatively, implement your own log drains for full control over what happens to your logs.
Writing to Your Log
Your logs capture anything your app writes to standard out (
stdout) or standard error (
stderr). You can log from anywhere in your application code with a simple output statement.
In Ruby, you could use something like:
puts "Hello, logs!"
System.err.println("Hello, logs!"); System.out.println("Hello, logs!");
The same holds true for all other languages supported by Heroku.
To take advantage of real-time logging, disable any log buffering your application performs. For example, in Ruby, add the following code to your
$stdout.sync = true
Some frameworks send log output somewhere other than
stdout by default and require extra configuration. For example, when using the Ruby on Rails TaggedLogger by ActiveSupport, add the following into your app’s configuration to get
config.logger = Logger.new(STDOUT)
See Writing Best Practices For Application Logs for more info.
You can’t view logs for apps in Shield spaces with Private Space Logging enabled. Retrieve logs from your log drain instead.
View Logs with the Heroku CLI
To fetch your app’s most recent logs, use the
heroku logs command:
$ heroku logs 2010-09-16T15:13:46.677020+00:00 app[web.1]: Processing PostController#list (for 126.96.36.199 at 2010-09-16 15:13:46) [GET] 2010-09-16T15:13:46.677023+00:00 app[web.1]: Rendering template within layouts/application 2010-09-16T15:13:46.677902+00:00 app[web.1]: Rendering post/list 2010-09-16T15:13:46.678990+00:00 app[web.1]: Rendered includes/_header (0.1ms) 2010-09-16T15:13:46.698234+00:00 app[web.1]: Completed in 74ms (View: 31, DB: 40) | 200 OK [http://myapp.heroku.com/] 2010-09-16T15:13:46.723498+00:00 heroku[router]: at=info method=GET path="/posts" host=myapp.herokuapp.com" fwd="188.8.131.52" dyno=web.1 connect=1ms service=18ms status=200 bytes=975 2010-09-16T15:13:47.893472+00:00 app[worker.1]: 2 jobs processed at 16.6761 j/s, 0 failed ...
In this example, the output includes log lines from one of the app’s web dynos, the Heroku HTTP router, and one of the app’s workers. See Heroku’s Log Format and Message Ordering for more info.
logs command retrieves 100 log lines by default. You can specify the number of log lines to retrieve (up to a maximum of 1,500 lines) by using the
$ heroku logs -n 200
tail -f, real-time tail displays recent logs and leaves the session open for real-time logs to stream in. By viewing a live stream of logs from your app, you can gain insight into the behavior of your live application and debug current problems.
You can tail your logs using
$ heroku logs --tail
When you’re done, press Ctrl+C to return to the prompt.
A real-time tail session automatically terminates after one hour of inactivity.
If you only want to fetch logs with a certain source, a certain dyno, or both, you can use the
-d) filtering arguments:
$ heroku logs --dyno router 2012-02-07T09:43:06.123456+00:00 heroku[router]: at=info method=GET path="/stylesheets/dev-center/library.css" host=devcenter.heroku.com fwd="184.108.40.206" dyno=web.5 connect=1ms service=18ms status=200 bytes=13 2012-02-07T09:43:06.123456+00:00 heroku[router]: at=info method=GET path="/articles/bundler" host=devcenter.heroku.com fwd="220.127.116.11" dyno=web.6 connect=1ms service=18ms status=200 bytes=20375 $ heroku logs --source app 2012-02-07T09:45:47.123456+00:00 app[web.1]: Rendered shared/_search.html.erb (1.0ms) 2012-02-07T09:45:47.123456+00:00 app[web.1]: Completed 200 OK in 83ms (Views: 48.7ms | ActiveRecord: 32.2ms) 2012-02-07T09:45:47.123456+00:00 app[worker.1]: [Worker(host:465cf64e-61c8-46d3-b480-362bfd4ecff9 pid:1)] 1 jobs processed at 23.0330 j/s, 0 failed ... 2012-02-07T09:46:01.123456+00:00 app[web.6]: Started GET "/articles/buildpacks" for 18.104.22.168 at 2012-02-07 09:46:01 +0000 $ heroku logs --source app --dyno worker 2012-02-07T09:47:59.123456+00:00 app[worker.1]: [Worker(host:260cf64e-61c8-46d3-b480-362bfd4ecff9 pid:1)] Article#record_view_without_delay completed after 0.0221 2012-02-07T09:47:59.123456+00:00 app[worker.1]: [Worker(host:260cf64e-61c8-46d3-b480-362bfd4ecff9 pid:1)] 5 jobs processed at 31.6842 j/s, 0 failed ...
When filtering by dyno, you can use either the base name (like
--dyno web) or the full name ( like
You can also combine the filtering switches with
--tail to get a real-time stream of filtered output.
$ heroku logs --source app --tail
View Logs with the Heroku Dashboard
You can view your logs on the web by logging into your Heroku dashboard. Navigate to the app you want to see, for example,
https://dashboard.heroku.com/apps/<app-name>. On this page, select “more” tosee a drop-down menu:
From this menu, select
View logs. See Heroku’s Log Format and Message Ordering for more info.
View Logs with a Logging Add-on
It’s recommended to add one of the Heroku platform’s available logging add-ons to your app. Most of these add-ons offer a free plan to get started. See your add-on’s documentation for instructions on retrieving logs.
Alternatively, you can implement a custom log drain.
Heroku’s Log Format and Message Ordering
Heroku’s Logplex router collates and distributes the log entries generated by your app and other components of the platform.
Private Space Logging in Shield Spaces doesn’t use Logplex. See Private Space Logging for its log format.
Logs aren’t in chronological order. Logs originate from many sources and Logplex assembles them into a single log stream. Logplex itself uses a distributed architecture to ensure high availability, so log messages can also be out of order as they collect across multiple Logplex nodes.
The output format of the
heroku logs command is as follows:
timestamp source[dyno]: message
- Timestamp - The date and time recorded at the time the dyno or component produced the log line. The timestamp is in the format specified by RFC5424, and includes microsecond precision.
- Source - All of your app’s dynos (web dynos, background workers, cron) have the source,
app. All of Heroku’s system components (HTTP router, dyno manager) have the source,
- Dyno - The name of the dyno or component that wrote the log line. For example, worker #3 appears as
worker.3, and the Heroku HTTP router appears as
- Message - The content of the log line. Logplex splits any lines generated by dynos that exceed 10,000 bytes into 10,000-byte chunks without extra trailing newlines. It submits each chunk is submitted as a separate log line.