SwiftLogger/Logger/Logger.swift

132 lines
6 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// MIT License
//
// Copyright (c) 2018 Wojciech Nagrodzki
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
/// A type able to build custom log message and send it to a logging system.
public protocol Logger {
/// Builds log a message from passed parameters and sends it to the logging system.
///
/// Do not call this method directly.
///
/// - Parameters:
/// - time: Part of the log message provided by `description(for date: Date)` method.
/// - level: The log level.
/// - location: Part of the log message provided by `description(for file: String, line: Int, function: String)` method.
/// - object: Part of the log message provided by `description(for object: Any)` method.
func log(time: String, level: LogLevel, location: String, object: String)
/// Transforms `date` into textual representation which will be a part of the log message.
///
/// Customization point. Default implementation returns date in format `"yyyy-MM-dd HH:mm:ss.SSS"`.
///
/// - Parameter date: The date log method was called.
func description(for date: Date) -> String
/// Transforms passed parameters into location textual representation which will be a part of the log message.
///
/// Customization point. Default implementation returns location in format `"<file name>:<line> <function>"`,
///
/// - Parameters:
/// - file: The path to the file log method was called from.
/// - line: The line number log method was called at.
/// - function: The name of the declaration log method was called within.
func description(for file: String, line: Int, function: String) -> String
/// Transforms `object` into textual representation which will be a part of the log message.
///
/// Customization point. Default implementation returns `logDescription` for objects implementing `LogStringConvertible`,
/// or `String(describing:object)` otherwise.
///
/// - Parameter object: The object to be logged.
func description(for object: Any) -> String
}
/// Log level controls the conditions under which a message should be logged.
public enum LogLevel: String {
/// Use this level to capture information about things that might result a failure.
case `default` = "Default"
/// Use this level to capture information that may be helpful, but isnt essential, for troubleshooting errors.
case info = "Info"
/// Use this level to capture information that may be useful during development or while troubleshooting a specific problem.
case debug = "Debug"
/// Use this log level to capture process-level information to report errors in the process.
case error = "Error"
/// Use this level to capture system-level or multi-process information to report system errors.
case fault = "Fault"
}
extension Logger {
/// Sends object to the logging system, optionally specifying a custom log level.
///
/// - Parameters:
/// - object: The object to be logged.
/// - level: The log level. If unspecified, the `default` log level is used.
/// - file: **Do not provide a custom value.** The path to the file log method is called from.
/// - line: **Do not provide a custom value.** The line number log method is called at.
/// - function: **Do not provide a custom value.** The name of the declaration log method is called within.
public func log(_ object: Any, level: LogLevel = .default, file: String = #file, line: Int = #line, function: String = #function) {
let now = Date()
let time = description(for: now)
let location = description(for: file, line: line, function: function)
let objectDescription = description(for: object)
log(time: time, level: level, location: location, object: objectDescription)
}
/// Returns date in format `"yyyy-MM-dd HH:mm:ss.SSS"`.
public func description(for date: Date) -> String {
return dateFormatter.string(from: date)
}
/// Returns location in format `"<file name>:<line> <function>"`.
public func description(for file: String, line: Int, function: String) -> String {
return filename(fromFilePath: file) + ":\(line) \(function)"
}
/// Returns `logDescription` for objects implementing `LogStringConvertible`, or `String(describing:object)` otherwise.
public func description(for object: Any) -> String {
if let logStringConvertible = object as? LogStringConvertible {
return logStringConvertible.logDescription
}
return String(describing: object)
}
private func filename(fromFilePath path: String) -> String {
return URL(fileURLWithPath: path).deletingPathExtension().lastPathComponent
}
}
private let dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
formatter.timeZone = TimeZone(secondsFromGMT: 0)
return formatter
}()