lxlog.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. package lxlog
  2. import (
  3. "fmt"
  4. "os"
  5. "runtime"
  6. "strconv"
  7. "time"
  8. )
  9. // 异步写日志
  10. var MyLog *FileLog
  11. const (
  12. LogSplitTypeHour = iota
  13. LogSplitTypeSize
  14. logPath = "myLog"
  15. logName = "myLog"
  16. chanSize = 5000
  17. )
  18. type FileLog struct {
  19. logPath string
  20. logName string
  21. file *os.File //普通日志
  22. warnFile *os.File //错误日志 级别低
  23. logDataChan chan *LogData
  24. logSplitType int //分割类型
  25. logSplitSize int64 //分割体积
  26. lastSplitHour int //分割时间
  27. }
  28. type LogData struct {
  29. Message string
  30. TimeStr string
  31. LevelStr string
  32. IsWarn bool
  33. File string
  34. }
  35. // _ = tools.InitLog()
  36. func InitLog() (log *FileLog) {
  37. config := make(map[string]string, 8)
  38. config["log_path"] = "."
  39. config["log_name"] = "server"
  40. config["log_chan_size"] = "50000" //chan size 可以不用
  41. config["log_split_type"] = "size"
  42. config["log_split_size"] = strconv.Itoa(1024 * 1024 * 1024) // 1g
  43. log, err := NewFileLog(config)
  44. if err != nil {
  45. panic("init log err")
  46. }
  47. MyLog = log
  48. return log
  49. }
  50. func NewFileLog(config map[string]string) (logFile *FileLog, err error) {
  51. var logSplitType = LogSplitTypeSize
  52. var logSplitSize int64
  53. splitType, ok := config["log_split_type"]
  54. if !ok {
  55. splitType = "hour"
  56. } else {
  57. if splitType == "size" {
  58. splitSize, ok := config["log_split_size"]
  59. if !ok {
  60. splitSize = "104857600" //100M 以文字来讲很多了
  61. }
  62. logSplitSize, err = strconv.ParseInt(splitSize, 10, 64)
  63. if err != nil {
  64. logSplitSize = 104857600
  65. }
  66. logSplitType = LogSplitTypeSize
  67. } else {
  68. logSplitType = LogSplitTypeHour
  69. }
  70. }
  71. //打开日志文件
  72. exist, err := PathIsExists(logPath)
  73. if err != nil {
  74. fmt.Printf("get dir error![%v]\n", err)
  75. return
  76. }
  77. if !exist {
  78. err = os.Mkdir(logPath, os.ModePerm)
  79. if err != nil {
  80. fmt.Printf("mkdir failed![%v]\n", err)
  81. return
  82. } else {
  83. fmt.Printf("mkdir success!\n")
  84. }
  85. }
  86. //正常日志
  87. fileName := fmt.Sprintf("%s/%s.log", logPath, logName)
  88. file, err := os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755)
  89. //错误日志
  90. fileNameWarn := fmt.Sprintf("%s/%s.log.err", logPath, logName)
  91. fileWarn, err := os.OpenFile(fileNameWarn, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755)
  92. if err != nil {
  93. return
  94. }
  95. logFile = &FileLog{
  96. logPath: logPath,
  97. logName: logName,
  98. logDataChan: make(chan *LogData, chanSize),
  99. file: file,
  100. warnFile: fileWarn,
  101. logSplitType: logSplitType,
  102. logSplitSize: logSplitSize,
  103. lastSplitHour: time.Now().Hour(),
  104. }
  105. go logFile.writeLogBackGround()
  106. return
  107. }
  108. // 判断文件夹是否存在
  109. func PathIsExists(path string) (bool, error) {
  110. _, err := os.Stat(path)
  111. if err == nil {
  112. return true, nil
  113. }
  114. if os.IsNotExist(err) {
  115. return false, nil
  116. }
  117. return false, err
  118. }
  119. func (f *FileLog) Info(message string) {
  120. _, file, line, _ := runtime.Caller(1)
  121. fi := file + ":" + strconv.Itoa(line)
  122. f.print(message, "info", fi)
  123. }
  124. func (f *FileLog) Debug(message string) {
  125. _, file, line, _ := runtime.Caller(1)
  126. fi := file + ":" + strconv.Itoa(line)
  127. f.print(message, "debug", fi)
  128. }
  129. func (f *FileLog) Warn(message string) {
  130. _, file, line, _ := runtime.Caller(1)
  131. fi := file + ":" + strconv.Itoa(line)
  132. f.print(message, "warn", fi)
  133. }
  134. func (f *FileLog) Error(message string) {
  135. _, file, line, _ := runtime.Caller(1)
  136. fi := file + ":" + strconv.Itoa(line)
  137. f.print(message, "error", fi)
  138. }
  139. func (f *FileLog) print(message, Type string, file string) {
  140. isWarn := false
  141. if Type == "error" {
  142. isWarn = true
  143. }
  144. msg := &LogData{
  145. Message: message,
  146. TimeStr: time.Now().Format("2006-01-02 15:04:05"),
  147. LevelStr: Type,
  148. IsWarn: isWarn,
  149. File: file,
  150. }
  151. // 怕chan满了插不进去
  152. select {
  153. case f.logDataChan <- msg:
  154. default:
  155. }
  156. }
  157. func (f *FileLog) writeLogBackGround() {
  158. for logData := range f.logDataChan {
  159. var file = f.file
  160. if logData.IsWarn {
  161. file = f.warnFile
  162. }
  163. f.checkSplitFile(logData.IsWarn) // 检查文件分割类型
  164. fmt.Fprintf(file, "%s %s %s %s\n", logData.TimeStr, logData.LevelStr, logData.Message, logData.File)
  165. }
  166. }
  167. func (f *FileLog) checkSplitFile(isWarn bool) {
  168. if f.logSplitType == LogSplitTypeHour {
  169. f.splitHour(isWarn)
  170. return
  171. }
  172. f.splitSize(isWarn)
  173. }
  174. // 根据时间切割
  175. func (f *FileLog) splitHour(isWarn bool) {
  176. now := time.Now()
  177. hour := now.Hour()
  178. if hour == f.lastSplitHour {
  179. return
  180. }
  181. f.lastSplitHour = hour
  182. var backupFileName string
  183. var fileName string
  184. if isWarn {
  185. backupFileName = fmt.Sprintf("%s/%s.log.err_%s", f.logPath, f.logName, now.Format("20060102150405"))
  186. fileName = fmt.Sprintf("%s/%s.log.err", f.logPath, f.logName)
  187. } else {
  188. backupFileName = fmt.Sprintf("%s/%s.log_%s", f.logPath, f.logName, now.Format("20060102150405"))
  189. fileName = fmt.Sprintf("%s/%s.log", f.logPath, f.logName)
  190. }
  191. file := f.file
  192. if isWarn {
  193. file = f.warnFile
  194. }
  195. file.Close()
  196. os.Rename(fileName, backupFileName)
  197. file, err := os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755)
  198. if err != nil {
  199. return
  200. }
  201. if isWarn {
  202. f.warnFile = file
  203. } else {
  204. f.file = file
  205. }
  206. }
  207. // 根据文件大小来分割
  208. func (f *FileLog) splitSize(isWarn bool) {
  209. file := f.file
  210. if isWarn {
  211. file = f.warnFile
  212. }
  213. fileInfo, err := file.Stat() // 可以得到文件的参数
  214. if err != nil {
  215. return
  216. }
  217. fileSize := fileInfo.Size()
  218. if fileSize <= f.logSplitSize {
  219. return
  220. }
  221. var backupFileName string
  222. var fileName string
  223. now := time.Now()
  224. if isWarn {
  225. backupFileName = fmt.Sprintf("%s/%s.log.err_%s", f.logPath, f.logName, now.Format("20060102150405"))
  226. fileName = fmt.Sprintf("%s/%s.log.err", f.logPath, f.logName)
  227. } else {
  228. backupFileName = fmt.Sprintf("%s/%s.log_%s", f.logPath, f.logName, now.Format("20060102150405"))
  229. fileName = fmt.Sprintf("%s/%s.log", f.logPath, f.logName)
  230. }
  231. file.Close()
  232. os.Rename(fileName, backupFileName)
  233. file, err = os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755)
  234. if err != nil {
  235. return
  236. }
  237. if isWarn {
  238. f.warnFile = file
  239. } else {
  240. f.file = file
  241. }
  242. }