better logging

This commit is contained in:
Andy Pack 2022-11-23 23:39:58 +00:00
parent d73ec449cf
commit a3b1a67b5b
Signed by: sarsoo
GPG Key ID: A55BA3536A5E0ED7
12 changed files with 154 additions and 49 deletions

View File

@ -8,6 +8,7 @@
import UIKit
import SwiftyJSON
import OSLog
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
@ -34,3 +35,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
}
extension Logger {
private static var subsystem = Bundle.main.bundleIdentifier!
/// Logs the view cycles like viewDidLoad.
static let net = Logger(subsystem: subsystem, category: "net")
static let parse = Logger(subsystem: subsystem, category: "parse")
static let sys = Logger(subsystem: subsystem, category: "sys")
}

View File

@ -10,6 +10,7 @@ import Foundation
import Alamofire
import SwiftyJSON
import KeychainAccess
import OSLog
class LiveUser: ObservableObject {
@ -54,6 +55,8 @@ class LiveUser: ObservableObject {
func logout() {
let keychain = Keychain(service: "xyz.sarsoo.music.login")
Logger.sys.info("logging user out")
do {
try keychain.remove("username")
try keychain.remove("jwt")
@ -68,8 +71,10 @@ class LiveUser: ObservableObject {
self.loggedIn = false
Logger.sys.debug("successfully logged user out")
} catch let error {
debugPrint("Could not clear keychain, \(error)")
Logger.sys.error("could not clear keychain, \(error)")
}
}
@ -83,17 +88,21 @@ class LiveUser: ObservableObject {
func refresh_user(onSuccess: (() -> Void)? = nil, onFailure: (() -> Void)? = nil) {
self.isRefreshingUser = true
Logger.sys.info("refreshing user")
let api = UserApi.getUser
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
if self.check_network_response(response: response) {
guard let data = response.data else {
fatalError("error getting user")
Logger.net.error("error getting user")
return
}
guard let json = try? JSON(data: data) else {
fatalError("error parsing user")
Logger.parse.error("error parsing user")
return
}
// update state
@ -102,12 +111,14 @@ class LiveUser: ObservableObject {
self.isRefreshingUser = false
if let success = onSuccess {
Logger.sys.debug("successfully refreshed user")
success()
}
} else {
if let failure = onFailure {
Logger.net.error("failed to refresh user")
failure()
}
}
@ -117,17 +128,21 @@ class LiveUser: ObservableObject {
func refresh_playlists(onSuccess: (() -> Void)? = nil, onFailure: (() -> Void)? = nil) {
self.isRefreshingPlaylists = true
Logger.sys.info("refreshing playlists")
let api = PlaylistApi.getPlaylists
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
if self.check_network_response(response: response) {
guard let data = response.data else {
fatalError("error getting playlists")
Logger.net.error("error getting playlists from net request")
return
}
guard let json = try? JSON(data: data) else {
fatalError("error parsing reponse")
Logger.parse.error("error parsing playlists reponse")
return
}
let playlists = json["playlists"].arrayValue
@ -138,6 +153,7 @@ class LiveUser: ObservableObject {
self.isRefreshingPlaylists = false
if let success = onSuccess {
Logger.sys.debug("successfully refreshed playlists")
success()
}
@ -145,12 +161,13 @@ class LiveUser: ObservableObject {
do {
UserDefaults.standard.set(String(data: try encoder.encode(playlists), encoding: .utf8), forKey: "playlists")
} catch {
print("error encoding playlists: \(error)")
Logger.parse.error("error encoding playlists: \(error)")
}
} else {
if let failure = onFailure {
Logger.net.error("failed to refresh playlists")
failure()
}
}
@ -159,6 +176,8 @@ class LiveUser: ObservableObject {
func refresh_tags(onSuccess: (() -> Void)? = nil, onFailure: (() -> Void)? = nil) {
self.isRefreshingTags = true
Logger.sys.info("refreshing tags")
let api = TagApi.getTags
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
@ -166,11 +185,13 @@ class LiveUser: ObservableObject {
if self.check_network_response(response: response) {
guard let data = response.data else {
fatalError("error getting tags")
Logger.net.error("error getting tags")
return
}
guard let json = try? JSON(data: data) else {
fatalError("error parsing reponse")
Logger.parse.error("error parsing tags response")
return
}
let tags = json["tags"].arrayValue
@ -181,6 +202,7 @@ class LiveUser: ObservableObject {
self.isRefreshingTags = false
if let success = onSuccess {
Logger.sys.debug("successfully refreshed tags")
success()
}
@ -188,12 +210,13 @@ class LiveUser: ObservableObject {
do {
UserDefaults.standard.set(String(data: try encoder.encode(tags), encoding: .utf8), forKey: "tags")
} catch {
print("error encoding tags: \(error)")
Logger.parse.error("error encoding tags: \(error)")
}
} else {
if let failure = onFailure {
Logger.net.error("failed to refresh tags")
failure()
}
}
@ -205,21 +228,28 @@ class LiveUser: ObservableObject {
if let statusCode = response.response?.statusCode {
switch statusCode {
case 401: // token has expired
Logger.sys.info("token expired, logging user out")
self.logout()
return false
case 400..<500:
Logger.net.error("client fault \(statusCode)")
return false
case 500..<600:
Logger.net.warning("server fault \(statusCode)")
return false
case _: // 200 -> Success
return true
}
}
Logger.net.error("live user failed to access status code to check")
return false
}
func load_user_defaults() -> LiveUser {
Logger.sys.debug("loading user defaults")
let defaults = UserDefaults.standard
let decoder = JSONDecoder()
@ -230,17 +260,19 @@ class LiveUser: ObservableObject {
do {
if let _strPlaylists = _strPlaylists {
if _strPlaylists.count > 0 {
Logger.sys.debug("reading \(_strPlaylists.count) playlists")
self.playlists = (try decoder.decode([Playlist].self, from: _strPlaylists.data(using: .utf8)!)).sorted(by: { $0.name.lowercased() < $1.name.lowercased() })
}
}
if let _strTags = _strTags {
if _strTags.count > 0 {
Logger.sys.debug("reading \(_strTags.count) tags")
self.tags = (try decoder.decode([Tag].self, from: _strTags.data(using: .utf8)!)).sorted(by: { $0.name.lowercased() < $1.name.lowercased() })
}
}
} catch {
print("error decoding: \(error)")
Logger.parse.error("error parsing user defaults: \(error)")
}
return self

View File

@ -9,6 +9,7 @@
import Foundation
import UIKit
import SwiftyJSON
import OSLog
class Playlist: Identifiable, Equatable, Codable, ObservableObject {
@ -121,7 +122,7 @@ class Playlist: Identifiable, Equatable, Codable, ObservableObject {
case 200, 201:
break
case _:
debugPrint("error: \(self.name), \(updates)")
Logger.net.error("error: \(self.name), \(updates)")
}
}
//TODO: do better error checking
@ -261,7 +262,7 @@ class Playlist: Identifiable, Equatable, Codable, ObservableObject {
username = try container.decode(String.self, forKey: .username)
}catch {
username = "NO USER"
debugPrint("failed to parse username")
Logger.parse.warning("failed to parse username")
}
type = try container.decode(String.self, forKey: .type)
@ -269,13 +270,11 @@ class Playlist: Identifiable, Equatable, Codable, ObservableObject {
do{
description_overwrite = try container.decode(String.self, forKey: .description_overwrite)
}catch {
// debugPrint("no description overwrite")
}
do{
description_suffix = try container.decode(String.self, forKey: .description_suffix)
}catch {
// debugPrint("no description suffix")
}
last_updated = try container.decode(String.self, forKey: .last_updated)
@ -296,7 +295,6 @@ class Playlist: Identifiable, Equatable, Codable, ObservableObject {
include_library_tracks = try container.decode(Bool.self, forKey: .include_library_tracks)
}catch {
include_library_tracks = false
// debugPrint("failed to parse include_library_tracks")
}
parts = try container.decode([String].self, forKey: .parts)
@ -307,42 +305,36 @@ class Playlist: Identifiable, Equatable, Codable, ObservableObject {
sort = try container.decode(String.self, forKey: .sort)
}catch {
sort = "release_date"
// debugPrint("failed to parse sort value")
}
do {
add_last_month = try container.decode(Bool.self, forKey: .add_last_month)
}catch {
add_last_month = false
// debugPrint("failed to parse add last month")
}
do {
add_this_month = try container.decode(Bool.self, forKey: .add_this_month)
}catch {
add_this_month = false
// debugPrint("failed to parse add this month")
}
do {
day_boundary = try container.decode(Int.self, forKey: .day_boundary)
}catch {
day_boundary = 21
// debugPrint("failed to parse day boundary")
}
do{
chart_range = try LastFmRange(rawValue: container.decode(String.self, forKey: .chart_range)) ?? LastFmRange.month
}catch {
chart_range = .halfyear
// debugPrint("failed to parse chart_range")
}
do{
chart_limit = try container.decode(Int.self, forKey: .chart_limit)
}catch {
chart_limit = 50
// debugPrint("failed to parse chart_limit")
}
}

View File

@ -8,6 +8,7 @@
import UIKit
import SwiftyJSON
import OSLog
enum UserType: String, Decodable {
case user = "user"
@ -69,7 +70,7 @@ class User: Identifiable, Decodable {
case 200, 201:
break
case _:
debugPrint("error: \(updates)")
Logger.net.error("error while updating user: \(updates)")
}
}
//TODO: do better error checking

View File

@ -9,6 +9,7 @@
import Foundation
import Alamofire
import SwiftyJSON
import OSLog
let txTypeHeaders = ["default", "recents", "fmchart"]
@ -145,7 +146,7 @@ extension PlaylistApi: ApiRequest {
let playlist = try decoder.decode(Playlist.self, from: playlist)
return playlist
} catch {
print(error)
Logger.parse.error("error parsing playlist from json: \(error)")
}
return nil
}
@ -160,7 +161,7 @@ extension PlaylistApi: ApiRequest {
let playlist = try decoder.decode(Playlist.self, from: data)
return playlist
} catch {
print(error)
Logger.parse.error("error parsing playlist from json: \(error)")
}
}
return nil

View File

@ -9,6 +9,7 @@
import Foundation
import Alamofire
import SwiftyJSON
import OSLog
public enum TagApi {
case getTags
@ -110,7 +111,7 @@ extension TagApi: ApiRequest {
let _tag = try decoder.decode(Tag.self, from: data)
return _tag
} catch {
print(error)
Logger.parse.error("error parsing tag from json: \(error)")
}
}
return nil

View File

@ -9,6 +9,7 @@
import Foundation
import Alamofire
import SwiftyJSON
import OSLog
public enum UserApi {
case getUser
@ -76,7 +77,7 @@ extension UserApi: ApiRequest {
let user = try decoder.decode(User.self, from: user)
return user
} catch {
print(error)
Logger.parse.error("error parsing user from json: \(error)")
}
return nil
}
@ -91,7 +92,7 @@ extension UserApi: ApiRequest {
let user = try decoder.decode(User.self, from: data)
return user
} catch {
print(error)
Logger.parse.error("error parsing user from json: \(error)")
}
}
return nil

View File

@ -8,6 +8,7 @@
import SwiftUI
import SwiftyJSON
import OSLog
struct UsersList: View {
@ -48,11 +49,13 @@ struct UsersList: View {
if self.liveUser.check_network_response(response: response) {
guard let data = response.data else {
fatalError("error getting users")
Logger.net.error("failed to get users")
return
}
guard let json = try? JSON(data: data) else {
fatalError("error parsing user")
Logger.parse.error("failed to get users")
return
}
// update state
@ -62,7 +65,7 @@ struct UsersList: View {
})
} else {
Logger.net.error("failed to get users from view")
}
}
}

View File

@ -10,6 +10,7 @@ import SwiftUI
import ToastUI
import KeychainAccess
import SwiftyJSON
import OSLog
enum ScreenMode {
case None
@ -83,27 +84,34 @@ struct LoginScreen: View {
keychain["username"] = username
Logger.sys.debug("making login request")
let api = AuthApi.token(username: username, password: password, expiry: 604800)
RequestBuilder.buildRequest(apiRequest: api)
.validate()
.responseJSON { response in
switch response.response?.statusCode {
let code = response.response?.statusCode ?? -1
switch code {
case 200, 201:
guard let data = response.data else {
fatalError("error getting token")
Logger.net.error("failed to get API token from request")
return
}
guard let json = try? JSON(data: data) else {
fatalError("error parsing reponse")
Logger.parse.error("failed to parse API token")
return
}
let token = json["token"].stringValue
keychain["jwt"] = token
self.liveUser.loggedIn = true
Logger.net.info("login succeeded (\(code))")
case _:
keychain["username"] = nil
@ -111,6 +119,14 @@ struct LoginScreen: View {
toastText = "Login Failed"
showingToast = true
if let data = response.data {
Logger.net.info("login failed (\(code)): \(data)")
return
}
else {
Logger.net.info("login failed (\(code))")
}
}
}
}) {
@ -127,28 +143,38 @@ struct LoginScreen: View {
keychain["username"] = username
Logger.sys.debug("making register request")
let api = AuthApi.register(username: username, password: password, password2: password2)
RequestBuilder.buildRequest(apiRequest: api)
.validate()
.responseJSON { response in
switch response.response?.statusCode {
let registerCode = response.response?.statusCode ?? -1
switch registerCode {
case 200, 201:
Logger.net.debug("register request succeeded, logging in")
let token_api = AuthApi.token(username: username, password: password, expiry: 604800)
RequestBuilder.buildRequest(apiRequest: token_api)
.validate()
.responseJSON { response in
switch response.response?.statusCode {
let loginCode = response.response?.statusCode ?? -1
switch loginCode {
case 200, 201:
guard let data = response.data else {
fatalError("error getting token")
Logger.net.error("failed to get API token for register from login request")
return
}
guard let json = try? JSON(data: data) else {
fatalError("error parsing reponse")
Logger.parse.error("failed to parse API token for register from login request")
return
}
let token = json["token"].stringValue
@ -163,14 +189,21 @@ struct LoginScreen: View {
toastText = "Token Generation Failed"
showingToast = true
Logger.net.error("failed to login post-registration (\(loginCode)")
}
}
// TODO: add handling for 400, password dont match
// TODO: add handling for 409, conflict
case 400:
Logger.net.info("register failed, passwords didn't match (400)")
case 409:
Logger.net.info("register failed, username already exists (409)")
case _:
Logger.net.info("register request failed (\(registerCode)")
keychain["username"] = nil
keychain["jwt"] = nil

View File

@ -10,6 +10,7 @@ import SwiftUI
import ToastUI
import SwiftyJSON
import SwiftUICharts
import OSLog
struct PlaylistView: View {
@ -239,6 +240,9 @@ struct PlaylistView: View {
}
func runPlaylist() {
Logger.net.debug("running playlist from view: \(self.playlist.name)")
let api = PlaylistApi.runPlaylist(name: playlist.name)
RequestBuilder.buildRequest(apiRequest: api)
.validate()
@ -250,16 +254,23 @@ struct PlaylistView: View {
toastSuccess = true
showingToast = true
Logger.net.debug("playlist run queued from view: \(self.playlist.name)")
} else {
toastText = "Run Request Failed"
toastSuccess = false
showingToast = true
Logger.net.debug("playlist run request failed from view: \(self.playlist.name)")
}
}
}
func refreshStats() {
Logger.net.debug("refreshing playlist stats from view: \(self.playlist.name)")
let api = PlaylistApi.refreshStats(name: playlist.name)
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
@ -269,43 +280,56 @@ struct PlaylistView: View {
toastSuccess = true
showingToast = true
Logger.net.debug("stat refresh queued from view: \(self.playlist.name)")
} else {
toastText = "Stat Refresh Failed"
toastSuccess = false
showingToast = true
Logger.net.debug("stat refresh request failed from view: \(self.playlist.name)")
}
}
}
func openPlaylist() {
Logger.sys.debug("attempting to open \(self.playlist.link)")
if let url = URL(string: self.playlist.link) {
UIApplication.shared.open(url)
}
}
func updatePlaylist(updates: JSON) {
Logger.net.debug("updating playlist from view: \(self.playlist.name)")
let api = PlaylistApi.updatePlaylist(name: playlist.name, updates: updates)
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
if self.liveUser.check_network_response(response: response) {
debugPrint("success")
Logger.net.debug("updated playlist from view")
} else {
debugPrint("error")
Logger.net.error("failed to update playlist from view")
}
}
//TODO: do better error checking
}
func refreshPlaylist() {
Logger.net.debug("Refreshing playlist: \(self.playlist.name)")
let api = PlaylistApi.getPlaylist(name: self.playlist.name)
RequestBuilder.buildRequest(apiRequest: api).responseJSON{ response in
if self.liveUser.check_network_response(response: response) {
guard let data = response.data else {
fatalError("error getting playlist")
Logger.net.error("failed to get playlist from net request")
return
}
self.playlist = PlaylistApi.fromJSON(playlist: data)!
@ -314,7 +338,11 @@ struct PlaylistView: View {
toastSuccess = true
showingToast = true
Logger.net.debug("Successfully refreshed playlist: \(self.playlist.name)")
} else {
Logger.net.error("request failed for get playlist")
toastText = "Refresh Failed"
toastSuccess = false

View File

@ -8,6 +8,7 @@
import SwiftUI
import ToastUI
import OSLog
struct Name: Identifiable, Hashable {
var id = UUID()
@ -74,7 +75,7 @@ struct SpotInputList: View {
showingToast = true
}
else {
print("Failed to add playlist: \(response.response?.statusCode ?? 0)")
Logger.net.error("Failed to add playlist: \(response.response?.statusCode ?? 0)")
toastText = "Failed to add playlist"
toastSuccess = false
showingToast = true

View File

@ -9,6 +9,7 @@
import SwiftUI
import SwiftyJSON
import SwiftUICharts
import OSLog
struct TagView: View {
@ -149,11 +150,13 @@ struct TagView: View {
if self.liveUser.check_network_response(response: response) {
guard let data = response.data else {
fatalError("error getting tag")
Logger.net.error("failed to get tag from net request")
return
}
guard let json = try? JSON(data: data) else {
fatalError("error parsing reponse")
Logger.net.error("failed to parse tag")
return
}
let _tag = TagApi.fromJSON(tag: json["tag"])
if let tag = _tag {
@ -161,7 +164,7 @@ struct TagView: View {
}
} else {
Logger.net.error("request failed for refresh tag")
}
self.isRefreshing = false