예제 #1
0
        public PostprocessorsManager(
            ILogSourcesManager logSources,
            Telemetry.ITelemetryCollector telemetry,
            ISynchronizationContext modelSyncContext,
            ISynchronizationContext threadPoolSyncContext,
            IHeartBeatTimer heartbeat,
            Progress.IProgressAggregator progressAggregator,
            Settings.IGlobalSettingsAccessor settingsAccessor,
            IOutputDataDeserializer outputDataDeserializer,
            ITraceSourceFactory traceSourceFactory
            )
        {
            this.logSources             = logSources;
            this.telemetry              = telemetry;
            this.progressAggregator     = progressAggregator;
            this.settingsAccessor       = settingsAccessor;
            this.modelSyncContext       = modelSyncContext;
            this.threadPoolSyncContext  = threadPoolSyncContext;
            this.heartbeat              = heartbeat;
            this.outputDataDeserializer = outputDataDeserializer;
            this.tracer  = traceSourceFactory.CreateTraceSource("App", "ppm");
            this.updater = new AsyncInvokeHelper(modelSyncContext, Refresh);

            logSources.OnLogSourceAdded             += (sender, args) => updater.Invoke();
            logSources.OnLogSourceRemoved           += (sender, args) => updater.Invoke();
            logSources.OnLogSourceAnnotationChanged += (sender, args) => updater.Invoke();
            logSources.OnLogSourceStatsChanged      += (object sender, LogSourceStatsEventArgs e) =>
            {
                if ((e.Flags & LogProviderStatsFlag.ContentsEtag) != 0)
                {
                    updater.Invoke();
                }
            };
            Refresh();
        }
예제 #2
0
 public WorkspacesManager(
     ILogSourcesManager logSources,
     ILogProviderFactoryRegistry logProviderFactoryRegistry,
     IStorageManager storageManager,
     Backend.IBackendAccess backend,
     ITempFilesManager tempFilesManager,
     MRU.IRecentlyUsedEntities recentlyUsedEntities,
     IShutdown shutdown,
     ITraceSourceFactory traceSourceFactory
     )
 {
     this.tracer                     = traceSourceFactory.CreateTraceSource("Workspaces", "ws");
     this.logSources                 = logSources;
     this.backendAccess              = backend;
     this.tempFilesManager           = tempFilesManager;
     this.logProviderFactoryRegistry = logProviderFactoryRegistry;
     this.storageManager             = storageManager;
     this.recentlyUsedEntities       = recentlyUsedEntities;
     if (backend.IsConfigured)
     {
         this.status = WorkspacesManagerStatus.NoWorkspace;
     }
     else
     {
         this.status = WorkspacesManagerStatus.Unavailable;
     }
     shutdown.Cleanup += (s, e) => shutdown.AddCleanupTask(
         WaitUploadCompletion().WithTimeout(TimeSpan.FromSeconds(10)));
 }
예제 #3
0
        public LogSourcesPreprocessingManager(
            ISynchronizationContext invokeSynchronize,
            IFormatAutodetect formatAutodetect,
            IExtensionsRegistry extensions,
            IPreprocessingManagerExtension builtinStepsExtension,
            Telemetry.ITelemetryCollector telemetry,
            ITempFilesManager tempFilesManager,
            ILogSourcesManager logSourcesManager,
            IShutdown shutdown,
            ITraceSourceFactory traceSourceFactory,
            IChangeNotification changeNotification
            )
        {
            this.traceSourceFactory = traceSourceFactory;
            this.trace                   = traceSourceFactory.CreateTraceSource("PreprocessingManager", "prepr");
            this.invokeSynchronize       = invokeSynchronize;
            this.formatAutodetect        = formatAutodetect;
            this.providerYieldedCallback = prov => logSourcesManager.Create(prov.Factory, prov.ConnectionParams).Visible = !prov.IsHiddenLog;
            this.extensions              = extensions;
            this.telemetry               = telemetry;
            this.tempFilesManager        = tempFilesManager;
            this.logSourcesManager       = logSourcesManager;
            this.changeNotification      = changeNotification;

            extensions.Register(builtinStepsExtension);

            shutdown.Cleanup += (sender, e) =>
            {
                shutdown.AddCleanupTask(this.DeleteAllPreprocessings());
            };
        }
예제 #4
0
        public MessagesReader(
            MediaBasedReaderParams readerParams,
            FormatInfo fmt,
            FieldsProcessor.IFactory fieldsProcessorFactory,
            IRegexFactory regexFactory,
            ITraceSourceFactory traceSourceFactory
            ) :
            base(readerParams.Media, fmt.BeginFinder, fmt.EndFinder, fmt.ExtensionsInitData, fmt.TextStreamPositioningParams, readerParams.Flags, readerParams.SettingsAccessor)
        {
            if (readerParams.Threads == null)
            {
                throw new ArgumentNullException(nameof(readerParams) + ".Threads");
            }
            this.threads                = readerParams.Threads;
            this.traceSourceFactory     = traceSourceFactory;
            this.regexFactory           = regexFactory;
            this.fmtInfo                = fmt;
            this.fieldsProcessorFactory = fieldsProcessorFactory;
            this.trace = traceSourceFactory.CreateTraceSource("LogSource", string.Format("{0}.r{1:x4}", readerParams.ParentLoggingPrefix, Hashing.GetShortHashCode(this.GetHashCode())));

            base.Extensions.AttachExtensions();

            this.isBodySingleFieldExpression = new Lazy <bool>(() =>
            {
                return(CreateNewFieldsProcessor().IsBodySingleFieldExpression());
            });
        }
예제 #5
0
        public Presenter(
            IBookmarks bookmarks,
            IView view,
            LogViewer.IPresenter viewerPresenter,
            SearchResult.IPresenter searchResultPresenter,
            BookmarksList.IPresenter listPresenter,
            StatusReports.IPresenter statusReportFactory,
            IPresentersFacade navHandler,
            IAlertPopup alerts,
            ITraceSourceFactory traceSourceFactory
            )
        {
            this.bookmarks             = bookmarks;
            this.view                  = view;
            this.viewerPresenter       = viewerPresenter;
            this.tracer                = traceSourceFactory.CreateTraceSource("UI", "ui.bmkm");
            this.statusReportFactory   = statusReportFactory;
            this.searchResultPresenter = searchResultPresenter;
            this.navHandler            = navHandler;
            this.listPresenter         = listPresenter;
            this.alerts                = alerts;

            listPresenter.Click += (s, bmk) =>
            {
                IPresenter myPublicIntf = this;
                myPublicIntf.NavigateToBookmark(bmk, BookmarkNavigationOptions.EnablePopups | BookmarkNavigationOptions.BookmarksStringsSet);
            };

            view.SetPresenter(this);
        }
