checkin - notifier docs

pull/78/head
Hunter Long 2018-10-05 20:35:53 -07:00
parent bb3ab30a61
commit f5e15258c8
9 changed files with 177 additions and 61 deletions

View File

@ -9,7 +9,7 @@
# Statup - Status Page & Monitoring Server
An easy to use Status Page for your websites and applications. Statup will automatically fetch the application and render a beautiful status page with tons of features for you to build an even better status page. This Status Page generator allows you to use MySQL, Postgres, or SQLite on multiple operating systems.
[![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/statup-app/general)
[![GoDoc](https://godoc.org/github.com/golang/gddo?status.svg)](https://godoc.org/github.com/hunterlong/statup) [![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/statup-app/general)
## A Future-Proof Status Page
Statup strives to remain future-proof and remain intact if a failure is created. Your Statup service should not be running on the same instance you're trying to monitor. If your server crashes your Status Page should still remaining online to notify your users of downtime.

View File

@ -20,7 +20,6 @@ import (
"github.com/ararog/timeago"
"github.com/hunterlong/statup/types"
"github.com/hunterlong/statup/utils"
"github.com/jinzhu/gorm"
"time"
)
@ -80,17 +79,18 @@ func (u *Checkin) Hits() []CheckinHit {
return checkins
}
func (u *Checkin) Update() (int64, error) {
fmt.Println("updating: ", u.Id, u.ApiKey)
exists := checkinDB().Find(&u).RecordNotFound()
var row *gorm.DB
if !exists {
row = checkinDB().Update(&u)
} else {
func (u *Checkin) Create() (int64, error) {
u.ApiKey = utils.RandomString(7)
row = checkinDB().Create(&u)
row := checkinDB().Create(&u)
if row.Error != nil {
utils.Log(2, row.Error)
return 0, row.Error
}
fmt.Println("found: ", exists, u.Id, u.Service, u.Interval, u.GracePeriod, u.ApiKey)
return u.Id, row.Error
}
func (u *Checkin) Update() (int64, error) {
row := checkinDB().Update(&u)
if row.Error != nil {
utils.Log(2, row.Error)
return 0, row.Error

View File

@ -33,7 +33,7 @@ var example = &ExampleNotifier{&Notification{
Description: "Example Notifier",
Author: "Hunter Long",
AuthorUrl: "https://github.com/hunterlong",
Delay: time.Duration(200 * time.Millisecond),
Delay: time.Duration(3 * time.Second),
Limits: 7,
Form: []NotificationForm{{
Type: "text",
@ -182,7 +182,7 @@ func (n *ExampleNotifier) OnUpdatedNotifier(s *Notification) {
}
// Create a new notifier that includes a form for the end user to insert their own values
func Example() {
func ExampleNotification() {
// Create a new variable for your Notifier
example = &ExampleNotifier{&Notification{
Method: "Example",
@ -198,29 +198,91 @@ func Example() {
Placeholder: "Insert your Host here.",
DbField: "host",
SmallText: "you can also use SmallText to insert some helpful hints under this input",
}, {
Type: "text",
Title: "API Key",
Placeholder: "Include some type of API key here",
DbField: "api_key",
}},
}}
// AddNotifier accepts a notifier to load into the Statup Notification system
AddNotifier(example)
// AddNotifier accepts a Notifier to load into the Statup Notification system
err := AddNotifier(example)
fmt.Println(err)
// Output: <nil>
}
// Add any type of interface to the AddQueue function when a service is successful
func Example_onSuccess() {
// Add a Notifier to the AddQueue function to insert it into the system
func ExampleAddNotifier() {
err := AddNotifier(example)
fmt.Println(err)
// Output: <nil>
}
// OnSuccess will be triggered everytime a service is online
func ExampleNotification_OnSuccess() {
msg := fmt.Sprintf("this is a successful message as a string passing into AddQueue function")
example.AddQueue(msg)
fmt.Println(len(example.Queue))
// Output: 1
}
// Add any type of interface to the AddQueue function when a service is successful
func Example_onFailure() {
// Add any type of interface to the AddQueue function to be ran in the queue
func ExampleNotification_AddQueue() {
msg := fmt.Sprintf("this is a failing message as a string passing into AddQueue function")
example.AddQueue(msg)
queue := example.Queue
fmt.Printf("Example has %v items in the queue", len(queue))
// Output: Example has 2 items in the queue
}
// The Send method will run the main functionality of your notifier
func Example_send() {
// example.Send(msg interface{})
for i := 0; i <= 10; i++ {
fmt.Printf("do something awesome rather than a loop %v\n", i)
func ExampleNotification_Send() {
msg := "this can be any type of interface"
example.Send(msg)
queue := example.Queue
fmt.Printf("Example has %v items in the queue", len(queue))
// Output:
// i received this string: this can be any type of interface
// Example has 2 items in the queue
}
// LastSent will return the time.Duration of the last sent message
func ExampleNotification_LastSent() {
last := example.LastSent()
fmt.Printf("Last message was sent %v seconds ago", last.Seconds())
// Output: Last message was sent 0 seconds ago
}
// Logs will return a slice of previously sent items from your notifier
func ExampleNotification_Logs() {
logs := example.Logs()
fmt.Printf("Example has %v items in the log", len(logs))
// Output: Example has 0 items in the log
}
// SentLastMinute will return he amount of notifications sent in last 1 minute
func ExampleNotification_SentLastMinute() {
lastMinute := example.SentLastMinute()
fmt.Printf("%v notifications sent in the last minute", lastMinute)
// Output: 0 notifications sent in the last minute
}
// SentLastHour will return he amount of notifications sent in last 1 hour
func ExampleNotification_SentLastHour() {
lastHour := example.SentLastHour()
fmt.Printf("%v notifications sent in the last hour", lastHour)
// Output: 0 notifications sent in the last hour
}
// SentLastHour will return he amount of notifications sent in last 1 hour
func ExampleNotification_WithinLimits() {
ok, err := example.WithinLimits()
if err != nil {
panic(err)
}
if ok {
fmt.Printf("Example notifier is still within its sending limits")
}
// Output: Example notifier is still within its sending limits
}

View File

@ -94,18 +94,14 @@ func SetDB(d *gorm.DB) {
db = d
}
func asNotifier(n interface{}) Notifier {
return n.(Notifier)
}
func asNotification(n interface{}) *Notification {
return n.(Notifier).Select()
func asNotification(n Notifier) *Notification {
return n.Select()
}
// AddNotifier accept a Notifier interface to be added into the array
func AddNotifier(n interface{}) error {
func AddNotifier(n Notifier) error {
if isType(n, new(Notifier)) {
err := checkNotifierForm(asNotifier(n))
err := checkNotifierForm(n)
if err != nil {
return err
}

View File

@ -231,10 +231,9 @@ func TestRunAllQueueAndStop(t *testing.T) {
assert.True(t, example.IsRunning())
assert.Equal(t, 16, len(example.Queue))
go Queue(example)
assert.Equal(t, 16, len(example.Queue))
time.Sleep(12 * time.Second)
assert.Equal(t, 6, len(example.Queue))
time.Sleep(13 * time.Second)
assert.True(t, len(example.Queue) >= 10)
example.close()
assert.False(t, example.IsRunning())
assert.Equal(t, 6, len(example.Queue))
assert.True(t, len(example.Queue) >= 10)
}

View File

@ -49,10 +49,10 @@ func SelectService(id int64) *Service {
return nil
}
func (s *Service) Checkin() *Checkin {
var checkin types.Checkin
checkinDB().Find(&checkin, "service = ?", s.Id)
return &Checkin{&checkin}
func (s *Service) Checkins() []*Checkin {
var checkin []*Checkin
checkinDB().Where("service = ?", s.Id).Find(&checkin)
return checkin
}
// SelectAllServices returns a slice of *core.Service to be store on []*core.Services, should only be called once on startup.
@ -66,7 +66,7 @@ func (c *Core) SelectAllServices() ([]*Service, error) {
CoreApp.Services = nil
for _, service := range services {
service.Start()
service.Checkin()
service.Checkins()
service.AllFailures()
CoreApp.Services = append(CoreApp.Services, service)
}

View File

@ -17,6 +17,7 @@ package core
import (
"github.com/hunterlong/statup/types"
"github.com/hunterlong/statup/utils"
"github.com/stretchr/testify/assert"
"testing"
"time"
@ -224,7 +225,7 @@ func TestCreateFailingHTTPService(t *testing.T) {
func TestServiceFailedCheck(t *testing.T) {
service := SelectService(17)
assert.Equal(t, "Bad URL", service.Name)
service.Check(true)
service.Check(false)
assert.Equal(t, "Bad URL", service.Name)
assert.False(t, service.Online)
}
@ -249,7 +250,7 @@ func TestCreateFailingTCPService(t *testing.T) {
func TestServiceFailedTCPCheck(t *testing.T) {
service := SelectService(newServiceId)
service.Check(true)
service.Check(false)
assert.Equal(t, "Bad TCP", service.Name)
assert.False(t, service.Online)
}
@ -342,3 +343,57 @@ func TestDNScheckService(t *testing.T) {
assert.Nil(t, err)
assert.NotZero(t, amount)
}
func TestCreateCheckin(t *testing.T) {
checkin := ReturnCheckin(&types.Checkin{
Service: 1,
Interval: 10,
GracePeriod: 5,
ApiKey: utils.RandomString(7),
})
id, err := checkin.Create()
assert.Nil(t, err)
assert.NotZero(t, id)
}
func TestSelectCheckin(t *testing.T) {
service := SelectService(1)
checkins := service.Checkins()
assert.NotNil(t, checkins)
assert.Equal(t, 1, len(checkins))
first := checkins[0]
assert.Equal(t, int64(10), first.Interval)
assert.Equal(t, 7, len(first.ApiKey))
assert.Equal(t, int64(5), first.GracePeriod)
}
func TestCreateCheckinHits(t *testing.T) {
service := SelectService(1)
checkins := service.Checkins()
first := checkins[0]
created := time.Now().Add(-2 * time.Hour)
for i := 0; i <= 20; i++ {
hit := ReturnCheckinHit(&types.CheckinHit{
Checkin: first.Id,
From: "192.168.1.1",
CreatedAt: created,
})
hit.Create()
created = created.Add(10 * time.Second)
}
hits := first.Hits()
assert.Equal(t, 21, len(hits))
}
func TestSelectCheckinMethods(t *testing.T) {
time.Sleep(5 * time.Second)
service := SelectService(1)
checkins := service.Checkins()
assert.NotNil(t, checkins)
first := checkins[0]
lastHit := first.Last()
assert.Equal(t, float64(10), first.Period().Seconds())
assert.Equal(t, float64(5), first.Grace().Seconds())
assert.Equal(t, time.Now().Day(), lastHit.CreatedAt.Day())
assert.Equal(t, "Just now", lastHit.Ago())
}

View File

@ -261,7 +261,9 @@ func checkinCreateUpdateHandler(w http.ResponseWriter, r *http.Request) {
}
vars := mux.Vars(r)
service := core.SelectService(utils.StringInt(vars["id"]))
checkin := service.Checkin()
api := r.PostForm.Get("api")
checkin := core.SelectCheckin(api)
interval := utils.StringInt(r.PostForm.Get("interval"))
grace := utils.StringInt(r.PostForm.Get("grace"))
checkin.Interval = interval

View File

@ -105,16 +105,18 @@
</tr>
</thead>
<tbody>
{{$ch := $s.Checkin}}
{{range $s.Checkins}}
{{ $ch := . }}
<tr class="{{ if lt $ch.Expected 0}}bg-danger text-white{{else}}bg-light{{end}}">
<td>{{CoreApp.Domain}}/checkin/{{$ch.ApiKey}}</td>
<td>every {{Duration $ch.Period}}<br>after {{Duration $ch.Grace}}</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>
{{template "form_checkin" $ch}}
{{end}}
</tbody>
</table>
{{template "form_checkin" $ch}}
</div>