mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-09-06 17:46:23 +00:00
feat: support ClickHouse log database (#5663)
* feat: support ClickHouse log database * feat(log): optimize log deletion process for ClickHouse
This commit is contained in:
+99
-15
@@ -67,6 +67,27 @@ const (
|
||||
LogTypeLogin = 7
|
||||
)
|
||||
|
||||
func ensureLogRequestId(log *Log) {
|
||||
if log != nil && log.RequestId == "" {
|
||||
log.RequestId = common.NewRequestId()
|
||||
}
|
||||
}
|
||||
|
||||
func createLog(log *Log) error {
|
||||
ensureLogRequestId(log)
|
||||
return LOG_DB.Create(log).Error
|
||||
}
|
||||
|
||||
func clickHouseLogOrder(prefix string) string {
|
||||
return prefix + "created_at desc, " + prefix + "request_id desc"
|
||||
}
|
||||
|
||||
func assignDisplayLogIds(logs []*Log, startIdx int) {
|
||||
for i := range logs {
|
||||
logs[i].Id = startIdx + i + 1
|
||||
}
|
||||
}
|
||||
|
||||
func formatUserLogs(logs []*Log, startIdx int) {
|
||||
for i := range logs {
|
||||
logs[i].ChannelName = ""
|
||||
@@ -81,12 +102,16 @@ func formatUserLogs(logs []*Log, startIdx int) {
|
||||
delete(otherMap, "stream_status")
|
||||
}
|
||||
logs[i].Other = common.MapToJsonStr(otherMap)
|
||||
logs[i].Id = startIdx + i + 1
|
||||
}
|
||||
assignDisplayLogIds(logs, startIdx)
|
||||
}
|
||||
|
||||
func GetLogByTokenId(tokenId int) (logs []*Log, err error) {
|
||||
err = LOG_DB.Model(&Log{}).Where("token_id = ?", tokenId).Order("id desc").Limit(common.MaxRecentItems).Find(&logs).Error
|
||||
order := "id desc"
|
||||
if common.UsingLogDatabase(common.DatabaseTypeClickHouse) {
|
||||
order = clickHouseLogOrder("")
|
||||
}
|
||||
err = LOG_DB.Model(&Log{}).Where("token_id = ?", tokenId).Order(order).Limit(common.MaxRecentItems).Find(&logs).Error
|
||||
formatUserLogs(logs, 0)
|
||||
return logs, err
|
||||
}
|
||||
@@ -103,7 +128,7 @@ func RecordLog(userId int, logType int, content string) {
|
||||
Type: logType,
|
||||
Content: content,
|
||||
}
|
||||
err := LOG_DB.Create(log).Error
|
||||
err := createLog(log)
|
||||
if err != nil {
|
||||
common.SysLog("failed to record log: " + err.Error())
|
||||
}
|
||||
@@ -128,7 +153,7 @@ func RecordLogWithAdminInfo(userId int, logType int, content string, adminInfo m
|
||||
}
|
||||
log.Other = common.MapToJsonStr(other)
|
||||
}
|
||||
if err := LOG_DB.Create(log).Error; err != nil {
|
||||
if err := createLog(log); err != nil {
|
||||
common.SysLog("failed to record log: " + err.Error())
|
||||
}
|
||||
}
|
||||
@@ -165,7 +190,7 @@ func RecordLoginLog(userId int, username string, content string, ip string, acti
|
||||
Ip: ip,
|
||||
Other: common.MapToJsonStr(other),
|
||||
}
|
||||
if err := LOG_DB.Create(log).Error; err != nil {
|
||||
if err := createLog(log); err != nil {
|
||||
common.SysLog("failed to record login log: " + err.Error())
|
||||
}
|
||||
}
|
||||
@@ -196,7 +221,7 @@ func RecordOperationAuditLog(logUserId int, content string, ip string, action st
|
||||
Ip: ip,
|
||||
Other: common.MapToJsonStr(other),
|
||||
}
|
||||
if err := LOG_DB.Create(log).Error; err != nil {
|
||||
if err := createLog(log); err != nil {
|
||||
common.SysLog("failed to record operation audit log: " + err.Error())
|
||||
}
|
||||
}
|
||||
@@ -223,7 +248,7 @@ func RecordTopupLog(userId int, content string, callerIp string, paymentMethod s
|
||||
Ip: callerIp,
|
||||
Other: common.MapToJsonStr(other),
|
||||
}
|
||||
err := LOG_DB.Create(log).Error
|
||||
err := createLog(log)
|
||||
if err != nil {
|
||||
common.SysLog("failed to record topup log: " + err.Error())
|
||||
}
|
||||
@@ -269,7 +294,7 @@ func RecordErrorLog(c *gin.Context, userId int, channelId int, modelName string,
|
||||
UpstreamRequestId: upstreamRequestId,
|
||||
Other: otherStr,
|
||||
}
|
||||
err := LOG_DB.Create(log).Error
|
||||
err := createLog(log)
|
||||
if err != nil {
|
||||
logger.LogError(c, "failed to record log: "+err.Error())
|
||||
}
|
||||
@@ -333,7 +358,7 @@ func RecordConsumeLog(c *gin.Context, userId int, params RecordConsumeLogParams)
|
||||
UpstreamRequestId: upstreamRequestId,
|
||||
Other: otherStr,
|
||||
}
|
||||
err := LOG_DB.Create(log).Error
|
||||
err := createLog(log)
|
||||
if err != nil {
|
||||
logger.LogError(c, "failed to record log: "+err.Error())
|
||||
}
|
||||
@@ -393,7 +418,7 @@ func RecordTaskBillingLog(params RecordTaskBillingLogParams) {
|
||||
Group: params.Group,
|
||||
Other: common.MapToJsonStr(params.Other),
|
||||
}
|
||||
err := LOG_DB.Create(log).Error
|
||||
err := createLog(log)
|
||||
if err != nil {
|
||||
common.SysLog("failed to record task billing log: " + err.Error())
|
||||
}
|
||||
@@ -453,10 +478,17 @@ func GetAllLogs(logType int, startTimestamp int64, endTimestamp int64, modelName
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
err = tx.Order("logs.created_at desc, logs.id desc").Limit(num).Offset(startIdx).Find(&logs).Error
|
||||
order := "logs.created_at desc, logs.id desc"
|
||||
if common.UsingLogDatabase(common.DatabaseTypeClickHouse) {
|
||||
order = clickHouseLogOrder("logs.")
|
||||
}
|
||||
err = tx.Order(order).Limit(num).Offset(startIdx).Find(&logs).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
if common.UsingLogDatabase(common.DatabaseTypeClickHouse) {
|
||||
assignDisplayLogIds(logs, startIdx)
|
||||
}
|
||||
|
||||
channelIds := types.NewSet[int]()
|
||||
for _, log := range logs {
|
||||
@@ -537,7 +569,11 @@ func GetUserLogs(userId int, logType int, startTimestamp int64, endTimestamp int
|
||||
common.SysError("failed to count user logs: " + err.Error())
|
||||
return nil, 0, errors.New("查询日志失败")
|
||||
}
|
||||
err = tx.Order("logs.id desc").Limit(num).Offset(startIdx).Find(&logs).Error
|
||||
order := "logs.id desc"
|
||||
if common.UsingLogDatabase(common.DatabaseTypeClickHouse) {
|
||||
order = clickHouseLogOrder("logs.")
|
||||
}
|
||||
err = tx.Order(order).Limit(num).Offset(startIdx).Find(&logs).Error
|
||||
if err != nil {
|
||||
common.SysError("failed to search user logs: " + err.Error())
|
||||
return nil, 0, errors.New("查询日志失败")
|
||||
@@ -554,10 +590,10 @@ type Stat struct {
|
||||
}
|
||||
|
||||
func SumUsedQuota(logType int, startTimestamp int64, endTimestamp int64, modelName string, username string, tokenName string, channel int, group string) (stat Stat, err error) {
|
||||
tx := LOG_DB.Table("logs").Select("sum(quota) quota")
|
||||
tx := LOG_DB.Table("logs").Select("COALESCE(sum(quota), 0) quota")
|
||||
|
||||
// 为rpm和tpm创建单独的查询
|
||||
rpmTpmQuery := LOG_DB.Table("logs").Select("count(*) rpm, sum(prompt_tokens) + sum(completion_tokens) tpm")
|
||||
rpmTpmQuery := LOG_DB.Table("logs").Select("count(*) rpm, COALESCE(sum(prompt_tokens), 0) + COALESCE(sum(completion_tokens), 0) tpm")
|
||||
|
||||
if tx, err = applyExplicitLogTextFilter(tx, "username", username); err != nil {
|
||||
return stat, err
|
||||
@@ -610,7 +646,7 @@ func SumUsedQuota(logType int, startTimestamp int64, endTimestamp int64, modelNa
|
||||
}
|
||||
|
||||
func SumUsedToken(logType int, startTimestamp int64, endTimestamp int64, modelName string, username string, tokenName string) (token int) {
|
||||
tx := LOG_DB.Table("logs").Select("ifnull(sum(prompt_tokens),0) + ifnull(sum(completion_tokens),0)")
|
||||
tx := LOG_DB.Table("logs").Select("COALESCE(sum(prompt_tokens), 0) + COALESCE(sum(completion_tokens), 0)")
|
||||
if username != "" {
|
||||
tx = tx.Where("username = ?", username)
|
||||
}
|
||||
@@ -631,6 +667,54 @@ func SumUsedToken(logType int, startTimestamp int64, endTimestamp int64, modelNa
|
||||
}
|
||||
|
||||
func DeleteOldLog(ctx context.Context, targetTimestamp int64, limit int) (int64, error) {
|
||||
if common.UsingLogDatabase(common.DatabaseTypeClickHouse) {
|
||||
if limit <= 0 {
|
||||
limit = 100
|
||||
}
|
||||
|
||||
var total int64 = 0
|
||||
|
||||
for {
|
||||
if nil != ctx.Err() {
|
||||
return total, ctx.Err()
|
||||
}
|
||||
|
||||
var batchCount int64
|
||||
if err := LOG_DB.WithContext(ctx).Raw(`
|
||||
SELECT count() FROM (
|
||||
SELECT created_at, request_id
|
||||
FROM logs
|
||||
WHERE created_at < ?
|
||||
ORDER BY created_at ASC, request_id ASC
|
||||
LIMIT ?
|
||||
)`, targetTimestamp, limit).Scan(&batchCount).Error; err != nil {
|
||||
return total, err
|
||||
}
|
||||
if batchCount == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if err := LOG_DB.WithContext(ctx).Exec(`
|
||||
ALTER TABLE logs DELETE WHERE (created_at, request_id) IN (
|
||||
SELECT created_at, request_id
|
||||
FROM logs
|
||||
WHERE created_at < ?
|
||||
ORDER BY created_at ASC, request_id ASC
|
||||
LIMIT ?
|
||||
) SETTINGS mutations_sync = 1`, targetTimestamp, limit).Error; err != nil {
|
||||
return total, err
|
||||
}
|
||||
|
||||
total += batchCount
|
||||
|
||||
if batchCount < int64(limit) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return total, nil
|
||||
}
|
||||
|
||||
var total int64 = 0
|
||||
|
||||
for {
|
||||
|
||||
Reference in New Issue
Block a user