package main import ( "github.com/gorilla/mux" "labix.org/v2/mgo/bson" "net/http" "strconv" "strings" "time" ) func InitStats() { statsChannel = make(chan statsRequest, CHAN_SIZE) go statsWorker() } func GatherStats(function func(http.ResponseWriter, *http.Request, *Session)) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { sess := GetSession(r) function(w, r, sess) statsChannel <- statsRequest{bson.Now(), mux.Vars(r), sess, r} } } var statsChannel chan statsRequest type statsRequest struct { date time.Time vars map[string]string sess *Session r *http.Request } func statsWorker() { for req := range statsChannel { stats := make(map[string]interface{}) appendFiles(req.r, stats) appendMuxVars(req.vars, stats) appendUrl(req.r, stats) appendSession(req.sess, stats) stats["method"] = req.r.Method stats["date"] = req.date db.InsertStats(stats) } } func statsHandler(w http.ResponseWriter, r *http.Request, sess *Session) { var data statsData data.S = GetStatus(w, r) data.S.Stats = true data.Hourly = getHourlyVisits() data.Daily = getDailyVisits() data.Monthly = getMonthlyVisits() loadTemplate(w, "stats", data) } type statsData struct { S Status Hourly []visitData Daily []visitData Monthly []visitData } type visitData struct { Label string Count int } func getHourlyVisits() []visitData { const numDays = 2 var visits []visitData start := time.Now().UTC().Add(-numDays * 24 * time.Hour) visit, _ := db.GetHourVisits(start) for _, v := range visit { var elem visitData hour := time.Unix(v.Date/1000, 0).UTC().Hour() elem.Label = strconv.Itoa(hour + 1) elem.Count = v.Count visits = append(visits, elem) } return visits } func getDailyVisits() []visitData { const numDays = 30 var visits []visitData start := time.Now().UTC().Add(-numDays * 24 * time.Hour).Truncate(24 * time.Hour) visit, _ := db.GetDayVisits(start) for _, v := range visit { var elem visitData day := time.Unix(v.Date/1000, 0).UTC().Day() elem.Label = strconv.Itoa(day) elem.Count = v.Count visits = append(visits, elem) } return visits } func getMonthlyVisits() []visitData { const numDays = 365 var visits []visitData start := time.Now().UTC().Add(-numDays * 24 * time.Hour).Truncate(24 * time.Hour) visit, _ := db.GetMonthVisits(start) for _, v := range visit { var elem visitData month := time.Unix(v.Date/1000, 0).UTC().Month() elem.Label = month.String() elem.Count = v.Count visits = append(visits, elem) } return visits } func appendFiles(r *http.Request, stats map[string]interface{}) { if r.Method == "POST" && r.MultipartForm != nil { files := r.MultipartForm.File for key := range files { list := make([]string, len(files[key])) for i, f := range files[key] { list[i] = f.Filename } stats[key] = list } } } func appendMuxVars(vars map[string]string, stats map[string]interface{}) { for key, value := range vars { switch { case key == "id": if bson.IsObjectIdHex(value) { stats["id"] = bson.ObjectIdHex(value) } case key == "ids": var objectIds []bson.ObjectId ids := strings.Split(value, "/") for _, id := range ids { if bson.IsObjectIdHex(value) { objectIds = append(objectIds, bson.ObjectIdHex(id)) } } if len(objectIds) > 0 { stats["ids"] = objectIds stats["id"] = objectIds[0] } default: stats[key] = value } } } func appendUrl(r *http.Request, stats map[string]interface{}) { for key, value := range r.URL.Query() { stats[key] = value } stats["host"] = r.Host stats["path"] = r.URL.Path pattern := strings.Split(r.URL.Path, "/") if len(pattern) > 1 && pattern[1] != "" { stats["section"] = pattern[1] } else { stats["section"] = "/" } } func appendSession(sess *Session, stats map[string]interface{}) { stats["session"] = sess.Id() if sess.User != "" { stats["user"] = sess.User } }