SJA APS后端代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

189 lines
4.4 KiB

  1. // Go support for leveled logs, analogous to https://code.google.com/p/google-glog/
  2. //
  3. // Copyright 2013 Google Inc. All Rights Reserved.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. // File I/O for logs.
  17. package glog
  18. import (
  19. "errors"
  20. "fmt"
  21. "io/ioutil"
  22. "os"
  23. "os/user"
  24. "path/filepath"
  25. "sort"
  26. "strings"
  27. "sync"
  28. "time"
  29. )
  30. const (
  31. DEFAULT_LOG_DIR = "./_glog"
  32. )
  33. // MaxSize is the maximum size of a log file in bytes.
  34. var MaxSize uint64 = 1024 * 1024 * 1800
  35. // logDirs lists the candidate directories for new log files.
  36. var logDirs []string
  37. // If non-empty, overrides the choice of directory in which to write logs.
  38. // See createLogDirs for the full list of possible destinations.
  39. var defaultDir = GetAbsolutePath(DEFAULT_LOG_DIR)
  40. var logDir = defaultDir
  41. func init() {
  42. cmdLine.StringVar(&logDir, "log_dir", defaultDir, "If non-empty, write log files in this directory")
  43. }
  44. func createLogDirs() {
  45. if logDir != "" {
  46. logDirs = append(logDirs, EnsureDir(logDir))
  47. }
  48. logDirs = append(logDirs, os.TempDir())
  49. }
  50. var (
  51. pid = os.Getpid()
  52. program = filepath.Base(os.Args[0])
  53. host = "unknownhost"
  54. userName = "unknownuser"
  55. )
  56. func init() {
  57. h, err := os.Hostname()
  58. if err == nil {
  59. host = shortHostname(h)
  60. }
  61. current, err := user.Current()
  62. if err == nil {
  63. userName = current.Username
  64. }
  65. // Sanitize userName since it may contain filepath separators on Windows.
  66. userName = strings.Replace(userName, `\`, "_", -1)
  67. }
  68. // shortHostname returns its argument, truncating at the first period.
  69. // For instance, given "www.google.com" it returns "www".
  70. func shortHostname(hostname string) string {
  71. if i := strings.Index(hostname, "."); i >= 0 {
  72. return hostname[:i]
  73. }
  74. return hostname
  75. }
  76. // logName returns a new log file name containing tag, with start time t, and
  77. // the name for the symlink for tag.
  78. func logName(tag string, subType string, t time.Time) (name, link string) {
  79. cbName := tag + "." + subType
  80. name = fmt.Sprintf("%s.%04d_%02d_%02d-%02d%02d%02d.%d.log",
  81. cbName,
  82. t.Year(),
  83. t.Month(),
  84. t.Day(),
  85. t.Hour(),
  86. t.Minute(),
  87. t.Second(),
  88. pid)
  89. return name, cbName + ".log"
  90. }
  91. var DirMaxSize uint64 = MaxSize * 30
  92. type fileInfo []os.FileInfo
  93. func LogDirName() string {
  94. return program + "." + host + "." + userName
  95. }
  96. func (self fileInfo) Less(i, j int) bool {
  97. return self[i].ModTime().Unix() < self[j].ModTime().Unix()
  98. }
  99. func (self fileInfo) Len() int {
  100. return len(self)
  101. }
  102. func (self fileInfo) Swap(i, j int) {
  103. self[i], self[j] = self[j], self[i]
  104. }
  105. func ClearLogDir() {
  106. if logDir == "" {
  107. return
  108. }
  109. fdir, err := ioutil.ReadDir(logDir)
  110. if err != nil {
  111. return
  112. }
  113. files := make([]os.FileInfo, 0, 10)
  114. var size int64 = 0
  115. for _, fi := range fdir {
  116. if fi.IsDir() {
  117. continue
  118. }
  119. files = append(files, fi)
  120. size = size + int64(fi.Size())
  121. }
  122. if size < 0 || uint64(size) < DirMaxSize {
  123. return
  124. }
  125. sort.Sort(fileInfo(files))
  126. for _, fi := range files {
  127. fname := filepath.Join(logDir, fi.Name())
  128. err := os.Remove(fname)
  129. if err != nil {
  130. continue
  131. }
  132. size = size - fi.Size()
  133. if size < 0 || uint64(size) < DirMaxSize {
  134. return
  135. }
  136. }
  137. }
  138. var onceLogDirs sync.Once
  139. // create creates a new log file and returns the file and its filename, which
  140. // contains tag ("INFO", "FATAL", etc.) and t. If the file is created
  141. // successfully, create also attempts to update the symlink for that tag, ignoring
  142. // errors.
  143. func create(tag string, subType string, t time.Time) (f *os.File, filename string, err error) {
  144. onceLogDirs.Do(createLogDirs)
  145. if len(logDirs) == 0 {
  146. return nil, "", errors.New("log: no log dirs")
  147. }
  148. name, link := logName(tag, subType, t)
  149. var lastErr error
  150. for _, dir := range logDirs {
  151. fname := filepath.Join(dir, name)
  152. f, err := os.Create(fname)
  153. if err == nil {
  154. symlink := filepath.Join(dir, link)
  155. os.Remove(symlink) // ignore err
  156. os.Symlink(name, symlink) // ignore err
  157. ClearLogDir()
  158. return f, fname, nil
  159. }
  160. lastErr = err
  161. }
  162. return nil, "", fmt.Errorf("log: cannot create log: %v", lastErr)
  163. }