Swiftpack.co -  aliaslab-1984/BattleAxe as Swift Package
Swiftpack.co is a collection of thousands of indexed Swift packages. Search packages.
A simple and extensible Logger written in Swift.
.package(url: "https://github.com/aliaslab-1984/BattleAxe.git", from: "v0.2")


Swift SwiftPM compatible

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 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 initilaize LogService:

let logDateFormatter = LogDateFormatter(dateFormat: "yyyy-MM-dd HH:mm:ssSSS")
LogService.register(provider: ConsoleLogProvider(dateFormatter: logDateFormatter))
LogService.register(provider: FileLogProvider(dateFormatter: logDateFormatter,
                                              fileWriter: LogFileWriter(filePath: "~/logs.log")))
// And so on for all your providers..

Once you're done with the configuration, you can start logging by calling:

LogService.shared.debug("Your first log!")

BattleAxe offers a LogRotation feature built into any FileWriter. Logs could be rotated following three main criteria:

  • Log Size;
  • Log file Age;
  • Number of files.

You can easilly specify each of these properties when you initialize your custom RotatorConfiguration instance:

RotatorConfiguration(maxSize: 10.kiloBytes, maxFiles: 2) 
// keeps on logging on a file until it excedes the 10 kiloBytes threshold.
// rotates two backup files, plus the current logging file.

To make things easier BattleAxe offers some cool extensions to make your code even more readable, such as from days/hours to seconds, from int to kilo/Mega/Gigabytes.

/// This creates the number of bytes that corresponds to 10 megabytes. (1024 * 1024 * 10 in this case)
let fileSize = 10.megaBytes

Another great feature offered by BattleAxe is the ability to gather all the relevant information from each log entry, in fact, each log is transformed by the LogService into a LogMessage. A LogMessage is a protocol that describes all the required information that a LogEntry should hold.

public protocol LogMessage {
    var description: String { get }
    var callingThread: String { get }
    var processId: Int32 { get }
    var payload: String { get }
    var severity: LogSeverity { get }
    var callingFilePath: String { get }
    var callingFileLine: Int { get }
    var callingStackFrame: String { get }
    var callingThreadID: UInt64 { get }
    var timestamp: Date { get }

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


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:

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

  1. 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.
// Define a unique enum that holds all the LogChannels.
enum LogChannel: String, CaseIterable {
    case networking = "Networking 📻"
    case authentication = "Authentication 🗝"
    case general = "General Logger 📝"
  1. 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:
// .. Into your logger:

LogChannel.allCases.forEach {

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:

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.

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


Stars: 2
Last commit: 12 hours ago

Ad: Job Offers

iOS Software Engineer @ Perry Street Software
Perry Street Software is Jack’d and SCRUFF. We are two of the world’s largest gay, bi, trans and queer social dating apps on iOS and Android. Our brands reach more than 20 million members worldwide so members can connect, meet and express themselves on a platform that prioritizes privacy and security. We invest heavily into SwiftUI and using Swift Packages to modularize the codebase.

Release Notes

More fixes
16 hours ago

Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API