diff --git a/gateway/handlers/forwarding_proxy.go b/gateway/handlers/forwarding_proxy.go
new file mode 100644
index 0000000000000000000000000000000000000000..322d7a42e9b53d1f0c1eaaa8d90bc95dccdec648
--- /dev/null
+++ b/gateway/handlers/forwarding_proxy.go
@@ -0,0 +1,49 @@
+package handlers
+
+import (
+	"log"
+	"net/http"
+	"net/http/httputil"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/alexellis/faas/gateway/metrics"
+	"github.com/alexellis/faas/gateway/types"
+	"github.com/prometheus/client_golang/prometheus"
+)
+
+// MakeForwardingProxyHandler create a handler which forwards HTTP requests
+func MakeForwardingProxyHandler(proxy *httputil.ReverseProxy, metrics *metrics.MetricOptions) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		uri := r.URL.String()
+
+		log.Printf("> Forwarding [%s] to %s", r.Method, r.URL.String())
+		start := time.Now()
+
+		writeAdapter := types.NewWriteAdapter(w)
+		proxy.ServeHTTP(writeAdapter, r)
+
+		seconds := time.Since(start).Seconds()
+		log.Printf("< [%s] - %d took %f seconds\n", r.URL.String(), writeAdapter.GetHeaderCode(), seconds)
+
+		forward := "/function/"
+		if startsWith(uri, forward) {
+			log.Printf("function=%s", uri[len(forward):])
+
+			service := uri[len(forward):]
+
+			metrics.GatewayFunctionsHistogram.
+				WithLabelValues(service).
+				Observe(seconds)
+
+			code := strconv.Itoa(writeAdapter.GetHeaderCode())
+
+			metrics.GatewayFunctionInvocation.With(prometheus.Labels{"function_name": service, "code": code}).Inc()
+		}
+	}
+}
+
+func startsWith(value, token string) bool {
+	return len(value) > len(token) && strings.Index(value, token) == 0
+}
diff --git a/gateway/server.go b/gateway/server.go
index 0373d63a0a31b97d008ce6c4eb4a48126d46859b..b6e183b1ef77381a77864cc6269994fe203ae812 100644
--- a/gateway/server.go
+++ b/gateway/server.go
@@ -8,8 +8,6 @@ import (
 	"log"
 	"net/http"
 	"net/http/httputil"
-	"strconv"
-	"strings"
 	"time"
 
 	"fmt"
@@ -21,7 +19,6 @@ import (
 	"github.com/alexellis/faas/gateway/plugin"
 	"github.com/alexellis/faas/gateway/types"
 	"github.com/docker/docker/client"
-	"github.com/prometheus/client_golang/prometheus"
 
 	"github.com/gorilla/mux"
 )
@@ -78,14 +75,13 @@ func main() {
 
 		reverseProxy := httputil.NewSingleHostReverseProxy(config.FunctionsProviderURL)
 
-		faasHandlers.Proxy = makeHandler(reverseProxy, &metricsOptions)
-		faasHandlers.RoutelessProxy = makeHandler(reverseProxy, &metricsOptions)
-
-		faasHandlers.Alert = internalHandlers.MakeAlertHandler(plugin.NewExternalServiceQuery(*config.FunctionsProviderURL))
-
-		faasHandlers.ListFunctions = makeHandler(reverseProxy, &metricsOptions)
-		faasHandlers.DeployFunction = makeHandler(reverseProxy, &metricsOptions)
-		faasHandlers.DeleteFunction = makeHandler(reverseProxy, &metricsOptions)
+		faasHandlers.Proxy = internalHandlers.MakeForwardingProxyHandler(reverseProxy, &metricsOptions)
+		faasHandlers.RoutelessProxy = internalHandlers.MakeForwardingProxyHandler(reverseProxy, &metricsOptions)
+		faasHandlers.ListFunctions = internalHandlers.MakeForwardingProxyHandler(reverseProxy, &metricsOptions)
+		faasHandlers.DeployFunction = internalHandlers.MakeForwardingProxyHandler(reverseProxy, &metricsOptions)
+		faasHandlers.DeleteFunction = internalHandlers.MakeForwardingProxyHandler(reverseProxy, &metricsOptions)
+		alertHandler := plugin.NewExternalServiceQuery(*config.FunctionsProviderURL)
+		faasHandlers.Alert = internalHandlers.MakeAlertHandler(alertHandler)
 
 		metrics.AttachExternalWatcher(*config.FunctionsProviderURL, metricsOptions, "func", time.Second*5)
 
@@ -94,10 +90,12 @@ func main() {
 
 		faasHandlers.Proxy = internalHandlers.MakeProxy(metricsOptions, true, dockerClient, &logger)
 		faasHandlers.RoutelessProxy = internalHandlers.MakeProxy(metricsOptions, true, dockerClient, &logger)
-		faasHandlers.Alert = internalHandlers.MakeAlertHandler(internalHandlers.NewSwarmServiceQuery(dockerClient))
 		faasHandlers.ListFunctions = internalHandlers.MakeFunctionReader(metricsOptions, dockerClient)
 		faasHandlers.DeployFunction = internalHandlers.MakeNewFunctionHandler(metricsOptions, dockerClient, maxRestarts)
 		faasHandlers.DeleteFunction = internalHandlers.MakeDeleteFunctionHandler(metricsOptions, dockerClient)
+
+		faasHandlers.Alert = internalHandlers.MakeAlertHandler(internalHandlers.NewSwarmServiceQuery(dockerClient))
+
 		// This could exist in a separate process - records the replicas of each swarm service.
 		functionLabel := "function"
 		metrics.AttachSwarmWatcher(dockerClient, metricsOptions, functionLabel)
@@ -155,27 +153,3 @@ func main() {
 
 	log.Fatal(s.ListenAndServe())
 }
-
-func makeHandler(proxy *httputil.ReverseProxy, metrics *metrics.MetricOptions) http.HandlerFunc {
-	return func(w http.ResponseWriter, r *http.Request) {
-		uri := r.URL.String()
-
-		log.Printf("Forwarding [%s] to %s", r.Method, r.URL.String())
-		start := time.Now()
-
-		writeAdapter := types.NewWriteAdapter(w)
-		proxy.ServeHTTP(writeAdapter, r)
-
-		seconds := time.Since(start).Seconds()
-		fmt.Printf("[%d] took %f seconds\n", writeAdapter.GetHeaderCode(), seconds)
-
-		forward := "/function/"
-		if len(uri) > len(forward) && strings.Index(uri, forward) == 0 {
-			fmt.Println("function=", uri[len(forward):])
-			service := uri[len(forward):]
-			metrics.GatewayFunctionsHistogram.WithLabelValues(service).Observe(seconds)
-			code := writeAdapter.GetHeaderCode()
-			metrics.GatewayFunctionInvocation.With(prometheus.Labels{"function_name": service, "code": strconv.Itoa(code)}).Inc()
-		}
-	}
-}