Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
ControlCenter
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
/* 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)"
}
}