Skip to content

Instantly share code, notes, and snippets.

@elland
Last active September 16, 2025 13:14
Show Gist options
  • Select an option

  • Save elland/b45430c8daa5e8a85b1b4643f2f51ecc to your computer and use it in GitHub Desktop.

Select an option

Save elland/b45430c8daa5e8a85b1b4643f2f51ecc to your computer and use it in GitHub Desktop.
import Foundation
import Logging
final public class NushuLogger {
private static let shared = NushuLogger()
private let loggingURL = FileManager.default
.urls(for: .documentDirectory, in: .userDomainMask).first!
.appendingPathComponent("default.log")
private let logger: Logger
private init() {
self.logger = try! FileLogging.logger(label: "com.NushuiOS", localFile: self.loggingURL)
}
// MARK: - Interface
static func debug(_ msg: Logger.Message) {
self.shared.logger.debug(msg)
}
static func error(_ msg: Logger.Message) {
self.shared.logger.error(msg)
}
}
public struct FileLogging {
let stream: TextOutputStream
public init(to localFile: URL) throws {
self.stream = try FileHandlerOutputStream(localFile: localFile)
}
public static func logger(label: String, localFile url: URL) throws -> Logger {
let logging = try Self(to: url)
return Logger(label: label, factory: { label in
FileLogHandler(label: label, stream: logging.stream)
})
}
}
public struct FileLogHandler: LogHandler {
public var metadata: Logging.Logger.Metadata = Logger.Metadata()
public var logLevel: Logging.Logger.Level = .info
private let stream: TextOutputStream
private var label: String
public subscript(metadataKey metadataKey: String) -> Logger.Metadata.Value? {
get {
return self.metadata[metadataKey]
}
set {
self.metadata[metadataKey] = newValue
}
}
public func timestamp() -> String {
ISO8601DateFormatter().string(from: Date())
}
public init(label: String, stream: TextOutputStream) {
self.label = label
self.stream = stream
}
public func log(
level: Logger.Level,
message: Logger.Message,
metadata: Logger.Metadata?,
source: String,
file: String,
function: String,
line: UInt
) {
let meta = metadata?.map { "\($0)=\($1)" }.joined(separator: " ") ?? ""
var stream = self.stream
stream.write("\(self.timestamp()) \(level) \(self.label) :\(meta) \(message)\n")
}
}
struct FileHandlerOutputStream: TextOutputStream {
enum Error: Swift.Error {
case couldNotCreateFile
}
private let fileHandle: FileHandle
init(localFile url: URL) throws {
if !FileManager.default.fileExists(atPath: url.path) {
guard FileManager.default.createFile(atPath: url.path, contents: nil, attributes: nil) else {
throw Error.couldNotCreateFile
}
}
let fileHandle = try FileHandle(forWritingTo: url)
fileHandle.seekToEndOfFile()
self.fileHandle = fileHandle
}
mutating func write(_ string: String) {
if let data = string.data(using: .utf8) {
self.fileHandle.write(data)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment