reqlog.go 2.05 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
package commands

import (
	"strings"
	"sync"
	"time"
)

type ReqLogEntry struct {
	StartTime time.Time
	EndTime   time.Time
	Active    bool
	Command   string
	Options   map[string]interface{}
	Args      []string
	ID        int

	req Request
	log *ReqLog
}

func (r *ReqLogEntry) Finish() {
23 24 25
	log := r.log
	log.lock.Lock()
	defer log.lock.Unlock()
26 27 28 29

	r.Active = false
	r.EndTime = time.Now()
	r.log.maybeCleanup()
30 31 32 33 34

	// remove references to save memory
	r.req = nil
	r.log = nil

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
}

func (r *ReqLogEntry) Copy() *ReqLogEntry {
	out := *r
	out.log = nil
	return &out
}

type ReqLog struct {
	Requests []*ReqLogEntry
	nextID   int
	lock     sync.Mutex
}

func (rl *ReqLog) Add(req Request) *ReqLogEntry {
	rl.lock.Lock()
	defer rl.lock.Unlock()

	rle := &ReqLogEntry{
		StartTime: time.Now(),
		Active:    true,
		Command:   strings.Join(req.Path(), "/"),
		Options:   req.Options(),
		Args:      req.Arguments(),
		ID:        rl.nextID,
		req:       req,
		log:       rl,
	}

	rl.nextID++
	rl.Requests = append(rl.Requests, rle)
	return rle
}

69 70 71 72 73 74 75 76 77 78 79 80 81
func (rl *ReqLog) ClearInactive() {
	rl.lock.Lock()
	defer rl.lock.Unlock()
	i := 0
	for j := 0; j < len(rl.Requests); j++ {
		if rl.Requests[j].Active {
			rl.Requests[i] = rl.Requests[j]
			i++
		}
	}
	rl.Requests = rl.Requests[:i]
}

82 83 84 85 86 87 88 89 90 91
func (rl *ReqLog) maybeCleanup() {
	// only do it every so often or it might
	// become a perf issue
	if len(rl.Requests) == 0 {
		rl.cleanup()
	}
}

func (rl *ReqLog) cleanup() {
	var i int
Jeromy's avatar
Jeromy committed
92
	// drop all logs at are inactive and more than an hour old
93 94
	for ; i < len(rl.Requests); i++ {
		req := rl.Requests[i]
95
		if req.Active || req.EndTime.Add(time.Hour/2).After(time.Now()) {
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
			break
		}
	}

	if i > 0 {
		var j int
		for i < len(rl.Requests) {
			rl.Requests[j] = rl.Requests[i]
			j++
			i++
		}
		rl.Requests = rl.Requests[:len(rl.Requests)-i]
	}
}

Jeromy's avatar
Jeromy committed
111
// Report generates a copy of all the entries in the requestlog
112 113 114 115 116 117 118 119 120 121 122
func (rl *ReqLog) Report() []*ReqLogEntry {
	rl.lock.Lock()
	defer rl.lock.Unlock()
	out := make([]*ReqLogEntry, len(rl.Requests))

	for i, e := range rl.Requests {
		out[i] = e.Copy()
	}

	return out
}