fields.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. // Copyright 2013, Cong Ding. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. //
  15. // author: Cong Ding <dinggnu@gmail.com>
  16. //
  17. package logging
  18. import (
  19. "bitbucket.org/kardianos/osext"
  20. "os"
  21. "path"
  22. "runtime"
  23. "sync/atomic"
  24. "time"
  25. )
  26. // The struct for each log record
  27. type record struct {
  28. level Level
  29. seqid uint64
  30. pathname string
  31. filename string
  32. module string
  33. lineno int
  34. funcname string
  35. thread int
  36. process int
  37. message string
  38. time time.Time
  39. }
  40. // This variable maps fields in recordArgs to relavent function signatures
  41. var fields = map[string]func(*Logger, *record) interface{}{
  42. "name": (*Logger).lname, // name of the logger
  43. "seqid": (*Logger).nextSeqid, // sequence number
  44. "levelno": (*Logger).levelno, // level number
  45. "levelname": (*Logger).levelname, // level name
  46. "created": (*Logger).created, // starting time of the logger
  47. "nsecs": (*Logger).nsecs, // nanosecond of the starting time
  48. "time": (*Logger).time, // record created time
  49. "timestamp": (*Logger).timestamp, // timestamp of record
  50. "rtime": (*Logger).rtime, // relative time since started
  51. "filename": (*Logger).filename, // source filename of the caller
  52. "pathname": (*Logger).pathname, // filename with path
  53. "module": (*Logger).module, // executable filename
  54. "lineno": (*Logger).lineno, // line number in source code
  55. "funcname": (*Logger).funcname, // function name of the caller
  56. "thread": (*Logger).thread, // thread id
  57. "process": (*Logger).process, // process id
  58. "message": (*Logger).message, // logger message
  59. }
  60. var runtimeFields = map[string]bool{
  61. "name": false,
  62. "seqid": false,
  63. "levelno": false,
  64. "levelname": false,
  65. "created": false,
  66. "nsecs": false,
  67. "time": false,
  68. "timestamp": false,
  69. "rtime": false,
  70. "filename": true,
  71. "pathname": true,
  72. "module": false,
  73. "lineno": true,
  74. "funcname": true,
  75. "thread": true,
  76. "process": false,
  77. "message": false,
  78. }
  79. // If it fails to get some fields with string type, these fields are set to
  80. // errString value.
  81. const errString = "???"
  82. // GetGoID returns the id of goroutine, which is defined in ./get_go_id.c
  83. func GetGoID() int32
  84. // genRuntime generates the runtime information, including pathname, function
  85. // name, filename, line number.
  86. func genRuntime(r *record) {
  87. calldepth := 5
  88. pc, file, line, ok := runtime.Caller(calldepth)
  89. if ok {
  90. // Generate short function name
  91. fname := runtime.FuncForPC(pc).Name()
  92. fshort := fname
  93. for i := len(fname) - 1; i > 0; i-- {
  94. if fname[i] == '.' {
  95. fshort = fname[i+1:]
  96. break
  97. }
  98. }
  99. r.pathname = file
  100. r.funcname = fshort
  101. r.filename = path.Base(file)
  102. r.lineno = line
  103. } else {
  104. r.pathname = errString
  105. r.funcname = errString
  106. r.filename = errString
  107. // Here we uses -1 rather than 0, because the default value in
  108. // golang is 0 and we should know the value is uninitialized
  109. // or failed to get
  110. r.lineno = -1
  111. }
  112. }
  113. // Logger name
  114. func (logger *Logger) lname(r *record) interface{} {
  115. return logger.name
  116. }
  117. // Next sequence number
  118. func (logger *Logger) nextSeqid(r *record) interface{} {
  119. if r.seqid == 0 {
  120. r.seqid = atomic.AddUint64(&(logger.seqid), 1)
  121. }
  122. return r.seqid
  123. }
  124. // Log level number
  125. func (logger *Logger) levelno(r *record) interface{} {
  126. return int32(r.level)
  127. }
  128. // Log level name
  129. func (logger *Logger) levelname(r *record) interface{} {
  130. return levelNames[r.level]
  131. }
  132. // File name of calling logger, with whole path
  133. func (logger *Logger) pathname(r *record) interface{} {
  134. if r.pathname == "" {
  135. genRuntime(r)
  136. }
  137. return r.pathname
  138. }
  139. // File name of calling logger
  140. func (logger *Logger) filename(r *record) interface{} {
  141. if r.filename == "" {
  142. genRuntime(r)
  143. }
  144. return r.filename
  145. }
  146. // module name
  147. func (logger *Logger) module(r *record) interface{} {
  148. module, _ := osext.Executable()
  149. return path.Base(module)
  150. }
  151. // Line number
  152. func (logger *Logger) lineno(r *record) interface{} {
  153. if r.lineno == 0 {
  154. genRuntime(r)
  155. }
  156. return r.lineno
  157. }
  158. // Function name
  159. func (logger *Logger) funcname(r *record) interface{} {
  160. if r.funcname == "" {
  161. genRuntime(r)
  162. }
  163. return r.funcname
  164. }
  165. // Timestamp of starting time
  166. func (logger *Logger) created(r *record) interface{} {
  167. return logger.startTime.UnixNano()
  168. }
  169. // RFC3339Nano time
  170. func (logger *Logger) time(r *record) interface{} {
  171. if r.time.IsZero() {
  172. r.time = time.Now()
  173. }
  174. return r.time.Format(logger.timeFormat)
  175. }
  176. // Nanosecond of starting time
  177. func (logger *Logger) nsecs(r *record) interface{} {
  178. return logger.startTime.Nanosecond()
  179. }
  180. // Nanosecond timestamp
  181. func (logger *Logger) timestamp(r *record) interface{} {
  182. if r.time.IsZero() {
  183. r.time = time.Now()
  184. }
  185. return r.time.UnixNano()
  186. }
  187. // Nanoseconds since logger created
  188. func (logger *Logger) rtime(r *record) interface{} {
  189. if r.time.IsZero() {
  190. r.time = time.Now()
  191. }
  192. return r.time.Sub(logger.startTime).Nanoseconds()
  193. }
  194. // Thread ID
  195. func (logger *Logger) thread(r *record) interface{} {
  196. if r.thread == 0 {
  197. r.thread = int(GetGoID())
  198. }
  199. return r.thread
  200. }
  201. // Process ID
  202. func (logger *Logger) process(r *record) interface{} {
  203. if r.process == 0 {
  204. r.process = os.Getpid()
  205. }
  206. return r.process
  207. }
  208. // The log message
  209. func (logger *Logger) message(r *record) interface{} {
  210. return r.message
  211. }