Add log export option (#7)

This commit is contained in:
pascal-fischer
2024-04-30 11:45:27 +02:00
committed by GitHub
parent ae50616f8a
commit cd954d80cd
7 changed files with 181 additions and 20 deletions
+10 -4
View File
@@ -76,7 +76,9 @@
50CD81B02AD5B94D00CF830B /* PeerCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50CD81AF2AD5B94D00CF830B /* PeerCard.swift */; };
50CD81B12AD5B94D00CF830B /* PeerCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50CD81AF2AD5B94D00CF830B /* PeerCard.swift */; };
50CD84362AD82F9400CF830B /* ServerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50CD84352AD82F9400CF830B /* ServerView.swift */; };
50D402902BD8188C00D4AC5B /* NetBirdSDK.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50D4028F2BD8188C00D4AC5B /* NetBirdSDK.xcframework */; };
50D402922BD913D100D4AC5B /* DirectoryPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50D402912BD913D100D4AC5B /* DirectoryPicker.swift */; };
50D402942BD9143900D4AC5B /* NetBirdSDK.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50D402932BD9143900D4AC5B /* NetBirdSDK.xcframework */; };
50D402952BD9143900D4AC5B /* NetBirdSDK.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50D402932BD9143900D4AC5B /* NetBirdSDK.xcframework */; };
50E608132A7958B100BAF09B /* MainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E608122A7958B100BAF09B /* MainViewModel.swift */; };
50E608202A7979D600BAF09B /* SideDrawer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E6081F2A7979D600BAF09B /* SideDrawer.swift */; };
50E608242A79966600BAF09B /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E608232A79966600BAF09B /* AboutView.swift */; };
@@ -153,7 +155,8 @@
50CD81A62AD5504B00CF830B /* StatusDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusDetails.swift; sourceTree = "<group>"; };
50CD81AF2AD5B94D00CF830B /* PeerCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeerCard.swift; sourceTree = "<group>"; };
50CD84352AD82F9400CF830B /* ServerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerView.swift; sourceTree = "<group>"; };
50D4028F2BD8188C00D4AC5B /* NetBirdSDK.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = NetBirdSDK.xcframework; path = NetBird/NetBirdSDK.xcframework; sourceTree = "<group>"; };
50D402912BD913D100D4AC5B /* DirectoryPicker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DirectoryPicker.swift; sourceTree = "<group>"; };
50D402932BD9143900D4AC5B /* NetBirdSDK.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = NetBirdSDK.xcframework; path = NetBird/NetBirdSDK.xcframework; sourceTree = "<group>"; };
50E608022A7950CB00BAF09B /* Device.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Device.swift; sourceTree = "<group>"; };
50E608122A7958B100BAF09B /* MainViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewModel.swift; sourceTree = "<group>"; };
50E6081F2A7979D600BAF09B /* SideDrawer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideDrawer.swift; sourceTree = "<group>"; };
@@ -167,6 +170,7 @@
buildActionMask = 2147483647;
files = (
508BD8492AF140D50055E415 /* FirebaseAnalyticsSwift in Frameworks */,
50D402952BD9143900D4AC5B /* NetBirdSDK.xcframework in Frameworks */,
50245A542A80431B0034792B /* NetworkExtension.framework in Frameworks */,
50003BBE2AFBCA7900E5EB6B /* FirebasePerformance in Frameworks */,
508BD84B2AF140D50055E415 /* FirebaseCrashlytics in Frameworks */,
@@ -186,7 +190,7 @@
50051DE02AE69A8100AFBDC4 /* FirebaseCrashlytics in Frameworks */,
50003BBC2AFBCA6B00E5EB6B /* FirebasePerformance in Frameworks */,
5051190F2AE03F68003027D3 /* FirebaseAnalytics in Frameworks */,
50D402902BD8188C00D4AC5B /* NetBirdSDK.xcframework in Frameworks */,
50D402942BD9143900D4AC5B /* NetBirdSDK.xcframework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -246,7 +250,7 @@
50A8910E2A792A15007C48FC = {
isa = PBXGroup;
children = (
50D4028F2BD8188C00D4AC5B /* NetBirdSDK.xcframework */,
50D402932BD9143900D4AC5B /* NetBirdSDK.xcframework */,
506331F72AF1676B00BC8F0E /* GoogleService-Info.plist */,
50245A0A2A7AA9390034792B /* NetBird-Bridging-Header.h */,
50A891192A792A15007C48FC /* NetBird */,
@@ -325,6 +329,7 @@
50E608092A79557A00BAF09B /* Components */ = {
isa = PBXGroup;
children = (
50D402912BD913D100D4AC5B /* DirectoryPicker.swift */,
50E6081F2A7979D600BAF09B /* SideDrawer.swift */,
502455BC2A79B0480034792B /* CustomBackButton.swift */,
502455BE2A79B4500034792B /* SolidButton.swift */,
@@ -568,6 +573,7 @@
50216D8E2ACB1905009574C9 /* NetworkChangeListener.swift in Sources */,
50CD81A72AD5504B00CF830B /* StatusDetails.swift in Sources */,
505118CE2AD96ECA003027D3 /* x25519.c in Sources */,
50D402922BD913D100D4AC5B /* DirectoryPicker.swift in Sources */,
508BD8452AF04A990055E415 /* SafariView.swift in Sources */,
505118D02AD96ECA003027D3 /* key.c in Sources */,
50E608262A79968500BAF09B /* AdvancedView.swift in Sources */,
@@ -18,6 +18,7 @@ class ViewModel: ObservableObject {
@Published var showInvalidServerAlert = false
@Published var showInvalidSetupKeyHint = false
@Published var showInvalidSetupKeyAlert = false
@Published var showLogLevelChangedAlert = false
@Published var showInvalidPresharedKeyAlert = false
@Published var showServerChangedInfo = false
@Published var showPreSharedKeyChangedInfo = false
@@ -39,6 +40,17 @@ class ViewModel: ObservableObject {
@Published var extensionStateText = "Disconnected"
@Published var connectPressed = false
@Published var disconnectPressed = false
@Published var traceLogsEnabled: Bool {
didSet {
self.showLogLevelChangedAlert = true
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
self.showLogLevelChangedAlert = false
}
let logLevel = traceLogsEnabled ? "TRACE" : "INFO"
UserDefaults.standard.set(logLevel, forKey: "logLevel")
UserDefaults.standard.synchronize()
}
}
var preferences = Preferences.newPreferences()
var buttonLock = false
let defaults = UserDefaults.standard
@@ -48,6 +60,8 @@ class ViewModel: ObservableObject {
private var cancellables = Set<AnyCancellable>()
init() {
let logLevel = UserDefaults.standard.string(forKey: "logLevel") ?? "INFO"
self.traceLogsEnabled = logLevel == "TRACE"
self.rosenpassEnabled = self.getRosenpassEnabled()
self.rosenpassPermissive = self.getRosenpassPermissive()
@@ -11,6 +11,8 @@ struct AdvancedView: View {
@EnvironmentObject var viewModel: ViewModel
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
@State private var directoryPickerPresented = false
var body: some View {
ZStack {
Color("BgPage")
@@ -44,7 +46,19 @@ struct AdvancedView: View {
}
}
}
.padding(.top, 10)
Divider()
.padding([.top, .bottom])
Toggle(isOn: $viewModel.traceLogsEnabled, label: {
Text("Enable Trace logs.")
.multilineTextAlignment(.leading)
.font(.system(size: 18, weight: .regular))
.foregroundColor(Color("TextSecondary"))
.padding(.top, 3)
.padding(.top, 5)
SolidButton(text: "Share logs") {
directoryPickerPresented = true
}
Divider()
.padding([.top, .bottom])
Toggle(isOn: $viewModel.rosenpassEnabled, label: {
@@ -54,6 +68,7 @@ struct AdvancedView: View {
.foregroundColor(Color("TextSecondary"))
.padding(.top, 3)
})
.padding(.top, 10)
.onChange(of: viewModel.rosenpassEnabled) { value in
if !value {
viewModel.rosenpassPermissive = false
@@ -76,6 +91,20 @@ struct AdvancedView: View {
Spacer()
}
.padding([.leading, .trailing], UIScreen.main.bounds.width * 0.10)
if viewModel.showLogLevelChangedAlert {
Color.black.opacity(0.4)
.edgesIgnoringSafeArea(.all)
.onTapGesture {
viewModel.buttonLock = true
viewModel.showLogLevelChangedAlert = false
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
viewModel.buttonLock = false
}
}
LogLevelAlert(viewModel: viewModel, isPresented: $viewModel.showLogLevelChangedAlert)
.frame(maxWidth: UIScreen.main.bounds.width * 0.9)
}
}
.onAppear(perform: {
viewModel.loadPreSharedKey()
@@ -89,6 +118,38 @@ struct AdvancedView: View {
.onTapGesture {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
.sheet(isPresented: $directoryPickerPresented) {
DirectoryPicker { url in
print("Directory selected: \(url)")
saveLogFile(at: url)
}
}
}
func saveLogFile(at url: URL?) {
guard let url = url else { return }
let fileManager = FileManager.default
guard let groupURL = fileManager.containerURL(forSecurityApplicationGroupIdentifier: "group.io.netbird.app") else {
print("Failed to retrieve the group URL")
return
}
let logURL = groupURL.appendingPathComponent("logfile.log")
do {
let logData = try String(contentsOf: logURL, encoding: .utf8)
let fileURL = url.appendingPathComponent("netbird.log")
do {
try logData.write(to: fileURL, atomically: true, encoding: .utf8)
print("Log file saved successfully.")
} catch {
print("Failed to save log file: \(error)")
}
} catch {
print("Failed to read log data: \(error)")
return
}
}
func checkForValidPresharedKey(text: String) {
@@ -115,6 +176,32 @@ struct AdvancedView: View {
}
}
struct LogLevelAlert: View {
@StateObject var viewModel: ViewModel
@Binding var isPresented: Bool
var body: some View {
VStack(spacing: 20) {
Image("exclamation-circle")
.padding(.top, 20)
Text("Changing Log Level")
.font(.title)
.foregroundColor(Color("TextAlert"))
Text("Changing log level will take effect after next connect.")
.foregroundColor(Color("TextAlert"))
.multilineTextAlignment(.center)
SolidButton(text: "Confirm") {
isPresented.toggle()
}
.padding(.top, 20)
}
.padding()
.background(Color("BgSideDrawer"))
.cornerRadius(15)
.shadow(radius: 10)
}
}
struct AdvancedView_Previews: PreviewProvider {
static var previews: some View {
AdvancedView()
@@ -0,0 +1,43 @@
import SwiftUI
import UIKit
struct DirectoryPicker: UIViewControllerRepresentable {
@Environment(\.presentationMode) var presentationMode
var onDirectoryPick: (URL) -> Void
func makeUIViewController(context: Context) -> UIDocumentPickerViewController {
let picker = UIDocumentPickerViewController(forOpeningContentTypes: [.folder], asCopy: false)
picker.delegate = context.coordinator
picker.modalPresentationStyle = .formSheet
return picker
}
func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: Context) {
// No update action needed
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UIDocumentPickerDelegate {
var parent: DirectoryPicker
init(_ picker: DirectoryPicker) {
self.parent = picker
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
if let url = urls.first {
url.startAccessingSecurityScopedResource()
parent.onDirectoryPick(url)
url.stopAccessingSecurityScopedResource()
}
parent.presentationMode.wrappedValue.dismiss()
}
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
parent.presentationMode.wrappedValue.dismiss()
}
}
}
+10 -7
View File
@@ -7,6 +7,7 @@
import SwiftUI
import Lottie
import NetworkExtension
struct MainView: View {
@EnvironmentObject var viewModel: ViewModel
@@ -78,13 +79,15 @@ struct MainView: View {
}
Spacer()
}
// Spacer()
// Button("print logs") {
// let fileManager = FileManager.default
// let groupURL = fileManager.containerURL(forSecurityApplicationGroupIdentifier: "group.io.netbird.app")
// let logURL = groupURL?.appendingPathComponent("logfile.log")
// printLogContents(from: logURL!)
// }
#if DEBUG
Spacer()
Button("print logs") {
let fileManager = FileManager.default
let groupURL = fileManager.containerURL(forSecurityApplicationGroupIdentifier: "group.io.netbird.app")
let logURL = groupURL?.appendingPathComponent("logfile.log")
printLogContents(from: logURL!)
}
#endif
Spacer()
Button(action: {
if !viewModel.buttonLock {
+5 -1
View File
@@ -118,8 +118,12 @@ public class NetworkExtensionAdapter: ObservableObject {
public func startVPNConnection() {
print("starting tunnel")
let logLevel = UserDefaults.standard.string(forKey: "logLevel") ?? "INFO"
print("Loglevel: " + logLevel)
let options: [String: NSObject] = ["logLevel": logLevel as NSObject]
do {
try self.session?.startVPNTunnel()
try self.session?.startVPNTunnel(options: options)
print("VPN Tunnel started.")
} catch let error {
print("Failed to start VPN tunnel: \(error)")
@@ -22,14 +22,18 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
private lazy var adapter: NetBirdAdapter = {
return NetBirdAdapter(with: self.tunnelManager)
}()
override init() {
initializeLogging()
}
override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
let options = FirebaseOptions(contentsOfFile: Bundle.main.path(forResource: "GoogleService-Info", ofType: "plist")!)
FirebaseApp.configure(options: options!)
let firebaseOptions = FirebaseOptions(contentsOfFile: Bundle.main.path(forResource: "GoogleService-Info", ofType: "plist")!)
FirebaseApp.configure(options: firebaseOptions!)
if let options = options {
// For example, handle a specific option
if let logLevel = options["logLevel"] as? String {
initializeLogging(loglevel: logLevel)
}
}
if adapter.needsLogin() {
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
@@ -124,7 +128,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
}
}
func initializeLogging() {
func initializeLogging(loglevel: String) {
let fileManager = FileManager.default
let groupURL = fileManager.containerURL(forSecurityApplicationGroupIdentifier: "group.io.netbird.app")
@@ -166,7 +170,7 @@ func initializeLogging() {
if let logPath = logURL?.path {
success = NetBirdSDKInitializeLog("DEBUG", logPath, &error)
success = NetBirdSDKInitializeLog(loglevel, logPath, &error)
}
if !success, let actualError = error {
print("Failed to initialize log: \(actualError.localizedDescription)")