mirror of https://github.com/statping/statping
vue
parent
cb7787f26c
commit
05c77a5e98
|
@ -272,10 +272,16 @@ type DateScanObj struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GraphDataRaw will return all the hits between 2 times for a Service
|
// GraphDataRaw will return all the hits between 2 times for a Service
|
||||||
func GraphHitsDataRaw(service types.ServiceInterface, start, end time.Time, group string, column string) *DateScanObj {
|
func GraphHitsDataRaw(service types.ServiceInterface, query types.GroupQuery, column string) *DateScanObj {
|
||||||
model := service.(*Service).HitsBetween(start, end, group, column)
|
srv := service.(*Service)
|
||||||
model = model.Order("timeframe asc", false).Group("timeframe")
|
|
||||||
outgoing, err := model.ToChart()
|
dbQuery := Database(&types.Hit{}).
|
||||||
|
Where("service = ?", srv.Id).
|
||||||
|
Between(query.Start, query.End).
|
||||||
|
MultipleSelects(Database(&types.Hit{}).SelectByTime(query.Group), types.CountAmount()).
|
||||||
|
GroupByTimeframe()
|
||||||
|
|
||||||
|
outgoing, err := dbQuery.ToChart()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -283,16 +289,16 @@ func GraphHitsDataRaw(service types.ServiceInterface, start, end time.Time, grou
|
||||||
}
|
}
|
||||||
|
|
||||||
// GraphDataRaw will return all the hits between 2 times for a Service
|
// GraphDataRaw will return all the hits between 2 times for a Service
|
||||||
func GraphFailuresDataRaw(service types.ServiceInterface, start, end time.Time, group string) []*types.TimeValue {
|
func GraphFailuresDataRaw(service types.ServiceInterface, query types.GroupQuery) []*types.TimeValue {
|
||||||
srv := service.(*Service)
|
srv := service.(*Service)
|
||||||
|
|
||||||
query := Database(&types.Failure{}).
|
dbQuery := Database(&types.Failure{}).
|
||||||
Where("service = ?", srv.Id).
|
Where("service = ?", srv.Id).
|
||||||
Between(start, end).
|
Between(query.Start, query.End).
|
||||||
MultipleSelects(types.SelectByTime(group), types.CountAmount()).
|
MultipleSelects(Database(&types.Failure{}).SelectByTime(query.Group), types.CountAmount()).
|
||||||
GroupByTimeframe().Debug()
|
GroupByTimeframe()
|
||||||
|
|
||||||
outgoing, err := query.ToTimeValue(start, end)
|
outgoing, err := dbQuery.ToTimeValue(query.Start, query.End)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +1 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/hunterlong/statping/utils"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SparklineDayFailures returns a string array of daily service failures
|
|
||||||
func (s *Service) SparklineDayFailures(days int) string {
|
|
||||||
var arr []string
|
|
||||||
ago := time.Now().UTC().Add((time.Duration(days) * -24) * time.Hour)
|
|
||||||
for day := 1; day <= days; day++ {
|
|
||||||
ago = ago.Add(24 * time.Hour)
|
|
||||||
failures, _ := s.TotalFailuresOnDate(ago)
|
|
||||||
arr = append(arr, utils.ToString(failures))
|
|
||||||
}
|
|
||||||
return "[" + strings.Join(arr, ",") + "]"
|
|
||||||
}
|
|
||||||
|
|
||||||
// SparklineHourResponse returns a string array for the average response or ping time for a service
|
|
||||||
func (s *Service) SparklineHourResponse(hours int, method string) string {
|
|
||||||
var arr []string
|
|
||||||
end := time.Now().UTC()
|
|
||||||
start := end.Add(time.Duration(-hours) * time.Hour)
|
|
||||||
obj := GraphHitsDataRaw(s, start, end, "hour", method)
|
|
||||||
for _, v := range obj.Array {
|
|
||||||
arr = append(arr, utils.ToString(v.Value))
|
|
||||||
}
|
|
||||||
return "[" + strings.Join(arr, ",") + "]"
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
version: '3.1'
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
mysql_data: {}
|
||||||
|
postgres_data: {}
|
||||||
|
|
||||||
|
services:
|
||||||
|
|
||||||
|
mysql:
|
||||||
|
image: mysql:5.7
|
||||||
|
volumes:
|
||||||
|
- mysql_data:/var/lib/mysql
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- 3306:3306
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: password123
|
||||||
|
MYSQL_DATABASE: statping
|
||||||
|
MYSQL_USER: root
|
||||||
|
MYSQL_PASSWORD: password
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
container_name: postgres
|
||||||
|
image: postgres:10.0-alpine
|
||||||
|
ports:
|
||||||
|
- 5432:5432
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data/pg_data
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: password123
|
||||||
|
POSTGRES_DB: statping
|
||||||
|
POSTGRES_USER: root
|
||||||
|
POSTGRES_PORT: 5432
|
||||||
|
PGDATA: /var/lib/postgresql/data/pg_data
|
||||||
|
|
||||||
|
phpmyadmin:
|
||||||
|
image: phpmyadmin/phpmyadmin
|
||||||
|
container_name: phpmyadmin
|
||||||
|
environment:
|
||||||
|
- PMA_HOST=mysql
|
||||||
|
- PMA_USER=root
|
||||||
|
- PMA_PASSWORD=password123
|
||||||
|
restart: always
|
||||||
|
depends_on:
|
||||||
|
- mysql
|
||||||
|
links:
|
||||||
|
- mysql
|
||||||
|
ports:
|
||||||
|
- 7474:80
|
||||||
|
volumes:
|
||||||
|
- /sessions
|
|
@ -2,9 +2,52 @@ statping:
|
||||||
container_name: statping
|
container_name: statping
|
||||||
image: hunterlong/statping
|
image: hunterlong/statping
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
|
||||||
- 8080:8080
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./statping:/app
|
- statping_data:/app
|
||||||
environment:
|
environment:
|
||||||
DB_CONN: sqlite
|
DB_CONN: sqlite
|
||||||
|
LETSENCRYPT_HOST: demo.statping.com
|
||||||
|
VIRTUAL_HOST: demo.statping.com
|
||||||
|
VIRTUAL_PORT: 8080
|
||||||
|
|
||||||
|
prometheus:
|
||||||
|
container_name: prometheus
|
||||||
|
image: prom/prometheus:v2.0.0
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- 9090:9090
|
||||||
|
volumes:
|
||||||
|
- prometheus_config_data:/etc/prometheus/
|
||||||
|
- prometheus_data:/prometheus
|
||||||
|
links:
|
||||||
|
- statping
|
||||||
|
depends_on:
|
||||||
|
- statping
|
||||||
|
|
||||||
|
grafana:
|
||||||
|
container_name: grafana
|
||||||
|
image: grafana/grafana
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- 3000:3000
|
||||||
|
volumes:
|
||||||
|
- grafana_data:/var/lib/grafana
|
||||||
|
environment:
|
||||||
|
- GF_SECURITY_ADMIN_PASSWORD=password123
|
||||||
|
- GF_USERS_ALLOW_SIGN_UP=false
|
||||||
|
depends_on:
|
||||||
|
- prometheus
|
||||||
|
links:
|
||||||
|
- prometheus
|
||||||
|
|
||||||
|
|
||||||
|
global:
|
||||||
|
scrape_interval: 30s
|
||||||
|
evaluation_interval: 30s
|
||||||
|
|
||||||
|
scrape_configs:
|
||||||
|
- job_name: 'statping'
|
||||||
|
scrape_interval: 30s
|
||||||
|
bearer_token: 'SECRET API KEY HERE'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['statping:8080']
|
||||||
|
|
|
@ -37,7 +37,7 @@ class Api {
|
||||||
}
|
}
|
||||||
|
|
||||||
async service_hits(id, start, end, group) {
|
async service_hits(id, start, end, group) {
|
||||||
return axios.get('/api/services/' + id + '/data?start=' + start + '&end=' + end + '&group=' + group).then(response => (response.data))
|
return axios.get('/api/services/' + id + '/hits_data?start=' + start + '&end=' + end + '&group=' + group).then(response => (response.data))
|
||||||
}
|
}
|
||||||
|
|
||||||
async service_failures_data(id, start, end, group) {
|
async service_failures_data(id, start, end, group) {
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
this.set1 = await this.getHits(24 * 2, "hour")
|
this.set1 = await this.getHits(24, "minute")
|
||||||
this.set1_name = this.calc(this.set1)
|
this.set1_name = this.calc(this.set1)
|
||||||
this.set2 = await this.getHits(24 * 7, "hour")
|
this.set2 = await this.getHits(24 * 7, "hour")
|
||||||
this.set2_name = this.calc(this.set2)
|
this.set2_name = this.calc(this.set2)
|
||||||
|
|
|
@ -126,9 +126,9 @@ func Router() *mux.Router {
|
||||||
api.Handle("/api/services/{id}/hits", scoped(apiServiceHitsHandler)).Methods("GET")
|
api.Handle("/api/services/{id}/hits", scoped(apiServiceHitsHandler)).Methods("GET")
|
||||||
|
|
||||||
// API SERVICE CHART DATA Routes
|
// API SERVICE CHART DATA Routes
|
||||||
api.Handle("/api/services/{id}/data", cached("30s", "application/json", apiServiceDataHandler)).Methods("GET")
|
api.Handle("/api/services/{id}/hits_data", cached("30s", "application/json", apiServiceDataHandler)).Methods("GET")
|
||||||
api.Handle("/api/services/{id}/failure_data", cached("30s", "application/json", apiServiceFailureDataHandler)).Methods("GET")
|
api.Handle("/api/services/{id}/failure_data", cached("30s", "application/json", apiServiceFailureDataHandler)).Methods("GET")
|
||||||
api.Handle("/api/services/{id}/ping", cached("30s", "application/json", apiServicePingDataHandler)).Methods("GET")
|
api.Handle("/api/services/{id}/ping_data", cached("30s", "application/json", apiServicePingDataHandler)).Methods("GET")
|
||||||
api.Handle("/api/services/{id}/heatmap", cached("30s", "application/json", apiServiceHeatmapHandler)).Methods("GET")
|
api.Handle("/api/services/{id}/heatmap", cached("30s", "application/json", apiServiceHeatmapHandler)).Methods("GET")
|
||||||
|
|
||||||
// API INCIDENTS Routes
|
// API INCIDENTS Routes
|
||||||
|
|
|
@ -24,7 +24,6 @@ import (
|
||||||
"github.com/hunterlong/statping/types"
|
"github.com/hunterlong/statping/types"
|
||||||
"github.com/hunterlong/statping/utils"
|
"github.com/hunterlong/statping/utils"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -73,54 +72,6 @@ func reorderServiceHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
returnJson(newOrder, w, r)
|
returnJson(newOrder, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func servicesViewHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
vars := mux.Vars(r)
|
|
||||||
fields := parseGet(r)
|
|
||||||
r.ParseForm()
|
|
||||||
|
|
||||||
var serv *core.Service
|
|
||||||
id := vars["id"]
|
|
||||||
if _, err := strconv.Atoi(id); err == nil {
|
|
||||||
serv = core.SelectService(utils.ToInt(id))
|
|
||||||
} else {
|
|
||||||
serv = core.SelectServiceLink(id)
|
|
||||||
}
|
|
||||||
if serv == nil {
|
|
||||||
w.WriteHeader(http.StatusNotFound)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
startField := utils.ToInt(fields.Get("start"))
|
|
||||||
endField := utils.ToInt(fields.Get("end"))
|
|
||||||
group := r.Form.Get("group")
|
|
||||||
|
|
||||||
end := utils.Now().UTC()
|
|
||||||
start := end.Add((-24 * 7) * time.Hour).UTC()
|
|
||||||
|
|
||||||
if startField != 0 {
|
|
||||||
start = time.Unix(startField, 0).UTC()
|
|
||||||
}
|
|
||||||
if endField != 0 {
|
|
||||||
end = time.Unix(endField, 0).UTC()
|
|
||||||
}
|
|
||||||
if group == "" {
|
|
||||||
group = "hour"
|
|
||||||
}
|
|
||||||
|
|
||||||
data := core.GraphHitsDataRaw(serv, start, end, group, "latency")
|
|
||||||
|
|
||||||
out := struct {
|
|
||||||
Service *core.Service
|
|
||||||
Start string
|
|
||||||
End string
|
|
||||||
StartUnix int64
|
|
||||||
EndUnix int64
|
|
||||||
Data string
|
|
||||||
}{serv, start.Format(utils.FlatpickrReadable), end.Format(utils.FlatpickrReadable), start.Unix(), end.Unix(), data.ToString()}
|
|
||||||
|
|
||||||
ExecuteResponse(w, r, "service.gohtml", out, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func apiServiceHandler(r *http.Request) interface{} {
|
func apiServiceHandler(r *http.Request) interface{} {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
servicer := core.SelectService(utils.ToInt(vars["id"]))
|
servicer := core.SelectService(utils.ToInt(vars["id"]))
|
||||||
|
@ -205,18 +156,9 @@ func apiServiceDataHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
sendErrorJson(errors.New("service data not found"), w, r)
|
sendErrorJson(errors.New("service data not found"), w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fields := parseGet(r)
|
groupQuery := parseGroupQuery(r)
|
||||||
grouping := fields.Get("group")
|
|
||||||
if grouping == "" {
|
|
||||||
grouping = "hour"
|
|
||||||
}
|
|
||||||
startField := utils.ToInt(fields.Get("start"))
|
|
||||||
endField := utils.ToInt(fields.Get("end"))
|
|
||||||
|
|
||||||
start := time.Unix(startField, 0)
|
obj := core.GraphHitsDataRaw(service, groupQuery, "latency")
|
||||||
end := time.Unix(endField, 0)
|
|
||||||
|
|
||||||
obj := core.GraphHitsDataRaw(service, start, end, grouping, "latency")
|
|
||||||
returnJson(obj, w, r)
|
returnJson(obj, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,6 +169,13 @@ func apiServiceFailureDataHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
sendErrorJson(errors.New("service data not found"), w, r)
|
sendErrorJson(errors.New("service data not found"), w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
groupQuery := parseGroupQuery(r)
|
||||||
|
|
||||||
|
obj := core.GraphFailuresDataRaw(service, groupQuery)
|
||||||
|
returnJson(obj, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseGroupQuery(r *http.Request) types.GroupQuery {
|
||||||
fields := parseGet(r)
|
fields := parseGet(r)
|
||||||
grouping := fields.Get("group")
|
grouping := fields.Get("group")
|
||||||
if grouping == "" {
|
if grouping == "" {
|
||||||
|
@ -235,11 +184,11 @@ func apiServiceFailureDataHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
startField := utils.ToInt(fields.Get("start"))
|
startField := utils.ToInt(fields.Get("start"))
|
||||||
endField := utils.ToInt(fields.Get("end"))
|
endField := utils.ToInt(fields.Get("end"))
|
||||||
|
|
||||||
start := time.Unix(startField, 0).UTC()
|
return types.GroupQuery{
|
||||||
end := time.Unix(endField, 0).UTC()
|
Start: time.Unix(startField, 0).UTC(),
|
||||||
|
End: time.Unix(endField, 0).UTC(),
|
||||||
obj := core.GraphFailuresDataRaw(service, start, end, grouping)
|
Group: grouping,
|
||||||
returnJson(obj, w, r)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiServicePingDataHandler(w http.ResponseWriter, r *http.Request) {
|
func apiServicePingDataHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -249,15 +198,9 @@ func apiServicePingDataHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
sendErrorJson(errors.New("service not found"), w, r)
|
sendErrorJson(errors.New("service not found"), w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fields := parseGet(r)
|
groupQuery := parseGroupQuery(r)
|
||||||
grouping := fields.Get("group")
|
|
||||||
startField := utils.ToInt(fields.Get("start"))
|
|
||||||
endField := utils.ToInt(fields.Get("end"))
|
|
||||||
|
|
||||||
start := time.Unix(startField, 0)
|
obj := core.GraphHitsDataRaw(service, groupQuery, "ping_time")
|
||||||
end := time.Unix(endField, 0)
|
|
||||||
|
|
||||||
obj := core.GraphHitsDataRaw(service, start, end, grouping, "ping_time")
|
|
||||||
returnJson(obj, w, r)
|
returnJson(obj, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,9 @@ import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/jinzhu/gorm"
|
"github.com/jinzhu/gorm"
|
||||||
|
_ "github.com/jinzhu/gorm/dialects/mysql"
|
||||||
|
_ "github.com/jinzhu/gorm/dialects/postgres"
|
||||||
|
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -112,7 +115,7 @@ type Database interface {
|
||||||
|
|
||||||
GroupByTimeframe() Database
|
GroupByTimeframe() Database
|
||||||
ToTimeValue(time.Time, time.Time) ([]*TimeValue, error)
|
ToTimeValue(time.Time, time.Time) ([]*TimeValue, error)
|
||||||
|
SelectByTime(string) string
|
||||||
MultipleSelects(args ...string) Database
|
MultipleSelects(args ...string) Database
|
||||||
|
|
||||||
Failurer
|
Failurer
|
||||||
|
@ -123,7 +126,26 @@ type Failurer interface {
|
||||||
Fails() ([]*Failure, error)
|
Fails() ([]*Failure, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func sqlTimeframes(increment string) string {
|
func mysqlTimestamps(increment string) string {
|
||||||
|
switch increment {
|
||||||
|
case "second":
|
||||||
|
return "%Y-%m-%d %H:%i:%S"
|
||||||
|
case "minute":
|
||||||
|
return "%Y-%m-%d %H:%i:00"
|
||||||
|
case "hour":
|
||||||
|
return "%Y-%m-%d %H:00:00"
|
||||||
|
case "day":
|
||||||
|
return "%Y-%m-%d 00:00:00"
|
||||||
|
case "month":
|
||||||
|
return "%Y-%m 00:00:00"
|
||||||
|
case "year":
|
||||||
|
return "%Y"
|
||||||
|
default:
|
||||||
|
return "%Y-%m-%d 00:00:00"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sqliteTimestamps(increment string) string {
|
||||||
switch increment {
|
switch increment {
|
||||||
case "second":
|
case "second":
|
||||||
return "%Y-%m-%d %H:%M:%S"
|
return "%Y-%m-%d %H:%M:%S"
|
||||||
|
@ -151,8 +173,15 @@ func CountAmount() string {
|
||||||
return fmt.Sprintf("COUNT(id) as amount")
|
return fmt.Sprintf("COUNT(id) as amount")
|
||||||
}
|
}
|
||||||
|
|
||||||
func SelectByTime(increment string) string {
|
func (it *Db) SelectByTime(increment string) string {
|
||||||
return fmt.Sprintf("strftime('%s', created_at, 'utc') as timeframe", sqlTimeframes(increment))
|
switch it.Type {
|
||||||
|
case "mysql":
|
||||||
|
return fmt.Sprintf("CONCAT(date_format(created_at, '%s')) AS timeframe", mysqlTimestamps(increment))
|
||||||
|
case "postgres":
|
||||||
|
return fmt.Sprintf("date_trunc('%s', created_at) AS timeframe", increment)
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("strftime('%s', created_at, 'utc') as timeframe", sqliteTimestamps(increment))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (it *Db) GroupByTimeframe() Database {
|
func (it *Db) GroupByTimeframe() Database {
|
||||||
|
@ -528,11 +557,18 @@ func (it *Db) ToTimeValue(start, end time.Time) ([]*TimeValue, error) {
|
||||||
Amount: amount,
|
Amount: amount,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return fillMissing(data, start, end), nil
|
return it.fillMissing(data, start, end), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseTime(t time.Time) string {
|
func (it *Db) FormatTime(t time.Time) string {
|
||||||
return t.Format("2006-01-02T00:00:00Z")
|
switch it.Type {
|
||||||
|
case "mysql":
|
||||||
|
return t.UTC().Format("2006-01-02T00:00:00Z")
|
||||||
|
case "postgres":
|
||||||
|
return t.UTC().Format("2006-01-02T00:00:00Z")
|
||||||
|
default:
|
||||||
|
return t.UTC().Format("2006-01-02T00:00:00Z")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func reparseTime(t string) time.Time {
|
func reparseTime(t string) time.Time {
|
||||||
|
@ -540,19 +576,19 @@ func reparseTime(t string) time.Time {
|
||||||
return re.UTC()
|
return re.UTC()
|
||||||
}
|
}
|
||||||
|
|
||||||
func fillMissing(vals []*TimeValue, start, end time.Time) []*TimeValue {
|
func (it *Db) fillMissing(vals []*TimeValue, start, end time.Time) []*TimeValue {
|
||||||
timeMap := make(map[string]*TimeValue)
|
timeMap := make(map[string]*TimeValue)
|
||||||
var validSet []*TimeValue
|
var validSet []*TimeValue
|
||||||
|
|
||||||
for _, v := range vals {
|
for _, v := range vals {
|
||||||
timeMap[parseTime(v.Timeframe)] = v
|
timeMap[it.FormatTime(v.Timeframe)] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
current := start.UTC()
|
current := start.UTC()
|
||||||
maxTime := end
|
maxTime := end
|
||||||
for {
|
for {
|
||||||
amount := int64(0)
|
amount := int64(0)
|
||||||
currentStr := parseTime(current)
|
currentStr := it.FormatTime(current)
|
||||||
if timeMap[currentStr] != nil {
|
if timeMap[currentStr] != nil {
|
||||||
amount = timeMap[currentStr].Amount
|
amount = timeMap[currentStr].Amount
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,13 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type GroupQuery struct {
|
||||||
|
Id int64
|
||||||
|
Start time.Time
|
||||||
|
End time.Time
|
||||||
|
Group string
|
||||||
|
}
|
||||||
|
|
||||||
// Hit struct is a 'successful' ping or web response entry for a service.
|
// Hit struct is a 'successful' ping or web response entry for a service.
|
||||||
type Hit struct {
|
type Hit struct {
|
||||||
Id int64 `gorm:"primary_key;column:id" json:"id"`
|
Id int64 `gorm:"primary_key;column:id" json:"id"`
|
||||||
|
|
Loading…
Reference in New Issue