From 8da55d33c43b65f9306a6f8672b61fd7121aec63 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Wed, 5 Oct 2022 02:34:29 +0200
Subject: [PATCH] Add MessengerLogger

---
 .../Utils/MessengerLogger.swift               | 90 +++++++++++++++++++
 .../Utils/MessengerLoggerTests.swift          | 71 +++++++++++++++
 2 files changed, 161 insertions(+)
 create mode 100644 Sources/XXMessengerClient/Utils/MessengerLogger.swift
 create mode 100644 Tests/XXMessengerClientTests/Utils/MessengerLoggerTests.swift

diff --git a/Sources/XXMessengerClient/Utils/MessengerLogger.swift b/Sources/XXMessengerClient/Utils/MessengerLogger.swift
new file mode 100644
index 00000000..0dcf0bc5
--- /dev/null
+++ b/Sources/XXMessengerClient/Utils/MessengerLogger.swift
@@ -0,0 +1,90 @@
+import Foundation
+import Logging
+import XCTestDynamicOverlay
+
+public struct MessengerLogger {
+  public struct Log: Equatable {
+    public init(level: Logger.Level, message: String) {
+      self.level = level
+      self.message = message
+    }
+
+    public var level: Logger.Level
+    public var message: String
+  }
+
+  public var run: (Log, String, String, UInt) -> Void
+
+  public func callAsFunction(
+    _ item: Log,
+    file: String = #fileID,
+    function: String = #function,
+    line: UInt = #line
+  ) {
+    run(item, file, function, line)
+  }
+}
+
+extension MessengerLogger {
+  public static func live(
+    logger: Logger = Logger(label: "xx.network.MessengerClient")
+  ) -> MessengerLogger {
+    MessengerLogger { item, file, function, line in
+      logger.log(
+        level: item.level,
+        .init(stringLiteral: item.message),
+        file: file,
+        function: function,
+        line: line
+      )
+    }
+  }
+}
+
+extension MessengerLogger {
+  public static let unimplemented = MessengerLogger(
+    run: XCTUnimplemented("\(Self.self)")
+  )
+}
+
+extension MessengerLogger.Log {
+  static func parse(_ string: String) -> MessengerLogger.Log {
+    let level: Logger.Level
+    let message: String
+    let pattern = #"^([A-Z]+)( \d{4}/\d{2}/\d{2})?( \d{1,2}:\d{2}:\d{2}\.\d+)? (.*)"#
+    let regex = try! NSRegularExpression(
+      pattern: pattern,
+      options: .dotMatchesLineSeparators
+    )
+    let stringRange = NSRange(location: 0, length: string.utf16.count)
+    if let match = regex.firstMatch(in: string, range: stringRange) {
+      var groups: [Int: String] = [:]
+      for rangeIndex in 1..<match.numberOfRanges {
+        let nsRange = match.range(at: rangeIndex)
+        if !NSEqualRanges(nsRange, NSMakeRange(NSNotFound, 0)) {
+          let group = (string as NSString).substring(with: nsRange)
+          groups[rangeIndex] = group
+        }
+      }
+      level = MessengerLogger.Log.level(form: groups[1])
+      message = groups[4] ?? string
+    } else {
+      level = .notice
+      message = string
+    }
+    return MessengerLogger.Log(level: level, message: message)
+  }
+
+  static func level(form string: String?) -> Logger.Level {
+    switch string {
+    case "TRACE": return .trace
+    case "DEBUG": return .debug
+    case "INFO": return .info
+    case "WARN": return .warning
+    case "ERROR": return .error
+    case "CRITICAL": return .critical
+    case "FATAL": return .critical
+    default: return .notice
+    }
+  }
+}
diff --git a/Tests/XXMessengerClientTests/Utils/MessengerLoggerTests.swift b/Tests/XXMessengerClientTests/Utils/MessengerLoggerTests.swift
new file mode 100644
index 00000000..755863d9
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Utils/MessengerLoggerTests.swift
@@ -0,0 +1,71 @@
+import CustomDump
+import XCTest
+@testable import XXMessengerClient
+
+final class MessengerLoggerTests: XCTestCase {
+  func testParsingLog() {
+    XCTAssertNoDifference(
+      MessengerLogger.Log.parse("TRACE Tracing..."),
+      MessengerLogger.Log(level: .trace, message: "Tracing...")
+    )
+    XCTAssertNoDifference(
+      MessengerLogger.Log.parse("DEBUG Debugging..."),
+      MessengerLogger.Log(level: .debug, message: "Debugging...")
+    )
+    XCTAssertNoDifference(
+      MessengerLogger.Log.parse("INFO Informing..."),
+      MessengerLogger.Log(level: .info, message: "Informing...")
+    )
+    XCTAssertNoDifference(
+      MessengerLogger.Log.parse("WARN Warning!"),
+      MessengerLogger.Log(level: .warning, message: "Warning!")
+    )
+    XCTAssertNoDifference(
+      MessengerLogger.Log.parse("ERROR Failure!"),
+      MessengerLogger.Log(level: .error, message: "Failure!")
+    )
+    XCTAssertNoDifference(
+      MessengerLogger.Log.parse("CRITICAL Critical failure!"),
+      MessengerLogger.Log(level: .critical, message: "Critical failure!")
+    )
+    XCTAssertNoDifference(
+      MessengerLogger.Log.parse("FATAL Fatal failure!"),
+      MessengerLogger.Log(level: .critical, message: "Fatal failure!")
+    )
+  }
+
+  func testParsingFallbacks() {
+    XCTAssertNoDifference(
+      MessengerLogger.Log.parse("1234 Wrongly formatted"),
+      MessengerLogger.Log(level: .notice, message: "1234 Wrongly formatted")
+    )
+  }
+
+  func testParsingStripsDateTime() {
+    XCTAssertNoDifference(
+      MessengerLogger.Log.parse("INFO 2022/10/04 Informing..."),
+      MessengerLogger.Log(level: .info, message: "Informing...")
+    )
+    XCTAssertNoDifference(
+      MessengerLogger.Log.parse("INFO 23:36:55.755390 Informing..."),
+      MessengerLogger.Log(level: .info, message: "Informing...")
+    )
+    XCTAssertNoDifference(
+      MessengerLogger.Log.parse("INFO 2022/10/04 23:36:55.755390 Informing..."),
+      MessengerLogger.Log(level: .info, message: "Informing...")
+    )
+  }
+
+  func testParsingMultilineMessage() {
+    XCTAssertNoDifference(
+      MessengerLogger.Log.parse("""
+      ERROR 2022/10/04 23:51:15.021658 First line
+      Second line
+      """),
+      MessengerLogger.Log(level: .error, message: """
+      First line
+      Second line
+      """)
+    )
+  }
+}
-- 
GitLab