mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-23 02:51:55 +00:00
Merge pull request #66 from djs55/docker-proxy-ports
Add custom docker-proxy which understands host port forwarding
This commit is contained in:
commit
1956a5485a
@ -26,6 +26,7 @@ COPY kernel/kernel-source-info /etc/
|
|||||||
|
|
||||||
COPY packages/9pudc/9pudc /sbin/
|
COPY packages/9pudc/9pudc /sbin/
|
||||||
COPY packages/9pudc/etc /etc/
|
COPY packages/9pudc/etc /etc/
|
||||||
|
COPY packages/proxy/proxy /sbin/
|
||||||
COPY packages/transfused/transfused /sbin/
|
COPY packages/transfused/transfused /sbin/
|
||||||
COPY packages/transfused/etc /etc/
|
COPY packages/transfused/etc /etc/
|
||||||
COPY packages/mdnstool/mdnstool /sbin/
|
COPY packages/mdnstool/mdnstool /sbin/
|
||||||
|
@ -24,6 +24,10 @@ start()
|
|||||||
"db")
|
"db")
|
||||||
mkdir -p /Database
|
mkdir -p /Database
|
||||||
mount -t 9p -o trans=virtio,dfltuid=1001,dfltgid=50,version=9p2000 db /Database
|
mount -t 9p -o trans=virtio,dfltuid=1001,dfltgid=50,version=9p2000 db /Database
|
||||||
|
;;
|
||||||
|
"port")
|
||||||
|
mkdir -p /port
|
||||||
|
mount -t 9p -o trans=virtio,dfltuid=1001,dfltgid=50,version=9p2000 port /port
|
||||||
esac
|
esac
|
||||||
|
|
||||||
done
|
done
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
all:
|
all:
|
||||||
$(MAKE) -C 9pudc OS=linux
|
$(MAKE) -C 9pudc OS=linux
|
||||||
|
$(MAKE) -C proxy OS=linux
|
||||||
$(MAKE) -C transfused OS=linux
|
$(MAKE) -C transfused OS=linux
|
||||||
$(MAKE) -C mdnstool OS=linux
|
$(MAKE) -C mdnstool OS=linux
|
||||||
$(MAKE) -C hupper OS=linux
|
$(MAKE) -C hupper OS=linux
|
||||||
@ -8,6 +9,7 @@ all:
|
|||||||
|
|
||||||
arm:
|
arm:
|
||||||
$(MAKE) -C 9pudc OS=linux ARCH=arm
|
$(MAKE) -C 9pudc OS=linux ARCH=arm
|
||||||
|
$(MAKE) -C proxy OS=linux ARCH=arm
|
||||||
$(MAKE) -C transfused OS=linux ARCH=arm
|
$(MAKE) -C transfused OS=linux ARCH=arm
|
||||||
$(MAKE) -C mdnstool OS=linux ARCH=arm
|
$(MAKE) -C mdnstool OS=linux ARCH=arm
|
||||||
$(MAKE) -C hupper OS=linux ARCH=arm
|
$(MAKE) -C hupper OS=linux ARCH=arm
|
||||||
@ -15,6 +17,7 @@ arm:
|
|||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(MAKE) -C 9pudc clean
|
$(MAKE) -C 9pudc clean
|
||||||
|
$(MAKE) -C proxy clean
|
||||||
$(MAKE) -C transfused clean
|
$(MAKE) -C transfused clean
|
||||||
$(MAKE) -C mdnstool clean
|
$(MAKE) -C mdnstool clean
|
||||||
$(MAKE) -C docker clean
|
$(MAKE) -C docker clean
|
||||||
|
1
alpine/packages/docker/.gitignore
vendored
1
alpine/packages/docker/.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
bin/
|
bin/
|
||||||
|
docker.git
|
||||||
|
@ -1,14 +1,24 @@
|
|||||||
all: docker
|
|
||||||
|
|
||||||
DOCKER_VERSION=1.11.0-rc3
|
DOCKER_VERSION=1.11.0-rc3
|
||||||
ARCH?=x86_64
|
ARCH?=x86_64
|
||||||
OS?=Linux
|
OS?=Linux
|
||||||
|
|
||||||
DOCKER_HOST=$(shell if echo "$(DOCKER_VERSION)" | grep -q -- '-rc'; then echo "test.docker.com"; else echo "get.docker.com"; fi)
|
all: bin
|
||||||
docker:
|
|
||||||
|
bin: docker.git
|
||||||
|
(cd docker.git && git fetch origin --tags)
|
||||||
|
cd docker.git && \
|
||||||
|
git checkout v${DOCKER_VERSION} && \
|
||||||
|
git branch -D v${DOCKER_VERSION}-patched; \
|
||||||
|
git checkout -b v${DOCKER_VERSION}-patched && \
|
||||||
|
(for i in $(shell ls -1 patches); do patch -p1 < ../patches/$${i}; git commit -a -s -m "applied $${i}"; done)
|
||||||
|
BIND_DIR=$(shell pwd) make -C docker.git binary
|
||||||
mkdir -p bin
|
mkdir -p bin
|
||||||
if [ "${ARCH}" != "arm" ] ; then curl -f -L -o docker.tgz https://${DOCKER_HOST}/builds/${OS}/${ARCH}/docker-${DOCKER_VERSION}.tgz && tar xzf docker.tgz && mv docker/* bin && rm -rf docker/ docker.tgz; else cp docker-arm bin/docker; fi
|
cp docker.git/bundles/${DOCKER_VERSION}/binary/* bin/
|
||||||
chmod +x bin/*
|
rm -f bin/*.md5
|
||||||
|
rm -f bin/*.sha256
|
||||||
|
|
||||||
|
docker.git:
|
||||||
|
git clone git://github.com/docker/docker.git docker.git
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf bin
|
rm -rf bin
|
||||||
|
@ -41,8 +41,14 @@ start()
|
|||||||
if cat /proc/cmdline | grep -q 'com.docker.database'
|
if cat /proc/cmdline | grep -q 'com.docker.database'
|
||||||
then
|
then
|
||||||
DATABASE="$(cat /proc/cmdline | sed -e 's/.*com.docker.database="//' -e 's/".*//')"
|
DATABASE="$(cat /proc/cmdline | sed -e 's/.*com.docker.database="//' -e 's/".*//')"
|
||||||
CONFIG_FILE="/Database/branch/master/ro/${DATABASE}/etc/docker/daemon.json"
|
MASTER_RO="/Database/branch/master/ro"
|
||||||
|
CONFIG_FILE="${MASTER_RO}/${DATABASE}/etc/docker/daemon.json"
|
||||||
[ -s ${CONFIG_FILE} ] && DOCKER_OPTS="${DOCKER_OPTS} --config-file ${CONFIG_FILE}"
|
[ -s ${CONFIG_FILE} ] && DOCKER_OPTS="${DOCKER_OPTS} --config-file ${CONFIG_FILE}"
|
||||||
|
NETWORK_MODE="$(cat ${MASTER_RO}/${DATABASE}/network | tr -d '[[:space:]]')"
|
||||||
|
NATIVE_PORT_FORWARDING="$(cat ${MASTER_RO}/${DATABASE}/native/port-forwarding | tr -d '[[:space:]]')"
|
||||||
|
if [ "${NETWORK_MODE}" = "slirp" -o "${NATIVE_PORT_FORWARDING}" = "true" ]; then
|
||||||
|
DOCKER_OPTS="${DOCKER_OPTS} --userland-proxy-bin /sbin/proxy"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for d in Users Volumes tmp private
|
for d in Users Volumes tmp private
|
||||||
|
@ -0,0 +1,207 @@
|
|||||||
|
commit dfb1652b51a083ef3285977b4c42ec113480c67b
|
||||||
|
Author: David Scott <dave@recoil.org>
|
||||||
|
Date: Sun Apr 3 10:39:34 2016 +0100
|
||||||
|
|
||||||
|
Add a command-line argument --userland-proxy-bin=""
|
||||||
|
|
||||||
|
We will use to prototype a "ports plugin" mechanism which will
|
||||||
|
ultimately be able to expose container ports on other machines,
|
||||||
|
via other protocols e.g.
|
||||||
|
|
||||||
|
- as a channel multiplexed within an ssh connection
|
||||||
|
- as a TCP port exposed on a host running a VM running docker
|
||||||
|
|
||||||
|
The new --userland-proxy-bin argument is only inspected if
|
||||||
|
--userland-proxy=true.
|
||||||
|
|
||||||
|
If --userland-proxy-bin="" (the default) then the existing built-in
|
||||||
|
docker-proxy will be used.
|
||||||
|
|
||||||
|
If --userland-proxy-bin<>"" then the named program will be run instead.
|
||||||
|
|
||||||
|
Signed-off-by: David Scott <dave.scott@docker.com>
|
||||||
|
|
||||||
|
diff --git a/daemon/config_unix.go b/daemon/config_unix.go
|
||||||
|
index 5394949..ce10498 100644
|
||||||
|
--- a/daemon/config_unix.go
|
||||||
|
+++ b/daemon/config_unix.go
|
||||||
|
@@ -42,6 +42,7 @@ type bridgeConfig struct {
|
||||||
|
EnableIPForward bool `json:"ip-forward,omitempty"`
|
||||||
|
EnableIPMasq bool `json:"ip-mask,omitempty"`
|
||||||
|
EnableUserlandProxy bool `json:"userland-proxy,omitempty"`
|
||||||
|
+ UserlandProxyBin string `json:"userland-proxy-bin,omitempty"`
|
||||||
|
DefaultIP net.IP `json:"ip,omitempty"`
|
||||||
|
Iface string `json:"bridge,omitempty"`
|
||||||
|
IP string `json:"bip,omitempty"`
|
||||||
|
@@ -78,6 +79,7 @@ func (config *Config) InstallFlags(cmd *flag.FlagSet, usageFn func(string) strin
|
||||||
|
cmd.BoolVar(&config.bridgeConfig.InterContainerCommunication, []string{"#icc", "-icc"}, true, usageFn("Enable inter-container communication"))
|
||||||
|
cmd.Var(opts.NewIPOpt(&config.bridgeConfig.DefaultIP, "0.0.0.0"), []string{"#ip", "-ip"}, usageFn("Default IP when binding container ports"))
|
||||||
|
cmd.BoolVar(&config.bridgeConfig.EnableUserlandProxy, []string{"-userland-proxy"}, true, usageFn("Use userland proxy for loopback traffic"))
|
||||||
|
+ cmd.StringVar(&config.bridgeConfig.UserlandProxyBin, []string{"-userland-proxy-bin"}, "", usageFn("Use specific userland proxy binary if in userland proxy mode"))
|
||||||
|
cmd.BoolVar(&config.EnableCors, []string{"#api-enable-cors", "#-api-enable-cors"}, false, usageFn("Enable CORS headers in the remote API, this is deprecated by --api-cors-header"))
|
||||||
|
cmd.StringVar(&config.CorsHeaders, []string{"-api-cors-header"}, "", usageFn("Set CORS headers in the remote API"))
|
||||||
|
cmd.StringVar(&config.CgroupParent, []string{"-cgroup-parent"}, "", usageFn("Set parent cgroup for all containers"))
|
||||||
|
diff --git a/daemon/daemon_unix.go b/daemon/daemon_unix.go
|
||||||
|
index a152fd0..2ed48e1 100644
|
||||||
|
--- a/daemon/daemon_unix.go
|
||||||
|
+++ b/daemon/daemon_unix.go
|
||||||
|
@@ -651,7 +651,8 @@ func driverOptions(config *Config) []nwconfig.Option {
|
||||||
|
bridgeConfig := options.Generic{
|
||||||
|
"EnableIPForwarding": config.bridgeConfig.EnableIPForward,
|
||||||
|
"EnableIPTables": config.bridgeConfig.EnableIPTables,
|
||||||
|
- "EnableUserlandProxy": config.bridgeConfig.EnableUserlandProxy}
|
||||||
|
+ "EnableUserlandProxy": config.bridgeConfig.EnableUserlandProxy,
|
||||||
|
+ "UserlandProxyBin": config.bridgeConfig.UserlandProxyBin}
|
||||||
|
bridgeOption := options.Generic{netlabel.GenericData: bridgeConfig}
|
||||||
|
|
||||||
|
dOptions := []nwconfig.Option{}
|
||||||
|
diff --git a/docs/reference/commandline/daemon.md b/docs/reference/commandline/daemon.md
|
||||||
|
index 5ca0024..61cd369 100644
|
||||||
|
--- a/docs/reference/commandline/daemon.md
|
||||||
|
+++ b/docs/reference/commandline/daemon.md
|
||||||
|
@@ -67,6 +67,7 @@ weight = -1
|
||||||
|
--tlsverify Use TLS and verify the remote
|
||||||
|
--userns-remap="default" Enable user namespace remapping
|
||||||
|
--userland-proxy=true Use userland proxy for loopback traffic
|
||||||
|
+ --userland-proxy-bin="" Use this userland proxy binary, if userland-proxy is set
|
||||||
|
|
||||||
|
Options with [] may be specified multiple times.
|
||||||
|
|
||||||
|
diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go
|
||||||
|
index 00e16e1..16ad81d 100644
|
||||||
|
--- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go
|
||||||
|
+++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go
|
||||||
|
@@ -50,6 +50,7 @@ type configuration struct {
|
||||||
|
EnableIPForwarding bool
|
||||||
|
EnableIPTables bool
|
||||||
|
EnableUserlandProxy bool
|
||||||
|
+ UserlandProxyBin string
|
||||||
|
}
|
||||||
|
|
||||||
|
// networkConfiguration for network specific configuration
|
||||||
|
@@ -1211,7 +1212,7 @@ func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Program any required port mapping and store them in the endpoint
|
||||||
|
- endpoint.portMapping, err = network.allocatePorts(endpoint, network.config.DefaultBindingIP, d.config.EnableUserlandProxy)
|
||||||
|
+ endpoint.portMapping, err = network.allocatePorts(endpoint, network.config.DefaultBindingIP, d.config.EnableUserlandProxy, d.config.UserlandProxyBin)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/port_mapping.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/port_mapping.go
|
||||||
|
index 965cc9a..1824f46 100644
|
||||||
|
--- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/port_mapping.go
|
||||||
|
+++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/port_mapping.go
|
||||||
|
@@ -14,7 +14,7 @@ var (
|
||||||
|
defaultBindingIP = net.IPv4(0, 0, 0, 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
-func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
|
||||||
|
+func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, reqDefBindIP net.IP, ulPxyEnabled bool, pxyBin string) ([]types.PortBinding, error) {
|
||||||
|
if ep.extConnConfig == nil || ep.extConnConfig.PortBindings == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
@@ -24,14 +24,14 @@ func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, reqDefBindIP net.IP, u
|
||||||
|
defHostIP = reqDefBindIP
|
||||||
|
}
|
||||||
|
|
||||||
|
- return n.allocatePortsInternal(ep.extConnConfig.PortBindings, ep.addr.IP, defHostIP, ulPxyEnabled)
|
||||||
|
+ return n.allocatePortsInternal(ep.extConnConfig.PortBindings, ep.addr.IP, defHostIP, ulPxyEnabled, pxyBin)
|
||||||
|
}
|
||||||
|
|
||||||
|
-func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
|
||||||
|
+func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool, pxyBin string) ([]types.PortBinding, error) {
|
||||||
|
bs := make([]types.PortBinding, 0, len(bindings))
|
||||||
|
for _, c := range bindings {
|
||||||
|
b := c.GetCopy()
|
||||||
|
- if err := n.allocatePort(&b, containerIP, defHostIP, ulPxyEnabled); err != nil {
|
||||||
|
+ if err := n.allocatePort(&b, containerIP, defHostIP, ulPxyEnabled, pxyBin); err != nil {
|
||||||
|
// On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
|
||||||
|
if cuErr := n.releasePortsInternal(bs); cuErr != nil {
|
||||||
|
logrus.Warnf("Upon allocation failure for %v, failed to clear previously allocated port bindings: %v", b, cuErr)
|
||||||
|
@@ -43,7 +43,7 @@ func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, cont
|
||||||
|
return bs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
-func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) error {
|
||||||
|
+func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool, pxyBin string) error {
|
||||||
|
var (
|
||||||
|
host net.Addr
|
||||||
|
err error
|
||||||
|
@@ -70,7 +70,7 @@ func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHos
|
||||||
|
|
||||||
|
// Try up to maxAllocatePortAttempts times to get a port that's not already allocated.
|
||||||
|
for i := 0; i < maxAllocatePortAttempts; i++ {
|
||||||
|
- if host, err = n.portMapper.MapRange(container, bnd.HostIP, int(bnd.HostPort), int(bnd.HostPortEnd), ulPxyEnabled); err == nil {
|
||||||
|
+ if host, err = n.portMapper.MapRange(container, bnd.HostIP, int(bnd.HostPort), int(bnd.HostPortEnd), ulPxyEnabled, pxyBin); err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// There is no point in immediately retrying to map an explicitly chosen port.
|
||||||
|
diff --git a/vendor/src/github.com/docker/libnetwork/portmapper/mapper.go b/vendor/src/github.com/docker/libnetwork/portmapper/mapper.go
|
||||||
|
index d125fa8..e30b88c 100644
|
||||||
|
--- a/vendor/src/github.com/docker/libnetwork/portmapper/mapper.go
|
||||||
|
+++ b/vendor/src/github.com/docker/libnetwork/portmapper/mapper.go
|
||||||
|
@@ -61,12 +61,12 @@ func (pm *PortMapper) SetIptablesChain(c *iptables.ChainInfo, bridgeName string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map maps the specified container transport address to the host's network address and transport port
|
||||||
|
-func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, useProxy bool) (host net.Addr, err error) {
|
||||||
|
- return pm.MapRange(container, hostIP, hostPort, hostPort, useProxy)
|
||||||
|
+func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, useProxy bool, proxyBin string) (host net.Addr, err error) {
|
||||||
|
+ return pm.MapRange(container, hostIP, hostPort, hostPort, useProxy, proxyBin)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapRange maps the specified container transport address to the host's network address and transport port range
|
||||||
|
-func (pm *PortMapper) MapRange(container net.Addr, hostIP net.IP, hostPortStart, hostPortEnd int, useProxy bool) (host net.Addr, err error) {
|
||||||
|
+func (pm *PortMapper) MapRange(container net.Addr, hostIP net.IP, hostPortStart, hostPortEnd int, useProxy bool, proxyBin string) (host net.Addr, err error) {
|
||||||
|
pm.lock.Lock()
|
||||||
|
defer pm.lock.Unlock()
|
||||||
|
|
||||||
|
@@ -90,7 +90,7 @@ func (pm *PortMapper) MapRange(container net.Addr, hostIP net.IP, hostPortStart,
|
||||||
|
}
|
||||||
|
|
||||||
|
if useProxy {
|
||||||
|
- m.userlandProxy = newProxy(proto, hostIP, allocatedHostPort, container.(*net.TCPAddr).IP, container.(*net.TCPAddr).Port)
|
||||||
|
+ m.userlandProxy = newProxy(proxyBin, proto, hostIP, allocatedHostPort, container.(*net.TCPAddr).IP, container.(*net.TCPAddr).Port)
|
||||||
|
} else {
|
||||||
|
m.userlandProxy = newDummyProxy(proto, hostIP, allocatedHostPort)
|
||||||
|
}
|
||||||
|
@@ -107,7 +107,7 @@ func (pm *PortMapper) MapRange(container net.Addr, hostIP net.IP, hostPortStart,
|
||||||
|
}
|
||||||
|
|
||||||
|
if useProxy {
|
||||||
|
- m.userlandProxy = newProxy(proto, hostIP, allocatedHostPort, container.(*net.UDPAddr).IP, container.(*net.UDPAddr).Port)
|
||||||
|
+ m.userlandProxy = newProxy(proxyBin, proto, hostIP, allocatedHostPort, container.(*net.UDPAddr).IP, container.(*net.UDPAddr).Port)
|
||||||
|
} else {
|
||||||
|
m.userlandProxy = newDummyProxy(proto, hostIP, allocatedHostPort)
|
||||||
|
}
|
||||||
|
diff --git a/vendor/src/github.com/docker/libnetwork/portmapper/proxy.go b/vendor/src/github.com/docker/libnetwork/portmapper/proxy.go
|
||||||
|
index ddde274..57bfeb1 100644
|
||||||
|
--- a/vendor/src/github.com/docker/libnetwork/portmapper/proxy.go
|
||||||
|
+++ b/vendor/src/github.com/docker/libnetwork/portmapper/proxy.go
|
||||||
|
@@ -92,9 +92,14 @@ func handleStopSignals(p proxy.Proxy) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-func newProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int) userlandProxy {
|
||||||
|
+func newProxyCommand(userlandProxyBin string, proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int) userlandProxy {
|
||||||
|
+ path := userlandProxyBin
|
||||||
|
+ if userlandProxyBin == "" {
|
||||||
|
+ userlandProxyBin = userlandProxyCommandName
|
||||||
|
+ path = reexec.Self()
|
||||||
|
+ }
|
||||||
|
args := []string{
|
||||||
|
- userlandProxyCommandName,
|
||||||
|
+ userlandProxyBin,
|
||||||
|
"-proto", proto,
|
||||||
|
"-host-ip", hostIP.String(),
|
||||||
|
"-host-port", strconv.Itoa(hostPort),
|
||||||
|
@@ -104,7 +109,7 @@ func newProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.
|
||||||
|
|
||||||
|
return &proxyCommand{
|
||||||
|
cmd: &exec.Cmd{
|
||||||
|
- Path: reexec.Self(),
|
||||||
|
+ Path: path,
|
||||||
|
Args: args,
|
||||||
|
SysProcAttr: &syscall.SysProcAttr{
|
||||||
|
Pdeathsig: syscall.SIGTERM, // send a sigterm to the proxy if the daemon process dies
|
1
alpine/packages/proxy/.gitignore
vendored
Normal file
1
alpine/packages/proxy/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/proxy
|
18
alpine/packages/proxy/Dockerfile
Normal file
18
alpine/packages/proxy/Dockerfile
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
FROM golang:alpine
|
||||||
|
|
||||||
|
RUN mkdir -p /go/src/proxy
|
||||||
|
WORKDIR /go/src/proxy
|
||||||
|
|
||||||
|
COPY * /go/src/proxy/
|
||||||
|
|
||||||
|
RUN mkdir -p /go/src/pkg/proxy
|
||||||
|
COPY pkg/* /go/src/pkg/proxy/
|
||||||
|
RUN mkdir -p /go/src/vendor/github.com/Sirupsen/logrus
|
||||||
|
COPY vendor/github.com/Sirupsen/logrus/* /go/src/vendor/github.com/Sirupsen/logrus/
|
||||||
|
|
||||||
|
ARG GOARCH
|
||||||
|
ARG GOOS
|
||||||
|
|
||||||
|
RUN go install
|
||||||
|
|
||||||
|
RUN [ -f /go/bin/*/proxy ] && mv /go/bin/*/proxy /go/bin/ || true
|
202
alpine/packages/proxy/LICENSE
Normal file
202
alpine/packages/proxy/LICENSE
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright {yyyy} {name of copyright owner}
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
10
alpine/packages/proxy/Makefile
Normal file
10
alpine/packages/proxy/Makefile
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
all: proxy
|
||||||
|
|
||||||
|
proxy: Dockerfile main.go proxy.go
|
||||||
|
docker build --build-arg GOOS=$(OS) --build-arg GOARCH=$(ARCH) -t proxy:build .
|
||||||
|
docker run --rm proxy:build cat /go/bin/proxy > proxy
|
||||||
|
chmod 755 proxy
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f proxy
|
||||||
|
docker images -q proxy:build | xargs docker rmi -f
|
11
alpine/packages/proxy/README.md
Normal file
11
alpine/packages/proxy/README.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
docker-proxy which can set up tunnels into the VM
|
||||||
|
=================================================
|
||||||
|
|
||||||
|
This is a replacement for the built-in `docker-proxy` command, which
|
||||||
|
proxies data from external ports to internal container ports.
|
||||||
|
|
||||||
|
This program uses the 9P filesystem under /port to extend the port
|
||||||
|
forward from the host running the Moby VM all the way to the container.
|
||||||
|
|
||||||
|
docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 8080 -container-ip 172.17.0.2 -container-port 8080
|
||||||
|
|
112
alpine/packages/proxy/main.go
Normal file
112
alpine/packages/proxy/main.go
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"pkg/proxy"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
host, port, container := parseHostContainerAddrs()
|
||||||
|
|
||||||
|
err := exposePort(host, port)
|
||||||
|
if err != nil {
|
||||||
|
sendError(err)
|
||||||
|
}
|
||||||
|
p, err := proxy.NewProxy(host, container)
|
||||||
|
if err != nil {
|
||||||
|
unexposePort(host)
|
||||||
|
sendError(err)
|
||||||
|
}
|
||||||
|
go handleStopSignals(p)
|
||||||
|
sendOK()
|
||||||
|
p.Run()
|
||||||
|
unexposePort(host)
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func exposePort(host net.Addr, port int) error {
|
||||||
|
name := host.String()
|
||||||
|
log.Printf("exposePort %s\n", name)
|
||||||
|
err := os.Mkdir("/port/"+name, 0)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to mkdir /port/%s: %#v\n", name, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ctl, err := os.OpenFile("/port/"+name+"/ctl", os.O_RDWR, 0)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to open /port/%s/ctl: %#v\n", name, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
me, err := getMyAddress()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to determine my local address: %#v\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = ctl.WriteString(fmt.Sprintf("%s:%s:%d", name, me, port))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to open /port/%s/ctl: %#v\n", name, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = ctl.Seek(0, 0)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to seek on /port/%s/ctl: %#v\n", name, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
results := make([]byte, 100)
|
||||||
|
count, err := ctl.Read(results)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to read from /port/%s/ctl: %#v\n", name, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// TODO: consider whether close/clunk of ctl would be a better tear down
|
||||||
|
// signal
|
||||||
|
ctl.Close()
|
||||||
|
|
||||||
|
response := string(results[0:count])
|
||||||
|
if strings.HasPrefix(response, "ERROR ") {
|
||||||
|
os.Remove("/port/" + name + "/ctl")
|
||||||
|
response = strings.Trim(response[6:], " \t\r\n")
|
||||||
|
return errors.New(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unexposePort(host net.Addr) {
|
||||||
|
name := host.String()
|
||||||
|
log.Printf("unexposePort %s\n", name)
|
||||||
|
err := os.Remove("/port/" + name)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to remove /port/%s: %#v\n", name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var myAddress string
|
||||||
|
|
||||||
|
// getMyAddress returns a string representing my address from the host's
|
||||||
|
// point of view. For now this is an IP address but it soon should be a vsock
|
||||||
|
// port.
|
||||||
|
func getMyAddress() (string, error) {
|
||||||
|
if myAddress != "" {
|
||||||
|
return myAddress, nil
|
||||||
|
}
|
||||||
|
d, err := os.Open("/port/docker")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer d.Close()
|
||||||
|
bytes := make([]byte, 100)
|
||||||
|
count, err := d.Read(bytes)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
s := string(bytes)[0:count]
|
||||||
|
bits := strings.Split(s, ":")
|
||||||
|
myAddress = bits[2]
|
||||||
|
return myAddress, nil
|
||||||
|
}
|
216
alpine/packages/proxy/pkg/proxy/network_proxy_test.go
Normal file
216
alpine/packages/proxy/pkg/proxy/network_proxy_test.go
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
package proxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var testBuf = []byte("Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo")
|
||||||
|
var testBufSize = len(testBuf)
|
||||||
|
|
||||||
|
type EchoServer interface {
|
||||||
|
Run()
|
||||||
|
Close()
|
||||||
|
LocalAddr() net.Addr
|
||||||
|
}
|
||||||
|
|
||||||
|
type TCPEchoServer struct {
|
||||||
|
listener net.Listener
|
||||||
|
testCtx *testing.T
|
||||||
|
}
|
||||||
|
|
||||||
|
type UDPEchoServer struct {
|
||||||
|
conn net.PacketConn
|
||||||
|
testCtx *testing.T
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEchoServer(t *testing.T, proto, address string) EchoServer {
|
||||||
|
var server EchoServer
|
||||||
|
if strings.HasPrefix(proto, "tcp") {
|
||||||
|
listener, err := net.Listen(proto, address)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
server = &TCPEchoServer{listener: listener, testCtx: t}
|
||||||
|
} else {
|
||||||
|
socket, err := net.ListenPacket(proto, address)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
server = &UDPEchoServer{conn: socket, testCtx: t}
|
||||||
|
}
|
||||||
|
return server
|
||||||
|
}
|
||||||
|
|
||||||
|
func (server *TCPEchoServer) Run() {
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
client, err := server.listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
go func(client net.Conn) {
|
||||||
|
if _, err := io.Copy(client, client); err != nil {
|
||||||
|
server.testCtx.Logf("can't echo to the client: %v\n", err.Error())
|
||||||
|
}
|
||||||
|
client.Close()
|
||||||
|
}(client)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (server *TCPEchoServer) LocalAddr() net.Addr { return server.listener.Addr() }
|
||||||
|
func (server *TCPEchoServer) Close() { server.listener.Addr() }
|
||||||
|
|
||||||
|
func (server *UDPEchoServer) Run() {
|
||||||
|
go func() {
|
||||||
|
readBuf := make([]byte, 1024)
|
||||||
|
for {
|
||||||
|
read, from, err := server.conn.ReadFrom(readBuf)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i := 0; i != read; {
|
||||||
|
written, err := server.conn.WriteTo(readBuf[i:read], from)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
i += written
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (server *UDPEchoServer) LocalAddr() net.Addr { return server.conn.LocalAddr() }
|
||||||
|
func (server *UDPEchoServer) Close() { server.conn.Close() }
|
||||||
|
|
||||||
|
func testProxyAt(t *testing.T, proto string, proxy Proxy, addr string) {
|
||||||
|
defer proxy.Close()
|
||||||
|
go proxy.Run()
|
||||||
|
client, err := net.Dial(proto, addr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Can't connect to the proxy: %v", err)
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
client.SetDeadline(time.Now().Add(10 * time.Second))
|
||||||
|
if _, err = client.Write(testBuf); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
recvBuf := make([]byte, testBufSize)
|
||||||
|
if _, err = client.Read(recvBuf); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(testBuf, recvBuf) {
|
||||||
|
t.Fatal(fmt.Errorf("Expected [%v] but got [%v]", testBuf, recvBuf))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testProxy(t *testing.T, proto string, proxy Proxy) {
|
||||||
|
testProxyAt(t, proto, proxy, proxy.FrontendAddr().String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTCP4Proxy(t *testing.T) {
|
||||||
|
backend := NewEchoServer(t, "tcp", "127.0.0.1:0")
|
||||||
|
defer backend.Close()
|
||||||
|
backend.Run()
|
||||||
|
frontendAddr := &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}
|
||||||
|
proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
testProxy(t, "tcp", proxy)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTCP6Proxy(t *testing.T) {
|
||||||
|
backend := NewEchoServer(t, "tcp", "[::1]:0")
|
||||||
|
defer backend.Close()
|
||||||
|
backend.Run()
|
||||||
|
frontendAddr := &net.TCPAddr{IP: net.IPv6loopback, Port: 0}
|
||||||
|
proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
testProxy(t, "tcp", proxy)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTCPDualStackProxy(t *testing.T) {
|
||||||
|
// If I understand `godoc -src net favoriteAddrFamily` (used by the
|
||||||
|
// net.Listen* functions) correctly this should work, but it doesn't.
|
||||||
|
t.Skip("No support for dual stack yet")
|
||||||
|
backend := NewEchoServer(t, "tcp", "[::1]:0")
|
||||||
|
defer backend.Close()
|
||||||
|
backend.Run()
|
||||||
|
frontendAddr := &net.TCPAddr{IP: net.IPv6loopback, Port: 0}
|
||||||
|
proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ipv4ProxyAddr := &net.TCPAddr{
|
||||||
|
IP: net.IPv4(127, 0, 0, 1),
|
||||||
|
Port: proxy.FrontendAddr().(*net.TCPAddr).Port,
|
||||||
|
}
|
||||||
|
testProxyAt(t, "tcp", proxy, ipv4ProxyAddr.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUDP4Proxy(t *testing.T) {
|
||||||
|
backend := NewEchoServer(t, "udp", "127.0.0.1:0")
|
||||||
|
defer backend.Close()
|
||||||
|
backend.Run()
|
||||||
|
frontendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}
|
||||||
|
proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
testProxy(t, "udp", proxy)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUDP6Proxy(t *testing.T) {
|
||||||
|
backend := NewEchoServer(t, "udp", "[::1]:0")
|
||||||
|
defer backend.Close()
|
||||||
|
backend.Run()
|
||||||
|
frontendAddr := &net.UDPAddr{IP: net.IPv6loopback, Port: 0}
|
||||||
|
proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
testProxy(t, "udp", proxy)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUDPWriteError(t *testing.T) {
|
||||||
|
frontendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}
|
||||||
|
// Hopefully, this port will be free: */
|
||||||
|
backendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 25587}
|
||||||
|
proxy, err := NewProxy(frontendAddr, backendAddr)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer proxy.Close()
|
||||||
|
go proxy.Run()
|
||||||
|
client, err := net.Dial("udp", "127.0.0.1:25587")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Can't connect to the proxy: %v", err)
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
// Make sure the proxy doesn't stop when there is no actual backend:
|
||||||
|
client.Write(testBuf)
|
||||||
|
client.Write(testBuf)
|
||||||
|
backend := NewEchoServer(t, "udp", "127.0.0.1:25587")
|
||||||
|
defer backend.Close()
|
||||||
|
backend.Run()
|
||||||
|
client.SetDeadline(time.Now().Add(10 * time.Second))
|
||||||
|
if _, err = client.Write(testBuf); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
recvBuf := make([]byte, testBufSize)
|
||||||
|
if _, err = client.Read(recvBuf); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(testBuf, recvBuf) {
|
||||||
|
t.Fatal(fmt.Errorf("Expected [%v] but got [%v]", testBuf, recvBuf))
|
||||||
|
}
|
||||||
|
}
|
37
alpine/packages/proxy/pkg/proxy/proxy.go
Normal file
37
alpine/packages/proxy/pkg/proxy/proxy.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// Package proxy provides a network Proxy interface and implementations for TCP
|
||||||
|
// and UDP.
|
||||||
|
package proxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Proxy defines the behavior of a proxy. It forwards traffic back and forth
|
||||||
|
// between two endpoints : the frontend and the backend.
|
||||||
|
// It can be used to do software port-mapping between two addresses.
|
||||||
|
// e.g. forward all traffic between the frontend (host) 127.0.0.1:3000
|
||||||
|
// to the backend (container) at 172.17.42.108:4000.
|
||||||
|
type Proxy interface {
|
||||||
|
// Run starts forwarding traffic back and forth between the front
|
||||||
|
// and back-end addresses.
|
||||||
|
Run()
|
||||||
|
// Close stops forwarding traffic and close both ends of the Proxy.
|
||||||
|
Close()
|
||||||
|
// FrontendAddr returns the address on which the proxy is listening.
|
||||||
|
FrontendAddr() net.Addr
|
||||||
|
// BackendAddr returns the proxied address.
|
||||||
|
BackendAddr() net.Addr
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewProxy creates a Proxy according to the specified frontendAddr and backendAddr.
|
||||||
|
func NewProxy(frontendAddr, backendAddr net.Addr) (Proxy, error) {
|
||||||
|
switch frontendAddr.(type) {
|
||||||
|
case *net.UDPAddr:
|
||||||
|
return NewUDPProxy(frontendAddr.(*net.UDPAddr), backendAddr.(*net.UDPAddr))
|
||||||
|
case *net.TCPAddr:
|
||||||
|
return NewTCPProxy(frontendAddr.(*net.TCPAddr), backendAddr.(*net.TCPAddr))
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("Unsupported protocol"))
|
||||||
|
}
|
||||||
|
}
|
31
alpine/packages/proxy/pkg/proxy/stub_proxy.go
Normal file
31
alpine/packages/proxy/pkg/proxy/stub_proxy.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package proxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StubProxy is a proxy that is a stub (does nothing).
|
||||||
|
type StubProxy struct {
|
||||||
|
frontendAddr net.Addr
|
||||||
|
backendAddr net.Addr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run does nothing.
|
||||||
|
func (p *StubProxy) Run() {}
|
||||||
|
|
||||||
|
// Close does nothing.
|
||||||
|
func (p *StubProxy) Close() {}
|
||||||
|
|
||||||
|
// FrontendAddr returns the frontend address.
|
||||||
|
func (p *StubProxy) FrontendAddr() net.Addr { return p.frontendAddr }
|
||||||
|
|
||||||
|
// BackendAddr returns the backend address.
|
||||||
|
func (p *StubProxy) BackendAddr() net.Addr { return p.backendAddr }
|
||||||
|
|
||||||
|
// NewStubProxy creates a new StubProxy
|
||||||
|
func NewStubProxy(frontendAddr, backendAddr net.Addr) (Proxy, error) {
|
||||||
|
return &StubProxy{
|
||||||
|
frontendAddr: frontendAddr,
|
||||||
|
backendAddr: backendAddr,
|
||||||
|
}, nil
|
||||||
|
}
|
99
alpine/packages/proxy/pkg/proxy/tcp_proxy.go
Normal file
99
alpine/packages/proxy/pkg/proxy/tcp_proxy.go
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
package proxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TCPProxy is a proxy for TCP connections. It implements the Proxy interface to
|
||||||
|
// handle TCP traffic forwarding between the frontend and backend addresses.
|
||||||
|
type TCPProxy struct {
|
||||||
|
listener *net.TCPListener
|
||||||
|
frontendAddr *net.TCPAddr
|
||||||
|
backendAddr *net.TCPAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTCPProxy creates a new TCPProxy.
|
||||||
|
func NewTCPProxy(frontendAddr, backendAddr *net.TCPAddr) (*TCPProxy, error) {
|
||||||
|
listener, err := net.ListenTCP("tcp", frontendAddr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// If the port in frontendAddr was 0 then ListenTCP will have a picked
|
||||||
|
// a port to listen on, hence the call to Addr to get that actual port:
|
||||||
|
return &TCPProxy{
|
||||||
|
listener: listener,
|
||||||
|
frontendAddr: listener.Addr().(*net.TCPAddr),
|
||||||
|
backendAddr: backendAddr,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (proxy *TCPProxy) clientLoop(client *net.TCPConn, quit chan bool) {
|
||||||
|
backend, err := net.DialTCP("tcp", nil, proxy.backendAddr)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Printf("Can't forward traffic to backend tcp/%v: %s\n", proxy.backendAddr, err)
|
||||||
|
client.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
event := make(chan int64)
|
||||||
|
var broker = func(to, from *net.TCPConn) {
|
||||||
|
written, err := io.Copy(to, from)
|
||||||
|
if err != nil {
|
||||||
|
// If the socket we are writing to is shutdown with
|
||||||
|
// SHUT_WR, forward it to the other end of the pipe:
|
||||||
|
if err, ok := err.(*net.OpError); ok && err.Err == syscall.EPIPE {
|
||||||
|
from.CloseWrite()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
to.CloseRead()
|
||||||
|
event <- written
|
||||||
|
}
|
||||||
|
|
||||||
|
go broker(client, backend)
|
||||||
|
go broker(backend, client)
|
||||||
|
|
||||||
|
var transferred int64
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
select {
|
||||||
|
case written := <-event:
|
||||||
|
transferred += written
|
||||||
|
case <-quit:
|
||||||
|
// Interrupt the two brokers and "join" them.
|
||||||
|
client.Close()
|
||||||
|
backend.Close()
|
||||||
|
for ; i < 2; i++ {
|
||||||
|
transferred += <-event
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
client.Close()
|
||||||
|
backend.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run starts forwarding the traffic using TCP.
|
||||||
|
func (proxy *TCPProxy) Run() {
|
||||||
|
quit := make(chan bool)
|
||||||
|
defer close(quit)
|
||||||
|
for {
|
||||||
|
client, err := proxy.listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
logrus.Printf("Stopping proxy on tcp/%v for tcp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
go proxy.clientLoop(client.(*net.TCPConn), quit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close stops forwarding the traffic.
|
||||||
|
func (proxy *TCPProxy) Close() { proxy.listener.Close() }
|
||||||
|
|
||||||
|
// FrontendAddr returns the TCP address on which the proxy is listening.
|
||||||
|
func (proxy *TCPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr }
|
||||||
|
|
||||||
|
// BackendAddr returns the TCP proxied address.
|
||||||
|
func (proxy *TCPProxy) BackendAddr() net.Addr { return proxy.backendAddr }
|
169
alpine/packages/proxy/pkg/proxy/udp_proxy.go
Normal file
169
alpine/packages/proxy/pkg/proxy/udp_proxy.go
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
package proxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// UDPConnTrackTimeout is the timeout used for UDP connection tracking
|
||||||
|
UDPConnTrackTimeout = 90 * time.Second
|
||||||
|
// UDPBufSize is the buffer size for the UDP proxy
|
||||||
|
UDPBufSize = 65507
|
||||||
|
)
|
||||||
|
|
||||||
|
// A net.Addr where the IP is split into two fields so you can use it as a key
|
||||||
|
// in a map:
|
||||||
|
type connTrackKey struct {
|
||||||
|
IPHigh uint64
|
||||||
|
IPLow uint64
|
||||||
|
Port int
|
||||||
|
}
|
||||||
|
|
||||||
|
func newConnTrackKey(addr *net.UDPAddr) *connTrackKey {
|
||||||
|
if len(addr.IP) == net.IPv4len {
|
||||||
|
return &connTrackKey{
|
||||||
|
IPHigh: 0,
|
||||||
|
IPLow: uint64(binary.BigEndian.Uint32(addr.IP)),
|
||||||
|
Port: addr.Port,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &connTrackKey{
|
||||||
|
IPHigh: binary.BigEndian.Uint64(addr.IP[:8]),
|
||||||
|
IPLow: binary.BigEndian.Uint64(addr.IP[8:]),
|
||||||
|
Port: addr.Port,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type connTrackMap map[connTrackKey]*net.UDPConn
|
||||||
|
|
||||||
|
// UDPProxy is proxy for which handles UDP datagrams. It implements the Proxy
|
||||||
|
// interface to handle UDP traffic forwarding between the frontend and backend
|
||||||
|
// addresses.
|
||||||
|
type UDPProxy struct {
|
||||||
|
listener *net.UDPConn
|
||||||
|
frontendAddr *net.UDPAddr
|
||||||
|
backendAddr *net.UDPAddr
|
||||||
|
connTrackTable connTrackMap
|
||||||
|
connTrackLock sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewUDPProxy creates a new UDPProxy.
|
||||||
|
func NewUDPProxy(frontendAddr, backendAddr *net.UDPAddr) (*UDPProxy, error) {
|
||||||
|
listener, err := net.ListenUDP("udp", frontendAddr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &UDPProxy{
|
||||||
|
listener: listener,
|
||||||
|
frontendAddr: listener.LocalAddr().(*net.UDPAddr),
|
||||||
|
backendAddr: backendAddr,
|
||||||
|
connTrackTable: make(connTrackMap),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (proxy *UDPProxy) replyLoop(proxyConn *net.UDPConn, clientAddr *net.UDPAddr, clientKey *connTrackKey) {
|
||||||
|
defer func() {
|
||||||
|
proxy.connTrackLock.Lock()
|
||||||
|
delete(proxy.connTrackTable, *clientKey)
|
||||||
|
proxy.connTrackLock.Unlock()
|
||||||
|
proxyConn.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
readBuf := make([]byte, UDPBufSize)
|
||||||
|
for {
|
||||||
|
proxyConn.SetReadDeadline(time.Now().Add(UDPConnTrackTimeout))
|
||||||
|
again:
|
||||||
|
read, err := proxyConn.Read(readBuf)
|
||||||
|
if err != nil {
|
||||||
|
if err, ok := err.(*net.OpError); ok && err.Err == syscall.ECONNREFUSED {
|
||||||
|
// This will happen if the last write failed
|
||||||
|
// (e.g: nothing is actually listening on the
|
||||||
|
// proxied port on the container), ignore it
|
||||||
|
// and continue until UDPConnTrackTimeout
|
||||||
|
// expires:
|
||||||
|
goto again
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i := 0; i != read; {
|
||||||
|
written, err := proxy.listener.WriteToUDP(readBuf[i:read], clientAddr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
i += written
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run starts forwarding the traffic using UDP.
|
||||||
|
func (proxy *UDPProxy) Run() {
|
||||||
|
readBuf := make([]byte, UDPBufSize)
|
||||||
|
for {
|
||||||
|
read, from, err := proxy.listener.ReadFromUDP(readBuf)
|
||||||
|
if err != nil {
|
||||||
|
// NOTE: Apparently ReadFrom doesn't return
|
||||||
|
// ECONNREFUSED like Read do (see comment in
|
||||||
|
// UDPProxy.replyLoop)
|
||||||
|
if !isClosedError(err) {
|
||||||
|
logrus.Printf("Stopping proxy on udp/%v for udp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
fromKey := newConnTrackKey(from)
|
||||||
|
proxy.connTrackLock.Lock()
|
||||||
|
proxyConn, hit := proxy.connTrackTable[*fromKey]
|
||||||
|
if !hit {
|
||||||
|
proxyConn, err = net.DialUDP("udp", nil, proxy.backendAddr)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Printf("Can't proxy a datagram to udp/%s: %s\n", proxy.backendAddr, err)
|
||||||
|
proxy.connTrackLock.Unlock()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
proxy.connTrackTable[*fromKey] = proxyConn
|
||||||
|
go proxy.replyLoop(proxyConn, from, fromKey)
|
||||||
|
}
|
||||||
|
proxy.connTrackLock.Unlock()
|
||||||
|
for i := 0; i != read; {
|
||||||
|
written, err := proxyConn.Write(readBuf[i:read])
|
||||||
|
if err != nil {
|
||||||
|
logrus.Printf("Can't proxy a datagram to udp/%s: %s\n", proxy.backendAddr, err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
i += written
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close stops forwarding the traffic.
|
||||||
|
func (proxy *UDPProxy) Close() {
|
||||||
|
proxy.listener.Close()
|
||||||
|
proxy.connTrackLock.Lock()
|
||||||
|
defer proxy.connTrackLock.Unlock()
|
||||||
|
for _, conn := range proxy.connTrackTable {
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FrontendAddr returns the UDP address on which the proxy is listening.
|
||||||
|
func (proxy *UDPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr }
|
||||||
|
|
||||||
|
// BackendAddr returns the proxied UDP address.
|
||||||
|
func (proxy *UDPProxy) BackendAddr() net.Addr { return proxy.backendAddr }
|
||||||
|
|
||||||
|
func isClosedError(err error) bool {
|
||||||
|
/* This comparison is ugly, but unfortunately, net.go doesn't export errClosing.
|
||||||
|
* See:
|
||||||
|
* http://golang.org/src/pkg/net/net.go
|
||||||
|
* https://code.google.com/p/go/issues/detail?id=4337
|
||||||
|
* https://groups.google.com/forum/#!msg/golang-nuts/0_aaCvBmOcM/SptmDyX1XJMJ
|
||||||
|
*/
|
||||||
|
return strings.HasSuffix(err.Error(), "use of closed network connection")
|
||||||
|
}
|
69
alpine/packages/proxy/proxy.go
Normal file
69
alpine/packages/proxy/proxy.go
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"pkg/proxy"
|
||||||
|
)
|
||||||
|
|
||||||
|
// sendError signals the error to the parent and quits the process.
|
||||||
|
func sendError(err error) {
|
||||||
|
f := os.NewFile(3, "signal-parent")
|
||||||
|
|
||||||
|
fmt.Fprintf(f, "1\n%s", err)
|
||||||
|
f.Close()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendOK signals the parent that the forward is running.
|
||||||
|
func sendOK() {
|
||||||
|
f := os.NewFile(3, "signal-parent")
|
||||||
|
fmt.Fprint(f, "0\n")
|
||||||
|
f.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// From docker/libnetwork/portmapper/proxy.go:
|
||||||
|
|
||||||
|
// parseHostContainerAddrs parses the flags passed on reexec to create the TCP or UDP
|
||||||
|
// net.Addrs to map the host and container ports
|
||||||
|
func parseHostContainerAddrs() (host net.Addr, port int, container net.Addr) {
|
||||||
|
var (
|
||||||
|
proto = flag.String("proto", "tcp", "proxy protocol")
|
||||||
|
hostIP = flag.String("host-ip", "", "host ip")
|
||||||
|
hostPort = flag.Int("host-port", -1, "host port")
|
||||||
|
containerIP = flag.String("container-ip", "", "container ip")
|
||||||
|
containerPort = flag.Int("container-port", -1, "container port")
|
||||||
|
)
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
switch *proto {
|
||||||
|
case "tcp":
|
||||||
|
host = &net.TCPAddr{IP: net.ParseIP(*hostIP), Port: *hostPort}
|
||||||
|
port = *hostPort
|
||||||
|
container = &net.TCPAddr{IP: net.ParseIP(*containerIP), Port: *containerPort}
|
||||||
|
case "udp":
|
||||||
|
host = &net.UDPAddr{IP: net.ParseIP(*hostIP), Port: *hostPort}
|
||||||
|
port = *hostPort
|
||||||
|
container = &net.UDPAddr{IP: net.ParseIP(*containerIP), Port: *containerPort}
|
||||||
|
default:
|
||||||
|
log.Fatalf("unsupported protocol %s", *proto)
|
||||||
|
}
|
||||||
|
|
||||||
|
return host, port, container
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleStopSignals(p proxy.Proxy) {
|
||||||
|
s := make(chan os.Signal, 10)
|
||||||
|
signal.Notify(s, os.Interrupt, syscall.SIGTERM, syscall.SIGSTOP)
|
||||||
|
|
||||||
|
for range s {
|
||||||
|
p.Close()
|
||||||
|
}
|
||||||
|
}
|
1
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/.gitignore
generated
vendored
Normal file
1
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/.gitignore
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
logrus
|
8
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/.travis.yml
generated
vendored
Normal file
8
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- 1.2
|
||||||
|
- 1.3
|
||||||
|
- 1.4
|
||||||
|
- tip
|
||||||
|
install:
|
||||||
|
- go get -t ./...
|
47
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/CHANGELOG.md
generated
vendored
Normal file
47
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/CHANGELOG.md
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# 0.8.7
|
||||||
|
|
||||||
|
* logrus/core: fix possible race (#216)
|
||||||
|
* logrus/doc: small typo fixes and doc improvements
|
||||||
|
|
||||||
|
|
||||||
|
# 0.8.6
|
||||||
|
|
||||||
|
* hooks/raven: allow passing an initialized client
|
||||||
|
|
||||||
|
# 0.8.5
|
||||||
|
|
||||||
|
* logrus/core: revert #208
|
||||||
|
|
||||||
|
# 0.8.4
|
||||||
|
|
||||||
|
* formatter/text: fix data race (#218)
|
||||||
|
|
||||||
|
# 0.8.3
|
||||||
|
|
||||||
|
* logrus/core: fix entry log level (#208)
|
||||||
|
* logrus/core: improve performance of text formatter by 40%
|
||||||
|
* logrus/core: expose `LevelHooks` type
|
||||||
|
* logrus/core: add support for DragonflyBSD and NetBSD
|
||||||
|
* formatter/text: print structs more verbosely
|
||||||
|
|
||||||
|
# 0.8.2
|
||||||
|
|
||||||
|
* logrus: fix more Fatal family functions
|
||||||
|
|
||||||
|
# 0.8.1
|
||||||
|
|
||||||
|
* logrus: fix not exiting on `Fatalf` and `Fatalln`
|
||||||
|
|
||||||
|
# 0.8.0
|
||||||
|
|
||||||
|
* logrus: defaults to stderr instead of stdout
|
||||||
|
* hooks/sentry: add special field for `*http.Request`
|
||||||
|
* formatter/text: ignore Windows for colors
|
||||||
|
|
||||||
|
# 0.7.3
|
||||||
|
|
||||||
|
* formatter/\*: allow configuration of timestamp layout
|
||||||
|
|
||||||
|
# 0.7.2
|
||||||
|
|
||||||
|
* formatter/text: Add configuration option for time format (#158)
|
21
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/LICENSE
generated
vendored
Normal file
21
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Simon Eskildsen
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
357
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/README.md
generated
vendored
Normal file
357
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/README.md
generated
vendored
Normal file
@ -0,0 +1,357 @@
|
|||||||
|
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [](https://travis-ci.org/Sirupsen/logrus) [][godoc]
|
||||||
|
|
||||||
|
Logrus is a structured logger for Go (golang), completely API compatible with
|
||||||
|
the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not
|
||||||
|
yet stable (pre 1.0). Logrus itself is completely stable and has been used in
|
||||||
|
many large deployments. The core API is unlikely to change much but please
|
||||||
|
version control your Logrus to make sure you aren't fetching latest `master` on
|
||||||
|
every build.**
|
||||||
|
|
||||||
|
Nicely color-coded in development (when a TTY is attached, otherwise just
|
||||||
|
plain text):
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
With `log.Formatter = new(logrus.JSONFormatter)`, for easy parsing by logstash
|
||||||
|
or Splunk:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the
|
||||||
|
ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
|
||||||
|
|
||||||
|
{"level":"warning","msg":"The group's number increased tremendously!",
|
||||||
|
"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"}
|
||||||
|
|
||||||
|
{"animal":"walrus","level":"info","msg":"A giant walrus appears!",
|
||||||
|
"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"}
|
||||||
|
|
||||||
|
{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.",
|
||||||
|
"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"}
|
||||||
|
|
||||||
|
{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,
|
||||||
|
"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
|
||||||
|
```
|
||||||
|
|
||||||
|
With the default `log.Formatter = new(&log.TextFormatter{})` when a TTY is not
|
||||||
|
attached, the output is compatible with the
|
||||||
|
[logfmt](http://godoc.org/github.com/kr/logfmt) format:
|
||||||
|
|
||||||
|
```text
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
|
||||||
|
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
|
||||||
|
exit status 1
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
The simplest way to use Logrus is simply the package-level exported logger:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
}).Info("A walrus appears")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that it's completely api-compatible with the stdlib logger, so you can
|
||||||
|
replace your `log` imports everywhere with `log "github.com/Sirupsen/logrus"`
|
||||||
|
and you'll now have the flexibility of Logrus. You can customize it all you
|
||||||
|
want:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
"github.com/Sirupsen/logrus/hooks/airbrake"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Log as JSON instead of the default ASCII formatter.
|
||||||
|
log.SetFormatter(&log.JSONFormatter{})
|
||||||
|
|
||||||
|
// Use the Airbrake hook to report errors that have Error severity or above to
|
||||||
|
// an exception tracker. You can create custom hooks, see the Hooks section.
|
||||||
|
log.AddHook(airbrake.NewHook("https://example.com", "xyz", "development"))
|
||||||
|
|
||||||
|
// Output to stderr instead of stdout, could also be a file.
|
||||||
|
log.SetOutput(os.Stderr)
|
||||||
|
|
||||||
|
// Only log the warning severity or above.
|
||||||
|
log.SetLevel(log.WarnLevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
"size": 10,
|
||||||
|
}).Info("A group of walrus emerges from the ocean")
|
||||||
|
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"omg": true,
|
||||||
|
"number": 122,
|
||||||
|
}).Warn("The group's number increased tremendously!")
|
||||||
|
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"omg": true,
|
||||||
|
"number": 100,
|
||||||
|
}).Fatal("The ice breaks!")
|
||||||
|
|
||||||
|
// A common pattern is to re-use fields between logging statements by re-using
|
||||||
|
// the logrus.Entry returned from WithFields()
|
||||||
|
contextLogger := log.WithFields(log.Fields{
|
||||||
|
"common": "this is a common field",
|
||||||
|
"other": "I also should be logged always",
|
||||||
|
})
|
||||||
|
|
||||||
|
contextLogger.Info("I'll be logged with common and other field")
|
||||||
|
contextLogger.Info("Me too")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For more advanced usage such as logging to multiple locations from the same
|
||||||
|
application, you can also create an instance of the `logrus` Logger:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Create a new instance of the logger. You can have any number of instances.
|
||||||
|
var log = logrus.New()
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// The API for setting attributes is a little different than the package level
|
||||||
|
// exported logger. See Godoc.
|
||||||
|
log.Out = os.Stderr
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
"size": 10,
|
||||||
|
}).Info("A group of walrus emerges from the ocean")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Fields
|
||||||
|
|
||||||
|
Logrus encourages careful, structured logging though logging fields instead of
|
||||||
|
long, unparseable error messages. For example, instead of: `log.Fatalf("Failed
|
||||||
|
to send event %s to topic %s with key %d")`, you should log the much more
|
||||||
|
discoverable:
|
||||||
|
|
||||||
|
```go
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"event": event,
|
||||||
|
"topic": topic,
|
||||||
|
"key": key,
|
||||||
|
}).Fatal("Failed to send event")
|
||||||
|
```
|
||||||
|
|
||||||
|
We've found this API forces you to think about logging in a way that produces
|
||||||
|
much more useful logging messages. We've been in countless situations where just
|
||||||
|
a single added field to a log statement that was already there would've saved us
|
||||||
|
hours. The `WithFields` call is optional.
|
||||||
|
|
||||||
|
In general, with Logrus using any of the `printf`-family functions should be
|
||||||
|
seen as a hint you should add a field, however, you can still use the
|
||||||
|
`printf`-family functions with Logrus.
|
||||||
|
|
||||||
|
#### Hooks
|
||||||
|
|
||||||
|
You can add hooks for logging levels. For example to send errors to an exception
|
||||||
|
tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to
|
||||||
|
multiple places simultaneously, e.g. syslog.
|
||||||
|
|
||||||
|
Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
|
||||||
|
`init`:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
"github.com/Sirupsen/logrus/hooks/airbrake"
|
||||||
|
logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
|
||||||
|
"log/syslog"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
log.AddHook(airbrake.NewHook("https://example.com", "xyz", "development"))
|
||||||
|
|
||||||
|
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Unable to connect to local syslog daemon")
|
||||||
|
} else {
|
||||||
|
log.AddHook(hook)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
| Hook | Description |
|
||||||
|
| ----- | ----------- |
|
||||||
|
| [Airbrake](https://github.com/Sirupsen/logrus/blob/master/hooks/airbrake/airbrake.go) | Send errors to an exception tracking service compatible with the Airbrake API. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. |
|
||||||
|
| [Papertrail](https://github.com/Sirupsen/logrus/blob/master/hooks/papertrail/papertrail.go) | Send errors to the Papertrail hosted logging service via UDP. |
|
||||||
|
| [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
|
||||||
|
| [BugSnag](https://github.com/Sirupsen/logrus/blob/master/hooks/bugsnag/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
|
||||||
|
| [Sentry](https://github.com/Sirupsen/logrus/blob/master/hooks/sentry/sentry.go) | Send errors to the Sentry error logging and aggregation service. |
|
||||||
|
| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
|
||||||
|
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
|
||||||
|
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
|
||||||
|
| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
|
||||||
|
| [Graylog](https://github.com/gemnasium/logrus-hooks/tree/master/graylog) | Hook for logging to [Graylog](http://graylog2.org/) |
|
||||||
|
| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
|
||||||
|
| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
|
||||||
|
| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger |
|
||||||
|
| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
|
||||||
|
| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar |
|
||||||
|
| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd |
|
||||||
|
| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
|
||||||
|
|
||||||
|
#### Level logging
|
||||||
|
|
||||||
|
Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic.
|
||||||
|
|
||||||
|
```go
|
||||||
|
log.Debug("Useful debugging information.")
|
||||||
|
log.Info("Something noteworthy happened!")
|
||||||
|
log.Warn("You should probably take a look at this.")
|
||||||
|
log.Error("Something failed but I'm not quitting.")
|
||||||
|
// Calls os.Exit(1) after logging
|
||||||
|
log.Fatal("Bye.")
|
||||||
|
// Calls panic() after logging
|
||||||
|
log.Panic("I'm bailing.")
|
||||||
|
```
|
||||||
|
|
||||||
|
You can set the logging level on a `Logger`, then it will only log entries with
|
||||||
|
that severity or anything above it:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Will log anything that is info or above (warn, error, fatal, panic). Default.
|
||||||
|
log.SetLevel(log.InfoLevel)
|
||||||
|
```
|
||||||
|
|
||||||
|
It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose
|
||||||
|
environment if your application has that.
|
||||||
|
|
||||||
|
#### Entries
|
||||||
|
|
||||||
|
Besides the fields added with `WithField` or `WithFields` some fields are
|
||||||
|
automatically added to all logging events:
|
||||||
|
|
||||||
|
1. `time`. The timestamp when the entry was created.
|
||||||
|
2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after
|
||||||
|
the `AddFields` call. E.g. `Failed to send event.`
|
||||||
|
3. `level`. The logging level. E.g. `info`.
|
||||||
|
|
||||||
|
#### Environments
|
||||||
|
|
||||||
|
Logrus has no notion of environment.
|
||||||
|
|
||||||
|
If you wish for hooks and formatters to only be used in specific environments,
|
||||||
|
you should handle that yourself. For example, if your application has a global
|
||||||
|
variable `Environment`, which is a string representation of the environment you
|
||||||
|
could do:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
init() {
|
||||||
|
// do something here to set environment depending on an environment variable
|
||||||
|
// or command-line flag
|
||||||
|
if Environment == "production" {
|
||||||
|
log.SetFormatter(&log.JSONFormatter{})
|
||||||
|
} else {
|
||||||
|
// The TextFormatter is default, you don't actually have to do this.
|
||||||
|
log.SetFormatter(&log.TextFormatter{})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This configuration is how `logrus` was intended to be used, but JSON in
|
||||||
|
production is mostly only useful if you do log aggregation with tools like
|
||||||
|
Splunk or Logstash.
|
||||||
|
|
||||||
|
#### Formatters
|
||||||
|
|
||||||
|
The built-in logging formatters are:
|
||||||
|
|
||||||
|
* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise
|
||||||
|
without colors.
|
||||||
|
* *Note:* to force colored output when there is no TTY, set the `ForceColors`
|
||||||
|
field to `true`. To force no colored output even if there is a TTY set the
|
||||||
|
`DisableColors` field to `true`
|
||||||
|
* `logrus.JSONFormatter`. Logs fields as JSON.
|
||||||
|
* `logrus_logstash.LogstashFormatter`. Logs fields as Logstash Events (http://logstash.net).
|
||||||
|
|
||||||
|
```go
|
||||||
|
logrus.SetFormatter(&logrus_logstash.LogstashFormatter{Type: “application_name"})
|
||||||
|
```
|
||||||
|
|
||||||
|
Third party logging formatters:
|
||||||
|
|
||||||
|
* [`zalgo`](https://github.com/aybabtme/logzalgo): invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
|
||||||
|
|
||||||
|
You can define your formatter by implementing the `Formatter` interface,
|
||||||
|
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
|
||||||
|
`Fields` type (`map[string]interface{}`) with all your fields as well as the
|
||||||
|
default ones (see Entries section above):
|
||||||
|
|
||||||
|
```go
|
||||||
|
type MyJSONFormatter struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
log.SetFormatter(new(MyJSONFormatter))
|
||||||
|
|
||||||
|
func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
|
// Note this doesn't include Time, Level and Message which are available on
|
||||||
|
// the Entry. Consult `godoc` on information about those fields or read the
|
||||||
|
// source of the official loggers.
|
||||||
|
serialized, err := json.Marshal(entry.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
||||||
|
}
|
||||||
|
return append(serialized, '\n'), nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Logger as an `io.Writer`
|
||||||
|
|
||||||
|
Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it.
|
||||||
|
|
||||||
|
```go
|
||||||
|
w := logger.Writer()
|
||||||
|
defer w.Close()
|
||||||
|
|
||||||
|
srv := http.Server{
|
||||||
|
// create a stdlib log.Logger that writes to
|
||||||
|
// logrus.Logger.
|
||||||
|
ErrorLog: log.New(w, "", 0),
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Each line written to that writer will be printed the usual way, using formatters
|
||||||
|
and hooks. The level for those entries is `info`.
|
||||||
|
|
||||||
|
#### Rotation
|
||||||
|
|
||||||
|
Log rotation is not provided with Logrus. Log rotation should be done by an
|
||||||
|
external program (like `logrotate(8)`) that can compress and delete old log
|
||||||
|
entries. It should not be a feature of the application-level logger.
|
||||||
|
|
||||||
|
|
||||||
|
[godoc]: https://godoc.org/github.com/Sirupsen/logrus
|
26
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/doc.go
generated
vendored
Normal file
26
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/doc.go
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
Package logrus is a structured logger for Go, completely API compatible with the standard library logger.
|
||||||
|
|
||||||
|
|
||||||
|
The simplest way to use Logrus is simply the package-level exported logger:
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
"number": 1,
|
||||||
|
"size": 10,
|
||||||
|
}).Info("A walrus appears")
|
||||||
|
}
|
||||||
|
|
||||||
|
Output:
|
||||||
|
time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10
|
||||||
|
|
||||||
|
For a full guide visit https://github.com/Sirupsen/logrus
|
||||||
|
*/
|
||||||
|
package logrus
|
264
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/entry.go
generated
vendored
Normal file
264
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/entry.go
generated
vendored
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Defines the key when adding errors using WithError.
|
||||||
|
var ErrorKey = "error"
|
||||||
|
|
||||||
|
// An entry is the final or intermediate Logrus logging entry. It contains all
|
||||||
|
// the fields passed with WithField{,s}. It's finally logged when Debug, Info,
|
||||||
|
// Warn, Error, Fatal or Panic is called on it. These objects can be reused and
|
||||||
|
// passed around as much as you wish to avoid field duplication.
|
||||||
|
type Entry struct {
|
||||||
|
Logger *Logger
|
||||||
|
|
||||||
|
// Contains all the fields set by the user.
|
||||||
|
Data Fields
|
||||||
|
|
||||||
|
// Time at which the log entry was created
|
||||||
|
Time time.Time
|
||||||
|
|
||||||
|
// Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic
|
||||||
|
Level Level
|
||||||
|
|
||||||
|
// Message passed to Debug, Info, Warn, Error, Fatal or Panic
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEntry(logger *Logger) *Entry {
|
||||||
|
return &Entry{
|
||||||
|
Logger: logger,
|
||||||
|
// Default is three fields, give a little extra room
|
||||||
|
Data: make(Fields, 5),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a reader for the entry, which is a proxy to the formatter.
|
||||||
|
func (entry *Entry) Reader() (*bytes.Buffer, error) {
|
||||||
|
serialized, err := entry.Logger.Formatter.Format(entry)
|
||||||
|
return bytes.NewBuffer(serialized), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the string representation from the reader and ultimately the
|
||||||
|
// formatter.
|
||||||
|
func (entry *Entry) String() (string, error) {
|
||||||
|
reader, err := entry.Reader()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return reader.String(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add an error as single field (using the key defined in ErrorKey) to the Entry.
|
||||||
|
func (entry *Entry) WithError(err error) *Entry {
|
||||||
|
return entry.WithField(ErrorKey, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a single field to the Entry.
|
||||||
|
func (entry *Entry) WithField(key string, value interface{}) *Entry {
|
||||||
|
return entry.WithFields(Fields{key: value})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a map of fields to the Entry.
|
||||||
|
func (entry *Entry) WithFields(fields Fields) *Entry {
|
||||||
|
data := Fields{}
|
||||||
|
for k, v := range entry.Data {
|
||||||
|
data[k] = v
|
||||||
|
}
|
||||||
|
for k, v := range fields {
|
||||||
|
data[k] = v
|
||||||
|
}
|
||||||
|
return &Entry{Logger: entry.Logger, Data: data}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function is not declared with a pointer value because otherwise
|
||||||
|
// race conditions will occur when using multiple goroutines
|
||||||
|
func (entry Entry) log(level Level, msg string) {
|
||||||
|
entry.Time = time.Now()
|
||||||
|
entry.Level = level
|
||||||
|
entry.Message = msg
|
||||||
|
|
||||||
|
if err := entry.Logger.Hooks.Fire(level, &entry); err != nil {
|
||||||
|
entry.Logger.mu.Lock()
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
||||||
|
entry.Logger.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
reader, err := entry.Reader()
|
||||||
|
if err != nil {
|
||||||
|
entry.Logger.mu.Lock()
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
|
||||||
|
entry.Logger.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.Logger.mu.Lock()
|
||||||
|
defer entry.Logger.mu.Unlock()
|
||||||
|
|
||||||
|
_, err = io.Copy(entry.Logger.Out, reader)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// To avoid Entry#log() returning a value that only would make sense for
|
||||||
|
// panic() to use in Entry#Panic(), we avoid the allocation by checking
|
||||||
|
// directly here.
|
||||||
|
if level <= PanicLevel {
|
||||||
|
panic(&entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Debug(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= DebugLevel {
|
||||||
|
entry.log(DebugLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Print(args ...interface{}) {
|
||||||
|
entry.Info(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Info(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= InfoLevel {
|
||||||
|
entry.log(InfoLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warn(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= WarnLevel {
|
||||||
|
entry.log(WarnLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warning(args ...interface{}) {
|
||||||
|
entry.Warn(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Error(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= ErrorLevel {
|
||||||
|
entry.log(ErrorLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Fatal(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= FatalLevel {
|
||||||
|
entry.log(FatalLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Panic(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= PanicLevel {
|
||||||
|
entry.log(PanicLevel, fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
panic(fmt.Sprint(args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entry Printf family functions
|
||||||
|
|
||||||
|
func (entry *Entry) Debugf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= DebugLevel {
|
||||||
|
entry.Debug(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Infof(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= InfoLevel {
|
||||||
|
entry.Info(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Printf(format string, args ...interface{}) {
|
||||||
|
entry.Infof(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warnf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= WarnLevel {
|
||||||
|
entry.Warn(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warningf(format string, args ...interface{}) {
|
||||||
|
entry.Warnf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Errorf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= ErrorLevel {
|
||||||
|
entry.Error(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Fatalf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= FatalLevel {
|
||||||
|
entry.Fatal(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Panicf(format string, args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= PanicLevel {
|
||||||
|
entry.Panic(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entry Println family functions
|
||||||
|
|
||||||
|
func (entry *Entry) Debugln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= DebugLevel {
|
||||||
|
entry.Debug(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Infoln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= InfoLevel {
|
||||||
|
entry.Info(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Println(args ...interface{}) {
|
||||||
|
entry.Infoln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warnln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= WarnLevel {
|
||||||
|
entry.Warn(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Warningln(args ...interface{}) {
|
||||||
|
entry.Warnln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Errorln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= ErrorLevel {
|
||||||
|
entry.Error(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Fatalln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= FatalLevel {
|
||||||
|
entry.Fatal(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (entry *Entry) Panicln(args ...interface{}) {
|
||||||
|
if entry.Logger.Level >= PanicLevel {
|
||||||
|
entry.Panic(entry.sprintlnn(args...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sprintlnn => Sprint no newline. This is to get the behavior of how
|
||||||
|
// fmt.Sprintln where spaces are always added between operands, regardless of
|
||||||
|
// their type. Instead of vendoring the Sprintln implementation to spare a
|
||||||
|
// string allocation, we do the simplest thing.
|
||||||
|
func (entry *Entry) sprintlnn(args ...interface{}) string {
|
||||||
|
msg := fmt.Sprintln(args...)
|
||||||
|
return msg[:len(msg)-1]
|
||||||
|
}
|
50
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/examples/basic/basic.go
generated
vendored
Normal file
50
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/examples/basic/basic.go
generated
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
var log = logrus.New()
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
log.Formatter = new(logrus.JSONFormatter)
|
||||||
|
log.Formatter = new(logrus.TextFormatter) // default
|
||||||
|
log.Level = logrus.DebugLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
defer func() {
|
||||||
|
err := recover()
|
||||||
|
if err != nil {
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"omg": true,
|
||||||
|
"err": err,
|
||||||
|
"number": 100,
|
||||||
|
}).Fatal("The ice breaks!")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
"number": 8,
|
||||||
|
}).Debug("Started observing beach")
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
"size": 10,
|
||||||
|
}).Info("A group of walrus emerges from the ocean")
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"omg": true,
|
||||||
|
"number": 122,
|
||||||
|
}).Warn("The group's number increased tremendously!")
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"temperature": -4,
|
||||||
|
}).Debug("Temperature changes")
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"animal": "orca",
|
||||||
|
"size": 9009,
|
||||||
|
}).Panic("It's over 9000!")
|
||||||
|
}
|
30
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/examples/hook/hook.go
generated
vendored
Normal file
30
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/examples/hook/hook.go
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/Sirupsen/logrus/hooks/airbrake"
|
||||||
|
)
|
||||||
|
|
||||||
|
var log = logrus.New()
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
log.Formatter = new(logrus.TextFormatter) // default
|
||||||
|
log.Hooks.Add(airbrake.NewHook("https://example.com", "xyz", "development"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"animal": "walrus",
|
||||||
|
"size": 10,
|
||||||
|
}).Info("A group of walrus emerges from the ocean")
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"omg": true,
|
||||||
|
"number": 122,
|
||||||
|
}).Warn("The group's number increased tremendously!")
|
||||||
|
|
||||||
|
log.WithFields(logrus.Fields{
|
||||||
|
"omg": true,
|
||||||
|
"number": 100,
|
||||||
|
}).Fatal("The ice breaks!")
|
||||||
|
}
|
193
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/exported.go
generated
vendored
Normal file
193
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/exported.go
generated
vendored
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// std is the name of the standard logger in stdlib `log`
|
||||||
|
std = New()
|
||||||
|
)
|
||||||
|
|
||||||
|
func StandardLogger() *Logger {
|
||||||
|
return std
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOutput sets the standard logger output.
|
||||||
|
func SetOutput(out io.Writer) {
|
||||||
|
std.mu.Lock()
|
||||||
|
defer std.mu.Unlock()
|
||||||
|
std.Out = out
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFormatter sets the standard logger formatter.
|
||||||
|
func SetFormatter(formatter Formatter) {
|
||||||
|
std.mu.Lock()
|
||||||
|
defer std.mu.Unlock()
|
||||||
|
std.Formatter = formatter
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLevel sets the standard logger level.
|
||||||
|
func SetLevel(level Level) {
|
||||||
|
std.mu.Lock()
|
||||||
|
defer std.mu.Unlock()
|
||||||
|
std.Level = level
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLevel returns the standard logger level.
|
||||||
|
func GetLevel() Level {
|
||||||
|
std.mu.Lock()
|
||||||
|
defer std.mu.Unlock()
|
||||||
|
return std.Level
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddHook adds a hook to the standard logger hooks.
|
||||||
|
func AddHook(hook Hook) {
|
||||||
|
std.mu.Lock()
|
||||||
|
defer std.mu.Unlock()
|
||||||
|
std.Hooks.Add(hook)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
|
||||||
|
func WithError(err error) *Entry {
|
||||||
|
return std.WithField(ErrorKey, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithField creates an entry from the standard logger and adds a field to
|
||||||
|
// it. If you want multiple fields, use `WithFields`.
|
||||||
|
//
|
||||||
|
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||||
|
// or Panic on the Entry it returns.
|
||||||
|
func WithField(key string, value interface{}) *Entry {
|
||||||
|
return std.WithField(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithFields creates an entry from the standard logger and adds multiple
|
||||||
|
// fields to it. This is simply a helper for `WithField`, invoking it
|
||||||
|
// once for each field.
|
||||||
|
//
|
||||||
|
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
||||||
|
// or Panic on the Entry it returns.
|
||||||
|
func WithFields(fields Fields) *Entry {
|
||||||
|
return std.WithFields(fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug logs a message at level Debug on the standard logger.
|
||||||
|
func Debug(args ...interface{}) {
|
||||||
|
std.Debug(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print logs a message at level Info on the standard logger.
|
||||||
|
func Print(args ...interface{}) {
|
||||||
|
std.Print(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info logs a message at level Info on the standard logger.
|
||||||
|
func Info(args ...interface{}) {
|
||||||
|
std.Info(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warn logs a message at level Warn on the standard logger.
|
||||||
|
func Warn(args ...interface{}) {
|
||||||
|
std.Warn(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warning logs a message at level Warn on the standard logger.
|
||||||
|
func Warning(args ...interface{}) {
|
||||||
|
std.Warning(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error logs a message at level Error on the standard logger.
|
||||||
|
func Error(args ...interface{}) {
|
||||||
|
std.Error(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panic logs a message at level Panic on the standard logger.
|
||||||
|
func Panic(args ...interface{}) {
|
||||||
|
std.Panic(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatal logs a message at level Fatal on the standard logger.
|
||||||
|
func Fatal(args ...interface{}) {
|
||||||
|
std.Fatal(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debugf logs a message at level Debug on the standard logger.
|
||||||
|
func Debugf(format string, args ...interface{}) {
|
||||||
|
std.Debugf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Printf logs a message at level Info on the standard logger.
|
||||||
|
func Printf(format string, args ...interface{}) {
|
||||||
|
std.Printf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infof logs a message at level Info on the standard logger.
|
||||||
|
func Infof(format string, args ...interface{}) {
|
||||||
|
std.Infof(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warnf logs a message at level Warn on the standard logger.
|
||||||
|
func Warnf(format string, args ...interface{}) {
|
||||||
|
std.Warnf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warningf logs a message at level Warn on the standard logger.
|
||||||
|
func Warningf(format string, args ...interface{}) {
|
||||||
|
std.Warningf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorf logs a message at level Error on the standard logger.
|
||||||
|
func Errorf(format string, args ...interface{}) {
|
||||||
|
std.Errorf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panicf logs a message at level Panic on the standard logger.
|
||||||
|
func Panicf(format string, args ...interface{}) {
|
||||||
|
std.Panicf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatalf logs a message at level Fatal on the standard logger.
|
||||||
|
func Fatalf(format string, args ...interface{}) {
|
||||||
|
std.Fatalf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debugln logs a message at level Debug on the standard logger.
|
||||||
|
func Debugln(args ...interface{}) {
|
||||||
|
std.Debugln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Println logs a message at level Info on the standard logger.
|
||||||
|
func Println(args ...interface{}) {
|
||||||
|
std.Println(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infoln logs a message at level Info on the standard logger.
|
||||||
|
func Infoln(args ...interface{}) {
|
||||||
|
std.Infoln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warnln logs a message at level Warn on the standard logger.
|
||||||
|
func Warnln(args ...interface{}) {
|
||||||
|
std.Warnln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warningln logs a message at level Warn on the standard logger.
|
||||||
|
func Warningln(args ...interface{}) {
|
||||||
|
std.Warningln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorln logs a message at level Error on the standard logger.
|
||||||
|
func Errorln(args ...interface{}) {
|
||||||
|
std.Errorln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panicln logs a message at level Panic on the standard logger.
|
||||||
|
func Panicln(args ...interface{}) {
|
||||||
|
std.Panicln(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatalln logs a message at level Fatal on the standard logger.
|
||||||
|
func Fatalln(args ...interface{}) {
|
||||||
|
std.Fatalln(args...)
|
||||||
|
}
|
48
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/formatter.go
generated
vendored
Normal file
48
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/formatter.go
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package logrus
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
const DefaultTimestampFormat = time.RFC3339
|
||||||
|
|
||||||
|
// The Formatter interface is used to implement a custom Formatter. It takes an
|
||||||
|
// `Entry`. It exposes all the fields, including the default ones:
|
||||||
|
//
|
||||||
|
// * `entry.Data["msg"]`. The message passed from Info, Warn, Error ..
|
||||||
|
// * `entry.Data["time"]`. The timestamp.
|
||||||
|
// * `entry.Data["level"]. The level the entry was logged at.
|
||||||
|
//
|
||||||
|
// Any additional fields added with `WithField` or `WithFields` are also in
|
||||||
|
// `entry.Data`. Format is expected to return an array of bytes which are then
|
||||||
|
// logged to `logger.Out`.
|
||||||
|
type Formatter interface {
|
||||||
|
Format(*Entry) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is to not silently overwrite `time`, `msg` and `level` fields when
|
||||||
|
// dumping it. If this code wasn't there doing:
|
||||||
|
//
|
||||||
|
// logrus.WithField("level", 1).Info("hello")
|
||||||
|
//
|
||||||
|
// Would just silently drop the user provided level. Instead with this code
|
||||||
|
// it'll logged as:
|
||||||
|
//
|
||||||
|
// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
|
||||||
|
//
|
||||||
|
// It's not exported because it's still using Data in an opinionated way. It's to
|
||||||
|
// avoid code duplication between the two default formatters.
|
||||||
|
func prefixFieldClashes(data Fields) {
|
||||||
|
_, ok := data["time"]
|
||||||
|
if ok {
|
||||||
|
data["fields.time"] = data["time"]
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok = data["msg"]
|
||||||
|
if ok {
|
||||||
|
data["fields.msg"] = data["msg"]
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok = data["level"]
|
||||||
|
if ok {
|
||||||
|
data["fields.level"] = data["level"]
|
||||||
|
}
|
||||||
|
}
|
56
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash.go
generated
vendored
Normal file
56
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/formatters/logstash/logstash.go
generated
vendored
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package logstash
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Formatter generates json in logstash format.
|
||||||
|
// Logstash site: http://logstash.net/
|
||||||
|
type LogstashFormatter struct {
|
||||||
|
Type string // if not empty use for logstash type field.
|
||||||
|
|
||||||
|
// TimestampFormat sets the format used for timestamps.
|
||||||
|
TimestampFormat string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *LogstashFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
||||||
|
entry.Data["@version"] = 1
|
||||||
|
|
||||||
|
if f.TimestampFormat == "" {
|
||||||
|
f.TimestampFormat = logrus.DefaultTimestampFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.Data["@timestamp"] = entry.Time.Format(f.TimestampFormat)
|
||||||
|
|
||||||
|
// set message field
|
||||||
|
v, ok := entry.Data["message"]
|
||||||
|
if ok {
|
||||||
|
entry.Data["fields.message"] = v
|
||||||
|
}
|
||||||
|
entry.Data["message"] = entry.Message
|
||||||
|
|
||||||
|
// set level field
|
||||||
|
v, ok = entry.Data["level"]
|
||||||
|
if ok {
|
||||||
|
entry.Data["fields.level"] = v
|
||||||
|
}
|
||||||
|
entry.Data["level"] = entry.Level.String()
|
||||||
|
|
||||||
|
// set type field
|
||||||
|
if f.Type != "" {
|
||||||
|
v, ok = entry.Data["type"]
|
||||||
|
if ok {
|
||||||
|
entry.Data["fields.type"] = v
|
||||||
|
}
|
||||||
|
entry.Data["type"] = f.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
serialized, err := json.Marshal(entry.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
||||||
|
}
|
||||||
|
return append(serialized, '\n'), nil
|
||||||
|
}
|
34
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/hooks.go
generated
vendored
Normal file
34
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/hooks.go
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package logrus
|
||||||
|
|
||||||
|
// A hook to be fired when logging on the logging levels returned from
|
||||||
|
// `Levels()` on your implementation of the interface. Note that this is not
|
||||||
|
// fired in a goroutine or a channel with workers, you should handle such
|
||||||
|
// functionality yourself if your call is non-blocking and you don't wish for
|
||||||
|
// the logging calls for levels returned from `Levels()` to block.
|
||||||
|
type Hook interface {
|
||||||
|
Levels() []Level
|
||||||
|
Fire(*Entry) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal type for storing the hooks on a logger instance.
|
||||||
|
type LevelHooks map[Level][]Hook
|
||||||
|
|
||||||
|
// Add a hook to an instance of logger. This is called with
|
||||||
|
// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface.
|
||||||
|
func (hooks LevelHooks) Add(hook Hook) {
|
||||||
|
for _, level := range hook.Levels() {
|
||||||
|
hooks[level] = append(hooks[level], hook)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire all the hooks for the passed level. Used by `entry.log` to fire
|
||||||
|
// appropriate hooks for a log entry.
|
||||||
|
func (hooks LevelHooks) Fire(level Level, entry *Entry) error {
|
||||||
|
for _, hook := range hooks[level] {
|
||||||
|
if err := hook.Fire(entry); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
54
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go
generated
vendored
Normal file
54
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package airbrake
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/tobi/airbrake-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AirbrakeHook to send exceptions to an exception-tracking service compatible
|
||||||
|
// with the Airbrake API.
|
||||||
|
type airbrakeHook struct {
|
||||||
|
APIKey string
|
||||||
|
Endpoint string
|
||||||
|
Environment string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHook(endpoint, apiKey, env string) *airbrakeHook {
|
||||||
|
return &airbrakeHook{
|
||||||
|
APIKey: apiKey,
|
||||||
|
Endpoint: endpoint,
|
||||||
|
Environment: env,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hook *airbrakeHook) Fire(entry *logrus.Entry) error {
|
||||||
|
airbrake.ApiKey = hook.APIKey
|
||||||
|
airbrake.Endpoint = hook.Endpoint
|
||||||
|
airbrake.Environment = hook.Environment
|
||||||
|
|
||||||
|
var notifyErr error
|
||||||
|
err, ok := entry.Data["error"].(error)
|
||||||
|
if ok {
|
||||||
|
notifyErr = err
|
||||||
|
} else {
|
||||||
|
notifyErr = errors.New(entry.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
airErr := airbrake.Notify(notifyErr)
|
||||||
|
if airErr != nil {
|
||||||
|
return fmt.Errorf("Failed to send error to Airbrake: %s", airErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hook *airbrakeHook) Levels() []logrus.Level {
|
||||||
|
return []logrus.Level{
|
||||||
|
logrus.ErrorLevel,
|
||||||
|
logrus.FatalLevel,
|
||||||
|
logrus.PanicLevel,
|
||||||
|
}
|
||||||
|
}
|
68
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag.go
generated
vendored
Normal file
68
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag.go
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
package logrus_bugsnag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/bugsnag/bugsnag-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
type bugsnagHook struct{}
|
||||||
|
|
||||||
|
// ErrBugsnagUnconfigured is returned if NewBugsnagHook is called before
|
||||||
|
// bugsnag.Configure. Bugsnag must be configured before the hook.
|
||||||
|
var ErrBugsnagUnconfigured = errors.New("bugsnag must be configured before installing this logrus hook")
|
||||||
|
|
||||||
|
// ErrBugsnagSendFailed indicates that the hook failed to submit an error to
|
||||||
|
// bugsnag. The error was successfully generated, but `bugsnag.Notify()`
|
||||||
|
// failed.
|
||||||
|
type ErrBugsnagSendFailed struct {
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrBugsnagSendFailed) Error() string {
|
||||||
|
return "failed to send error to Bugsnag: " + e.err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBugsnagHook initializes a logrus hook which sends exceptions to an
|
||||||
|
// exception-tracking service compatible with the Bugsnag API. Before using
|
||||||
|
// this hook, you must call bugsnag.Configure(). The returned object should be
|
||||||
|
// registered with a log via `AddHook()`
|
||||||
|
//
|
||||||
|
// Entries that trigger an Error, Fatal or Panic should now include an "error"
|
||||||
|
// field to send to Bugsnag.
|
||||||
|
func NewBugsnagHook() (*bugsnagHook, error) {
|
||||||
|
if bugsnag.Config.APIKey == "" {
|
||||||
|
return nil, ErrBugsnagUnconfigured
|
||||||
|
}
|
||||||
|
return &bugsnagHook{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire forwards an error to Bugsnag. Given a logrus.Entry, it extracts the
|
||||||
|
// "error" field (or the Message if the error isn't present) and sends it off.
|
||||||
|
func (hook *bugsnagHook) Fire(entry *logrus.Entry) error {
|
||||||
|
var notifyErr error
|
||||||
|
err, ok := entry.Data["error"].(error)
|
||||||
|
if ok {
|
||||||
|
notifyErr = err
|
||||||
|
} else {
|
||||||
|
notifyErr = errors.New(entry.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
bugsnagErr := bugsnag.Notify(notifyErr)
|
||||||
|
if bugsnagErr != nil {
|
||||||
|
return ErrBugsnagSendFailed{bugsnagErr}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Levels enumerates the log levels on which the error should be forwarded to
|
||||||
|
// bugsnag: everything at or above the "Error" level.
|
||||||
|
func (hook *bugsnagHook) Levels() []logrus.Level {
|
||||||
|
return []logrus.Level{
|
||||||
|
logrus.ErrorLevel,
|
||||||
|
logrus.FatalLevel,
|
||||||
|
logrus.PanicLevel,
|
||||||
|
}
|
||||||
|
}
|
28
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/hooks/papertrail/README.md
generated
vendored
Normal file
28
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/hooks/papertrail/README.md
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Papertrail Hook for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:" />
|
||||||
|
|
||||||
|
[Papertrail](https://papertrailapp.com) provides hosted log management. Once stored in Papertrail, you can [group](http://help.papertrailapp.com/kb/how-it-works/groups/) your logs on various dimensions, [search](http://help.papertrailapp.com/kb/how-it-works/search-syntax) them, and trigger [alerts](http://help.papertrailapp.com/kb/how-it-works/alerts).
|
||||||
|
|
||||||
|
In most deployments, you'll want to send logs to Papertrail via their [remote_syslog](http://help.papertrailapp.com/kb/configuration/configuring-centralized-logging-from-text-log-files-in-unix/) daemon, which requires no application-specific configuration. This hook is intended for relatively low-volume logging, likely in managed cloud hosting deployments where installing `remote_syslog` is not possible.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
You can find your Papertrail UDP port on your [Papertrail account page](https://papertrailapp.com/account/destinations). Substitute it below for `YOUR_PAPERTRAIL_UDP_PORT`.
|
||||||
|
|
||||||
|
For `YOUR_APP_NAME`, substitute a short string that will readily identify your application or service in the logs.
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"log/syslog"
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/Sirupsen/logrus/hooks/papertrail"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log := logrus.New()
|
||||||
|
hook, err := logrus_papertrail.NewPapertrailHook("logs.papertrailapp.com", YOUR_PAPERTRAIL_UDP_PORT, YOUR_APP_NAME)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
log.Hooks.Add(hook)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
55
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go
generated
vendored
Normal file
55
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package logrus_papertrail
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
format = "Jan 2 15:04:05"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PapertrailHook to send logs to a logging service compatible with the Papertrail API.
|
||||||
|
type PapertrailHook struct {
|
||||||
|
Host string
|
||||||
|
Port int
|
||||||
|
AppName string
|
||||||
|
UDPConn net.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPapertrailHook creates a hook to be added to an instance of logger.
|
||||||
|
func NewPapertrailHook(host string, port int, appName string) (*PapertrailHook, error) {
|
||||||
|
conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", host, port))
|
||||||
|
return &PapertrailHook{host, port, appName, conn}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire is called when a log event is fired.
|
||||||
|
func (hook *PapertrailHook) Fire(entry *logrus.Entry) error {
|
||||||
|
date := time.Now().Format(format)
|
||||||
|
msg, _ := entry.String()
|
||||||
|
payload := fmt.Sprintf("<22> %s %s: %s", date, hook.AppName, msg)
|
||||||
|
|
||||||
|
bytesWritten, err := hook.UDPConn.Write([]byte(payload))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Unable to send log line to Papertrail via UDP. Wrote %d bytes before error: %v", bytesWritten, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Levels returns the available logging levels.
|
||||||
|
func (hook *PapertrailHook) Levels() []logrus.Level {
|
||||||
|
return []logrus.Level{
|
||||||
|
logrus.PanicLevel,
|
||||||
|
logrus.FatalLevel,
|
||||||
|
logrus.ErrorLevel,
|
||||||
|
logrus.WarnLevel,
|
||||||
|
logrus.InfoLevel,
|
||||||
|
logrus.DebugLevel,
|
||||||
|
}
|
||||||
|
}
|
111
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/hooks/sentry/README.md
generated
vendored
Normal file
111
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/hooks/sentry/README.md
generated
vendored
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
# Sentry Hook for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:" />
|
||||||
|
|
||||||
|
[Sentry](https://getsentry.com) provides both self-hosted and hosted
|
||||||
|
solutions for exception tracking.
|
||||||
|
Both client and server are
|
||||||
|
[open source](https://github.com/getsentry/sentry).
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Every sentry application defined on the server gets a different
|
||||||
|
[DSN](https://www.getsentry.com/docs/). In the example below replace
|
||||||
|
`YOUR_DSN` with the one created for your application.
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/Sirupsen/logrus/hooks/sentry"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log := logrus.New()
|
||||||
|
hook, err := logrus_sentry.NewSentryHook(YOUR_DSN, []logrus.Level{
|
||||||
|
logrus.PanicLevel,
|
||||||
|
logrus.FatalLevel,
|
||||||
|
logrus.ErrorLevel,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
log.Hooks.Add(hook)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If you wish to initialize a SentryHook with tags, you can use the `NewWithTagsSentryHook` constructor to provide default tags:
|
||||||
|
|
||||||
|
```go
|
||||||
|
tags := map[string]string{
|
||||||
|
"site": "example.com",
|
||||||
|
}
|
||||||
|
levels := []logrus.Level{
|
||||||
|
logrus.PanicLevel,
|
||||||
|
logrus.FatalLevel,
|
||||||
|
logrus.ErrorLevel,
|
||||||
|
}
|
||||||
|
hook, err := logrus_sentry.NewWithTagsSentryHook(YOUR_DSN, tags, levels)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
If you wish to initialize a SentryHook with an already initialized raven client, you can use
|
||||||
|
the `NewWithClientSentryHook` constructor:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/Sirupsen/logrus/hooks/sentry"
|
||||||
|
"github.com/getsentry/raven-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log := logrus.New()
|
||||||
|
|
||||||
|
client, err := raven.New(YOUR_DSN)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hook, err := logrus_sentry.NewWithClientSentryHook(client, []logrus.Level{
|
||||||
|
logrus.PanicLevel,
|
||||||
|
logrus.FatalLevel,
|
||||||
|
logrus.ErrorLevel,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
log.Hooks.Add(hook)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hook, err := NewWithClientSentryHook(client, []logrus.Level{
|
||||||
|
logrus.ErrorLevel,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Special fields
|
||||||
|
|
||||||
|
Some logrus fields have a special meaning in this hook,
|
||||||
|
these are `server_name`, `logger` and `http_request`.
|
||||||
|
When logs are sent to sentry these fields are treated differently.
|
||||||
|
- `server_name` (also known as hostname) is the name of the server which
|
||||||
|
is logging the event (hostname.example.com)
|
||||||
|
- `logger` is the part of the application which is logging the event.
|
||||||
|
In go this usually means setting it to the name of the package.
|
||||||
|
- `http_request` is the in-coming request(*http.Request). The detailed request data are sent to Sentry.
|
||||||
|
|
||||||
|
## Timeout
|
||||||
|
|
||||||
|
`Timeout` is the time the sentry hook will wait for a response
|
||||||
|
from the sentry server.
|
||||||
|
|
||||||
|
If this time elapses with no response from
|
||||||
|
the server an error will be returned.
|
||||||
|
|
||||||
|
If `Timeout` is set to 0 the SentryHook will not wait for a reply
|
||||||
|
and will assume a correct delivery.
|
||||||
|
|
||||||
|
The SentryHook has a default timeout of `100 milliseconds` when created
|
||||||
|
with a call to `NewSentryHook`. This can be changed by assigning a value to the `Timeout` field:
|
||||||
|
|
||||||
|
```go
|
||||||
|
hook, _ := logrus_sentry.NewSentryHook(...)
|
||||||
|
hook.Timeout = 20*time.Second
|
||||||
|
```
|
137
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/hooks/sentry/sentry.go
generated
vendored
Normal file
137
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/hooks/sentry/sentry.go
generated
vendored
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
package logrus_sentry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/getsentry/raven-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
severityMap = map[logrus.Level]raven.Severity{
|
||||||
|
logrus.DebugLevel: raven.DEBUG,
|
||||||
|
logrus.InfoLevel: raven.INFO,
|
||||||
|
logrus.WarnLevel: raven.WARNING,
|
||||||
|
logrus.ErrorLevel: raven.ERROR,
|
||||||
|
logrus.FatalLevel: raven.FATAL,
|
||||||
|
logrus.PanicLevel: raven.FATAL,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func getAndDel(d logrus.Fields, key string) (string, bool) {
|
||||||
|
var (
|
||||||
|
ok bool
|
||||||
|
v interface{}
|
||||||
|
val string
|
||||||
|
)
|
||||||
|
if v, ok = d[key]; !ok {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, ok = v.(string); !ok {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
delete(d, key)
|
||||||
|
return val, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAndDelRequest(d logrus.Fields, key string) (*http.Request, bool) {
|
||||||
|
var (
|
||||||
|
ok bool
|
||||||
|
v interface{}
|
||||||
|
req *http.Request
|
||||||
|
)
|
||||||
|
if v, ok = d[key]; !ok {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
if req, ok = v.(*http.Request); !ok || req == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
delete(d, key)
|
||||||
|
return req, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// SentryHook delivers logs to a sentry server.
|
||||||
|
type SentryHook struct {
|
||||||
|
// Timeout sets the time to wait for a delivery error from the sentry server.
|
||||||
|
// If this is set to zero the server will not wait for any response and will
|
||||||
|
// consider the message correctly sent
|
||||||
|
Timeout time.Duration
|
||||||
|
|
||||||
|
client *raven.Client
|
||||||
|
levels []logrus.Level
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSentryHook creates a hook to be added to an instance of logger
|
||||||
|
// and initializes the raven client.
|
||||||
|
// This method sets the timeout to 100 milliseconds.
|
||||||
|
func NewSentryHook(DSN string, levels []logrus.Level) (*SentryHook, error) {
|
||||||
|
client, err := raven.New(DSN)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &SentryHook{100 * time.Millisecond, client, levels}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWithTagsSentryHook creates a hook with tags to be added to an instance
|
||||||
|
// of logger and initializes the raven client. This method sets the timeout to
|
||||||
|
// 100 milliseconds.
|
||||||
|
func NewWithTagsSentryHook(DSN string, tags map[string]string, levels []logrus.Level) (*SentryHook, error) {
|
||||||
|
client, err := raven.NewWithTags(DSN, tags)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &SentryHook{100 * time.Millisecond, client, levels}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWithClientSentryHook creates a hook using an initialized raven client.
|
||||||
|
// This method sets the timeout to 100 milliseconds.
|
||||||
|
func NewWithClientSentryHook(client *raven.Client, levels []logrus.Level) (*SentryHook, error) {
|
||||||
|
return &SentryHook{100 * time.Millisecond, client, levels}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when an event should be sent to sentry
|
||||||
|
// Special fields that sentry uses to give more information to the server
|
||||||
|
// are extracted from entry.Data (if they are found)
|
||||||
|
// These fields are: logger, server_name and http_request
|
||||||
|
func (hook *SentryHook) Fire(entry *logrus.Entry) error {
|
||||||
|
packet := &raven.Packet{
|
||||||
|
Message: entry.Message,
|
||||||
|
Timestamp: raven.Timestamp(entry.Time),
|
||||||
|
Level: severityMap[entry.Level],
|
||||||
|
Platform: "go",
|
||||||
|
}
|
||||||
|
|
||||||
|
d := entry.Data
|
||||||
|
|
||||||
|
if logger, ok := getAndDel(d, "logger"); ok {
|
||||||
|
packet.Logger = logger
|
||||||
|
}
|
||||||
|
if serverName, ok := getAndDel(d, "server_name"); ok {
|
||||||
|
packet.ServerName = serverName
|
||||||
|
}
|
||||||
|
if req, ok := getAndDelRequest(d, "http_request"); ok {
|
||||||
|
packet.Interfaces = append(packet.Interfaces, raven.NewHttp(req))
|
||||||
|
}
|
||||||
|
packet.Extra = map[string]interface{}(d)
|
||||||
|
|
||||||
|
_, errCh := hook.client.Capture(packet, nil)
|
||||||
|
timeout := hook.Timeout
|
||||||
|
if timeout != 0 {
|
||||||
|
timeoutCh := time.After(timeout)
|
||||||
|
select {
|
||||||
|
case err := <-errCh:
|
||||||
|
return err
|
||||||
|
case <-timeoutCh:
|
||||||
|
return fmt.Errorf("no response from sentry server in %s", timeout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Levels returns the available logging levels.
|
||||||
|
func (hook *SentryHook) Levels() []logrus.Level {
|
||||||
|
return hook.levels
|
||||||
|
}
|
20
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md
generated
vendored
Normal file
20
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Syslog Hooks for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"log/syslog"
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log := logrus.New()
|
||||||
|
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
log.Hooks.Add(hook)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
59
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
generated
vendored
Normal file
59
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
generated
vendored
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package logrus_syslog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"log/syslog"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SyslogHook to send logs via syslog.
|
||||||
|
type SyslogHook struct {
|
||||||
|
Writer *syslog.Writer
|
||||||
|
SyslogNetwork string
|
||||||
|
SyslogRaddr string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a hook to be added to an instance of logger. This is called with
|
||||||
|
// `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")`
|
||||||
|
// `if err == nil { log.Hooks.Add(hook) }`
|
||||||
|
func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) {
|
||||||
|
w, err := syslog.Dial(network, raddr, priority, tag)
|
||||||
|
return &SyslogHook{w, network, raddr}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hook *SyslogHook) Fire(entry *logrus.Entry) error {
|
||||||
|
line, err := entry.String()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch entry.Level {
|
||||||
|
case logrus.PanicLevel:
|
||||||
|
return hook.Writer.Crit(line)
|
||||||
|
case logrus.FatalLevel:
|
||||||
|
return hook.Writer.Crit(line)
|
||||||
|
case logrus.ErrorLevel:
|
||||||
|
return hook.Writer.Err(line)
|
||||||
|
case logrus.WarnLevel:
|
||||||
|
return hook.Writer.Warning(line)
|
||||||
|
case logrus.InfoLevel:
|
||||||
|
return hook.Writer.Info(line)
|
||||||
|
case logrus.DebugLevel:
|
||||||
|
return hook.Writer.Debug(line)
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hook *SyslogHook) Levels() []logrus.Level {
|
||||||
|
return []logrus.Level{
|
||||||
|
logrus.PanicLevel,
|
||||||
|
logrus.FatalLevel,
|
||||||
|
logrus.ErrorLevel,
|
||||||
|
logrus.WarnLevel,
|
||||||
|
logrus.InfoLevel,
|
||||||
|
logrus.DebugLevel,
|
||||||
|
}
|
||||||
|
}
|
41
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/json_formatter.go
generated
vendored
Normal file
41
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/json_formatter.go
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type JSONFormatter struct {
|
||||||
|
// TimestampFormat sets the format used for marshaling timestamps.
|
||||||
|
TimestampFormat string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
|
data := make(Fields, len(entry.Data)+3)
|
||||||
|
for k, v := range entry.Data {
|
||||||
|
switch v := v.(type) {
|
||||||
|
case error:
|
||||||
|
// Otherwise errors are ignored by `encoding/json`
|
||||||
|
// https://github.com/Sirupsen/logrus/issues/137
|
||||||
|
data[k] = v.Error()
|
||||||
|
default:
|
||||||
|
data[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prefixFieldClashes(data)
|
||||||
|
|
||||||
|
timestampFormat := f.TimestampFormat
|
||||||
|
if timestampFormat == "" {
|
||||||
|
timestampFormat = DefaultTimestampFormat
|
||||||
|
}
|
||||||
|
|
||||||
|
data["time"] = entry.Time.Format(timestampFormat)
|
||||||
|
data["msg"] = entry.Message
|
||||||
|
data["level"] = entry.Level.String()
|
||||||
|
|
||||||
|
serialized, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err)
|
||||||
|
}
|
||||||
|
return append(serialized, '\n'), nil
|
||||||
|
}
|
206
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/logger.go
generated
vendored
Normal file
206
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/logger.go
generated
vendored
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Logger struct {
|
||||||
|
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
|
||||||
|
// file, or leave it default which is `os.Stderr`. You can also set this to
|
||||||
|
// something more adventorous, such as logging to Kafka.
|
||||||
|
Out io.Writer
|
||||||
|
// Hooks for the logger instance. These allow firing events based on logging
|
||||||
|
// levels and log entries. For example, to send errors to an error tracking
|
||||||
|
// service, log to StatsD or dump the core on fatal errors.
|
||||||
|
Hooks LevelHooks
|
||||||
|
// All log entries pass through the formatter before logged to Out. The
|
||||||
|
// included formatters are `TextFormatter` and `JSONFormatter` for which
|
||||||
|
// TextFormatter is the default. In development (when a TTY is attached) it
|
||||||
|
// logs with colors, but to a file it wouldn't. You can easily implement your
|
||||||
|
// own that implements the `Formatter` interface, see the `README` or included
|
||||||
|
// formatters for examples.
|
||||||
|
Formatter Formatter
|
||||||
|
// The logging level the logger should log at. This is typically (and defaults
|
||||||
|
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
|
||||||
|
// logged. `logrus.Debug` is useful in
|
||||||
|
Level Level
|
||||||
|
// Used to sync writing to the log.
|
||||||
|
mu sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a new logger. Configuration should be set by changing `Formatter`,
|
||||||
|
// `Out` and `Hooks` directly on the default logger instance. You can also just
|
||||||
|
// instantiate your own:
|
||||||
|
//
|
||||||
|
// var log = &Logger{
|
||||||
|
// Out: os.Stderr,
|
||||||
|
// Formatter: new(JSONFormatter),
|
||||||
|
// Hooks: make(LevelHooks),
|
||||||
|
// Level: logrus.DebugLevel,
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// It's recommended to make this a global instance called `log`.
|
||||||
|
func New() *Logger {
|
||||||
|
return &Logger{
|
||||||
|
Out: os.Stderr,
|
||||||
|
Formatter: new(TextFormatter),
|
||||||
|
Hooks: make(LevelHooks),
|
||||||
|
Level: InfoLevel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a field to the log entry, note that you it doesn't log until you call
|
||||||
|
// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
|
||||||
|
// If you want multiple fields, use `WithFields`.
|
||||||
|
func (logger *Logger) WithField(key string, value interface{}) *Entry {
|
||||||
|
return NewEntry(logger).WithField(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a struct of fields to the log entry. All it does is call `WithField` for
|
||||||
|
// each `Field`.
|
||||||
|
func (logger *Logger) WithFields(fields Fields) *Entry {
|
||||||
|
return NewEntry(logger).WithFields(fields)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= DebugLevel {
|
||||||
|
NewEntry(logger).Debugf(format, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Infof(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= InfoLevel {
|
||||||
|
NewEntry(logger).Infof(format, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Printf(format string, args ...interface{}) {
|
||||||
|
NewEntry(logger).Printf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warnf(format, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warnf(format, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= ErrorLevel {
|
||||||
|
NewEntry(logger).Errorf(format, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= FatalLevel {
|
||||||
|
NewEntry(logger).Fatalf(format, args...)
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
||||||
|
if logger.Level >= PanicLevel {
|
||||||
|
NewEntry(logger).Panicf(format, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Debug(args ...interface{}) {
|
||||||
|
if logger.Level >= DebugLevel {
|
||||||
|
NewEntry(logger).Debug(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Info(args ...interface{}) {
|
||||||
|
if logger.Level >= InfoLevel {
|
||||||
|
NewEntry(logger).Info(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Print(args ...interface{}) {
|
||||||
|
NewEntry(logger).Info(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warn(args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warn(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warning(args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warn(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Error(args ...interface{}) {
|
||||||
|
if logger.Level >= ErrorLevel {
|
||||||
|
NewEntry(logger).Error(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Fatal(args ...interface{}) {
|
||||||
|
if logger.Level >= FatalLevel {
|
||||||
|
NewEntry(logger).Fatal(args...)
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Panic(args ...interface{}) {
|
||||||
|
if logger.Level >= PanicLevel {
|
||||||
|
NewEntry(logger).Panic(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Debugln(args ...interface{}) {
|
||||||
|
if logger.Level >= DebugLevel {
|
||||||
|
NewEntry(logger).Debugln(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Infoln(args ...interface{}) {
|
||||||
|
if logger.Level >= InfoLevel {
|
||||||
|
NewEntry(logger).Infoln(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Println(args ...interface{}) {
|
||||||
|
NewEntry(logger).Println(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warnln(args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warnln(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Warningln(args ...interface{}) {
|
||||||
|
if logger.Level >= WarnLevel {
|
||||||
|
NewEntry(logger).Warnln(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Errorln(args ...interface{}) {
|
||||||
|
if logger.Level >= ErrorLevel {
|
||||||
|
NewEntry(logger).Errorln(args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Fatalln(args ...interface{}) {
|
||||||
|
if logger.Level >= FatalLevel {
|
||||||
|
NewEntry(logger).Fatalln(args...)
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) Panicln(args ...interface{}) {
|
||||||
|
if logger.Level >= PanicLevel {
|
||||||
|
NewEntry(logger).Panicln(args...)
|
||||||
|
}
|
||||||
|
}
|
98
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/logrus.go
generated
vendored
Normal file
98
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/logrus.go
generated
vendored
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Fields type, used to pass to `WithFields`.
|
||||||
|
type Fields map[string]interface{}
|
||||||
|
|
||||||
|
// Level type
|
||||||
|
type Level uint8
|
||||||
|
|
||||||
|
// Convert the Level to a string. E.g. PanicLevel becomes "panic".
|
||||||
|
func (level Level) String() string {
|
||||||
|
switch level {
|
||||||
|
case DebugLevel:
|
||||||
|
return "debug"
|
||||||
|
case InfoLevel:
|
||||||
|
return "info"
|
||||||
|
case WarnLevel:
|
||||||
|
return "warning"
|
||||||
|
case ErrorLevel:
|
||||||
|
return "error"
|
||||||
|
case FatalLevel:
|
||||||
|
return "fatal"
|
||||||
|
case PanicLevel:
|
||||||
|
return "panic"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseLevel takes a string level and returns the Logrus log level constant.
|
||||||
|
func ParseLevel(lvl string) (Level, error) {
|
||||||
|
switch lvl {
|
||||||
|
case "panic":
|
||||||
|
return PanicLevel, nil
|
||||||
|
case "fatal":
|
||||||
|
return FatalLevel, nil
|
||||||
|
case "error":
|
||||||
|
return ErrorLevel, nil
|
||||||
|
case "warn", "warning":
|
||||||
|
return WarnLevel, nil
|
||||||
|
case "info":
|
||||||
|
return InfoLevel, nil
|
||||||
|
case "debug":
|
||||||
|
return DebugLevel, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var l Level
|
||||||
|
return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are the different logging levels. You can set the logging level to log
|
||||||
|
// on your instance of logger, obtained with `logrus.New()`.
|
||||||
|
const (
|
||||||
|
// PanicLevel level, highest level of severity. Logs and then calls panic with the
|
||||||
|
// message passed to Debug, Info, ...
|
||||||
|
PanicLevel Level = iota
|
||||||
|
// FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the
|
||||||
|
// logging level is set to Panic.
|
||||||
|
FatalLevel
|
||||||
|
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
|
||||||
|
// Commonly used for hooks to send errors to an error tracking service.
|
||||||
|
ErrorLevel
|
||||||
|
// WarnLevel level. Non-critical entries that deserve eyes.
|
||||||
|
WarnLevel
|
||||||
|
// InfoLevel level. General operational entries about what's going on inside the
|
||||||
|
// application.
|
||||||
|
InfoLevel
|
||||||
|
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
|
||||||
|
DebugLevel
|
||||||
|
)
|
||||||
|
|
||||||
|
// Won't compile if StdLogger can't be realized by a log.Logger
|
||||||
|
var (
|
||||||
|
_ StdLogger = &log.Logger{}
|
||||||
|
_ StdLogger = &Entry{}
|
||||||
|
_ StdLogger = &Logger{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// StdLogger is what your logrus-enabled library should take, that way
|
||||||
|
// it'll accept a stdlib logger and a logrus logger. There's no standard
|
||||||
|
// interface, this is the closest we get, unfortunately.
|
||||||
|
type StdLogger interface {
|
||||||
|
Print(...interface{})
|
||||||
|
Printf(string, ...interface{})
|
||||||
|
Println(...interface{})
|
||||||
|
|
||||||
|
Fatal(...interface{})
|
||||||
|
Fatalf(string, ...interface{})
|
||||||
|
Fatalln(...interface{})
|
||||||
|
|
||||||
|
Panic(...interface{})
|
||||||
|
Panicf(string, ...interface{})
|
||||||
|
Panicln(...interface{})
|
||||||
|
}
|
9
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/terminal_bsd.go
generated
vendored
Normal file
9
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/terminal_bsd.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// +build darwin freebsd openbsd netbsd dragonfly
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
const ioctlReadTermios = syscall.TIOCGETA
|
||||||
|
|
||||||
|
type Termios syscall.Termios
|
12
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/terminal_linux.go
generated
vendored
Normal file
12
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/terminal_linux.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// Based on ssh/terminal:
|
||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
const ioctlReadTermios = syscall.TCGETS
|
||||||
|
|
||||||
|
type Termios syscall.Termios
|
21
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
generated
vendored
Normal file
21
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/terminal_notwindows.go
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Based on ssh/terminal:
|
||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build linux darwin freebsd openbsd netbsd dragonfly
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||||
|
func IsTerminal() bool {
|
||||||
|
fd := syscall.Stdout
|
||||||
|
var termios Termios
|
||||||
|
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
|
||||||
|
return err == 0
|
||||||
|
}
|
27
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/terminal_windows.go
generated
vendored
Normal file
27
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/terminal_windows.go
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Based on ssh/terminal:
|
||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||||
|
|
||||||
|
var (
|
||||||
|
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||||
|
func IsTerminal() bool {
|
||||||
|
fd := syscall.Stdout
|
||||||
|
var st uint32
|
||||||
|
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
|
||||||
|
return r != 0 && e == 0
|
||||||
|
}
|
159
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/text_formatter.go
generated
vendored
Normal file
159
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/text_formatter.go
generated
vendored
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
nocolor = 0
|
||||||
|
red = 31
|
||||||
|
green = 32
|
||||||
|
yellow = 33
|
||||||
|
blue = 34
|
||||||
|
gray = 37
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
baseTimestamp time.Time
|
||||||
|
isTerminal bool
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
baseTimestamp = time.Now()
|
||||||
|
isTerminal = IsTerminal()
|
||||||
|
}
|
||||||
|
|
||||||
|
func miniTS() int {
|
||||||
|
return int(time.Since(baseTimestamp) / time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
type TextFormatter struct {
|
||||||
|
// Set to true to bypass checking for a TTY before outputting colors.
|
||||||
|
ForceColors bool
|
||||||
|
|
||||||
|
// Force disabling colors.
|
||||||
|
DisableColors bool
|
||||||
|
|
||||||
|
// Disable timestamp logging. useful when output is redirected to logging
|
||||||
|
// system that already adds timestamps.
|
||||||
|
DisableTimestamp bool
|
||||||
|
|
||||||
|
// Enable logging the full timestamp when a TTY is attached instead of just
|
||||||
|
// the time passed since beginning of execution.
|
||||||
|
FullTimestamp bool
|
||||||
|
|
||||||
|
// TimestampFormat to use for display when a full timestamp is printed
|
||||||
|
TimestampFormat string
|
||||||
|
|
||||||
|
// The fields are sorted by default for a consistent output. For applications
|
||||||
|
// that log extremely frequently and don't use the JSON formatter this may not
|
||||||
|
// be desired.
|
||||||
|
DisableSorting bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||||
|
var keys []string = make([]string, 0, len(entry.Data))
|
||||||
|
for k := range entry.Data {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !f.DisableSorting {
|
||||||
|
sort.Strings(keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
b := &bytes.Buffer{}
|
||||||
|
|
||||||
|
prefixFieldClashes(entry.Data)
|
||||||
|
|
||||||
|
isColorTerminal := isTerminal && (runtime.GOOS != "windows")
|
||||||
|
isColored := (f.ForceColors || isColorTerminal) && !f.DisableColors
|
||||||
|
|
||||||
|
timestampFormat := f.TimestampFormat
|
||||||
|
if timestampFormat == "" {
|
||||||
|
timestampFormat = DefaultTimestampFormat
|
||||||
|
}
|
||||||
|
if isColored {
|
||||||
|
f.printColored(b, entry, keys, timestampFormat)
|
||||||
|
} else {
|
||||||
|
if !f.DisableTimestamp {
|
||||||
|
f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat))
|
||||||
|
}
|
||||||
|
f.appendKeyValue(b, "level", entry.Level.String())
|
||||||
|
f.appendKeyValue(b, "msg", entry.Message)
|
||||||
|
for _, key := range keys {
|
||||||
|
f.appendKeyValue(b, key, entry.Data[key])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b.WriteByte('\n')
|
||||||
|
return b.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) {
|
||||||
|
var levelColor int
|
||||||
|
switch entry.Level {
|
||||||
|
case DebugLevel:
|
||||||
|
levelColor = gray
|
||||||
|
case WarnLevel:
|
||||||
|
levelColor = yellow
|
||||||
|
case ErrorLevel, FatalLevel, PanicLevel:
|
||||||
|
levelColor = red
|
||||||
|
default:
|
||||||
|
levelColor = blue
|
||||||
|
}
|
||||||
|
|
||||||
|
levelText := strings.ToUpper(entry.Level.String())[0:4]
|
||||||
|
|
||||||
|
if !f.FullTimestamp {
|
||||||
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message)
|
||||||
|
}
|
||||||
|
for _, k := range keys {
|
||||||
|
v := entry.Data[k]
|
||||||
|
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%+v", levelColor, k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func needsQuoting(text string) bool {
|
||||||
|
for _, ch := range text {
|
||||||
|
if !((ch >= 'a' && ch <= 'z') ||
|
||||||
|
(ch >= 'A' && ch <= 'Z') ||
|
||||||
|
(ch >= '0' && ch <= '9') ||
|
||||||
|
ch == '-' || ch == '.') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
|
||||||
|
|
||||||
|
b.WriteString(key)
|
||||||
|
b.WriteByte('=')
|
||||||
|
|
||||||
|
switch value := value.(type) {
|
||||||
|
case string:
|
||||||
|
if needsQuoting(value) {
|
||||||
|
b.WriteString(value)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(b, "%q", value)
|
||||||
|
}
|
||||||
|
case error:
|
||||||
|
errmsg := value.Error()
|
||||||
|
if needsQuoting(errmsg) {
|
||||||
|
b.WriteString(errmsg)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(b, "%q", value)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
fmt.Fprint(b, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.WriteByte(' ')
|
||||||
|
}
|
31
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/writer.go
generated
vendored
Normal file
31
alpine/packages/proxy/vendor/github.com/Sirupsen/logrus/writer.go
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package logrus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (logger *Logger) Writer() *io.PipeWriter {
|
||||||
|
reader, writer := io.Pipe()
|
||||||
|
|
||||||
|
go logger.writerScanner(reader)
|
||||||
|
runtime.SetFinalizer(writer, writerFinalizer)
|
||||||
|
|
||||||
|
return writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logger *Logger) writerScanner(reader *io.PipeReader) {
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
for scanner.Scan() {
|
||||||
|
logger.Print(scanner.Text())
|
||||||
|
}
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
logger.Errorf("Error while reading from Writer: %s", err)
|
||||||
|
}
|
||||||
|
reader.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func writerFinalizer(writer *io.PipeWriter) {
|
||||||
|
writer.Close()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user