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

Logging functionality for CarPlay #3653

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 39 additions & 2 deletions Sources/MapboxNavigation/CarPlayManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import CarPlay
import MapboxCoreNavigation
import MapboxDirections
import MapboxMaps
import os.log
Copy link
Contributor

@MaximAlien MaximAlien Feb 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need to add logging for CPTemplate lifecycle callbacks in CarPlayManagerDelegate:

  • carPlayManager(_:templateWillAppear:animated:)
  • carPlayManager(_:templateDidAppear:animated:)
  • carPlayManager(_:templateWillDisappear:animated:)
  • carPlayManager(_:templateDidDisappear:animated:)


/**
`CarPlayManager` is the main object responsible for orchestrating interactions with a Mapbox map on CarPlay.
Expand Down Expand Up @@ -77,6 +78,7 @@ public class CarPlayManager: NSObject {

private weak var navigationService: NavigationService?
private var idleTimerCancellable: IdleTimerManager.Cancellable?
private let logger: OSLog = .init(subsystem: "com.mapbox.navigation", category: "CarPlayManager")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add a factory for loggers? So that we don't duplicate subsystem value everywhere.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or we can go with a simpler way: creating an internal constant for the log subsystem.

Copy link
Contributor Author

@jill-cardamon jill-cardamon Dec 16, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could use something like OSLogManager but would probably want to consider using this manager for all of the SDK.


/**
Programatically begins a CarPlay turn-by-turn navigation session.
Expand All @@ -93,6 +95,7 @@ public class CarPlayManager: NSObject {
locationProvider.stopUpdatingHeading()
if let passiveLocationProvider = locationProvider as? PassiveLocationProvider {
passiveLocationProvider.locationManager.pauseTripSession()
os_log("Trip session paused", log: logger, type: .debug)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be good to go through all methods in CarPlayManager and see what CarPlay related methods it uses. I think that we should log all callbacks we receive from it.

}
}

Expand Down Expand Up @@ -143,6 +146,7 @@ public class CarPlayManager: NSObject {
routingProvider: RoutingProvider,
eventsManager: NavigationEventsManager? = nil,
carPlayNavigationViewControllerClass: CarPlayNavigationViewController.Type? = nil) {

self.styles = styles ?? [DayStyle(), NightStyle()]
self.routingProvider = routingProvider
self.eventsManager = eventsManager ?? .init(activeNavigationDataSource: nil,
Expand All @@ -160,22 +164,39 @@ public class CarPlayManager: NSObject {
selector: #selector(navigationCameraStateDidChange(_:)),
name: .navigationCameraStateDidChange,
object: carPlayMapViewController?.navigationMapView.navigationCamera)
os_log("CarPlayManager subscribed for notifications.", log: logger, type: .info)
}

func unsubscribeFromNotifications() {
NotificationCenter.default.removeObserver(self,
name: .navigationCameraStateDidChange,
object: carPlayMapViewController?.navigationMapView.navigationCamera)
os_log("CarPlayManager suspended notifications.", log: logger, type: .info)
}

@available(iOS 15.0, *)
func getLogEntries() throws -> [OSLogEntryLog] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it for debugging? If so, don't forget to remove this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is for retrieving log entries if you want to see them printed to a file instead of looking at the log via the Console. This functionality is only available via iOS 15.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there are several build errors because of OSLogEntryLog. For example getting: error: cannot find type 'OSLogEntryLog' in scope.

let logStore = try OSLogStore(scope: .currentProcessIdentifier)
let oneHourAgo = logStore.position(date: Date().addingTimeInterval(-3600))
let allEntries = try logStore.getEntries(at: oneHourAgo)

return allEntries
.compactMap { $0 as? OSLogEntryLog }
.filter { $0.category == "CarPlay" }
}


@objc func navigationCameraStateDidChange(_ notification: Notification) {
guard let state = notification.userInfo?[NavigationCamera.NotificationUserInfoKey.state] as? NavigationCameraState else { return }
switch state {
case .idle:
os_log("Camera state: idle", log: logger, type: .info)
carPlayMapViewController?.recenterButton.isHidden = false
case .transitionToFollowing, .following:
os_log("Camera state: following", log: logger, type: .info)
carPlayMapViewController?.recenterButton.isHidden = true
case .transitionToOverview, .overview:
os_log("Camera state: overview", log: logger, type: .info)
break
}
}
Expand Down Expand Up @@ -333,6 +354,7 @@ extension CarPlayManager: CPApplicationDelegate {
interfaceController.setRootTemplate(mapTemplate, animated: false)

eventsManager.sendCarPlayConnectEvent()
os_log("CarInterfaceController did connect to window.", log: logger, type: .info)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that CPApplicationDelegate delegate methods are deprecated. We'll need similar logging for CPTemplateApplicationSceneDelegate as well. I think that it'd be also beneficial to log information regarding CPInterfaceController (e.g. its address, main template etc).


subscribeForNotifications()
}
Expand All @@ -351,6 +373,7 @@ extension CarPlayManager: CPApplicationDelegate {
carWindow = nil

eventsManager.sendCarPlayDisconnectEvent()
os_log("CarInterfaceController did disconnect from window.", log: logger, type: .info)

idleTimerCancellable = nil

Expand All @@ -362,6 +385,7 @@ extension CarPlayManager: CPApplicationDelegate {
mapTemplate.mapDelegate = self

let currentActivity: CarPlayActivity = .browsing
os_log("CarPlayActivity changed to browsing", log: logger, type: .debug)
mapTemplate.userInfo = [
CarPlayManager.currentActivityKey: currentActivity
]
Expand Down Expand Up @@ -392,7 +416,6 @@ extension CarPlayManager: CPApplicationDelegate {
} else if let mapButtons = browsingMapButtons(for: mapTemplate) {
mapTemplate.mapButtons = mapButtons
}

return mapTemplate
}

Expand All @@ -407,7 +430,6 @@ extension CarPlayManager: CPApplicationDelegate {
} else if let mapButtons = browsingMapButtons(for: mapTemplate) {
mapTemplate.mapButtons = mapButtons
}

mapTemplate.dismissPanningInterface(animated: false)
}
}
Expand Down Expand Up @@ -447,9 +469,12 @@ extension CarPlayManager: CPInterfaceControllerDelegate {
if let userInfo = template.userInfo as? Dictionary<String, Any>,
let currentActivity = userInfo[CarPlayManager.currentActivityKey] as? CarPlayActivity {
self.currentActivity = currentActivity
os_log("CarPlayActivity changed", log: logger, type: .debug)
} else {
self.currentActivity = nil
os_log("CarPlayActivity is nil", log: logger, type: .debug)
}
os_log("CarPlayManagerDelegate: template will appear", log: logger, type: .debug)
}

public func templateDidAppear(_ template: CPTemplate, animated: Bool) {
Expand All @@ -462,6 +487,7 @@ extension CarPlayManager: CPInterfaceControllerDelegate {
let navigationMapView = carPlayMapViewController.navigationMapView
navigationMapView.removeRoutes()
navigationMapView.removeWaypoints()
os_log("CarPlayManagerDelegate: template did disappear", log: logger, type: .debug)
}

public func templateWillDisappear(_ template: CPTemplate, animated: Bool) {
Expand All @@ -473,10 +499,12 @@ extension CarPlayManager: CPInterfaceControllerDelegate {
interfaceController.templates.count == 1 else { return }

navigationMapView?.navigationCamera.follow()
os_log("CarPlayManagerDelegate: template will disappear", log: logger, type: .debug)
}

public func templateDidDisappear(_ template: CPTemplate, animated: Bool) {
delegate?.carPlayManager(self, templateDidDisappear: template, animated: animated)
os_log("CarPlayManagerDelegate: template did disappear", log: logger, type: .debug)
}
}

Expand Down Expand Up @@ -561,6 +589,7 @@ extension CarPlayManager {

switch result {
case let .failure(error):
os_log("Failed to calculate routes.", log: logger, type: .error)
guard let delegate = delegate,
let alert = delegate.carPlayManager(self,
didFailToFetchRouteBetween: routeOptions.waypoints,
Expand Down Expand Up @@ -681,6 +710,7 @@ extension CarPlayManager: CPMapTemplateDelegate {
mapTemplate.mapDelegate = self

let currentActivity: CarPlayActivity = .navigating
os_log("CarPlayActivity changed to navigating", log: logger, type: .debug)
mapTemplate.userInfo = [
CarPlayManager.currentActivityKey: currentActivity
]
Expand Down Expand Up @@ -749,6 +779,7 @@ extension CarPlayManager: CPMapTemplateDelegate {
navigationMapView.removeWaypoints()
if let passiveLocationProvider = navigationMapView.mapView.location.locationProvider as? PassiveLocationProvider {
passiveLocationProvider.locationManager.resumeTripSession()
os_log("PassiveLocationProvider trip session resumed.", log: logger, type: .info)
}
delegate?.carPlayManagerDidEndNavigation(self)
}
Expand All @@ -775,9 +806,11 @@ extension CarPlayManager: CPMapTemplateDelegate {
if let carPlayNavigationViewController = carPlayNavigationViewController {
currentActivity = .panningInNavigationMode
traitCollection = carPlayNavigationViewController.traitCollection
os_log("CarPlayActivity changed to panning in navigation mode", log: logger, type: .debug)
} else if let carPlayMapViewController = self.carPlayMapViewController {
currentActivity = .panningInBrowsingMode
traitCollection = carPlayMapViewController.traitCollection
os_log("CarPlayActivity changed to panning in browsing mode", log: logger, type: .debug)
} else {
assertionFailure("Panning interface is only supported for free-drive or active-guidance navigation.")
return
Expand Down Expand Up @@ -909,6 +942,7 @@ extension CarPlayManager: CarPlayNavigationViewControllerDelegate {
interfaceController.dismissTemplate(animated: true)
// Unset existing main map template (fixes an issue with the buttons)
mainMapTemplate = nil
os_log("CarPlayManager did dismiss arrival UI.", log: logger, type: .info)

// Then (re-)create and assign new map template
let mapTemplate = previewMapTemplate()
Expand All @@ -919,6 +953,7 @@ extension CarPlayManager: CarPlayNavigationViewControllerDelegate {

if let passiveLocationProvider = navigationMapView?.mapView.location.locationProvider as? PassiveLocationProvider {
passiveLocationProvider.locationManager.resumeTripSession()
os_log("PassiveLocationProvider trip session resumed.", log: logger, type: .info)
}

self.carPlayNavigationViewController = nil
Expand Down Expand Up @@ -1003,6 +1038,7 @@ extension CarPlayManager {
interfaceController.setRootTemplate(mapTemplate, animated: false)

eventsManager.sendCarPlayConnectEvent()
os_log("CarPlayManager did connect InterfaceController.", log: logger, type: .info)

subscribeForNotifications()
}
Expand All @@ -1023,6 +1059,7 @@ extension CarPlayManager {
eventsManager.sendCarPlayDisconnectEvent()

idleTimerCancellable = nil
os_log("CarPlayManager did disconnect InterfaceController.", log: logger, type: .info)

unsubscribeFromNotifications()
}
Expand Down
4 changes: 4 additions & 0 deletions Sources/MapboxNavigation/CarPlayMapViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Foundation
@_spi(Restricted) import MapboxMaps
import MapboxCoreNavigation
import MapboxDirections
import os.log
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be useful to have logging information when CarPlayActivity value changes.


#if canImport(CarPlay)
import CarPlay
Expand Down Expand Up @@ -172,6 +173,7 @@ open class CarPlayMapViewController: UIViewController {

private var safeTrailingSpeedLimitViewConstraint: NSLayoutConstraint!
private var trailingSpeedLimitViewConstraint: NSLayoutConstraint!
private let logger: OSLog = .init(subsystem: "com.mapbox.navigation", category: "CarPlayMapViewController")

// MARK: Initialization Methods

Expand Down Expand Up @@ -278,12 +280,14 @@ open class CarPlayMapViewController: UIViewController {
selector: #selector(didUpdatePassiveLocation),
name: .passiveLocationManagerDidUpdate,
object: nil)
os_log("CarPlayMapViewController did subscribe to free drive notifications.", log: logger, type: .info)
}

func unsubscribeFromFreeDriveNotifications() {
NotificationCenter.default.removeObserver(self,
name: .passiveLocationManagerDidUpdate,
object: nil)
os_log("CarPlayMapViewController did unsubscribe from free drive notifications.", log: logger, type: .info)
}

@objc func didUpdatePassiveLocation(_ notification: Notification) {
Expand Down
10 changes: 10 additions & 0 deletions Sources/MapboxNavigation/CarPlayNavigationViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Foundation
import MapboxDirections
import MapboxCoreNavigation
@_spi(Restricted) import MapboxMaps
import os.log

#if canImport(CarPlay)
import CarPlay
Expand Down Expand Up @@ -94,6 +95,8 @@ open class CarPlayNavigationViewController: UIViewController, BuildingHighlighti

private var safeTrailingCompassViewConstraint: NSLayoutConstraint!
private var trailingCompassViewConstraint: NSLayoutConstraint!

private let logger: OSLog = .init(subsystem: "com.mapbox.navigation", category: "CarPlayNavigationViewController")

func setupOrnaments() {
let compassView = CarPlayCompassView()
Expand Down Expand Up @@ -149,8 +152,10 @@ open class CarPlayNavigationViewController: UIViewController, BuildingHighlighti
func updateTripEstimateStyle(_ userInterfaceStyle: UIUserInterfaceStyle) {
switch traitCollection.userInterfaceStyle {
case .dark:
os_log("TripEstimateStyle set to dark.", log: logger, type: .info)
mapTemplate.tripEstimateStyle = .dark
default:
os_log("TripEstimateStyle set to default/light.", log: logger, type: .info)
mapTemplate.tripEstimateStyle = .light
}
}
Expand Down Expand Up @@ -413,6 +418,7 @@ open class CarPlayNavigationViewController: UIViewController, BuildingHighlighti
super.traitCollectionDidChange(previousTraitCollection)

if previousTraitCollection?.userInterfaceStyle != traitCollection.userInterfaceStyle {
os_log("Trait collection changed.", log: logger, type: .info)
updateTripEstimateStyle(traitCollection.userInterfaceStyle)
updateManeuvers(navigationService.routeProgress)
}
Expand Down Expand Up @@ -516,6 +522,7 @@ open class CarPlayNavigationViewController: UIViewController, BuildingHighlighti
selector: #selector(didUpdateRoadNameFromStatus),
name: .currentRoadNameDidChange,
object: nil)
os_log("CarPlayNavigationViewController subscribed for notifications.", log: logger, type: .info)
}

func suspendNotifications() {
Expand All @@ -542,6 +549,7 @@ open class CarPlayNavigationViewController: UIViewController, BuildingHighlighti
NotificationCenter.default.removeObserver(self,
name: .currentRoadNameDidChange,
object: nil)
os_log("CarPlayNavigationViewController suspended notifications.", log: logger, type: .info)
}

@objc func visualInstructionDidChange(_ notification: NSNotification) {
Expand Down Expand Up @@ -648,6 +656,8 @@ open class CarPlayNavigationViewController: UIViewController, BuildingHighlighti
let simulatedSpeedMultiplier = notification.userInfo?[MapboxNavigationService.NotificationUserInfoKey.simulatedSpeedMultiplierKey] as? Double
else { return }

os_log("Simulation state did change.", log: logger, type: .info)

switch simulationState {
case .willBeginSimulation:
navigationMapView?.storeLocationProviderBeforeSimulation()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Foundation
import CarPlay
import MapboxDirections
import os.log

@available(iOS 12.0, *)
extension CarPlaySearchController: CPSearchTemplateDelegate {
Expand All @@ -21,6 +22,7 @@ extension CarPlaySearchController: CPSearchTemplateDelegate {
let template = CPListTemplate(title: delegate?.recentSearchText, sections: [section])
template.delegate = self
delegate?.pushTemplate(template, animated: true)
os_log("CarPlay search template search button pressed", log: logger, type: .debug)
}

public func searchTemplateButton(searchTemplate: CPSearchTemplate,
Expand Down Expand Up @@ -76,6 +78,7 @@ extension CarPlaySearchController: CPListTemplateDelegate {
let destinationWaypoint = Waypoint(location: location)
delegate?.popTemplate(animated: false)
delegate?.previewRoutes(to: destinationWaypoint, completionHandler: completionHandler)
os_log("Search item selected from list", log: logger, type: .debug)
return
}
}
Expand Down
3 changes: 3 additions & 0 deletions Sources/MapboxNavigation/CarPlaySearchController.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Foundation
import os.log

/**
`CarPlaySearchController` is the main object responsible for managing the search feature on CarPlay.
Expand All @@ -14,4 +15,6 @@ public class CarPlaySearchController: NSObject {
The `CarPlaySearchController` delegate.
*/
public weak var delegate: CarPlaySearchControllerDelegate?

let logger: OSLog = .init(subsystem: "com.mapbox.navigation", category: "CarPlaySearchController")
}
3 changes: 3 additions & 0 deletions Sources/MapboxNavigation/MapTemplateProvider.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import CarPlay
import os.log

@available(iOS 12.0, *)
class MapTemplateProvider: NSObject {
private let logger: OSLog = .init(subsystem: "com.mapbox.navigation", category: "MapTemplateProvider")

weak var delegate: MapTemplateProviderDelegate?

Expand All @@ -12,6 +14,7 @@ class MapTemplateProvider: NSObject {
mapTemplate.mapDelegate = mapDelegate

let currentActivity: CarPlayActivity = .previewing
os_log("CarPlayActivity changed to previewing", log: logger, type: .debug)

if let leadingButtons = delegate?.mapTemplateProvider(self,
mapTemplate: mapTemplate,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import MapboxMaps
import MapboxDirections
import MapboxCoreNavigation
import os.log

private let logger: OSLog = .init(subsystem: "com.mapbox.navigation", category: "RoadNameLabeling")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we use private global constants in other classes too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We needed one here since you can't create stored properties in extensions. For consistency, we should either move constants to be global or use a manager for these OSLog constants


extension NavigationMapView {

Expand All @@ -23,7 +26,7 @@ extension NavigationMapView {
do {
try mapView.mapboxMap.style.addSource(streetsSource, id: sourceIdentifier)
} catch {
NSLog("Failed to add \(sourceIdentifier) with error: \(error.localizedDescription).")
os_log("Failed to add %s with error: %s.", log: logger, type: .error, sourceIdentifier as CVarArg, error.localizedDescription)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The %s will be redacted out in the logs. Should it be %{public}s?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes. I will try this. Thank you

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need casting to CVarArg here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cast was needed since os_log uses StaticString

}
}

Expand Down Expand Up @@ -82,7 +85,7 @@ extension NavigationMapView {

try mapView.mapboxMap.style.addLayer(streetLabelLayer, layerPosition: layerPosition)
} catch {
NSLog("Failed to add \(roadLabelStyleLayerIdentifier) with error: \(error.localizedDescription).")
os_log("Failed to add %s with error: %s.", log: logger, type: .error, roadLabelStyleLayerIdentifier as CVarArg, error.localizedDescription)
}
}

Expand Down Expand Up @@ -164,7 +167,7 @@ extension NavigationMapView {
wayNameView.containerView.isHidden = hideWayName

case .failure:
NSLog("Failed to find visible features.")
os_log("Failed to find visible features.", log: logger, type: .error)
}
}
}
Expand Down