feat: AMF-audit日志文件获取接口
This commit is contained in:
@@ -3,12 +3,14 @@ package controller
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"be.ems/src/framework/i18n"
|
"be.ems/src/framework/i18n"
|
||||||
"be.ems/src/framework/logger"
|
"be.ems/src/framework/logger"
|
||||||
|
"be.ems/src/framework/resp"
|
||||||
"be.ems/src/framework/utils/ctx"
|
"be.ems/src/framework/utils/ctx"
|
||||||
"be.ems/src/framework/utils/date"
|
"be.ems/src/framework/utils/date"
|
||||||
"be.ems/src/framework/utils/file"
|
"be.ems/src/framework/utils/file"
|
||||||
@@ -370,3 +372,129 @@ func (s *AMFController) NbStateList(c *gin.Context) {
|
|||||||
|
|
||||||
c.JSON(200, result.OkData(data))
|
c.JSON(200, result.OkData(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取审计日志
|
||||||
|
//
|
||||||
|
// GET /log/audit
|
||||||
|
//
|
||||||
|
// @Tags network_data/amf
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param neId query string true "NE ID" default(001)
|
||||||
|
// @Success 200 {object} object "Response Results"
|
||||||
|
// @Security TokenAuth
|
||||||
|
// @Summary Access to the audit log
|
||||||
|
// @Description Access to the audit log
|
||||||
|
// @Router /neData/amf/log/audit [get]
|
||||||
|
func (s *AMFController) AuditLog(c *gin.Context) {
|
||||||
|
var query struct {
|
||||||
|
NeId string `form:"neId" binding:"required"`
|
||||||
|
BeginTime int64 `json:"beginTime" form:"beginTime"`
|
||||||
|
EndTime int64 `json:"endTime" form:"endTime"`
|
||||||
|
}
|
||||||
|
if err := c.ShouldBindQuery(&query); err != nil {
|
||||||
|
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||||
|
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理时间范围
|
||||||
|
if query.BeginTime != 0 && query.BeginTime < 1e12 {
|
||||||
|
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "begin time must ms"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if query.EndTime != 0 && query.EndTime < 1e12 {
|
||||||
|
c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "end time must ms"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
auditLog, err := neDataService.NewAMF.GetAuditLog(query.NeId)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(200, result.ErrMsg(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(auditLog) == 0 {
|
||||||
|
c.JSON(200, result.ErrMsg("audit log is empty"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对auditLog按time字段排序
|
||||||
|
sort.SliceStable(auditLog, func(i, j int) bool {
|
||||||
|
// 获取i的time值
|
||||||
|
timeI, okI := auditLog[i]["time"].(string)
|
||||||
|
// 获取j的time值
|
||||||
|
timeJ, okJ := auditLog[j]["time"].(string)
|
||||||
|
// 如果任何一个不包含有效time字段,将它们放在后面
|
||||||
|
if !okI || !okJ {
|
||||||
|
return okI && !okJ
|
||||||
|
}
|
||||||
|
// 解析时间字符串
|
||||||
|
tI, errI := time.Parse(time.DateTime, timeI)
|
||||||
|
tJ, errJ := time.Parse(time.DateTime, timeJ)
|
||||||
|
|
||||||
|
// 如果任何一个解析失败,将它们放在后面
|
||||||
|
if errI != nil || errJ != nil {
|
||||||
|
return errJ != nil && errI == nil
|
||||||
|
}
|
||||||
|
// 按时间升序排序(如果需要降序,改为tI.After(tJ))
|
||||||
|
return tI.After(tJ)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 响应格式
|
||||||
|
timeStr := ""
|
||||||
|
data := make([]map[string]any, 0)
|
||||||
|
if query.BeginTime > 1e12 && query.EndTime > 1e12 {
|
||||||
|
// 时间处理
|
||||||
|
beginT := time.UnixMilli(query.BeginTime)
|
||||||
|
endT := time.UnixMilli(query.EndTime)
|
||||||
|
timeStr = fmt.Sprintf("%s - %s", beginT.Format(time.DateTime), endT.Format(time.DateTime))
|
||||||
|
for _, v := range auditLog {
|
||||||
|
timeV, ok := v["time"].(string)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// 解析时间
|
||||||
|
t, err := time.Parse(time.DateTime, timeV)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查时间是否在范围内
|
||||||
|
if t.After(beginT) && t.After(endT) {
|
||||||
|
data = append(data, map[string]any{
|
||||||
|
"supi": fmt.Sprint(v["supi"]),
|
||||||
|
"amf_ue_ngap_id": parse.Number(v["amf_ue_ngap_id"]),
|
||||||
|
"ran_ue_ngap_id": parse.Number(v["ran_ue_ngap_id"]),
|
||||||
|
"gnb_id": parse.Number(v["gnb_id"]),
|
||||||
|
"time": timeV,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lastItem := auditLog[0]
|
||||||
|
lastTime := ""
|
||||||
|
if timeV, ok := lastItem["time"].(string); ok {
|
||||||
|
lastTime = timeV[:19]
|
||||||
|
}
|
||||||
|
timeStr = lastTime
|
||||||
|
for _, v := range auditLog {
|
||||||
|
timeV, ok := v["time"].(string)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(timeV, lastTime) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
data = append(data, map[string]any{
|
||||||
|
"supi": fmt.Sprint(v["supi"]),
|
||||||
|
"amf_ue_ngap_id": parse.Number(v["amf_ue_ngap_id"]),
|
||||||
|
"ran_ue_ngap_id": parse.Number(v["ran_ue_ngap_id"]),
|
||||||
|
"gnb_id": parse.Number(v["gnb_id"]),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.JSON(200, map[string]any{
|
||||||
|
"time": timeStr,
|
||||||
|
"ngap_context": data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
98
src/modules/network_data/service/amf.go
Normal file
98
src/modules/network_data/service/amf.go
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"be.ems/src/framework/utils/file"
|
||||||
|
neService "be.ems/src/modules/network_element/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化数据层 AMF 结构体
|
||||||
|
var NewAMF = &AMF{
|
||||||
|
neInfoService: neService.NewNeInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
// AMF 备份相关 服务层处理
|
||||||
|
type AMF struct {
|
||||||
|
neInfoService *neService.NeInfo // 网元信息服务
|
||||||
|
}
|
||||||
|
|
||||||
|
// FTPConfigInfo 获取FTP配置信息
|
||||||
|
func (r AMF) GetAuditLog(neId string) ([]map[string]any, error) {
|
||||||
|
// 网管本地路径
|
||||||
|
omcPath := "/usr/local/omc/backup/log"
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
omcPath = fmt.Sprintf("C:%s", omcPath)
|
||||||
|
}
|
||||||
|
localDirPath := fmt.Sprintf("%s/%s/%s", omcPath, "amf", neId)
|
||||||
|
|
||||||
|
// 网元主机的SSH客户端
|
||||||
|
sshClient, err := r.neInfoService.NeRunSSHClient("AMF", neId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer sshClient.Close()
|
||||||
|
// 网元主机的SSH客户端进行文件传输
|
||||||
|
sftpClient, err := sshClient.NewClientSFTP()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("ne info sftp client err")
|
||||||
|
}
|
||||||
|
defer sftpClient.Close()
|
||||||
|
// 网元端文件路径
|
||||||
|
neFilePath := "/var/log/amf-audit.log"
|
||||||
|
localFilePath := filepath.Join(localDirPath, filepath.Base(neFilePath))
|
||||||
|
// 网元端复制到本地
|
||||||
|
if err = sftpClient.CopyFileRemoteToLocal(neFilePath, localFilePath); err != nil {
|
||||||
|
return nil, fmt.Errorf("copy amf audit log err")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取本地文件
|
||||||
|
arr := file.ReadFileTXTLine(",", localFilePath)
|
||||||
|
if len(arr) == 0 {
|
||||||
|
return nil, fmt.Errorf("read file err")
|
||||||
|
}
|
||||||
|
// 解析日志
|
||||||
|
data := make([]map[string]any, 0)
|
||||||
|
for _, item := range arr {
|
||||||
|
if len(item) < 10 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
timeStr := item[0]
|
||||||
|
timeStr = timeStr[0:10] + " " + timeStr[11:] // 将破折号替换成空格,方便解析
|
||||||
|
t, err := time.Parse(time.DateTime, timeStr)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
supi := strings.TrimPrefix(item[1], "SUPI:imsi-")
|
||||||
|
amfUeNgapId := strings.TrimPrefix(item[2], "AMF-UE-NGAP-ID:")
|
||||||
|
ranUeNgapId := strings.TrimPrefix(item[3], "RAN-UE-NGAP-ID:")
|
||||||
|
gnbId := strings.TrimPrefix(item[4], "GNB-ID:")
|
||||||
|
gnbAddr := strings.TrimPrefix(item[5], "GNB-ADDR:")
|
||||||
|
tai := strings.TrimPrefix(item[6], "TAI:")
|
||||||
|
opType := strings.TrimPrefix(item[7], "OP-TYPE:")
|
||||||
|
regType := strings.TrimPrefix(item[8], "REG-TYPE:")
|
||||||
|
result := strings.TrimPrefix(item[9], "RESULT:")
|
||||||
|
|
||||||
|
data = append(data, map[string]any{
|
||||||
|
"time": t.Format(time.DateTime),
|
||||||
|
"supi": supi,
|
||||||
|
"amf_ue_ngap_id": amfUeNgapId,
|
||||||
|
"ran_ue_ngap_id": ranUeNgapId,
|
||||||
|
"gnb_id": gnbId,
|
||||||
|
"gnb_addr": gnbAddr,
|
||||||
|
"tai": tai,
|
||||||
|
"op_type": opType,
|
||||||
|
"reg_type": regType,
|
||||||
|
"result": result,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Remove(localFilePath)
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user