pull/10/head
Hunter Long 2018-06-29 20:40:00 -07:00
parent 6dc81e6849
commit 3866da7aad
11 changed files with 97 additions and 69 deletions

View File

@ -18,7 +18,7 @@ services:
env: env:
global: global:
- VERSION=0.27.8 - VERSION=0.27.81
- DB_HOST=localhost - DB_HOST=localhost
- DB_USER=travis - DB_USER=travis
- DB_PASS= - DB_PASS=

View File

@ -20,9 +20,9 @@ curl -s -X POST \
-d "$body" \ -d "$body" \
https://api.travis-ci.com/repo/hunterlong%2Fhomebrew-statup/requests https://api.travis-ci.com/repo/hunterlong%2Fhomebrew-statup/requests
if [ "$TRAVIS_BRANCH" == "master" ] #if [ "$TRAVIS_BRANCH" == "master" ]
then #then
curl -X POST $DOCKER > /dev/null # curl -X POST $DOCKER > /dev/null
else #else
curl -H "Content-Type: application/json" --data '{"source_type": "Tag", "source_name": "v'"$VERSION"'"}' -X POST $DOCKER > /dev/null # curl -H "Content-Type: application/json" --data '{"source_type": "Tag", "source_name": "v'"$VERSION"'"}' -X POST $DOCKER > /dev/null
fi #fi

View File

@ -1,6 +1,6 @@
FROM alpine:latest FROM alpine:latest
ENV VERSION=v0.27.8 ENV VERSION=v0.27.81
RUN apk --no-cache add libstdc++ ca-certificates RUN apk --no-cache add libstdc++ ca-certificates
RUN wget -q https://github.com/hunterlong/statup/releases/download/$VERSION/statup-linux-alpine.tar.gz && \ RUN wget -q https://github.com/hunterlong/statup/releases/download/$VERSION/statup-linux-alpine.tar.gz && \

View File

@ -96,10 +96,11 @@ aws ec2 run-instances \
``` ```
## Prometheus Exporter ## Prometheus Exporter
Statup includes a prometheus exporter so you can have even more monitoring power with your services. The prometheus exporter can be seen on `/metrics`, simply create another exporter in your prometheus config. Statup includes a prometheus exporter so you can have even more monitoring power with your services. The prometheus exporter can be seen on `/metrics`, simply create another exporter in your prometheus config. Use your Statup API Secret for the Authorization Bearer header, the `/metrics` URL is dedicated for Prometheus and requires the correct API Secret has `Authorization` header.
```yaml ```yaml
scrape_configs: scrape_configs:
- job_name: 'statup' - job_name: 'statup'
bearer_token: MY API SECRET HERE
static_configs: static_configs:
- targets: ['statup:8080'] - targets: ['statup:8080']
``` ```

View File

@ -116,18 +116,17 @@ func (c *DbConfig) Save() error {
DropDatabase() DropDatabase()
CreateDatabase() CreateDatabase()
newCore := Core{ newCore := &Core{
Name: c.Project, Name: c.Project,
Description: c.Description, Description: c.Description,
Config: "config.yml", Config: "config.yml",
ApiKey: utils.NewSHA1Hash(5), ApiKey: utils.NewSHA1Hash(9),
ApiSecret: utils.NewSHA1Hash(10), ApiSecret: utils.NewSHA1Hash(16),
Domain: c.Domain, Domain: c.Domain,
} }
col := DbSession.Collection("core") col := DbSession.Collection("core")
_, err = col.Insert(newCore) _, err = col.Insert(newCore)
return err return err
} }

View File

