Skip to content

Commit

Permalink
improve logging & fix macOS 15 bug (#33)
Browse files Browse the repository at this point in the history
* improve logging & fix macOS 15 bug

* fix lint issues

* better build output

* fix captured mutating self parameter
  • Loading branch information
lukepistrol authored Sep 17, 2024
1 parent 427af26 commit be04824
Show file tree
Hide file tree
Showing 12 changed files with 187 additions and 16 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
-scheme "TimeMachineStatus" \
-configuration "Release" \
-derivedDataPath "$RUNNER_TEMP/DerivedData" \
DEVELOPMENT_TEAM=$APPLE_TEAM_ID
DEVELOPMENT_TEAM=$APPLE_TEAM_ID | xcbeautify
- name: Clean up keychain and provisioning profile
if: ${{ always() }}
Expand Down
4 changes: 4 additions & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,7 @@ identifier_name:

nesting:
type_level: 2

excluded:
- DerivedData
- build
4 changes: 4 additions & 0 deletions TimeMachineStatus.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
28263FA02B023FD100F74655 /* TimeMachineStatusHelper.app in Copy Helper */ = {isa = PBXBuildFile; fileRef = 28263F8E2B023D4E00F74655 /* TimeMachineStatusHelper.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
28263FA32B023FFE00F74655 /* ServiceManagement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 28263FA22B023FFE00F74655 /* ServiceManagement.framework */; };
2885D6652B024D0B00C260DB /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2885D6642B024D0B00C260DB /* main.swift */; };
2888D17C2C99B3E80081FBBB /* KeyedDecodingContainer+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2888D17B2C99B3E80081FBBB /* KeyedDecodingContainer+.swift */; };
288F12FB2B011A9300678FAD /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 288F12FA2B011A9300678FAD /* Localizable.xcstrings */; };
28A0021B2AFBBFC300E2A01E /* TimeMachineStatusApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28A0021A2AFBBFC300E2A01E /* TimeMachineStatusApp.swift */; };
28A0021D2AFBBFC300E2A01E /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28A0021C2AFBBFC300E2A01E /* SettingsView.swift */; };
Expand Down Expand Up @@ -96,6 +97,7 @@
28263FA22B023FFE00F74655 /* ServiceManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ServiceManagement.framework; path = System/Library/Frameworks/ServiceManagement.framework; sourceTree = SDKROOT; };
28263FA42B0241E200F74655 /* TimeMachineStatusHelper.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = TimeMachineStatusHelper.entitlements; sourceTree = "<group>"; };
2885D6642B024D0B00C260DB /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
2888D17B2C99B3E80081FBBB /* KeyedDecodingContainer+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KeyedDecodingContainer+.swift"; sourceTree = "<group>"; };
288F12FA2B011A9300678FAD /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
28A002172AFBBFC300E2A01E /* TimeMachineStatus.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TimeMachineStatus.app; sourceTree = BUILT_PRODUCTS_DIR; };
28A0021A2AFBBFC300E2A01E /* TimeMachineStatusApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeMachineStatusApp.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -260,6 +262,7 @@
2818227D2AFE36780067E564 /* Bundle+.swift */,
281822522AFCF97C0067E564 /* FormatStyle+.swift */,
281822662AFD86AC0067E564 /* Color+RawRepresentable.swift */,
2888D17B2C99B3E80081FBBB /* KeyedDecodingContainer+.swift */,
);
path = Extensions;
sourceTree = "<group>";
Expand Down Expand Up @@ -492,6 +495,7 @@
2818227E2AFE36780067E564 /* Bundle+.swift in Sources */,
28FAD5AD2AFF0D7200F642E7 /* ExpandableSection.swift in Sources */,
2818225F2AFD3FF20067E564 /* Stopping.swift in Sources */,
2888D17C2C99B3E80081FBBB /* KeyedDecodingContainer+.swift in Sources */,
28A0024F2AFC030500E2A01E /* Symbols.swift in Sources */,
28A0025E2AFC04D300E2A01E /* Mounting.swift in Sources */,
28FAD5AF2AFF0D9600F642E7 /* UserfacingErrorView.swift in Sources */,
Expand Down
24 changes: 24 additions & 0 deletions TimeMachineStatus/Extensions/KeyedDecodingContainer+.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// Decodable+.swift
// TimeMachineStatus
//
// Created by Lukas Pistrol on 17.09.24.
//
// Copyright © 2024 Lukas Pistrol. All rights reserved.
//
// See LICENSE.md for license information.
//

import Foundation

extension KeyedDecodingContainer {
func decodeBoolOrIntIfPresent(for key: K, defaultValue: Bool? = nil) throws -> Bool? {
if let boolValue = try? decodeIfPresent(Bool.self, forKey: key) {
return boolValue
} else if let intValue = try? decodeIfPresent(Int.self, forKey: key) {
return intValue == 1
} else {
return defaultValue
}
}
}
88 changes: 88 additions & 0 deletions TimeMachineStatus/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -1566,6 +1566,94 @@
}
}
},
"settings_item_loglevel" : {
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Log Level"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Log Level"
}
},
"it" : {
"stringUnit" : {
"state" : "translated",
"value" : "Log Level"
}
}
}
},
"settings_item_loglevel_debug" : {
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Debug"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Debug"
}
},
"it" : {
"stringUnit" : {
"state" : "translated",
"value" : "Debug"
}
}
}
},
"settings_item_loglevel_footer" : {
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Erfordert einen Neustart der App"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Requires restarting the app to take effect"
}
},
"it" : {
"stringUnit" : {
"state" : "translated",
"value" : "Per avere effetto è necessario riavviare l'app"
}
}
}
},
"settings_item_loglevel_info" : {
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "Info (Standard)"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Info (Default)"
}
},
"it" : {
"stringUnit" : {
"state" : "translated",
"value" : "Info (Predefinito)"
}
}
}
},
"settings_item_showpercentage" : {
"localizations" : {
"de" : {
Expand Down
2 changes: 1 addition & 1 deletion TimeMachineStatus/Model/BackupState/BackupState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ enum BackupState {
static func getState() throws -> _State {
let result = try shellOut(to: Constants.Commands.status)

log.trace("Raw State: \(result)")
log.trace("Raw State: \"\(result)\"")

guard let data = result.data(using: .utf8) else {
throw BackupStateError.couldNotConvertStringToData(string: result)
Expand Down
17 changes: 17 additions & 0 deletions TimeMachineStatus/Model/Preferences/Preferences.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,23 @@ struct Preferences: Decodable {
case skipPaths = "SkipPaths"
}

init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.autoBackup = try container.decodeBoolOrIntIfPresent(for: .autoBackup)
self.autoBackupInterval = try container.decodeIfPresent(Int.self, forKey: .autoBackupInterval)
self.excludedVolumeUUIDs = try container.decodeIfPresent([UUID].self, forKey: .excludedVolumeUUIDs)
self.preferencesVersion = try container.decode(Int.self, forKey: .preferencesVersion)
self.requiresACPower = try container.decodeBoolOrIntIfPresent(for: .requiresACPower)
self.lastConfigurationTraceDate = try container.decodeIfPresent(Date.self, forKey: .lastConfigurationTraceDate)
self.lastDestinationID = try container.decodeIfPresent(UUID.self, forKey: .lastDestinationID)
self.localizedDiskImageVolumeName = try container.decodeIfPresent(
String.self,
forKey: .localizedDiskImageVolumeName
)
self.destinations = try container.decodeIfPresent([Destination].self, forKey: .destinations)
self.skipPaths = try container.decodeIfPresent([String].self, forKey: .skipPaths)
}

let autoBackup: Bool?
let autoBackupInterval: Int?
let excludedVolumeUUIDs: [UUID]?
Expand Down
7 changes: 5 additions & 2 deletions TimeMachineStatus/TimeMachineStatusApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,20 @@ import SwiftUI
@main
struct TimeMachineStatusApp: App {

@AppStorage(StorageKeys.logLevel.id)
private var logLevel: Logging.Logger.Level = StorageKeys.logLevel.default

@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

init() {
LoggingSystem.bootstrap { id in
LoggingSystem.bootstrap { [logLevel] id in
var mpx = MultiplexLogHandler([
LoggingOSLog(label: id)
])
#if DEBUG
mpx.logLevel = .trace
#else
mpx.logLevel = .info
mpx.logLevel = logLevel
#endif
return mpx
}
Expand Down
19 changes: 13 additions & 6 deletions TimeMachineStatus/ViewModel/TMUtility.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,14 @@ class TMUtility: ObservableObject {

func startBackup(id: UUID? = nil) {
do {
_ = if let id {
try shellOut(to: Constants.Commands.startBackup(id: id))
if let id {
log.info("Starting backup with id: \(id)")
let result = try shellOut(to: Constants.Commands.startBackup(id: id))
log.trace("Started backup: \(result)")
} else {
try shellOut(to: Constants.Commands.startBackup())
log.info("Starting backup")
let result = try shellOut(to: Constants.Commands.startBackup())
log.trace("Started backup: \(result)")
}
start(force: true)
} catch {
Expand All @@ -94,8 +98,9 @@ class TMUtility: ObservableObject {

func stopBackup() {
do {
let response = try shellOut(to: Constants.Commands.stopBackup)
print(response)
log.info("Stopping backup")
let result = try shellOut(to: Constants.Commands.stopBackup)
log.trace("Stopped backup: \(result)")
start(force: true)
} catch {
log.error("Error stopping backup: \(error)")
Expand All @@ -104,7 +109,9 @@ class TMUtility: ObservableObject {

func launchTimeMachine() {
do {
_ = try shellOut(to: Constants.Commands.launchTimeMachine)
log.info("Launching time machine")
let result = try shellOut(to: Constants.Commands.launchTimeMachine)
log.trace("Launched time machine: \(result)")
} catch {
log.error("Error launching time machine: \(error)")
}
Expand Down
8 changes: 6 additions & 2 deletions TimeMachineStatus/ViewModel/UpdaterViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,17 @@

import Combine
import Foundation
import Logging
import Sparkle

class UpdaterViewModel: ObservableObject {
@Published private (set) var canCheckForUpdates = false

private let log = Logger(label: "\(Bundle.identifier).UpdaterViewModel")

@Published private(set) var canCheckForUpdates = false
@Published var automaticallyChecksForUpdates: Bool {
didSet {
print(automaticallyChecksForUpdates)
log.debug("Automatically checks for update changed: \(automaticallyChecksForUpdates)")
updater.automaticallyChecksForUpdates = automaticallyChecksForUpdates
}
}
Expand Down
21 changes: 19 additions & 2 deletions TimeMachineStatus/Views/SettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
// See LICENSE.md for license information.
//

import Logging
import Sparkle
import SwiftUI

Expand All @@ -29,6 +30,8 @@ enum StorageKeys {
static let cornerRadius = Key(id: "cornerRadius", default: 5.0)
static let showPercentage = Key(id: "showPercentage", default: true)
static let animateIcon = Key(id: "animateIcon", default: true)

static let logLevel = Key(id: "logLevel", default: Logger.Level.info)
}

struct SettingsView: View {
Expand Down Expand Up @@ -63,6 +66,9 @@ struct SettingsView: View {
@AppStorage(StorageKeys.animateIcon.id)
private var animateIcon: Bool = StorageKeys.animateIcon.default

@AppStorage(StorageKeys.logLevel.id)
private var logLevel: Logger.Level = StorageKeys.logLevel.default

private enum Tabs: Hashable, CaseIterable {
case general
case appearance
Expand All @@ -71,8 +77,8 @@ struct SettingsView: View {
var height: Double {
switch self {
case .about: 350
case .appearance: 410
case .general: 250
case .appearance: 450
case .general: 320
}
}

Expand Down Expand Up @@ -134,6 +140,17 @@ struct SettingsView: View {
isOn: $updaterViewModel.automaticallyChecksForUpdates
)
}
Section {
Picker("settings_item_loglevel", selection: $logLevel) {
Text("settings_item_loglevel_debug").tag(Logger.Level.trace)
Text("settings_item_loglevel_info").tag(Logger.Level.info)
}
} footer: {
Text("settings_item_loglevel_footer")
.font(.footnote)
.foregroundStyle(.secondary)
.frame(maxWidth: .infinity, alignment: .leading)
}
}
.formStyle(.grouped)
.tabItem {
Expand Down
7 changes: 5 additions & 2 deletions TimeMachineStatus/Views/StatusBarItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
//

import Combine
import Logging
import SwiftUI

struct ItemSizePreferenceKey: PreferenceKey {
Expand Down Expand Up @@ -57,6 +58,8 @@ struct StatusBarItem: View {
var sizePassthrough: PassthroughSubject<CGSize, Never>
@ObservedObject var utility: TMUtility

private let log = Logger(label: "\(Bundle.identifier).StatusBarItem")

private var mainContent: some View {
HStack(spacing: spacing) {
if utility.isIdle {
Expand Down Expand Up @@ -98,12 +101,12 @@ struct StatusBarItem: View {
}
)
.onPreferenceChange(ItemSizePreferenceKey.self) { size in
print("Size: \(size)")
log.trace("Size: \(size)")
sizePassthrough.send(size)
}
.offset(y: -1)
.onChange(of: utility.isIdle) { oldValue, newValue in
print("Changed: \(oldValue) -> \(newValue)")
log.trace("Changed: \(oldValue) -> \(newValue)")
}
}

Expand Down

0 comments on commit be04824

Please sign in to comment.