mirror of
https://github.com/CocoaLumberjack/CocoaLumberjack.git
synced 2026-06-06 20:18:32 +00:00
222 lines
10 KiB
Swift
222 lines
10 KiB
Swift
// Software License Agreement (BSD License)
|
|
//
|
|
// Copyright (c) 2010-2025, Deusty, LLC
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use of this software in source and binary forms,
|
|
// with or without modification, are permitted provided that the following conditions are met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright notice,
|
|
// this list of conditions and the following disclaimer.
|
|
//
|
|
// * Neither the name of Deusty nor the names of its contributors may be used
|
|
// to endorse or promote products derived from this software without specific
|
|
// prior written permission of Deusty, LLC.
|
|
|
|
public import CocoaLumberjack
|
|
public import Logging
|
|
|
|
/// A swift-log ``LogHandler`` implementation that forwards messages to a given ``DDLog`` instance.
|
|
public struct DDLogHandler: LogHandler {
|
|
@usableFromInline
|
|
struct Configuration: Sendable {
|
|
@usableFromInline
|
|
struct SyncLogging: Sendable {
|
|
@usableFromInline
|
|
let tresholdLevel: Logging.Logger.Level
|
|
@usableFromInline
|
|
let metadataKey: Logging.Logger.Metadata.Key
|
|
}
|
|
|
|
@usableFromInline
|
|
let log: DDLog
|
|
@usableFromInline
|
|
let syncLogging: SyncLogging
|
|
}
|
|
|
|
@usableFromInline
|
|
struct LoggerInfo: Sendable {
|
|
@usableFromInline
|
|
struct MetadataSources: Sendable {
|
|
@usableFromInline
|
|
var provider: Logging.Logger.MetadataProvider?
|
|
@usableFromInline
|
|
var logger: Logging.Logger.Metadata = [:]
|
|
}
|
|
|
|
@usableFromInline
|
|
let label: String
|
|
@usableFromInline
|
|
var logLevel: Logging.Logger.Level
|
|
@usableFromInline
|
|
var metadataSources: MetadataSources
|
|
|
|
// Not removed due to `@usableFromInline`
|
|
@usableFromInline
|
|
@available(*, deprecated, renamed: "metadataSources.logger")
|
|
var metadata: Logging.Logger.Metadata {
|
|
get { metadataSources.logger }
|
|
set { metadataSources.logger = newValue }
|
|
}
|
|
}
|
|
|
|
@usableFromInline
|
|
let config: Configuration
|
|
@usableFromInline
|
|
var loggerInfo: LoggerInfo
|
|
|
|
@inlinable
|
|
public var logLevel: Logging.Logger.Level {
|
|
get { loggerInfo.logLevel }
|
|
set { loggerInfo.logLevel = newValue }
|
|
}
|
|
@inlinable
|
|
public var metadataProvider: Logging.Logger.MetadataProvider? {
|
|
get { loggerInfo.metadataSources.provider }
|
|
set { loggerInfo.metadataSources.provider = newValue }
|
|
}
|
|
@inlinable
|
|
public var metadata: Logging.Logger.Metadata {
|
|
get { loggerInfo.metadataSources.logger }
|
|
set { loggerInfo.metadataSources.logger = newValue }
|
|
}
|
|
|
|
@inlinable
|
|
public subscript(metadataKey metadataKey: String) -> Logging.Logger.Metadata.Value? {
|
|
get { metadata[metadataKey] }
|
|
set { metadata[metadataKey] = newValue }
|
|
}
|
|
|
|
private init(config: Configuration, loggerInfo: LoggerInfo) {
|
|
self.config = config
|
|
self.loggerInfo = loggerInfo
|
|
}
|
|
|
|
/// Returns whether a message with the given level and the given metadata should be logged asynchronous.
|
|
/// - Parameters:
|
|
/// - level: The level at which the message was logged.
|
|
/// - metadata: The metadata associated with the message.
|
|
/// - Returns: Whether to log the message asynchronous.
|
|
@usableFromInline
|
|
func _logAsync(level: Logging.Logger.Level, metadata: Logging.Logger.Metadata?) -> Bool {
|
|
if level >= config.syncLogging.tresholdLevel {
|
|
// Easiest check -> level is above treshold. Not async.
|
|
return false
|
|
} else if case .stringConvertible(let logSynchronous as Bool) = metadata?[config.syncLogging.metadataKey] {
|
|
// There's a metadata value, return it's value. We need to invert it since it defines whether to log _synchronous_.
|
|
return !logSynchronous
|
|
} else {
|
|
// If we're below the treshold and no metadata value is set -> we're logging async.
|
|
return true
|
|
}
|
|
}
|
|
|
|
@inlinable
|
|
public func log(level: Logging.Logger.Level,
|
|
message: Logging.Logger.Message,
|
|
metadata: Logging.Logger.Metadata?,
|
|
source: String,
|
|
file: String,
|
|
function: String,
|
|
line: UInt) {
|
|
let slMessage = SwiftLogMessage(loggerLabel: loggerInfo.label,
|
|
loggerMetadata: loggerInfo.metadataSources.logger,
|
|
loggerProvidedMetadata: loggerInfo.metadataSources.provider?.get(),
|
|
message: message,
|
|
level: level,
|
|
metadata: metadata,
|
|
source: source,
|
|
file: file,
|
|
function: function,
|
|
line: line)
|
|
config.log.log(asynchronous: _logAsync(level: level, metadata: metadata), message: slMessage)
|
|
}
|
|
}
|
|
|
|
/// A typealias for the "old" log handler factory.
|
|
@preconcurrency
|
|
public typealias OldLogHandlerFactory = @Sendable (String) -> any LogHandler
|
|
/// A typealias for the log handler factory.
|
|
@preconcurrency
|
|
public typealias LogHandlerFactory = @Sendable (String, Logging.Logger.MetadataProvider?) -> any LogHandler
|
|
|
|
extension DDLogHandler {
|
|
/// The default key to control per message whether to log it synchronous or asynchronous.
|
|
public static var defaultSynchronousLoggingMetadataKey: Logging.Logger.Metadata.Key {
|
|
"log-synchronous"
|
|
}
|
|
|
|
/// Creates a new ``LogHandler`` factory using ``DDLogHandler`` with the given parameters.
|
|
/// - Parameters:
|
|
/// - log: The ``DDLog`` instance to use for logging. Defaults to ``DDLog/sharedInstance``.
|
|
/// - defaultLogLevel: The default log level for new loggers. Defaults to ``Logging/Logger/Level/info``.
|
|
/// - syncLoggingTreshold: The level as of which log messages should be logged synchronously instead of asynchronously. Defaults to ``Logging/Logger/Level/error``.
|
|
/// - synchronousLoggingMetadataKey: The metadata key to check on messages to decide whether to log synchronous or asynchronous. Defaults to ``DDLogHandler/defaultSynchronousLoggingMetadataKey``.
|
|
/// - Returns: A new ``LogHandler`` factory using ``DDLogHandler`` that can be passed to ``LoggingSystem/bootstrap``.
|
|
/// - SeeAlso: ``DDLog``, ``LoggingSystem/boostrap``
|
|
public static func handlerFactory(
|
|
for log: DDLog = .sharedInstance,
|
|
defaultLogLevel: Logging.Logger.Level = .info,
|
|
loggingSynchronousAsOf syncLoggingTreshold: Logging.Logger.Level = .error,
|
|
synchronousLoggingMetadataKey: Logging.Logger.Metadata.Key = DDLogHandler.defaultSynchronousLoggingMetadataKey
|
|
) -> LogHandlerFactory {
|
|
let config = DDLogHandler.Configuration(
|
|
log: log,
|
|
syncLogging: .init(tresholdLevel: syncLoggingTreshold,
|
|
metadataKey: synchronousLoggingMetadataKey)
|
|
)
|
|
return {
|
|
DDLogHandler(config: config, loggerInfo: .init(label: $0, logLevel: defaultLogLevel, metadataSources: .init(provider: $1)))
|
|
}
|
|
}
|
|
|
|
/// Creates a new ``LogHandler`` factory using ``DDLogHandler`` with the given parameters.
|
|
/// - Parameters:
|
|
/// - log: The ``DDLog`` instance to use for logging. Defaults to ``DDLog/sharedInstance``.
|
|
/// - defaultLogLevel: The default log level for new loggers. Defaults to ``Logging/Logger/Level/info``.
|
|
/// - syncLoggingTreshold: The level as of which log messages should be logged synchronously instead of asynchronously. Defaults to ``Logging/Logger/Level/error``.
|
|
/// - synchronousLoggingMetadataKey: The metadata key to check on messages to decide whether to log synchronous or asynchronous. Defaults to ``DDLogHandler/defaultSynchronousLoggingMetadataKey``.
|
|
/// - Returns: A new ``LogHandler`` factory using ``DDLogHandler`` that can be passed to ``LoggingSystem/bootstrap``.
|
|
/// - SeeAlso: ``DDLog``, ``LoggingSystem/boostrap``
|
|
@inlinable
|
|
public static func handlerFactory(
|
|
for log: DDLog = .sharedInstance,
|
|
defaultLogLevel: Logging.Logger.Level = .info,
|
|
loggingSynchronousAsOf syncLoggingTreshold: Logging.Logger.Level = .error,
|
|
synchronousLoggingMetadataKey: Logging.Logger.Metadata.Key = DDLogHandler.defaultSynchronousLoggingMetadataKey
|
|
) -> OldLogHandlerFactory {
|
|
let factory: LogHandlerFactory = handlerFactory(
|
|
for: log,
|
|
defaultLogLevel: defaultLogLevel,
|
|
loggingSynchronousAsOf: syncLoggingTreshold,
|
|
synchronousLoggingMetadataKey: synchronousLoggingMetadataKey
|
|
)
|
|
return { factory($0, nil) }
|
|
}
|
|
}
|
|
|
|
extension LoggingSystem {
|
|
/// Bootraps the logging system with a new ``LogHandler`` factory using ``DDLogHandler``.
|
|
/// - Parameters:
|
|
/// - log: The ``DDLog`` instance to use for logging. Defaults to ``DDLog/sharedInstance``.
|
|
/// - defaultLogLevel: The default log level for new loggers. Defaults to ``Logging/Logger/Level/info``.
|
|
/// - syncLoggingTreshold: The level as of which log messages should be logged synchronously instead of asynchronously. Defaults to ``Logging/Logger/Level/error``.
|
|
/// - synchronousLoggingMetadataKey: The metadata key to check on messages to decide whether to log synchronous or asynchronous. Defaults to ``DDLogHandler/defaultSynchronousLoggingMetadataKey``.
|
|
/// - metadataProvider: The (global) metadata provider to use with the setup. Defaults to `nil`.
|
|
/// - SeeAlso: ``DDLogHandler/handlerFactory``, ``LoggingSystem/bootstrap``
|
|
@inlinable
|
|
public static func bootstrapWithCocoaLumberjack(
|
|
for log: DDLog = .sharedInstance,
|
|
defaultLogLevel: Logging.Logger.Level = .info,
|
|
loggingSynchronousAsOf syncLoggingTreshold: Logging.Logger.Level = .error,
|
|
synchronousLoggingMetadataKey: Logging.Logger.Metadata.Key = DDLogHandler.defaultSynchronousLoggingMetadataKey,
|
|
metadataProvider: Logging.Logger.MetadataProvider? = nil
|
|
) {
|
|
bootstrap(DDLogHandler.handlerFactory(for: log,
|
|
defaultLogLevel: defaultLogLevel,
|
|
loggingSynchronousAsOf: syncLoggingTreshold,
|
|
synchronousLoggingMetadataKey: synchronousLoggingMetadataKey),
|
|
metadataProvider: metadataProvider)
|
|
}
|
|
}
|