From b4682a3abfe299c19b24752b2fb1ce2477611ec3 Mon Sep 17 00:00:00 2001 From: Roy Ben Shabat Date: Fri, 10 Apr 2020 15:06:42 +0300 Subject: Implemented FSE/PPC Logs. --- .../Tango.FSE.PPCConsole.csproj | 8 + .../Tango.FSE.PPCConsole/ViewModelLocator.cs | 9 + .../Tango.FSE.PPCConsole/ViewModels/LogsViewVM.cs | 288 +++++++++++++++++++++ .../Tango.FSE.PPCConsole/ViewModels/MainViewVM.cs | 1 + .../Tango.FSE.PPCConsole/Views/LogsView.xaml | 225 ++++++++++++++++ .../Tango.FSE.PPCConsole/Views/LogsView.xaml.cs | 28 ++ .../Tango.FSE.PPCConsole/Views/MainView.xaml | 5 +- .../Tango.FSE.PPCConsole/Views/UpdatesView.xaml | 2 +- .../Dialogs/ApplicationLogItemView.xaml | 4 +- .../Dialogs/FirmwareLogItemView.xaml | 39 +++ .../Dialogs/FirmwareLogItemView.xaml.cs | 28 ++ .../Dialogs/FirmwareLogItemViewVM.cs | 21 ++ .../Dialogs/MachineLogItemView.xaml | 39 --- .../Dialogs/MachineLogItemView.xaml.cs | 28 -- .../Dialogs/MachineLogItemViewVM.cs | 21 -- .../Tango.FSE.Common/Logging/ILoggingProvider.cs | 37 ++- .../Tango.FSE.Common/Logging/RemoteLogFileModel.cs | 128 +++++++++ .../Logging/RemoteLogFileStatus.cs | 19 ++ .../FSE/Tango.FSE.Common/Tango.FSE.Common.csproj | 10 +- .../Connection/DefaultMachineProvider.cs | 5 +- .../Tango.FSE.UI/Logging/DefaultLoggingProvider.cs | 89 ++++++- .../FSE/Tango.FSE.UI/Panes/LogViewerPane.xaml | 12 +- .../FSE/Tango.FSE.UI/Panes/LogViewerPaneVM.cs | 84 +++--- .../FSE/Tango.FSE.UI/ViewModelLocator.cs | 2 +- 24 files changed, 978 insertions(+), 154 deletions(-) create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/LogsViewVM.cs create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/LogsView.xaml create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/LogsView.xaml.cs create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemView.xaml create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemView.xaml.cs create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemViewVM.cs delete mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemView.xaml delete mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemView.xaml.cs delete mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemViewVM.cs create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/RemoteLogFileModel.cs create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/RemoteLogFileStatus.cs (limited to 'Software/Visual_Studio/FSE') diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj index 783dfa9fe..287273015 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj @@ -113,10 +113,14 @@ + + + LogsView.xaml + UpdatesView.xaml @@ -252,6 +256,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + MSBuild:Compile Designer diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModelLocator.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModelLocator.cs index 4faa72e8e..a3b800b22 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModelLocator.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModelLocator.cs @@ -18,6 +18,7 @@ namespace Tango.FSE.PPCConsole TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); + TangoIOC.Default.Register(); } public static MainViewVM MainViewVM @@ -67,5 +68,13 @@ namespace Tango.FSE.PPCConsole return TangoIOC.Default.GetInstance(); } } + + public static LogsViewVM LogsViewVM + { + get + { + return TangoIOC.Default.GetInstance(); + } + } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/LogsViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/LogsViewVM.cs new file mode 100644 index 000000000..52955e18a --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/LogsViewVM.cs @@ -0,0 +1,288 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; +using Tango.Core; +using Tango.Core.Commands; +using Tango.Core.Helpers; +using Tango.FSE.Common; +using Tango.FSE.Common.Connection; +using Tango.FSE.Common.Dialogs; +using Tango.FSE.Common.FileSystem; +using Tango.FSE.Common.Logging; +using Tango.Logging; +using Tango.PPC.Shared.Logs; +using Tango.SharedUI.Components; +using static Tango.SharedUI.Controls.NavigationControl; + +namespace Tango.FSE.PPCConsole.ViewModels +{ + public class LogsViewVM : FSEViewModel, INavigationViewModel + { + private bool _loaded; + + private List> _logFiles; + /// + /// Gets or sets the remote log files. + /// + public List> LogFiles + { + get { return _logFiles; } + set { _logFiles = value; RaisePropertyChangedAuto(); } + } + + private RemoteLogFileModel _selectedLogFile; + /// + /// Gets or sets the selected remote log file. + /// + public RemoteLogFileModel SelectedLogFile + { + get { return _selectedLogFile; } + set { _selectedLogFile = value; RaisePropertyChangedAuto(); OnSelectedLogFileChanged(); } + } + + /// + /// Gets or sets the application logs. + /// + public ObservableCollection ApplicationLogs { get; set; } + + /// + /// Gets or sets the application logs view. + /// + public ICollectionView ApplicationLogsView { get; set; } + + /// + /// Gets or sets the selected application logs categories. + /// + public SelectedObjectCollection SelectedApplicationLogsCategories { get; set; } + + private String _applicationLogsFilter; + /// + /// Gets or sets the application logs filter. + /// + public String ApplicationLogsFilter + { + get { return _applicationLogsFilter; } + set { _applicationLogsFilter = value; RaisePropertyChangedAuto(); ApplicationLogsView.Refresh(); } + } + + /// + /// Opens the detailed application log dialog. + /// + public RelayCommand OpenApplicationLogItemCommand { get; set; } + + /// + /// Exports the selected log file to local disk. + /// + public RelayCommand ExportLogFileCommand { get; set; } + + /// + /// Exports all the downloaded log files to disk. + /// + public RelayCommand ExportAllDownloadedLogFilesCommand { get; set; } + + /// + /// Downloads all the available log files. + /// + public RelayCommand DownloadAllLogFilesCommand { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public LogsViewVM() + { + ApplicationLogs = new ObservableCollection(); + ApplicationLogsView = CollectionViewSource.GetDefaultView(ApplicationLogs); + ApplicationLogsView.Filter = FilterApplicationLogs; + SelectedApplicationLogsCategories = new SelectedObjectCollection(new ObservableCollection() + { + LogCategory.Info, + LogCategory.Warning, + LogCategory.Error, + LogCategory.Critical, + }, new ObservableCollection() + { + LogCategory.Info, + LogCategory.Warning, + LogCategory.Error, + LogCategory.Critical, + }); + + SelectedApplicationLogsCategories.SynchedSource.CollectionChanged += (_, __) => ApplicationLogsView.Refresh(); + + OpenApplicationLogItemCommand = new RelayCommand(OpenApplicationLogItem); + + ExportLogFileCommand = new RelayCommand(ExportSelectedLogFile); + ExportAllDownloadedLogFilesCommand = new RelayCommand(ExportAllDownloadedLogFiles); + DownloadAllLogFilesCommand = new RelayCommand(DownloadAllLogFiles); + } + + public override void OnApplicationStarted() + { + base.OnApplicationStarted(); + MachineProvider.MachineConnected += MachineProvider_MachineConnected; + } + + private void MachineProvider_MachineConnected(object sender, MachineConnectedEventArgs e) + { + if (e.DifferentFromPrevious) + { + _loaded = false; + + if (MachineProvider.ConnectionType.IsRemote() && IsVisible) + { + LoadLogFiles(); + } + } + } + + public override void OnNavigatedTo() + { + base.OnNavigatedTo(); + + if (!_loaded) + { + LoadLogFiles(); + } + } + + private async void LoadLogFiles() + { + if (!MachineProvider.ConnectionType.IsRemote() || !IsFree) return; + + try + { + IsFree = false; + var logFiles = await LoggingProvider.GetApplicationLogFiles(); + LogFiles = logFiles.Select(x => + { + + var model = new RemoteLogFileModel(new ApplicationLogFileParser()); + model.RemoteLogFile = x; + model.DownloadCompleted += OnRemoteLogFileDownloadCompleted; + return model; + + }).ToList(); + SelectedLogFile = LogFiles.FirstOrDefault(); + _loaded = true; + } + catch (Exception ex) + { + LogManager.Log(ex, "Error loading log files."); + } + finally + { + IsFree = true; + } + } + + private void OnRemoteLogFileDownloadCompleted(object sender, EventArgs e) + { + if (SelectedLogFile == sender) + { + OnSelectedLogFileChanged(); + } + } + + private void OnSelectedLogFileChanged() + { + if (SelectedLogFile == null) return; + + InvokeUI(() => + { + ApplicationLogs.Clear(); + foreach (var logItem in SelectedLogFile.LogItems) + { + ApplicationLogs.Add(logItem); + } + + ApplicationLogsView.Refresh(); + }); + } + + private async void OpenApplicationLogItem(LogItemBase logItem) + { + await NotificationProvider.ShowDialog(new ApplicationLogItemViewVM() { LogItem = logItem }); + } + + private bool FilterApplicationLogs(object obj) + { + var log = obj as LogItemBase; + return SelectedApplicationLogsCategories.SynchedSource.Contains(log.Category) && (String.IsNullOrWhiteSpace(ApplicationLogsFilter) || log.Message.ToLower().Contains(ApplicationLogsFilter.ToLower())); + } + + private async void ExportSelectedLogFile() + { + if (SelectedLogFile != null && SelectedLogFile.Status == RemoteLogFileStatus.Downloaded) + { + var result = await StorageProvider.SaveFile("Export Log File", "Application Log Files|*.log", SelectedLogFile.RemoteLogFile.Name, ".log"); + if (result) + { + using (NotificationProvider.PushTaskItem("Exporting log file...")) + { + try + { + File.Copy(SelectedLogFile.TemporaryFile, result.SelectedItem, true); + await NotificationProvider.ShowSuccess("Log file exported successfully."); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error exporting application log file."); + await NotificationProvider.ShowError($"Could not export the log file.\n{ex.FlattenMessage()}"); + } + } + } + } + } + + private async void ExportAllDownloadedLogFiles() + { + var result = await StorageProvider.SelectFolder("Export Log Files"); + if (result) + { + var toExport = LogFiles.Where(x => x.Status == RemoteLogFileStatus.Downloaded).ToList(); + var count = toExport.Count; + + using (var task = NotificationProvider.PushTaskItem("Exporting log files...")) + { + foreach (var logFile in toExport.ToList()) + { + try + { + await Task.Delay(500); + File.Copy(logFile.TemporaryFile, Path.Combine(result.SelectedItem, logFile.RemoteLogFile.Name), true); + toExport.Remove(logFile); + task.UpdateProgress("Exporting log files...", count - toExport.Count, count, false); + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error exporting application log file '{logFile.RemoteLogFile.Name}'."); + await NotificationProvider.ShowError($"Could not export '{logFile.RemoteLogFile.Name}'.\n{ex.FlattenMessage()}"); + } + } + } + + await NotificationProvider.ShowSuccess($"Successfully exported {count - toExport.Count} out of {count} log files."); + } + } + + private async void DownloadAllLogFiles() + { + var toDownload = LogFiles.Where(x => x.Status == RemoteLogFileStatus.None); + var totalSize = FileHelper.GetFriendlyFileSize(toDownload.Select(x => x.RemoteLogFile.Length).Sum()); + + if (await NotificationProvider.ShowWarningQuestion($"Are you sure you wish to download the entire history of log files?\nTotal size: {totalSize}", "DOWNLOAD", "CANCEL")) + { + foreach (var logFile in toDownload) + { + logFile.DownloadLogFile(); + } + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/MainViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/MainViewVM.cs index e18a75ef6..f4614ccf1 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/ViewModels/MainViewVM.cs @@ -20,6 +20,7 @@ namespace Tango.FSE.PPCConsole.ViewModels MonitoringView, FileSystemView, UpdatesView, + LogsView, } private NavigationView _selectedView; diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/LogsView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/LogsView.xaml new file mode 100644 index 000000000..81258e971 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/LogsView.xaml @@ -0,0 +1,225 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + | + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Download this log file from the remote machine in order to display its content + DOWNLOAD + + + + + + + + Error occurred while trying to download this log file + TRY AGAIN + + + + + + + + Downloading log file, please wait... + + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/LogsView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/LogsView.xaml.cs new file mode 100644 index 000000000..d08f18326 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/LogsView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.FSE.PPCConsole.Views +{ + /// + /// Interaction logic for LogsView.xaml + /// + public partial class LogsView : UserControl + { + public LogsView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MainView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MainView.xaml index 1efc0516f..b8932be95 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MainView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MainView.xaml @@ -29,19 +29,20 @@ - + + - + diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/UpdatesView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/UpdatesView.xaml index 037fa6d96..8a8e6546e 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/UpdatesView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/UpdatesView.xaml @@ -60,7 +60,7 @@ - + diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/ApplicationLogItemView.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/ApplicationLogItemView.xaml index 844bdc992..6abda9b6d 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/ApplicationLogItemView.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/ApplicationLogItemView.xaml @@ -11,14 +11,14 @@ - + - + diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemView.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemView.xaml new file mode 100644 index 000000000..49d67f205 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemView.xaml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemView.xaml.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemView.xaml.cs new file mode 100644 index 000000000..6e7556c40 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.FSE.Common.Dialogs +{ + /// + /// Interaction logic for ApplicationLogItemView.xaml + /// + public partial class FirmwareLogItemView : UserControl + { + public FirmwareLogItemView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemViewVM.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemViewVM.cs new file mode 100644 index 000000000..1ee76e381 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/FirmwareLogItemViewVM.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Integration.Logging; + +namespace Tango.FSE.Common.Dialogs +{ + public class FirmwareLogItemViewVM : FSEDialogViewVM + { + public EmbeddedLogItem LogItem { get; set; } + + public FirmwareLogItemViewVM() + { + CanClose = false; + OKText = "CLOSE"; + HasDefault = true; + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemView.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemView.xaml deleted file mode 100644 index 776e6d893..000000000 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemView.xaml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemView.xaml.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemView.xaml.cs deleted file mode 100644 index 97103c34e..000000000 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemView.xaml.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; - -namespace Tango.FSE.Common.Dialogs -{ - /// - /// Interaction logic for ApplicationLogItemView.xaml - /// - public partial class MachineLogItemView : UserControl - { - public MachineLogItemView() - { - InitializeComponent(); - } - } -} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemViewVM.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemViewVM.cs deleted file mode 100644 index 2ac7a7b3a..000000000 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Dialogs/MachineLogItemViewVM.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Tango.Integration.Logging; - -namespace Tango.FSE.Common.Dialogs -{ - public class MachineLogItemViewVM : FSEDialogViewVM - { - public EmbeddedLogItem LogItem { get; set; } - - public MachineLogItemViewVM() - { - CanClose = false; - OKText = "CLOSE"; - HasDefault = true; - } - } -} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/ILoggingProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/ILoggingProvider.cs index d49f8b21d..68c288e60 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/ILoggingProvider.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/ILoggingProvider.cs @@ -1,10 +1,13 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; +using Tango.FSE.Common.FileSystem; using Tango.Integration.Logging; using Tango.Logging; +using Tango.PPC.Shared.Logs; namespace Tango.FSE.Common.Logging { @@ -13,14 +16,44 @@ namespace Tango.FSE.Common.Logging /// public interface ILoggingProvider { + /// + /// Gets the last retrieved history of the application log files. + /// + ObservableCollection ApplicationLogFiles { get; } + + /// + /// Gets the last retrieved history of the embedded firmware log files. + /// + ObservableCollection FirmwareLogFiles { get; } + + /// + /// Gets the history of application log files. + /// + /// + Task> GetApplicationLogFiles(); + + /// + /// Gets the history of the embedded firmware log files. + /// + /// + Task> GetFirmwareLogFiles(); + + /// + /// Downloads the specified remote log file. + /// + /// The log file. + /// Target folder. + /// + Task DownloadLogFile(RemoteLogFile logFile, String targetFolder); + /// /// Occurs when a new PPC application log is available. /// event EventHandler ApplicationLogAvailable; /// - /// Occurs when a new embedded log is available. + /// Occurs when a new embedded firmware log is available. /// - event EventHandler EmbeddedLogAvailable; + event EventHandler FirmwareLogAvailable; } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/RemoteLogFileModel.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/RemoteLogFileModel.cs new file mode 100644 index 000000000..cf71ed270 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/RemoteLogFileModel.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; +using Tango.Core; +using Tango.Core.Commands; +using Tango.Core.DI; +using Tango.FSE.Common.FileSystem; +using Tango.Logging; +using Tango.PPC.Shared.Logs; +using Tango.SharedUI.Components; + +namespace Tango.FSE.Common.Logging +{ + /// + /// Represents a remote log file model. + /// + /// + /// + public class RemoteLogFileModel : ExtendedObject where T : LogItemBase + { + private ILogFileParser _parser; + + /// + /// Occurs when the remote log file has downloaded successfully. + /// + public event EventHandler DownloadCompleted; + + [TangoInject] + private ILoggingProvider LoggingProvider { get; set; } + + /// + /// Gets or sets the remote log file. + /// + public RemoteLogFile RemoteLogFile { get; set; } + + /// + /// Gets the duration of the remote log file. + /// + public TimeSpan Duration + { + get { return RemoteLogFile.DateModified - RemoteLogFile.DateCreated; } + } + + private RemoteLogFileStatus _status; + /// + /// Gets or sets the remote log file status. + /// + public RemoteLogFileStatus Status + { + get { return _status; } + set { _status = value; RaisePropertyChangedAuto(); } + } + + private FileSystemHandler _handler; + /// + /// Gets or sets the remote log file download handler. + /// + public FileSystemHandler Handler + { + get { return _handler; } + set { _handler = value; RaisePropertyChangedAuto(); } + } + + /// + /// Gets or sets the temporary file (where the actual log file is stored locally). + /// + public String TemporaryFile { get; set; } + + private ObservableCollection _logItems; + /// + /// Gets or sets the log items. + /// + public ObservableCollection LogItems + { + get { return _logItems; } + set { _logItems = value; RaisePropertyChangedAuto(); } + } + + /// + /// Gets or sets the download command. + /// + public RelayCommand DownloadCommand { get; set; } + + /// + /// Initializes a new instance of the class. + /// + /// The parser. + public RemoteLogFileModel(ILogFileParser parser) + { + TangoIOC.Default.Inject(this); + _parser = parser; + LogItems = new ObservableCollection(); + DownloadCommand = new RelayCommand(DownloadLogFile); + } + + /// + /// Downloads the log file. + /// + public async void DownloadLogFile() + { + if (Status == RemoteLogFileStatus.None || Status == RemoteLogFileStatus.Failed) + { + Status = RemoteLogFileStatus.Downloading; + String tempLogFile = TemporaryManager.CreateImaginaryFile(".log"); + Handler = await LoggingProvider.DownloadLogFile(RemoteLogFile, tempLogFile); + Handler.StatusChanged += (x, status) => + { + if (status == FileSystemHandlerStatus.Completed) + { + TemporaryFile = tempLogFile; + LogItems = new ObservableCollection(_parser.Parse(tempLogFile, RemoteLogFile.DateCreated.ToLocalTime())); + Status = RemoteLogFileStatus.Downloaded; + DownloadCompleted?.Invoke(this, new EventArgs()); + } + else if (status == FileSystemHandlerStatus.Failed) + { + Status = RemoteLogFileStatus.Failed; + } + }; + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/RemoteLogFileStatus.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/RemoteLogFileStatus.cs new file mode 100644 index 000000000..25f3f4eac --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Logging/RemoteLogFileStatus.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.Common.Logging +{ + /// + /// Represents the remote log file statuses. + /// + public enum RemoteLogFileStatus + { + None, + Downloading, + Downloaded, + Failed, + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj b/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj index 7134dbcbb..1581bd25b 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj @@ -108,14 +108,14 @@ - - MachineLogItemView.xaml + + FirmwareLogItemView.xaml ApplicationLogItemView.xaml - + @@ -132,6 +132,8 @@ + + @@ -194,7 +196,7 @@ Designer MSBuild:Compile - + MSBuild:Compile Designer diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Connection/DefaultMachineProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/Connection/DefaultMachineProvider.cs index 3a43e71f0..4837fd100 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Connection/DefaultMachineProvider.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Connection/DefaultMachineProvider.cs @@ -457,11 +457,12 @@ namespace Tango.FSE.UI.Connection MachineOperator.RequestTimeout = TimeSpan.FromSeconds(5); MachineOperator.ContinuousRequestTimeout = TimeSpan.FromSeconds(5); - if (MachineOperator is ExternalBridgeTcpClient) + if (ConnectionType.IsRemote()) { - ExternalBridgeTcpClient tcpClient = MachineOperator as ExternalBridgeTcpClient; + ExternalBridgeTcpClient tcpClient = MachineOperator.As(); tcpClient.EnableApplicationLogs = true; tcpClient.InjectApplicationLogsToDefaultLogManager = false; + tcpClient.LogEmbeddedDebuggingToFile = false; } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Logging/DefaultLoggingProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/Logging/DefaultLoggingProvider.cs index b3a2d4051..4570589b6 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Logging/DefaultLoggingProvider.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Logging/DefaultLoggingProvider.cs @@ -1,13 +1,19 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; +using Tango.Core; +using Tango.FileSystem; using Tango.FSE.Common.Connection; +using Tango.FSE.Common.FileSystem; using Tango.FSE.Common.Logging; using Tango.Integration.ExternalBridge; using Tango.Integration.Logging; using Tango.Logging; +using Tango.PPC.Shared.Logs; namespace Tango.FSE.UI.Logging { @@ -15,8 +21,11 @@ namespace Tango.FSE.UI.Logging /// Represents the default implementation. /// /// - public class DefaultLoggingProvider : ILoggingProvider + public class DefaultLoggingProvider : ExtendedObject, ILoggingProvider { + private IFileSystemProvider _fileSystemProvider; + private IMachineProvider _machineProvider; + /// /// Occurs when a new PPC application log is available. /// @@ -25,14 +34,30 @@ namespace Tango.FSE.UI.Logging /// /// Occurs when a new embedded log is available. /// - public event EventHandler EmbeddedLogAvailable; + public event EventHandler FirmwareLogAvailable; + + /// + /// Gets the last retrieved history of the application log files. + /// + public ObservableCollection ApplicationLogFiles { get; private set; } + + /// + /// Gets the last retrieved history of the embedded firmware log files. + /// + public ObservableCollection FirmwareLogFiles { get; private set; } /// /// Initializes a new instance of the class. /// /// The machine provider. - public DefaultLoggingProvider(IMachineProvider machineProvider) + public DefaultLoggingProvider(IMachineProvider machineProvider, IFileSystemProvider fileSystemProvider) { + ApplicationLogFiles = new ObservableCollection(); + FirmwareLogFiles = new ObservableCollection(); + + _machineProvider = machineProvider; + _fileSystemProvider = fileSystemProvider; + if (machineProvider.MachineOperator is ExternalBridgeTcpClient) { (machineProvider.MachineOperator as ExternalBridgeTcpClient).ApplicationLogAvailable += DefaultLoggingProvider_ApplicationLogAvailable; @@ -41,6 +66,62 @@ namespace Tango.FSE.UI.Logging machineProvider.MachineOperator.DebugLogAvailable += MachineOperator_DebugLogAvailable; } + /// + /// Gets the history of application log files. + /// + /// + public async Task> GetApplicationLogFiles() + { + var response = await _machineProvider.MachineOperator.SendGenericRequest(new GetLogFilesRequest() { LogFileType = RemoteLogFileType.Application }); + + ApplicationLogFiles.Clear(); + + foreach (var item in response.LogFiles) + { + ApplicationLogFiles.Add(item); + } + + return response.LogFiles; + } + + /// + /// Gets the history of the embedded firmware log files. + /// + /// + public async Task> GetFirmwareLogFiles() + { + var response = await _machineProvider.MachineOperator.SendGenericRequest(new GetLogFilesRequest() { LogFileType = RemoteLogFileType.Firmware }); + + FirmwareLogFiles.Clear(); + + foreach (var item in response.LogFiles) + { + FirmwareLogFiles.Add(item); + } + + return response.LogFiles; + } + + /// + /// Downloads the specified remote log file. + /// + /// The log file. + /// Target local folder. + /// + public async Task DownloadLogFile(RemoteLogFile logFile, String targetFolder) + { + var tempFolder = TemporaryManager.CreateFolder(); + var handler = await _fileSystemProvider.Download(new FileItem() { Path = logFile.Path }, tempFolder); + handler.StatusChanged += (x, status) => + { + if (status == FileSystemHandlerStatus.Completed) + { + File.Move(Path.Combine(tempFolder, logFile.Name), targetFolder); + } + }; + return handler; + } + private void DefaultLoggingProvider_ApplicationLogAvailable(object sender, LogItemBase log) { ApplicationLogAvailable?.Invoke(this, log); @@ -48,7 +129,7 @@ namespace Tango.FSE.UI.Logging private void MachineOperator_DebugLogAvailable(object sender, PMR.Debugging.StartDebugLogResponse log) { - EmbeddedLogAvailable?.Invoke(this, new EmbeddedLogItem(log) { TimeStamp = DateTime.Now}); + FirmwareLogAvailable?.Invoke(this, new EmbeddedLogItem(log) { TimeStamp = DateTime.Now }); } } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/LogViewerPane.xaml b/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/LogViewerPane.xaml index d3ece6db1..50faea56c 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/LogViewerPane.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/LogViewerPane.xaml @@ -97,14 +97,14 @@ - MACHINE LOGS + FIRMWARE LOGS - - + + - + @@ -125,13 +125,13 @@ - + - + diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/LogViewerPaneVM.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/LogViewerPaneVM.cs index 1a4083f28..cb0ea0229 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/LogViewerPaneVM.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/LogViewerPaneVM.cs @@ -23,7 +23,7 @@ namespace Tango.FSE.UI.Panes public class LogViewerPaneVM : FSEViewModel { private List _pausedApplicationLogs; - private List _pausedMachineLogs; + private List _pausedFirmwareLogs; /// /// Gets or sets the application logs. @@ -31,9 +31,9 @@ namespace Tango.FSE.UI.Panes public ObservableCollection ApplicationLogs { get; set; } /// - /// Gets or sets the machine logs. + /// Gets or sets the firmware logs. /// - public ObservableCollection MachineLogs { get; set; } + public ObservableCollection FirmwareLogs { get; set; } /// /// Gets or sets the application logs view. @@ -41,9 +41,9 @@ namespace Tango.FSE.UI.Panes public ICollectionView ApplicationLogsView { get; set; } /// - /// Gets or sets the machine logs view. + /// Gets or sets the firmware logs view. /// - public ICollectionView MachineLogsView { get; set; } + public ICollectionView FirmwareLogsView { get; set; } /// /// Gets or sets the selected application logs categories. @@ -51,9 +51,9 @@ namespace Tango.FSE.UI.Panes public SelectedObjectCollection SelectedApplicationLogsCategories { get; set; } /// - /// Gets or sets the selected machine logs categories. + /// Gets or sets the selected firmware logs categories. /// - public SelectedObjectCollection SelectedMachineLogsCategories { get; set; } + public SelectedObjectCollection SelectedFirmwareLogsCategories { get; set; } /// /// Gets or sets a value indicating whether to pause the insertion of application logs. @@ -61,9 +61,9 @@ namespace Tango.FSE.UI.Panes public bool ApplicationLogsPaused { get; set; } /// - /// Gets or sets a value indicating whether to pause the insertion of machine logs. + /// Gets or sets a value indicating whether to pause the insertion of firmware logs. /// - public bool MachineLogsPaused { get; set; } + public bool FirmwareLogsPaused { get; set; } private String _applicationLogsFilter; /// @@ -75,14 +75,14 @@ namespace Tango.FSE.UI.Panes set { _applicationLogsFilter = value; RaisePropertyChangedAuto(); ApplicationLogsView.Refresh(); } } - private String _machineLogsFilter; + private String _firmwareLogsFilter; /// - /// Gets or sets the machine logs filter. + /// Gets or sets the firmware logs filter. /// - public String MachineLogsFilter + public String FirmwareLogsFilter { - get { return _machineLogsFilter; } - set { _machineLogsFilter = value; RaisePropertyChangedAuto(); MachineLogsView.Refresh(); } + get { return _firmwareLogsFilter; } + set { _firmwareLogsFilter = value; RaisePropertyChangedAuto(); FirmwareLogsView.Refresh(); } } /// @@ -91,9 +91,9 @@ namespace Tango.FSE.UI.Panes public RelayCommand ClearApplicationLogsCommand { get; set; } /// - /// Clears the machine logs. + /// Clears the firmware logs. /// - public RelayCommand ClearMachineLogsCommand { get; set; } + public RelayCommand ClearFirmwareLogsCommand { get; set; } /// /// Opens the detailed application log dialog. @@ -101,9 +101,9 @@ namespace Tango.FSE.UI.Panes public RelayCommand OpenApplicationLogItemCommand { get; set; } /// - /// Opens the detailed machine log dialog. + /// Opens the detailed firmware log dialog. /// - public RelayCommand OpenMachineLogItemCommand { get; set; } + public RelayCommand OpenFirmareLogItemCommand { get; set; } /// /// Initializes a new instance of the class. @@ -111,15 +111,15 @@ namespace Tango.FSE.UI.Panes public LogViewerPaneVM() { _pausedApplicationLogs = new List(); - _pausedMachineLogs = new List(); + _pausedFirmwareLogs = new List(); ApplicationLogs = new ObservableCollection(); - MachineLogs = new ObservableCollection(); + FirmwareLogs = new ObservableCollection(); ApplicationLogsView = CollectionViewSource.GetDefaultView(ApplicationLogs); - MachineLogsView = CollectionViewSource.GetDefaultView(MachineLogs); + FirmwareLogsView = CollectionViewSource.GetDefaultView(FirmwareLogs); ApplicationLogsView.Filter = FilterApplicationLogs; - MachineLogsView.Filter = FilterMachineLogs; + FirmwareLogsView.Filter = FilterFirmwareLogs; SelectedApplicationLogsCategories = new SelectedObjectCollection(new ObservableCollection() { @@ -135,7 +135,7 @@ namespace Tango.FSE.UI.Panes LogCategory.Critical, }); - SelectedMachineLogsCategories = new SelectedObjectCollection(new ObservableCollection() + SelectedFirmwareLogsCategories = new SelectedObjectCollection(new ObservableCollection() { LogCategory.Info, LogCategory.Warning, @@ -152,18 +152,18 @@ namespace Tango.FSE.UI.Panes }); SelectedApplicationLogsCategories.SynchedSource.CollectionChanged += (_, __) => ApplicationLogsView.Refresh(); - SelectedMachineLogsCategories.SynchedSource.CollectionChanged += (_, __) => MachineLogsView.Refresh(); + SelectedFirmwareLogsCategories.SynchedSource.CollectionChanged += (_, __) => FirmwareLogsView.Refresh(); ClearApplicationLogsCommand = new RelayCommand(ClearApplicationLogs); - ClearMachineLogsCommand = new RelayCommand(ClearMachineLogs); + ClearFirmwareLogsCommand = new RelayCommand(ClearFirmwareLogs); TangoIOC.Default.Inject(this); LoggingProvider.ApplicationLogAvailable += LoggingProvider_ApplicationLogAvailable; - LoggingProvider.EmbeddedLogAvailable += LoggingProvider_EmbeddedLogAvailable; + LoggingProvider.FirmwareLogAvailable += LoggingProvider_FirmwareLogAvailable; OpenApplicationLogItemCommand = new RelayCommand(OpenApplicationLogItem); - OpenMachineLogItemCommand = new RelayCommand(OpenMachineLogItem); + OpenFirmareLogItemCommand = new RelayCommand(OpenFirmwareLogItem); } private async void OpenApplicationLogItem(LogItemBase logItem) @@ -171,9 +171,9 @@ namespace Tango.FSE.UI.Panes await NotificationProvider.ShowDialog(new ApplicationLogItemViewVM() { LogItem = logItem }); } - private async void OpenMachineLogItem(EmbeddedLogItem logItem) + private async void OpenFirmwareLogItem(EmbeddedLogItem logItem) { - await NotificationProvider.ShowDialog(new MachineLogItemViewVM() { LogItem = logItem }); + await NotificationProvider.ShowDialog(new FirmwareLogItemViewVM() { LogItem = logItem }); } private bool FilterApplicationLogs(object obj) @@ -182,10 +182,10 @@ namespace Tango.FSE.UI.Panes return SelectedApplicationLogsCategories.SynchedSource.Contains(log.Category) && (String.IsNullOrWhiteSpace(ApplicationLogsFilter) || log.Message.ToLower().Contains(ApplicationLogsFilter.ToLower())); } - private bool FilterMachineLogs(object obj) + private bool FilterFirmwareLogs(object obj) { var log = obj as EmbeddedLogItem; - return SelectedMachineLogsCategories.SynchedSource.Contains(log.Category) && (String.IsNullOrWhiteSpace(MachineLogsFilter) || log.Message.ToLower().Contains(MachineLogsFilter.ToLower())); + return SelectedFirmwareLogsCategories.SynchedSource.Contains(log.Category) && (String.IsNullOrWhiteSpace(FirmwareLogsFilter) || log.Message.ToLower().Contains(FirmwareLogsFilter.ToLower())); } private void ClearApplicationLogs() @@ -194,10 +194,10 @@ namespace Tango.FSE.UI.Panes ApplicationLogs.Clear(); } - private void ClearMachineLogs() + private void ClearFirmwareLogs() { - _pausedMachineLogs.Clear(); - MachineLogs.Clear(); + _pausedFirmwareLogs.Clear(); + FirmwareLogs.Clear(); } private void LoggingProvider_ApplicationLogAvailable(object sender, LogItemBase logItem) @@ -225,27 +225,27 @@ namespace Tango.FSE.UI.Panes } } - private void LoggingProvider_EmbeddedLogAvailable(object sender, EmbeddedLogItem logItem) + private void LoggingProvider_FirmwareLogAvailable(object sender, EmbeddedLogItem logItem) { - if (MachineLogsPaused) + if (FirmwareLogsPaused) { - _pausedMachineLogs.Add(logItem); + _pausedFirmwareLogs.Add(logItem); } else { InvokeUI(() => { - if (_pausedMachineLogs.Count > 0) + if (_pausedFirmwareLogs.Count > 0) { - foreach (var pausedItem in _pausedMachineLogs) + foreach (var pausedItem in _pausedFirmwareLogs) { - MachineLogs.Insert(0, pausedItem); + FirmwareLogs.Insert(0, pausedItem); } - _pausedMachineLogs.Clear(); + _pausedFirmwareLogs.Clear(); } - MachineLogs.Insert(0, logItem); + FirmwareLogs.Insert(0, logItem); }); } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs index 5d5463d1b..f89c2010f 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs @@ -93,8 +93,8 @@ namespace Tango.FSE.UI TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); - TangoIOC.Default.Register(); TangoIOC.Default.Register(); + TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); -- cgit v1.3.1