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