log.odin 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. package log
  2. import "base:runtime"
  3. import "core:fmt"
  4. // NOTE(bill, 2019-12-31): These are defined in `package runtime` as they are used in the `context`. This is to prevent an import definition cycle.
  5. /*
  6. Logger_Level :: enum {
  7. Debug = 0,
  8. Info = 10,
  9. Warning = 20,
  10. Error = 30,
  11. Fatal = 40,
  12. }
  13. */
  14. Level :: runtime.Logger_Level
  15. /*
  16. Option :: enum {
  17. Level,
  18. Date,
  19. Time,
  20. Short_File_Path,
  21. Long_File_Path,
  22. Line,
  23. Procedure,
  24. Terminal_Color
  25. }
  26. */
  27. Option :: runtime.Logger_Option
  28. /*
  29. Options :: bit_set[Option];
  30. */
  31. Options :: runtime.Logger_Options
  32. Full_Timestamp_Opts :: Options{
  33. .Date,
  34. .Time,
  35. }
  36. Location_Header_Opts :: Options{
  37. .Short_File_Path,
  38. .Long_File_Path,
  39. .Line,
  40. .Procedure,
  41. }
  42. Location_File_Opts :: Options{
  43. .Short_File_Path,
  44. .Long_File_Path,
  45. }
  46. /*
  47. Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location);
  48. */
  49. Logger_Proc :: runtime.Logger_Proc
  50. /*
  51. Logger :: struct {
  52. procedure: Logger_Proc,
  53. data: rawptr,
  54. lowest_level: Level,
  55. options: Logger_Options,
  56. }
  57. */
  58. Logger :: runtime.Logger
  59. nil_logger_proc :: runtime.default_logger_proc
  60. nil_logger :: proc() -> Logger {
  61. return Logger{nil_logger_proc, nil, Level.Debug, nil}
  62. }
  63. debugf :: proc(fmt_str: string, args: ..any, location := #caller_location) {
  64. logf(.Debug, fmt_str, ..args, location=location)
  65. }
  66. infof :: proc(fmt_str: string, args: ..any, location := #caller_location) {
  67. logf(.Info, fmt_str, ..args, location=location)
  68. }
  69. warnf :: proc(fmt_str: string, args: ..any, location := #caller_location) {
  70. logf(.Warning, fmt_str, ..args, location=location)
  71. }
  72. errorf :: proc(fmt_str: string, args: ..any, location := #caller_location) {
  73. logf(.Error, fmt_str, ..args, location=location)
  74. }
  75. fatalf :: proc(fmt_str: string, args: ..any, location := #caller_location) {
  76. logf(.Fatal, fmt_str, ..args, location=location)
  77. }
  78. debug :: proc(args: ..any, sep := " ", location := #caller_location) {
  79. log(.Debug, ..args, sep=sep, location=location)
  80. }
  81. info :: proc(args: ..any, sep := " ", location := #caller_location) {
  82. log(.Info, ..args, sep=sep, location=location)
  83. }
  84. warn :: proc(args: ..any, sep := " ", location := #caller_location) {
  85. log(.Warning, ..args, sep=sep, location=location)
  86. }
  87. error :: proc(args: ..any, sep := " ", location := #caller_location) {
  88. log(.Error, ..args, sep=sep, location=location)
  89. }
  90. fatal :: proc(args: ..any, sep := " ", location := #caller_location) {
  91. log(.Fatal, ..args, sep=sep, location=location)
  92. }
  93. panic :: proc(args: ..any, location := #caller_location) -> ! {
  94. log(.Fatal, ..args, location=location)
  95. runtime.panic("log.panic", location)
  96. }
  97. panicf :: proc(fmt_str: string, args: ..any, location := #caller_location) -> ! {
  98. logf(.Fatal, fmt_str, ..args, location=location)
  99. runtime.panic("log.panicf", location)
  100. }
  101. @(disabled=ODIN_DISABLE_ASSERT)
  102. assert :: proc(condition: bool, message := #caller_expression(condition), loc := #caller_location) {
  103. if !condition {
  104. @(cold)
  105. internal :: proc(message: string, loc: runtime.Source_Code_Location) {
  106. p := context.assertion_failure_proc
  107. if p == nil {
  108. p = runtime.default_assertion_failure_proc
  109. }
  110. log(.Fatal, message, location=loc)
  111. p("runtime assertion", message, loc)
  112. }
  113. internal(message, loc)
  114. }
  115. }
  116. @(disabled=ODIN_DISABLE_ASSERT)
  117. assertf :: proc(condition: bool, fmt_str: string, args: ..any, loc := #caller_location) {
  118. if !condition {
  119. // NOTE(dragos): We are using the same trick as in builtin.assert
  120. // to improve performance to make the CPU not
  121. // execute speculatively, making it about an order of
  122. // magnitude faster
  123. @(cold)
  124. internal :: proc(loc: runtime.Source_Code_Location, fmt_str: string, args: ..any) {
  125. p := context.assertion_failure_proc
  126. if p == nil {
  127. p = runtime.default_assertion_failure_proc
  128. }
  129. message := fmt.tprintf(fmt_str, ..args)
  130. log(.Fatal, message, location=loc)
  131. p("runtime assertion", message, loc)
  132. }
  133. internal(loc, fmt_str, ..args)
  134. }
  135. }
  136. ensure :: proc(condition: bool, message := #caller_expression(condition), loc := #caller_location) {
  137. if !condition {
  138. @(cold)
  139. internal :: proc(message: string, loc: runtime.Source_Code_Location) {
  140. p := context.assertion_failure_proc
  141. if p == nil {
  142. p = runtime.default_assertion_failure_proc
  143. }
  144. log(.Fatal, message, location=loc)
  145. p("unsatisfied ensure", message, loc)
  146. }
  147. internal(message, loc)
  148. }
  149. }
  150. ensuref :: proc(condition: bool, fmt_str: string, args: ..any, loc := #caller_location) {
  151. if !condition {
  152. @(cold)
  153. internal :: proc(loc: runtime.Source_Code_Location, fmt_str: string, args: ..any) {
  154. p := context.assertion_failure_proc
  155. if p == nil {
  156. p = runtime.default_assertion_failure_proc
  157. }
  158. message := fmt.tprintf(fmt_str, ..args)
  159. log(.Fatal, message, location=loc)
  160. p("unsatisfied ensure", message, loc)
  161. }
  162. internal(loc, fmt_str, ..args)
  163. }
  164. }
  165. log :: proc(level: Level, args: ..any, sep := " ", location := #caller_location) {
  166. logger := context.logger
  167. if logger.procedure == nil || logger.procedure == nil_logger_proc {
  168. return
  169. }
  170. if level < logger.lowest_level {
  171. return
  172. }
  173. runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
  174. str := fmt.tprint(..args, sep=sep) //NOTE(Hoej): While tprint isn't thread-safe, no logging is.
  175. logger.procedure(logger.data, level, str, logger.options, location)
  176. }
  177. logf :: proc(level: Level, fmt_str: string, args: ..any, location := #caller_location) {
  178. logger := context.logger
  179. if logger.procedure == nil || logger.procedure == nil_logger_proc {
  180. return
  181. }
  182. if level < logger.lowest_level {
  183. return
  184. }
  185. runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
  186. str := fmt.tprintf(fmt_str, ..args)
  187. logger.procedure(logger.data, level, str, logger.options, location)
  188. }