diff --git a/Package.swift b/Package.swift index 4915f74ff86..a08eb1e2e24 100644 --- a/Package.swift +++ b/Package.swift @@ -448,7 +448,7 @@ if isNativeTalkEnabled { package.dependencies.append(.package(name: "JitsiMeet", path: "ThirdParty/JitsiMeet")) package.products.append(.library(name: "BraveTalk", targets: ["BraveTalk"])) package.targets.append(contentsOf: [ - .target(name: "BraveTalk", dependencies: ["Shared", "JitsiMeet"]), + .target(name: "BraveTalk", dependencies: ["Shared", "JitsiMeet"], plugins: ["LoggerPlugin"]), .testTarget(name: "BraveTalkTests", dependencies: ["BraveTalk", "Shared"]), ]) } diff --git a/Sources/Brave/Frontend/Settings/Debug/BraveTalkLogsViewController.swift b/Sources/Brave/Frontend/Settings/Debug/BraveTalkLogsViewController.swift new file mode 100644 index 00000000000..aca02948ee5 --- /dev/null +++ b/Sources/Brave/Frontend/Settings/Debug/BraveTalkLogsViewController.swift @@ -0,0 +1,65 @@ +// Copyright 2024 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import UIKit +import os.log +import OSLog +import SnapKit + +public class BraveTalkLogsViewController: UIViewController { + + private var logsTextView = UITextView() + + public override func viewDidLoad() { + super.viewDidLoad() + + logsTextView.isEditable = false + view.addSubview(logsTextView) + logsTextView.snp.makeConstraints { + $0.edges.equalToSuperview() + } + + logsTextView.text = getLogs() + + let shareButton = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(shareLogs)) + navigationItem.rightBarButtonItem = shareButton + } + + @objc private func shareLogs() { + do { + let fileURL = try createTemporaryLogFile() + let activityViewController = UIActivityViewController(activityItems: [fileURL], applicationActivities: nil) + present(activityViewController, animated: true) + } catch { + Logger.module.error("Error while creating the log file: \(error.localizedDescription, privacy: .public)") + } + } + + private func createTemporaryLogFile() throws -> URL { + let logsString = getLogs() + let temporaryDirectoryURL = FileManager.default.temporaryDirectory + let logFileURL = temporaryDirectoryURL.appendingPathComponent("Logs.txt") + + try logsString.write(to: logFileURL, atomically: true, encoding: .utf8) + return logFileURL + } + + private func getLogs() -> String { + do { + let store = try OSLogStore(scope: .currentProcessIdentifier) + + return try store + .getEntries() + .compactMap { $0 as? OSLogEntryLog } + .filter { $0.category == "BraveTalk" && $0.subsystem == Bundle.main.bundleIdentifier } + .map { "[\($0.date.formatted())] \($0.composedMessage)" } + .joined(separator: "\n") + } catch { + Logger.module.error("\(error.localizedDescription, privacy: .public)") + } + + return "" + } +} diff --git a/Sources/Brave/Frontend/Settings/SettingsViewController.swift b/Sources/Brave/Frontend/Settings/SettingsViewController.swift index 17100493ffa..cc9b00aaddf 100644 --- a/Sources/Brave/Frontend/Settings/SettingsViewController.swift +++ b/Sources/Brave/Frontend/Settings/SettingsViewController.swift @@ -861,6 +861,11 @@ class SettingsViewController: TableViewController { selection: { [unowned self] in self.navigationController?.pushViewController(VPNLogsViewController(), animated: true) }, accessory: .disclosureIndicator, cellClass: MultilineValue1Cell.self), + Row( + text: "Brave Talk Logs", + selection: { [unowned self] in + self.navigationController?.pushViewController(BraveTalkLogsViewController(), animated: true) + }, accessory: .disclosureIndicator, cellClass: MultilineValue1Cell.self), Row( text: "Retention Preferences Debug Menu", selection: { [unowned self] in diff --git a/Sources/BraveTalk/BraveTalkJitsiCoordinator.swift b/Sources/BraveTalk/BraveTalkJitsiCoordinator.swift index 0b8546f09fe..e2abe3a4a2d 100644 --- a/Sources/BraveTalk/BraveTalkJitsiCoordinator.swift +++ b/Sources/BraveTalk/BraveTalkJitsiCoordinator.swift @@ -17,7 +17,11 @@ import JitsiMeetSDK return true } - public init() {} + public init() { + if !AppConstants.buildChannel.isPublic { + JitsiMeetLogger.add(BraveTalkJitsiLogHandler()) + } + } public enum AppLifetimeEvent { case didFinishLaunching(options: [UIApplication.LaunchOptionsKey: Any] = [:]) diff --git a/Sources/BraveTalk/BraveTalkJitsiLogHandler.swift b/Sources/BraveTalk/BraveTalkJitsiLogHandler.swift new file mode 100644 index 00000000000..74053afee35 --- /dev/null +++ b/Sources/BraveTalk/BraveTalkJitsiLogHandler.swift @@ -0,0 +1,32 @@ +// Copyright 2024 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import Foundation +import Shared +import JitsiMeetSDK +import os.log + +class BraveTalkJitsiLogHandler: JitsiMeetBaseLogHandler { + + override func logVerbose(_ msg: String!) { + Logger.module.debug("[verbose]: \(msg, privacy: .public)") + } + + override func logDebug(_ msg: String!) { + Logger.module.debug("\(msg, privacy: .public)") + } + + override func logInfo(_ msg: String!) { + Logger.module.info("\(msg, privacy: .public)") + } + + override func logWarn(_ msg: String!) { + Logger.module.warning("\(msg, privacy: .public)") + } + + override func logError(_ msg: String!) { + Logger.module.error("\(msg, privacy: .public)") + } +}