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

improve logging & fix macOS 15 bug #33

Merged
merged 4 commits into from
Sep 17, 2024
Merged
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
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
Loading