mirror of
https://github.com/jech/galene.git
synced 2024-11-22 16:45:58 +01:00
Export stats as JSON.
This commit is contained in:
parent
9b1d814b58
commit
3a6ade988d
4 changed files with 47 additions and 95 deletions
4
README
4
README
|
@ -163,8 +163,8 @@ with others, there is no need to go through the landing page.
|
||||||
Recordings can be accessed under `/recordings/groupname`. This is only
|
Recordings can be accessed under `/recordings/groupname`. This is only
|
||||||
available to the administrator of the group.
|
available to the administrator of the group.
|
||||||
|
|
||||||
Some statistics are available under `/stats`. This is only available to
|
Some statistics are available under `/stats.json`. This is only available
|
||||||
the server administrator.
|
to the server administrator.
|
||||||
|
|
||||||
## Side menu
|
## Side menu
|
||||||
|
|
||||||
|
|
|
@ -23,18 +23,15 @@ func (c *webClient) GetStats() *stats.Client {
|
||||||
tracks := up.getTracks()
|
tracks := up.getTracks()
|
||||||
for _, t := range tracks {
|
for _, t := range tracks {
|
||||||
s := t.cache.GetStats(false)
|
s := t.cache.GetStats(false)
|
||||||
var loss uint8
|
loss := float64(s.Expected - s.Received) /
|
||||||
if s.Expected > s.Received {
|
float64(s.Expected)
|
||||||
loss = uint8((s.Expected - s.Received) * 100 /
|
|
||||||
s.Expected)
|
|
||||||
}
|
|
||||||
jitter := time.Duration(t.jitter.Jitter()) *
|
jitter := time.Duration(t.jitter.Jitter()) *
|
||||||
(time.Second / time.Duration(t.jitter.HZ()))
|
(time.Second / time.Duration(t.jitter.HZ()))
|
||||||
rate, _ := t.rate.Estimate()
|
rate, _ := t.rate.Estimate()
|
||||||
conns.Tracks = append(conns.Tracks, stats.Track{
|
conns.Tracks = append(conns.Tracks, stats.Track{
|
||||||
Bitrate: uint64(rate) * 8,
|
Bitrate: uint64(rate) * 8,
|
||||||
Loss: loss,
|
Loss: loss,
|
||||||
Jitter: jitter,
|
Jitter: stats.Duration(jitter),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
cs.Up = append(cs.Up, conns)
|
cs.Up = append(cs.Up, conns)
|
||||||
|
@ -59,9 +56,9 @@ func (c *webClient) GetStats() *stats.Client {
|
||||||
conns.Tracks = append(conns.Tracks, stats.Track{
|
conns.Tracks = append(conns.Tracks, stats.Track{
|
||||||
Bitrate: uint64(rate) * 8,
|
Bitrate: uint64(rate) * 8,
|
||||||
MaxBitrate: t.maxBitrate.Get(jiffies),
|
MaxBitrate: t.maxBitrate.Get(jiffies),
|
||||||
Loss: uint8(uint32(loss) * 100 / 256),
|
Loss: float64(loss) / 256.0,
|
||||||
Rtt: rtt,
|
Rtt: stats.Duration(rtt),
|
||||||
Jitter: j,
|
Jitter: stats.Duration(j),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
cs.Down = append(cs.Down, conns)
|
cs.Down = append(cs.Down, conns)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package stats
|
package stats
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -8,13 +9,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type GroupStats struct {
|
type GroupStats struct {
|
||||||
Name string
|
Name string `json:"name"`
|
||||||
Clients []*Client
|
Clients []*Client `json:"clients,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
Id string
|
Id string `json:"id"`
|
||||||
Up, Down []Conn
|
Up []Conn `json:"up,omitempty"`
|
||||||
|
Down []Conn `json:"down,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Statable interface {
|
type Statable interface {
|
||||||
|
@ -22,17 +24,34 @@ type Statable interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Conn struct {
|
type Conn struct {
|
||||||
Id string
|
Id string `json:"id"`
|
||||||
MaxBitrate uint64
|
MaxBitrate uint64 `json:"maxBitrate,omitempty"`
|
||||||
Tracks []Track
|
Tracks []Track `json:"tracks"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Duration time.Duration
|
||||||
|
|
||||||
|
func (d Duration) MarshalJSON() ([]byte, error) {
|
||||||
|
s := float64(d) / float64(time.Millisecond)
|
||||||
|
return json.Marshal(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Duration) UnmarshalJSON(buf []byte) error {
|
||||||
|
var s float64
|
||||||
|
err := json.Unmarshal(buf, &s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*d = Duration(s * float64(time.Millisecond))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Track struct {
|
type Track struct {
|
||||||
Bitrate uint64
|
Bitrate uint64 `json:"bitrate"`
|
||||||
MaxBitrate uint64
|
MaxBitrate uint64 `json:"maxBitrate,omitempty"`
|
||||||
Loss uint8
|
Loss float64 `json:"loss"`
|
||||||
Rtt time.Duration
|
Rtt Duration `json:"rtt,omitempty"`
|
||||||
Jitter time.Duration
|
Jitter Duration `json:"jitter,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetGroups() []GroupStats {
|
func GetGroups() []GroupStats {
|
||||||
|
|
|
@ -47,7 +47,8 @@ func Serve(address string, dataDir string) error {
|
||||||
http.HandleFunc("/recordings/", recordingsHandler)
|
http.HandleFunc("/recordings/", recordingsHandler)
|
||||||
http.HandleFunc("/ws", wsHandler)
|
http.HandleFunc("/ws", wsHandler)
|
||||||
http.HandleFunc("/public-groups.json", publicHandler)
|
http.HandleFunc("/public-groups.json", publicHandler)
|
||||||
http.HandleFunc("/stats", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/stats.json",
|
||||||
|
func(w http.ResponseWriter, r *http.Request) {
|
||||||
statsHandler(w, r, dataDir)
|
statsHandler(w, r, dataDir)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -361,81 +362,16 @@ func statsHandler(w http.ResponseWriter, r *http.Request, dataDir string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("content-type", "text/html; charset=utf-8")
|
w.Header().Set("content-type", "application/json")
|
||||||
w.Header().Set("cache-control", "no-cache")
|
w.Header().Set("cache-control", "no-cache")
|
||||||
if r.Method == "HEAD" {
|
if r.Method == "HEAD" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ss := stats.GetGroups()
|
ss := stats.GetGroups()
|
||||||
|
e := json.NewEncoder(w)
|
||||||
fmt.Fprintf(w, "<!DOCTYPE html>\n<html><head>\n")
|
e.Encode(ss)
|
||||||
fmt.Fprintf(w, "<title>Stats</title>\n")
|
return
|
||||||
fmt.Fprintf(w, "<link rel=\"stylesheet\" type=\"text/css\" href=\"/common.css\"/>")
|
|
||||||
fmt.Fprintf(w, "<head><body>\n")
|
|
||||||
|
|
||||||
printBitrate := func(w io.Writer, rate, maxRate uint64) error {
|
|
||||||
var err error
|
|
||||||
if maxRate != 0 && maxRate != ^uint64(0) {
|
|
||||||
_, err = fmt.Fprintf(w, "%v/%v", rate, maxRate)
|
|
||||||
} else {
|
|
||||||
_, err = fmt.Fprintf(w, "%v", rate)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
printTrack := func(w io.Writer, t stats.Track) {
|
|
||||||
fmt.Fprintf(w, "<tr><td></td><td></td><td></td>")
|
|
||||||
fmt.Fprintf(w, "<td>")
|
|
||||||
printBitrate(w, t.Bitrate, t.MaxBitrate)
|
|
||||||
fmt.Fprintf(w, "</td>")
|
|
||||||
fmt.Fprintf(w, "<td>%d%%</td>",
|
|
||||||
t.Loss,
|
|
||||||
)
|
|
||||||
fmt.Fprintf(w, "<td>")
|
|
||||||
if t.Rtt > 0 {
|
|
||||||
fmt.Fprintf(w, "%v", t.Rtt)
|
|
||||||
}
|
|
||||||
if t.Jitter > 0 {
|
|
||||||
fmt.Fprintf(w, "±%v", t.Jitter)
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, "</td>")
|
|
||||||
fmt.Fprintf(w, "</tr>")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, gs := range ss {
|
|
||||||
fmt.Fprintf(w, "<p>%v</p>\n", html.EscapeString(gs.Name))
|
|
||||||
fmt.Fprintf(w, "<table>")
|
|
||||||
for _, cs := range gs.Clients {
|
|
||||||
fmt.Fprintf(w, "<tr><td>%v</td></tr>\n", cs.Id)
|
|
||||||
for _, up := range cs.Up {
|
|
||||||
fmt.Fprintf(w, "<tr><td></td><td>Up</td><td>%v</td>",
|
|
||||||
up.Id)
|
|
||||||
if up.MaxBitrate > 0 {
|
|
||||||
fmt.Fprintf(w, "<td>%v</td>",
|
|
||||||
up.MaxBitrate)
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, "</tr>\n")
|
|
||||||
for _, t := range up.Tracks {
|
|
||||||
printTrack(w, t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, down := range cs.Down {
|
|
||||||
fmt.Fprintf(w, "<tr><td></td><td>Down</td><td> %v</td>",
|
|
||||||
down.Id)
|
|
||||||
if down.MaxBitrate > 0 {
|
|
||||||
fmt.Fprintf(w, "<td>%v</td>",
|
|
||||||
down.MaxBitrate)
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, "</tr>\n")
|
|
||||||
for _, t := range down.Tracks {
|
|
||||||
printTrack(w, t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, "</table>\n")
|
|
||||||
}
|
|
||||||
fmt.Fprintf(w, "</body></html>\n")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var wsUpgrader = websocket.Upgrader{
|
var wsUpgrader = websocket.Upgrader{
|
||||||
|
|
Loading…
Reference in a new issue