Skip Navigation
Show nav
Heroku Dev Center
  • Get Started
  • Documentation
  • Changelog
  • Search
  • Get Started
    • Node.js
    • Ruby on Rails
    • Ruby
    • Python
    • Java
    • PHP
    • Go
    • Scala
    • Clojure
  • Documentation
  • Changelog
  • More
    Additional Resources
    • Home
    • Elements
    • Products
    • Pricing
    • Careers
    • Help
    • Status
    • Events
    • Podcasts
    • Compliance Center
    Heroku Blog

    Heroku Blog

    Find out what's new with Heroku on our blog.

    Visit Blog
  • Log inorSign up
View categories

Categories

  • Heroku Architecture
    • Dynos (app containers)
    • Stacks (operating system images)
    • Networking & DNS
    • Platform Policies
    • Platform Principles
  • Command Line
  • Deployment
    • Deploying with Git
    • Deploying with Docker
    • Deployment Integrations
  • Continuous Delivery
    • Continuous Integration
  • Language Support
    • Node.js
    • Ruby
      • Working with Bundler
      • Rails Support
    • Python
      • Background Jobs in Python
      • Working with Django
    • Java
      • Working with Maven
      • Java Database Operations
      • Java Advanced Topics
      • Working with Spring Boot
    • PHP
    • Go
      • Go Dependency Management
    • Scala
    • Clojure
  • Databases & Data Management
    • Heroku Postgres
      • Postgres Basics
      • Postgres Getting Started
      • Postgres Performance
      • Postgres Data Transfer & Preservation
      • Postgres Availability
      • Postgres Special Topics
    • Heroku Data For Redis
    • Apache Kafka on Heroku
    • Other Data Stores
  • Monitoring & Metrics
    • Logging
  • App Performance
  • Add-ons
    • All Add-ons
  • Collaboration
  • Security
    • App Security
    • Identities & Authentication
    • Compliance
  • Heroku Enterprise
    • Private Spaces
      • Infrastructure Networking
    • Enterprise Accounts
    • Enterprise Teams
    • Heroku Connect (Salesforce sync)
      • Heroku Connect Administration
      • Heroku Connect Reference
      • Heroku Connect Troubleshooting
    • Single Sign-on (SSO)
  • Patterns & Best Practices
  • Extending Heroku
    • Platform API
    • App Webhooks
    • Heroku Labs
    • Building Add-ons
      • Add-on Development Tasks
      • Add-on APIs
      • Add-on Guidelines & Requirements
    • Building CLI Plugins
    • Developing Buildpacks
    • Dev Center
  • Accounts & Billing
  • Troubleshooting & Support
  • Integrating with Salesforce
  • Heroku Architecture
  • Networking & DNS
  • HTTP Request IDs

HTTP Request IDs

English — 日本語に切り替える

Last updated May 27, 2020

Table of Contents

  • How it works
  • Router logs
  • Usage with Rails
  • Usage with Ruby Rack middleware
  • Usage with Node.js
  • Usage with Django
  • Usage with Java
  • Usage with PHP
  • Usage with Scala
  • Usage with Clojure

HTTP request IDs let you correlate router logs for a given web request against the web dyno logs for that same request.

How it works

The Heroku router generates a unique request ID for every incoming HTTP request that it receives. This unique ID is then passed to your application as an HTTP header called X-Request-ID.

Alternately, you can specify the X-Request-ID header when making a request. The value must be between 20 and 200 characters, and consist of ASCII letters, digits, or the characters +, /, =, and -. Invalid IDs will be ignored and replaced with generated ones.

Your app code can then read this ID and log it or use it for other purposes.

Router logs

These request IDs will also also be visible in the Heroku router logs as request_id. Here’s an example:

$ heroku logs --ps router
2013-03-10T19:53:10+00:00 heroku[router]: at=info method=GET path=/ host=myapp.herokuapp.com request_id=f9ed4675f1c53513c61a3b3b4e25b4c0 fwd="215.90.1.17" dyno=web.4 connect=0ms service=61ms status=200 bytes=1382

Example: correlate H13 error against app backtrace

Scenario: your app is reporting occasional H13 errors. The router reports the dyno closed the connection; how do we find the web dyno logs associated with one of these requests? Request IDs can help here, especially on a busy app with lots of data in the logs.

Find the router log line for the H13:

2010-10-06T21:51:37-07:00 heroku[router]: at=error code=H13 desc="Connection closed without response" method=GET path=/ host=myapp.herokuapp.com request_id=30f14c6c1fc85cba12bfd093aa8f90e3 fwd="215.90.1.17" dyno=web.15 connect=3030ms service=9767ms status=503 bytes=0

Note the request ID, which is 30f14c6c1fc85cba12bfd093aa8f90e3 in this example. Now you can search your logs (using Papertrail or other log search method) for that ID and find the request, logged by the middleware shown in the previous section:

2010-10-06T21:51:37-07:00 heroku[web.15]: request_id=30f14c6c1fc85cba12bfd093aa8f90e3
2010-10-06T21:51:37-07:00 heroku[web.15]: /usr/local/heroku/vendor/gems/excon-0.14.0/lib/excon/ssl_socket.rb:74: [BUG] Segmentation fault

Here we see that this request is causing the dyno to crash due to a bug in the SSL library and/or the Ruby interpreter. Upgrading to a newer version of Ruby might help, or if not, you now have the backtrace that you can use to file a bug with.

Usage with Rails

By default, Rails 3.2 and above will pick up the X-Request-ID and set it as the requests UUID. To tie this request ID in with your application logs, add this line to your config/environments/production.rb

config.log_tags = [ :uuid ]

On Rails 5.0 and up:

config.log_tags = [ :request_id ]

The values in your logs will then be tagged with the request ID:

2014-02-07T00:58:00.978819+00:00 app[web.1]: [6a7f7b2f-889b-4ae8-b849-db1f635c971c] Started GET "/" for 99.61.71.11 at 2014-02-07 00:58:00 +0000

Here 6a7f7b2f-889b-4ae8-b849-db1f635c971c is the request ID. You can get more information on tagged logging with UUID in Rails here. Note that if there is not an available X-Request-ID, then Rails will generate a UUID for you, so if you enable this in development you will see a “request ID” even though one may not be provided in the X-Request-ID header.

Usage with Ruby Rack middleware

Here is a sample Rack module for logging the request ID.

module Rack::LogRequestID
  def initialize(app); @app = app; end

  def call(env)
    puts "request_id=#{env['HTTP_X_REQUEST_ID']}"
    @app.call(env)
  end
end

If you are using Rack without Rails, for a more comprehensive Rack middleware, we recommend the Heroku Request ID gem. Do not use this gem if you are using Rails, this gem will break Rails request logging functionality. Using the gem with Rack will provide timing information if you have Rack::Runtime enabled:

use Rack::Runtime

Usage with Node.js

If you’re using the logfmt Node module >=0.21.0, the X-Request-Id header will automatically be output to your logs on every web request as request_id.

If you prefer not to use logfmt in your Node app, be aware that Node’s core HTTP module downcases header keys, so the header will be named req.headers['x-request-id'].

Usage with Django

You can easily use all of the power of request IDs in Django with the excellent django-log-request-id library. First, you’ll need to install it by adding it to your requirements.txt file:

django-log-request-id==1.0.0

Next, you need to install the newly available Django middleware into your application’s settings.py. Make sure that it’s the first specified middleware, or it may not function properly:

MIDDLEWARE_CLASSES = (
    'log_request_id.middleware.RequestIDMiddleware',
    ...

Finally, you need to modify settings.py to configure Django to properly log outgoing requests to stdout.


# Support for X-Request-ID

LOG_REQUEST_ID_HEADER = 'HTTP_X_REQUEST_ID'
LOG_REQUESTS = True

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
        'request_id': {
            '()': 'log_request_id.filters.RequestIDFilter'
        }
    },
    'formatters': {
        'standard': {
            'format': '%(levelname)-8s [%(asctime)s] [%(request_id)s] %(name)s: %(message)s'
        },
    },
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'filters': ['request_id'],
            'formatter': 'standard',
        },
    },
    'loggers': {
        'log_request_id.middleware': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': False,
        },
    }

Usage with Java

Depending on the framework your application is using, the method of accessing and logging the request ID in Java can vary. This is a simplified example using a Java Servlet filter to access the header and print it to System.out.

