├── .gitignore ├── .dockerignore ├── README.md ├── cfg └── config.json ├── Dockerfile ├── .github └── workflows │ └── build-push-docker.yml ├── main.go ├── config └── config.go ├── LICENSE ├── go.mod ├── web └── web.go ├── stream └── stream_sender.go ├── srt └── srt.go └── go.sum /.gitignore: -------------------------------------------------------------------------------- 1 | ./srt-advanced-server -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | build_and_start.bat 3 | README.md 4 | .git 5 | .dockerignore -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # srt-advanced-server 2 | SRT-Advanced-Server is an SRT server implementation that is highly configurable and supports streams from a single source to multiple targets. -------------------------------------------------------------------------------- /cfg/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "inputs": [ 3 | { 4 | "port": 11001, 5 | "latency": 200 6 | } 7 | ], 8 | "outputs": [ 9 | { 10 | "port": 11101, 11 | "streamId": "obs1", 12 | "latency": 200 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.14.2 2 | 3 | RUN apk add go linux-headers alpine-sdk cmake tcl openssl-dev zlib-dev supervisor 4 | 5 | # Install SRT 6 | WORKDIR /srt 7 | RUN git clone https://github.com/Haivision/srt.git . 8 | RUN git checkout v1.4.3 9 | RUN ./configure && make && make install 10 | 11 | RUN mkdir /app 12 | WORKDIR /app 13 | 14 | COPY go.mod /app 15 | COPY go.sum /app 16 | 17 | RUN go mod download 18 | 19 | ADD . /app 20 | 21 | RUN go build . 22 | 23 | ENTRYPOINT [ "/app/srt-advanced-server" ] -------------------------------------------------------------------------------- /.github/workflows/build-push-docker.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | 11 | build: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Build the Docker image 18 | run: docker build . --file Dockerfile --tag laraka/srt-advanced-server:latest 19 | - name: Push To Registry 20 | uses: redhat-actions/push-to-registry@v2 21 | with: 22 | image: laraka/srt-advanced-server 23 | tags: latest 24 | registry: registry.hub.docker.com 25 | username: ${{ secrets.DOCKER_USER }} 26 | password: ${{ secrets.DOCKER_PASSWORD }} 27 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/RCVolus/srt-advanced-server/config" 7 | "github.com/RCVolus/srt-advanced-server/srt" 8 | "github.com/RCVolus/srt-advanced-server/web" 9 | "github.com/prometheus/client_golang/prometheus" 10 | ) 11 | 12 | var Exit = make(chan string) 13 | 14 | func main() { 15 | println("Starting SRT Advanced Server by RCVolus") 16 | 17 | go web.StartHttp() 18 | 19 | prometheus.MustRegister(srt.SrtStats) 20 | 21 | var config = config.GetConfig() 22 | 23 | time.Sleep(200 * time.Millisecond) 24 | 25 | for _, input := range config.Inputs { 26 | go srt.ListenIngressSocket(input.Port, input.Latency) 27 | } 28 | 29 | for _, output := range config.Outputs { 30 | go srt.ListenEgressSocket(output.Port, output.StreamId, output.Latency) 31 | } 32 | 33 | <-Exit 34 | } 35 | -------------------------------------------------------------------------------- /config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "encoding/json" 5 | "io/ioutil" 6 | "log" 7 | ) 8 | 9 | type StreamServerConfig struct { 10 | Inputs []struct { 11 | Port uint16 `json:"port"` 12 | Latency uint16 `json:"latency"` 13 | } `json:"inputs"` 14 | Outputs []struct { 15 | StreamId string `json:"streamId"` 16 | Port uint16 `json:"port"` 17 | Latency uint16 `json:"latency"` 18 | } `json:"outputs"` 19 | } 20 | 21 | var config *StreamServerConfig 22 | 23 | func loadConfig() { 24 | raw, err := ioutil.ReadFile("./cfg/config.json") 25 | if err != nil { 26 | log.Println("Error occured while reading config", err) 27 | return 28 | } 29 | json.Unmarshal(raw, &config) 30 | } 31 | 32 | func GetConfig() StreamServerConfig { 33 | if config == nil { 34 | loadConfig() 35 | } 36 | 37 | return *config 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Riot Community Volunteers 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/RCVolus/srt-advanced-server 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/haivision/srtgo v0.0.0-20210809105856-d4ed7d4623c4 7 | github.com/labstack/echo v3.3.10+incompatible 8 | ) 9 | 10 | require ( 11 | github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect 12 | github.com/labstack/gommon v0.3.0 // indirect 13 | github.com/mattn/go-colorable v0.1.8 // indirect 14 | github.com/mattn/go-isatty v0.0.14 // indirect 15 | github.com/prometheus/client_golang v1.11.0 16 | github.com/valyala/fasttemplate v1.2.1 // indirect 17 | golang.org/x/crypto v0.0.0-20210920023735-84f357641f63 // indirect 18 | golang.org/x/net v0.0.0-20210917221730-978cfadd31cf // indirect 19 | golang.org/x/sys v0.0.0-20210917161153-d61c044b1678 // indirect 20 | golang.org/x/text v0.3.7 // indirect 21 | ) 22 | 23 | require ( 24 | github.com/beorn7/perks v1.0.1 // indirect 25 | github.com/cespare/xxhash/v2 v2.1.1 // indirect 26 | github.com/golang/protobuf v1.4.3 // indirect 27 | github.com/mattn/go-pointer v0.0.1 // indirect 28 | github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect 29 | github.com/prometheus/client_model v0.2.0 // indirect 30 | github.com/prometheus/common v0.26.0 // indirect 31 | github.com/prometheus/procfs v0.6.0 // indirect 32 | github.com/valyala/bytebufferpool v1.0.0 // indirect 33 | google.golang.org/protobuf v1.26.0-rc.1 // indirect 34 | ) 35 | -------------------------------------------------------------------------------- /web/web.go: -------------------------------------------------------------------------------- 1 | package web 2 | 3 | import ( 4 | "net/http" 5 | "os" 6 | 7 | "github.com/RCVolus/srt-advanced-server/stream" 8 | "github.com/haivision/srtgo" 9 | "github.com/labstack/echo" 10 | "github.com/labstack/echo/middleware" 11 | "github.com/prometheus/client_golang/prometheus/promhttp" 12 | ) 13 | 14 | type OutputInfo struct { 15 | StreamInfo stream.EgestStreamInformation 16 | StreamStats srtgo.SrtStats 17 | } 18 | 19 | type StreamInfo struct { 20 | StreamInfo stream.IngestStreamInformation 21 | StreamStats srtgo.SrtStats 22 | Outputs []OutputInfo 23 | } 24 | 25 | func StartHttp() { 26 | e := echo.New() 27 | 28 | // e.Use(middleware.Logger()) 29 | e.Use(middleware.Recover()) 30 | 31 | e.GET("/", func(c echo.Context) error { 32 | streamInfo := make(map[string]StreamInfo) 33 | 34 | for key, value := range stream.IngestStreams { 35 | var outputs []OutputInfo 36 | 37 | for _, output := range value.Outputs { 38 | stats, _ := output.Socket.Stats() 39 | outputs = append(outputs, OutputInfo{ 40 | StreamInfo: output.EgestStreamInformation, 41 | StreamStats: *stats, 42 | }) 43 | } 44 | 45 | stats, _ := value.Socket.Stats() 46 | streamInfo[key] = StreamInfo{ 47 | StreamInfo: value.IngestStreamInformation, 48 | StreamStats: *stats, 49 | Outputs: outputs, 50 | } 51 | } 52 | 53 | return c.JSON(http.StatusOK, streamInfo) 54 | }) 55 | 56 | e.GET("/metrics", echo.WrapHandler(promhttp.Handler())) 57 | 58 | httpPort := os.Getenv("HTTP_PORT") 59 | if httpPort == "" { 60 | httpPort = "11000" 61 | } 62 | 63 | e.Start(":" + httpPort) 64 | } 65 | -------------------------------------------------------------------------------- /stream/stream_sender.go: -------------------------------------------------------------------------------- 1 | package stream 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | 7 | "github.com/haivision/srtgo" 8 | ) 9 | 10 | var IngestStreams = make(map[string]StreamSender) 11 | 12 | type StreamReceiver struct { 13 | EgestStreamInformation EgestStreamInformation 14 | Socket *srtgo.SrtSocket 15 | } 16 | 17 | type StreamSender struct { 18 | Broadcast chan<- []byte 19 | IngestStreamInformation IngestStreamInformation 20 | Socket srtgo.SrtSocket 21 | 22 | Outputs map[chan []byte]StreamReceiver 23 | 24 | LockOutputs sync.Mutex 25 | } 26 | 27 | type EgestStreamInformation struct { 28 | Remote string 29 | ConnectedAt time.Time 30 | } 31 | 32 | type IngestStreamInformation struct { 33 | StreamId string 34 | Remote string 35 | ConnectedAt time.Time 36 | } 37 | 38 | func NewStreamSender(ingestStreamInformation IngestStreamInformation, socket srtgo.SrtSocket) (streamSender *StreamSender) { 39 | streamSender = &StreamSender{} 40 | broadcast := make(chan []byte, 1024) 41 | streamSender.Broadcast = broadcast 42 | streamSender.Outputs = make(map[chan []byte]StreamReceiver) 43 | streamSender.IngestStreamInformation = ingestStreamInformation 44 | streamSender.Socket = socket 45 | 46 | go streamSender.run(broadcast) 47 | return streamSender 48 | } 49 | 50 | func (streamSender *StreamSender) run(broadcast <-chan []byte) { 51 | for msg := range broadcast { 52 | streamSender.LockOutputs.Lock() 53 | for output := range streamSender.Outputs { 54 | select { 55 | case output <- msg: 56 | default: 57 | if len(output) > 1 { 58 | <-output 59 | } 60 | } 61 | } 62 | streamSender.LockOutputs.Unlock() 63 | } 64 | 65 | // The sender channel has been closed, close all outputs 66 | streamSender.LockOutputs.Lock() 67 | for ch := range streamSender.Outputs { 68 | delete(streamSender.Outputs, ch) 69 | close(ch) 70 | } 71 | streamSender.LockOutputs.Unlock() 72 | } 73 | 74 | // Close stream sender and remove all outputs 75 | func (streamSender *StreamSender) Close() { 76 | close(streamSender.Broadcast) 77 | } 78 | 79 | // Register a new output 80 | func (streamSender *StreamSender) Register(output chan []byte, info EgestStreamInformation, socket *srtgo.SrtSocket) { 81 | streamSender.LockOutputs.Lock() 82 | streamSender.Outputs[output] = StreamReceiver{ 83 | EgestStreamInformation: info, 84 | Socket: socket, 85 | } 86 | streamSender.LockOutputs.Unlock() 87 | } 88 | 89 | // Remove an output 90 | func (streamSender *StreamSender) Unregister(output chan []byte) { 91 | streamSender.LockOutputs.Lock() 92 | _, ok := streamSender.Outputs[output] 93 | if ok { 94 | delete(streamSender.Outputs, output) 95 | close(output) 96 | } 97 | defer streamSender.LockOutputs.Unlock() 98 | } 99 | -------------------------------------------------------------------------------- /srt/srt.go: -------------------------------------------------------------------------------- 1 | package srt 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net" 7 | "time" 8 | 9 | "github.com/RCVolus/srt-advanced-server/stream" 10 | "github.com/haivision/srtgo" 11 | "github.com/prometheus/client_golang/prometheus" 12 | ) 13 | 14 | var ( 15 | SrtStats = prometheus.NewGaugeVec(prometheus.GaugeOpts{ 16 | Name: "srt_stats", 17 | Help: "SRT stats provided by the SRT library.", 18 | }, []string{"stream", "stat", "type", "remoteAddr"}) 19 | ) 20 | 21 | func ListenIngressSocket(port uint16, latency uint16) { 22 | options := make(map[string]string) 23 | options["transtype"] = "live" 24 | options["latency"] = string(latency) 25 | options["blocking"] = "1" 26 | options["rcvbuf"] = "20000000" 27 | 28 | sck := srtgo.NewSrtSocket("0.0.0.0", port, options) 29 | 30 | log.Println(fmt.Sprintf("Waiting for ingest SRT connections on 0.0.0.0:%d", port)) 31 | 32 | // sck.SetListenCallback(ListenCallback) 33 | 34 | defer sck.Close() 35 | sck.Listen(10) 36 | 37 | for { 38 | socket, addr, _ := sck.Accept() 39 | log.Println("New SRT socket for ingest opened") 40 | go HandleIngressSocket(socket, addr) 41 | } 42 | } 43 | 44 | func HandleIngressSocket(socket *srtgo.SrtSocket, addr *net.UDPAddr) { 45 | streamId, err := socket.GetSockOptString(srtgo.SRTO_STREAMID) 46 | if err != nil { 47 | log.Fatalln(fmt.Sprintf("Failed to get stream id, %s", err)) 48 | } 49 | log.Println(fmt.Sprintf("Receiving new stream with StreamId %s", streamId)) 50 | 51 | ingestInfo := &stream.IngestStreamInformation{ 52 | StreamId: streamId, 53 | Remote: addr.String(), 54 | ConnectedAt: time.Now(), 55 | } 56 | 57 | streamSender := stream.NewStreamSender(*ingestInfo, *socket) 58 | stream.IngestStreams[streamId] = *streamSender 59 | 60 | for { 61 | // Create a new buffer 62 | // UDP packet cannot be larger than MTU (1500) 63 | buff := make([]byte, 1500) 64 | 65 | n, err := socket.Read(buff) 66 | if err != nil { 67 | log.Println("Error occurred while reading SRT socket:", err) 68 | break 69 | } 70 | 71 | if n == 0 { 72 | // End of stream 73 | log.Println("Received no bytes, stopping stream.") 74 | break 75 | } 76 | 77 | // Send raw data to other streams 78 | buff = buff[:n] 79 | streamSender.Broadcast <- buff 80 | 81 | // Update stats 82 | UpdateStats(socket, streamId, "ingest", addr.String()) 83 | } 84 | 85 | // Close stream 86 | streamSender.Close() 87 | socket.Close() 88 | 89 | delete(stream.IngestStreams, streamId) 90 | } 91 | 92 | /* func ListenCallback(socket *srtgo.SrtSocket, version int, addr *net.UDPAddr, streamid string) bool { 93 | fmt.Printf("Streamid: %v\n", streamid) 94 | 95 | return true 96 | } */ 97 | 98 | func ListenEgressSocket(port uint16, streamId string, latency uint16) { 99 | // Open up a new socket 100 | options := make(map[string]string) 101 | options["transtype"] = "live" 102 | options["latency"] = string(latency) 103 | options["blocking"] = "0" 104 | 105 | sck := srtgo.NewSrtSocket("0.0.0.0", port, options) 106 | 107 | log.Println(fmt.Sprintf("Waiting for egest SRT connection on 0.0.0.0:%d", port)) 108 | 109 | defer sck.Close() 110 | sck.Listen(10) 111 | 112 | for { 113 | socket, addr, _ := sck.Accept() 114 | log.Println("New SRT socket for egest opened") 115 | 116 | // Send options 117 | /* sendSocket.SetSockOptInt(srtgo.SRTO_LATENCY, 2000) 118 | sendSocket.SetSockOptInt(srtgo.SRTO_RCVBUF, 4096) 119 | sendSocket.SetSockOptInt(srtgo.SRTO_SNDBUF, 4096) */ 120 | 121 | // go SendSocket(*s) 122 | 123 | // Register new output 124 | go HandleEgressSocket(socket, addr, streamId) 125 | } 126 | } 127 | 128 | func HandleEgressSocket(socket *srtgo.SrtSocket, addr *net.UDPAddr, streamId string) { 129 | c := make(chan []byte, 1024) 130 | currentStream, ok := stream.IngestStreams[streamId] 131 | 132 | if !ok { 133 | log.Println("Unable to create SRT viewer, no ingest stream found") 134 | socket.SetRejectReason(srtgo.RejectionReasonNotFound) 135 | socket.Close() 136 | return 137 | } 138 | 139 | egestInfo := stream.EgestStreamInformation{ 140 | Remote: addr.String(), 141 | ConnectedAt: time.Now(), 142 | } 143 | 144 | currentStream.Register(c, egestInfo, socket) 145 | 146 | for data := range c { 147 | if len(data) < 1 { 148 | log.Println("SRT viewer removed, end of stream") 149 | break 150 | } 151 | 152 | _, err := socket.Write(data) 153 | if err != nil { 154 | log.Printf("Remove SRT viewer because of sending error, %s", err) 155 | break 156 | } 157 | 158 | // Update stats 159 | UpdateStats(socket, "test", "egest", addr.String()) 160 | } 161 | 162 | currentStream.Unregister(c) 163 | socket.Close() 164 | } 165 | 166 | func UpdateStats(socket *srtgo.SrtSocket, streamid string, streamType string, remoteAddr string) { 167 | // stats, _ := socket.Stats() 168 | 169 | /* v := reflect.ValueOf(stats) 170 | 171 | for i := 0; i < v.NumField(); i++ { 172 | // values[i] = v.Field(i).Interface() 173 | var metricValue float64 174 | 175 | switch v.Field(i).Type().Key().Kind() { 176 | case reflect.Int: 177 | metricValue = float64(v.Field(i).Interface().(int)) 178 | case reflect.Int64: 179 | metricValue = float64(v.Field(i).Interface().(int64)) 180 | case reflect.Float64: 181 | metricValue = v.Field(i).Interface().(float64) 182 | } 183 | 184 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": v.Field(i).Type().Name()}).Set(metricValue) 185 | } */ 186 | 187 | /* SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "MbpsBandwidth"}).Set(stats.MbpsBandwidth) 188 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "MbpsMaxBW"}).Set(stats.MbpsMaxBW) 189 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "MbpsRecvRate"}).Set(stats.MbpsRecvRate) 190 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "MbpsSendRate"}).Set(stats.MbpsSendRate) 191 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "MsRTT"}).Set(stats.MsRTT) 192 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRcvAvgBelatedTime"}).Set(stats.PktRcvAvgBelatedTime) 193 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "UsPktSndPeriod"}).Set(stats.UsPktSndPeriod) 194 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "ByteAvailRcvBuf"}).Set(float64(stats.ByteAvailRcvBuf)) 195 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "ByteAvailSndBuf"}).Set(float64(stats.ByteAvailSndBuf)) 196 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "ByteMSS"}).Set(float64(stats.ByteMSS)) 197 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "ByteRcvBuf"}).Set(float64(stats.ByteRcvBuf)) 198 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "ByteRcvDrop"}).Set(float64(stats.ByteRcvDrop)) 199 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "ByteRcvDropTotal"}).Set(float64(stats.ByteRcvDropTotal)) 200 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "ByteRcvLoss"}).Set(float64(stats.ByteRcvLoss)) 201 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "ByteRcvLossTotal"}).Set(float64(stats.ByteRcvLossTotal)) 202 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "ByteRcvUndecrypt"}).Set(float64(stats.ByteRcvUndecrypt)) 203 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "ByteRcvUndecryptTotal"}).Set(float64(stats.ByteRcvUndecryptTotal)) 204 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "ByteRecv"}).Set(float64(stats.ByteRecv)) 205 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "ByteRecvTotal"}).Set(float64(stats.ByteRecvTotal)) 206 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "ByteRetrans"}).Set(float64(stats.ByteRetrans)) 207 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "ByteRetransTotal"}).Set(float64(stats.ByteRetransTotal)) 208 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "ByteSent"}).Set(float64(stats.ByteSent)) 209 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "ByteSentTotal"}).Set(float64(stats.ByteSentTotal)) 210 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "ByteSndBuf"}).Set(float64(stats.ByteSndBuf)) 211 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "ByteSndDrop"}).Set(float64(stats.ByteSndDrop)) 212 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "ByteSndDropTotal"}).Set(float64(stats.ByteSndDropTotal)) 213 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "MsRcvBuf"}).Set(float64(stats.MsRcvBuf)) 214 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "MsRcvTsbPdDelay"}).Set(float64(stats.MsRcvTsbPdDelay)) 215 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "MsSndBuf"}).Set(float64(stats.MsSndBuf)) 216 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "MsSndTsbPdDelay"}).Set(float64(stats.MsSndTsbPdDelay)) 217 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "MsTimeStamp"}).Set(float64(stats.MsTimeStamp)) 218 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktCongestionWindow"}).Set(float64(stats.PktCongestionWindow)) 219 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktFlightSize"}).Set(float64(stats.PktFlightSize)) 220 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktFlowWindow"}).Set(float64(stats.PktFlowWindow)) 221 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRcvBelated"}).Set(float64(stats.PktRcvBelated)) 222 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRcvBuf"}).Set(float64(stats.PktRcvBuf)) 223 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRcvDrop"}).Set(float64(stats.PktRcvDrop)) 224 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRcvDropTotal"}).Set(float64(stats.PktRcvDropTotal)) 225 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRcvFilterExtra"}).Set(float64(stats.PktRcvFilterExtra)) 226 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRcvFilterExtraTotal"}).Set(float64(stats.PktRcvFilterExtraTotal)) 227 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRcvFilterLoss"}).Set(float64(stats.PktRcvFilterLoss)) 228 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRcvFilterLossTotal"}).Set(float64(stats.PktRcvFilterLossTotal)) 229 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRcvFilterSupply"}).Set(float64(stats.PktRcvFilterSupply)) 230 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRcvFilterSupplyTotal"}).Set(float64(stats.PktRcvFilterSupplyTotal)) 231 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRcvLoss"}).Set(float64(stats.PktRcvLoss)) 232 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRcvLossTotal"}).Set(float64(stats.PktRcvLossTotal)) 233 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRcvRetrans"}).Set(float64(stats.PktRcvRetrans)) 234 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRcvUndecrypt"}).Set(float64(stats.PktRcvUndecrypt)) 235 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRcvUndecryptTotal"}).Set(float64(stats.PktRcvUndecryptTotal)) 236 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRecv"}).Set(float64(stats.PktRecv)) 237 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRecvACK"}).Set(float64(stats.PktRecvACK)) 238 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRecvACKTotal"}).Set(float64(stats.PktRecvACKTotal)) 239 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRecvNAK"}).Set(float64(stats.PktRecvNAK)) 240 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRecvNAKTotal"}).Set(float64(stats.PktRecvNAKTotal)) 241 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRecvTotal"}).Set(float64(stats.PktRecvTotal)) 242 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktReorderDistance"}).Set(float64(stats.PktReorderDistance)) 243 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktReorderTolerance"}).Set(float64(stats.PktReorderTolerance)) 244 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRetrans"}).Set(float64(stats.PktRetrans)) 245 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktRetransTotal"}).Set(float64(stats.PktRetransTotal)) 246 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktSent"}).Set(float64(stats.PktSent)) 247 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktSentACK"}).Set(float64(stats.PktSentACK)) 248 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktSentACKTotal"}).Set(float64(stats.PktSentACKTotal)) 249 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktSentNAK"}).Set(float64(stats.PktSentNAK)) 250 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktSentNAKTotal"}).Set(float64(stats.PktSentNAKTotal)) 251 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktSentTotal"}).Set(float64(stats.PktSentTotal)) 252 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktSndBuf"}).Set(float64(stats.PktSndBuf)) 253 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktSndDrop"}).Set(float64(stats.PktSndDrop)) 254 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktSndDropTotal"}).Set(float64(stats.PktSndDropTotal)) 255 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktSndFilterExtra"}).Set(float64(stats.PktSndFilterExtra)) 256 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktSndFilterExtraTotal"}).Set(float64(stats.PktSndFilterExtraTotal)) 257 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktSndLoss"}).Set(float64(stats.PktSndLoss)) 258 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "PktSndLossTotal"}).Set(float64(stats.PktSndLossTotal)) 259 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "UsSndDuration"}).Set(float64(stats.UsSndDuration)) 260 | SrtStats.With(prometheus.Labels{"stream": streamid, "type": streamType, "remoteAddr": remoteAddr, "stat": "UsSndDurationTotal"}).Set(float64(stats.UsSndDurationTotal)) */ 261 | } 262 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 3 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 4 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 5 | github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 6 | github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= 7 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 8 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 9 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 10 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 11 | github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= 12 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 13 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 14 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 15 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 16 | github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= 17 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 18 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 19 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 20 | github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= 21 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 22 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 23 | github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= 24 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 25 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 26 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 27 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 28 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 29 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 30 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 31 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 32 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 33 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 34 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 35 | github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= 36 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 37 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 38 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 39 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 40 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 41 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 42 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 43 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 44 | github.com/haivision/srtgo v0.0.0-20210809105856-d4ed7d4623c4 h1:OM3RzUUv6dA+lt5+aTCox8+rW6r15uM22PlXIAzAKGY= 45 | github.com/haivision/srtgo v0.0.0-20210809105856-d4ed7d4623c4/go.mod h1:aTd4vOr9wtzkCbbocUFh6atlJy7H/iV5jhqEWlTdCdA= 46 | github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= 47 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 48 | github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 49 | github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 50 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 51 | github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= 52 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 53 | github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 54 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 55 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 56 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 57 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 58 | github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg= 59 | github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s= 60 | github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0= 61 | github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= 62 | github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 63 | github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= 64 | github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 65 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 66 | github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= 67 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 68 | github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= 69 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 70 | github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0= 71 | github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= 72 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= 73 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 74 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 75 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 76 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 77 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 78 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 79 | github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 80 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 81 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 82 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 83 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 84 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 85 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 86 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= 87 | github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= 88 | github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= 89 | github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= 90 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 91 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 92 | github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= 93 | github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 94 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 95 | github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= 96 | github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= 97 | github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= 98 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 99 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 100 | github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= 101 | github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= 102 | github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= 103 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 104 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 105 | github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= 106 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 107 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 108 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 109 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 110 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 111 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 112 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= 113 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 114 | github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= 115 | github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4= 116 | github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= 117 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 118 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 119 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 120 | golang.org/x/crypto v0.0.0-20210920023735-84f357641f63 h1:kETrAMYZq6WVGPa8IIixL0CaEcIUNi+1WX7grUoi3y8= 121 | golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 122 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 123 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 124 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 125 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 126 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 127 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 128 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 129 | golang.org/x/net v0.0.0-20210917221730-978cfadd31cf h1:R150MpwJIv1MpS0N/pc+NhTM8ajzvlmxlY5OYsrevXQ= 130 | golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 131 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 132 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 133 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 134 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 135 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 136 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 137 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 138 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 139 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 140 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 141 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 142 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 143 | golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 144 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 145 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 146 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 147 | golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 148 | golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 149 | golang.org/x/sys v0.0.0-20200926100807-9d91bd62050c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 150 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 151 | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 152 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 153 | golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 154 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 155 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 156 | golang.org/x/sys v0.0.0-20210917161153-d61c044b1678 h1:J27LZFQBFoihqXoegpscI10HpjZ7B5WQLLKL2FZXQKw= 157 | golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 158 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 159 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 160 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 161 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 162 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 163 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= 164 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 165 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 166 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 167 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 168 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 169 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 170 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 171 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 172 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 173 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 174 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 175 | google.golang.org/protobuf v1.26.0-rc.1 h1:7QnIQpGRHE5RnLKnESfDoxm2dTapTZua5a0kS0A+VXQ= 176 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 177 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 178 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 179 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 180 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 181 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 182 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 183 | gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 184 | gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= 185 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 186 | --------------------------------------------------------------------------------