Zealous Logger v1.0.0
This commit is contained in:
parent
22f9c06308
commit
b4d4156e29
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"object": {
|
||||
"pins": [
|
||||
{
|
||||
"package": "CocoaLumberjack",
|
||||
"repositoryURL": "https://github.com/CocoaLumberjack/CocoaLumberjack.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "b06614d2373a9830c87817144d47ce654980a2d7",
|
||||
"version": "3.7.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-log",
|
||||
"repositoryURL": "https://github.com/apple/swift-log.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "5d66f7ba25daf4f94100e7022febf3c75e37a6c7",
|
||||
"version": "1.4.2"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": 1
|
||||
}
|
|
@ -15,16 +15,17 @@ let package = Package(
|
|||
],
|
||||
dependencies: [
|
||||
// Dependencies declare other packages that this package depends on.
|
||||
// .package(url: /* package url */, from: "1.0.0"),
|
||||
.package(url: "https://github.com/CocoaLumberjack/CocoaLumberjack.git", from: "3.7.0")
|
||||
],
|
||||
targets: [
|
||||
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
||||
// Targets can depend on other targets in this package, and on products in packages this package depends on.
|
||||
.target(
|
||||
name: "zealous-logger",
|
||||
dependencies: []),
|
||||
dependencies: [.product(name: "CocoaLumberjackSwift", package: "CocoaLumberjack")]),
|
||||
.testTarget(
|
||||
name: "zealous-loggerTests",
|
||||
dependencies: ["zealous-logger"]),
|
||||
dependencies: ["zealous-logger",
|
||||
.product(name: "CocoaLumberjackSwift", package: "CocoaLumberjack")]),
|
||||
]
|
||||
)
|
||||
|
|
|
@ -8,65 +8,95 @@
|
|||
import Foundation
|
||||
import os
|
||||
|
||||
#if COCOAPODS
|
||||
import CocoaLumberjack
|
||||
#else
|
||||
import CocoaLumberjackSwift
|
||||
#endif
|
||||
|
||||
|
||||
protocol ConcreteLogger {
|
||||
func log(level: LogLevel, message: String, file: StaticString, function: StaticString, line: Int)
|
||||
var level: LogLevel { get }
|
||||
}
|
||||
|
||||
class ConsoleLogger: Logger {
|
||||
enum LogLevel: Int {
|
||||
case debug
|
||||
case error
|
||||
case warning
|
||||
case event
|
||||
case info
|
||||
|
||||
var concreteLogger: ConcreteLogger
|
||||
|
||||
init(concreteLogger: ConcreteLogger) {
|
||||
self.concreteLogger = concreteLogger
|
||||
}
|
||||
|
||||
enum LoggerType {
|
||||
case osLog
|
||||
case printerLog
|
||||
func debug(_ message: String, file: StaticString, function: StaticString, line: Int) {
|
||||
guard concreteLogger.level.rawValue == LogLevel.debug.rawValue else { return }
|
||||
concreteLogger.log(level: concreteLogger.level, message: message, file: file, function: function, line: line)
|
||||
}
|
||||
|
||||
var level: LogLevel
|
||||
var loggerType: LoggerType
|
||||
|
||||
init(logLevel: LogLevel, type: LoggerType = .osLog) {
|
||||
self.level = logLevel
|
||||
self.loggerType = type
|
||||
func error(_ message: String, file: StaticString, function: StaticString, line: Int) {
|
||||
guard concreteLogger.level.rawValue <= LogLevel.error.rawValue else { return }
|
||||
concreteLogger.log(level: concreteLogger.level, message: message, file: file, function: function, line: line)
|
||||
}
|
||||
|
||||
private static let subsystem = Bundle.main.bundleIdentifier!
|
||||
|
||||
@available(OSX 10.12, *)
|
||||
static let oslog = OSLog(subsystem: subsystem, category: "logs")
|
||||
|
||||
func debug(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
|
||||
guard level.rawValue == LogLevel.debug.rawValue else { return }
|
||||
log(level: "DEBUG 🐞", message: message, file: file, function: function, line: line)
|
||||
}
|
||||
|
||||
func error(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
|
||||
guard level.rawValue <= LogLevel.error.rawValue else { return }
|
||||
log(level: "ERROR 💥", message: message, file: file, function: function, line: line)
|
||||
}
|
||||
|
||||
func warn(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
|
||||
guard level.rawValue <= LogLevel.warning.rawValue else { return }
|
||||
log(level: "WARNING ⚠️", message: message, file: file, function: function, line: line)
|
||||
func warn(_ message: String, file: StaticString, function: StaticString, line: Int) {
|
||||
guard concreteLogger.level.rawValue <= LogLevel.warning.rawValue else { return }
|
||||
concreteLogger.log(level: concreteLogger.level, message: message, file: file, function: function, line: line)
|
||||
}
|
||||
|
||||
func event(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
|
||||
guard level.rawValue <= LogLevel.event.rawValue else { return }
|
||||
log(level: "EVENT ⏱", message: message, file: file, function: function, line: line)
|
||||
func event(_ message: String, file: StaticString, function: StaticString, line: Int) {
|
||||
guard concreteLogger.level.rawValue <= LogLevel.event.rawValue else { return }
|
||||
concreteLogger.log(level: concreteLogger.level, message: message, file: file, function: function, line: line)
|
||||
}
|
||||
|
||||
func info(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
|
||||
guard level.rawValue <= LogLevel.info.rawValue else { return }
|
||||
log(level: "INFO ℹ️", message: message, file: file, function: function, line: line)
|
||||
}
|
||||
|
||||
private func log(level: String, message: String, file: String, function: String, line: Int) {
|
||||
let fileName = (file as NSString).lastPathComponent
|
||||
switch loggerType {
|
||||
case .printerLog:
|
||||
print("[\(level)] \(fileName) - \(function) - line: \(line) -> \(message)")
|
||||
default:
|
||||
os_log("[%{public}@] %{public}@ - %{public}@ - Line: %{public}d -> %{public}@", level, fileName, function, line, message)
|
||||
}
|
||||
func info(_ message: String, file: StaticString, function: StaticString, line: Int) {
|
||||
guard concreteLogger.level.rawValue <= LogLevel.info.rawValue else { return }
|
||||
concreteLogger.log(level: concreteLogger.level, message: message, file: file, function: function, line: line)
|
||||
}
|
||||
}
|
||||
|
||||
class OsLogLogger: ConcreteLogger {
|
||||
|
||||
var level: LogLevel
|
||||
|
||||
var oslog: OSLog
|
||||
|
||||
init(subsystem: String, level: LogLevel) {
|
||||
self.level = level
|
||||
self.oslog = OSLog(subsystem: subsystem, category: "logs")
|
||||
}
|
||||
|
||||
private func describeLevel(_ level: LogLevel) -> String {
|
||||
switch level {
|
||||
case .debug:
|
||||
return "DEBUG 🐞"
|
||||
case .error:
|
||||
return "ERROR 💥"
|
||||
case .event:
|
||||
return "EVENT ⏱"
|
||||
case .info:
|
||||
return "INFO ℹ️"
|
||||
case .warning:
|
||||
return "WARNING ⚠️"
|
||||
}
|
||||
}
|
||||
|
||||
func log(level: LogLevel, message: String, file: StaticString, function: StaticString, line: Int) {
|
||||
let fileName = (String(describing: file) as NSString).lastPathComponent
|
||||
|
||||
os_log("[%{public}@] %{public}@ - %{public}@ - Line: %{public}d -> %{public}@", log: oslog, describeLevel(level), fileName, String(describing: fileName), line, message)
|
||||
}
|
||||
}
|
||||
|
||||
class PrinterLogger: ConcreteLogger {
|
||||
|
||||
var level: LogLevel
|
||||
|
||||
init(level: LogLevel) {
|
||||
self.level = level
|
||||
}
|
||||
|
||||
func log(level: LogLevel, message: String, file: StaticString, function: StaticString, line: Int) {
|
||||
let filename = (String(describing: file) as NSString).lastPathComponent
|
||||
print("[\(level)] \(filename) - \(function) - line: \(line) -> \(message)")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
//
|
||||
// FileLogger.swift
|
||||
//
|
||||
//
|
||||
// Created by Francisco Gindre on 3/9/21.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
#if COCOAPODS
|
||||
import CocoaLumberjack
|
||||
#else
|
||||
import CocoaLumberjackSwift
|
||||
#endif
|
||||
|
||||
|
||||
class DDLogger: Logger {
|
||||
|
||||
var concreteLogger: ConcreteLogger
|
||||
|
||||
init(concreteLogger: ConcreteLogger) {
|
||||
self.concreteLogger = concreteLogger
|
||||
}
|
||||
|
||||
public func debug(_ message: String, file: StaticString, function: StaticString, line: Int) {
|
||||
DDLogDebug(message, level: toDDLogLevel(.debug), file: file, function: function, line: UInt(line))
|
||||
}
|
||||
|
||||
public func info(_ message: String, file: StaticString, function: StaticString, line: Int) {
|
||||
DDLogInfo(message, level: toDDLogLevel(.debug), file: file, function: function, line: UInt(line))
|
||||
}
|
||||
|
||||
public func event(_ message: String, file: StaticString, function: StaticString, line: Int) {
|
||||
DDLogInfo(message, level: toDDLogLevel(.debug), file: file, function: function, line: UInt(line))
|
||||
}
|
||||
|
||||
public func warn(_ message: String, file: StaticString, function: StaticString, line: Int) {
|
||||
DDLogWarn(message, level: toDDLogLevel(.debug), file: file, function: function, line: UInt(line))
|
||||
}
|
||||
|
||||
public func error(_ message: String, file: StaticString, function: StaticString, line: Int) {
|
||||
DDLogError(message, level: toDDLogLevel(.debug), file: file, function: function, line: UInt(line))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class LumberjackLogger: ConcreteLogger {
|
||||
|
||||
|
||||
|
||||
init(logDirectory: URL, level: LogLevel, alsoPrint: Bool) {
|
||||
self.level = level
|
||||
let manager = DDLogFileManagerDefault(logsDirectory: logDirectory.path)
|
||||
manager.maximumNumberOfLogFiles = 2
|
||||
|
||||
let l = DDFileLogger(logFileManager: manager)
|
||||
l.maximumFileSize = 1024 * 1024
|
||||
l.rollingFrequency = 60 * 60 * 24 * 7 // weekly rollout
|
||||
DDLog.add(l, with: toDDLogLevel(level))
|
||||
self.fileLogger = l
|
||||
|
||||
if alsoPrint {
|
||||
DDLog.add(DDOSLogger(subsystem: Bundle.main.bundleIdentifier, category: "application logs") , with: toDDLogLevel(level))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var fileLogger: DDFileLogger
|
||||
var level: LogLevel
|
||||
|
||||
|
||||
/**
|
||||
This function does nothing because DDLog uses a Shared instance architecture where everything goes through the DDLog class shared instance.
|
||||
*/
|
||||
func log(level: LogLevel, message: String, file: StaticString, function: StaticString, line: Int) {
|
||||
// This is fine
|
||||
}
|
||||
}
|
||||
@inlinable
|
||||
func levelToDDLogFlag(_ level: LogLevel) -> DDLogFlag {
|
||||
switch level {
|
||||
case .debug:
|
||||
return .debug
|
||||
case .error:
|
||||
return .error
|
||||
case .info:
|
||||
return .info
|
||||
case .event:
|
||||
return .info
|
||||
case .warning:
|
||||
return .warning
|
||||
}
|
||||
}
|
||||
|
||||
@inlinable
|
||||
func toDDLogLevel(_ level: LogLevel) -> DDLogLevel {
|
||||
switch level {
|
||||
case .debug:
|
||||
return .all
|
||||
case .error:
|
||||
return .error
|
||||
case .event:
|
||||
return .info
|
||||
case .info:
|
||||
return .info
|
||||
case .warning:
|
||||
return .warning
|
||||
}
|
||||
}
|
|
@ -4,14 +4,43 @@ import Foundation
|
|||
*/
|
||||
public protocol Logger {
|
||||
|
||||
func debug(_ message: String, file: String, function: String, line: Int)
|
||||
func debug(_ message: String, file: StaticString, function: StaticString, line: Int)
|
||||
|
||||
func info(_ message: String, file: String, function: String, line: Int)
|
||||
func info(_ message: String, file: StaticString, function: StaticString, line: Int)
|
||||
|
||||
func event(_ message: String, file: String, function: String, line: Int)
|
||||
func event(_ message: String, file: StaticString, function: StaticString, line: Int)
|
||||
|
||||
func warn(_ message: String, file: String, function: String, line: Int)
|
||||
func warn(_ message: String, file: StaticString, function: StaticString, line: Int)
|
||||
|
||||
func error(_ message: String, file: String, function: String, line: Int)
|
||||
func error(_ message: String, file: StaticString, function: StaticString, line: Int)
|
||||
|
||||
}
|
||||
|
||||
public enum LogLevel: Int {
|
||||
case debug
|
||||
case error
|
||||
case warning
|
||||
case event
|
||||
case info
|
||||
}
|
||||
|
||||
public enum LoggerType {
|
||||
case osLog(subsystem: String) // prints to OSLog
|
||||
case printerLog // prints to console
|
||||
case fileLogger(logsDirectory: URL, alsoPrint: Bool) // prints logs to files
|
||||
}
|
||||
|
||||
|
||||
public class ZealousLogger {
|
||||
|
||||
public static func logger(_ type: LoggerType, level: LogLevel) -> Logger {
|
||||
switch type {
|
||||
case .fileLogger(let url, let alsoPrint):
|
||||
return DDLogger(concreteLogger: LumberjackLogger(logDirectory: url, level: level, alsoPrint: alsoPrint))
|
||||
case .osLog(let subsystem):
|
||||
return ConsoleLogger(concreteLogger: OsLogLogger(subsystem: subsystem, level: level))
|
||||
case .printerLog:
|
||||
return ConsoleLogger(concreteLogger: PrinterLogger(level: level))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,14 +2,40 @@ import XCTest
|
|||
@testable import zealous_logger
|
||||
|
||||
final class zealous_loggerTests: XCTestCase {
|
||||
func testExample() {
|
||||
func testFileLogger() throws {
|
||||
// This is an example of a functional test case.
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct
|
||||
// results.
|
||||
//XCTAssertEqual(zealous_logger().text, "Hello, World!")
|
||||
XCTAssertNotNil(ZealousLogger.logger(.printerLog, level: .debug) as? ConsoleLogger)
|
||||
|
||||
|
||||
let url = FileManager.default.temporaryDirectory
|
||||
|
||||
let fileLogger = ZealousLogger.logger(.fileLogger(logsDirectory: url, alsoPrint: true), level: .debug)
|
||||
fileLogger.debug("test 123", file: #file, function: #function, line: #line)
|
||||
|
||||
guard let logfile = try FileManager.default.contentsOfDirectory(atPath: url.path).first(where: { $0.contains(Bundle.main.bundleIdentifier!)})
|
||||
else {
|
||||
XCTFail("no logfile found! in \(url)")
|
||||
return
|
||||
}
|
||||
let logfilePath = url.appendingPathComponent(logfile).path
|
||||
let logAttributes = try FileManager.default.attributesOfItem(atPath: logfilePath)
|
||||
|
||||
let firstLogfileSize = logAttributes[FileAttributeKey.size] as! NSNumber
|
||||
|
||||
fileLogger.debug("test 123", file: #file, function: #function, line: #line)
|
||||
|
||||
let logAttributes2 = try FileManager.default.attributesOfItem(atPath: logfilePath)
|
||||
|
||||
let secondLogfileSize = logAttributes2[FileAttributeKey.size] as! NSNumber
|
||||
|
||||
XCTAssertGreaterThan(secondLogfileSize.uint64Value,firstLogfileSize.uint64Value)
|
||||
|
||||
|
||||
}
|
||||
|
||||
static var allTests = [
|
||||
("testExample", testExample),
|
||||
("testFileLogger", testFileLogger),
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
#
|
||||
# Be sure to run `pod lib lint zealous-logger.podspec' to ensure this is a
|
||||
# valid spec before submitting.
|
||||
#
|
||||
# Any lines starting with a # are optional, but their use is encouraged
|
||||
# To learn more about a Podspec see https://guides.cocoapods.org/syntax/podspec.html
|
||||
#
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'zealous-logger'
|
||||
s.version = '1.0.0'
|
||||
s.summary = 'Zealous Logger is a small, simple, discrete but yet enthusiastic logger'
|
||||
|
||||
|
||||
s.description = <<-DESC
|
||||
Zealous Logger is a small, simple, discrete but yet enthusiastic logger. Designed for those who need logs, but not snitches. We acknowledge that Application Logs are needed for troubleshooting and development purposes. That doesn't mean that you should choose between logging and your users' privacy. We believe that Privacy is a Human Right, so logs shouldn't leave your device unless you explicitly want to. We write this small library with that in mind.
|
||||
DESC
|
||||
|
||||
s.homepage = 'https://github.com/zcash-hackworks/zealous-logger'
|
||||
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
s.author = { 'Francisco \'Pacu\' Gindre' => 'francisco.gindre@gmail.com' }
|
||||
s.source = { :git => 'https://github.com/zcash-hackworks/zealous-logger', :tag => s.version.to_s }
|
||||
|
||||
|
||||
s.ios.deployment_target = '12.0'
|
||||
s.osx.deployment_target = '10.12'
|
||||
|
||||
s.source_files = 'Sources/zealous-logger/**/*.{swift}'
|
||||
s.swift_version = '5.1'
|
||||
s.dependency 'CocoaLumberjack/Swift', '~> 3.7.0'
|
||||
s.frameworks = 'OSLog'
|
||||
s.test_spec 'Tests' do | test_spec |
|
||||
test_spec.source_files = 'Tests/zealous-loggerTests/**/*.{swift}'
|
||||
test_spec.dependency 'CocoaLumberjack/Swift', '~> 3.7.0'
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue