package trantor import ( log "github.com/cihub/seelog" "net/http" "strings" "time" "github.com/gorilla/mux" "gitlab.com/trantor/trantor/lib/database" "gitlab.com/trantor/trantor/lib/storage" ) const ( stats_version = 2 statsChanSize = 100 ) type handler struct { w http.ResponseWriter r *http.Request sess *Session db database.DB store storage.Store template *Template hostname string ro bool } type StatsGatherer struct { db database.DB store storage.Store template *Template hostname string channel chan statsRequest ro bool } func InitStats(database database.DB, store storage.Store, hostname string, template *Template, ro bool) *StatsGatherer { sg := StatsGatherer{ channel: make(chan statsRequest, statsChanSize), db: database, store: store, template: template, hostname: hostname, ro: ro, } go sg.worker() return &sg } func (sg StatsGatherer) Gather(function func(handler)) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { log.Info("Query ", r.Method, " ", r.RequestURI) h := handler{ store: sg.store, db: sg.db, template: sg.template, hostname: sg.hostname, w: w, r: r, sess: GetSession(r, sg.db), ro: sg.ro, } function(h) sg.channel <- statsRequest{time.Now(), mux.Vars(r), h.sess, r} } } type statsRequest struct { date time.Time vars map[string]string sess *Session r *http.Request } func (sg StatsGatherer) worker() { for req := range sg.channel { stats := make(map[string]interface{}) appendFiles(req.r, stats) appendMuxVars(req.vars, stats) appendUrl(req.r, stats) appendSession(req.sess, stats) stats["version"] = stats_version stats["method"] = req.r.Method stats["date"] = req.date sg.db.AddStats(stats) } } 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": stats["id"] = value case key == "ids": var objectIds []string ids := strings.Split(value, "/") for _, id := range ids { objectIds = append(objectIds, 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 } }