github.com/dbernstein1/tyk@v2.9.0-beta9-dl-apic+incompatible/gateway/instrumentation_handlers.go (about) 1 package gateway 2 3 import ( 4 "net/http" 5 "os" 6 "runtime/debug" 7 "strconv" 8 "time" 9 10 "github.com/gocraft/health" 11 12 "github.com/TykTechnologies/tyk/cli" 13 "github.com/TykTechnologies/tyk/request" 14 15 "github.com/TykTechnologies/tyk/config" 16 ) 17 18 var applicationGCStats = debug.GCStats{} 19 var instrument = health.NewStream() 20 var instrumentationEnabled bool 21 22 // setupInstrumentation handles all the intialisation of the instrumentation handler 23 func setupInstrumentation() { 24 switch { 25 case *cli.LogInstrumentation: 26 case os.Getenv("TYK_INSTRUMENTATION") == "1": 27 default: 28 return 29 } 30 31 if config.Global().StatsdConnectionString == "" { 32 log.Error("Instrumentation is enabled, but no connectionstring set for statsd") 33 return 34 } 35 36 instrumentationEnabled = true 37 38 log.Info("Sending stats to: ", config.Global().StatsdConnectionString, " with prefix: ", config.Global().StatsdPrefix) 39 statsdSink, err := NewStatsDSink(config.Global().StatsdConnectionString, 40 &StatsDSinkOptions{Prefix: config.Global().StatsdPrefix}) 41 42 if err != nil { 43 log.Fatal("Failed to start StatsD check: ", err) 44 } 45 46 log.Info("StatsD instrumentation sink started") 47 instrument.AddSink(statsdSink) 48 49 MonitorApplicationInstrumentation() 50 } 51 52 // InstrumentationMW will set basic instrumentation events, variables and timers on API jobs 53 func InstrumentationMW(next http.Handler) http.Handler { 54 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 55 job := instrument.NewJob("SystemAPICall") 56 57 next.ServeHTTP(w, r) 58 job.EventKv("called", health.Kvs{ 59 "from_ip": request.RealIP(r), 60 "method": r.Method, 61 "endpoint": r.URL.Path, 62 "raw_url": r.URL.String(), 63 "size": strconv.Itoa(int(r.ContentLength)), 64 }) 65 job.Complete(health.Success) 66 }) 67 } 68 69 func MonitorApplicationInstrumentation() { 70 log.Info("Starting application monitoring...") 71 go func() { 72 job := instrument.NewJob("GCActivity") 73 job_rl := instrument.NewJob("Load") 74 metadata := health.Kvs{"host": hostDetails.Hostname} 75 applicationGCStats.PauseQuantiles = make([]time.Duration, 5) 76 77 for { 78 debug.ReadGCStats(&applicationGCStats) 79 job.GaugeKv("pauses_quantile_min", float64(applicationGCStats.PauseQuantiles[0].Nanoseconds()), metadata) 80 job.GaugeKv("pauses_quantile_25", float64(applicationGCStats.PauseQuantiles[1].Nanoseconds()), metadata) 81 job.GaugeKv("pauses_quantile_50", float64(applicationGCStats.PauseQuantiles[2].Nanoseconds()), metadata) 82 job.GaugeKv("pauses_quantile_75", float64(applicationGCStats.PauseQuantiles[3].Nanoseconds()), metadata) 83 job.GaugeKv("pauses_quantile_max", float64(applicationGCStats.PauseQuantiles[4].Nanoseconds()), metadata) 84 85 job_rl.GaugeKv("rps", float64(GlobalRate.Rate()), metadata) 86 time.Sleep(5 * time.Second) 87 } 88 }() 89 }