mirror of https://github.com/statping/statping
parent
fc1fe03f89
commit
9a6c91a997
|
@ -49,26 +49,41 @@ func SelectCheckin(api string) *Checkin {
|
|||
return &checkin
|
||||
}
|
||||
|
||||
func FindCheckin(api string) *types.Checkin {
|
||||
for _, ser := range CoreApp.Services {
|
||||
service := ser.Select()
|
||||
for _, c := range service.Checkins {
|
||||
if c.ApiKey == api {
|
||||
return c
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
func (u Checkin) Period() time.Duration {
|
||||
duration, _ := time.ParseDuration(fmt.Sprintf("%vs", u.Interval))
|
||||
return duration
|
||||
}
|
||||
|
||||
func (u Checkin) Grace() time.Duration {
|
||||
duration, _ := time.ParseDuration(fmt.Sprintf("%vs", u.GracePeriod))
|
||||
return duration
|
||||
}
|
||||
|
||||
func (u Checkin) Expected() time.Duration {
|
||||
last := u.Last().CreatedAt
|
||||
now := time.Now()
|
||||
lastDir := now.Sub(last)
|
||||
sub := time.Duration(u.Period() - lastDir)
|
||||
return sub
|
||||
}
|
||||
|
||||
func (u Checkin) Last() CheckinHit {
|
||||
var hit CheckinHit
|
||||
checkinHitsDB().Where("checkin = ?", u.Id).Last(&hit)
|
||||
return hit
|
||||
}
|
||||
|
||||
func (u *Checkin) Hits() []CheckinHit {
|
||||
var checkins []CheckinHit
|
||||
checkinDB().Where("checkin = ?", u.Id).Order("id DESC").Find(&checkins)
|
||||
checkinHitsDB().Where("checkin = ?", u.Id).Order("id DESC").Find(&checkins)
|
||||
return checkins
|
||||
}
|
||||
|
||||
func (u *Checkin) Create() (int64, error) {
|
||||
u.CreatedAt = time.Now()
|
||||
if u.CreatedAt.IsZero() {
|
||||
u.CreatedAt = time.Now()
|
||||
}
|
||||
u.ApiKey = utils.NewSHA1Hash(7)
|
||||
row := checkinDB().Create(u)
|
||||
if row.Error == nil {
|
||||
utils.Log(2, row.Error)
|
||||
|
@ -78,7 +93,9 @@ func (u *Checkin) Create() (int64, error) {
|
|||
}
|
||||
|
||||
func (u *CheckinHit) Create() (int64, error) {
|
||||
u.CreatedAt = time.Now()
|
||||
if u.CreatedAt.IsZero() {
|
||||
u.CreatedAt = time.Now()
|
||||
}
|
||||
row := checkinHitsDB().Create(u)
|
||||
if row.Error == nil {
|
||||
utils.Log(2, row.Error)
|
||||
|
|
|
@ -108,6 +108,16 @@ func (u *User) AfterFind() (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (s *Checkin) AfterFind() (err error) {
|
||||
s.CreatedAt = utils.Timezoner(s.CreatedAt, CoreApp.Timezone)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *CheckinHit) AfterFind() (err error) {
|
||||
s.CreatedAt = utils.Timezoner(s.CreatedAt, CoreApp.Timezone)
|
||||
return
|
||||
}
|
||||
|
||||
func (u *Hit) BeforeCreate() (err error) {
|
||||
if u.CreatedAt.IsZero() {
|
||||
u.CreatedAt = time.Now().UTC()
|
||||
|
@ -130,6 +140,16 @@ func (u *Service) BeforeCreate() (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (u *Checkin) BeforeCreate() (err error) {
|
||||
u.CreatedAt = time.Now().UTC()
|
||||
return
|
||||
}
|
||||
|
||||
func (u *CheckinHit) BeforeCreate() (err error) {
|
||||
u.CreatedAt = time.Now().UTC()
|
||||
return
|
||||
}
|
||||
|
||||
// InsertCore create the single row for the Core settings in Statup
|
||||
func (db *DbConfig) InsertCore() (*Core, error) {
|
||||
CoreApp = &Core{Core: &types.Core{
|
||||
|
|
|
@ -84,6 +84,31 @@ func InsertSampleData() error {
|
|||
s4.Create(false)
|
||||
s5.Create(false)
|
||||
|
||||
checkin1 := ReturnCheckin(&types.Checkin{
|
||||
Service: s1.Id,
|
||||
Interval: 300,
|
||||
GracePeriod: 300,
|
||||
})
|
||||
checkin1.Create()
|
||||
|
||||
checkin2 := ReturnCheckin(&types.Checkin{
|
||||
Service: s2.Id,
|
||||
Interval: 900,
|
||||
GracePeriod: 300,
|
||||
})
|
||||
checkin2.Create()
|
||||
|
||||
checkTime := time.Now().Add(-24 * time.Hour)
|
||||
for i := 0; i <= 60; i++ {
|
||||
checkHit := ReturnCheckinHit(&types.CheckinHit{
|
||||
Checkin: checkin1.Id,
|
||||
From: "192.168.0.1",
|
||||
CreatedAt: checkTime.UTC(),
|
||||
})
|
||||
checkHit.Create()
|
||||
checkTime = checkTime.Add(10 * time.Minute)
|
||||
}
|
||||
|
||||
utils.Log(1, "Sample data has finished importing")
|
||||
|
||||
return nil
|
||||
|
@ -114,39 +139,6 @@ func InsertSampleHits() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func sampleGraphData(i float64, upward *bool) float64 {
|
||||
alpha := 0.0003
|
||||
if *upward {
|
||||
i += 0.3
|
||||
if i >= 6500 {
|
||||
i += 0.1
|
||||
*upward = false
|
||||
} else if i >= 4500 {
|
||||
i += 3
|
||||
} else if i >= 2300 {
|
||||
i += 1
|
||||
} else if i >= 1150 {
|
||||
i += 2
|
||||
} else if i >= 500 {
|
||||
i += 1
|
||||
}
|
||||
} else {
|
||||
i -= 0.3
|
||||
if i <= 6500 {
|
||||
i -= 0.1
|
||||
} else if i <= 4500 {
|
||||
i -= 3
|
||||
} else if i <= 2300 {
|
||||
i -= 1
|
||||
} else if i <= 1150 {
|
||||
i -= 2
|
||||
} else if i <= 500 {
|
||||
i -= 1
|
||||
}
|
||||
}
|
||||
return i * alpha
|
||||
}
|
||||
|
||||
func insertSampleCore() error {
|
||||
core := &types.Core{
|
||||
Name: "Statup Sample Data",
|
||||
|
|
|
@ -49,9 +49,9 @@ func SelectService(id int64) *Service {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) Checkins() []*Checkin {
|
||||
var hits []*Checkin
|
||||
servicesDB().Where("service = ?", s.Id).Find(&hits)
|
||||
func (s *Service) Checkin() Checkin {
|
||||
var hits Checkin
|
||||
servicesDB().Where("service = ?", s.Id).First(&hits)
|
||||
return hits
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,7 @@ func (c *Core) SelectAllServices() ([]*Service, error) {
|
|||
CoreApp.Services = nil
|
||||
for _, service := range services {
|
||||
service.Start()
|
||||
service.Checkins()
|
||||
service.Checkin()
|
||||
service.AllFailures()
|
||||
CoreApp.Services = append(CoreApp.Services, service)
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ func apiCheckinHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
vars := mux.Vars(r)
|
||||
checkin := core.FindCheckin(vars["api"])
|
||||
checkin := core.SelectCheckin(vars["api"])
|
||||
//checkin.Receivehit()
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(checkin)
|
||||
|
|
|
@ -137,6 +137,25 @@ var handlerFuncs = func(w http.ResponseWriter, r *http.Request) template.FuncMap
|
|||
"ToString": func(v interface{}) string {
|
||||
return utils.ToString(v)
|
||||
},
|
||||
"Ago": func(t time.Time) string {
|
||||
return utils.Timestamp(t).Ago()
|
||||
},
|
||||
"Duration": func(t time.Duration) string {
|
||||
var out string
|
||||
duration, _ := time.ParseDuration(fmt.Sprintf("%vs", t.Seconds()))
|
||||
if duration.Minutes() < 1 {
|
||||
out = fmt.Sprintf("%0.0f second", duration.Seconds())
|
||||
if duration.Seconds() >= 2 {
|
||||
out += "s"
|
||||
}
|
||||
} else {
|
||||
out = fmt.Sprintf("%0.0f minute", duration.Minutes())
|
||||
if duration.Minutes() >= 2 {
|
||||
out += "s"
|
||||
}
|
||||
}
|
||||
return out
|
||||
},
|
||||
"ToUnix": func(t time.Time) int64 {
|
||||
return t.UTC().Unix()
|
||||
},
|
||||
|
|
|
@ -53,6 +53,31 @@ func Router() *mux.Router {
|
|||
r.Handle("/dashboard", http.HandlerFunc(dashboardHandler)).Methods("GET")
|
||||
r.Handle("/dashboard", http.HandlerFunc(loginHandler)).Methods("POST")
|
||||
r.Handle("/logout", http.HandlerFunc(logoutHandler))
|
||||
r.Handle("/checkin/{id}", http.HandlerFunc(checkinUpdateHandler))
|
||||
r.Handle("/plugins/download/{name}", http.HandlerFunc(pluginsDownloadHandler))
|
||||
r.Handle("/plugins/{name}/save", http.HandlerFunc(pluginSavedHandler)).Methods("POST")
|
||||
r.Handle("/help", http.HandlerFunc(helpHandler))
|
||||
r.Handle("/logs", http.HandlerFunc(logsHandler))
|
||||
r.Handle("/logs/line", http.HandlerFunc(logsLineHandler))
|
||||
|
||||
// USER Routes
|
||||
r.Handle("/users", http.HandlerFunc(usersHandler)).Methods("GET")
|
||||
r.Handle("/users", http.HandlerFunc(createUserHandler)).Methods("POST")
|
||||
r.Handle("/user/{id}", http.HandlerFunc(usersEditHandler)).Methods("GET")
|
||||
r.Handle("/user/{id}", http.HandlerFunc(updateUserHandler)).Methods("POST")
|
||||
r.Handle("/user/{id}/delete", http.HandlerFunc(usersDeleteHandler)).Methods("GET")
|
||||
|
||||
// SETTINGS Routes
|
||||
r.Handle("/settings", http.HandlerFunc(settingsHandler)).Methods("GET")
|
||||
r.Handle("/settings", http.HandlerFunc(saveSettingsHandler)).Methods("POST")
|
||||
r.Handle("/settings/css", http.HandlerFunc(saveSASSHandler)).Methods("POST")
|
||||
r.Handle("/settings/build", http.HandlerFunc(saveAssetsHandler)).Methods("GET")
|
||||
r.Handle("/settings/delete_assets", http.HandlerFunc(deleteAssetsHandler)).Methods("GET")
|
||||
r.Handle("/settings/notifier/{method}", http.HandlerFunc(saveNotificationHandler)).Methods("POST")
|
||||
r.Handle("/settings/notifier/{method}/test", http.HandlerFunc(testNotificationHandler)).Methods("POST")
|
||||
r.Handle("/settings/export", http.HandlerFunc(exportHandler)).Methods("GET")
|
||||
|
||||
// SERVICE Routes
|
||||
r.Handle("/services", http.HandlerFunc(servicesHandler)).Methods("GET")
|
||||
r.Handle("/services", http.HandlerFunc(createServiceHandler)).Methods("POST")
|
||||
r.Handle("/services/reorder", http.HandlerFunc(reorderServiceHandler)).Methods("POST")
|
||||
|
@ -62,27 +87,8 @@ func Router() *mux.Router {
|
|||
r.Handle("/service/{id}/delete", http.HandlerFunc(servicesDeleteHandler))
|
||||
r.Handle("/service/{id}/delete_failures", http.HandlerFunc(servicesDeleteFailuresHandler)).Methods("GET")
|
||||
r.Handle("/service/{id}/checkin", http.HandlerFunc(checkinCreateUpdateHandler)).Methods("POST")
|
||||
r.Handle("/checkin/{id}", http.HandlerFunc(checkinUpdateHandler))
|
||||
r.Handle("/users", http.HandlerFunc(usersHandler)).Methods("GET")
|
||||
r.Handle("/users", http.HandlerFunc(createUserHandler)).Methods("POST")
|
||||
r.Handle("/user/{id}", http.HandlerFunc(usersEditHandler)).Methods("GET")
|
||||
r.Handle("/user/{id}", http.HandlerFunc(updateUserHandler)).Methods("POST")
|
||||
r.Handle("/user/{id}/delete", http.HandlerFunc(usersDeleteHandler)).Methods("GET")
|
||||
r.Handle("/settings", http.HandlerFunc(settingsHandler)).Methods("GET")
|
||||
r.Handle("/settings", http.HandlerFunc(saveSettingsHandler)).Methods("POST")
|
||||
r.Handle("/settings/css", http.HandlerFunc(saveSASSHandler)).Methods("POST")
|
||||
r.Handle("/settings/build", http.HandlerFunc(saveAssetsHandler)).Methods("GET")
|
||||
r.Handle("/settings/delete_assets", http.HandlerFunc(deleteAssetsHandler)).Methods("GET")
|
||||
r.Handle("/settings/notifier/{method}", http.HandlerFunc(saveNotificationHandler)).Methods("POST")
|
||||
r.Handle("/settings/notifier/{method}/test", http.HandlerFunc(testNotificationHandler)).Methods("POST")
|
||||
r.Handle("/settings/export", http.HandlerFunc(exportHandler)).Methods("GET")
|
||||
r.Handle("/plugins/download/{name}", http.HandlerFunc(pluginsDownloadHandler))
|
||||
r.Handle("/plugins/{name}/save", http.HandlerFunc(pluginSavedHandler)).Methods("POST")
|
||||
r.Handle("/help", http.HandlerFunc(helpHandler))
|
||||
r.Handle("/logs", http.HandlerFunc(logsHandler))
|
||||
r.Handle("/logs/line", http.HandlerFunc(logsLineHandler))
|
||||
|
||||
// SERVICE API Routes
|
||||
// API SERVICE Routes
|
||||
r.Handle("/api/services", http.HandlerFunc(apiAllServicesHandler)).Methods("GET")
|
||||
r.Handle("/api/services", http.HandlerFunc(apiCreateServiceHandler)).Methods("POST")
|
||||
r.Handle("/api/services/{id}", http.HandlerFunc(apiServiceHandler)).Methods("GET")
|
||||
|
@ -91,7 +97,7 @@ func Router() *mux.Router {
|
|||
r.Handle("/api/services/{id}", http.HandlerFunc(apiServiceUpdateHandler)).Methods("POST")
|
||||
r.Handle("/api/services/{id}", http.HandlerFunc(apiServiceDeleteHandler)).Methods("DELETE")
|
||||
|
||||
// USER API Routes
|
||||
// API USER Routes
|
||||
r.Handle("/api/users", http.HandlerFunc(apiAllUsersHandler)).Methods("GET")
|
||||
r.Handle("/api/users", http.HandlerFunc(apiCreateUsersHandler)).Methods("POST")
|
||||
r.Handle("/api/users/{id}", http.HandlerFunc(apiUserHandler)).Methods("GET")
|
||||
|
@ -103,8 +109,8 @@ func Router() *mux.Router {
|
|||
r.Handle("/api/renew", http.HandlerFunc(apiRenewHandler))
|
||||
r.Handle("/api/checkin/{api}", http.HandlerFunc(apiCheckinHandler))
|
||||
r.Handle("/metrics", http.HandlerFunc(prometheusHandler))
|
||||
r.NotFoundHandler = http.HandlerFunc(error404Handler)
|
||||
r.Handle("/tray", http.HandlerFunc(trayHandler))
|
||||
r.NotFoundHandler = http.HandlerFunc(error404Handler)
|
||||
return r
|
||||
}
|
||||
|
||||
|
|
|
@ -268,7 +268,6 @@ func checkinCreateUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
|||
Service: service.Id,
|
||||
Interval: interval,
|
||||
GracePeriod: grace,
|
||||
ApiKey: utils.NewSHA1Hash(18),
|
||||
})
|
||||
checkin.Create()
|
||||
executeResponse(w, r, "service.html", service, fmt.Sprintf("/service/%v", service.Id))
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
<input type="number" name="expected_status" class="form-control" value="{{if ne .ExpectedStatus 0}}{{.ExpectedStatus}}{{end}}" placeholder="200" id="service_response_code">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row{{if eq .Type "http"}} d-none{{end}}">
|
||||
<div class="form-group row{{if eq .Type ""}} d-none{{else if eq .Type "http"}} d-none{{end}}">
|
||||
<label for="service_port" class="col-sm-4 col-form-label">TCP Port</label>
|
||||
<div class="col-sm-8">
|
||||
<input type="number" name="port" class="form-control" value="{{if ne .Port 0}}{{.Port}}{{end}}" id="service_port" placeholder="8080">
|
||||
|
|
|
@ -96,18 +96,27 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 mt-4{{if eq $s.Type "tcp"}} d-none{{end}}">
|
||||
<h3>Service Checkins</h3>
|
||||
{{ range $s.Checkins }}
|
||||
<h5>Check #{{.Id}} <span class="badge online_badge float-right">Checked in</span></h5>
|
||||
<input type="text" class="form-control" value="{{CoreApp.Domain}}/checkin/{{.ApiKey}}">
|
||||
<ul class="list-group">
|
||||
{{ range .Hits }}
|
||||
<li class="list-group-item">Received Checkin at {{.CreatedAt}}</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
{{ end }}
|
||||
|
||||
<div class="col-12 mt-4">
|
||||
<h3>Service Checkin</h3>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Checkin</th>
|
||||
<th scope="col">Report Period<br>Grace Period</th>
|
||||
<th scope="col">Last Seen</th>
|
||||
<th scope="col">Expected</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{$ch := $s.Checkin}}
|
||||
<tr>
|
||||
<td>{{CoreApp.Domain}}/checkin/{{$ch.ApiKey}}</td>
|
||||
<td>every {{Duration $ch.Period}}<br>{{Duration $ch.Grace}} grace period</td>
|
||||
<td>{{Ago $ch.Last.CreatedAt}}</td>
|
||||
<td>{{ if lt $ch.Expected 0}}{{Duration $ch.Expected}} ago{{else}}in {{Duration $ch.Expected}}{{end}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{{template "form_checkin" $s}}
|
||||
|
||||
</div>
|
||||
|
|
|
@ -20,14 +20,13 @@ import (
|
|||
)
|
||||
|
||||
type Checkin struct {
|
||||
Id int64 `gorm:"primary_key;column:id"`
|
||||
Service int64 `gorm:"index;column:service"`
|
||||
Interval int64 `gorm:"column:check_interval"`
|
||||
GracePeriod int64 `gorm:"column:grace_period"`
|
||||
ApiKey string `gorm:"column:api_key"`
|
||||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
||||
Hits []CheckinHit `json:"hits"`
|
||||
Id int64 `gorm:"primary_key;column:id"`
|
||||
Service int64 `gorm:"index;column:service"`
|
||||
Interval int64 `gorm:"column:check_interval"`
|
||||
GracePeriod int64 `gorm:"column:grace_period"`
|
||||
ApiKey string `gorm:"column:api_key"`
|
||||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
||||
}
|
||||
|
||||
type CheckinHit struct {
|
||||
|
|
|
@ -46,7 +46,7 @@ type Service struct {
|
|||
LastStatusCode int `gorm:"-" json:"status_code"`
|
||||
LastOnline time.Time `gorm:"-" json:"last_online"`
|
||||
Failures []interface{} `gorm:"-" json:"failures,omitempty"`
|
||||
Checkins []*Checkin `gorm:"-" json:"checkins,omitempty"`
|
||||
//Checkins []*Checkin `gorm:"-" json:"checkins,omitempty"`
|
||||
}
|
||||
|
||||
type ServiceInterface interface {
|
||||
|
|
Loading…
Reference in New Issue