package main import ( "bufio" "fmt" "log" "os" "regexp" "strconv" "net/http" ) const COUNTER_SLOTS = 20 func main() { counter := NewCounter() go counter.ScanStdin() http.HandleFunc("/", counter.MetricsHandler) err := http.ListenAndServe(":8080", nil) log.Fatalf("unable to listen: %s", err) } type Counter struct { counters []int names []string current int } func NewCounter() *Counter { return &Counter{ counters: make([]int, COUNTER_SLOTS), names: make([]string, COUNTER_SLOTS), } } func (c *Counter) MetricsHandler(w http.ResponseWriter, r *http.Request) { w.Header().Add("Content-Type", "text/plain") for i, name := range c.names { fmt.Fprintf(w, "rc3_stream_count[name=%q] %d\n", name, c.counters[i]) } fmt.Fprintf(w, "rc3_stream_current[name=\"%d\"] 1\n", c.current) } func (c *Counter) ScanStdin() { matcher := regexp.MustCompile(`/hls/stream-([0-9]*).ts`) scanner := bufio.NewScanner(os.Stdin) scanner.Split(bufio.ScanLines) for scanner.Scan() { matches := matcher.FindStringSubmatch(scanner.Text()) if len(matches) == 2 { c.countViewers(matches[1]) } } } func (c *Counter) countViewers(part string) { i, _ := strconv.Atoi(part) mod := i % COUNTER_SLOTS if c.names[mod] != part { c.counters[mod] = 0 } c.current = i c.counters[mod] += 1 c.names[mod] = part }