예제 #6
0
        public Presenter(
            IBookmarks bookmarks,
            ILogSourcesManager sourcesManager,
            IView view,
            IHeartBeatTimer heartbeat,
            LoadedMessages.IPresenter loadedMessagesPresenter,
            IClipboardAccess clipboardAccess,
            IColorTheme colorTheme,
            IChangeNotification changeNotification,
            ITraceSourceFactory traceSourceFactory
            )
        {
            this.bookmarks = bookmarks;
            this.view      = view;
            this.loadedMessagesPresenter = loadedMessagesPresenter;
            this.clipboardAccess         = clipboardAccess;
            this.colorTheme         = colorTheme;
            this.changeNotification = changeNotification;
            this.trace = traceSourceFactory.CreateTraceSource("UI", "bmks");

            itemsSelector = Selectors.Create(
                () => bookmarks.Items,
                () => selectedBookmarks,
                () => colorTheme.ThreadColors,
                () => loadedMessagesPresenter.LogViewerPresenter.Coloring,
                CreateViewItems
                );
            focusedMessagePositionSelector = Selectors.Create(
                () => loadedMessagesPresenter.LogViewerPresenter.FocusedMessageBookmark,
                () => bookmarks.Items,
                FindFocusedMessagePosition
                );

            view.SetViewModel(this);
        }
        public PluggableProtocolManager(
            ITraceSourceFactory traceSourceFactory,
            MultiInstance.IInstancesCounter instancesCounter,
            IShutdown shutdown,
            Telemetry.ITelemetryCollector telemetryCollector,
            Persistence.IFirstStartDetector firstStartDetector,
            ILaunchUrlParser launchUrlParser
            )
        {
            this.tracer          = traceSourceFactory.CreateTraceSource("PluggableProtocol");
            this.launchUrlParser = launchUrlParser;

            if (instancesCounter.IsPrimaryInstance)
            {
                this.regUpdater = RegistryUpdater(shutdown.ShutdownToken, telemetryCollector, firstStartDetector.IsFirstStartDetected);
            }

            shutdown.Cleanup += (s, e) =>
            {
                if (regUpdater != null)
                {
                    shutdown.AddCleanupTask(regUpdater.WithTimeout(TimeSpan.FromSeconds(1)));
                }
            };
        }
예제 #8
0
        internal LogSourcesManager(
            IHeartBeatTimer heartbeat,
            MRU.IRecentlyUsedEntities recentlyUsedEntities,
            IShutdown shutdown,
            ITraceSourceFactory traceSourceFactory,
            IChangeNotification changeNotification,
            ILogSourceFactory logSourceFactory
            )
        {
            this.tracer               = traceSourceFactory.CreateTraceSource("LogSourcesManager", "lsm");
            this.logSourceFactory     = logSourceFactory;
            this.recentlyUsedEntities = recentlyUsedEntities;
            this.changeNotification   = changeNotification;

            this.visibleItems = Selectors.Create(
                () => logSources,
                () => visibilityRevision,
                (items, _) => ImmutableArray.CreateRange(items.Where(i => i.Visible))
                );

            heartbeat.OnTimer += (s, e) =>
            {
                if (e.IsRareUpdate)
                {
                    PeriodicUpdate();
                }
            };

            shutdown.Cleanup += (sender, e) =>
            {
                shutdown.AddCleanupTask(this.DeleteAllLogs());
            };
        }
예제 #9
0
 public AzureWorkspacesBackend(ITraceSourceFactory traceSourceFactory, string configUri)
 {
     this.trace = traceSourceFactory.CreateTraceSource("Workspaces", "wsbackend");
     if (Uri.IsWellFormedUriString(configUri, UriKind.Absolute))
     {
         this.serviceUrl = new Uri(configUri);
     }
 }
예제 #10
0
 public PersistentUserDataManager(ITraceSourceFactory traceSourceFactory, Implementation.IStorageManagerImplementation impl, IShutdown shutdown)
 {
     this.trace = traceSourceFactory.CreateTraceSource("Storage", "storage");
     this.impl  = impl;
     this.impl.SetTrace(trace);
     this.globalSettingsEntry = new Lazy <IStorageEntry>(() => impl.GetEntry("global", 0));
     shutdown.Cleanup        += (sender, e) => impl.Dispose();
 }
예제 #11
0
        public Presenter(
            ILogSourcesManager logSourcesManager,
            IChangeNotification changeNotification,
            IView view,
            Preprocessing.IManager sourcesPreprocessingManager,
            Preprocessing.IStepsFactory preprocessingStepsFactory,
            MRU.IRecentlyUsedEntities mru,
            QuickSearchTextBox.IPresenter searchBoxPresenter,
            IAlertPopup alerts,
            ITraceSourceFactory traceSourceFactory
            )
        {
            this.view = view;
            this.changeNotification          = changeNotification;
            this.logSourcesManager           = logSourcesManager;
            this.sourcesPreprocessingManager = sourcesPreprocessingManager;
            this.preprocessingStepsFactory   = preprocessingStepsFactory;
            this.mru = mru;
            this.searchBoxPresenter = searchBoxPresenter;
            this.trace  = traceSourceFactory.CreateTraceSource("UI", "hist-dlg");
            this.alerts = alerts;

            items            = Selectors.Create(() => visible, () => acceptedFilter, MakeItems);
            actuallySelected = Selectors.Create(() => items().displayItems, () => selected,
                                                (items, selected) => items.SelectMany(i => i.Flatten()).Where(i => selected.Contains(i.key)).ToImmutableList());
            openButtonEnabled = Selectors.Create(actuallySelected, selected => selected.Any(IsOpenable));
            rootViewItem      = Selectors.Create(() => items().displayItems, () => selected, () => expanded, MakeRootItem);

            searchBoxPresenter.OnSearchNow += (s, e) =>
            {
                acceptedFilter = searchBoxPresenter.Text;
                FocusItemsListAndSelectFirstItem();
                changeNotification.Post();
            };
            searchBoxPresenter.OnRealtimeSearch += (s, e) =>
            {
                acceptedFilter = searchBoxPresenter.Text;
                changeNotification.Post();
            };
            searchBoxPresenter.OnCancelled += (s, e) =>
            {
                if (acceptedFilter != "")
                {
                    acceptedFilter = "";
                    searchBoxPresenter.Focus(null);
                }
                else
                {
                    visible = false;
                }
                changeNotification.Post();
            };

            view.SetViewModel(this);
        }
