OktaLogger is a proxy-based logging SDK for allowing an app to log to many destinations at once, allowing for easy error and metric reporting without extraneous noise.
- Compatible with Swift and Objective-C;
- Supports single input to multiple output logger classes (e.g. console, firebase, filesystem);
- Supports runtime log level changes to any destination;
- Supports changing destinations at runtime;
- Default properties for logging destinations in order to support data such as device identifier.
This SDK is available through CocoaPods. To install it, add the following line to your Podfile:
pod 'OktaLogger', :git => 'https://github.com/okta/okta-logger-swift.git'
There are few available subspecs:
Core
- Contains only basic functionality and Console logger destination;FileLogger
- Core + File logger destination;FirebaseCrashlytics
- Core + Firebase Crashlytics logger destination;Complete
- Includes all available functionality. This subspec will be used by default.
This SDK is available through Swift Package Manager. To install it, import it from the following url:
https://github.com/okta/okta-logger-swift.git
There are few available products available to import:
OktaLoggerCore
- Contains only basic functionality and Console logger destination;OktaFileLogger
- Core + File logger destination;OktaFirebaseCrashlytics
- Core + Firebase Crashlytics logger destination;OktaInstabugLogger
- Core + Instabug logger destination;OktaLogger
- Includes all available functionality;
To start using OktaLogger you need to initialize OktaLogger
object. Initializer takes destinations
array as parameter, so you can specify which destinations your logger will use. Please note that each destination should have unique identifier. New destination with existing ID won't be added. You can find more information about logging destinations in the related section.
// Initialization
let consoleDestination = OktaLoggerConsoleLogger(
identifier: "com.okta.consoleLogger",
level: .all,
defaultProperties: nil
)
let logger = OktaLogger(destinations: [consoleDestination])
After initialization OktaLogger
object is ready to track events:
// Logging
logger.info(eventName: "Start enrollment", message: nil)
logger.error(eventName: "TOTP Failure", message: "Could not retrieve key for RSA Key: ab43csd")
To add or remove destinations use addDestination(_:)
and removeDestination(withIdentifier:)
methods of OktaLogger
instance:
// Edit destinations
let firebaseDestination = OktaFirebaseDestination(
crashlytics: Crashlytics.crashlytics(),
identifier: "com.okta.firebaseLogger",
level: .error
)
logger.addDestination(firebaseDestination)
logger.removeDestination(withIdentifier: consoleDestination.identifier)
Use setLogLevel(level:, identifiers:)
method to change log level of any destination(s):
// Changing log levels
logger.setLogLevel(level: [.warn, .error], identifiers: [console.identifier, firebase.identifier])
Destination is an entity which perform log operation according to its implementation. Destinations should conforms to OktaLoggerDestinationProtocol
. There are 3 default destinations which provided by OktaLogger SDK:
- Console (OktaLoggerConsoleLogger)
- File (OktaLoggerFileLogger)
- Firebase (OktaLoggerFirebaseCrashlyticsLogger)
- AppCenter (AppCenterLogger)
All of the default logging destinations are thread-safe and could be used from any thread.
Destination instance has an ID string to store and identify it in the OktaLogger
. You can use any format for identifier. We recommend to use reverse-domain format with app Bundle ID and destination name in it.
Each destination has its own log level that specifies which messages should be processed by it. Please, refer to related section to find out more about log levels.
Each destination also has defaultProperties
parameter. This is key-value structure that could be used for storing some general information like user ID, app version, etc. Default destinations including string representation of this structure in the every log message. You can modify default properties with addDefaultProperties(_:)
and removeDefaultProperties(for:)
methods.
Related class - OktaLoggerConsoleLogger.
This destination is using os_log
function to print log messages to the console. It does not contain any 3rd party dependencies and mainly used during the XCode debug sessions.
Related class - OktaLoggerFileLogger.
The purpose of this destination is storing logs on the disk.
There are several features available:
- Writing logs to filesystem in the specified location;
- Configure amount of logs that should be collected and the rolling policy (see OktaLoggerFileLoggerConfig);
- Retrieve log data and log files paths;
- Purge existing logs.
File logging destination is using CocoaLumberjack for logging implementation.
Related class - OktaLoggerFirebaseCrashlyticsLogger.
This destination is using FirebaseCrashlytics SDK to log messages, so they can be accessed from Firebase console.
There are few important features and restrictions in this destination:
- To initialize it you need to setup and initialize Firebase SDK first. After that, you can pass configured
Crashlytics
object to the destination initializer. - Logs with
warning
anderror
levels are sent as non-fatal events. These logs are also added to non-fatal and fatal error reports. - Logs with
debug
,info
anduiEvent
are added as custom log messages. These logs can be accessible only in scope of fatal or non-fatal errors. - Error name in Firebase event consist of destination id and lowercased event name in the following format:
<destination id>.<event name>
. For example, "Push register failed" error event hasokta.verify.crashlytics.logger.push-register-failed
error name. - Maximum amount of logs that could be added to one report is restricted by 64kB on SDK level.
- Fatal and non-fatal error reports is sent on the next app launch.
This destination is using Firebase Crashlytics SDK for logging implementation.
Related class -
OktaLoggerInstabugLogger.
This destination uses the Instabug SDK to send events, so they can be accessed from the Instabug console in bug report or improvement suggestion.
There are a few important features and restrictions in this destination:
- Logger will not send events unless Instabug is configured setup Instabug in iOS app.
- You can review only 1000 log records for one report. See Instabug docs for more details.
- For each log level OktaLogger will call appropriate Instabug log method. See the full list in the table below.
OktaLogger log level | Instabug log method |
---|---|
all |
IBGLog.logVerbose() |
debug |
IBGLog.logDebug() |
info |
IBGLog.logInfo() |
uiEvent |
IBGLog.logInfo() |
warning |
IBGLog.logWarn() |
error |
IBGLog.logError() |
This destination is using Instabug iOS SDK for logging implementation.
If you want to create your custom destination it is recommended to inherit it from OktaLoggerDestinationBase
class, as this class implements some basic functionality. Hovewer, the only requirement for destinations is to conform to OktaLoggerDestinationProtocol
.
If you choose to inherit from OktaLoggerDestinationBase
, than you need to implement log()
method in order to make it work. You can use stringValue()
method to receive default log message string representation. Please, refer to OktaLoggerConsoleLogger as an example of logger destination implementation.
OktaLogger provides 7 log levels:
off
error
uiEvent
warning
info
debug
all
Every destination has its own level, so you can change it separately for each of them. Logging destinations will only log events which match against their level(s).
For example, the following console logger will ignore debug
logs, but will process logs with level info
, warning
and error
:
let consoleLogger = OktaLoggerConsoleLogger(identifier: "console.logger", level: [.info, .warn, .error])`
let logger = OktaLogger(destinations: [consoleLogger])
Logging level can be changed at runtime using setLogLevel(level:, identifiers:)
method of OktaLogger
or by changing level
property in OktaLoggerDestination
instance.
logger.setLogLevel(level: .all, destinations: [consoleLogger.identifier])
// or
consoleLogger.level = .all
classDiagram
OktaLogger *-- OktaLoggerDestinationBase : contains
OktaLoggerDestinationBase .. OktaLogLevel
class OktaLogger {
var main: OktaLogger? static instance
let destinations: [string:OktaLoggerDestinationProtocol]
init(destinations: [OktaLoggerDestinationProtocol])
log(level:eventName:message:properties:file:line:function)
debug(eventName:message:properties)
info(eventName:message:properties)
warning(eventName:message:properties)
uiEvent(eventName:message:properties)
error(eventName:message:properties)
}
class OktaLoggerDestinationBase {
let identifier: String
var logLevel: OktaLogLevel
log(level:eventName:message:properties:file:line:function)
}
class OktaLogLevel {
static let off
static let debug
static let info
static let warning
static let uiEvent
static let error
static let all
}
sequenceDiagram
participant Application
participant OktaLogger
participant ConsoleDestination
participant FileDestination
participant FirebaseDestination
Application->>Application: Create destinations\n(console, file, firebase)
Application->>OktaLogger: Create OktaLogger instance\nwith destinations
Application->>OktaLogger: logError(event, message, data)
OktaLogger->>ConsoleDestination: logError()
ConsoleDestination->>ConsoleDestination: Log to console + IDE
OktaLogger->>FileDestination: logError()
FileDestination->>FileDestination: Write log entry to file
OktaLogger->>FirebaseDestination: logError()
FirebaseDestination->>FirebaseDestination: recordNonFatal(error)
Application->>OktaLogger: logDebug("network request")
OktaLogger->>ConsoleDestination: log to console + IDE
OktaLogger->>OktaLogger: Skip destinations\nwithout level: .debug