Merge pull request #150 from lanrenwo/lifetime

增加审计日志、图表数据自动清理功能
This commit is contained in:
bjdgyc 2022-10-13 10:57:30 +08:00 committed by GitHub
commit 2093bd0bef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 267 additions and 5 deletions

View File

@ -2,8 +2,10 @@ package admin
import (
"encoding/json"
"errors"
"io/ioutil"
"net/http"
"regexp"
"github.com/bjdgyc/anylink/dbdata"
)
@ -60,3 +62,42 @@ func SetOtherEdit(w http.ResponseWriter, r *http.Request) {
data := &dbdata.SettingOther{}
setOtherEdit(data, w, r)
}
func SetOtherAuditLog(w http.ResponseWriter, r *http.Request) {
data, err := dbdata.SettingGetAuditLog()
if err != nil {
RespError(w, RespInternalErr, err)
return
}
RespSucess(w, data)
}
func SetOtherAuditLogEdit(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
RespError(w, RespInternalErr, err)
return
}
defer r.Body.Close()
data := &dbdata.SettingAuditLog{}
err = json.Unmarshal(body, data)
if err != nil {
RespError(w, RespInternalErr, err)
return
}
if data.LifeDay < 0 || data.LifeDay > 365 {
RespError(w, RespParamErr, errors.New("日志存储时长范围在 0 ~ 365"))
return
}
ok, _ := regexp.Match("^([0-9]|0[0-9]|1[0-9]|2[0-3]):([0][0])$", []byte(data.ClearTime))
if !ok {
RespError(w, RespParamErr, errors.New("每天清理时间填写有误"))
return
}
err = dbdata.SettingSet(data)
if err != nil {
RespError(w, RespInternalErr, err)
return
}
RespSucess(w, data)
}

View File

@ -41,6 +41,8 @@ func StartAdmin() {
r.HandleFunc("/set/other/edit", SetOtherEdit)
r.HandleFunc("/set/other/smtp", SetOtherSmtp)
r.HandleFunc("/set/other/smtp/edit", SetOtherSmtpEdit)
r.HandleFunc("/set/other/audit_log", SetOtherAuditLog)
r.HandleFunc("/set/other/audit_log/edit", SetOtherAuditLogEdit)
r.HandleFunc("/set/audit/list", SetAuditList)
r.HandleFunc("/set/audit/export", SetAuditExport)

View File

@ -0,0 +1,20 @@
package cron
import (
"github.com/bjdgyc/anylink/base"
"github.com/bjdgyc/anylink/dbdata"
)
// 清除访问审计日志
func ClearAudit() {
lifeDay, timesUp := isClearTime()
if !timesUp {
return
}
// 当审计日志永久保存,则退出
if lifeDay <= 0 {
return
}
affected, err := dbdata.ClearAccessAudit(getTimeAgo(lifeDay))
base.Info("Cron ClearAudit: ", affected, err)
}

View File

@ -0,0 +1,52 @@
package cron
import (
"time"
"github.com/bjdgyc/anylink/base"
"github.com/bjdgyc/anylink/dbdata"
)
const siLifeDay = 30
// 清除图表数据
func ClearStatsInfo() {
_, timesUp := isClearTime()
if !timesUp {
return
}
ts := getTimeAgo(siLifeDay)
for _, item := range dbdata.StatsInfoIns.Actions {
affected, err := dbdata.StatsInfoIns.ClearStatsInfo(item, ts)
base.Info("Cron ClearStatsInfo "+item+": ", affected, err)
}
}
// 是否到了"清理时间"
func isClearTime() (int, bool) {
dataLog, err := dbdata.SettingGetAuditLog()
if err != nil {
base.Error("Cron SettingGetLog: ", err)
return -1, false
}
currentTime := time.Now().Format("15:04")
// 未到"清理时间"时, 则返回
if dataLog.ClearTime != currentTime {
return -1, false
}
return dataLog.LifeDay, true
}
// 根据存储时长,获取清理日期
func getTimeAgo(days int) string {
var timeS string
ts := time.Now().AddDate(0, 0, -days)
tsZero := time.Date(ts.Year(), ts.Month(), ts.Day(), 0, 0, 0, 0, time.Local)
timeS = tsZero.Format(dbdata.LayoutTimeFormat)
// UTC
switch base.Cfg.DbType {
case "sqlite3", "postgres":
timeS = tsZero.UTC().Format(dbdata.LayoutTimeFormat)
}
return timeS
}

14
server/cron/start.go Normal file
View File

@ -0,0 +1,14 @@
package cron
import (
"time"
"github.com/go-co-op/gocron"
)
func Start() {
s := gocron.NewScheduler(time.Local)
s.Cron("0 * * * *").Do(ClearAudit)
s.Cron("0 * * * *").Do(ClearStatsInfo)
s.StartAsync()
}

View File

@ -49,3 +49,8 @@ func GetAuditSession(search string) *xorm.Session {
}
return session
}
func ClearAccessAudit(ts string) (int64, error) {
affected, err := xdb.Where("created_at < '" + ts + "'").Delete(&AccessAudit{})
return affected, err
}

