db changes

pull/429/head
Hunter Long 2020-03-06 14:18:06 -08:00
parent d9e47e6d3d
commit c92f99a455
30 changed files with 259 additions and 225 deletions

View File

@ -4,20 +4,20 @@ about: If you're having an issue or see an error
---
**Describe the bug**
### Describe the bug
Try to explain what issue your'e having in detail. You can copy and paste the issue from the log file in your root directory `/logs/statup.log`.
**To Reproduce**
### To Reproduce
Steps to reproduce the behavior:
1. I'm using version: '...'
2. I went to '....'
3. Press this button '....'
4. And things did '....'
**Expected Behavior**
### Expected Behavior
A clear and concise description of what you expected to happen.
**Screenshots**
### Screenshots
If applicable, add screenshots to help explain your problem.
[![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/statup-app/general) [![GitHub release](https://img.shields.io/github/release/hunterlong/statup.svg)](https://github.com/hunterlong/statping/releases/latest) [![Build Status](https://travis-ci.com/hunterlong/statup.svg?branch=master)](https://travis-ci.com/hunterlong/statup)
[![Slack](https://slack.statping.com/badge.svg)](https://slack.statping.com/) [![GitHub release](https://img.shields.io/github/release/hunterlong/statping.svg)](https://github.com/hunterlong/statping/releases/latest) [![Build Status](https://travis-ci.com/hunterlong/statping.svg?branch=master)](https://travis-ci.com/hunterlong/statping)

View File

@ -4,19 +4,19 @@ about: Suggest a feature and let's see what others say
---
**What would you like on Statping?**
### What would you like on Statping?
A clear and concise description of what you want to happen.
**Describe the solution you'd like**
### Describe the solution you'd like
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
### Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.
**Is your feature request related to a problem? Please describe.**
### Is your feature request related to a problem? Please describe.
I'm always frustrated when [...]
**Additional context**
### Additional context
Add any other context or screenshots about the feature request here.
[![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/statup-app/general) [![GitHub release](https://img.shields.io/github/release/hunterlong/statup.svg)](https://github.com/hunterlong/statping/releases/latest) [![Build Status](https://travis-ci.com/hunterlong/statup.svg?branch=master)](https://travis-ci.com/hunterlong/statup)
[![Slack](https://slack.statping.com/badge.svg)](https://slack.statping.com/) [![GitHub release](https://img.shields.io/github/release/hunterlong/statping.svg)](https://github.com/hunterlong/statping/releases/latest) [![Build Status](https://travis-ci.com/hunterlong/statping.svg?branch=master)](https://travis-ci.com/hunterlong/statping)

View File

@ -4,20 +4,20 @@ about: If you're having an issue or see an error
---
**Describe the bug**
### Describe the bug
A clear and concise description of what the bug is.
**To Reproduce**
### To Reproduce
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
### Expected behavior
A clear and concise description of what you expected to happen.
**Screenshots**
### Screenshots
If applicable, add screenshots to help explain your problem.
[![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/statup-app/general) [![GitHub release](https://img.shields.io/github/release/hunterlong/statup.svg)](https://github.com/hunterlong/statping/releases/latest) [![Build Status](https://travis-ci.com/hunterlong/statup.svg?branch=master)](https://travis-ci.com/hunterlong/statup)

View File

@ -1,16 +1,43 @@
FROM hunterlong/statping:base as base
FROM node:10.17.0 AS frontend
RUN npm install yarn -g
WORKDIR /statping
COPY ./frontend/package.json .
COPY ./frontend/yarn.lock .
RUN yarn install
COPY ./frontend .
RUN yarn build && rm -rf node_modules
FROM alpine:latest
# Statping Golang BACKEND building from source
# Creates "/go/bin/statping" and "/usr/local/bin/sass" for copying
FROM golang:1.14-alpine AS backend
LABEL maintainer="Hunter Long (https://github.com/hunterlong)"
COPY --from=base /usr/local/bin/sass /usr/local/bin/sass
COPY --from=base /go/bin/statping /usr/local/bin/statping
ARG VERSION
RUN apk add --update --no-cache libstdc++ gcc g++ make git ca-certificates linux-headers wget curl jq
RUN curl -L -s https://assets.statping.com/sass -o /usr/local/bin/sass && \
chmod +x /usr/local/bin/sass
WORKDIR /go/src/github.com/hunterlong/statping
ADD go.mod go.sum ./
RUN go mod download
ENV GO111MODULE on
RUN go get github.com/stretchr/testify/assert && \
go get github.com/stretchr/testify/require && \
go get github.com/GeertJohan/go.rice/rice && \
go get github.com/cortesi/modd/cmd/modd && \
go get github.com/crazy-max/xgo
COPY . .
COPY --from=frontend /statping/dist ./source/
RUN make clean generate embed build
RUN chmod a+x statping && mv statping /go/bin/statping
RUN apk --no-cache add curl jq
# Statping main Docker image that contains all required libraries
FROM alpine:latest
RUN apk --no-cache add libgcc libstdc++ curl jq
COPY --from=backend /go/bin/statping /usr/local/bin/
COPY --from=backend /usr/local/bin/sass /usr/local/bin/
COPY --from=backend /usr/local/share/ca-certificates /usr/local/share/
WORKDIR /app
VOLUME /app
ENV IS_DOCKER=true
ENV STATPING_DIR=/app
@ -21,3 +48,4 @@ EXPOSE $PORT
HEALTHCHECK --interval=60s --timeout=10s --retries=3 CMD curl -s "http://localhost:$PORT/health" | jq -r -e ".online==true"
CMD statping -port $PORT

View File

@ -80,15 +80,20 @@ top:
docker-compose -f docker-compose.yml -f dev/docker-compose.full.yml top
frontend-build:
cd frontend && rm -rf dist && yarn build
rm -rf source/dist && cp -r frontend/dist source/ && cp -r frontend/src/assets/scss source/dist/
rm -rf source/dist && rm -rf frontend/dist
cd frontend && yarn build
cp -r frontend/dist source/ && cp -r frontend/src/assets/scss source/dist/
cp -r source/tmpl/*.* source/dist/
# compile assets using SASS and Rice. compiles scss -> css, and run rice embed-go
compile: generate frontend-build
rm -f source/rice-box.go
cd source && rice embed-go
build: clean
embed:
cd source && rice embed-go
build:
$(GOBUILD) $(BUILDVERSION) -o $(BINARY_NAME) ./cmd
install: build

View File

@ -106,7 +106,7 @@ func catchCLI(args []string) error {
if err != nil {
return err
}
if err = configs.ConnectConfigs(config); err != nil {
if err = configs.ConnectConfigs(config, false); err != nil {
return err
}
if data, err = handlers.ExportSettings(); err != nil {
@ -206,7 +206,7 @@ func runOnce() error {
if err != nil {
return errors.Wrap(err, "config.yml file not found")
}
err = configs.ConnectConfigs(config)
err = configs.ConnectConfigs(config, false)
if err != nil {
return errors.Wrap(err, "issue connecting to database")
}

View File

@ -16,20 +16,21 @@
package main
import (
"flag"
"fmt"
"os"
"os/signal"
"syscall"
"github.com/hunterlong/statping/source"
"github.com/hunterlong/statping/database"
"github.com/hunterlong/statping/handlers"
"github.com/hunterlong/statping/types/configs"
"github.com/hunterlong/statping/types/core"
"github.com/hunterlong/statping/types/services"
"github.com/hunterlong/statping/utils"
"github.com/pkg/errors"
"flag"
"fmt"
"github.com/hunterlong/statping/handlers"
"github.com/hunterlong/statping/source"
"os"
"os/signal"
"syscall"
)
var (
@ -113,7 +114,7 @@ func main() {
}
}
if err = configs.ConnectConfigs(c); err != nil {
if err = configs.ConnectConfigs(c, true); err != nil {
exit(err)
}
@ -139,8 +140,9 @@ func SetupMode() error {
// sigterm will attempt to close the database connections gracefully
func sigterm() {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
<-sigs
fmt.Println("Shutting down Statping")
Close()
os.Exit(1)
}

View File

@ -497,6 +497,6 @@ func (it *Db) Between(t1 time.Time, t2 time.Time) Database {
}
type TimeValue struct {
Timeframe string `json:"timeframe"`
Amount float64 `json:"amount"`
Timeframe string `json:"timeframe"`
Amount int64 `json:"amount"`
}

View File

@ -68,37 +68,13 @@ func (t *TimeVar) ToValues() ([]*TimeValue, error) {
return t.data, nil
}
func (g *GroupQuery) toFloatRows() []*TimeValue {
rows, err := g.db.Rows()
if err != nil {
return nil
}
var data []*TimeValue
for rows.Next() {
var timeframe time.Time
amount := float64(0)
if err := rows.Scan(&timeframe, &amount); err != nil {
log.Errorln(err)
}
fmt.Println("float rows: ", timeframe, amount)
newTs := types.FixedTime(timeframe, g.Group)
data = append(data, &TimeValue{
Timeframe: newTs,
Amount: amount,
})
}
return data
}
// GraphData will return all hits or failures
func (g *GroupQuery) GraphData(by By) ([]*TimeValue, error) {
dbQuery := g.db.MultipleSelects(
g.db.SelectByTime(g.Group),
by.String(),
).Group("timeframe").Debug()
).Group("timeframe")
g.db = dbQuery
@ -121,7 +97,7 @@ func (g *GroupQuery) ToTimeValue() (*TimeVar, error) {
var data []*TimeValue
for rows.Next() {
var timeframe string
amount := float64(0)
amount := int64(0)
if err := rows.Scan(&timeframe, &amount); err != nil {
log.Error(err, timeframe)
}
@ -136,7 +112,7 @@ func (g *GroupQuery) ToTimeValue() (*TimeVar, error) {
}
func (t *TimeVar) FillMissing(current, end time.Time) ([]*TimeValue, error) {
timeMap := make(map[string]float64)
timeMap := make(map[string]int64)
var validSet []*TimeValue
dur := t.g.Group
for _, v := range t.data {
@ -146,7 +122,7 @@ func (t *TimeVar) FillMissing(current, end time.Time) ([]*TimeValue, error) {
currentStr := types.FixedTime(current, t.g.Group)
for {
var amount float64
var amount int64
if timeMap[currentStr] != 0 {
amount = timeMap[currentStr]
}

View File

@ -543,6 +543,10 @@ input.inputTags-field:focus {
min-height: 85pt;
}
.list-group-item:HOVER {
background-color: #fff;
}
.index_container {
min-height: 980pt;
}

View File

@ -11,6 +11,11 @@
padding: 0 !important;
}
.lower_canvas {
height: 4rem;
margin-top: -1px;
}
.list-group-item H5 {
font-size: 0.9rem;
}
@ -36,8 +41,8 @@
}
.btn-sm {
line-height: 0.9rem;
font-size: 0.65rem;
line-height: 1.4rem;
font-size: 1rem;
}
.full-col-12 {

View File

@ -126,17 +126,17 @@
visible: function(newVal, oldVal) {
if (newVal && !this.showing) {
this.showing = true
this.chartHits("1h")
this.chartHits("2h")
}
}
},
methods: {
async chartHits(group) {
const start = this.nowSubtract((3600 * 24) * 30)
this.data = await Api.service_hits(this.service.id, this.toUnix(start), this.toUnix(new Date()), group)
const start = this.nowSubtract((3600 * 24) * 3)
this.data = await Api.service_hits(this.service.id, this.toUnix(start), this.toUnix(new Date()), group, false)
if (this.data.length === 0 && group !== "1h") {
await this.chartHits("30m")
await this.chartHits("1h")
}
this.series = [{
name: this.service.name,

View File

@ -62,7 +62,7 @@
this.failures = await Api.service_failures(this.service.id, this.toUnix(start), this.toUnix(this.now()), 5)
return [{name: "None", data: []}]
}
const fetched = await Api.service_hits(this.service.id, this.toUnix(start), this.toUnix(this.now()), group)
const fetched = await Api.service_hits(this.service.id, this.toUnix(start), this.toUnix(this.now()), group, false)
if (!data) {
return [{name: "None", data: []}]
}

View File

@ -170,9 +170,7 @@
return
}
const auth = await Api.login(s.username, s.password)
this.auth = Api.saveToken(s.username, auth.token)
await this.$store.dispatch('loadAdmin')
await this.$store.dispatch('loadRequired')
this.loading = false
this.$router.push('/')

View File

@ -247,10 +247,10 @@ export default {
this.failures = await Api.service_failures(this.service.id, this.now() - 3600, this.now(), 15)
},
async chartHits() {
const start = this.nowSubtract((3600 * 24) * 7)
const start = this.nowSubtract((3600 * 24) * 3)
this.start_time = start
this.end_time = new Date()
this.data = await Api.service_hits(this.service.id, this.toUnix(start), this.toUnix(new Date()), "1h")
this.data = await Api.service_hits(this.service.id, this.toUnix(start), this.toUnix(new Date()), "15m", false)
this.series = [{
name: this.service.name,
...this.data

1
go.mod
View File

@ -8,7 +8,6 @@ require (
github.com/Microsoft/go-winio v0.4.14 // indirect
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
github.com/ararog/timeago v0.0.0-20160328174124-e9969cf18b8d
github.com/crazy-max/xgo v0.3.2 // indirect
github.com/daaku/go.zipexe v1.0.1 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/docker/distribution v2.7.1+incompatible // indirect

8
go.sum
View File

@ -1,10 +1,12 @@
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/GeertJohan/go.incremental v1.0.0 h1:7AH+pY1XUgQE4Y1HcXYaMqAI0m9yrFqo/jt0CW30vsg=
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
github.com/GeertJohan/go.rice v1.0.0 h1:KkI6O9uMaQU3VEKaj01ulavtF7o1fWT7+pk/4voiMLQ=
github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw=
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
@ -18,8 +20,6 @@ github.com/ararog/timeago v0.0.0-20160328174124-e9969cf18b8d h1:ZX0t+GA3MWiP7LWt
github.com/ararog/timeago v0.0.0-20160328174124-e9969cf18b8d/go.mod h1:EcJ034SpbWy4heOSDiBZJRn3b5wKJM1b4sFfYeVAkI4=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/crazy-max/xgo v0.3.2 h1:A5KmtgpPVzzqJzYcEmzpM0zFgCCyUar1FSvHFXxLiWA=
github.com/crazy-max/xgo v0.3.2/go.mod h1:9sA9qZWLR9koBkgNTcktix7/MVbYrLWNnIQvYYq6/DA=
github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY=
github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E=
github.com/daaku/go.zipexe v1.0.1 h1:wV4zMsDOI2SZ2m7Tdz1Ps96Zrx+TzaK15VbUaGozw0M=
@ -64,6 +64,7 @@ github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPg
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc=
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q=
github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs=
@ -92,6 +93,7 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229 h1:E2B8qYyeSgv5MXpmzZXRNp8IAQ4vjxIjhpAf5hv/tAg=
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E=
github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@ -130,7 +132,9 @@ github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e h1:nt2877sKfojlHCTOBXbpWjBkuWKritFaGIfgQwbQUls=
github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e/go.mod h1:B4+Kq1u5FlULTjFSM707Q6e/cOHFv0z/6QRoxubDIQ8=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=

View File

@ -62,11 +62,12 @@ func reorderServiceHandler(w http.ResponseWriter, r *http.Request) {
}
func apiServiceHandler(r *http.Request) interface{} {
service, err := serviceByID(r)
srv, err := serviceByID(r)
if err != nil {
return err
}
return *service
srv = srv.UpdateStats()
return *srv
}
func apiCreateServiceHandler(w http.ResponseWriter, r *http.Request) {
@ -192,15 +193,6 @@ func apiAllServicesHandler(r *http.Request) interface{} {
return services.AllInOrder()
}
func joinServices(srvss map[int64]*services.Service) []*services.Service {
var srvs []*services.Service
for _, v := range srvss {
v.UpdateStats()
srvs = append(srvs, v)
}
return srvs
}
func servicesDeleteFailuresHandler(w http.ResponseWriter, r *http.Request) {
service, err := serviceByID(r)
if err != nil {

View File

@ -20,10 +20,8 @@ import (
"github.com/hunterlong/statping/types/configs"
"github.com/hunterlong/statping/types/core"
"github.com/hunterlong/statping/types/null"
"github.com/hunterlong/statping/types/users"
"github.com/hunterlong/statping/utils"
"net/http"
"strconv"
"time"
)
@ -33,59 +31,21 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
sendErrorJson(errors.New("Statping has already been setup"), w, r)
return
}
if err = r.ParseForm(); err != nil {
log.Errorln(err)
sendErrorJson(err, w, r)
return
}
dbHost := r.PostForm.Get("db_host")
dbUser := r.PostForm.Get("db_user")
dbPass := r.PostForm.Get("db_password")
dbDatabase := r.PostForm.Get("db_database")
dbConn := r.PostForm.Get("db_connection")
dbPort := utils.ToInt(r.PostForm.Get("db_port"))
project := r.PostForm.Get("project")
username := r.PostForm.Get("username")
password := r.PostForm.Get("password")
description := r.PostForm.Get("description")
domain := r.PostForm.Get("domain")
email := r.PostForm.Get("email")
sample, _ := strconv.ParseBool(r.PostForm.Get("sample_data"))
confg := &configs.DbConfig{
DbConn: dbConn,
DbHost: dbHost,
DbUser: dbUser,
DbPass: dbPass,
DbData: dbDatabase,
DbPort: int(dbPort),
Project: project,
Description: description,
Domain: domain,
Username: username,
Password: password,
Email: email,
Error: nil,
Location: utils.Directory,
}
log.WithFields(utils.ToFields(core.App, confg)).Debugln("new configs posted")
if err := confg.Save(utils.Directory); err != nil {
confgs, err := configs.LoadConfigForm(r)
if err != nil {
log.Errorln(err)
sendErrorJson(err, w, r)
return
}
if confg, err = configs.LoadConfigFile(utils.Directory); err != nil {
log.Errorln(err)
sendErrorJson(err, w, r)
return
}
//sample, _ := strconv.ParseBool(r.PostForm.Get("sample_data"))
if err = configs.ConnectConfigs(confg); err != nil {
log.WithFields(utils.ToFields(core.App, confgs)).Debugln("new configs posted")
if err = configs.ConnectConfigs(confgs, true); err != nil {
log.Errorln(err)
if err := confg.Delete(); err != nil {
if err := confgs.Delete(); err != nil {
log.Errorln(err)
sendErrorJson(err, w, r)
return
@ -94,7 +54,13 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
return
}
if err = confg.MigrateDatabase(); err != nil {
if err := confgs.Save(utils.Directory); err != nil {
log.Errorln(err)
sendErrorJson(err, w, r)
return
}
if err = confgs.MigrateDatabase(); err != nil {
sendErrorJson(err, w, r)
return
}
@ -111,6 +77,7 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
Footer: null.NewNullString(""),
}
log.Infoln("Creating new Core")
if err := c.Create(); err != nil {
log.Errorln(err)
sendErrorJson(err, w, r)
@ -119,27 +86,22 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
core.App = c
admin := &users.User{
Username: confg.Username,
Password: confg.Password,
Email: confg.Email,
Admin: null.NewNullBool(true),
}
//if sample {
// log.Infoln("Adding sample data into new database")
// if err = configs.TriggerSamples(); err != nil {
// log.Errorln(err)
// sendErrorJson(err, w, r)
// return
// }
//}
if err := admin.Create(); err != nil {
log.Infoln("Initializing new Statping instance")
if err := core.InitApp(); err != nil {
log.Errorln(err)
sendErrorJson(err, w, r)
return
}
if sample {
if err = configs.TriggerSamples(); err != nil {
sendErrorJson(err, w, r)
return
}
}
core.InitApp()
CacheStorage.Delete("/")
resetCookies()
time.Sleep(1 * time.Second)
@ -148,11 +110,7 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
Config *configs.DbConfig `json:"config"`
}{
"success",
confg,
confgs,
}
returnJson(out, w, r)
}
func setupResponseError(w http.ResponseWriter, r *http.Request, a interface{}) {
ExecuteResponse(w, r, "setup.gohtml", a, nil)
}

View File

@ -0,0 +1,50 @@
package configs
import (
"github.com/hunterlong/statping/utils"
"github.com/pkg/errors"
"net/http"
)
func LoadConfigForm(r *http.Request) (*DbConfig, error) {
if err := r.ParseForm(); err != nil {
return nil, err
}
dbHost := r.PostForm.Get("db_host")
dbUser := r.PostForm.Get("db_user")
dbPass := r.PostForm.Get("db_password")
dbDatabase := r.PostForm.Get("db_database")
dbConn := r.PostForm.Get("db_connection")
dbPort := utils.ToInt(r.PostForm.Get("db_port"))
project := r.PostForm.Get("project")
username := r.PostForm.Get("username")
password := r.PostForm.Get("password")
description := r.PostForm.Get("description")
domain := r.PostForm.Get("domain")
email := r.PostForm.Get("email")
if project == "" || username == "" || password == "" {
err := errors.New("Missing required elements on setup form")
return nil, err
}
confg := &DbConfig{
DbConn: dbConn,
DbHost: dbHost,
DbUser: dbUser,
DbPass: dbPass,
DbData: dbDatabase,
DbPort: int(dbPort),
Project: project,
Description: description,
Domain: domain,
Username: username,
Password: password,
Email: email,
Error: nil,
Location: utils.Directory,
}
return confg, nil
}

View File

@ -19,7 +19,7 @@ func TestDbConfig_Save(t *testing.T) {
Location: utils.Directory,
}
err := ConnectConfigs(config)
err := ConnectConfigs(config, true)
require.Nil(t, err)
err = config.Save(utils.Directory)

View File

@ -99,15 +99,18 @@ func InitialSetup(configs *DbConfig) error {
return errors.Wrap(err, "error creating database")
}
username := utils.Getenv("ADMIN_USER", "admin").(string)
password := utils.Getenv("ADMIN_PASSWORD", "admin").(string)
if configs.Username == "" && configs.Password == "" {
configs.Username = utils.Getenv("ADMIN_USER", "admin").(string)
configs.Password = utils.Getenv("ADMIN_PASSWORD", "admin").(string)
}
admin := &users.User{
Username: username,
Password: password,
Username: configs.Username,
Password: configs.Password,
Email: "info@admin.com",
Admin: null.NewNullBool(true),
}
if err := admin.Create(); err != nil {
return errors.Wrap(err, "error creating admin")
}

View File

@ -11,7 +11,7 @@ import (
var log = utils.Log
func ConnectConfigs(configs *DbConfig) error {
func ConnectConfigs(configs *DbConfig, initiate bool) error {
err := Connect(configs, true)
if err != nil {
return errors.Wrap(err, "error connecting to database")
@ -21,7 +21,7 @@ func ConnectConfigs(configs *DbConfig) error {
}
exists := database.DB().HasTable("core")
if !exists {
if !exists && initiate {
return InitialSetup(configs)
}
return nil

View File

@ -3,6 +3,7 @@ package failures
import (
"fmt"
"github.com/hunterlong/statping/types"
"github.com/hunterlong/statping/utils"
"github.com/prometheus/common/log"
"sync"
"time"
@ -16,7 +17,7 @@ func Samples() {
tx := DB().Begin()
sg := new(sync.WaitGroup)
createdAt := time.Now().Add(-1 * types.Month)
createdAt := utils.Now().Add(-3 * types.Day)
for i := int64(1); i <= 4; i++ {
sg.Add(1)
@ -25,8 +26,8 @@ func Samples() {
go func() {
defer sg.Done()
for fi := 0.; fi <= float64(730); fi++ {
createdAt = createdAt.Add(2 * time.Minute)
for fi := 0.; fi <= float64(400); fi++ {
createdAt = createdAt.Add(35 * time.Minute)
failure := &Failure{
Service: i,
Issue: "testing right here",

View File

@ -63,6 +63,15 @@ func (h Hitters) Sum() float64 {
return result.amount
}
func (h Hitters) Avg() int64 {
result := struct {
amount int64
}{0}
h.db.Select("AVG(latency) as amount").Scan(&result)
return result.amount
}
func AllHits(obj ColumnIDInterfacer) Hitters {
column, id := obj.HitsColumnID()
return Hitters{DB().Where(fmt.Sprintf("%s = ?", column), id)}

View File

@ -1,7 +1,6 @@
package hits
import (
"fmt"
"github.com/hunterlong/statping/database"
"github.com/hunterlong/statping/types"
"github.com/hunterlong/statping/utils"
@ -13,13 +12,13 @@ import (
_ "github.com/jinzhu/gorm/dialects/sqlite"
)
var SampleHits = 9900.
var SampleHits = 99900.
func Samples() {
tx := DB().Begin()
sg := new(sync.WaitGroup)
for i := int64(1); i <= 4; i++ {
for i := int64(1); i <= 5; i++ {
err := createHitsAt(tx, i, sg)
if err != nil {
log.Error(err)
@ -30,14 +29,14 @@ func Samples() {
}
func createHitsAt(db database.Database, serviceID int64, sg *sync.WaitGroup) error {
createdAt := utils.Now().Add(-30 * types.Day)
createdAt := utils.Now().Add(-3 * types.Day)
p := utils.NewPerlin(2, 2, 5, utils.Now().UnixNano())
i := 0
for hi := 0.; hi <= SampleHits; hi++ {
latency := p.Noise1D(hi / 500)
createdAt = createdAt.Add(10 * time.Minute)
createdAt = createdAt.Add(30 * time.Second)
hit := &Hit{
Service: serviceID,
@ -47,10 +46,11 @@ func createHitsAt(db database.Database, serviceID int64, sg *sync.WaitGroup) err
}
db = db.Create(&hit)
fmt.Printf("Creating hit %d hit %d: %.2f %v\n", serviceID, hit.Id, latency, createdAt.String())
i++
if createdAt.After(utils.Now()) {
break
}
}
return db.Commit().Error()
}

View File

@ -133,32 +133,35 @@ func niceDomainName(domain string, paths string) string {
return domain + strings.Join(addedName, "/")
}
func (s *Service) UpdateStats() {
func (s *Service) UpdateStats() *Service {
s.Online24Hours = s.OnlineDaysPercent(1)
s.Online7Days = s.OnlineDaysPercent(7)
s.AvgResponse = s.AvgTime()
s.FailuresLast24Hours = len(s.AllFailures().Since(time.Now().UTC().Add(-time.Hour * 24)))
s.FailuresLast24Hours = len(s.AllFailures().Since(utils.Now().Add(-time.Hour * 24)))
if s.LastOffline.IsZero() {
lastFail := s.LastFailure()
if lastFail != nil {
s.LastOffline = s.LastFailure().CreatedAt
}
}
s.Stats = &Stats{
Failures: s.AllFailures().Count(),
Hits: s.AllHits().Count(),
FirstHit: s.FirstHit().CreatedAt,
}
return s
}
// AvgTime will return the average amount of time for a service to response back successfully
func (s *Service) AvgTime() float64 {
sum := s.AllHits().Sum()
return sum
}
// AvgUptime will return the average amount of time for a service to response back successfully
func (s *Service) AvgUptime(since time.Time) float64 {
sum := s.AllHits().Sum()
return sum
func (s *Service) AvgTime() int64 {
return s.AllHits().Avg()
}
// OnlineDaysPercent returns the service's uptime percent within last 24 hours
func (s *Service) OnlineDaysPercent(days int) float32 {
ago := time.Now().UTC().Add((-24 * time.Duration(days)) * time.Hour)
ago := utils.Now().Add((-24 * time.Duration(days)) * time.Hour)
return s.OnlineSince(ago)
}

View File

@ -45,7 +45,7 @@ type Service struct {
PingTime float64 `gorm:"-" json:"ping_time"`
Online24Hours float32 `gorm:"-" json:"online_24_hours"`
Online7Days float32 `gorm:"-" json:"online_7_days"`
AvgResponse float64 `gorm:"-" json:"avg_response"`
AvgResponse int64 `gorm:"-" json:"avg_response"`
FailuresLast24Hours int `gorm:"-" json:"failures_24_hours"`
Running chan bool `gorm:"-" json:"-"`
Checkpoint time.Time `gorm:"-" json:"-"`
@ -57,22 +57,25 @@ type Service struct {
DownText string `gorm:"-" json:"-"` // Contains the current generated Downtime Text
SuccessNotified bool `gorm:"-" json:"-"` // Is 'true' if the user has already be informed that the Services now again available
LastStatusCode int `gorm:"-" json:"status_code"`
LastOnline time.Time `gorm:"-" json:"last_success"`
LastOffline time.Time `gorm:"-" json:"last_error"`
Failures []*failures.Failure `gorm:"-" json:"failures,omitempty" scope:"user,admin"`
AllCheckins []*checkins.Checkin `gorm:"-" json:"checkins,omitempty" scope:"user,admin"`
Stats *Stats `gorm:"-" json:"stats,omitempty"`
LastLookupTime int64 `gorm:"-" json:"-"`
LastLatency int64 `gorm:"-" json:"-"`
LastCheck time.Time `gorm:"-" json:"-"`
LastOnline time.Time `gorm:"-" json:"last_success"`
LastOffline time.Time `gorm:"-" json:"last_error"`
Stats *Stats `gorm:"-" json:"stats,omitempty"`
SecondsOnline int64 `gorm:"-" json:"-"`
SecondsOffline int64 `gorm:"-" json:"-"`
}
type Stats struct {
Failures int `gorm:"-" json:"failures"`
Hits int `gorm:"-" json:"hits"`
Failures int `gorm:"-" json:"failures"`
Hits int `gorm:"-" json:"hits"`
LastLookupTime int64 `gorm:"-" json:"last_lookup"`
LastLatency int64 `gorm:"-" json:"last_latency"`
FirstHit time.Time `gorm:"-" json:"first_hit"`
}
// BeforeCreate for Service will set CreatedAt to UTC

View File

@ -16,7 +16,6 @@
package types
import (
"fmt"
"time"
)
@ -38,31 +37,29 @@ var (
)
func FixedTime(t time.Time, d time.Duration) string {
switch d {
case Month:
month := fmt.Sprintf("%v", int(t.Month()))
if int(t.Month()) < 10 {
month = fmt.Sprintf("0%v", int(t.Month()))
}
return fmt.Sprintf("%v-%v-01T00:00:00Z", t.Year(), month)
case Year:
return fmt.Sprintf("%v-01-01T00:00:00Z", t.Year())
default:
return t.Format(durationStr(d))
}
return t.Format(durationStr(d))
}
func durationStr(d time.Duration) string {
switch d {
case Second:
return "2006-01-02T15:04:05Z"
case Minute:
return "2006-01-02T15:04:00Z"
case Hour:
switch m := d.Seconds(); {
case m >= Month.Seconds():
return "2006-01-01T00:00:00Z"
case m >= Week.Seconds():
return "2006-01-02T00:00:00Z"
case m >= Day.Seconds():
return "2006-01-02T15:00:00Z"
case Day:
return "2006-01-02T00:00:00Z"
case m >= Hour.Seconds():
return "2006-01-02T15:04:00Z"
case m >= Minute.Seconds():
return "2006-01-02T15:04:00Z"
default:
return "2006-01-02T00:00:00Z"
return "2006-01-02T15:04:05Z"
}
}

View File

@ -1,7 +1,6 @@
package users
import (
"errors"
"github.com/hunterlong/statping/database"
"github.com/hunterlong/statping/utils"
"github.com/prometheus/common/log"
@ -32,13 +31,11 @@ func All() []*User {
func (u *User) Create() error {
u.CreatedAt = time.Now().UTC()
if u.Password == "" {
return errors.New("did not supply user password")
}
u.Password = utils.HashPassword(u.Password)
u.ApiKey = utils.NewSHA1Hash(16)
u.ApiSecret = utils.NewSHA1Hash(16)
if u.ApiKey == "" || u.ApiSecret == "" {
u.ApiKey = utils.NewSHA1Hash(16)
u.ApiSecret = utils.NewSHA1Hash(16)
}
db := DB().Create(u)
if db.Error() == nil {
log.Warnf("User #%d (%s) has been created", u.Id, u.Username)