Skip to content

Commit

Permalink
Merge pull request #2 from aliaslab-1984/develop
Browse files Browse the repository at this point in the history
BattleAxe channels
  • Loading branch information
icesco authored May 19, 2021
2 parents 0ce5a69 + 0b494b5 commit f0b7251
Show file tree
Hide file tree
Showing 17 changed files with 456 additions and 75 deletions.
54 changes: 51 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
![Swift](https://github.com/aliaslab-1984/BattleAxe/workflows/Swift/badge.svg)
[![SwiftPM compatible](https://img.shields.io/badge/SwiftPM-compatible-brightgreen.svg)](https://swift.org/package-manager/)

Welcome to BattleAxe, an easy and super extstensible Logger for iOS and macOS.
Welcome to BattleAxe, an easy and super extensible Logger for iOS and macOS.

To start using BattleAxe follow this steps:

It might be useful to initialize all the LogProviders whenever the app is launched/created, in order to mantain syncronization.
It might be useful to initialize all the LogProviders whenever the app is launched/created, in order to mantain synchronization.
A good place for that could be `application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool` or `scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions)`if you use `SceneDelegate`.

Here's a small example to intilaize `LogService`:
Here's a small example to initilaize `LogService`:
``` swift
let logDateFormatter = LogDateFormatter(dateFormat: "yyyy-MM-dd HH:mm:ssSSS")
LogService.register(provider: ConsoleLogProvider(dateFormatter: logDateFormatter))
Expand Down Expand Up @@ -70,3 +70,51 @@ public protocol LogMessage {
```

All of these information could be useful when you write your own `LogProvider` object.

## Channels

BattleAxe lets you organize your logs per Channel! This makes log filtering easier.
By default, if you don't specify a channel to log into, BattleAxe is going to log on the default general channel (`BattleAxe 🪓`).
To start using channels all you have to do is:
1. Register all your `LogProvider` instances as it follows:

```swift

let provider = ConsoleLogProvider(dateFormatter: BattleAxe.LogDateFormatter.init(dateFormat: "dd-mm-yy"), configuration: .naive)
LogService.register(provider: provider)

```

2. After that, you need to register all the channels that you intend to use on your project. We highly raccomend to define them in an enum, as we show below. This will make sure that you won't make typos and log on unwanted channels.
```swift
// Define a unique enum that holds all the LogChannels.
enum LogChannel: String, CaseIterable {

case networking = "Networking 📻"
case authentication = "Authentication 🗝"
case general = "General Logger 📝"

}
```
3. After defining your channels you only need to register them by using the `LogSevice` static method, or to register each provider with a subset of your channels:
```swift
// .. Into your logger:

LogChannel.allCases.forEach {
LogService.add($0.rawValue)
}
```
This approach subscribes *all* your registered providers to the specified channel.
An alternative is to call the `addChannel(_ channel: String)` to a single `LogProvider`, like so:

``` swift
let provider = ConsoleLogProvider(dateFormatter: BattleAxe.LogDateFormatter.init(dateFormat: "dd-mm-yy"), configuration: .naive)
let remoteProvider = MyProvider(dateFormatter: BattleAxe.LogDateFormatter.init(dateFormat: "dd-mm-yy"), configuration: .naive)

// .. we want to share our .network Logs with the remoteProvider instance.

remoteProvider.addChannel(LogChannel.networking)
// from now all the logs that are shared via the `.network` channel, are going to be passed to the remoteProvider instance.

```

1 change: 1 addition & 0 deletions Sources/BattleAxe/FileWriter/Writers/BaseFileWriter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ open class BaseFileWriter: FileWriter {

public func write(_ message: String) {
// Does nothing
fatalError("Subclasses need to implement the `write(_ message: String)` method.")
}

/// Returns the URL where the log collection is stored.
Expand Down
5 changes: 3 additions & 2 deletions Sources/BattleAxe/LogMessage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public protocol LogMessage {
var callingStackFrame: String { get }
var callingThreadID: UInt64 { get }
var timestamp: Date { get }
var channel: String { get }
}

/**
Expand All @@ -43,15 +44,15 @@ public struct LoggedMessage: Codable, LogMessage, Hashable, Equatable {
public var callingFileLine: Int
public var callingStackFrame: String
public var callingThreadID: UInt64

public var channel: String
public var timestamp: Date = Date()

}

/**
Helper struct that gathers the current ProcessIdentification and encapsulates the process's name and identifier.
*/
fileprivate struct ProcessIdentification {
struct ProcessIdentification {
// this ensures we only look up process info once
public static let current = ProcessIdentification()

Expand Down
46 changes: 46 additions & 0 deletions Sources/BattleAxe/LogMessageComposer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// File.swift
//
//
// Created by Francesco Bianco on 14/05/21.
//

import Foundation

/// Helper struct that handles the creation of a printable message, given the message and the needed ingredients.
struct LogMessageFormatter {

/// Given a log message creates a correclty formatted string following the ingredients provided.
/// - Parameters:
/// - message: The message that needs to be formatted.
/// - ingredients: The ingredients that need to be added to the formatted message.
/// - dateFormatter: The dateformetter style.
/// - Returns: the formatted string.
static func compose(_ message: LogMessage,
using ingredients: [LoggerConfiguration.LogIngredient],
dateFormatter: DateFormatter) -> String {
var finalMessage: String = ""

ingredients.forEach { ingredient in
switch ingredient {
case .channel:
finalMessage.append("{\(message.channel)} ")
case .severity:
finalMessage.append("[\(message.severity.prettyDescription)] ")
case .date:
finalMessage.append("\(dateFormatter.getCurrentDateAsString()) ")
case .fileName:
finalMessage.append("\(message.callingFilePath):")
case .functionName:
finalMessage.append("\(message.callingStackFrame):")
case .lineNumber:
finalMessage.append("(\(message.callingFileLine))")
case .payload:
finalMessage.append("\(message.payload)")
}
}

return finalMessage
}

}
78 changes: 53 additions & 25 deletions Sources/BattleAxe/LogService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ public final class LogService {
/// Whether the logging is enabled or not.
public var enabled: Bool = true

/// The default channel
public static let defaultChannel: String = "BattleAxe 🪓"

public typealias Dump = () -> Any

private init(providers: [LogProvider]) {
Expand All @@ -39,10 +42,27 @@ public final class LogService {
providers.remove(at: index)
}

/// Removes all the registered providers.
public static func empty() {
self.providers = []
}

/// Removes the passed channel to all the providers.
/// - Parameter channel: the channel that is going to be removed.
public static func silence(_ channel: String) {
providers.forEach { provider in
provider.removeChannel(channel)
}
}

/// Adds the passed channel to all the providers.
/// - Parameter channel: the channel that is going to be added. If a provider already uses the passed channel it won't duplicate.
public static func add(_ channel: String) {
providers.forEach { provider in
provider.addChannel(channel)
}
}

/// The currently registered providers
public static var currentProviders: [LogProvider] { return providers }

Expand Down Expand Up @@ -75,21 +95,16 @@ public final class LogService {
/// - line: The file's line.
public func log(_ severity: LogSeverity,
_ object: @autoclosure @escaping Dump,
channel: String? = nil,
filename: String = #file,
funcName: String = #function,
line: Int = #line) {
switch severity {
case .verbose:
self.evaluate(severity: .verbose, object, filename: filename, line: line, funcName: funcName)
case .debug:
self.evaluate(severity: .debug, object, filename: filename, line: line, funcName: funcName)
case .info:
self.evaluate(severity: .info, object, filename: filename, line: line, funcName: funcName)
case .warning:
self.evaluate(severity: .warning, object, filename: filename, line: line, funcName: funcName)
case .error:
self.evaluate(severity: .error, object, filename: filename, line: line, funcName: funcName)
}
self.evaluate(severity: severity,
object,
channel: channel ?? Self.defaultChannel,
filename: filename,
line: line,
funcName: funcName)
}


Expand All @@ -101,6 +116,7 @@ public final class LogService {
/// - funcName: The method name from which it is getting called.
/// - line: The line from where it's getting called.
public func info(_ object: @autoclosure Dump,
channel: String? = nil,
filename: String = #file,
funcName: String = #function,
line: Int = #line) {
Expand All @@ -111,6 +127,7 @@ public final class LogService {

propagate(object(),
.info,
channel: channel ?? Self.defaultChannel,
filename: LogService.fileName(filePath: filename),
line: line,
funcName: funcName)
Expand All @@ -124,16 +141,18 @@ public final class LogService {
/// - funcName: The method name from which it is getting called.
/// - line: The line from where it's getting called.
public func debug(_ object: @autoclosure Dump,
filename: String = #file,
line: Int = #line,
funcName: String = #function) {
channel: String? = nil,
filename: String = #file,
line: Int = #line,
funcName: String = #function) {

guard minimumSeverity <= .debug, enabled else {
return
}

propagate(object(),
.debug,
channel: channel ?? Self.defaultChannel,
filename: LogService.fileName(filePath: filename),
line: line,
funcName: funcName)
Expand All @@ -147,16 +166,18 @@ public final class LogService {
/// - funcName: The method name from which it is getting called.
/// - line: The line from where it's getting called.
public func verbose(_ object: @autoclosure Dump,
filename: String = #file,
line: Int = #line,
funcName: String = #function) {
channel: String? = nil,
filename: String = #file,
line: Int = #line,
funcName: String = #function) {

guard minimumSeverity <= .verbose, enabled else {
return
}

propagate(object(),
.verbose,
channel: channel ?? Self.defaultChannel,
filename: LogService.fileName(filePath: filename),
line: line,
funcName: funcName)
Expand All @@ -170,16 +191,18 @@ public final class LogService {
/// - funcName: The method name from which it is getting called.
/// - line: The line from where it's getting called.
public func warning(_ object: @autoclosure Dump,
filename: String = #file,
line: Int = #line,
funcName: String = #function) {
channel: String? = nil,
filename: String = #file,
line: Int = #line,
funcName: String = #function) {

guard minimumSeverity <= .warning, enabled else {
return
}

propagate(object(),
.warning,
channel: channel ?? Self.defaultChannel,
filename: LogService.fileName(filePath: filename),
line: line,
funcName: funcName)
Expand All @@ -193,23 +216,26 @@ public final class LogService {
/// - funcName: The method name from which it is getting called.
/// - line: The line from where it's getting called.
public func error(_ object: @autoclosure Dump,
filename: String = #file,
line: Int = #line,
funcName: String = #function) {
channel: String? = nil,
filename: String = #file,
line: Int = #line,
funcName: String = #function) {

guard minimumSeverity <= .error, enabled else {
return
}

propagate(object(),
.error,
channel: channel ?? Self.defaultChannel,
filename: LogService.fileName(filePath: filename),
line: line,
funcName: funcName)
}

private func evaluate(severity: LogSeverity,
_ object: @autoclosure Dump,
channel: String,
filename: String = #file,
line: Int = #line,
funcName: String = #function) {
Expand All @@ -220,6 +246,7 @@ public final class LogService {

propagate(object(),
severity,
channel: channel,
filename: LogService.fileName(filePath: filename),
line: line,
funcName: funcName)
Expand All @@ -228,6 +255,7 @@ public final class LogService {
/// Propagates the log to all the registered providers.
private func propagate(_ object: Any,
_ severity: LogSeverity,
channel: String,
filename: String = #file,
line: Int = #line,
funcName: String = #function) {
Expand All @@ -242,7 +270,7 @@ public final class LogService {
oggetto = object
}

let entity = LoggedMessage(payload: String(describing: oggetto), severity: severity, callingFilePath: filename, callingFileLine: line, callingStackFrame: funcName, callingThreadID: threadID)
let entity = LoggedMessage(payload: String(describing: oggetto), severity: severity, callingFilePath: filename, callingFileLine: line, callingStackFrame: funcName, callingThreadID: threadID, channel: channel)

LogService.providers.forEach {
$0.log(entity)
Expand Down
2 changes: 1 addition & 1 deletion Sources/BattleAxe/LogSeverity.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ import os.log
@available (iOS 10.0, *)
internal extension LogSeverity {

func toOSLogLevel() -> OSLogType {
var OSLogLevel: OSLogType {
switch self {
case .debug:
return .debug
Expand Down
Loading

0 comments on commit f0b7251

Please sign in to comment.