RequestIdLoggingFilter.java

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

public class RequestIdLoggingFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        if (servletRequest instanceof HttpServletRequest) {
            final String requestId = ((HttpServletRequest) servletRequest).getHeader("X-Request-ID");
            if (requestId != null) {
                System.out.println("request_id=" + requestId);
            }
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {}
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">
    <filter>
      <filter-name>RequestIdLoggingFilter</filter-name>
      <filter-class>com.example.config.RequestIdLoggingFilter</filter-class>
    </filter>
    <filter-mapping>
      <filter-name>RequestIdLoggingFilter</filter-name>
      <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

Usage with PHP

Assuming you’re using the excellent Monolog package, you can simply register a custom processor that adds the contents of the X-Request-Id HTTP header to the extra fields array of the record:

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

require('vendor/autoload.php');

$logger = new Logger('my_logger');
$logger->pushHandler(new StreamHandler('php://stderr', Logger::DEBUG));

$logger->pushProcessor(function ($record) {
    $record['extra']['request_id'] = isset($_SERVER['HTTP_X_REQUEST_ID']) ? $_SERVER['HTTP_X_REQUEST_ID'] : null;
    return $record;
});

$logger->addInfo('Hello World');

The logged message will then contain the request ID in your heroku logs stream:

2014-11-19T15:10:32.027154+00:00 app[web.1]: [2014-11-19 15:10:31] my_logger.INFO: Hello World [] {"request_id":"a0a86a10-2a3a-4852-ae80-893e5d4e8348"}

For more information, check out the documentation section on Processors, or framework-specific documentation on integrating Monolog Processors using Symfony.

Usage with Scala

Depending on the framework your application is using, the method of accessing and logging the request ID in Scala can vary. This is a simplified example using a Play Framework filter to access the header and log it.

import play.api.mvc._
import play.api.Logger
import scala.concurrent.Future
import play.api.libs.concurrent.Execution.Implicits.defaultContext

object RequestIdLoggingFilter extends Filter {
  def apply(nextFilter: (RequestHeader) => Future[Result])
  (requestHeader: RequestHeader): Future[Result] = {
    Logger.info(s"request_id=${requestHeader.headers.get("X-Request-ID").getOrElse("None")}")
    nextFilter(requestHeader)
  }
}

You can use the filter by declaring a Global object.

object Global extends WithFilters(RequestIdLoggingFilter) {
  // ...
}

The logged message will then contain the request ID in your heroku logs stream:

2014-11-19T16:08:59.427428+00:00 app[web.1]: [info] application - request_id=2bcf9cec-7717-40e3-9bcf-b438b93b7770

Usage with Clojure

Depending on the framework your application is using, the method of accessing and logging the request ID in Clojure can vary. This an example using the Compojure routing library to access the header and log it.

(defroutes request-id-logger
  (ANY "*" {:keys [headers params body] :as request}
    (println (format "request_id=%s" (get headers "x-request-id")))))

As long as this route is declared before your other routes, it will be executed before the router moves on to match any other routes.

The logged message will then contain the request ID in your heroku logs stream:

2014-12-20T23:23:56.782823+00:00 app[web.1]: request_id=0e748c63-70ef-4d45-ab97-96510ddcdf5a

Keep reading

  • Networking & DNS

Feedback

Log in to submit feedback.

WebSockets on Heroku HTTP Routing

Information & Support

  • Getting Started
  • Documentation
  • Changelog
  • Compliance Center
  • Training & Education
  • Blog
  • Podcasts
  • Support Channels
  • Status

Language Reference

  • Node.js
  • Ruby
  • Java
  • PHP
  • Python
  • Go
  • Scala
  • Clojure

Other Resources

  • Careers
  • Elements
  • Products
  • Pricing

Subscribe to our monthly newsletter

Your email address:

  • RSS
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku Blog
    • Heroku News Blog
    • Heroku Engineering Blog
  • Heroku Podcasts
  • Twitter
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku
    • Heroku Status
  • Facebook
  • Instagram
  • Github
  • LinkedIn
  • YouTube
Heroku is acompany

 © Salesforce.com

  • heroku.com
  • Terms of Service
  • Privacy
  • Cookies
  • Cookie Preferences