log.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. package model
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/bytedance/gopkg/util/gopool"
  6. "gorm.io/gorm"
  7. "one-api/common"
  8. "strings"
  9. )
  10. type Log struct {
  11. Id int `json:"id" gorm:"index:idx_created_at_id,priority:1"`
  12. UserId int `json:"user_id" gorm:"index"`
  13. CreatedAt int64 `json:"created_at" gorm:"bigint;index:idx_created_at_id,priority:2;index:idx_created_at_type"`
  14. Type int `json:"type" gorm:"index:idx_created_at_type"`
  15. Content string `json:"content"`
  16. Username string `json:"username" gorm:"index:index_username_model_name,priority:2;default:''"`
  17. TokenName string `json:"token_name" gorm:"index;default:''"`
  18. ModelName string `json:"model_name" gorm:"index;index:index_username_model_name,priority:1;default:''"`
  19. Quota int `json:"quota" gorm:"default:0"`
  20. PromptTokens int `json:"prompt_tokens" gorm:"default:0"`
  21. CompletionTokens int `json:"completion_tokens" gorm:"default:0"`
  22. UseTime int `json:"use_time" gorm:"default:0"`
  23. IsStream bool `json:"is_stream" gorm:"default:false"`
  24. ChannelId int `json:"channel" gorm:"index"`
  25. TokenId int `json:"token_id" gorm:"default:0;index"`
  26. Other string `json:"other"`
  27. }
  28. const (
  29. LogTypeUnknown = iota
  30. LogTypeTopup
  31. LogTypeConsume
  32. LogTypeManage
  33. LogTypeSystem
  34. )
  35. func GetLogByKey(key string) (logs []*Log, err error) {
  36. err = DB.Joins("left join tokens on tokens.id = logs.token_id").Where("tokens.key = ?", strings.TrimPrefix(key, "sk-")).Find(&logs).Error
  37. return logs, err
  38. }
  39. func RecordLog(userId int, logType int, content string) {
  40. if logType == LogTypeConsume && !common.LogConsumeEnabled {
  41. return
  42. }
  43. username, _ := CacheGetUsername(userId)
  44. log := &Log{
  45. UserId: userId,
  46. Username: username,
  47. CreatedAt: common.GetTimestamp(),
  48. Type: logType,
  49. Content: content,
  50. }
  51. err := DB.Create(log).Error
  52. if err != nil {
  53. common.SysError("failed to record log: " + err.Error())
  54. }
  55. }
  56. func RecordConsumeLog(ctx context.Context, userId int, channelId int, promptTokens int, completionTokens int, modelName string, tokenName string, quota int, content string, tokenId int, userQuota int, useTimeSeconds int, isStream bool, other map[string]interface{}) {
  57. common.LogInfo(ctx, fmt.Sprintf("record consume log: userId=%d, 用户调用前余额=%d, channelId=%d, promptTokens=%d, completionTokens=%d, modelName=%s, tokenName=%s, quota=%d, content=%s", userId, userQuota, channelId, promptTokens, completionTokens, modelName, tokenName, quota, content))
  58. if !common.LogConsumeEnabled {
  59. return
  60. }
  61. username, _ := CacheGetUsername(userId)
  62. otherStr := common.MapToJsonStr(other)
  63. log := &Log{
  64. UserId: userId,
  65. Username: username,
  66. CreatedAt: common.GetTimestamp(),
  67. Type: LogTypeConsume,
  68. Content: content,
  69. PromptTokens: promptTokens,
  70. CompletionTokens: completionTokens,
  71. TokenName: tokenName,
  72. ModelName: modelName,
  73. Quota: quota,
  74. ChannelId: channelId,
  75. TokenId: tokenId,
  76. UseTime: useTimeSeconds,
  77. IsStream: isStream,
  78. Other: otherStr,
  79. }
  80. err := DB.Create(log).Error
  81. if err != nil {
  82. common.LogError(ctx, "failed to record log: "+err.Error())
  83. }
  84. if common.DataExportEnabled {
  85. gopool.Go(func() {
  86. LogQuotaData(userId, username, modelName, quota, common.GetTimestamp(), promptTokens+completionTokens)
  87. })
  88. }
  89. }
  90. func GetAllLogs(logType int, startTimestamp int64, endTimestamp int64, modelName string, username string, tokenName string, startIdx int, num int, channel int) (logs []*Log, err error) {
  91. var tx *gorm.DB
  92. if logType == LogTypeUnknown {
  93. tx = DB
  94. } else {
  95. tx = DB.Where("type = ?", logType)
  96. }
  97. if modelName != "" {
  98. tx = tx.Where("model_name = ?", modelName)
  99. }
  100. if username != "" {
  101. tx = tx.Where("username = ?", username)
  102. }
  103. if tokenName != "" {
  104. tx = tx.Where("token_name = ?", tokenName)
  105. }
  106. if startTimestamp != 0 {
  107. tx = tx.Where("created_at >= ?", startTimestamp)
  108. }
  109. if endTimestamp != 0 {
  110. tx = tx.Where("created_at <= ?", endTimestamp)
  111. }
  112. if channel != 0 {
  113. tx = tx.Where("channel_id = ?", channel)
  114. }
  115. err = tx.Order("id desc").Limit(num).Offset(startIdx).Find(&logs).Error
  116. return logs, err
  117. }
  118. func GetUserLogs(userId int, logType int, startTimestamp int64, endTimestamp int64, modelName string, tokenName string, startIdx int, num int) (logs []*Log, err error) {
  119. var tx *gorm.DB
  120. if logType == LogTypeUnknown {
  121. tx = DB.Where("user_id = ?", userId)
  122. } else {
  123. tx = DB.Where("user_id = ? and type = ?", userId, logType)
  124. }
  125. if modelName != "" {
  126. tx = tx.Where("model_name = ?", modelName)
  127. }
  128. if tokenName != "" {
  129. tx = tx.Where("token_name = ?", tokenName)
  130. }
  131. if startTimestamp != 0 {
  132. tx = tx.Where("created_at >= ?", startTimestamp)
  133. }
  134. if endTimestamp != 0 {
  135. tx = tx.Where("created_at <= ?", endTimestamp)
  136. }
  137. err = tx.Order("id desc").Limit(num).Offset(startIdx).Omit("id").Find(&logs).Error
  138. for i := range logs {
  139. var otherMap map[string]interface{}
  140. otherMap = common.StrToMap(logs[i].Other)
  141. if otherMap != nil {
  142. // delete admin
  143. delete(otherMap, "admin_info")
  144. }
  145. logs[i].Other = common.MapToJsonStr(otherMap)
  146. }
  147. return logs, err
  148. }
  149. func SearchAllLogs(keyword string) (logs []*Log, err error) {
  150. err = DB.Where("type = ? or content LIKE ?", keyword, keyword+"%").Order("id desc").Limit(common.MaxRecentItems).Find(&logs).Error
  151. return logs, err
  152. }
  153. func SearchUserLogs(userId int, keyword string) (logs []*Log, err error) {
  154. err = DB.Where("user_id = ? and type = ?", userId, keyword).Order("id desc").Limit(common.MaxRecentItems).Omit("id").Find(&logs).Error
  155. return logs, err
  156. }
  157. type Stat struct {
  158. Quota int `json:"quota"`
  159. Rpm int `json:"rpm"`
  160. Tpm int `json:"tpm"`
  161. }
  162. func SumUsedQuota(logType int, startTimestamp int64, endTimestamp int64, modelName string, username string, tokenName string, channel int) (stat Stat) {
  163. tx := DB.Table("logs").Select("sum(quota) quota, count(*) rpm, sum(prompt_tokens) + sum(completion_tokens) tpm")
  164. if username != "" {
  165. tx = tx.Where("username = ?", username)
  166. }
  167. if tokenName != "" {
  168. tx = tx.Where("token_name = ?", tokenName)
  169. }
  170. if startTimestamp != 0 {
  171. tx = tx.Where("created_at >= ?", startTimestamp)
  172. }
  173. if endTimestamp != 0 {
  174. tx = tx.Where("created_at <= ?", endTimestamp)
  175. }
  176. if modelName != "" {
  177. tx = tx.Where("model_name = ?", modelName)
  178. }
  179. if channel != 0 {
  180. tx = tx.Where("channel_id = ?", channel)
  181. }
  182. tx.Where("type = ?", LogTypeConsume).Scan(&stat)
  183. return stat
  184. }
  185. func SumUsedToken(logType int, startTimestamp int64, endTimestamp int64, modelName string, username string, tokenName string) (token int) {
  186. tx := DB.Table("logs").Select("ifnull(sum(prompt_tokens),0) + ifnull(sum(completion_tokens),0)")
  187. if username != "" {
  188. tx = tx.Where("username = ?", username)
  189. }
  190. if tokenName != "" {
  191. tx = tx.Where("token_name = ?", tokenName)
  192. }
  193. if startTimestamp != 0 {
  194. tx = tx.Where("created_at >= ?", startTimestamp)
  195. }
  196. if endTimestamp != 0 {
  197. tx = tx.Where("created_at <= ?", endTimestamp)
  198. }
  199. if modelName != "" {
  200. tx = tx.Where("model_name = ?", modelName)
  201. }
  202. tx.Where("type = ?", LogTypeConsume).Scan(&token)
  203. return token
  204. }
  205. func DeleteOldLog(targetTimestamp int64) (int64, error) {
  206. result := DB.Where("created_at < ?", targetTimestamp).Delete(&Log{})
  207. return result.RowsAffected, result.Error
  208. }