CapturingLogHandler.swift 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /*
  2. * Copyright 2020, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import struct Foundation.Date
  17. import Logging
  18. import NIOConcurrencyHelpers
  19. /// A `LogHandler` factory which captures all logs emitted by the handlers it makes.
  20. internal class CapturingLogHandlerFactory {
  21. private var lock = Lock()
  22. private var _logs: [CapturedLog] = []
  23. /// Returns all captured logs and empties the store of captured logs.
  24. func clearCapturedLogs() -> [CapturedLog] {
  25. return self.lock.withLock {
  26. let logs = self._logs
  27. self._logs.removeAll()
  28. return logs
  29. }
  30. }
  31. /// Make a `LogHandler` whose logs will be recorded by this factory.
  32. func make(_ label: String) -> LogHandler {
  33. return CapturingLogHandler(label: label) { log in
  34. self.lock.withLockVoid {
  35. self._logs.append(log)
  36. }
  37. }
  38. }
  39. }
  40. /// A captured log.
  41. internal struct CapturedLog {
  42. var label: String
  43. var level: Logger.Level
  44. var message: Logger.Message
  45. var metadata: Logger.Metadata
  46. var file: String
  47. var function: String
  48. var line: UInt
  49. var date: Date
  50. }
  51. /// A log handler which captures all logs it records.
  52. internal struct CapturingLogHandler: LogHandler {
  53. private let capture: (CapturedLog) -> Void
  54. internal let label: String
  55. internal var metadata: Logger.Metadata = [:]
  56. internal var logLevel: Logger.Level = .trace
  57. fileprivate init(label: String, capture: @escaping (CapturedLog) -> ()) {
  58. self.label = label
  59. self.capture = capture
  60. }
  61. internal func log(
  62. level: Logger.Level,
  63. message: Logger.Message,
  64. metadata: Logger.Metadata?,
  65. file: String,
  66. function: String,
  67. line: UInt
  68. ) {
  69. let merged: Logger.Metadata
  70. if let metadata = metadata {
  71. merged = self.metadata.merging(metadata, uniquingKeysWith: { old, new in return new })
  72. } else {
  73. merged = self.metadata
  74. }
  75. let log = CapturedLog(
  76. label: self.label,
  77. level: level,
  78. message: message,
  79. metadata: merged,
  80. file: file,
  81. function: function,
  82. line: line,
  83. date: Date()
  84. )
  85. self.capture(log)
  86. }
  87. internal subscript(metadataKey metadataKey: String) -> Logger.Metadata.Value? {
  88. get {
  89. return self.metadata[metadataKey]
  90. }
  91. set {
  92. self.metadata[metadataKey] = newValue
  93. }
  94. }
  95. }