Logging

Configure log levels, privacy settings, and custom log handlers to control how the Airship SDK logs messages.

The Airship SDK provides configurable log levels to help you debug issues without overwhelming the console. If you don’t configure logging, the SDK uses Info for development builds and Error for production builds with private privacy level.

Log levels

The log level acts as a minimum threshold—only logs at that level and higher will be logged. Available log levels, ordered from most to least verbose:

Log LevelPrefixDescription
Verbose[Airship] [V]Highly detailed SDK status for deep debugging and troubleshooting
Debug[Airship] [D]General SDK status with more detailed information than Info
Info[Airship] [I]General SDK status and lifecycle events
Warning[Airship] [W]API deprecations, invalid setup, and other recoverable issues
Error[Airship] [E]Critical errors and exceptions that the SDK cannot gracefully handle
NoneDisables all logging

Log privacy levels

Control the visibility of log contents using privacy levels. This is especially useful when debugging release builds without exposing sensitive information.

  • private (default): Uses os.Logger to log all messages at the private level. The content of most logs will be redacted and will not be visible in the Console app by default. Use this for production builds to protect sensitive data.
  • public: Sends all logs to os.Logger with a public privacy level, preventing their content from being redacted. Use this when you need to capture detailed logs from release builds for debugging.
 Note

When using public privacy level, verbose and debug log messages are automatically elevated to info level because Console log doesn’t support those levels directly. This ensures all detailed logs are visible when debugging production builds.

Configuration

You can set separate log levels and privacy levels for development and production builds in your Airship config during takeOff.

Common configuration

Typical setup: more verbose logging for development, minimal logging for production:

Common logging configuration

var config = AirshipConfig()

// Development: verbose logging for debugging
config.developmentLogLevel = .verbose
config.developmentLogPrivacyLevel = .public

// Production: minimal logging to reduce noise
config.productionLogLevel = .error
config.productionLogPrivacyLevel = .private

try! Airship.takeOff(config)
UAConfig *config = [UAConfig config];

// Development: verbose logging for debugging
config.developmentLogLevel = UAAirshipLogLevelVerbose;

// Production: minimal logging to reduce noise
config.productionLogLevel = UAAirshipLogLevelError;

// Privacy levels (set via AirshipConfig.plist)
// <key>developmentLogPrivacyLevel</key>
// <string>public</string>
// <key>productionLogPrivacyLevel</key>
// <string>private</string>

[UAirship takeOff:config error:&airshipError];

Debugging production issues

When debugging issues in production builds, temporarily enable verbose logging to capture detailed SDK behavior:

Debugging production

var config = AirshipConfig()

// Production debugging: enable verbose logs
config.productionLogLevel = .verbose
config.productionLogPrivacyLevel = .public

try! Airship.takeOff(config)
UAConfig *config = [UAConfig config];

// Production debugging: enable verbose logs
config.productionLogLevel = UAAirshipLogLevelVerbose;

// Set via AirshipConfig.plist:
// <key>productionLogPrivacyLevel</key>
// <string>public</string>

[UAirship takeOff:config error:&airshipError];

Custom log handler

You can provide a custom log handler to intercept and handle all Airship log messages. This is useful when you need to integrate Airship logs with your own logging system or customize how logs are formatted or stored.

When a custom log handler is set, the default Airship log handler is completely replaced. Log level filtering is performed before your handler is called, so your handler will only receive logs that meet the configured log level threshold.

Implement the AirshipLogHandler protocol and set it on your Airship config:

import os.log

final class CustomLogHandler: AirshipLogHandler {
    private let logger = Logger(subsystem: "com.yourapp.airship", category: "Airship")
    
    func log(
        logLevel: AirshipLogLevel,
        message: String,
        fileID: String,
        line: UInt,
        function: String
    ) {
        // Forward to your logging system
        let osLogLevel: OSLogType
        switch logLevel {
        case .verbose, .debug:
            osLogLevel = .debug
        case .info:
            osLogLevel = .info
        case .warning:
            osLogLevel = .default
        case .error:
            osLogLevel = .error
        case .none:
            return
        }
        
        logger.log(level: osLogLevel, "\(message)")
        
        // Optionally: send to remote logging service
        // YourLoggingService.log(message, level: logLevel)
    }
}

var config = AirshipConfig()
config.logHandler = CustomLogHandler()

try! Airship.takeOff(config)