This repository has been archived by the owner. It is now read-only.
Permalink
Cannot retrieve contributors at this time
115 lines (94 sloc)
4.06 KB
| /* This Source Code Form is subject to the terms of the Mozilla Public | |
| * License, v. 2.0. If a copy of the MPL was not distributed with this | |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
| import Foundation | |
| import XCGLogger | |
| //// A rolling file logger that saves to a different log file based on given timestamp. | |
| open class RollingFileLogger: XCGLogger { | |
| fileprivate static let TwoMBsInBytes: Int64 = 2 * 100000 | |
| fileprivate let sizeLimit: Int64 | |
| fileprivate let logDirectoryPath: String? | |
| let fileLogIdentifierPrefix = "com.mozilla.firefox.filelogger." | |
| fileprivate static let DateFormatter: DateFormatter = { | |
| let formatter = Foundation.DateFormatter() | |
| formatter.dateFormat = "yyyyMMdd'T'HHmmssZ" | |
| return formatter | |
| }() | |
| let root: String | |
| public init(filenameRoot: String, logDirectoryPath: String?, sizeLimit: Int64 = TwoMBsInBytes) { | |
| root = filenameRoot | |
| self.sizeLimit = sizeLimit | |
| self.logDirectoryPath = logDirectoryPath | |
| super.init() | |
| } | |
| /** | |
| Create a new log file with the given timestamp to log events into | |
| :param: date Date for with to start and mark the new log file | |
| */ | |
| open func newLogWithDate(_ date: Date) { | |
| // Don't start a log if we don't have a valid log directory path | |
| if logDirectoryPath == nil { | |
| return | |
| } | |
| if let filename = filenameWithRoot(root, withDate: date) { | |
| remove(destinationWithIdentifier: fileLogIdentifierWithRoot(root)) | |
| add(destination: FileDestination(owner: self, writeToFile: filename, identifier: fileLogIdentifierWithRoot(root))) | |
| info("Created file destination for logger with root: \(self.root) and timestamp: \(date)") | |
| } else { | |
| error("Failed to create a new log with root name: \(self.root) and timestamp: \(date)") | |
| } | |
| } | |
| open func deleteOldLogsDownToSizeLimit() { | |
| // Check to see we haven't hit our size limit and if we did, clear out some logs to make room. | |
| while sizeOfAllLogFilesWithPrefix(self.root, exceedsSizeInBytes: sizeLimit) { | |
| deleteOldestLogWithPrefix(self.root) | |
| } | |
| } | |
| open func logFilenamesAndURLs() throws -> [(String, URL)] { | |
| guard let logPath = logDirectoryPath else { | |
| return [] | |
| } | |
| let files = try FileManager.default.contentsOfDirectoryAtPath(logPath, withFilenamePrefix: root) | |
| return files.flatMap { filename in | |
| if let url = URL(string: "\(logPath)/\(filename)") { | |
| return (filename, url) | |
| } | |
| return nil | |
| } | |
| } | |
| fileprivate func deleteOldestLogWithPrefix(_ prefix: String) { | |
| if logDirectoryPath == nil { | |
| return | |
| } | |
| do { | |
| let logFiles = try FileManager.default.contentsOfDirectoryAtPath(logDirectoryPath!, withFilenamePrefix: prefix) | |
| if let oldestLogFilename = logFiles.first { | |
| try FileManager.default.removeItem(atPath: "\(logDirectoryPath!)/\(oldestLogFilename)") | |
| } | |
| } catch _ as NSError { | |
| error("Shouldn't get here") | |
| return | |
| } | |
| } | |
| fileprivate func sizeOfAllLogFilesWithPrefix(_ prefix: String, exceedsSizeInBytes threshold: Int64) -> Bool { | |
| guard let path = logDirectoryPath else { | |
| return false | |
| } | |
| let logDirURL = URL(fileURLWithPath: path) | |
| do { | |
| return try FileManager.default.allocatedSizeOfDirectoryAtURL(logDirURL, forFilesPrefixedWith: prefix, isLargerThanBytes: threshold) | |
| } catch let errorValue as NSError { | |
| error("Error determining log directory size: \(errorValue)") | |
| } | |
| return false | |
| } | |
| fileprivate func filenameWithRoot(_ root: String, withDate date: Date) -> String? { | |
| if let dir = logDirectoryPath { | |
| return "\(dir)/\(root).\(RollingFileLogger.DateFormatter.string(from: date)).log" | |
| } | |
| return nil | |
| } | |
| fileprivate func fileLogIdentifierWithRoot(_ root: String) -> String { | |
| return "\(fileLogIdentifierPrefix).\(root)" | |
| } | |
| } |