SwiftyBeaver.swift 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. //
  2. // SwiftyBeaver.swift
  3. // SwiftyBeaver
  4. //
  5. // Created by Sebastian Kreutzberger (Twitter @skreutzb) on 28.11.15.
  6. // Copyright © 2015 Sebastian Kreutzberger
  7. // Some rights reserved: http://opensource.org/licenses/MIT
  8. //
  9. import Foundation
  10. open class SwiftyBeaver {
  11. /// version string of framework
  12. public static let version = "1.7.0" // UPDATE ON RELEASE!
  13. /// build number of framework
  14. public static let build = 1700 // version 1.6.2 -> 1620, UPDATE ON RELEASE!
  15. public enum Level: Int {
  16. case verbose = 0
  17. case debug = 1
  18. case info = 2
  19. case warning = 3
  20. case error = 4
  21. }
  22. // a set of active destinations
  23. public private(set) static var destinations = Set<BaseDestination>()
  24. // MARK: Destination Handling
  25. /// returns boolean about success
  26. @discardableResult
  27. open class func addDestination(_ destination: BaseDestination) -> Bool {
  28. if destinations.contains(destination) {
  29. return false
  30. }
  31. destinations.insert(destination)
  32. return true
  33. }
  34. /// returns boolean about success
  35. @discardableResult
  36. open class func removeDestination(_ destination: BaseDestination) -> Bool {
  37. if destinations.contains(destination) == false {
  38. return false
  39. }
  40. destinations.remove(destination)
  41. return true
  42. }
  43. /// if you need to start fresh
  44. open class func removeAllDestinations() {
  45. destinations.removeAll()
  46. }
  47. /// returns the amount of destinations
  48. open class func countDestinations() -> Int {
  49. return destinations.count
  50. }
  51. /// returns the current thread name
  52. class func threadName() -> String {
  53. #if os(Linux)
  54. // on 9/30/2016 not yet implemented in server-side Swift:
  55. // > import Foundation
  56. // > Thread.isMainThread
  57. return ""
  58. #else
  59. if Thread.isMainThread {
  60. return ""
  61. } else {
  62. let threadName = Thread.current.name
  63. if let threadName = threadName, !threadName.isEmpty {
  64. return threadName
  65. } else {
  66. return String(format: "%p", Thread.current)
  67. }
  68. }
  69. #endif
  70. }
  71. // MARK: Levels
  72. /// log something generally unimportant (lowest priority)
  73. open class func verbose(_ message: @autoclosure () -> Any, _
  74. file: String = #file, _ function: String = #function, line: Int = #line, context: Any? = nil) {
  75. #if swift(>=5)
  76. custom(level: .verbose, message: message(), file: file, function: function, line: line, context: context)
  77. #else
  78. custom(level: .verbose, message: message, file: file, function: function, line: line, context: context)
  79. #endif
  80. }
  81. /// log something which help during debugging (low priority)
  82. open class func debug(_ message: @autoclosure () -> Any, _
  83. file: String = #file, _ function: String = #function, line: Int = #line, context: Any? = nil) {
  84. #if swift(>=5)
  85. custom(level: .debug, message: message(), file: file, function: function, line: line, context: context)
  86. #else
  87. custom(level: .debug, message: message, file: file, function: function, line: line, context: context)
  88. #endif
  89. }
  90. /// log something which you are really interested but which is not an issue or error (normal priority)
  91. open class func info(_ message: @autoclosure () -> Any, _
  92. file: String = #file, _ function: String = #function, line: Int = #line, context: Any? = nil) {
  93. #if swift(>=5)
  94. custom(level: .info, message: message(), file: file, function: function, line: line, context: context)
  95. #else
  96. custom(level: .info, message: message, file: file, function: function, line: line, context: context)
  97. #endif
  98. }
  99. /// log something which may cause big trouble soon (high priority)
  100. open class func warning(_ message: @autoclosure () -> Any, _
  101. file: String = #file, _ function: String = #function, line: Int = #line, context: Any? = nil) {
  102. #if swift(>=5)
  103. custom(level: .warning, message: message(), file: file, function: function, line: line, context: context)
  104. #else
  105. custom(level: .warning, message: message, file: file, function: function, line: line, context: context)
  106. #endif
  107. }
  108. /// log something which will keep you awake at night (highest priority)
  109. open class func error(_ message: @autoclosure () -> Any, _
  110. file: String = #file, _ function: String = #function, line: Int = #line, context: Any? = nil) {
  111. #if swift(>=5)
  112. custom(level: .error, message: message(), file: file, function: function, line: line, context: context)
  113. #else
  114. custom(level: .error, message: message, file: file, function: function, line: line, context: context)
  115. #endif
  116. }
  117. /// custom logging to manually adjust values, should just be used by other frameworks
  118. public class func custom(level: SwiftyBeaver.Level, message: @autoclosure () -> Any,
  119. file: String = #file, function: String = #function, line: Int = #line, context: Any? = nil) {
  120. #if swift(>=5)
  121. dispatch_send(level: level, message: message(), thread: threadName(),
  122. file: file, function: function, line: line, context: context)
  123. #else
  124. dispatch_send(level: level, message: message, thread: threadName(),
  125. file: file, function: function, line: line, context: context)
  126. #endif
  127. }
  128. /// internal helper which dispatches send to dedicated queue if minLevel is ok
  129. class func dispatch_send(level: SwiftyBeaver.Level, message: @autoclosure () -> Any,
  130. thread: String, file: String, function: String, line: Int, context: Any?) {
  131. var resolvedMessage: String?
  132. for dest in destinations {
  133. guard let queue = dest.queue else {
  134. continue
  135. }
  136. resolvedMessage = resolvedMessage == nil && dest.hasMessageFilters() ? "\(message())" : resolvedMessage
  137. if dest.shouldLevelBeLogged(level, path: file, function: function, message: resolvedMessage) {
  138. // try to convert msg object to String and put it on queue
  139. let msgStr = resolvedMessage == nil ? "\(message())" : resolvedMessage!
  140. let f = stripParams(function: function)
  141. if dest.asynchronously {
  142. queue.async {
  143. _ = dest.send(level, msg: msgStr, thread: thread, file: file, function: f, line: line, context: context)
  144. }
  145. } else {
  146. queue.sync {
  147. _ = dest.send(level, msg: msgStr, thread: thread, file: file, function: f, line: line, context: context)
  148. }
  149. }
  150. }
  151. }
  152. }
  153. /**
  154. DEPRECATED & NEEDS COMPLETE REWRITE DUE TO SWIFT 3 AND GENERAL INCORRECT LOGIC
  155. Flush all destinations to make sure all logging messages have been written out
  156. Returns after all messages flushed or timeout seconds
  157. - returns: true if all messages flushed, false if timeout or error occurred
  158. */
  159. public class func flush(secondTimeout: Int64) -> Bool {
  160. /*
  161. guard let grp = dispatch_group_create() else { return false }
  162. for dest in destinations {
  163. if let queue = dest.queue {
  164. dispatch_group_enter(grp)
  165. queue.asynchronously(execute: {
  166. dest.flush()
  167. grp.leave()
  168. })
  169. }
  170. }
  171. let waitUntil = DispatchTime.now(dispatch_time_t(DISPATCH_TIME_NOW), secondTimeout * 1000000000)
  172. return dispatch_group_wait(grp, waitUntil) == 0
  173. */
  174. return true
  175. }
  176. /// removes the parameters from a function because it looks weird with a single param
  177. class func stripParams(function: String) -> String {
  178. var f = function
  179. if let indexOfBrace = f.find("(") {
  180. #if swift(>=4.0)
  181. f = String(f[..<indexOfBrace])
  182. #else
  183. f = f.substring(to: indexOfBrace)
  184. #endif
  185. }
  186. f += "()"
  187. return f
  188. }
  189. }