View File

@ -87,6 +87,13 @@ func addInitData() error {
return err
}
// SettingAuditLog
auditLog := SettingGetAuditLogDefault()
err = SettingSessAdd(sess, auditLog)
if err != nil {
return err
}
// SettingOther
other := &SettingOther{
LinkAddr: "vpn.xx.com",

View File

@ -3,6 +3,7 @@ package dbdata
import (
"encoding/json"
"reflect"
"xorm.io/xorm"
)
@ -19,6 +20,11 @@ type SettingSmtp struct {
Encryption string `json:"encryption"`
}
type SettingAuditLog struct {
LifeDay int `json:"life_day"`
ClearTime string `json:"clear_time"`
}
type SettingOther struct {
LinkAddr string `json:"link_addr"`
Banner string `json:"banner"`
@ -64,3 +70,30 @@ func SettingGet(data interface{}) error {
err = json.Unmarshal(s.Data, data)
return err
}
func SettingGetAuditLog() (SettingAuditLog, error) {
data := SettingAuditLog{}
err := SettingGet(&data)
if err == nil {
return data, err
}
if !CheckErrNotFound(err) {
return data, err
}
sess := xdb.NewSession()
defer sess.Close()
auditLog := SettingGetAuditLogDefault()
err = SettingSessAdd(sess, auditLog)
if err != nil {
return data, err
}
return auditLog, nil
}
func SettingGetAuditLogDefault() SettingAuditLog {
auditLog := SettingAuditLog{
LifeDay: 0,
ClearTime: "05:00",
}
return auditLog
}

View File

@ -237,3 +237,17 @@ func (s *StatsInfo) getStatsWhere(sd *ScopeDetail) (where string) {
}
return
}
func (s *StatsInfo) ClearStatsInfo(action string, ts string) (affected int64, err error) {
switch action {
case "online":
affected, err = xdb.Where("created_at < '" + ts + "'").Delete(&StatsOnline{})
case "network":
affected, err = xdb.Where("created_at < '" + ts + "'").Delete(&StatsNetwork{})
case "cpu":
affected, err = xdb.Where("created_at < '" + ts + "'").Delete(&StatsCpu{})
case "mem":
affected, err = xdb.Where("created_at < '" + ts + "'").Delete(&StatsMem{})
}
return affected, err
}

View File

@ -4,6 +4,7 @@ go 1.18
require (
github.com/arl/statsviz v0.5.1
github.com/go-co-op/gocron v1.17.0
github.com/go-ldap/ldap v3.0.3+incompatible
github.com/go-sql-driver/mysql v1.6.0
github.com/gocarina/gocsv v0.0.0-20220712153207-8b2118da4570
@ -23,7 +24,7 @@ require (
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8
github.com/spf13/cobra v1.2.1
github.com/spf13/viper v1.8.1
github.com/stretchr/testify v1.7.0
github.com/stretchr/testify v1.8.0
github.com/xhit/go-simple-mail/v2 v2.10.0
github.com/xlzd/gotp v0.0.0-20181030022105-c8557ba2c119
go.uber.org/atomic v1.10.0
@ -54,6 +55,7 @@ require (
github.com/pion/transport v0.13.0 // indirect
github.com/pion/udp v0.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/spf13/afero v1.6.0 // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
@ -62,11 +64,12 @@ require (
github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/tklauser/go-sysconf v0.3.7 // indirect
github.com/tklauser/numcpus v0.2.3 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
golang.org/x/text v0.3.7 // indirect
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
xorm.io/builder v0.3.9 // indirect
)

View File

@ -123,6 +123,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-co-op/gocron v1.17.0 h1:IixLXsti+Qo0wMvmn6Kmjp2csk2ykpkcL+EmHmST18w=
github.com/go-co-op/gocron v1.17.0/go.mod h1:IpDBSaJOVfFw7hXZuTag3SCSkqazXBBUkbQ1m1aesBs=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@ -460,6 +462,8 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
@ -512,13 +516,16 @@ github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5J
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
@ -696,6 +703,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -981,8 +989,9 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -7,6 +7,7 @@ import (
"github.com/bjdgyc/anylink/admin"
"github.com/bjdgyc/anylink/base"
"github.com/bjdgyc/anylink/cron"
"github.com/bjdgyc/anylink/dbdata"
"github.com/bjdgyc/anylink/sessdata"
)
@ -14,6 +15,7 @@ import (
func Start() {
dbdata.Start()
sessdata.Start()
cron.Start()
switch base.Cfg.LinkMode {
case base.LinkModeTUN:

View File

@ -32,6 +32,32 @@
</el-form>
</el-tab-pane>
<el-tab-pane label="审计日志" name="dataAuditLog">
<el-form :model="dataAuditLog" ref="dataAuditLog" :rules="rules" label-width="100px" class="tab-one">
<el-form-item label="存储时长" prop="life_day">
<el-input-number v-model="dataAuditLog.life_day" :min="0" :max="365" size="small" label="天数"></el-input-number>
<p class="input_tip">范围: 0 ~ 365 , <strong style="color:#EA3323;">0 代表永久保存</strong></p>
</el-form-item>
<el-form-item label="清理时间" prop="clear_time">
<el-time-select
v-model="dataAuditLog.clear_time"
:picker-options="{
start: '00:00',
step: '01:00',
end: '23:00'
}"
editable=false,
size="small"
placeholder="请选择"
style="width:130px;">
</el-time-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('dataAuditLog')">保存</el-button>
<el-button @click="resetForm('dataAuditLog')">重置</el-button>
</el-form-item>
</el-form>
</el-tab-pane>
<el-tab-pane label="其他设置" name="dataOther">
<el-form :model="dataOther" ref="dataOther" :rules="rules" label-width="100px" class="tab-one">
@ -104,6 +130,7 @@ export default {
return {
activeName: 'dataSmtp',
dataSmtp: {},
dataAuditLog: {},
dataOther: {},
rules: {
host: {required: true, message: '请输入服务器地址', trigger: 'blur'},
@ -122,9 +149,12 @@ export default {
case "dataSmtp":
this.getSmtp()
break
case "dataAuditLog":
this.getAuditLog()
break
case "dataOther":
this.getOther()
break
break
}
},
getSmtp() {
@ -141,6 +171,20 @@ export default {
console.log(error);
});
},
getAuditLog() {
axios.get('/set/other/audit_log').then(resp => {
let rdata = resp.data
console.log(rdata)
if (rdata.code !== 0) {
this.$message.error(rdata.msg);
return;
}
this.dataAuditLog = rdata.data
}).catch(error => {
this.$message.error('哦,请求出错');
console.log(error);
});
},
getOther() {
axios.get('/set/other').then(resp => {
let rdata = resp.data
@ -174,6 +218,17 @@ export default {
})
break;
case "dataAuditLog":
axios.post('/set/other/audit_log/edit', this.dataAuditLog).then(resp => {
var rdata = resp.data
console.log(rdata);
if (rdata.code === 0) {
this.$message.success(rdata.msg);
} else {
this.$message.error(rdata.msg);
}
})
break;
case "dataOther":
axios.post('/set/other/edit', this.dataOther).then(resp => {
var rdata = resp.data
@ -201,4 +256,9 @@ export default {
width: 600px;
}
.input_tip {
line-height: 1.428;
margin:2px 0 0 0;
}
</style>