예제 #12
0
        public PostprocessorsManager(
            ILogSourcesManager logSources,
            Telemetry.ITelemetryCollector telemetry,
            ISynchronizationContext modelSyncContext,
            ISynchronizationContext threadPoolSyncContext,
            IHeartBeatTimer heartbeat,
            Progress.IProgressAggregator progressAggregator,
            Settings.IGlobalSettingsAccessor settingsAccessor,
            IOutputDataDeserializer outputDataDeserializer,
            ITraceSourceFactory traceSourceFactory,
            ILogPartTokenFactories logPartTokenFactories,
            Correlation.ISameNodeDetectionTokenFactories sameNodeDetectionTokenFactories,
            IChangeNotification changeNotification,
            LogMedia.IFileSystem logFileSystem
            )
        {
            this.logSources                      = logSources;
            this.telemetry                       = telemetry;
            this.progressAggregator              = progressAggregator;
            this.settingsAccessor                = settingsAccessor;
            this.modelSyncContext                = modelSyncContext;
            this.threadPoolSyncContext           = threadPoolSyncContext;
            this.heartbeat                       = heartbeat;
            this.outputDataDeserializer          = outputDataDeserializer;
            this.logPartTokenFactories           = logPartTokenFactories;
            this.sameNodeDetectionTokenFactories = sameNodeDetectionTokenFactories;
            this.changeNotification              = changeNotification;
            this.logFileSystem                   = logFileSystem;
            this.tracer  = traceSourceFactory.CreateTraceSource("App", "ppm");
            this.updater = new AsyncInvokeHelper(modelSyncContext, Refresh);

            logSources.OnLogSourceAdded             += (sender, args) => updater.Invoke();
            logSources.OnLogSourceRemoved           += (sender, args) => updater.Invoke();
            logSources.OnLogSourceAnnotationChanged += (sender, args) => updater.Invoke();
            logSources.OnLogSourceStatsChanged      += (object sender, LogSourceStatsEventArgs e) =>
            {
                if ((e.Flags & LogProviderStatsFlag.ContentsEtag) != 0)
                {
                    updater.Invoke();
                }
            };

            this.visiblePostprocessorsOutputs = Selectors.Create(
                () => postprocessorsOutputs,
                () => logSources.Items,
                (outputs, sources) => {
                var sourcesMap = sources.ToLookup(s => s);
                return(ImmutableArray.CreateRange(outputs.Where(output => sourcesMap.Contains(output.LogSource))));
            }
                );

            Refresh();
        }
예제 #13
0
 public UserDefinedFormatsManager(
     IFormatDefinitionsRepository repository,
     ILogProviderFactoryRegistry registry,
     ITempFilesManager tempFilesManager,
     ITraceSourceFactory traceSourceFactory
     )
 {
     this.repository         = repository ?? throw new ArgumentNullException(nameof(repository));
     this.registry           = registry ?? throw new ArgumentNullException(nameof(registry));
     this.tempFilesManager   = tempFilesManager;
     this.traceSourceFactory = traceSourceFactory;
     this.tracer             = traceSourceFactory.CreateTraceSource("UserDefinedFormatsManager", "udfm");
 }
        public Presenter(
            IView view,
            ISynchronizationContext uiInvokeSynchronization,
            Persistence.IWebContentCache cache,
            IShutdown shutdown,
            ITraceSourceFactory traceSourceFactory
            )
        {
            this.downloaderForm          = view;
            this.uiInvokeSynchronization = uiInvokeSynchronization;
            this.tracer = traceSourceFactory.CreateTraceSource("BrowserDownloader", "web.dl");
            this.cache  = cache;

            shutdown.Cleanup += Shutdown;

            downloaderForm.SetViewModel(this);
        }
예제 #15
0
        public SearchingParser(
            IPositionedMessagesReader owner,
            CreateSearchingParserParams p,
            TextStreamPositioningParams textStreamPositioningParams,
            DejitteringParams?dejitteringParams,
            Stream rawStream,
            Encoding streamEncoding,
            bool allowPlainTextSearchOptimization,
            LoadedRegex headerRe,
            ILogSourceThreads threads,
            ITraceSourceFactory traceSourceFactory,
            RegularExpressions.IRegexFactory regexFactory
            )
        {
            this.owner        = owner;
            this.parserParams = p;
            this.plainTextSearchOptimizationAllowed = allowPlainTextSearchOptimization && ((p.Flags & MessagesParserFlag.DisablePlainTextSearchOptimization) == 0);
            this.threads        = threads;
            this.requestedRange = p.Range;
            this.textStreamPositioningParams = textStreamPositioningParams;
            this.dejitteringParams           = dejitteringParams;
            this.rawStream      = rawStream;
            this.streamEncoding = streamEncoding;
            this.regexFactory   = regexFactory;
            this.trace          = traceSourceFactory.CreateTraceSource("LogSource", "srchp." + GetHashCode().ToString("x"));
            this.dummyFilter    = new Filter(FilterAction.Include, "", true, new Search.Options(), null, regexFactory);
            var continuationToken = p.ContinuationToken as ContinuationToken;

            if (continuationToken != null)
            {
                this.requestedRange = new FileRange.Range(continuationToken.NextPosition, requestedRange.End);
            }
            this.aligmentTextAccess      = new StreamTextAccess(rawStream, streamEncoding, textStreamPositioningParams);
            this.aligmentSplitter        = new MessagesSplitter(aligmentTextAccess, headerRe.Clone().Regex, headerRe.GetHeaderReSplitterFlags());
            this.aligmentCapture         = new TextMessageCapture();
            this.progressAndCancellation = new ProgressAndCancellation()
            {
                progressHandler   = p.ProgressHandler,
                cancellationToken = p.Cancellation,
                continuationToken = new ContinuationToken()
                {
                    NextPosition = requestedRange.Begin
                }
            };
            this.impl = Enum();
        }
