func Proxy(redispool *redis.Pool, fluent *fluent.Fluent) {
	defer redispool.Close()
	defer glog.Flush()
	glog.Info("starting proxy server...")
	glog.Infof("using ReverseProxyServer: %q, RedisControllerChannel: %q", Conf.ReverseProxyServer.String(), Conf.RedisControllerChannel)
	GoProxy.Verbose = Conf.Verbose
	onRequstCommonFunc := func(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
		id := gouuid.NewV4()
		uuid := id.Bytes()
		ctx.UserData = map[string][]byte{"uuid": uuid}
		GoProxy.Tr = &http.Transport{Dial: forward(Conf.ReverseProxyServer, GoProxy)}
		if fluent != nil {
			rq, e := httputil.DumpRequest(r, true)
			if e != nil {
				glog.Errorf("proxy: httpmessagedump: onrequest: %q", e)
				return r, nil
			}
			glog.V(5).Infof("proxy: httpmessagedump: onrequest: %q", rq)
			go dumphttpRequest(uuid, fluent, rq)
		}
		return r, nil
	}
	GoProxy.OnRequest().DoFunc(onRequstCommonFunc)
	GoProxy.OnRequest(goproxy.ReqHostMatches(regexp.MustCompile("^.*:80$"))).
		HandleConnectFunc(func(host string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) {
			return goproxy.HTTPMitmConnect, host
		})
	GoProxy.OnRequest(goproxy.ReqHostMatches(regexp.MustCompile("^.*:443$"))).
		HandleConnectFunc(func(host string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) {
			return goproxy.MitmConnect, host
		})
	GoProxy.OnResponse().DoFunc(func(r *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
		v, ok := ctx.UserData.(map[string][]byte)
		if !ok {
			glog.Error("proxy: proxy: onresponse: invalid userdata")
			return r
		}
		glog.Infof("%s => %s[%d]", Conf.ReverseProxyServer.String(), r.Request.Host, r.StatusCode)
		toatlProxyRequests.With(prometheus.Labels{"site": r.Request.Host, "statusCode": fmt.Sprintf("%d", r.StatusCode)}).Inc()
		if redispool != nil && r.StatusCode >= 400 && r.StatusCode <= 599 {
			c := redispool.Get()
			defer c.Close()
			msg := &controllerMessage{
				Site:        r.Request.Host,
				SenderProxy: Conf.ReverseProxyServer.String(),
				StatusCode:  r.StatusCode,
			}
			tmp, e := json.Marshal(*msg)
			if e != nil {
				glog.Errorf("proxy: proxy: onresponse: json marshal error: %q", e)
				return r
			}
			c.Do("PUBLISH", Conf.RedisControllerChannel, tmp)
			c.Flush()
		}
		uuid := v["uuid"]
		if fluent != nil {
			rsp, e := httputil.DumpResponse(r, true)
			if e != nil {
				glog.Errorf("proxy: httpmessagedump: onresponse: %q", e)
				return r
			}
			glog.V(5).Infof("proxy: httpmessagedump: onresponse: %q", rsp)
			go dumphttpResponse(uuid, fluent, rsp)
		}
		id, err := gouuid.FromBytes(uuid)
		if err != nil {
			glog.Error("proxy: proxy: unable to parse uuid")
			return r
		}
		r.Header.Set("X-Camouflage-Context", id.String())
		return r
	})
	serverMuxA := http.NewServeMux()
	serverMuxA.Handle("/", promhttp.Handler())
	go func() {
		glog.Info("starting proxy metric server...")
		glog.Error(http.ListenAndServe(fmt.Sprintf(":%d", Conf.MetricPort), serverMuxA))
	}()
	glog.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", Conf.ProxyPort), GoProxy))
}
Impletments proxy functionality.
If fluent is nil, then doesn't dump http request and response.
If redispool is nil, then doesn't publish on redis Channel for bad status.
It adds a uuid to request, to bind it to corresponding response and send it to client as a header on response.
package proxy
import (
	"bufio"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"regexp"
	"strings"
	"github.com/elazarl/goproxy"
	"github.com/fluent/fluent-logger-golang/fluent"
	"github.com/garyburd/redigo/redis"
	"github.com/golang/glog"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	gouuid "github.com/satori/go.uuid"
)
type Config struct {
	RedisControllerChannel string
	ReverseProxyServer url.URL
	ProxyPort int
	MetricPort int
	Verbose bool
	DumpInWireFormat bool
}
type controllerMessage struct {
	Site        string
	SenderProxy string
	StatusCode  int
}
var (
	GoProxy = goproxy.NewProxyHttpServer()
	Conf = new(Config)
	toatlProxyRequests = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Name: "proxy_requests_total",
			Help: "Total Number of Request per Response StatusCode and site.",
		},
		[]string{"site", "statusCode"},
	)
)
func init() {
	prometheus.MustRegister(toatlProxyRequests)
}