mirror of
https://github.com/jech/galene.git
synced 2024-12-22 15:25:48 +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
|
||||
available to the administrator of the group.
|
||||
|
||||
Some statistics are available under `/stats`. This is only available to
|
||||
the server administrator.
|
||||
Some statistics are available under `/stats.json`. This is only available
|
||||
to the server administrator.
|
||||
|
||||
## Side menu
|
||||
|
||||
|
|
|
@ -23,18 +23,15 @@ func (c *webClient) GetStats() *stats.Client {
|
|||
tracks := up.getTracks()
|
||||
for _, t := range tracks {
|
||||
s := t.cache.GetStats(false)
|
||||
var loss uint8
|
||||
if s.Expected > s.Received {
|
||||
loss = uint8((s.Expected - s.Received) * 100 /
|
||||
s.Expected)
|
||||
}
|
||||
loss := float64(s.Expected - s.Received) /
|
||||
float64(s.Expected)
|
||||
jitter := time.Duration(t.jitter.Jitter()) *
|
||||
(time.Second / time.Duration(t.jitter.HZ()))
|
||||
rate, _ := t.rate.Estimate()
|
||||
conns.Tracks = append(conns.Tracks, stats.Track{
|
||||
Bitrate: uint64(rate) * 8,
|
||||
Loss: loss,
|
||||
Jitter: jitter,
|
||||
Jitter: stats.Duration(jitter),
|
||||
})
|
||||
}
|
||||
cs.Up = append(cs.Up, conns)
|
||||
|
@ -59,9 +56,9 @@ func (c *webClient) GetStats() *stats.Client {
|
|||
conns.Tracks = append(conns.Tracks, stats.Track{
|
||||
Bitrate: uint64(rate) * 8,
|
||||
MaxBitrate: t.maxBitrate.Get(jiffies),
|
||||
Loss: uint8(uint32(loss) * 100 / 256),
|
||||
Rtt: rtt,
|
||||
Jitter: j,
|
||||
Loss: float64(loss) / 256.0,
|
||||
Rtt: stats.Duration(rtt),
|
||||
Jitter: stats.Duration(j),
|
||||
})
|
||||
}
|
||||
cs.Down = append(cs.Down, conns)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package stats
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
|
@ -8,13 +9,14 @@ import (
|
|||
)
|
||||
|
||||
type GroupStats struct {
|
||||
Name string
|
||||
Clients []*Client
|
||||
Name string `json:"name"`
|
||||
Clients []*Client `json:"clients,omitempty"`
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
Id string
|
||||
Up, Down []Conn
|
||||
Id string `json:"id"`
|
||||
Up []Conn `json:"up,omitempty"`
|
||||
Down []Conn `json:"down,omitempty"`
|
||||
}
|
||||
|
||||
type Statable interface {
|
||||
|
@ -22,17 +24,34 @@ type Statable interface {
|
|||
}
|
||||
|
||||
type Conn struct {
|
||||
Id string
|
||||
MaxBitrate uint64
|
||||
Tracks []Track
|
||||
Id string `json:"id"`
|
||||
MaxBitrate uint64 `json:"maxBitrate,omitempty"`
|
||||
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 {
|
||||
Bitrate uint64
|
||||
MaxBitrate uint64
|
||||
Loss uint8
|
||||
Rtt time.Duration
|
||||
Jitter time.Duration
|
||||
Bitrate uint64 `json:"bitrate"`
|
||||
MaxBitrate uint64 `json:"maxBitrate,omitempty"`
|
||||
Loss float64 `json:"loss"`
|
||||
Rtt Duration `json:"rtt,omitempty"`
|
||||
Jitter Duration `json:"jitter,omitempty"`
|
||||
}
|
||||
|
||||
func GetGroups() []GroupStats {
|
||||
|
|
|
@ -47,9 +47,10 @@ func Serve(address string, dataDir string) error {
|
|||
http.HandleFunc("/recordings/", recordingsHandler)
|
||||
http.HandleFunc("/ws", wsHandler)
|
||||
http.HandleFunc("/public-groups.json", publicHandler)
|
||||
http.HandleFunc("/stats", func(w http.ResponseWriter, r *http.Request) {
|
||||
statsHandler(w, r, dataDir)
|
||||
})
|
||||
http.HandleFunc("/stats.json",
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
statsHandler(w, r, dataDir)
|
||||
})
|
||||
|
||||
s := &http.Server{
|
||||
Addr: address,
|
||||
|
@ -361,81 +362,16 @@ func statsHandler(w http.ResponseWriter, r *http.Request, dataDir string) {
|
|||
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")
|
||||
if r.Method == "HEAD" {
|
||||
return
|
||||
}
|
||||
|
||||
ss := stats.GetGroups()
|
||||
|
||||
fmt.Fprintf(w, "<!DOCTYPE html>\n<html><head>\n")
|
||||
fmt.Fprintf(w, "<title>Stats</title>\n")
|
||||
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")
|
||||
e := json.NewEncoder(w)
|
||||
e.Encode(ss)
|
||||
return
|
||||
}
|
||||
|
||||
var wsUpgrader = websocket.Upgrader{
|
||||
|
|
Loading…
Reference in a new issue