package gometrics

import (
	"runtime"
	"time"

	"github.com/cactus/go-statsd-client/statsd"
)

// Monitor launches a background goroutine which sends runtime metrics to statsd continuously at the provided rate
// For reference of available data, refer to https://golang.org/pkg/runtime/#MemStats
func Monitor(stats statsd.Statter, rate time.Duration) {
	go func() {
		var previousNumGC uint32
		var previousMallocs, previousFrees, previousGCTotal uint64

		memStats := &runtime.MemStats{}
		ticker := time.NewTicker(rate)
		defer ticker.Stop()

		for range ticker.C {
			runtime.ReadMemStats(memStats)

			stats.Gauge("go.num_goroutines", int64(runtime.NumGoroutine()), 1.0)

			stats.Gauge("go.mem.heap_objects", int64(memStats.HeapObjects), 1.0)
			stats.Inc("go.mem.mallocs", int64(memStats.Mallocs-previousMallocs), 1.0)
			stats.Inc("go.mem.frees", int64(memStats.Frees-previousFrees), 1.0)

			stats.Gauge("go.gc.percent_cpu", fractionToPercent(memStats.GCCPUFraction), 1.0)
			stats.Inc("go.gc.collections", int64(memStats.NumGC-previousNumGC), 1.0)
			stats.TimingDuration("go.gc.last_duration", time.Duration(memStats.PauseNs[(memStats.NumGC+255)%256]), 1.0)
			stats.TimingDuration("go.gc.total_duration", time.Duration(memStats.PauseTotalNs-previousGCTotal), 1.0)

			previousNumGC = memStats.NumGC
			previousMallocs = memStats.Mallocs
			previousFrees = memStats.Frees
			previousGCTotal = memStats.PauseTotalNs
		}
	}()
}

func fractionToPercent(fraction float64) int64 {
	return int64((fraction * 100) + 0.5)
}