예제 #16
0
        public TimeGapsDetector(
            LJTraceSource tracer,
            ISynchronizationContext modelSynchronizationContext,
            ITimeGapsSource source,
            ITraceSourceFactory traceSourceFactory
            )
        {
            this.traceSourceFactory = traceSourceFactory;
            this.trace = traceSourceFactory.CreateTraceSource("GapsDetector", tracer.Prefix + ".gaps");
            using (trace.NewFrame)
            {
                this.modelSynchronizationContext = modelSynchronizationContext;
                this.source = source;

                trace.Info("starting worker thread");
                thread = Task.Run((Func <Task>)ThreadProc);
            }
        }
예제 #17
0
 public AzureTelemetryUploader(
     ITraceSourceFactory traceSourceFactory,
     string telemetryUrl,
     string issuesUrl
     )
 {
     this.trace        = traceSourceFactory.CreateTraceSource("Telemetry");
     this.telemetryUrl = telemetryUrl;
     if (!Uri.IsWellFormedUriString(this.telemetryUrl, UriKind.Absolute))
     {
         this.telemetryUrl = null;
     }
     this.issuesUrl = issuesUrl;
     if (!Uri.IsWellFormedUriString(this.issuesUrl, UriKind.Absolute))
     {
         this.issuesUrl = null;
     }
 }
예제 #18
0
        public SearchResult(
            ISearchManagerInternal owner,
            SearchAllOptions options,
            IFilter optionsFilter,
            IList <ILogSourceSearchWorkerInternal> workers,
            Progress.IProgressAggregatorFactory progressAggregatorFactory,
            ISynchronizationContext modelSynchronization,
            Settings.IGlobalSettingsAccessor settings,
            int id,
            ISearchObjectsFactory factory,
            ITraceSourceFactory traceSourceFactory
            )
        {
            this.owner                = owner;
            this.options              = options;
            this.optionsFilter        = optionsFilter;
            this.factory              = factory;
            this.modelSynchronization = modelSynchronization;
            this.id                     = id;
            this.cancellation           = new CancellationTokenSource();
            this.results                = new List <ISourceSearchResultInternal>();
            this.progressAggregator     = progressAggregatorFactory.CreateProgressAggregator();
            this.updateInvokationHelper = new AsyncInvokeHelper(modelSynchronization, UpdateStatus);
            this.hitsLimit              = settings.MaxNumberOfHitsInSearchResultsView;
            this.visible                = true;
            this.trace                  = traceSourceFactory.CreateTraceSource("SearchManager", "sr." + id.ToString());
            this.timeGapsDetector       = new TimeGapsDetector(trace, modelSynchronization, this, traceSourceFactory);

            this.timeGapsDetector.OnTimeGapsChanged += (s, e) =>
            {
                owner.OnResultChanged(this, SearchResultChangeFlag.TimeGapsChanged);
            };

            this.progressAggregator.ProgressChanged += HandleProgressChanged;

            this.searchTime = Stopwatch.StartNew();
            this.results.AddRange(workers.Select(w => factory.CreateSourceSearchResults(w, this, cancellation.Token, progressAggregator)));
            if (results.Count == 0)
            {
                status = SearchResultStatus.Finished;
                HandleFinalStateTransition();
            }
        }
예제 #19
0
        public Presenter(
            ILogSourcesManager logSourcesManager,
            IView view,
            Preprocessing.IManager sourcesPreprocessingManager,
            Preprocessing.IStepsFactory preprocessingStepsFactory,
            MRU.IRecentlyUsedEntities mru,
            QuickSearchTextBox.IPresenter searchBoxPresenter,
            IAlertPopup alerts,
            ITraceSourceFactory traceSourceFactory
            )
        {
            this.view = view;
            this.logSourcesManager           = logSourcesManager;
            this.sourcesPreprocessingManager = sourcesPreprocessingManager;
            this.preprocessingStepsFactory   = preprocessingStepsFactory;
            this.mru = mru;
            this.searchBoxPresenter = searchBoxPresenter;
            this.trace  = traceSourceFactory.CreateTraceSource("UI", "hist-dlg");
            this.alerts = alerts;

            searchBoxPresenter.OnSearchNow += (s, e) =>
            {
                UpdateItems();
                FocusItemsListAndSelectFirstItem();
            };
            searchBoxPresenter.OnRealtimeSearch += (s, e) => UpdateItems();
            searchBoxPresenter.OnCancelled      += (s, e) =>
            {
                if (itemsFiltered)
                {
                    UpdateItems();
                    searchBoxPresenter.Focus(null);
                }
                else
                {
                    view.Hide();
                }
            };

            view.SetEventsHandler(this);
        }
예제 #20
0
        public PluginsManager(
            ITraceSourceFactory traceSourceFactory,
            Telemetry.ITelemetryCollector telemetry,
            IShutdown shutdown,
            IPluginFormatsManager pluginFormatsManager,
            AutoUpdate.IUpdateDownloader pluginsIndexDownloader,
            IPluginsIndexFactory pluginsIndexFactory,
            IChangeNotification changeNotification,
            AutoUpdate.IUpdateDownloader updateDownloader
            )
        {
            this.tracer                 = traceSourceFactory.CreateTraceSource("Extensibility", "plug-ins-mgr");
            this.telemetry              = telemetry;
            this.pluginFormatsManager   = pluginFormatsManager;
            this.pluginsIndexDownloader = pluginsIndexDownloader;
            this.pluginsIndexFactory    = pluginsIndexFactory;
            this.changeNotification     = changeNotification;
            this.updateDownloader       = updateDownloader;

            shutdown.Cleanup += (s, e) => Dispose();
        }
예제 #21
0
        public TempFilesManager(ITraceSourceFactory traceSourceFactory, MultiInstance.IInstancesCounter instancesCounter)
        {
            var tracer = traceSourceFactory.CreateTraceSource("App", "tmp");

            using (tracer.NewFrame)
            {
#if !SILVERLIGHT
                folder = Path.Combine(Path.GetTempPath(), "LogJoint");
#else
#endif
                tracer.Info("Temp directory: {0}", folder);

                if (!Directory.Exists(folder))
                {
                    tracer.Info("Temp directory doesn't exist. Creating it.");
                    Directory.CreateDirectory(folder);
                }
                else
                {
                    if (!instancesCounter.IsPrimaryInstance)
                    {
                        tracer.Info("Temp directory exists and I am NOT the only instance in the system. Skipping temp cleanup.");
                    }
                    else
                    {
                        tracer.Info("Temp directory exists. Deleting it first.");
                        try
                        {
                            Directory.Delete(folder, true);
                        }
                        catch (Exception e)
                        {
                            tracer.Error(e, "Failed to delete tempdir");
                        }
                    }
                    tracer.Info("Creating temp directory.");
                    Directory.CreateDirectory(folder);
                }
            }
        }
예제 #22
0
        public LogSource(ILogSourcesManagerInternal owner, int id,
                         ILogProviderFactory providerFactory, IConnectionParams connectionParams,
                         IModelThreadsInternal threads, ITempFilesManager tempFilesManager, Persistence.IStorageManager storageManager,
                         ISynchronizationContext modelSyncContext, Settings.IGlobalSettingsAccessor globalSettingsAccess, IBookmarks bookmarks,
                         ITraceSourceFactory traceSourceFactory, RegularExpressions.IRegexFactory regexFactory, LogMedia.IFileSystem fileSystem)
        {
            this.owner                = owner;
            this.tracer               = traceSourceFactory.CreateTraceSource("LogSource", string.Format("ls{0:D2}", id));
            this.tempFilesManager     = tempFilesManager;
            this.modelSyncContext     = modelSyncContext;
            this.globalSettingsAccess = globalSettingsAccess;
            this.bookmarks            = bookmarks;
            this.traceSourceFactory   = traceSourceFactory;
            this.regexFactory         = regexFactory;
            this.fileSystem           = fileSystem;

            try
            {
                this.logSourceThreads              = new LogSourceThreads(this.tracer, threads, this);
                this.timeGaps                      = new TimeGapsDetector(tracer, modelSyncContext, new LogSourceGapsSource(this), traceSourceFactory);
                this.timeGaps.OnTimeGapsChanged   += timeGaps_OnTimeGapsChanged;
                this.logSourceSpecificStorageEntry = CreateLogSourceSpecificStorageEntry(providerFactory, connectionParams, storageManager);

                var extendedConnectionParams = connectionParams.Clone(true);
                this.LoadPersistedSettings(extendedConnectionParams);
                this.provider = providerFactory.CreateFromConnectionParams(this, extendedConnectionParams);
            }
            catch (Exception e)
            {
                tracer.Error(e, "Failed to initialize log source");
                ((ILogSource)this).Dispose();
                throw;
            }

            this.owner.Add(this);
            this.owner.FireOnLogSourceAdded(this);

            this.LoadBookmarks();
        }
예제 #23
0
        public TelemetryCollector(
            Persistence.IStorageManager storage,
            ITelemetryUploader telemetryUploader,
            ISynchronizationContext synchronization,
            MultiInstance.IInstancesCounter instancesCounter,
            IShutdown shutdown,
            IMemBufferTraceAccess traceAccess,
            ITraceSourceFactory traceSourceFactory
            )
        {
            this.trace             = traceSourceFactory.CreateTraceSource("Telemetry");
            this.telemetryUploader = telemetryUploader;
            this.synchronization   = synchronization;
            this.traceAccess       = traceAccess;

            this.telemetryStorageEntry = storage.GetEntry("telemetry");
            this.sessionStartedMillis  = Environment.TickCount;

            this.currentSessionId = telemetryUploader.IsTelemetryConfigured ?
                                    ("session" + Guid.NewGuid().ToString("n")) : null;

            this.transactionInvoker = new AsyncInvokeHelper(synchronization,
                                                            () => DoSessionsRegistryTransaction(TransactionFlag.Default));

            shutdown.Cleanup += (s, e) => shutdown.AddCleanupTask(DisposeAsync());

            if (currentSessionId != null)
            {
                CreateCurrentSessionSection();
                InitStaticTelemetryProperties();
            }

            if (telemetryUploader.IsTelemetryConfigured && instancesCounter.IsPrimaryInstance)
            {
                this.workerCancellation     = new CancellationTokenSource();
                this.workerCancellationTask = new TaskCompletionSource <int>();
                this.worker = TaskUtils.StartInThreadPoolTaskScheduler(Worker);
            }
        }
예제 #24
0
 internal MultiThreadedStrategy(ILogMedia media, Encoding encoding, IRegex headerRe, MessagesSplitterFlags splitterFlags,
                                bool useMockThreading, TextStreamPositioningParams textStreamPositioningParams, string parentLoggingPrefix, ITraceSourceFactory traceSourceFactory)
     : base(media, encoding, headerRe, textStreamPositioningParams)
 {
     if (parentLoggingPrefix != null)
     {
         this.tracer = traceSourceFactory.CreateTraceSource("LogSource", string.Format("{0}.mts_{1:x4}", parentLoggingPrefix, Hashing.GetShortHashCode(this.GetHashCode())));
     }
     this.streamDataPool = new ThreadSafeObjectPool <Byte[]>(pool =>
     {
         var ret = new Byte[BytesToParsePerThread];
         tracer.Info("Allocating new piece of stream data: {0:x8}", ret.GetHashCode());
         return(ret);
     });
     this.outputBuffersPool = new ThreadSafeObjectPool <List <PostprocessedMessage> >(pool =>
     {
         var ret = new List <PostprocessedMessage>(1024 * 8);
         tracer.Info("Allocating new output buffer: {0:x8}", ret.GetHashCode());
         return(ret);
     });
     this.useMockThreading = useMockThreading;
     this.splitterFlags    = splitterFlags;
 }
예제 #25
0
파일: FactoryUI.cs 프로젝트: cxsun/logjoint
        public FactoryUI(Factory factory, ILogSourcesManager logSources, IRecentlyUsedEntities recentlyUsedLogs, ITraceSourceFactory traceSourceFactory)
        {
            this.trace            = traceSourceFactory.CreateTraceSource("UI");
            this.factory          = factory;
            this.logSources       = logSources;
            this.recentlyUsedLogs = recentlyUsedLogs;
            InitializeComponent();

            recentPeriodCounterPresenter = new Presenters.LabeledStepperPresenter.Presenter(recentPeriodCounter);
            this.recentPeriodCounterPresenter.MaxValue      = 2147483647;
            this.recentPeriodCounterPresenter.MinValue      = 1;
            this.recentPeriodCounterPresenter.Value         = 1;
            this.recentPeriodCounterPresenter.AllowedValues = new int[0];

            var mostRecentConnectionParams = FindMostRecentConnectionParams();

            if (mostRecentConnectionParams != null)
            {
                PrefillAccountFields(mostRecentConnectionParams);
            }

            SetInitialDatesRange();
            UpdateControls();
        }
예제 #26
0
        public static async Task <IPendingUpdate> Create(
            IFactory factory,
            ITempFilesManager tempFiles,
            ITraceSourceFactory traceSourceFactory,
            MultiInstance.IInstancesCounter mutualExecutionCounter,
            IReadOnlyList <Extensibility.IPluginInfo> requiredPlugins,
            string managedAssembliesPath,
            string updateLogFileName,
            CancellationToken cancellation
            )
        {
            LJTraceSource trace = traceSourceFactory.CreateTraceSource("AutoUpdater", $"pupd-{Interlocked.Increment(ref pendingUpdateIdx)}");

            string installationDir = Path.GetFullPath(
                Path.Combine(managedAssembliesPath, Constants.installationPathRootRelativeToManagedAssembliesLocation));
            string tempInstallationDir = GetTempInstallationDir(installationDir, tempFiles);

            async Task <(string tempZipFile, DownloadUpdateResult result)> Download(IUpdateDownloader updateDownloader, string name)
            {
                var tempFileName = tempFiles.GenerateNewName();

                using (var tempFileStream = new FileStream(tempFileName, FileMode.Create, FileAccess.Write))
                {
                    trace.Info("downloading update for '{0}' to '{1}'", name, tempFileName);
                    var downloadResult = await updateDownloader.DownloadUpdate(null, tempFileStream, cancellation);

                    cancellation.ThrowIfCancellationRequested();
                    if (downloadResult.Status == DownloadUpdateResult.StatusCode.Failure)
                    {
                        throw new Exception($"Failed to download update for {name}: {downloadResult.ErrorMessage}");
                    }
                    return(tempFileName, downloadResult);
                }
            }

            var downloadResults = await Task.WhenAll(
                new[] { Download(factory.CreateAppUpdateDownloader(), "app") }
                .Union(requiredPlugins.Select(plugin => Download(factory.CreatePluginUpdateDownloader(plugin), plugin.Name)))
                );

            void UnzipDownloadedUpdate(string zipFileName, string targetDir)
            {
                using (var fs = new FileStream(zipFileName, FileMode.Open))
                    using (var zipFile = new ZipArchive(fs, ZipArchiveMode.Read))
                    {
                        try
                        {
                            zipFile.ExtractToDirectory(targetDir);
                        }
                        catch (UnauthorizedAccessException e)
                        {
                            throw new BadInstallationDirException(e);
                        }
                    }
                cancellation.ThrowIfCancellationRequested();
            }

            trace.Info("unzipping downloaded update to {0}", tempInstallationDir);
            UnzipDownloadedUpdate(downloadResults[0].tempZipFile, tempInstallationDir);

            var newUpdateInfoPath = Path.Combine(tempInstallationDir,
                                                 Constants.managedAssembliesLocationRelativeToInstallationRoot, Constants.updateInfoFileName);

            new UpdateInfoFileContent(downloadResults[0].result.ETag, DateTime.UtcNow, null).Write(newUpdateInfoPath);

            UpdatePermissions(tempInstallationDir);

            trace.Info("starting updater");

            async Task <(Process process, string autoRestartFlagFileName)> StartUpdater()
            {
                var    tempUpdaterExePath = tempFiles.GenerateNewName() + ".lj.updater.exe";
                string updaterExePath;
                string programToStart;
                string firstArg;
                string autoRestartCommandLine;
                string autoRestartIPCKey;
                string restartFlagFileName;

                if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                {
                    updaterExePath = Path.Combine(installationDir, Constants.managedAssembliesLocationRelativeToInstallationRoot, "logjoint.updater.exe");
                    var monoPath = @"/Library/Frameworks/Mono.framework/Versions/Current/bin/mono";
                    programToStart         = monoPath;
                    firstArg               = string.Format("\"{0}\" ", tempUpdaterExePath);
                    restartFlagFileName    = tempFiles.GenerateNewName() + ".autorestart";
                    autoRestartIPCKey      = restartFlagFileName;
                    autoRestartCommandLine = Path.GetFullPath(Path.Combine(installationDir, ".."));
                }
                else
                {
                    updaterExePath         = Path.Combine(installationDir, "updater", "logjoint.updater.exe");
                    programToStart         = tempUpdaterExePath;
                    firstArg               = "";
                    autoRestartIPCKey      = Constants.startAfterUpdateEventName;
                    autoRestartCommandLine = Path.Combine(installationDir, "logjoint.exe");
                    restartFlagFileName    = null;
                }

                File.Copy(updaterExePath, tempUpdaterExePath);

                trace.Info("updater executable copied to '{0}'", tempUpdaterExePath);

                trace.Info("this update's log is '{0}'", updateLogFileName);

                var updaterExeProcessParams = new ProcessStartInfo()
                {
                    UseShellExecute = false,
                    FileName        = programToStart,
                    Arguments       = string.Format("{0}\"{1}\" \"{2}\" \"{3}\" \"{4}\" \"{5}\" \"{6}\"",
                                                    firstArg,
                                                    installationDir,
                                                    tempInstallationDir,
                                                    mutualExecutionCounter.MutualExecutionKey,
                                                    updateLogFileName,
                                                    autoRestartIPCKey,
                                                    autoRestartCommandLine
                                                    ),
                    WorkingDirectory = Path.GetDirectoryName(tempUpdaterExePath)
                };

                trace.Info("starting updater executable '{0}' with args '{1}'",
                           updaterExeProcessParams.FileName,
                           updaterExeProcessParams.Arguments);

                Environment.SetEnvironmentVariable("MONO_ENV_OPTIONS", "");                 // todo
                var process = Process.Start(updaterExeProcessParams);

                // wait a bit to catch and log immediate updater's failure
                for (int i = 0; i < 10 && !cancellation.IsCancellationRequested; ++i)
                {
                    if (process.HasExited && process.ExitCode != 0)
                    {
                        trace.Error("updater process exited abnormally with code {0}", process.ExitCode);
                        break;
                    }
                    await Task.Delay(100);
                }
                return(process, restartFlagFileName);
            }

            var(updater, autoRestartFlagFileName) = await StartUpdater();

            var key = factory.CreateUpdateKey(
                downloadResults[0].result.ETag,
                ImmutableDictionary.CreateRange(
                    downloadResults.Skip(1).Select(r => r.result.ETag).Zip(requiredPlugins, (etag, plugin) => new KeyValuePair <string, string>(plugin.Id, etag))
                    )
                );

            var pluginsFolder = Path.Combine(tempInstallationDir, Constants.managedAssembliesLocationRelativeToInstallationRoot, "Plugins");

            if (Directory.Exists(pluginsFolder))
            {
                Directory.Delete(pluginsFolder, true);
            }
            Directory.CreateDirectory(pluginsFolder);


            var pluginFormats = new HashSet <string>();

            foreach (var plugin in downloadResults.Skip(1).Zip(requiredPlugins, (downloadResult, plugin) => (plugin, downloadResult)))
            {
                var pluginFolder = Path.Combine(pluginsFolder, plugin.plugin.Id);
                UnzipDownloadedUpdate(plugin.downloadResult.tempZipFile, pluginFolder);
                new UpdateInfoFileContent(plugin.downloadResult.result.ETag, plugin.downloadResult.result.LastModifiedUtc, null).Write(
                    Path.Combine(pluginFolder, Constants.updateInfoFileName));

                try
                {
                    Extensibility.IPluginManifest manifest = new Extensibility.PluginManifest(pluginFolder);
                    pluginFormats.UnionWith(manifest.Files
                                            .Where(f => f.Type == Extensibility.PluginFileType.FormatDefinition)
                                            .Select(f => Path.GetFileName(f.AbsolulePath).ToLower()));
                }
                catch (Extensibility.BadManifestException)
                {
                    continue;
                }
            }

            CopyCustomFormats(
                managedAssembliesPath,
                Path.Combine(tempInstallationDir, Constants.managedAssembliesLocationRelativeToInstallationRoot),
                pluginFormats,                 // Temporary measure: plugin formats used to be copied to root Formats folder. Ignore them on update.
                trace
                );

            return(new PendingUpdate(tempInstallationDir, key, trace, updater, autoRestartFlagFileName));
        }
예제 #27
0
        public Presenter(
            ILogSourcesManager logSources,
            Preprocessing.IManager preprocessingsManager,
            IView view,
            LogViewer.IPresenterInternal viewerPresenter,
            SearchResult.IPresenter searchResultPresenter,
            SearchPanel.IPresenter searchPanelPresenter,
            SourcesManager.IPresenter sourcesManagerPresenter,
            MessagePropertiesDialog.IPresenter messagePropertiesDialogPresenter,
            LoadedMessages.IPresenter loadedMessagesPresenter,
            BookmarksManager.IPresenter bookmarksManagerPresenter,
            IHeartBeatTimer heartBeatTimer,
            ITabUsageTracker tabUsageTracker,
            StatusReports.IPresenter statusReportFactory,
            IDragDropHandler dragDropHandler,
            IPresentersFacade presentersFacade,
            IAutoUpdater autoUpdater,
            Progress.IProgressAggregator progressAggregator,
            IAlertPopup alerts,
            SharingDialog.IPresenter sharingDialogPresenter,
            IssueReportDialogPresenter.IPresenter issueReportDialogPresenter,
            IShutdownSource shutdown,
            IColorTheme theme,
            IChangeNotification changeNotification,
            ITraceSourceFactory traceSourceFactory
            )
        {
            this.tracer                = traceSourceFactory.CreateTraceSource("UI", "ui.main");
            this.logSources            = logSources;
            this.preprocessingsManager = preprocessingsManager;
            this.view                       = view;
            this.tabUsageTracker            = tabUsageTracker;
            this.searchPanelPresenter       = searchPanelPresenter;
            this.searchResultPresenter      = searchResultPresenter;
            this.bookmarksManagerPresenter  = bookmarksManagerPresenter;
            this.viewerPresenter            = viewerPresenter;
            this.presentersFacade           = presentersFacade;
            this.dragDropHandler            = dragDropHandler;
            this.heartBeatTimer             = heartBeatTimer;
            this.autoUpdater                = autoUpdater;
            this.progressAggregator         = progressAggregator;
            this.alerts                     = alerts;
            this.sharingDialogPresenter     = sharingDialogPresenter;
            this.issueReportDialogPresenter = issueReportDialogPresenter;
            this.shutdown                   = shutdown;
            this.statusRepors               = statusReportFactory;
            this.theme                      = theme;
            this.changeNotification         = changeNotification;

            view.SetViewModel(this);

            viewerPresenter.ManualRefresh += delegate(object sender, EventArgs args)
            {
                using (tracer.NewFrame)
                {
                    tracer.Info("----> User Command: Refresh");
                    logSources.Refresh();
                }
            };
            viewerPresenter.FocusedMessageBookmarkChanged += delegate(object sender, EventArgs args)
            {
                if (searchResultPresenter != null)
                {
                    searchResultPresenter.MasterFocusedMessage = viewerPresenter.FocusedMessageBookmark;
                }
            };
            if (messagePropertiesDialogPresenter != null)
            {
                viewerPresenter.DefaultFocusedMessageActionCaption = "Show properties...";
                viewerPresenter.DefaultFocusedMessageAction       += (s, e) =>
                {
                    messagePropertiesDialogPresenter.Show();
                };
            }

            if (searchResultPresenter != null)
            {
                searchResultPresenter.OnClose           += (sender, args) => searchPanelPresenter.CollapseSearchResultPanel();
                searchResultPresenter.OnResizingStarted += (sender, args) => view.BeginSplittingSearchResults();
            }

            sourcesManagerPresenter.OnBusyState += (_, evt) => SetWaitState(evt.BusyStateRequired);

            searchPanelPresenter.InputFocusAbandoned += delegate(object sender, EventArgs args)
            {
                loadedMessagesPresenter.LogViewerPresenter.ReceiveInputFocus();
            };
            loadedMessagesPresenter.OnResizingStarted += (s, e) => view.BeginSplittingTabsPanel();

            this.heartBeatTimer.OnTimer += (sender, e) =>
            {
                if (e.IsRareUpdate)
                {
                    SetAnalyzingIndication(logSources.Items.Any(s => s.TimeGaps.IsWorking));
                }
            };

            logSources.OnLogSourceAdded += (sender, evt) =>
            {
                UpdateFormCaption();
            };
            logSources.OnLogSourceRemoved += (sender, evt) =>
            {
                UpdateFormCaption();
            };

            progressAggregator.ProgressStarted += (sender, args) =>
            {
                view.SetTaskbarState(TaskbarState.Progress);
                UpdateFormCaption();
            };

            progressAggregator.ProgressEnded += (sender, args) =>
            {
                view.SetTaskbarState(TaskbarState.Idle);
                UpdateFormCaption();
            };

            progressAggregator.ProgressChanged += (sender, args) =>
            {
                view.UpdateTaskbarProgress(args.ProgressPercentage);
                UpdateFormCaption();
            };

            if (sharingDialogPresenter != null)
            {
                sharingDialogPresenter.AvailabilityChanged += (sender, args) =>
                {
                    UpdateShareButton();
                };
                sharingDialogPresenter.IsBusyChanged += (sender, args) =>
                {
                    UpdateShareButton();
                };
            }
            ;

            UpdateFormCaption();
            UpdateShareButton();

            view.SetIssueReportingMenuAvailablity(issueReportDialogPresenter.IsAvailable);
        }
