log.odin 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  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 :: proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location) {
  60. // Do nothing
  61. }
  62. nil_logger :: proc() -> Logger {
  63. return Logger{nil_logger_proc, nil, Level.Debug, nil}
  64. }
  65. debugf :: proc(fmt_str: string, args: ..any, location := #caller_location) {
  66. logf(.Debug, fmt_str, ..args, location=location)
  67. }
  68. infof :: proc(fmt_str: string, args: ..any, location := #caller_location) {
  69. logf(.Info, fmt_str, ..args, location=location)
  70. }
  71. warnf :: proc(fmt_str: string, args: ..any, location := #caller_location) {
  72. logf(.Warning, fmt_str, ..args, location=location)
  73. }
  74. errorf :: proc(fmt_str: string, args: ..any, location := #caller_location) {
  75. logf(.Error, fmt_str, ..args, location=location)
  76. }
  77. fatalf :: proc(fmt_str: string, args: ..any, location := #caller_location) {
  78. logf(.Fatal, fmt_str, ..args, location=location)
  79. }
  80. debug :: proc(args: ..any, sep := " ", location := #caller_location) {
  81. log(.Debug, ..args, sep=sep, location=location)
  82. }
  83. info :: proc(args: ..any, sep := " ", location := #caller_location) {
  84. log(.Info, ..args, sep=sep, location=location)
  85. }
  86. warn :: proc(args: ..any, sep := " ", location := #caller_location) {
  87. log(.Warning, ..args, sep=sep, location=location)
  88. }
  89. error :: proc(args: ..any, sep := " ", location := #caller_location) {
  90. log(.Error, ..args, sep=sep, location=location)
  91. }
  92. fatal :: proc(args: ..any, sep := " ", location := #caller_location) {
  93. log(.Fatal, ..args, sep=sep, location=location)
  94. }
  95. panic :: proc(args: ..any, location := #caller_location) -> ! {
  96. log(.Fatal, ..args, location=location)
  97. runtime.panic("log.panic", location)
  98. }
  99. panicf :: proc(fmt_str: string, args: ..any, location := #caller_location) -> ! {
  100. logf(.Fatal, fmt_str, ..args, location=location)
  101. runtime.panic("log.panicf", location)
  102. }
  103. @(disabled=ODIN_DISABLE_ASSERT)
  104. assert :: proc(condition: bool, message := "", loc := #caller_location) {
  105. if !condition {
  106. @(cold)
  107. internal :: proc(message: string, loc: runtime.Source_Code_Location) {
  108. p := context.assertion_failure_proc
  109. if p == nil {
  110. p = runtime.default_assertion_failure_proc
  111. }
  112. log(.Fatal, message, location=loc)
  113. p("runtime assertion", message, loc)
  114. }
  115. internal(message, loc)
  116. }
  117. }
  118. @(disabled=ODIN_DISABLE_ASSERT)
  119. assertf :: proc(condition: bool, fmt_str: string, args: ..any, loc := #caller_location) {
  120. if !condition {
  121. // NOTE(dragos): We are using the same trick as in builtin.assert
  122. // to improve performance to make the CPU not
  123. // execute speculatively, making it about an order of
  124. // magnitude faster
  125. @(cold)
  126. internal :: proc(loc: runtime.Source_Code_Location, fmt_str: string, args: ..any) {
  127. p := context.assertion_failure_proc
  128. if p == nil {
  129. p = runtime.default_assertion_failure_proc
  130. }
  131. message := fmt.tprintf(fmt_str, ..args)
  132. log(.Fatal, message, location=loc)
  133. p("Runtime assertion", message, loc)
  134. }
  135. internal(loc, fmt_str, ..args)
  136. }
  137. }
  138. log :: proc(level: Level, args: ..any, sep := " ", location := #caller_location) {
  139. logger := context.logger
  140. if logger.procedure == nil {
  141. return
  142. }
  143. if level < logger.lowest_level {
  144. return
  145. }
  146. str := fmt.tprint(..args, sep=sep) //NOTE(Hoej): While tprint isn't thread-safe, no logging is.
  147. logger.procedure(logger.data, level, str, logger.options, location)
  148. }
  149. logf :: proc(level: Level, fmt_str: string, args: ..any, location := #caller_location) {
  150. logger := context.logger
  151. if logger.procedure == nil {
  152. return
  153. }
  154. if level < logger.lowest_level {
  155. return
  156. }
  157. str := fmt.tprintf(fmt_str, ..args)
  158. logger.procedure(logger.data, level, str, logger.options, location)
  159. }