Skip to content

Commit

Permalink
Add LocalLogHandler
Browse files Browse the repository at this point in the history
  • Loading branch information
Justin Magnini committed May 27, 2021
1 parent c06f4d9 commit 75edda5
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 17 deletions.
20 changes: 11 additions & 9 deletions Example/Pods/Pods.xcodeproj/project.pbxproj

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 11 additions & 3 deletions Example/Tests/LogTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@ class LogTests: XCTestCase {

func testLogHandler() {

let handler = LocalLogHandler()

var loggedStrings: [(level: Log.Level, string: String)] = []
Log.globalHandler = { (log, level, string) in
handler.addEntry(log: log, level: level, entry: string)
loggedStrings.append((level: level, string: string))
}

Expand All @@ -49,21 +52,26 @@ class LogTests: XCTestCase {
NetworkLog.verbose("network verbose")
NetworkLog.debug("network debug")
NetworkLog.info("network info")
NetworkLog.warn("network warning")
NetworkLog.error("network error")
NetworkLog.warn("Network warning")
NetworkLog.error("network ERROR!")

localInstance.warn("Local Instance Warning")
Loggers.userInterface.info("Button Pressed")
Loggers.userInterface.info("Button Released")
Loggers.app.warn("Out of Memory")

Log.trace("tests", type: .end)

// Log messages include the date, which is not conducive to testing,
// so we just check the end of the logged string.
XCTAssertEqual(loggedStrings.count, 8)
XCTAssertEqual(loggedStrings.count, 9)
XCTAssertEqual(loggedStrings[1].level, .error)
XCTAssertTrue(loggedStrings[1].string.hasSuffix("Don't ignore me!"))
XCTAssertTrue(loggedStrings[2].string.hasSuffix("network info"))
XCTAssertEqual(networkStrings.count, 3)

XCTAssertEqual(handler.getEntries(level: .error).count, 2)
XCTAssertEqual(handler.getEntries("Network", level: .error).count, 1)
XCTAssertEqual(handler.search("Button").count, 2)
}
}
105 changes: 105 additions & 0 deletions LocalLogHandler.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
//
// LocalLogHandler.swift
// Swiftilities
//
// Created by Justin Magnini on 5/27/21.
//

import Foundation

/// A handler to collect Log messages locally, and allow for searching and filtering.
open class LocalLogHandler {

/// Represents a single entry collected from a Log instance
public struct LogEntry {
/// Category of the Log where this entry was originated from
var category: String

/// Log level of entry.
var level: Log.Level

/// Message sent by Log.
var message: String

/// When Log entry was received
var timestamp: Date
}

/// Maximum number of Log entries that may be collected.
var size: UInt = 1000

private var entries: [LogEntry] = []

// MARK: Initializer

public init(size: UInt = 1000) {
self.size = size
}

// MARK: Public Methods

/// Intended to be called from the Log.globalHandler to record Log messages.
public func addEntry(log: Log, level: Log.Level, entry: String) {
entries.append(.init(category: log.name, level: level, message: entry, timestamp: Date()))
while entries.count > size {
entries.remove(at: 0)
}
}

/// Remove all entries
public func removeAllEntries() {
entries.removeAll()
}

/// Returns all entries captured by the LocalLogHandler raw, and unfiltered
public func allEntries() -> [LogEntry] {
return entries
}

/**
Filters all log entries, only returning those that match the given criteria

- parameter category: If non-nill, entry must have come from a Log with this category.
- parameter level: If non-nill, minimum level for a log entry.

- returns: A filtered listed of `LogEntry` elements that match the criteria.
*/
public func getEntries(_ category: String, level: Log.Level? = nil) -> [LogEntry] {
return getEntries(categories: [category], level: level)
}

/**
Filters all log entries, only returning those that match the given criteria

- parameter categories: If non-nill, entry must have come from a Log with one of these category.
- parameter level: If non-nill, minimum level for a log entry.

- returns: A filtered listed of `LogEntry` elements that match the criteria.
*/
public func getEntries(categories: [String]? = nil, level: Log.Level? = nil) -> [LogEntry] {
return entries.filter {
if !(categories?.contains($0.category) ?? true) {
return false
}

if $0.level.rawValue < level?.rawValue ?? 0 {
return false
}

return true
}
}

/**
Searches for log entries that match the provided query.

- parameter query: Regular Expression search query.

- returns: A filtered listed of `LogEntry` elements that match the query.
*/
public func search(_ query: String) -> [LogEntry] {
return entries.filter {
($0.message.range(of: query, options: .regularExpression)?.isEmpty ?? true) == false
}
}
}
10 changes: 5 additions & 5 deletions Pod/Classes/Logging/Log.swift
Original file line number Diff line number Diff line change
Expand Up @@ -150,15 +150,15 @@ open class Log {
let logger = Logger(subsystem: subsystem, category: name)
switch level {
case .trace, .verbose:
logger.trace("\(logMessage):\n\(objectString, privacy: .private)")
logger.trace("\(logMessage):\n\(objectString)")
case .debug:
logger.debug("\(logMessage):\n\(objectString, privacy: .private)")
logger.debug("\(logMessage):\n\(objectString)")
case .info:
logger.info("\(logMessage):\n\(objectString, privacy: .private)")
logger.info("\(logMessage):\n\(objectString)")
case .warn:
logger.warning("\(logMessage):\n\(objectString, privacy: .private)")
logger.warning("\(logMessage):\n\(objectString)")
case .error:
logger.error("\(logMessage):\n\(objectString, privacy: .private)")
logger.error("\(logMessage):\n\(objectString)")
case .off:
break
}
Expand Down

0 comments on commit 75edda5

Please sign in to comment.