mirror of
				https://github.com/Oxalide/vsphere-influxdb-go.git
				synced 2023-10-10 11:36:51 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			141 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			141 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package httpd
 | |
| 
 | |
| import (
 | |
| 	"container/list"
 | |
| 	"fmt"
 | |
| 	"net"
 | |
| 	"net/http"
 | |
| 	"sync"
 | |
| 	"sync/atomic"
 | |
| 
 | |
| 	"github.com/influxdata/influxdb/services/meta"
 | |
| )
 | |
| 
 | |
| type RequestInfo struct {
 | |
| 	IPAddr   string
 | |
| 	Username string
 | |
| }
 | |
| 
 | |
| type RequestStats struct {
 | |
| 	Writes  int64 `json:"writes"`
 | |
| 	Queries int64 `json:"queries"`
 | |
| }
 | |
| 
 | |
| func (r *RequestInfo) String() string {
 | |
| 	if r.Username != "" {
 | |
| 		return fmt.Sprintf("%s:%s", r.Username, r.IPAddr)
 | |
| 	}
 | |
| 	return r.IPAddr
 | |
| }
 | |
| 
 | |
| type RequestProfile struct {
 | |
| 	tracker *RequestTracker
 | |
| 	elem    *list.Element
 | |
| 
 | |
| 	mu       sync.RWMutex
 | |
| 	Requests map[RequestInfo]*RequestStats
 | |
| }
 | |
| 
 | |
| func (p *RequestProfile) AddWrite(info RequestInfo) {
 | |
| 	p.add(info, p.addWrite)
 | |
| }
 | |
| 
 | |
| func (p *RequestProfile) AddQuery(info RequestInfo) {
 | |
| 	p.add(info, p.addQuery)
 | |
| }
 | |
| 
 | |
| func (p *RequestProfile) add(info RequestInfo, fn func(*RequestStats)) {
 | |
| 	// Look for a request entry for this request.
 | |
| 	p.mu.RLock()
 | |
| 	st, ok := p.Requests[info]
 | |
| 	p.mu.RUnlock()
 | |
| 	if ok {
 | |
| 		fn(st)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// There is no entry in the request tracker. Create one.
 | |
| 	p.mu.Lock()
 | |
| 	if st, ok := p.Requests[info]; ok {
 | |
| 		// Something else created this entry while we were waiting for the lock.
 | |
| 		p.mu.Unlock()
 | |
| 		fn(st)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	st = &RequestStats{}
 | |
| 	p.Requests[info] = st
 | |
| 	p.mu.Unlock()
 | |
| 	fn(st)
 | |
| }
 | |
| 
 | |
| func (p *RequestProfile) addWrite(st *RequestStats) {
 | |
| 	atomic.AddInt64(&st.Writes, 1)
 | |
| }
 | |
| 
 | |
| func (p *RequestProfile) addQuery(st *RequestStats) {
 | |
| 	atomic.AddInt64(&st.Queries, 1)
 | |
| }
 | |
| 
 | |
| // Stop informs the RequestTracker to stop collecting statistics for this
 | |
| // profile.
 | |
| func (p *RequestProfile) Stop() {
 | |
| 	p.tracker.mu.Lock()
 | |
| 	p.tracker.profiles.Remove(p.elem)
 | |
| 	p.tracker.mu.Unlock()
 | |
| }
 | |
| 
 | |
| type RequestTracker struct {
 | |
| 	mu       sync.RWMutex
 | |
| 	profiles *list.List
 | |
| }
 | |
| 
 | |
| func NewRequestTracker() *RequestTracker {
 | |
| 	return &RequestTracker{
 | |
| 		profiles: list.New(),
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (rt *RequestTracker) TrackRequests() *RequestProfile {
 | |
| 	// Perform the memory allocation outside of the lock.
 | |
| 	profile := &RequestProfile{
 | |
| 		Requests: make(map[RequestInfo]*RequestStats),
 | |
| 		tracker:  rt,
 | |
| 	}
 | |
| 
 | |
| 	rt.mu.Lock()
 | |
| 	profile.elem = rt.profiles.PushBack(profile)
 | |
| 	rt.mu.Unlock()
 | |
| 	return profile
 | |
| }
 | |
| 
 | |
| func (rt *RequestTracker) Add(req *http.Request, user meta.User) {
 | |
| 	rt.mu.RLock()
 | |
| 	if rt.profiles.Len() == 0 {
 | |
| 		rt.mu.RUnlock()
 | |
| 		return
 | |
| 	}
 | |
| 	defer rt.mu.RUnlock()
 | |
| 
 | |
| 	var info RequestInfo
 | |
| 	host, _, err := net.SplitHostPort(req.RemoteAddr)
 | |
| 	if err != nil {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	info.IPAddr = host
 | |
| 	if user != nil {
 | |
| 		info.Username = user.ID()
 | |
| 	}
 | |
| 
 | |
| 	// Add the request info to the profiles.
 | |
| 	for p := rt.profiles.Front(); p != nil; p = p.Next() {
 | |
| 		profile := p.Value.(*RequestProfile)
 | |
| 		if req.URL.Path == "/query" {
 | |
| 			profile.AddQuery(info)
 | |
| 		} else if req.URL.Path == "/write" {
 | |
| 			profile.AddWrite(info)
 | |
| 		}
 | |
| 	}
 | |
| }
 |