2
0

CapturingLogHandler.swift 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  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 source: String
  47. var file: String
  48. var function: String
  49. var line: UInt
  50. var date: Date
  51. }
  52. /// A log handler which captures all logs it records.
  53. internal struct CapturingLogHandler: LogHandler {
  54. private let capture: (CapturedLog) -> Void
  55. internal let label: String
  56. internal var metadata: Logger.Metadata = [:]
  57. internal var logLevel: Logger.Level = .trace
  58. fileprivate init(label: String, capture: @escaping (CapturedLog) -> Void) {
  59. self.label = label
  60. self.capture = capture
  61. }
  62. internal func log(
  63. level: Logger.Level,
  64. message: Logger.Message,
  65. metadata: Logger.Metadata?,
  66. source: String,
  67. file: String,
  68. function: String,
  69. line: UInt
  70. ) {
  71. let merged: Logger.Metadata
  72. if let metadata = metadata {
  73. merged = self.metadata.merging(metadata, uniquingKeysWith: { _, new in new })
  74. } else {
  75. merged = self.metadata
  76. }
  77. let log = CapturedLog(
  78. label: self.label,
  79. level: level,
  80. message: message,
  81. metadata: merged,
  82. source: source,
  83. file: file,
  84. function: function,
  85. line: line,
  86. date: Date()
  87. )
  88. self.capture(log)
  89. }
  90. internal subscript(metadataKey metadataKey: String) -> Logger.Metadata.Value? {
  91. get {
  92. return self.metadata[metadataKey]
  93. }
  94. set {
  95. self.metadata[metadataKey] = newValue
  96. }
  97. }
  98. }