Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add optional file protection + backup exclusion to FileLoggerable #93

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion Sources/Puppy/FileLogger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,20 @@ public struct FileLogger: FileLoggerable {

public let fileURL: URL
public let filePermission: String
public let fileProtectionType: FileProtectionType?
public let isExcludedFromBackup: Bool

public let flushMode: FlushMode
public let writeMode: FileWritingErrorHandlingMode

public init(_ label: String, logLevel: LogLevel = .trace, logFormat: LogFormattable? = nil, fileURL: URL, filePermission: String = "640", flushMode: FlushMode = .always, writeMode: FileWritingErrorHandlingMode = .force) throws {
public init(_ label: String,
logLevel: LogLevel = .trace,
logFormat: LogFormattable? = nil,
fileURL: URL, filePermission: String = "640",
fileProtectionType: FileProtectionType? = nil,
isExcludedFromBackup: Bool = false,
flushMode: FlushMode = .always,
writeMode: FileWritingErrorHandlingMode = .force) throws {
self.label = label
self.queue = DispatchQueue(label: label)
self.logLevel = logLevel
Expand All @@ -22,6 +31,8 @@ public struct FileLogger: FileLoggerable {
self.fileURL = fileURL
puppyDebug("initialized, fileURL: \(fileURL)")
self.filePermission = filePermission
self.fileProtectionType = fileProtectionType
self.isExcludedFromBackup = isExcludedFromBackup

self.flushMode = flushMode
self.writeMode = writeMode
Expand Down
14 changes: 14 additions & 0 deletions Sources/Puppy/FileLoggerable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public enum FileWritingErrorHandlingMode: Sendable {
public protocol FileLoggerable: Loggerable, Sendable {
var fileURL: URL { get }
var filePermission: String { get }
var fileProtectionType: FileProtectionType? { get }
var isExcludedFromBackup: Bool { get }
}

extension FileLoggerable {
Expand Down Expand Up @@ -107,6 +109,18 @@ extension FileLoggerable {

if !FileManager.default.fileExists(atPath: fileURL.path) {
let successful = FileManager.default.createFile(atPath: fileURL.path, contents: nil, attributes: [FileAttributeKey.posixPermissions: uintPermission])

if let fileProtectionType = fileProtectionType {
try FileManager.default.setAttributes([.protectionKey: fileProtectionType], ofItemAtPath: fileURL.path)
}

if isExcludedFromBackup {
var resourceValues = URLResourceValues()
resourceValues.isExcludedFromBackup = true
var fileURL = fileURL
try fileURL.setResourceValues(resourceValues)
}

if successful {
puppyDebug("succeeded in creating filePath")
} else {
Expand Down
24 changes: 22 additions & 2 deletions Sources/Puppy/FileRotationLogger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,28 @@ public struct FileRotationLogger: FileLoggerable {

public let fileURL: URL
public let filePermission: String
public var fileProtectionType: FileProtectionType?
public var isExcludedFromBackup: Bool

public let flushMode: FlushMode
public let writeMode: FileWritingErrorHandlingMode

let rotationConfig: RotationConfig
private weak var delegate: FileRotationLoggerDelegate?

private var dateFormat: DateFormatter

public init(_ label: String, logLevel: LogLevel = .trace, logFormat: LogFormattable? = nil, fileURL: URL, filePermission: String = "640", rotationConfig: RotationConfig, delegate: FileRotationLoggerDelegate? = nil) throws {
public init(_ label: String,
logLevel: LogLevel = .trace,
logFormat: LogFormattable? = nil,
fileURL: URL,
filePermission: String = "640",
fileProtectionType: FileProtectionType? = nil,
isExcludedFromBackup: Bool = false,
rotationConfig: RotationConfig,
flushMode: FlushMode = .always,
writeMode: FileWritingErrorHandlingMode = .force,
delegate: FileRotationLoggerDelegate? = nil) throws {
self.label = label
self.queue = DispatchQueue(label: label)
self.logLevel = logLevel
Expand All @@ -29,6 +44,11 @@ public struct FileRotationLogger: FileLoggerable {
self.fileURL = fileURL
puppyDebug("initialized, fileURL: \(fileURL)")
self.filePermission = filePermission
self.fileProtectionType = fileProtectionType
self.isExcludedFromBackup = isExcludedFromBackup

self.flushMode = flushMode
self.writeMode = writeMode

self.rotationConfig = rotationConfig
self.delegate = delegate
Expand All @@ -40,7 +60,7 @@ public struct FileRotationLogger: FileLoggerable {

public func log(_ level: LogLevel, string: String) {
rotateFiles()
append(level, string: string)
append(level, string: string, flushMode: flushMode, writeMode: writeMode)
rotateFiles()
}

Expand Down
40 changes: 40 additions & 0 deletions Tests/PuppyTests/FileLoggerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,46 @@ final class FileLoggerTests: XCTestCase {
log.remove(fileLogger)
}

func testFileProtection() throws {
#if os(iOS) || os(macOS)
let fileURL = URL(fileURLWithPath: "./protected.log").absoluteURL
let fileLogger: FileLogger = try .init("com.example.yourapp.filelogger.protected", fileURL: fileURL, fileProtectionType: .completeUntilFirstUserAuthentication)
var log = Puppy()
log.add(fileLogger)
log.trace("protection, TRACE message using FileLogger")
log.verbose("protection, VERBOSE message using FileLogger")
fileLogger.flush(fileURL)

let attributes = try FileManager.default.attributesOfItem(atPath: fileURL.path)
// swiftlint:disable force_cast
let protection = attributes[FileAttributeKey.protectionKey] as! FileProtectionType
// swiftlint:enable force_cast

XCTAssertEqual(protection, FileProtectionType.completeUntilFirstUserAuthentication)

_ = fileLogger.delete(fileURL)
log.remove(fileLogger)
#endif
}

func testExcludeFromBackup() throws {
#if os(iOS) || os(macOS)
let fileURL = URL(fileURLWithPath: "./exclude-from-backup.log").absoluteURL
let fileLogger: FileLogger = try .init("com.example.yourapp.filelogger.exclude-from-backup", fileURL: fileURL, isExcludedFromBackup: true)
var log = Puppy()
log.add(fileLogger)
log.trace("exclude from backup, TRACE message using FileLogger")
log.verbose("exclude from backup, VERBOSE message using FileLogger")
fileLogger.flush(fileURL)

let resourceValues = try fileURL.resourceValues(forKeys: [.isExcludedFromBackupKey])
XCTAssertTrue(resourceValues.isExcludedFromBackup == true)

_ = fileLogger.delete(fileURL)
log.remove(fileLogger)
#endif
}

func testFilePermissionError() throws {
let permission800FileURL = URL(fileURLWithPath: "./permission800.log").absoluteURL
let filePermission800 = "800"
Expand Down
Loading