json http handler - improved sample chart data

pull/156/head
Hunter Long 2019-03-01 17:33:41 -08:00
parent 2548606224
commit a03498e035
12 changed files with 178 additions and 69 deletions

View File

@ -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,

View File

@ -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)
}

View File

@ -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) {

View File

@ -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)
}

View File

@ -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 {

View File

@ -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)
}

View File

@ -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) {

View File

@ -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) {

View File

@ -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)
}

View File

@ -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

View File

@ -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)
}