Address logging issues (#304)
* Make specific message levels a default extension * Define Loggable protocol * Keep track of message originator metadata * Fix tracing of Core Data logs * Log query on entity not found
This commit is contained in:
parent
7ccb10febc
commit
efcda495bc
|
@ -42,15 +42,33 @@ public protocol Logger {
|
|||
|
||||
var logLevel: LoggerLevel { get set }
|
||||
|
||||
func verbose(_ message: Any)
|
||||
func logMessage(_ level: LoggerLevel, _ message: Any, _ file: String, _ function: String, _ line: Int)
|
||||
}
|
||||
|
||||
func debug(_ message: Any)
|
||||
extension Logger {
|
||||
public func verbose(_ message: Any, _ file: String = #file, _ function: String = #function, _ line: Int = #line) {
|
||||
logMessage(.verbose, message, file, function, line)
|
||||
}
|
||||
|
||||
func info(_ message: Any)
|
||||
public func debug(_ message: Any, _ file: String = #file, _ function: String = #function, _ line: Int = #line) {
|
||||
logMessage(.debug, message, file, function, line)
|
||||
}
|
||||
|
||||
func warning(_ message: Any)
|
||||
public func info(_ message: Any, _ file: String = #file, _ function: String = #function, _ line: Int = #line) {
|
||||
logMessage(.info, message, file, function, line)
|
||||
}
|
||||
|
||||
func error(_ message: Any)
|
||||
public func warning(_ message: Any, _ file: String = #file, _ function: String = #function, _ line: Int = #line) {
|
||||
logMessage(.warning, message, file, function, line)
|
||||
}
|
||||
|
||||
public func error(_ message: Any, _ file: String = #file, _ function: String = #function, _ line: Int = #line) {
|
||||
logMessage(.error, message, file, function, line)
|
||||
}
|
||||
}
|
||||
|
||||
public protocol Loggable {
|
||||
var logDescription: String { get }
|
||||
}
|
||||
|
||||
final class DefaultLogger: Logger {
|
||||
|
@ -58,42 +76,10 @@ final class DefaultLogger: Logger {
|
|||
|
||||
var logLevel: LoggerLevel = .debug
|
||||
|
||||
func verbose(_ message: Any) {
|
||||
guard logLevel.rawValue >= LoggerLevel.verbose.rawValue else {
|
||||
func logMessage(_ level: LoggerLevel, _ message: Any, _ file: String, _ function: String, _ line: Int) {
|
||||
guard level.rawValue >= logLevel.rawValue else {
|
||||
return
|
||||
}
|
||||
logMessage(message)
|
||||
}
|
||||
|
||||
func debug(_ message: Any) {
|
||||
guard logLevel.rawValue >= LoggerLevel.debug.rawValue else {
|
||||
return
|
||||
}
|
||||
logMessage(message)
|
||||
}
|
||||
|
||||
func info(_ message: Any) {
|
||||
guard logLevel.rawValue >= LoggerLevel.info.rawValue else {
|
||||
return
|
||||
}
|
||||
logMessage(message)
|
||||
}
|
||||
|
||||
func warning(_ message: Any) {
|
||||
guard logLevel.rawValue >= LoggerLevel.warning.rawValue else {
|
||||
return
|
||||
}
|
||||
logMessage(message)
|
||||
}
|
||||
|
||||
func error(_ message: Any) {
|
||||
guard logLevel.rawValue >= LoggerLevel.error.rawValue else {
|
||||
return
|
||||
}
|
||||
logMessage(message)
|
||||
}
|
||||
|
||||
private func logMessage(_ message: Any) {
|
||||
guard let string = message as? String else {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -25,23 +25,32 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
// XXX: these should be aliases like #define to print original caller line
|
||||
extension Utils {
|
||||
public static func assertCoreDataDecodingFailed(
|
||||
_ file: String,
|
||||
_ function: String,
|
||||
_ line: Int,
|
||||
_ message: String? = nil
|
||||
_ message: String? = nil,
|
||||
_ file: String = #file,
|
||||
_ function: String = #function,
|
||||
_ line: Int = #line
|
||||
) {
|
||||
// assertionFailure(message ?? "Cannot decode entity required fields - \(file):\(function):\(line)")
|
||||
pp_log.warning(message ?? "Cannot decode entity required fields - \(file):\(function):\(line)")
|
||||
// assertionFailure(message ?? "Cannot decode entity required fields", file, function, line)
|
||||
pp_log.warning(message ?? "Cannot decode entity required fields", file, function, line)
|
||||
}
|
||||
|
||||
public static func logFetchError(_ file: String, _ function: String, _ line: Int, _ error: Error) {
|
||||
pp_log.error("Unable to fetch: \(error) - \(file):\(function):\(line)")
|
||||
public static func logFetchError(
|
||||
_ error: Error,
|
||||
_ file: String = #file,
|
||||
_ function: String = #function,
|
||||
_ line: Int = #line
|
||||
) {
|
||||
pp_log.error("Unable to fetch: \(error)", file, function, line)
|
||||
}
|
||||
|
||||
public static func logFetchNotFound(_ file: String, _ function: String, _ line: Int) {
|
||||
pp_log.debug("Not found - \(file):\(function):\(line)")
|
||||
public static func logFetchNotFound(
|
||||
_ query: String,
|
||||
_ file: String = #file,
|
||||
_ function: String = #function,
|
||||
_ line: Int = #line
|
||||
) {
|
||||
pp_log.debug("Entity not found: (\(query))", file, function, line)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Domain+Logging.swift
|
||||
// Domain+Loggable.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 4/7/22.
|
||||
|
@ -24,8 +24,9 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import PassepartoutCore
|
||||
|
||||
extension ProviderServer {
|
||||
extension ProviderServer: Loggable {
|
||||
public var logDescription: String {
|
||||
"{'\(categoryName)', \(countryCode), '\(apiId)', \(id)}"
|
||||
}
|
|
@ -39,12 +39,12 @@ extension CDLocalProvidersRepository: InfrastructureRepository {
|
|||
]
|
||||
do {
|
||||
guard let infrastructureDTO = try context.fetch(request).first else {
|
||||
Utils.logFetchNotFound(#file, #function, #line)
|
||||
Utils.logFetchNotFound("\(name), \(vpnProtocol)")
|
||||
return nil
|
||||
}
|
||||
return infrastructureDTO.defaults?.usernamePlaceholder
|
||||
} catch {
|
||||
Utils.logFetchError(#file, #function, #line, error)
|
||||
Utils.logFetchError(error)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -61,14 +61,14 @@ extension CDLocalProvidersRepository: InfrastructureRepository {
|
|||
do {
|
||||
let infrastructures = try context.fetch(request)
|
||||
guard !infrastructures.isEmpty else {
|
||||
Utils.logFetchNotFound(#file, #function, #line)
|
||||
Utils.logFetchNotFound("\(name), \(vpnProtocol)")
|
||||
return nil
|
||||
}
|
||||
let recent = infrastructures.first!
|
||||
return recent.lastUpdate
|
||||
} catch {
|
||||
context.rollback()
|
||||
Utils.logFetchError(#file, #function, #line, error)
|
||||
Utils.logFetchError(error)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ extension CDLocalProvidersRepository: ProviderRepository {
|
|||
}
|
||||
return providers.compactMap(ProviderMapper.toModel)
|
||||
} catch {
|
||||
Utils.logFetchError(#file, #function, #line, error)
|
||||
Utils.logFetchError(error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
@ -62,13 +62,13 @@ extension CDLocalProvidersRepository: ProviderRepository {
|
|||
do {
|
||||
let providers = try context.fetch(request)
|
||||
guard !providers.isEmpty else {
|
||||
Utils.logFetchNotFound(#file, #function, #line)
|
||||
Utils.logFetchNotFound(name)
|
||||
return nil
|
||||
}
|
||||
let recent = providers.first!
|
||||
return ProviderMapper.toModel(recent)
|
||||
} catch {
|
||||
Utils.logFetchError(#file, #function, #line, error)
|
||||
Utils.logFetchError(error)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ extension CDLocalProvidersRepository: ServerRepository {
|
|||
let categoryDTOs = try context.fetch(request)
|
||||
return categoryDTOs.compactMap(CategoryMapper.toModel)
|
||||
} catch {
|
||||
Utils.logFetchError(#file, #function, #line, error)
|
||||
Utils.logFetchError(error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ extension CDLocalProvidersRepository: ServerRepository {
|
|||
// just preset ids, no full ProviderServer.Preset
|
||||
return serverDTOs.compactMap(ServerMapper.toModel)
|
||||
} catch {
|
||||
Utils.logFetchError(#file, #function, #line, error)
|
||||
Utils.logFetchError(error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
@ -94,12 +94,12 @@ extension CDLocalProvidersRepository: ServerRepository {
|
|||
]
|
||||
do {
|
||||
guard let serverDTO = try context.fetch(request).first else {
|
||||
Utils.logFetchNotFound(#file, #function, #line)
|
||||
Utils.logFetchNotFound("\(providerName), \(vpnProtocol), \(apiId)")
|
||||
return nil
|
||||
}
|
||||
return ServerMapper.toModelWithPresets(serverDTO)
|
||||
} catch {
|
||||
Utils.logFetchError(#file, #function, #line, error)
|
||||
Utils.logFetchError(error)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -121,12 +121,12 @@ extension CDLocalProvidersRepository: ServerRepository {
|
|||
do {
|
||||
try Utils.randomizeFetchResults(request, in: context)
|
||||
guard let serverDTO = try context.fetch(request).first else {
|
||||
Utils.logFetchNotFound(#file, #function, #line)
|
||||
Utils.logFetchNotFound("\(providerName), \(vpnProtocol), \(countryCode)")
|
||||
return nil
|
||||
}
|
||||
return ServerMapper.toModelWithPresets(serverDTO)
|
||||
} catch {
|
||||
Utils.logFetchError(#file, #function, #line, error)
|
||||
Utils.logFetchError(error)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -148,12 +148,12 @@ extension CDLocalProvidersRepository: ServerRepository {
|
|||
do {
|
||||
try Utils.randomizeFetchResults(request, in: context)
|
||||
guard let serverDTO = try context.fetch(request).first else {
|
||||
Utils.logFetchNotFound(#file, #function, #line)
|
||||
Utils.logFetchNotFound("\(providerName), \(vpnProtocol)")
|
||||
return nil
|
||||
}
|
||||
return ServerMapper.toModelWithPresets(serverDTO)
|
||||
} catch {
|
||||
Utils.logFetchError(#file, #function, #line, error)
|
||||
Utils.logFetchError(error)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -171,12 +171,12 @@ extension CDLocalProvidersRepository: ServerRepository {
|
|||
]
|
||||
do {
|
||||
guard let serverDTO = try context.fetch(request).first else {
|
||||
Utils.logFetchNotFound(#file, #function, #line)
|
||||
Utils.logFetchNotFound(id)
|
||||
return nil
|
||||
}
|
||||
return ServerMapper.toModelWithPresets(serverDTO)
|
||||
} catch {
|
||||
Utils.logFetchError(#file, #function, #line, error)
|
||||
Utils.logFetchError(error)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ struct CategoryMapper: DTOMapper, ModelMapper {
|
|||
let name = dto.name,
|
||||
let locations = dto.locations else {
|
||||
|
||||
Utils.assertCoreDataDecodingFailed(#file, #function, #line)
|
||||
Utils.assertCoreDataDecodingFailed()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ struct InfrastructureMapper: DTOMapper {
|
|||
vpnProtocol: vpnProtocol,
|
||||
apiId: apiId
|
||||
) else {
|
||||
Utils.assertCoreDataDecodingFailed(#file, #function, #line)
|
||||
Utils.assertCoreDataDecodingFailed()
|
||||
return
|
||||
}
|
||||
server.uniqueId = uniqueId
|
||||
|
|
|
@ -58,7 +58,7 @@ struct LocationMapper: DTOMapper, ModelMapper {
|
|||
let categoryName = dto.category?.name,
|
||||
let countryCode = dto.countryCode else {
|
||||
|
||||
Utils.assertCoreDataDecodingFailed(#file, #function, #line)
|
||||
Utils.assertCoreDataDecodingFailed()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ struct PresetMapper: DTOMapper, ModelMapper {
|
|||
let vpnProtocol = VPNProtocolType(rawValue: vpnProtocolString),
|
||||
let vpnConfiguration = dto.decodedConfiguration else {
|
||||
|
||||
Utils.assertCoreDataDecodingFailed(#file, #function, #line)
|
||||
Utils.assertCoreDataDecodingFailed()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ struct ProviderMapper: DTOMapper, ModelMapper {
|
|||
guard let name = dto.name,
|
||||
let fullName = dto.fullName else {
|
||||
|
||||
Utils.assertCoreDataDecodingFailed(#file, #function, #line)
|
||||
Utils.assertCoreDataDecodingFailed()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -73,14 +73,11 @@ struct ServerMapper: DTOMapper, ModelMapper {
|
|||
let providerMetadata = ProviderMapper.toModel(providerDTO),
|
||||
let countryCode = dto.countryCode else {
|
||||
|
||||
Utils.assertCoreDataDecodingFailed(#file, #function, #line)
|
||||
Utils.assertCoreDataDecodingFailed()
|
||||
return nil
|
||||
}
|
||||
guard let presetDTOs = categoryDTO.presets?.allObjects as? [CDInfrastructurePreset], !presetDTOs.isEmpty else {
|
||||
Utils.assertCoreDataDecodingFailed(
|
||||
#file, #function, #line,
|
||||
"Category '\(categoryName)' of server \(apiId) has no presets"
|
||||
)
|
||||
Utils.assertCoreDataDecodingFailed("Category '\(categoryName)' of server \(apiId) has no presets")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -109,14 +106,11 @@ struct ServerMapper: DTOMapper, ModelMapper {
|
|||
let categoryDTO = dto.category,
|
||||
let categoryName = categoryDTO.name else {
|
||||
|
||||
Utils.assertCoreDataDecodingFailed(#file, #function, #line)
|
||||
Utils.assertCoreDataDecodingFailed()
|
||||
return nil
|
||||
}
|
||||
guard let presetDTOs = dto.category?.presets?.allObjects as? [CDInfrastructurePreset], !presetDTOs.isEmpty else {
|
||||
Utils.assertCoreDataDecodingFailed(
|
||||
#file, #function, #line,
|
||||
"Category '\(categoryName)' has no presets"
|
||||
)
|
||||
Utils.assertCoreDataDecodingFailed("Category '\(categoryName)' has no presets")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Domain+Logging.swift
|
||||
// Domain+Loggable.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 4/7/22.
|
||||
|
@ -24,14 +24,15 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import PassepartoutCore
|
||||
|
||||
extension Profile.Header {
|
||||
extension Profile.Header: Loggable {
|
||||
public var logDescription: String {
|
||||
"{\(id), '\(name)'}"
|
||||
}
|
||||
}
|
||||
|
||||
extension Profile {
|
||||
extension Profile: Loggable {
|
||||
public var logDescription: String {
|
||||
header.logDescription
|
||||
}
|
|
@ -48,7 +48,7 @@ struct ProfileMapper: DTOMapper, ModelMapper {
|
|||
|
||||
static func toModel(_ dto: CDProfile) throws -> Profile? {
|
||||
guard let json = dto.json else {
|
||||
Utils.assertCoreDataDecodingFailed(#file, #function, #line)
|
||||
Utils.assertCoreDataDecodingFailed()
|
||||
return nil
|
||||
}
|
||||
do {
|
||||
|
@ -80,7 +80,7 @@ struct ProfileHeaderMapper: DTOMapper, ModelMapper {
|
|||
guard let uuid = dto.uuid,
|
||||
let name = dto.name else {
|
||||
|
||||
Utils.assertCoreDataDecodingFailed(#file, #function, #line)
|
||||
Utils.assertCoreDataDecodingFailed()
|
||||
return nil
|
||||
}
|
||||
return Profile.Header(
|
||||
|
|
|
@ -32,8 +32,9 @@ public final class SwiftyBeaverLogger: Logger {
|
|||
|
||||
public var logLevel: LoggerLevel {
|
||||
didSet {
|
||||
let nativeLevel = logLevel.toSwiftyBeaver
|
||||
SwiftyBeaver.destinations.forEach {
|
||||
$0.minLevel = logLevel.toSwiftyBeaver
|
||||
$0.minLevel = nativeLevel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,24 +63,8 @@ public final class SwiftyBeaverLogger: Logger {
|
|||
}
|
||||
}
|
||||
|
||||
public func verbose(_ message: Any) {
|
||||
SwiftyBeaver.verbose(message)
|
||||
}
|
||||
|
||||
public func debug(_ message: Any) {
|
||||
SwiftyBeaver.debug(message)
|
||||
}
|
||||
|
||||
public func info(_ message: Any) {
|
||||
SwiftyBeaver.info(message)
|
||||
}
|
||||
|
||||
public func warning(_ message: Any) {
|
||||
SwiftyBeaver.warning(message)
|
||||
}
|
||||
|
||||
public func error(_ message: Any) {
|
||||
SwiftyBeaver.error(message)
|
||||
public func logMessage(_ level: LoggerLevel, _ message: Any, _ file: String, _ function: String, _ line: Int) {
|
||||
SwiftyBeaver.custom(level: level.toSwiftyBeaver, message: message, file: file, function: function, line: line)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue