Finish the dashboard summary things.

This commit is contained in:
zicla 2018-12-01 21:45:58 +08:00
parent 439d23df2d
commit 2d1a95594f
12 changed files with 229 additions and 61 deletions

View File

@ -46,17 +46,17 @@ func (this *Context) Init() {
this.Router = NewRouter() this.Router = NewRouter()
} }
func (this *Context) OpenDb() { func (this *Context) OpenDb() {
var err error = nil var err error = nil
this.DB, err = gorm.Open("mysql", CONFIG.MysqlUrl) this.DB, err = gorm.Open("mysql", CONFIG.MysqlUrl)
//是否打开sql日志
this.DB.LogMode(false)
if err != nil { if err != nil {
panic("failed to connect mysql database") LOGGER.Panic("failed to connect mysql database")
} }
//是否打开sql日志(在调试阶段可以打开以方便查看执行的SQL)
this.DB.LogMode(false)
} }
func (this *Context) CloseDb() { func (this *Context) CloseDb() {
@ -91,8 +91,7 @@ func (this *Context) registerBean(bean IBean) {
} }
} else { } else {
err := fmt.Sprintf("注册的【%s】不是Bean类型。", typeName) LOGGER.Panic("注册的【%s】不是Bean类型。", typeName)
panic(err)
} }
} }
@ -154,8 +153,8 @@ func (this *Context) GetBean(bean IBean) IBean {
if val, ok := this.BeanMap[typeName]; ok { if val, ok := this.BeanMap[typeName]; ok {
return val return val
} else { } else {
err := fmt.Sprintf("【%s】没有注册。", typeName) LOGGER.Panic("【%s】没有注册。", typeName)
panic(err) return nil
} }
} }

View File

@ -41,6 +41,6 @@ func (this *DashboardController) RegisterRoutes() map[string]func(writer http.Re
//过去七天分时调用量 //过去七天分时调用量
func (this *DashboardController) InvokeList(writer http.ResponseWriter, request *http.Request) *WebResult { func (this *DashboardController) InvokeList(writer http.ResponseWriter, request *http.Request) *WebResult {
return this.Success(this.dashboardDao.InvokeList()) return this.Success("")
} }

View File

@ -2,6 +2,7 @@ package rest
import ( import (
_ "github.com/jinzhu/gorm/dialects/mysql" _ "github.com/jinzhu/gorm/dialects/mysql"
"github.com/nu7hatch/gouuid"
"time" "time"
) )
@ -9,47 +10,46 @@ type DashboardDao struct {
BaseDao BaseDao
} }
//过去七天调用量 //创建
func (this *DashboardDao) InvokeList() []*DashboardInvoke { func (this *DashboardDao) Create(dashboard *Dashboard) *Dashboard {
//过去几天 timeUUID, _ := uuid.NewV4()
var dayNum = 15; dashboard.Uuid = string(timeUUID.String())
var tableName = Footprint{}.TableName() dashboard.CreateTime = time.Now()
now := time.Now() dashboard.UpdateTime = time.Now()
startDate := now.AddDate(0, 0, 1-dayNum) db := CONTEXT.DB.Create(dashboard)
rows, err := CONTEXT.DB.Raw("SELECT COUNT(uuid) AS invoke_num,COUNT(DISTINCT(ip)) AS uv,dt FROM "+tableName+" WHERE dt>= ? AND dt <= ? GROUP BY dt", this.PanicError(db.Error)
ConvertTimeToDateString(startDate),
ConvertTimeToDateString(now)).Rows()
this.PanicError(err)
defer rows.Close()
var invokeMap = make(map[string]*DashboardInvoke) return dashboard
var dashboardInvokes []*DashboardInvoke }
for rows.Next() {
var invokeNum int64 = 0; //修改一条记录
var uv int64 = 0; func (this *DashboardDao) Save(dashboard *Dashboard) *Dashboard {
var dt string;
rows.Scan(&invokeNum, &uv, &dt) dashboard.UpdateTime = time.Now()
invokeMap[dt] = &DashboardInvoke{ db := CONTEXT.DB.Save(dashboard)
InvokeNum: invokeNum, this.PanicError(db.Error)
Uv: uv,
Dt: dt, return dashboard
} }
}
for i := 1 - dayNum; i <= 0; i++ {
date := now.AddDate(0, 0, i) //删除一条记录
dt := ConvertTimeToDateString(date) func (this *DashboardDao) Delete(dashboard *Dashboard) {
v, ok := invokeMap[dt]
if ok { db := CONTEXT.DB.Delete(&dashboard)
dashboardInvokes = append(dashboardInvokes, v) this.PanicError(db.Error)
} else { }
dashboardInvokes = append(dashboardInvokes, &DashboardInvoke{
InvokeNum: 0,
Uv: 0, //按照dt查询
Dt: dt, func (this *DashboardDao) FindByDt(dt string) *Dashboard {
})
} // Read
} var dashboard Dashboard
db := CONTEXT.DB.Where(&Dashboard{Dt: dt}).First(&dashboard)
return dashboardInvokes if db.Error != nil {
return nil
}
return &dashboard
} }

