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

Custom logger implementation on iOS #1026

20 changes: 15 additions & 5 deletions PrebidMobile.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,9 @@
53514CF22D0851DE00A480C0 /* InterstitialControllerInteractionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53514CF12D0851DE00A480C0 /* InterstitialControllerInteractionDelegate.swift */; };
5355ACA929C454070014F16E /* VAST_with_empty_companion.xml in Resources */ = {isa = PBXBuildFile; fileRef = 5355ACA829C454070014F16E /* VAST_with_empty_companion.xml */; };
5355ACAB29C454770014F16E /* CreativeModelCollectionMakerVASTTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5355ACAA29C454770014F16E /* CreativeModelCollectionMakerVASTTests.swift */; };
536469C02D2FD78200F50B6D /* PluginEventDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536469BF2D2FD78200F50B6D /* PluginEventDelegate.swift */; };
535ADE0B2D2E970200DB888F /* SDKConsoleLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9F0999C2C78CC8A007DB464 /* SDKConsoleLogger.swift */; };
535ADE102D2E987E00DB888F /* PluginEventDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 535ADE0F2D2E987E00DB888F /* PluginEventDelegate.swift */; };
535ADE122D2EA2F500DB888F /* PrebidLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 535ADE112D2EA2F500DB888F /* PrebidLogger.swift */; };
536A39262A84C50F00B1CCEA /* StringExtensionsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536A39252A84C50F00B1CCEA /* StringExtensionsTest.swift */; };
536A427F282D11DA0069E9B2 /* PrebidServerConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536A427E282D11DA0069E9B2 /* PrebidServerConnection.swift */; };
536A4283282D12E80069E9B2 /* PrebidServerConnectionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536A4282282D12E80069E9B2 /* PrebidServerConnectionProtocol.swift */; };
Expand Down Expand Up @@ -813,6 +815,7 @@
A908694229E05EAF00B37479 /* PrebidMobilePluginRegister.swift in Sources */ = {isa = PBXBuildFile; fileRef = A908694129E05EAF00B37479 /* PrebidMobilePluginRegister.swift */; };
A908694429E05ED500B37479 /* PrebidMobilePluginRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A908694329E05ED500B37479 /* PrebidMobilePluginRenderer.swift */; };
A908694629E05F7900B37479 /* PrebidRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A908694529E05F7900B37479 /* PrebidRenderer.swift */; };
F9F0999B2C78C668007DB464 /* SDKConsoleLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = F91B60A82C52A73500DA9796 /* SDKConsoleLogger.swift */; };
FA5AD5E42271FA4100C8F274 /* ConstantsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA5AD5E32271FA4100C8F274 /* ConstantsTest.swift */; };
FA9D7F2722E8A83D006FCBEF /* AdViewUtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA9D7F2622E8A83D006FCBEF /* AdViewUtilsTests.swift */; };
FAA29904242D1C27002ACBF2 /* TargetingObjCTests.m in Sources */ = {isa = PBXBuildFile; fileRef = FAA29903242D1C27002ACBF2 /* TargetingObjCTests.m */; };
Expand Down Expand Up @@ -1002,7 +1005,8 @@
53514CF12D0851DE00A480C0 /* InterstitialControllerInteractionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterstitialControllerInteractionDelegate.swift; sourceTree = "<group>"; };
5355ACA829C454070014F16E /* VAST_with_empty_companion.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = VAST_with_empty_companion.xml; sourceTree = "<group>"; };
5355ACAA29C454770014F16E /* CreativeModelCollectionMakerVASTTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreativeModelCollectionMakerVASTTests.swift; sourceTree = "<group>"; };
536469BF2D2FD78200F50B6D /* PluginEventDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginEventDelegate.swift; sourceTree = "<group>"; };
535ADE0F2D2E987E00DB888F /* PluginEventDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginEventDelegate.swift; sourceTree = "<group>"; };
535ADE112D2EA2F500DB888F /* PrebidLogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrebidLogger.swift; sourceTree = "<group>"; };
536A39252A84C50F00B1CCEA /* StringExtensionsTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtensionsTest.swift; sourceTree = "<group>"; };
536A427E282D11DA0069E9B2 /* PrebidServerConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrebidServerConnection.swift; sourceTree = "<group>"; };
536A4282282D12E80069E9B2 /* PrebidServerConnectionProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrebidServerConnectionProtocol.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1738,6 +1742,7 @@
A908694129E05EAF00B37479 /* PrebidMobilePluginRegister.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrebidMobilePluginRegister.swift; sourceTree = "<group>"; };
A908694329E05ED500B37479 /* PrebidMobilePluginRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrebidMobilePluginRenderer.swift; sourceTree = "<group>"; };
A908694529E05F7900B37479 /* PrebidRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrebidRenderer.swift; sourceTree = "<group>"; };
F9F0999C2C78CC8A007DB464 /* SDKConsoleLogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SDKConsoleLogger.swift; sourceTree = "<group>"; };
FA4A88432497A99D00FDCBB6 /* Swizzling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Swizzling.swift; sourceTree = "<group>"; };
FA5AD5E32271FA4100C8F274 /* ConstantsTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConstantsTest.swift; sourceTree = "<group>"; };
FA85F9B4264946FC00B8BE72 /* TestUtils.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = TestUtils.xcodeproj; path = ../tools/TestUtils/TestUtils.xcodeproj; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1964,6 +1969,8 @@
FAEE4CE2262DC2B200AD9966 /* Log.swift */,
531CF21827E8FC1B005E5ABE /* LogLevel.swift */,
53F096C927E917D40058C94C /* Log+Extensions.h */,
535ADE112D2EA2F500DB888F /* PrebidLogger.swift */,
F9F0999C2C78CC8A007DB464 /* SDKConsoleLogger.swift */,
);
path = Logging;
sourceTree = "<group>";
Expand Down Expand Up @@ -2049,6 +2056,7 @@
5BC3764E271F1CFD00444D5E /* ExtensionsAndWrappers */ = {
isa = PBXGroup;
children = (
5BC37666271F1CFD00444D5E /* NSTimer */,
5BC37652271F1CFD00444D5E /* Exposure */,
5BC37659271F1CFD00444D5E /* NSDictionary+PBMExtensions.h */,
5BC3765F271F1CFD00444D5E /* NSDictionary+PBMExtensions.m */,
Expand All @@ -2060,18 +2068,17 @@
5BC3765A271F1CFD00444D5E /* NSNumber+PBMORTBNative.m */,
5BC3764F271F1CFD00444D5E /* NSString+PBMExtensions.h */,
5BC37662271F1CFD00444D5E /* NSString+PBMExtensions.m */,
5BC37666271F1CFD00444D5E /* NSTimer */,
5BC3765B271F1CFD00444D5E /* PBMTouchDownRecognizer.h */,
5BC3766E271F1CFD00444D5E /* PBMTouchDownRecognizer.m */,
5BC37650271F1CFD00444D5E /* UIView+PBMExtensions.h */,
5BC37661271F1CFD00444D5E /* UIView+PBMExtensions.m */,
5BC3765E271F1CFD00444D5E /* UIWindow+PBMExtensions.h */,
5BC3766F271F1CFD00444D5E /* UIWindow+PBMExtensions.m */,
53C925012990FB30009E6F94 /* String+Extensions.swift */,
53D3C38B2C2BEF9B0074D99B /* NSURL+PBMExtensions.h */,
53D3C38C2C2BEF9B0074D99B /* NSURL+PBMExtensions.m */,
535145DE2CCB758800D40B19 /* NSObject+PBMExtensions.h */,
535145DF2CCB758800D40B19 /* NSObject+PBMExtensions.m */,
53C925012990FB30009E6F94 /* String+Extensions.swift */,
);
path = ExtensionsAndWrappers;
sourceTree = "<group>";
Expand Down Expand Up @@ -3292,7 +3299,7 @@
A908694029E05E8D00B37479 /* PluginRenderer */ = {
isa = PBXGroup;
children = (
536469BF2D2FD78200F50B6D /* PluginEventDelegate.swift */,
535ADE0F2D2E987E00DB888F /* PluginEventDelegate.swift */,
A908694129E05EAF00B37479 /* PrebidMobilePluginRegister.swift */,
A908694329E05ED500B37479 /* PrebidMobilePluginRenderer.swift */,
53BFCD302CFE435D00A3287A /* PrebidMobilePluginRenderer+Extensions.swift */,
Expand Down Expand Up @@ -4109,6 +4116,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
535ADE0B2D2E970200DB888F /* SDKConsoleLogger.swift in Sources */,
5BC37AB1271F1D0000444D5E /* DemandResponseInfo.swift in Sources */,
5BC37AAE271F1D0000444D5E /* BannerEventHandlerStandalone.swift in Sources */,
5BC378DF271F1CFF00444D5E /* PBMORTBApp.m in Sources */,
Expand Down Expand Up @@ -4144,6 +4152,7 @@
5BC378CC271F1CFF00444D5E /* PBMWeakTimerTargetBox.m in Sources */,
5BC379AC271F1D0000444D5E /* PBMModalManager.m in Sources */,
FAEE4D1C262DC2B200AD9966 /* InstreamVideoAdUnit.swift in Sources */,
535ADE102D2E987E00DB888F /* PluginEventDelegate.swift in Sources */,
53B221D12A0E3D3D00C91CCB /* PrebidJSLibraryManager.swift in Sources */,
5BC37970271F1D0000444D5E /* PBMVastAbstractAd.m in Sources */,
53BDBF89293F5EFF004B6DE8 /* InternalUserConsentDataManager.m in Sources */,
Expand Down Expand Up @@ -4374,6 +4383,7 @@
928E5A7027F0F743000ADA1A /* ContextSubType.swift in Sources */,
5BC37A20271F1D0000444D5E /* PBMORTBMacrosHelper.m in Sources */,
92989653275FE98C00D3C174 /* PBMORTBContentData.m in Sources */,
535ADE122D2EA2F500DB888F /* PrebidLogger.swift in Sources */,
5BC378BB271F1CFF00444D5E /* NSNumber+PBMORTBNative.m in Sources */,
5BC37961271F1D0000444D5E /* PBMVastAdsBuilder.m in Sources */,
5BC37A91271F1D0000444D5E /* InterstitialEventLoadingDelegate.swift in Sources */,
Expand Down
8 changes: 4 additions & 4 deletions PrebidMobile/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ import UIKit

public let PrebidLocalCacheIdKey = "hb_cache_id_local"

@objc public class Constants: NSObject {
@objc public static let PREBID_VERSION = "2.3.1"
}

extension String {

static let EMPTY_String = ""
Expand Down Expand Up @@ -117,4 +113,8 @@ public class PrebidConstants: NSObject {
</html>
"""
}

public static let PREBID_VERSION = "2.3.1"

public static let SDK_NAME = "prebid-mobile-sdk"
}
152 changes: 55 additions & 97 deletions PrebidMobile/Logging/Log.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,66 +15,90 @@

import Foundation

/// This class serves as the central point for all logging operations within the SDK.
/// It allows for categorized logging based on severity levels (e.g., error, warning, debug) and offers options for both console and file-based logging.
/// It also provides the ability to set third-party logger.
@objc(PBMLog) @objcMembers
public class Log: NSObject {

// MARK: - Public properties

public static var dateFormat = "yyyy-MM-dd hh:mm:ssSSS"
public static var dateFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.dateFormat = dateFormat
formatter.locale = Locale.current
formatter.timeZone = TimeZone.current
return formatter
}

/// The current logging level. Only messages at this level or higher will be logged.
public static var logLevel: LogLevel = .debug

/// Indicates whether logs should also be saved to a file.
public static var logToFile = false

/// Sets a custom logger to handle log messages.
public static func setCustomLogger(_ logger: PrebidLogger) {
self.logger = logger
}

public static func error(_ object: Any, filename: String = #file, line: Int = #line, function: String = #function) {
log(object, logLevel: .error, filename: filename, line: line, function: function)
logger.error(object, filename: filename, line: line, function: function)
}

public static func info(_ object: Any, filename: String = #file, line: Int = #line, function: String = #function) {
log(object, logLevel: .info, filename: filename, line: line, function: function)
logger.info(object, filename: filename, line: line, function: function)
}

public static func debug(_ object: Any, filename: String = #file, line: Int = #line, function: String = #function) {
log(object, logLevel: .debug, filename: filename, line: line, function: function)
logger.debug(object, filename: filename, line: line, function: function)
}

public static func verbose(_ object: Any, filename: String = #file, line: Int = #line, function: String = #function) {
log(object, logLevel: .verbose, filename: filename, line: line, function: function)
logger.verbose(object, filename: filename, line: line, function: function)
}

public static func warn(_ object: Any, filename: String = #file, line: Int = #line, function: String = #function) {
log(object, logLevel: .warn, filename: filename, line: line, function: function)
logger.warn(object, filename: filename, line: line, function: function)
}

public static func severe(_ object: Any, filename: String = #file, line: Int = #line, function: String = #function) {
log(object, logLevel: .severe, filename: filename, line: line, function: function)
logger.severe(object, filename: filename, line: line, function: function)
}

public static func whereAmI(filename: String = #file, line: Int = #line, function: String = #function) {
log("", logLevel: .info, filename: filename, line: line, function: function)
}

static func log(_ object: Any, logLevel: LogLevel, filename: String, line: Int, function: String) {
if isLoggingEnabled(for: logLevel) {
let finalMessage = "\(sdkName): \(Date().toString()) \(logLevel.stringValue)[\(sourceFileName(filePath: filename))]:\(line) \(function) -> \(object)"
print(finalMessage)
serialWriteToLog(finalMessage)
}
logger.whereAmI(filename: filename, line: line, function: function)
}

/// Writes a log message to the log file asynchronously.
///
/// - Parameter message: The log message to be written to the file.
public static func serialWriteToLog(_ message: String) {
loggingQueue.async {
writeToLogFile(message)
}
}

public static func writeToLogFile(_ message: String) {
/// Reads the contents of the log file as a single string.
public static func getLogFileAsString() -> String? {
loggingQueue.sync {
if let logFileURL = logFileURL {
do {
return try String(contentsOf: logFileURL, encoding: .utf8)
} catch {
Log.error("\(PrebidConstants.SDK_NAME) Error getting log file: \(error.localizedDescription)")
}
}
return nil
}
}

/// Clears the contents of the log file.
public static func clearLogFile() {
loggingQueue.sync {
do {
if let logFileURL = logFileURL {
try "".data(using: .utf8)?.write(to: logFileURL)
}
} catch {
Log.error("\(PrebidConstants.SDK_NAME) Error clearing log file: \(error.localizedDescription)")
}
}
}

static func writeToLogFile(_ message: String) {
if !Log.logToFile {
return
}
Expand All @@ -93,7 +117,7 @@ public class Log: NSObject {
try fileHandle.write(contentsOf: data)
try fileHandle.close()
} catch {
Log.error("\(sdkName) Couldn't write to log file: \(error.localizedDescription)")
Log.error("\(PrebidConstants.SDK_NAME) Couldn't write to log file: \(error.localizedDescription)")
}
} else {
fileHandle.seekToEndOfFile()
Expand All @@ -106,83 +130,17 @@ public class Log: NSObject {
do {
try data.write(to: logFileURL)
} catch {
Log.error("\(sdkName) Couldn't write to log file URL: \(error.localizedDescription)")
}
}
}
}

public static func getLogFileAsString() -> String? {
loggingQueue.sync {
if let logFileURL = logFileURL {
do {
return try String(contentsOf: logFileURL, encoding: .utf8)
} catch {
Log.error("\(sdkName) Error getting log file: \(error.localizedDescription)")
}
}
return nil
}
}

public static func clearLogFile() {
loggingQueue.sync {
do {
if let logFileURL = logFileURL {
try "".data(using: .utf8)?.write(to: logFileURL)
Log.error("\(PrebidConstants.SDK_NAME) Couldn't write to log file URL: \(error.localizedDescription)")
}
} catch {
Log.error("\(sdkName) Error clearing log file: \(error.localizedDescription)")
}
}
}

// MARK: - Internal properties and methods

private static let sdkName = "prebid-mobile-sdk"

private static let loggingQueue = DispatchQueue(label: sdkName)
// MARK: - Private Properties

private static var logFileURL = getURLForDoc(sdkName + ".txt")
private static var logger: PrebidLogger = SDKConsoleLogger()

private class func isLoggingEnabled(for currentLevel: LogLevel) -> Bool {
#if !(DEBUG)
return false
#endif

if currentLevel.rawValue < Log.logLevel.rawValue {
return false
}

return true
}
private static let loggingQueue = DispatchQueue(label: PrebidConstants.SDK_NAME)

private static func getURLForDoc(_ docName: String) -> URL? {
let temporaryDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory())
return temporaryDirectoryURL.appendingPathComponent(docName)
}

private static func sourceFileName(filePath: String) -> String {
let components = filePath.components(separatedBy: "/")
return components.isEmpty ? "" : components.last!
}
}

extension Date {
func toString() -> String {
return Log.dateFormatter.string(from: self as Date)
}
}

/// Wrapping Swift.print() within DEBUG flag
///
/// - Note: *print()* might cause [security vulnerabilities](https://codifiedsecurity.com/mobile-app-security-testing-checklist-ios/)
///
/// - Parameter object: The object which is to be logged
///
func print(_ object: Any) {
// Only allowing in DEBUG mode
#if DEBUG
Swift.print(object)
#endif
private static let logFileURL = URL.temporaryURL(for: PrebidConstants.SDK_NAME + ".txt")
}
Loading