Initial implementation

This commit is contained in:
T. R. Bernstein
2026-02-27 22:18:00 +01:00
commit fec4a037db
6 changed files with 161 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.build

15
Package.resolved Normal file
View File

@@ -0,0 +1,15 @@
{
"originHash" : "041d5a9b2664fe8fba9d0ff5826e7f1955cca0b22d288fe2f2383df27258b52a",
"pins" : [
{
"identity" : "swift-log",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-log",
"state" : {
"revision" : "bbd81b6725ae874c69e9b8c8804d462356b55523",
"version" : "1.10.1"
}
}
],
"version" : 3
}

31
Package.swift Normal file
View File

@@ -0,0 +1,31 @@
// swift-tools-version: 6.0
import PackageDescription
let package = Package(
name: "swift-log-oslog",
platforms: [.macOS(.v11), .iOS(.v14), .tvOS(.v14), .watchOS(.v6)],
products: [
.library(
name: "LoggingOSLog",
targets: ["LoggingOSLog"]
)
],
dependencies: [
.package(url: "https://github.com/apple/swift-log", from: "1.10.1"),
],
targets: [
.target(
name: "LoggingOSLog",
dependencies: [.product(name: "Logging", package: "swift-log")],
path: "Sources/Logging OSLog"
),
.testTarget(
name: "LoggingOSLogTests",
dependencies: [
.product(name: "Logging", package: "swift-log"),
"LoggingOSLog"
],
path: "Tests/Logging OSLog Tests",
),
]
)

View File

@@ -0,0 +1,75 @@
import Foundation
import os
import Logging
public struct LoggingOSLog: LogHandler {
public var logLevel: Logging.Logger.Level = .info
public var metadata: Logging.Logger.Metadata = [:]
public var metadataProvider: Logging.Logger.MetadataProvider?
private let oslogger: os.Logger
public init(label: String) {
let lastDotPosition = label.lastIndex(of: ".") ?? label.startIndex
let frontPart = label.prefix(upTo: lastDotPosition)
let backPart = label.suffix(from: lastDotPosition)
guard frontPart.count > 0 else {
let subsystem = Bundle.main.bundleIdentifier ?? "SwiftLogToOsLog"
self.init(subsystem: subsystem, category: label)
return
}
self.init(subsystem: String(frontPart), category: String(backPart))
}
public init(
subsystem: String = Bundle.main.bundleIdentifier ?? "SwiftLogToOsLog",
category: String,
logLevel: Logging.Logger.Level = .debug
) {
self.oslogger = os.Logger(subsystem: subsystem, category: category)
self.logLevel = logLevel
}
public init(oslog: os.Logger, logLevel: Logging.Logger.Level = .debug) {
self.oslogger = oslog
self.logLevel = logLevel
}
public func log(
level: Logging.Logger.Level,
message: Logging.Logger.Message,
metadata: Logging.Logger.Metadata?,
source: String,
file: String,
function: String,
line: UInt
) {
let metadataCSV = Self.joinMetadata(self.metadata, self.metadataProvider?.get(), metadata)
let messageParts = [message.description, metadataCSV]
let message = messageParts.compactMap { $0 }.joined(separator: " -> ")
self.oslogger.log(level: OSLogType.from(loggerLevel: level), "\(message)")
}
public subscript(metadataKey metadataKey: String) -> Logging.Logger.Metadata.Value? {
get {
return self.metadata[metadataKey]
}
set {
self.metadata[metadataKey] = newValue
}
}
private static func joinMetadata(_ metadataList: Logging.Logger.Metadata?...) -> String? {
var metadataAggregator: Logging.Logger.Metadata = [:]
for metadata in metadataList {
guard let metadata = metadata else { continue }
metadataAggregator.merge(metadata) { return $1 }
}
return Self.joinMetadata(metadataAggregator)
}
private static func joinMetadata(_ metadata: Logging.Logger.Metadata, with separator: String = ", ") -> String? {
guard !metadata.isEmpty else { return nil }
return metadata.map { "\($0) = \($1)" }.joined(separator: separator)
}
}

View File

@@ -0,0 +1,23 @@
import Logging
import os
extension OSLogType {
static func from(loggerLevel: Logging.Logger.Level) -> Self {
switch loggerLevel {
case .trace:
return .debug
case .debug:
return .debug
case .info:
return .info
case .notice:
return .default
case .warning:
return .info
case .error:
return .error
case .critical:
return .fault
}
}
}

View File

@@ -0,0 +1,16 @@
import Testing
import Logging
import LoggingOSLog
@Test func isConstructable() {
let _ = LoggingOSLog(subsystem: "de.astzweig.app", category: "Image Processing")
}
@Test func canAddAsLoggingBackend() {
LoggingSystem.bootstrap(LoggingOSLog.init)
}
@Test func canLogMessage() {
let logger = Logging.Logger(label: "de.astzweig.loggingoslog.Test")
logger.info("Test message")
}