View File

@ -5,8 +5,8 @@ package rest
*/ */
type Dashboard struct { type Dashboard struct {
Base Base
VisitNum int64 `json:"visitNum"` InvokeNum int64 `json:"invokeNum"`
TotalVisitNum int64 `json:"totalVisitNum"` TotalInvokeNum int64 `json:"totalInvokeNum"`
Uv int64 `json:"uv"` Uv int64 `json:"uv"`
TotalUv int64 `json:"totalUv"` TotalUv int64 `json:"totalUv"`
MatterNum int64 `json:"matterNum"` MatterNum int64 `json:"matterNum"`

View File

@ -1,13 +1,21 @@
package rest package rest
import (
"time"
)
//@Service //@Service
type DashboardService struct { type DashboardService struct {
Bean Bean
dashboardDao *DashboardDao dashboardDao *DashboardDao
userDao *UserDao footprintDao *FootprintDao
matterDao *MatterDao
imageCacheDao *ImageCacheDao
userDao *UserDao
//每天凌晨定时整理器
maintainTimer *time.Timer
} }
//初始化方法 //初始化方法
func (this *DashboardService) Init() { func (this *DashboardService) Init() {
this.Bean.Init() this.Bean.Init()
@ -18,9 +26,103 @@ func (this *DashboardService) Init() {
this.dashboardDao = b this.dashboardDao = b
} }
b = CONTEXT.GetBean(this.footprintDao)
if b, ok := b.(*FootprintDao); ok {
this.footprintDao = b
}
b = CONTEXT.GetBean(this.matterDao)
if b, ok := b.(*MatterDao); ok {
this.matterDao = b
}
b = CONTEXT.GetBean(this.imageCacheDao)
if b, ok := b.(*ImageCacheDao); ok {
this.imageCacheDao = b
}
b = CONTEXT.GetBean(this.userDao) b = CONTEXT.GetBean(this.userDao)
if b, ok := b.(*UserDao); ok { if b, ok := b.(*UserDao); ok {
this.userDao = b this.userDao = b
} }
//立即执行数据清洗任务
go this.maintain()
}
//每日清洗离线数据表。
func (this *DashboardService) maintain() {
//准备好下次维护日志的时间。
now := time.Now()
nextTime := FirstMinuteOfDay(Tomorrow())
duration := nextTime.Sub(now)
this.logger.Info("每日数据汇总,下次时间:%s ", ConvertTimeToDateTimeString(nextTime))
this.maintainTimer = time.AfterFunc(duration, func() {
go this.maintain()
})
//准备日期开始结尾
startTime := FirstSecondOfDay(Yesterday())
endTime := LastSecondOfDay(Yesterday())
dt := ConvertTimeToDateString(startTime)
longTimeAgo := time.Now()
longTimeAgo = longTimeAgo.AddDate(-20, 0, 0)
this.logger.Info("统计汇总表 %s -> %s", ConvertTimeToDateTimeString(startTime), ConvertTimeToDateTimeString(endTime))
//判断昨天的记录是否已经生成,如果生成了就直接删除掉
dbDashboard := this.dashboardDao.FindByDt(dt)
if dbDashboard != nil {
this.logger.Info(" %s 的汇总已经存在了,删除以进行更新", dt)
this.dashboardDao.Delete(dbDashboard)
}
invokeNum := this.footprintDao.CountBetweenTime(startTime, endTime)
this.logger.Info("调用数:%d", invokeNum)
totalInvokeNum := this.footprintDao.CountBetweenTime(longTimeAgo, endTime)
this.logger.Info("历史总调用数:%d", totalInvokeNum)
uv := this.footprintDao.UvBetweenTime(startTime, endTime)
this.logger.Info("UV%d", uv)
totalUv := this.footprintDao.UvBetweenTime(longTimeAgo, endTime)
this.logger.Info("历史总UV%d", totalUv)
matterNum := this.matterDao.CountBetweenTime(startTime, endTime)
this.logger.Info("文件数量数:%d", matterNum)
totalMatterNum := this.matterDao.CountBetweenTime(longTimeAgo, endTime)
this.logger.Info("历史文件总数:%d", totalMatterNum)
matterSize := this.matterDao.SizeBetweenTime(startTime, endTime)
this.logger.Info("文件大小:%d", matterSize)
totalMatterSize := this.matterDao.SizeBetweenTime(longTimeAgo, endTime)
this.logger.Info("历史文件总大小:%d", totalMatterSize)
cacheSize := this.imageCacheDao.SizeBetweenTime(startTime, endTime)
this.logger.Info("缓存大小:%d", cacheSize)
totalCacheSize := this.imageCacheDao.SizeBetweenTime(longTimeAgo, endTime)
this.logger.Info("历史缓存总大小:%d", totalCacheSize)
avgCost := this.footprintDao.AvgCostBetweenTime(startTime, endTime)
this.logger.Info("平均耗时:%d ms", avgCost)
dashboard := &Dashboard{
InvokeNum: invokeNum,
TotalInvokeNum: totalInvokeNum,
Uv: uv,
TotalUv: totalUv,
MatterNum: matterNum,
TotalMatterNum: totalMatterNum,
FileSize: matterSize + cacheSize,
TotalFileSize: totalMatterSize + totalCacheSize,
AvgCost: avgCost,
Dt: dt,
}
this.dashboardDao.Create(dashboard)
} }

View File

@ -88,3 +88,31 @@ func (this *FootprintDao) Delete(footprint *Footprint) {
db := CONTEXT.DB.Delete(&footprint) db := CONTEXT.DB.Delete(&footprint)
this.PanicError(db.Error) this.PanicError(db.Error)
} }
//获取一段时间中,总的数量
func (this *FootprintDao) CountBetweenTime(startTime time.Time, endTime time.Time) int64 {
var count int64
db := CONTEXT.DB.Model(&Footprint{}).Where("create_time >= ? AND create_time <= ?", startTime, endTime).Count(&count)
this.PanicError(db.Error)
return count
}
//获取一段时间中UV的数量
func (this *FootprintDao) UvBetweenTime(startTime time.Time, endTime time.Time) int64 {
var count int64
db := CONTEXT.DB.Model(&Footprint{}).Where("create_time >= ? AND create_time <= ?", startTime, endTime).Select("COUNT(DISTINCT(ip))")
this.PanicError(db.Error)
row := db.Row()
row.Scan(&count)
return count
}
//获取一段时间中平均耗时
func (this *FootprintDao) AvgCostBetweenTime(startTime time.Time, endTime time.Time) int64 {
var cost float64
db := CONTEXT.DB.Model(&Footprint{}).Where("create_time >= ? AND create_time <= ?", startTime, endTime).Select("AVG(cost)")
this.PanicError(db.Error)
row := db.Row()
row.Scan(&cost)
return int64(cost)
}

