OSLog est une nouvelle framework native Apple qui permet de récupérer des messages de log au niveau de votre application mobile. OSLog constitue un remplacement pour des solutions comme print, debugPrint.. Elle permet d’afficher les logs très clairs avec plusieurs types(trace, notice, warning, critical..) surtout avec la console actuelle de Xcode15.

Dans cet article, on découvrira à travers un exemple pratique comment utiliser OSLog.

Utilisation pour tracker des calls api

Dans cet exemple, on essaye de récupérer une liste de repos swift depuis une API Github connu

https://api.github.com/search/repositories?q=language:swift

final class SwiftReposListViewModel: ObservableObject {
    @Published var repos: [RepoDTO] = []
    private let httpClient: HTTPClient

    init(httpClient: HTTPClient) {
        self.httpClient = httpClient
    }


    func fetch() async throws {
        guard let url = URL(string: Constants.SwiftRepoUrl.rawValue) else { return }
        do {
            debugPrint("Start fetching data")
            let result = try await httpClient.get(from: url)
            debugPrint("Finish fetching data")
            switch result {
            case let .success(data, _) :
                do {
                    let apiResult = try JSONDecoder().decode(GithubSearchResponse.self, from: data)
                    if let items = apiResult.items {
                        let repos = items.toRepoDTOs
                        DispatchQueue.main.async {
                            self.repos = repos
                        }
                    }
                }
                catch {}
            case let .failure(error):
                debugPrint(error)
                
            }
        } catch {
            debugPrint(error)
        }
    }
}

Le code permet de récupérer une liste de repos depuis l’api Github et de convertir vers un tableau de RepoDTO utilisé ensuite au niveau la vue SwiftUI pour afficher une liste de repos qui parlent de Swift etc.

On utilise un httpClient qui permet de faire un appel à base de Async Await.

Pour plus de détails sur la nouvelle framework concurrency, vous pouvez consulter notre article

Async Await et DI

Revenons à notre code, vous remarquez qu’on a ajouté un debugPrint pour tracer l’exécution de l’appel API. Imaginons qu’on peut catégoriser nos logs par type genre API Call tracking logs, Analytics logs, persistant data Logs … Imaginons encore que je peux distinguer graphiquement par des des couleurs les types des messages de logs afin de distinguer entre des messages simples, des erreurs, des warnings… En effet, OSLog permet de faire ça et on va voir comment.

extension Logger {
    private static var subsystem = Bundle.main.bundleIdentifier!
    static let apiCalls = Logger(subsystem: subsystem, category: "API calls life Cycle")
}

J’ai ajouté deux nouvelles propriétés subsystem et apiCalls. En effet, subsystem représente le bundle identifier qui nous permettra ensuite au niveau de la console de déboggage de distinguer les logs de notre application. Logger (une structure utiliser par OSLog pour émettre des logs) nous permet de définir une ou plusieurs types domaines de Log. Par exemple, j’ai choisi pour les call API le nom apiCalls.

Changeons maintenant le code pour ajouter l’appel vers Logger.

 do {
      Logger.apiCalls.trace("Swift repos start fetching")
      let result = try await httpClient.get(from: url)
      Logger.apiCalls.notice("Swift repos fetching is finished")
////
. catch {
      Logger.apiCalls.warning("\(error.localizedDescription, privacy: .public)")
}

Utilisation de la console

Tout d’abord pour afficher les logs sur la console, il faut l’afficher 😀. Pour se faire, il faut sélectionner manage Run Destinations depuis Xcode

Puis choisissez votre appareil et ensuite cliquer sur open Console

Vous aurez à ce moment l’interface de la console

Vous allez remarquez que notre console log tout (logs systems, applications). Afin de faciliter l’affichage de logs. Pour filter seulement sur notre application, on va utiliser notre bundle identifier fr.walidSASSI.SwiftRepos et choisissez Sous-système au niveau des filtres de recherche de la console.

Maintenant filtrons par le nom de notre domaine de recherche de logs à savoir API calls life Cycle

Si vous cliquez sur le message de log par exemple ‘Swift repos Start fetching’, vous retrouvez les informations sur son la catégorie API calls life cycle, le sous sytème ou on trouve notre bundle identifier, le numéro de processus pid associé, le thread.

Jouons avec les types des messages de logs

Logger avec plusieurs fonctions qui permettent de customiser vos messages de logs

public func trace(_ message: OSLogMessage)
public func debug(_ message: OSLogMessage)
public func info(_ message: OSLogMessage)
public func notice(_ message: OSLogMessage)
public func warning(_ message: OSLogMessage)
public func error(_ message: OSLogMessage)
public func critical(_ message: OSLogMessage)

Faisons les tests maintenant sur un simulateur iOS 17 sous Xcode 15. Vous allez remarquez que nos messages de logs prennent une forme assez stylé incluant plusieurs informations qu’on a vu au niveau de la console.

Xcode LLDB debugger distingue entre les différents type de messages de logs à travers des icônes spécifiques

Warning log
Trace log
Critical log

Une petite astuce de la WWDC 2023, vous pouvez cliquer sur le message de log avec la touche espace et vous voyez en détail les informations relatives au log event avec l’avantage de connaître la méthode dans laquelle s’est déclenché le log

Références

Debug With structured WWDC 2023

https://developer.apple.com/documentation/os/logger

https://swiftwithmajid.com/2022/04/19/exporting-data-from-unified-logging-system-in-swift/

https://swiftwithmajid.com/2022/04/06/logging-in-swift/