Files
allsochen 79f99bd4f1 feat: major rehaul of the preferences!
closes #351

BREAKING CHANGE: The old preferences panel has been replaced with a brand new one

Preferences are now much simpler, full of visual illustrations, and should provide a much better experience. Pick between 3 styles (thumbnails, app-icons, titles), sizes, dark/light themes, high visibility options, and more!
2024-10-10 11:19:39 +02:00

170 lines
6.2 KiB
Swift

//
// FileDestination.swift
// SwiftyBeaver
//
// Created by Sebastian Kreutzberger on 05.12.15.
// Copyright © 2015 Sebastian Kreutzberger
// Some rights reserved: http://opensource.org/licenses/MIT
//
import Foundation
public class FileDestination: BaseDestination {
public var logFileURL: URL?
public var syncAfterEachWrite: Bool = false
public var colored: Bool = false {
didSet {
if colored {
// bash font color, first value is intensity, second is color
// see http://bit.ly/1Otu3Zr & for syntax http://bit.ly/1Tp6Fw9
// uses the 256-color table from http://bit.ly/1W1qJuH
reset = "\u{001b}[0m"
escape = "\u{001b}[38;5;"
levelColor.verbose = "251m" // silver
levelColor.debug = "35m" // green
levelColor.info = "38m" // blue
levelColor.warning = "178m" // yellow
levelColor.error = "197m" // red
} else {
reset = ""
escape = ""
levelColor.verbose = ""
levelColor.debug = ""
levelColor.info = ""
levelColor.warning = ""
levelColor.error = ""
}
}
}
override public var defaultHashValue: Int {return 2}
let fileManager = FileManager.default
public init(logFileURL: URL? = nil) {
if let logFileURL = logFileURL {
self.logFileURL = logFileURL
super.init()
return
}
// platform-dependent logfile directory default
var baseURL: URL?
#if os(OSX)
if let url = fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first {
baseURL = url
// try to use ~/Library/Caches/APP NAME instead of ~/Library/Caches
if let appName = Bundle.main.object(forInfoDictionaryKey: "CFBundleExecutable") as? String {
do {
if let appURL = baseURL?.appendingPathComponent(appName, isDirectory: true) {
try fileManager.createDirectory(at: appURL,
withIntermediateDirectories: true, attributes: nil)
baseURL = appURL
}
} catch {
print("Warning! Could not create folder /Library/Caches/\(appName)")
}
}
}
#else
#if os(Linux)
baseURL = URL(fileURLWithPath: "/var/cache")
#else
// iOS, watchOS, etc. are using the caches directory
if let url = fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first {
baseURL = url
}
#endif
#endif
if let baseURL = baseURL {
self.logFileURL = baseURL.appendingPathComponent("swiftybeaver.log", isDirectory: false)
}
super.init()
}
// append to file. uses full base class functionality
override public func send(_ level: SwiftyBeaver.Level, msg: String, thread: String,
file: String, function: String, line: Int, context: Any? = nil) -> String? {
let formattedString = super.send(level, msg: msg, thread: thread, file: file, function: function, line: line, context: context)
if let str = formattedString {
_ = saveToFile(str: str)
}
return formattedString
}
/// appends a string as line to a file.
/// returns boolean about success
func saveToFile(str: String) -> Bool {
guard let url = logFileURL else { return false }
let line = str + "\n"
guard let data = line.data(using: String.Encoding.utf8) else { return false }
do {
if fileManager.fileExists(atPath: url.path) == false {
let directoryURL = url.deletingLastPathComponent()
if fileManager.fileExists(atPath: directoryURL.path) == false {
try fileManager.createDirectory(
at: directoryURL,
withIntermediateDirectories: true
)
}
fileManager.createFile(atPath: url.path, contents: nil)
#if os(iOS) || os(watchOS)
if #available(iOS 10.0, watchOS 3.0, *) {
var attributes = try fileManager.attributesOfItem(atPath: url.path)
attributes[FileAttributeKey.protectionKey] = FileProtectionType.none
try fileManager.setAttributes(attributes, ofItemAtPath: url.path)
}
#endif
}
write(data: data, to: url)
return true
} catch {
print("SwiftyBeaver File Destination could not write to file \(url).")
return false
}
}
private func write(data: Data, to url: URL) {
let coordinator = NSFileCoordinator(filePresenter: nil)
var error: NSError?
coordinator.coordinate(writingItemAt: url, error: &error) { url in
do {
let fileHandle = try FileHandle(forWritingTo: url)
fileHandle.seekToEndOfFile()
fileHandle.write(data)
if syncAfterEachWrite {
fileHandle.synchronizeFile()
}
fileHandle.closeFile()
} catch {
print("SwiftyBeaver File Destination could not write to file \(url).")
return
}
}
if let error = error {
print("Failed writing file with error: \(String(describing: error))")
}
}
/// deletes log file.
/// returns true if file was removed or does not exist, false otherwise
public func deleteLogFile() -> Bool {
guard let url = logFileURL, fileManager.fileExists(atPath: url.path) == true else { return true }
do {
try fileManager.removeItem(at: url)
return true
} catch {
print("SwiftyBeaver File Destination could not remove file \(url).")
return false
}
}
}