View File

@ -12,7 +12,6 @@ type Footprint struct {
Params string `json:"params"` Params string `json:"params"`
Cost int64 `json:"cost"` Cost int64 `json:"cost"`
Success bool `json:"success"` Success bool `json:"success"`
Dt string `json:"dt"`
} }
// set File's table name to be `profiles` // set File's table name to be `profiles`

View File

@ -76,7 +76,6 @@ func (this *FootprintService) Trace(writer http.ResponseWriter, request *http.Re
Params: paramsString, Params: paramsString,
Cost: int64(duration / time.Millisecond), Cost: int64(duration / time.Millisecond),
Success: success, Success: success,
Dt: ConvertTimeToDateString(time.Now()),
} }
footprint = this.footprintDao.Create(footprint) footprint = this.footprintDao.Create(footprint)

View File

@ -192,3 +192,13 @@ func (this *ImageCacheDao) DeleteByMatterUuid(matterUuid string) {
} }
} }
//获取一段时间中文件总大小
func (this *ImageCacheDao) SizeBetweenTime(startTime time.Time, endTime time.Time) int64 {
var size int64
db := CONTEXT.DB.Model(&ImageCache{}).Where("create_time >= ? AND create_time <= ?", startTime, endTime).Select("SUM(size)")
this.PanicError(db.Error)
row := db.Row()
row.Scan(&size)
return size
}

