using Newtonsoft.Json; 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; using System.Windows.Data; using Tango.Core.Commands; using Tango.FSE.BL.WindowsRegistry; using Tango.FSE.Common.Helpers; using Tango.FSE.Web.Messages; using Tango.Integration.Logging; using Tango.Logging; using ZetaIpc.Runtime.Server; using Tango.TFS; using System.Diagnostics; using Tango.Settings; namespace Tango.FSE.LogViewer.UI.ViewModels { public class LayoutViewVM : LogViewerViewModel { private ICollectionView _view; private IpcServer _ipcServer; private LogViewerSettings Settings { get; set; } public ObservableCollection LogFiles { get; set; } private LogFileTabViewVM _selectedLogFile; public LogFileTabViewVM SelectedLogFile { get { return _selectedLogFile; } set { _selectedLogFile = value; RaisePropertyChangedAuto(); OnSelectedLogFileChanged(); } } private String _filter; public String Filter { get { return _filter; } set { _filter = value; RaisePropertyChangedAuto(); OnFilterChanged(); } } private bool _wrapLines; public bool WrapLines { get { return _wrapLines; } set { _wrapLines = value; RaisePropertyChangedAuto(); OnWrapLinesChanged(); } } private List _recentLogFiles; public List RecentLogFiles { get { return _recentLogFiles; } set { _recentLogFiles = value; RaisePropertyChangedAuto(); } } private bool _isTabsListOpened; public bool IsTabsListOpened { get { return _isTabsListOpened; } set { _isTabsListOpened = value; RaisePropertyChangedAuto(); } } public RelayCommand OpenLogFileCommand { get; set; } public RelayCommand OpenRecentLogFileCommand { get; set; } public RelayCommand CloseLogFileCommand { get; set; } public RelayCommand SaveAsLogFileCommand { get; set; } public RelayCommand ExitCommand { get; set; } public LayoutViewVM() { WrapLines = true; RecentLogFiles = new List(); LogFiles = new ObservableCollection(); OpenLogFileCommand = new RelayCommand(OpenLogFiles); CloseLogFileCommand = new RelayCommand(CloseLogFile); SaveAsLogFileCommand = new RelayCommand(SaveAsLogFile); ExitCommand = new RelayCommand(ExitApplication); OpenRecentLogFileCommand = new RelayCommand(OpenRecentLogFile); _ipcServer = new IpcServer(); Application.Current.MainWindow.ContentRendered += MainWindow_ContentRendered; } private void MainWindow_ContentRendered(object sender, EventArgs e) { var startupArgs = Environment.GetCommandLineArgs().Skip(1).ToList(); OnApplicationReady(startupArgs); } private void ExitApplication() { Environment.Exit(0); } private async void SaveAsLogFile() { if (SelectedLogFile != null) { var result = await StorageProvider.SaveFile("Save Log File As...", "Twine Log Files|*.log", SelectedLogFile.Name, ".log"); if (result.Confirmed) { try { await Task.Factory.StartNew(() => { File.Copy(SelectedLogFile.File, result.SelectedItem, true); }); await NotificationProvider.ShowSuccess("Log file saved successfully."); } catch (Exception ex) { await NotificationProvider.ShowError($"Error saving log file.\n{ex.FlattenMessage()}"); } } } } private async void OpenLogFiles() { var result = await StorageProvider.OpenFiles("Browse for log files", "Twine Log Files|*.log"); if (result.Confirmed) { await OpenLogFiles(result.SelectedItems); } } private Task OpenLogFiles(String file) { return OpenLogFiles(new List() { file }); } private async Task OpenLogFiles(List files) { using (var task = NotificationProvider.PushTaskItem($"Loading '{Path.GetFileName(files.FirstOrDefault())}'...")) { bool setLastSelected = true; foreach (var file in files) { task.UpdateProgress($"Loading '{Path.GetFileName(file)}'..."); var existingLogFile = LogFiles.ToList().FirstOrDefault(x => x.File == file); if (existingLogFile != null) { setLastSelected = false; SelectedLogFile = existingLogFile; continue; } if (!File.Exists(file)) { await NotificationProvider.ShowError($"Error loading log file '{Path.GetFileName(file)}'. The file could not be found."); continue; } List logs = new List(); LogFileTabViewVM logFile = new LogFileTabViewVM(); try { DateTime createdTime = File.GetCreationTime(file); await Task.Delay(500); await Task.Factory.StartNew(() => { if (!Path.GetFileName(file).StartsWith("Embedded")) { ApplicationLogFileParser parser = new ApplicationLogFileParser(); logs = parser.Parse(file, createdTime); } else { EmbeddedLogFileParser parser = new EmbeddedLogFileParser(); logs = parser.Parse(file, createdTime).Cast().ToList(); logFile.IsEmbedded = true; } logFile.Name = Path.GetFileName(file); logFile.File = file; logFile.Size = Core.Helpers.FileHelper.GetFriendlyFileSize(new FileInfo(file).Length); logFile.StartTime = createdTime; logFile.EndTime = logs.Last().TimeStamp; }); logFile.Logs = new ObservableCollection(logs); LogFiles.Add(logFile); Settings.RecentFiles.RemoveAll(x => x == logFile.File); Settings.RecentFiles.Insert(0, logFile.File); if (Settings.RecentFiles.Count > 10) { Settings.RecentFiles.Remove(Settings.RecentFiles.Last()); } Settings.Save(); RecentLogFiles = Settings.RecentFiles.ToList(); } catch (Exception ex) { await NotificationProvider.ShowError($"Error loading log file '{Path.GetFileName(file)}'.\n{ex.FlattenMessage()}"); } } if (setLastSelected) { SelectedLogFile = LogFiles.LastOrDefault(); } } } private void CloseLogFile(LogFileTabViewVM logFile) { int index = LogFiles.IndexOf(logFile); int count = LogFiles.Count; LogFileTabViewVM selectedLogFile = SelectedLogFile; LogFiles.Remove(logFile); if (selectedLogFile == logFile) { if (LogFiles.Count > index) { SelectedLogFile = LogFiles[index]; } else if (LogFiles.Count > 0) { SelectedLogFile = LogFiles[index - 1]; } else { SelectedLogFile = null; } } } private void OnSelectedLogFileChanged() { IsTabsListOpened = false; if (_view != null) { _view.Filter = null; _view.Refresh(); } if (SelectedLogFile != null) { _view = CollectionViewSource.GetDefaultView(SelectedLogFile.Logs); _view.Filter = FilterLogs; } } private void OnFilterChanged() { _view?.Refresh(); } private bool FilterLogs(object obj) { bool includeLog = false; LogItemBase log = obj as LogItemBase; if (String.IsNullOrWhiteSpace(Filter)) return true; if (Filter.Contains("|")) { List keywords = Filter.Split('|').ToList(); if (keywords.Any(x => log.Category.ToString().ToLower() == x.ToLower())) { includeLog = true; } } else { if (log.Category.ToString().ToLower() == Filter.ToLower()) { includeLog = true; } } if (log.TimeStamp.ToString("HH:mm:ss").Contains(Filter)) { includeLog = true; } if (log.ClassName.ToLower() == Filter.ToLower()) { includeLog = true; } if (log.Message.ToLower().Contains(Filter.ToLower())) { includeLog = true; } return includeLog; } private void OnApplicationReady(List args) { Settings = SettingsManager.Default.GetOrCreate(); WrapLines = Settings.WrapLines; RecentLogFiles = Settings.RecentFiles.ToList(); try { LogManager.Log("Starting file association IPC service..."); _ipcServer.Start(App.FILE_ASSPCIATION_PORT); _ipcServer.ReceivedRequest += _ipcServer_ReceivedRequest; } catch (Exception ex) { LogManager.Log(ex, "Error starting file association IPC service. Another instance of the application might already be running..."); } HandleStartupArgs(args); } private void _ipcServer_ReceivedRequest(object sender, ReceivedRequestEventArgs e) { try { e.Handled = true; var argsObject = JsonConvert.DeserializeObject(e.Request); InvokeUI(() => { if (Application.Current.MainWindow.WindowState == WindowState.Minimized) { Application.Current.MainWindow.WindowState = WindowState.Normal; } Application.Current.MainWindow.Activate(); HandleStartupArgs(argsObject.Args); }); } catch (Exception ex) { LogManager.Log(ex); } } private async void HandleStartupArgs(List args) { if (args == null) return; args = StartupArgsHelper.CleanArgsFromWeb(args.ToArray()).ToList(); if (args.Count == 3 && args[0] == "-remote") { try { LoadFromTFS(args[2], (LoadFromTfsMode)Enum.Parse(typeof(LoadFromTfsMode), args[1])); } catch (Exception ex) { LogManager.Log(ex); await NotificationProvider.ShowError($"Error loading the specified work item logs.\n{ex.FlattenMessage()}"); } } else { await OpenLogFiles(args); } } private async void LoadFromTFS(String workItemID, LoadFromTfsMode mode) { try { String tempFile = null; using (NotificationProvider.PushTaskItem($"Loading {mode} logs from work item {workItemID}...")) { await Task.Factory.StartNew(() => { int id = int.Parse(workItemID); var encrypted = RegistryService.Default.GetValue("TFS"); BugReportingInfoResponse info = CryptographyProvider.Decrypt(encrypted); TeamFoundationServiceClient client = new TeamFoundationServiceClient(info.CollectionUrl, String.Empty, info.PersonalToken); Project project = client.GetProject("Tango").Result; var attachements = client.GetWorkItemAttachements(id).Result; AttachementHandler handler = attachements.Where(x => x.Extension == ".log").LastOrDefault(x => x.Name.StartsWith(mode.ToDescription()) && !x.Name.ToLower().Contains("session")); var tempFolder = TemporaryManager.CreateFolder(); tempFile = Path.Combine(tempFolder, handler.Name); handler.Download(tempFile).Wait(); }); await OpenLogFiles(tempFile); } } catch (Exception ex) { LogManager.Log(ex); await NotificationProvider.ShowError($"Error loading the specified work item logs.\n{ex.FlattenMessage()}"); } } internal async void OnFilesDropped(List files) { await OpenLogFiles(files.Where(x => File.Exists(x) && Path.GetExtension(x).ToLower() == ".log").ToList()); } private void OnWrapLinesChanged() { if (Settings != null) { Settings.WrapLines = WrapLines; Settings.Save(); } } private async void OpenRecentLogFile(string file) { await OpenLogFiles(file); } } }