mirror of https://github.com/statping/statping
json http handler - improved sample chart data
parent
2548606224
commit
a03498e035
|
@ -19,10 +19,14 @@ import (
|
|||
"fmt"
|
||||
"github.com/hunterlong/statping/types"
|
||||
"github.com/hunterlong/statping/utils"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
sampleStart = time.Now().Add((-24 * 7) * time.Hour).UTC()
|
||||
sampleHits = 9900.
|
||||
)
|
||||
|
||||
// InsertSampleData will create the example/dummy services for a brand new Statping installation
|
||||
func InsertSampleData() error {
|
||||
utils.Log(1, "Inserting Sample Data...")
|
||||
|
@ -163,26 +167,31 @@ func insertSampleCheckins() error {
|
|||
|
||||
// InsertSampleHits will create a couple new hits for the sample services
|
||||
func InsertSampleHits() error {
|
||||
since := time.Now().Add((-24 * 7) * time.Hour).UTC()
|
||||
for i := int64(1); i <= 5; i++ {
|
||||
service := SelectService(i)
|
||||
utils.Log(1, fmt.Sprintf("Adding %v sample hit records to service %v", 360, service.Name))
|
||||
createdAt := since
|
||||
alpha := float64(1.05)
|
||||
|
||||
for hi := int64(1); hi <= 168; hi++ {
|
||||
alpha += 0.01
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
latency := rand.Float64() * alpha
|
||||
createdAt = createdAt.Add(1 * time.Hour)
|
||||
for i := int64(1); i <= 5; i++ {
|
||||
|
||||
service := SelectService(i)
|
||||
seed := time.Now().UnixNano()
|
||||
|
||||
utils.Log(1, fmt.Sprintf("Adding %v sample hit records to service %v", sampleHits, service.Name))
|
||||
createdAt := sampleStart
|
||||
|
||||
p := utils.NewPerlin(2., 2., 10, seed)
|
||||
|
||||
for hi := 0.; hi <= float64(sampleHits); hi++ {
|
||||
|
||||
latency := p.Noise1D(hi / 500)
|
||||
createdAt = createdAt.Add(60 * time.Second)
|
||||
hit := &types.Hit{
|
||||
Service: service.Id,
|
||||
CreatedAt: createdAt,
|
||||
Latency: latency,
|
||||
}
|
||||
service.CreateHit(hit)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -397,7 +406,7 @@ func InsertLargeSampleData() error {
|
|||
|
||||
var dayAgo = time.Now().Add((-24 * 90) * time.Hour)
|
||||
|
||||
insertHitRecords(dayAgo, 1450)
|
||||
insertHitRecords(dayAgo, 5450)
|
||||
|
||||
insertFailureRecords(dayAgo, 730)
|
||||
|
||||
|
@ -432,9 +441,16 @@ func insertHitRecords(since time.Time, amount int64) {
|
|||
utils.Log(1, fmt.Sprintf("Adding %v hit records to service %v", amount, service.Name))
|
||||
createdAt := since
|
||||
|
||||
p := utils.NewPerlin(2, 2, 5, time.Now().UnixNano())
|
||||
|
||||
utils.Log(1, fmt.Sprint(p))
|
||||
|
||||
for hi := int64(1); hi <= amount; hi++ {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
latency := rand.Float64()
|
||||
|
||||
latency := p.Noise1D(float64(hi / 10))
|
||||
|
||||
fmt.Printf("%0.0f\t%0.4f\n", hi, latency)
|
||||
|
||||
createdAt = createdAt.Add(1 * time.Minute)
|
||||
hit := &types.Hit{
|
||||
Service: service.Id,
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/hunterlong/statping/core"
|
||||
|
@ -42,8 +41,7 @@ func apiIndexHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
coreClone := *core.CoreApp
|
||||
coreClone.Started = utils.Timezoner(core.CoreApp.Started, core.CoreApp.Timezone)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(coreClone)
|
||||
returnJson(coreClone, w, r)
|
||||
}
|
||||
|
||||
func apiRenewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -77,8 +75,7 @@ func sendErrorJson(err error, w http.ResponseWriter, r *http.Request) {
|
|||
Status: "error",
|
||||
Error: err.Error(),
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(output)
|
||||
returnJson(output, w, r)
|
||||
}
|
||||
|
||||
func sendJsonAction(obj interface{}, method string, w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -132,8 +129,7 @@ func sendJsonAction(obj interface{}, method string, w http.ResponseWriter, r *ht
|
|||
Output: obj,
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(output)
|
||||
returnJson(output, w, r)
|
||||
}
|
||||
|
||||
func sendUnauthorizedJson(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -141,7 +137,6 @@ func sendUnauthorizedJson(w http.ResponseWriter, r *http.Request) {
|
|||
Status: "error",
|
||||
Error: errors.New("not authorized").Error(),
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
json.NewEncoder(w).Encode(output)
|
||||
returnJson(output, w, r)
|
||||
}
|
||||
|
|
|
@ -37,8 +37,7 @@ func apiAllCheckinsHandler(w http.ResponseWriter, r *http.Request) {
|
|||
c.Hits = c.AllHits()
|
||||
c.Failures = c.LimitedFailures(64)
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(checkins)
|
||||
returnJson(checkins, w, r)
|
||||
}
|
||||
|
||||
func apiCheckinHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -54,8 +53,7 @@ func apiCheckinHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
checkin.Hits = checkin.LimitedHits(32)
|
||||
checkin.Failures = checkin.LimitedFailures(32)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(checkin)
|
||||
returnJson(checkin, w, r)
|
||||
}
|
||||
|
||||
func checkinCreateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
|
@ -32,8 +32,7 @@ func apiAllGroupHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
auth := IsUser(r)
|
||||
groups := core.SelectGroups(false, auth)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(groups)
|
||||
returnJson(groups, w, r)
|
||||
}
|
||||
|
||||
// apiGroupHandler will show a single group
|
||||
|
@ -48,8 +47,7 @@ func apiGroupHandler(w http.ResponseWriter, r *http.Request) {
|
|||
sendErrorJson(errors.New("group not found"), w, r)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(group)
|
||||
returnJson(group, w, r)
|
||||
}
|
||||
|
||||
// apiCreateGroupHandler accepts a POST method to create new groups
|
||||
|
@ -112,6 +110,5 @@ func apiGroupReorderHandler(w http.ResponseWriter, r *http.Request) {
|
|||
group.Order = g.Order
|
||||
group.Update()
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(newOrder)
|
||||
returnJson(newOrder, w, r)
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ package handlers
|
|||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/hunterlong/statping/core"
|
||||
|
@ -256,6 +257,12 @@ func executeJSResponse(w http.ResponseWriter, r *http.Request, file string, data
|
|||
}
|
||||
}
|
||||
|
||||
func returnJson(d interface{}, w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
json.NewEncoder(w).Encode(d)
|
||||
}
|
||||
|
||||
// error404Handler is a HTTP handler for 404 error pages
|
||||
func error404Handler(w http.ResponseWriter, r *http.Request) {
|
||||
if usingSSL {
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/hunterlong/statping/core"
|
||||
"net/http"
|
||||
)
|
||||
|
@ -30,10 +29,9 @@ func indexHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
func healthCheckHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
health := map[string]interface{}{
|
||||
"services": len(core.Services()),
|
||||
"online": core.Configs != nil,
|
||||
}
|
||||
json.NewEncoder(w).Encode(health)
|
||||
returnJson(health, w, r)
|
||||
}
|
||||
|
|
|
@ -59,8 +59,7 @@ func apiAllMessagesHandler(w http.ResponseWriter, r *http.Request) {
|
|||
sendErrorJson(err, w, r)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(messages)
|
||||
returnJson(messages, w, r)
|
||||
}
|
||||
|
||||
func apiMessageCreateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -95,8 +94,7 @@ func apiMessageGetHandler(w http.ResponseWriter, r *http.Request) {
|
|||
sendErrorJson(err, w, r)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(message)
|
||||
returnJson(message, w, r)
|
||||
}
|
||||
|
||||
func apiMessageDeleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
|
@ -36,8 +36,7 @@ func apiNotifiersHandler(w http.ResponseWriter, r *http.Request) {
|
|||
notif := n.(notifier.Notifier)
|
||||
notifiers = append(notifiers, notif.Select())
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(notifiers)
|
||||
returnJson(notifiers, w, r)
|
||||
}
|
||||
|
||||
func apiNotifierGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -51,8 +50,7 @@ func apiNotifierGetHandler(w http.ResponseWriter, r *http.Request) {
|
|||
sendErrorJson(err, w, r)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(notifierObj)
|
||||
returnJson(notifierObj, w, r)
|
||||
}
|
||||
|
||||
func apiNotifierUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
|
@ -78,8 +78,7 @@ func reorderServiceHandler(w http.ResponseWriter, r *http.Request) {
|
|||
service.Order = s.Order
|
||||
service.Update(false)
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(newOrder)
|
||||
returnJson(newOrder, w, r)
|
||||
}
|
||||
|
||||
func servicesViewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -141,8 +140,7 @@ func apiServiceHandler(w http.ResponseWriter, r *http.Request) {
|
|||
sendErrorJson(errors.New("service not found"), w, r)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(servicer)
|
||||
returnJson(servicer, w, r)
|
||||
}
|
||||
|
||||
func apiCreateServiceHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -207,8 +205,7 @@ func apiServiceDataHandler(w http.ResponseWriter, r *http.Request) {
|
|||
end := time.Unix(endField, 0)
|
||||
|
||||
obj := core.GraphDataRaw(service, start, end, grouping, "latency")
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(obj)
|
||||
returnJson(obj, w, r)
|
||||
}
|
||||
|
||||
func apiServicePingDataHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -227,9 +224,7 @@ func apiServicePingDataHandler(w http.ResponseWriter, r *http.Request) {
|
|||
end := time.Unix(endField, 0)
|
||||
|
||||
obj := core.GraphDataRaw(service, start, end, grouping, "ping_time")
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(obj)
|
||||
returnJson(obj, w, r)
|
||||
}
|
||||
|
||||
type dataXy struct {
|
||||
|
@ -285,9 +280,7 @@ func apiServiceHeatmapHandler(w http.ResponseWriter, r *http.Request) {
|
|||
month = 1
|
||||
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(monthOutput)
|
||||
returnJson(monthOutput, w, r)
|
||||
}
|
||||
|
||||
func apiServiceDeleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -315,8 +308,7 @@ func apiAllServicesHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
services := core.Services()
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(services)
|
||||
returnJson(services, w, r)
|
||||
}
|
||||
|
||||
func servicesDeleteFailuresHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -345,8 +337,7 @@ func apiServiceFailuresHandler(w http.ResponseWriter, r *http.Request) {
|
|||
sendErrorJson(errors.New("service not found"), w, r)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(servicer.AllFailures())
|
||||
returnJson(servicer.AllFailures(), w, r)
|
||||
}
|
||||
|
||||
func apiServiceHitsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -367,6 +358,5 @@ func apiServiceHitsHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(hits)
|
||||
returnJson(hits, w, r)
|
||||
}
|
||||
|
|
|
@ -59,8 +59,7 @@ func apiUserHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
user.Password = ""
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(user)
|
||||
returnJson(user, w, r)
|
||||
}
|
||||
|
||||
func apiUserUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -121,8 +120,7 @@ func apiAllUsersHandler(w http.ResponseWriter, r *http.Request) {
|
|||
sendErrorJson(err, w, r)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(users)
|
||||
returnJson(users, w, r)
|
||||
}
|
||||
|
||||
func apiCreateUsersHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
File diff suppressed because one or more lines are too long
114
utils/utils.go
114
utils/utils.go
|
@ -22,6 +22,8 @@ import (
|
|||
"github.com/ararog/timeago"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
@ -288,3 +290,115 @@ func HttpRequest(url, method string, content interface{}, headers []string, body
|
|||
contents, err := ioutil.ReadAll(resp.Body)
|
||||
return contents, resp, err
|
||||
}
|
||||
|
||||
const (
|
||||
B = 0x100
|
||||
N = 0x1000
|
||||
BM = 0xff
|
||||
)
|
||||
|
||||
func NewPerlin(alpha, beta float64, n int, seed int64) *Perlin {
|
||||
return NewPerlinRandSource(alpha, beta, n, rand.NewSource(seed))
|
||||
}
|
||||
|
||||
// Perlin is the noise generator
|
||||
type Perlin struct {
|
||||
alpha float64
|
||||
beta float64
|
||||
n int
|
||||
|
||||
p [B + B + 2]int
|
||||
g3 [B + B + 2][3]float64
|
||||
g2 [B + B + 2][2]float64
|
||||
g1 [B + B + 2]float64
|
||||
}
|
||||
|
||||
func NewPerlinRandSource(alpha, beta float64, n int, source rand.Source) *Perlin {
|
||||
var p Perlin
|
||||
var i int
|
||||
|
||||
p.alpha = alpha
|
||||
p.beta = beta
|
||||
p.n = n
|
||||
|
||||
r := rand.New(source)
|
||||
|
||||
for i = 0; i < B; i++ {
|
||||
p.p[i] = i
|
||||
p.g1[i] = float64((r.Int()%(B+B))-B) / B
|
||||
|
||||
for j := 0; j < 2; j++ {
|
||||
p.g2[i][j] = float64((r.Int()%(B+B))-B) / B
|
||||
}
|
||||
|
||||
normalize2(&p.g2[i])
|
||||
}
|
||||
|
||||
for ; i > 0; i-- {
|
||||
k := p.p[i]
|
||||
j := r.Int() % B
|
||||
p.p[i] = p.p[j]
|
||||
p.p[j] = k
|
||||
}
|
||||
|
||||
for i := 0; i < B+2; i++ {
|
||||
p.p[B+i] = p.p[i]
|
||||
p.g1[B+i] = p.g1[i]
|
||||
for j := 0; j < 2; j++ {
|
||||
p.g2[B+i][j] = p.g2[i][j]
|
||||
}
|
||||
for j := 0; j < 3; j++ {
|
||||
p.g3[B+i][j] = p.g3[i][j]
|
||||
}
|
||||
}
|
||||
|
||||
return &p
|
||||
}
|
||||
|
||||
func normalize2(v *[2]float64) {
|
||||
s := math.Sqrt(v[0]*v[0] + v[1]*v[1])
|
||||
v[0] = v[0] / s
|
||||
v[1] = v[1] / s
|
||||
}
|
||||
|
||||
func (p *Perlin) Noise1D(x float64) float64 {
|
||||
var scale float64 = 1
|
||||
var sum float64
|
||||
px := x
|
||||
|
||||
for i := 0; i < p.n; i++ {
|
||||
val := p.noise1(px)
|
||||
sum += val / scale
|
||||
scale *= p.alpha
|
||||
px *= p.beta
|
||||
}
|
||||
if sum < 0 {
|
||||
sum = sum * -1
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
func (p *Perlin) noise1(arg float64) float64 {
|
||||
var vec [1]float64
|
||||
vec[0] = arg
|
||||
|
||||
t := vec[0] + N
|
||||
bx0 := int(t) & BM
|
||||
bx1 := (bx0 + 1) & BM
|
||||
rx0 := t - float64(int(t))
|
||||
rx1 := rx0 - 1.
|
||||
|
||||
sx := sCurve(rx0)
|
||||
u := rx0 * p.g1[p.p[bx0]]
|
||||
v := rx1 * p.g1[p.p[bx1]]
|
||||
|
||||
return lerp(sx, u, v)
|
||||
}
|
||||
|
||||
func sCurve(t float64) float64 {
|
||||
return t * t * (3. - 2.*t)
|
||||
}
|
||||
|
||||
func lerp(t, a, b float64) float64 {
|
||||
return a + t*(b-a)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue