diff --git a/ansible/roles/common/tasks/config.yml b/ansible/roles/common/tasks/config.yml
index 8800d3ee4e..01d340431d 100644
--- a/ansible/roles/common/tasks/config.yml
+++ b/ansible/roles/common/tasks/config.yml
@@ -29,3 +29,4 @@
     dest: "{{ node_config_directory }}/heka/heka-{{ item }}.toml"
   with_items:
     - "global"
+    - "haproxy"
diff --git a/ansible/roles/common/templates/heka-haproxy.toml.j2 b/ansible/roles/common/templates/heka-haproxy.toml.j2
new file mode 100644
index 0000000000..d933a6f554
--- /dev/null
+++ b/ansible/roles/common/templates/heka-haproxy.toml.j2
@@ -0,0 +1,14 @@
+# HAProxy and Keepalived write their logs to Syslog, so the generic
+# Syslog input set in heka-global.toml.j2 is used.
+
+[haproxy_file_output]
+type = "FileOutput"
+message_matcher = "Type == 'Syslog' && Fields[programname] =~ /(?i:haproxy)/"
+path = "/var/log/kolla/haproxy/haproxy.log"
+encoder = "syslog_encoder"
+
+[keepalived_file_output]
+type = "FileOutput"
+message_matcher = "Type == 'Syslog' && Fields[programname] =~ /(?i:keepalived)/"
+path = "/var/log/kolla/haproxy/keepalived.log"
+encoder = "syslog_encoder"
diff --git a/ansible/roles/common/templates/heka.json.j2 b/ansible/roles/common/templates/heka.json.j2
index ff11902393..bda52ca561 100644
--- a/ansible/roles/common/templates/heka.json.j2
+++ b/ansible/roles/common/templates/heka.json.j2
@@ -6,6 +6,12 @@
             "dest": "/etc/heka/heka-global.toml",
             "owner": "heka",
             "perm": "0600"
+        },
+        {
+            "source": "{{ container_config_directory }}/heka-haproxy.toml",
+            "dest": "/etc/heka/heka-haproxy.toml",
+            "owner": "heka",
+            "perm": "0600"
         }
     ]
 }
diff --git a/ansible/roles/haproxy/tasks/start.yml b/ansible/roles/haproxy/tasks/start.yml
index 0193350f70..352311d948 100644
--- a/ansible/roles/haproxy/tasks/start.yml
+++ b/ansible/roles/haproxy/tasks/start.yml
@@ -9,6 +9,7 @@
     volumes:
       - "{{ node_config_directory }}/haproxy/:{{ container_config_directory }}/:ro"
       - "haproxy_socket:/var/lib/kolla/haproxy/"
+      - "heka_socket:/var/lib/kolla/heka/"
 
 - name: Starting keepalived container
   kolla_docker:
@@ -21,6 +22,7 @@
       - "{{ node_config_directory }}/keepalived/:{{ container_config_directory }}/:ro"
       - "/lib/modules:/lib/modules:ro"
       - "haproxy_socket:/var/lib/kolla/haproxy/"
+      - "heka_socket:/var/lib/kolla/heka/"
 
 - name: Ensuring latest haproxy config is used
   command: docker exec haproxy /usr/local/bin/kolla_ensure_haproxy_latest_config
diff --git a/ansible/roles/haproxy/templates/haproxy.cfg.j2 b/ansible/roles/haproxy/templates/haproxy.cfg.j2
index d45682d31d..f56daa8545 100644
--- a/ansible/roles/haproxy/templates/haproxy.cfg.j2
+++ b/ansible/roles/haproxy/templates/haproxy.cfg.j2
@@ -1,11 +1,14 @@
 global
   daemon
+  log /var/lib/kolla/heka/log local0
   maxconn 4000
   stats socket /var/lib/kolla/haproxy/haproxy.sock
 
 defaults
+  log global
   mode http
   option redispatch
+  option httplog
   retries 3
   timeout http-request 10s
   timeout queue 1m
@@ -25,6 +28,7 @@ listen stats {{ hostvars[inventory_hostname]['ansible_' + api_interface]['ipv4']
 {% if enable_mariadb | bool %}
 listen mariadb
   mode tcp
+  option tcplog
   option tcpka
   option mysql-check user haproxy
   bind {{ kolla_internal_address }}:{{ mariadb_port }}
diff --git a/docker/keepalived/extend_start.sh b/docker/keepalived/extend_start.sh
index e1fe5d9d8c..18e71d1f72 100644
--- a/docker/keepalived/extend_start.sh
+++ b/docker/keepalived/extend_start.sh
@@ -1,5 +1,10 @@
 #!/bin/bash
 
+# NOTE(elemoine): keepalived cannot be configured to change the log address to
+# anything other than /dev/log. Heka's log socket is at /var/lib/kolla/heka/log
+# so we symlink /dev/log to that location.
+ln -sf /var/lib/kolla/heka/log /dev/log
+
 modprobe ip_vs
 
 # Workaround for bug #1485079