@ -104,6 +104,21 @@ type DateScan struct {
Value int64 `json:"y"` Value int64 `json:"y"`
} }
func (s *Service) SmallText() string {
last := s.LimitedFailures()
hits, _ := s.LimitedHits()
if !s.Online {
return fmt.Sprintf("%v at %v", last[0].ParseError(), last[0].CreatedAt.Format("Monday 3:04PM, Jan _2 2006"))
} else {
if len(last) == 0 {
return fmt.Sprintf("Online since %v", s.CreatedAt.Format("Monday 3:04PM, Jan _2 2006"))
} else {
return fmt.Sprintf("Online, last failure was %v", hits[0].CreatedAt.Format("Monday 3:04PM, Jan _2 2006"))
}
}
return fmt.Sprintf("No Failures in the last 24 hours! %v", hits[0])
}
func (s *Service) GraphData() string { func (s *Service) GraphData() string {
var d []DateScan var d []DateScan
increment := "minute" increment := "minute"

View File

@ -3,12 +3,24 @@ package handlers
import ( import (
"fmt" "fmt"
"github.com/hunterlong/statup/core" "github.com/hunterlong/statup/core"
"github.com/hunterlong/statup/utils"
"net/http" "net/http"
"strings" "strings"
) )
func PrometheusHandler(w http.ResponseWriter, r *http.Request) { func PrometheusHandler(w http.ResponseWriter, r *http.Request) {
fmt.Printf("Prometheus /metrics Request From IP: %v\n", r.RemoteAddr) utils.Log(1, fmt.Sprintf("Prometheus /metrics Request From IP: %v\n", r.RemoteAddr))
var token string
tokens, ok := r.Header["Authorization"]
if ok && len(tokens) >= 1 {
token = tokens[0]
token = strings.TrimPrefix(token, "Bearer ")
}
if token != core.CoreApp.ApiSecret {
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
return
}
metrics := []string{} metrics := []string{}
system := fmt.Sprintf("statup_total_failures %v\n", core.CountFailures()) system := fmt.Sprintf("statup_total_failures %v\n", core.CountFailures())
system += fmt.Sprintf("statup_total_services %v", len(core.CoreApp.Services)) system += fmt.Sprintf("statup_total_services %v", len(core.CoreApp.Services))

View File

@ -52,7 +52,7 @@ func Router() *mux.Router {
r.Handle("/api/services/{id}", http.HandlerFunc(ApiServiceUpdateHandler)).Methods("POST") r.Handle("/api/services/{id}", http.HandlerFunc(ApiServiceUpdateHandler)).Methods("POST")
r.Handle("/api/users", http.HandlerFunc(ApiAllUsersHandler)) r.Handle("/api/users", http.HandlerFunc(ApiAllUsersHandler))
r.Handle("/api/users/{id}", http.HandlerFunc(ApiUserHandler)) r.Handle("/api/users/{id}", http.HandlerFunc(ApiUserHandler))
r.Handle("/metrics", http.HandlerFunc(PrometheusHandler)).Methods("GET") r.Handle("/metrics", http.HandlerFunc(PrometheusHandler))
Store = sessions.NewCookieStore([]byte("secretinfo")) Store = sessions.NewCookieStore([]byte("secretinfo"))
return r return r
} }

View File

@ -82,7 +82,7 @@
{{ end }} {{ end }}
<div class="lower_canvas full-col-12 text-white{{if not .Online}} bg-danger{{end}}"> <div class="lower_canvas full-col-12 text-white{{if not .Online}} bg-danger{{end}}">
<div class="col-12"> <div class="col-12">
<span>No failures within the last 25 days</span> <span>{{.SmallText}}</span>
<a href="/service/{{ .Id }}" class="btn {{if .Online}}btn-success{{else}}btn-danger{{end}} btn-sm float-right">View Service</a> <a href="/service/{{ .Id }}" class="btn {{if .Online}}btn-success{{else}}btn-danger{{end}} btn-sm float-right">View Service</a>
</div> </div>
</div> </div>

View File

@ -64,6 +64,17 @@
<button type="submit" class="btn btn-primary btn-block">Save Settings</button> <button type="submit" class="btn btn-primary btn-block">Save Settings</button>
<div class="form-group">
<label for="formGroupExampleInput">API Key</label>
<input type="text" name="description" class="form-control" value="{{ .ApiKey }}" id="formGroupExampleInput" readonly>
</div>
<div class="form-group">
<label for="formGroupExampleInput">API Secret</label>
<input type="text" name="description" class="form-control" value="{{ .ApiSecret }}" id="formGroupExampleInput" readonly>
</div>
</form> </form>
</div> </div>

View File

@ -52,53 +52,25 @@
<canvas id="service" width="400" height="120"></canvas> <canvas id="service" width="400" height="120"></canvas>
{{ range .Failures }} {{ if .LimitedFailures }}
<blockquote class="blockquote text-right mt-3"> <div class="list-group mt-5">
<p class="mb-0">{{.ParseError}}</p> {{ range .LimitedFailures }}
<footer class="blockquote-footer">Reported <cite title="Source Title">{{.Ago}}</cite></footer> <a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
</blockquote> <div class="d-flex w-100 justify-content-between">
{{ end }} <h5 class="mb-1">{{.ParseError}}</h5>
<small>Reported {{.Ago}}</small>
</div>
<p class="mb-1">{{.Issue}}</p>
</a>
{{ end }}
</div>
{{ end }}
</div> </div>
{{if Auth}} {{if Auth}}
<div class="col-12 mt-4">
<h3>Service Checkins</h3>
{{ range .Checkins }}
<div class="col-12 mt-3">
<h5>Check #{{.Id}} <span class="badge online_badge float-right">Checked in {{.Ago}}</span></h5>
<input type="text" class="form-control" value="https://domainhere.com/api/checkin/{{.Api}}">
</div>
{{ end }}
<form action="/service/{{.Id}}/checkin" method="POST">
<div class="form-group row">
<label for="service_name" class="col-sm-4 col-form-label">Check Interval (in seconds)</label>
<div class="col-sm-8">
<input type="number" name="name" class="form-control" id="checkin_interval" value="30" placeholder="Name">
</div>
</div>
<div class="form-group row">
<div class="col-sm-10">
<button type="submit" class="btn btn-success">Save Checkin</button>
</div>
</div>
</form>
</div>
<div class="col-12 mt-4"> <div class="col-12 mt-4">
<h3>Edit Service</h3> <h3>Edit Service</h3>
@ -186,19 +158,37 @@
{{end}} {{end}}
{{ if .LimitedFailures }} <div class="col-12 mt-4">
<div class="list-group mt-5"> <h3>Service Checkins</h3>
{{ range .LimitedFailures }}
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start"> {{ range .Checkins }}
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">{{.ParseError}}</h5> <h5>Check #{{.Id}} <span class="badge online_badge float-right">Checked in {{.Ago}}</span></h5>
<small>Reported {{.Ago}}</small>
</div> <input type="text" class="form-control" value="https://domainhere.com/api/checkin/{{.Api}}">
<p class="mb-1">{{.Issue}}</p>
</a>
{{ end }} </div>
{{ end }}
<form action="/service/{{.Id}}/checkin" method="POST">
<div class="form-group row">
<label for="service_name" class="col-sm-4 col-form-label">Check Interval (in seconds)</label>
<div class="col-sm-8">
<input type="number" name="name" class="form-control" id="checkin_interval" value="30" placeholder="Name">
</div>
</div> </div>
{{ end }} <div class="form-group row">
<div class="col-sm-10">
<button type="submit" class="btn btn-success">Save Checkin</button>
</div>
</div>
</form>
</div>
</div> </div>