View File

@ -32,10 +32,13 @@ func (this *Logger) log(prefix string, format string, v ...interface{}) {
defer this.Unlock() defer this.Unlock()
//控制台中打印日志 //控制台中打印日志
fmt.Printf(format+"\r\n", v...) var consoleFormat = fmt.Sprintf("%s%s %s\r\n", prefix, ConvertTimeToTimeString(time.Now()), format)
fmt.Printf(consoleFormat, v...)
this.goLogger.SetPrefix(prefix) this.goLogger.SetPrefix(prefix)
this.goLogger.Printf(format, v...) //每一行我们加上换行符
var fileFormat = fmt.Sprintf("%s\r\n", format)
this.goLogger.Printf(fileFormat, v...)
} }
//处理日志的统一方法。 //处理日志的统一方法。
@ -101,7 +104,7 @@ func (this *Logger) maintain() {
now := time.Now() now := time.Now()
nextTime := FirstSecondOfDay(Tomorrow()) nextTime := FirstSecondOfDay(Tomorrow())
duration := nextTime.Sub(now) duration := nextTime.Sub(now)
go this.Info("%vs后将进行下一次日志维护 下次时间维护时间:%v ", int64(duration/time.Second), nextTime) go this.Info("%vs 后将进行下一次日志维护 下次时间维护时间:%v ", int64(duration/time.Second), nextTime)
this.maintainTimer = time.AfterFunc(duration, func() { this.maintainTimer = time.AfterFunc(duration, func() {
go this.maintain() go this.maintain()
}) })
@ -133,7 +136,6 @@ func (this *Logger) closeFile() {
panic("尝试关闭日志时出错: " + err.Error()) panic("尝试关闭日志时出错: " + err.Error())
} }
} }
} }
func (this *Logger) Destroy() { func (this *Logger) Destroy() {

View File

@ -264,3 +264,21 @@ func (this *MatterDao) Delete(matter *Matter) {
} }
} }
//获取一段时间中,总的数量
func (this *MatterDao) CountBetweenTime(startTime time.Time, endTime time.Time) int64 {
var count int64
db := CONTEXT.DB.Model(&Matter{}).Where("create_time >= ? AND create_time <= ?", startTime, endTime).Count(&count)
this.PanicError(db.Error)
return count
}
//获取一段时间中文件总大小
func (this *MatterDao) SizeBetweenTime(startTime time.Time, endTime time.Time) int64 {
var size int64
db := CONTEXT.DB.Model(&Matter{}).Where("create_time >= ? AND create_time <= ?", startTime, endTime).Select("SUM(size)")
this.PanicError(db.Error)
row := db.Row()
row.Scan(&size)
return size
}

View File

@ -20,6 +20,11 @@ func ConvertTimeToDateTimeString(time time.Time) string {
return time.Local().Format("2006-01-02 15:04:05") return time.Local().Format("2006-01-02 15:04:05")
} }
//将一个时间字符串转换成日期时间对象(yyyy-MM-dd HH:mm:ss)
func ConvertTimeToTimeString(time time.Time) string {
return time.Local().Format("15:04:05")
}
//将一个时间字符串转换成日期对象(yyyy-MM-dd) //将一个时间字符串转换成日期对象(yyyy-MM-dd)
func ConvertTimeToDateString(time time.Time) string { func ConvertTimeToDateString(time time.Time) string {
return time.Local().Format("2006-01-02") return time.Local().Format("2006-01-02")
@ -37,6 +42,12 @@ func FirstSecondOfDay(day time.Time) time.Time {
return time.Date(day.Year(), day.Month(), day.Day(), 0, 0, 0, 0, local) return time.Date(day.Year(), day.Month(), day.Day(), 0, 0, 0, 0, local)
} }
//一天中的第一分钟
func FirstMinuteOfDay(day time.Time) time.Time {
local, _ := time.LoadLocation("Local")
return time.Date(day.Year(), day.Month(), day.Day(), 0, 1, 0, 0, local)
}
//明天此刻的时间 //明天此刻的时间
func Tomorrow() time.Time { func Tomorrow() time.Time {
tomorrow := time.Now() tomorrow := time.Now()