Skip to content

Commit

Permalink
add buffer count metric and time to start
Browse files Browse the repository at this point in the history
  • Loading branch information
lyoshenka committed Mar 24, 2020
1 parent fff54b3 commit 2ba432a
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 9 deletions.
8 changes: 6 additions & 2 deletions api/routes.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package api

import (
"net/http"

"github.com/lbryio/lbrytv/app/player"
"github.com/lbryio/lbrytv/app/proxy"
"github.com/lbryio/lbrytv/app/publish"
"github.com/lbryio/lbrytv/app/users"
"github.com/lbryio/lbrytv/internal/metrics"
"github.com/lbryio/lbrytv/internal/status"
"github.com/prometheus/client_golang/prometheus/promhttp"

"github.com/gorilla/mux"
"github.com/prometheus/client_golang/prometheus/promhttp"
)

// InstallRoutes sets up global API handlers
Expand All @@ -23,9 +26,10 @@ func InstallRoutes(proxyService *proxy.ProxyService, r *mux.Router) {
r.HandleFunc("/", Index)

v1Router := r.PathPrefix("/api/v1").Subrouter()
v1Router.HandleFunc("/proxy", proxyHandler.HandleOptions).Methods("OPTIONS")
v1Router.HandleFunc("/proxy", proxyHandler.HandleOptions).Methods(http.MethodOptions)
v1Router.HandleFunc("/proxy", authenticator.Wrap(upHandler.Handle)).MatcherFunc(upHandler.CanHandle)
v1Router.HandleFunc("/proxy", proxyHandler.Handle)
v1Router.HandleFunc("/metric/ui", metrics.TrackUIMetric).Methods(http.MethodPost)

internalRouter := r.PathPrefix("/internal").Subrouter()
internalRouter.Handle("/metrics", promhttp.Handler())
Expand Down
6 changes: 3 additions & 3 deletions api/routes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ func TestRoutesOptions(t *testing.T) {
InstallRoutes(proxy, r)
r.ServeHTTP(rr, req)
assert.Equal(t, http.StatusOK, rr.Code)
assert.Equal(t, "7200", rr.HeaderMap.Get("Access-Control-Max-Age"))
assert.Equal(t, "*", rr.HeaderMap.Get("Access-Control-Allow-Origin"))
assert.Equal(t, "7200", rr.Result().Header.Get("Access-Control-Max-Age"))
assert.Equal(t, "*", rr.Result().Header.Get("Access-Control-Allow-Origin"))
assert.Equal(
t,
"X-Lbry-Auth-Token, Origin, X-Requested-With, Content-Type, Accept",
rr.HeaderMap.Get("Access-Control-Allow-Headers"),
rr.Result().Header.Get("Access-Control-Allow-Headers"),
)
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ require (
github.com/rubenv/sql-migrate v0.0.0-20190618074426-f4d34eae5a5c
github.com/sirupsen/logrus v1.4.2
github.com/spf13/afero v1.2.2 // indirect
github.com/spf13/cast v1.3.0
github.com/spf13/cobra v0.0.5
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
Expand Down
15 changes: 15 additions & 0 deletions internal/metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const (
nsIAPI = "iapi"
nsProxy = "proxy"
nsLbrynet = "lbrynet"
nsUI = "ui"

LabelSource = "source"
LabelInstance = "instance"
Expand Down Expand Up @@ -120,4 +121,18 @@ var (
Name: "count",
Help: "Number of wallets currently loaded",
}, []string{LabelSource})

UIBufferCount = promauto.NewCounter(prometheus.CounterOpts{
Namespace: nsUI,
Subsystem: "buffer",
Name: "count",
Help: "Video buffer events",
})
UITimeToStart = promauto.NewHistogram(prometheus.HistogramOpts{
Namespace: nsUI,
Subsystem: "buffer",
Name: "time_to_start",
Help: "How long it takes the video to start",
Buckets: []float64{0.1, 0.25, 0.5, 1, 2, 4, 8, 16, 32},
})
)
43 changes: 43 additions & 0 deletions internal/metrics/routes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package metrics

import (
"encoding/json"
"net/http"

"github.com/lbryio/lbrytv/internal/monitor"

"github.com/spf13/cast"
)

var Logger = monitor.NewModuleLogger("metrics")

func TrackUIMetric(w http.ResponseWriter, req *http.Request) {
w.Header().Add("content-type", "application/json; charset=utf-8")
resp := make(map[string]string)
code := http.StatusOK

metricName := req.FormValue("name")
resp["name"] = metricName

switch metricName {
case "buffer":
UIBufferCount.Inc()
case "time_to_start":
t := cast.ToFloat64(req.FormValue("value"))
if t == 0 {
Logger.Log().Errorf("Time to start cannot be 0")
code = http.StatusBadRequest
resp["error"] = "Time to start cannot be 0"
} else {
UITimeToStart.Observe(t)
}
default:
Logger.Log().Errorf("invalid UI metric name: %s", metricName)
code = http.StatusBadRequest
resp["error"] = "Invalid metric name"
}

w.WriteHeader(code)
respByte, _ := json.Marshal(&resp)
w.Write(respByte)
}
64 changes: 64 additions & 0 deletions internal/metrics/routes_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package metrics_test

import (
"net/http"
"net/http/httptest"
"testing"

"github.com/lbryio/lbrytv/api"
"github.com/lbryio/lbrytv/app/proxy"

"github.com/gorilla/mux"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestBufferEvent(t *testing.T) {
name := "buffer"
rr := testMetricUIEvent(t, http.MethodPost, name, "")
assert.Equal(t, http.StatusOK, rr.Code)
assert.Equal(t, `{"name":"`+name+`"}`, rr.Body.String())
}

func TestInvalidEvent(t *testing.T) {
name := "win-the-lottery"
rr := testMetricUIEvent(t, http.MethodPost, name, "")
assert.Equal(t, http.StatusBadRequest, rr.Code)
assert.Equal(t, `{"error":"Invalid metric name","name":"`+name+`"}`, rr.Body.String())
}

func TestInvalidMethod(t *testing.T) {
rr := testMetricUIEvent(t, http.MethodGet, "", "")
assert.Equal(t, http.StatusMethodNotAllowed, rr.Code)
}

func TestTimeToStartEvent(t *testing.T) {
name := "time_to_start"
rr := testMetricUIEvent(t, http.MethodPost, name, "0.3")
assert.Equal(t, http.StatusOK, rr.Code)
assert.Equal(t, `{"name":"`+name+`"}`, rr.Body.String())
}

func TestTimeToStartEventNoValue(t *testing.T) {
name := "time_to_start"
rr := testMetricUIEvent(t, http.MethodPost, name, "")
assert.Equal(t, http.StatusBadRequest, rr.Code)
}

func testMetricUIEvent(t *testing.T, method, name, value string) *httptest.ResponseRecorder {
req, err := http.NewRequest(method, "/api/v1/metric/ui", nil)
require.Nil(t, err)

q := req.URL.Query()
q.Add("name", name)
if value != "" {
q.Add("value", value)
}
req.URL.RawQuery = q.Encode()

r := mux.NewRouter()
api.InstallRoutes(proxy.NewService(proxy.Opts{}), r)
rr := httptest.NewRecorder()
r.ServeHTTP(rr, req)
return rr
}
4 changes: 2 additions & 2 deletions internal/status/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
ljsonrpc "github.com/lbryio/lbry.go/v2/extras/jsonrpc"
)

var StatusLogger = monitor.NewModuleLogger("status")
var Logger = monitor.NewModuleLogger("status")

var PlayerServers = []string{
"https://player1.lbry.tv",
Expand Down Expand Up @@ -63,7 +63,7 @@ func GetStatus(w http.ResponseWriter, req *http.Request) {
sdks := router.GetSDKServerList()
for _, s := range sdks {
c := ljsonrpc.NewClient(s.Address)
c.SetRPCTimeout(5*time.Second)
c.SetRPCTimeout(5 * time.Second)
status, err := c.Status()
srv := ServerItem{Address: s.Address, Status: StatusOK}
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions internal/status/wallet_watch.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

func WatchWallets() {
r := router.NewDefault()
StatusLogger.Log().Infof("starting wallets watcher over %v instances", len(r.GetSDKServerList()))
Logger.Log().Infof("starting wallets watcher over %v instances", len(r.GetSDKServerList()))
walletWatchInterval := time.Duration(rand.Intn(10)+5) * time.Minute
ticker := time.NewTicker(walletWatchInterval)

Expand All @@ -33,7 +33,7 @@ func countWallets() {

wl, err := c.WalletList("", 1, 1)
if err != nil {
StatusLogger.Log().Errorf("lbrynet instance %v is not responding: %v", server.Address, err)
Logger.Log().Errorf("lbrynet instance %v is not responding: %v", server.Address, err)
m.Set(0.0)
} else {
m.Set(float64(wl.TotalPages - 1))
Expand Down

0 comments on commit 2ba432a

Please sign in to comment.