예제 #28
0
        public AutoUpdater(
            IFactory factory,
            MultiInstance.IInstancesCounter mutualExecutionCounter,
            IShutdown shutdown,
            ISynchronizationContext eventInvoker,
            Telemetry.ITelemetryCollector telemetry,
            Persistence.IStorageManager storage,
            ITraceSourceFactory traceSourceFactory,
            Extensibility.IPluginsManagerInternal pluginsManager,
            IChangeNotification changeNotification
            )
        {
            this.updateDownloader = factory.CreateAppUpdateDownloader();
            this.checkRequested   = new TaskCompletionSource <int>();
            this.factory          = factory;
            this.pluginsManager   = pluginsManager;
            this.trace            = traceSourceFactory.CreateTraceSource("AutoUpdater");

            var entryAssemblyLocation = Assembly.GetEntryAssembly()?.Location;

            if (entryAssemblyLocation != null)
            {
                this.managedAssembliesPath = Path.GetDirectoryName(entryAssemblyLocation);
                this.updateInfoFilePath    = Path.Combine(managedAssembliesPath, Constants.updateInfoFileName);
                this.installationDir       = Path.GetFullPath(
                    Path.Combine(managedAssembliesPath, Constants.installationPathRootRelativeToManagedAssembliesLocation));
            }

            this.eventInvoker = eventInvoker;
            this.telemetry    = telemetry;
            this.storage      = storage;

            shutdown.Cleanup += (s, e) => ((IDisposable)this).Dispose();

            this.updatesStorageEntry = storage.GetEntry("updates");

            bool isFirstInstance        = mutualExecutionCounter.IsPrimaryInstance;
            bool isDownloaderConfigured = updateDownloader.IsDownloaderConfigured;

            if (entryAssemblyLocation == null)
            {
                trace.Info("autoupdater is disabled - no entry assembly");
                isActiveAutoUpdaterInstance = false;

                state = AutoUpdateState.Disabled;
            }
            else if (!isDownloaderConfigured)
            {
                trace.Info("autoupdater is disabled - update downloader not configured");
                isActiveAutoUpdaterInstance = false;

                state = AutoUpdateState.Disabled;
            }
            else if (!isFirstInstance)
            {
                trace.Info("autoupdater is deactivated - not a first instance of logjoint");
                isActiveAutoUpdaterInstance = false;

                state = AutoUpdateState.Inactive;
            }
            else
            {
                trace.Info("autoupdater is enabled");
                isActiveAutoUpdaterInstance = true;

                state = AutoUpdateState.Idle;

                workerCancellation      = new CancellationTokenSource();
                workerCancellationToken = workerCancellation.Token;
                workerCancellationTask  = new TaskCompletionSource <int>();

                changeListenerSubscription = changeNotification.CreateSubscription(Updaters.Create(
                                                                                       () => pluginsManager.InstallationRequests,
                                                                                       (_, prev) =>
                {
                    if (prev != null)
                    {
                        checkRequested.TrySetResult(1);
                    }
                }
                                                                                       ));

                worker = TaskUtils.StartInThreadPoolTaskScheduler(Worker);
            }
        }
예제 #29
0
 public ContentCacheManager(ITraceSourceFactory traceSourceFactory, Implementation.IStorageManagerImplementation impl)
 {
     this.trace = traceSourceFactory.CreateTraceSource("ContentCache", "cache");
     this.impl  = impl;
     this.impl.SetTrace(trace);
 }
예제 #30
0
        public Presenter(
            ILogSourcesManager logSources,
            IUserDefinedFormatsManager udfManager,
            IRecentlyUsedEntities mru,
            Preprocessing.IManager logSourcesPreprocessings,
            IView view,
            Preprocessing.IStepsFactory preprocessingStepsFactory,
            Workspaces.IWorkspacesManager workspacesManager,
            SourcesList.IPresenter sourcesListPresenter,
            NewLogSourceDialog.IPresenter newLogSourceDialogPresenter,
            IHeartBeatTimer heartbeat,
            SharingDialog.IPresenter sharingDialogPresenter,
            HistoryDialog.IPresenter historyDialogPresenter,
            IPresentersFacade facade,
            SourcePropertiesWindow.IPresenter sourcePropertiesWindowPresenter,
            IAlertPopup alerts,
            ITraceSourceFactory traceSourceFactory,
            IChangeNotification changeNotification
            )
        {
            this.logSources = logSources;
            this.udfManager = udfManager;
            this.mru        = mru;
            this.view       = view;
            this.logSourcesPreprocessings    = logSourcesPreprocessings;
            this.preprocessingStepsFactory   = preprocessingStepsFactory;
            this.workspacesManager           = workspacesManager;
            this.newLogSourceDialogPresenter = newLogSourceDialogPresenter;
            this.sourcesListPresenter        = sourcesListPresenter;
            this.tracer = traceSourceFactory.CreateTraceSource("UI", "smgr-ui");
            this.sharingDialogPresenter          = sharingDialogPresenter;
            this.historyDialogPresenter          = historyDialogPresenter;
            this.sourcePropertiesWindowPresenter = sourcePropertiesWindowPresenter;
            this.alerts             = alerts;
            this.presentersFacade   = facade;
            this.changeNotification = changeNotification;

            sourcesListPresenter.DeleteRequested += (sender, args) =>
            {
                DeleteSelectedSources();
            };

            logSourcesPreprocessings.PreprocessingAdded += (sender, args) =>
            {
                if ((args.LogSourcePreprocessing.Flags & PreprocessingOptions.HighlightNewPreprocessing) != 0)
                {
                    preprocessingAwaitingHighlighting = args.LogSourcePreprocessing;
                    pendingUpdateFlag.Invalidate();
                }
            };

            heartbeat.OnTimer += (sender, args) =>
            {
                if (pendingUpdateFlag.Validate())
                {
                    UpdateView();
                }
            };

            view.SetViewModel(this);
        }