Dunfey · Hotel WWDC as data, est. 1983
Front desk everything
Years
Topics

2020 Privacy & SecuritySwift

WWDC20 · 17 min · Privacy & Security / Swift

Explore logging in Swift

Meet the latest generation of Swift unified logging APIs. Learn how to log events and errors in your app while preserving privacy. Take advantage of powerful yet readable options for formatting data — all without sacrificing performance. And we’ll show you how you can gather and process log messages to help you understand and debug unexpected behavior in your apps.

Watch at developer.apple.com ↗

Transcript all transcripts

Code shown on screen · 9 snippets

Example illustrating how to add logging to your app in three simple steps swift · at 2:44 ↗
// Add logging to your app in three simple steps
 
import os

let logger = Logger(subsystem: "com.example.Fruta", category: "giftcards")

func beginTask(url: URL, handler: (Data) -> Void) {
    launchTask(with: url) {
       handler($0)
    }

    logger.log("Started a task")
}
An example code that logs a message with run-time data swift · at 3:32 ↗
// Add runtime data to the log messsage using string interpolation

import os

let logger = Logger(subsystem: "com.example.Fruta", category: "giftcards")

func beginTask(url: URL, handler: (Data) -> Void) {
    launchTask(with: url) {
       handler($0)
    }
    logger.log("Started a task \(taskId)")
}
Example illustrating why nonnumeric types are redacted in the logs by default swift · at 4:28 ↗
logger.log("Paid with bank account \(accountNumber)")
Code that shows how to mark public data so that it is displayed in the logs swift · at 5:01 ↗
logger.log("Ordered smoothie \(smoothieName, privacy: .public)")
Code shown during first demo swift · at 6:03 ↗
import SwiftUI
import os

let logger = Logger(subsystem: "com.example.Fruta", category: "giftcards")

struct GiftCardView: View {
    // Denotes whether there is an active task for loading gift cards.
    @State private var taskRunning: Bool = false
    
    // A UUID that uniquely identifies a task.
    @State private var currentTaskID: UUID = UUID()
    
    // An unrecoverable error seen during execution.
    @State private var error: Error? = nil

    // A model that stores information about gift cards.
    @ObservedObject var model: GiftCardModel
    
    var body: some View {
        // Display a list of gifts which can be tapped on and scrolled through.
        GiftCardList(model: model, taskRunning: $taskRunning, currentTaskID: $currentTaskID, error: $error, downloadAction: beginTask, stopAction: endTask)
            .navigationTitle("Gift Cards")
    }
    
    // Start a task to download gift cards from a server.
    func beginTask(serverURL: URL, cardDownloadHandler: @escaping (Data) -> Void) {
        logger.log("Starting a new task for loading cards \(currentTaskID, privacy: .public)")        
        launchTask(with: serverURL) {
            cardDownloadHandler($0)
        }
    }
    
    // Stop the currently running task for downloading cards from a server.
    func endTask() {
        guard taskRunning else {
            logger.fault("Task \(currentTaskID, privacy: .public) is not runinng, cannot be stopped!")
            error = TaskError.noActiveTask
            return
        }
        taskRunning = false
        logger.log("Task \(currentTaskID, privacy: .public) interrupted")
    }
    
    // Start a URLSession dataTask with the given URL.
    func launchTask(with url: URL, handler: @escaping (Data) -> Void) {
        guard error == nil else {
            return
        }
        taskRunning = true
        let task = URLSession.shared.dataTask(with: url) {
            data, response, error in
            if let error = error {
                self.error = ConnectionError.other(error)
            }
            if let data = data {
                handler(data)
            }
        }
        task.resume()
    }

}
Illustration of how debug-level logging will not evaluate the code that constructs log message swift · at 11:51 ↗
logger.debug("\(slowFunction(data))")
Code that shows how to display run-time data with a fixed width and how to set precision of a floating-point value using formatting options swift · at 12:58 ↗
import SwiftUI
import os

let statisticsLogger = Logger(subsystem: "com.example.Fruta", category: "statistics")

// Log statistics about communication with a server.
func logStatistics(taskID: UUID, giftCardID: String, serverID: Int, seconds: Double) {
    statisticsLogger.log("\(taskID) \(giftCardID, align: .left(columns: GiftCard.maxIDLength)) \(serverID) \(seconds, format: .fixed(precision: 2))")
}
Example of formatting log messages swift · at 15:00 ↗
logger.log("\(data, format: .hex, align: .right(columns: width))")
Example illustrating the use of a hash to redact private data, which ensures that identical data get the same hash swift · at 16:05 ↗
logger.log("Paid with bank account: \(accountNumber, privacy: .private(mask: .hash))")