Beispiel #1
0
        public void CompressedReadWriteTests()
        {
            TestHelper.CleanupTestFolder();
            string          directoryPath = Path.Combine(TestHelper.TestFolder, "GzipCKMonWriterClientTest");
            ActivityMonitor m             = new ActivityMonitor();
            var             client        = new CKMonWriterClient(directoryPath, 20000, LogFilter.Undefined, true);

            m.Output.RegisterClient(client);
            using (m.OpenWarn().Send("Group test"))
            {
                m.Info().Send("Line test");
            }
            // This closes the client: the file is then compressed asynchronously
            // on a thread from the ThreadPool.
            Assert.That(client.IsOpened);
            m.Output.UnregisterClient(client);
            string    ckmonPath = TestHelper.WaitForCkmonFilesInDirectory(directoryPath, 1)[0];
            LogReader r         = LogReader.Open(ckmonPath);

            r.MoveNext();
            Assert.That(r.Current.LogType, Is.EqualTo(LogEntryType.OpenGroup));
            Assert.That(r.Current.Text, Is.EqualTo("Group test"));
            r.MoveNext();
            Assert.That(r.Current.LogType, Is.EqualTo(LogEntryType.Line));
            Assert.That(r.Current.Text, Is.EqualTo("Line test"));
            r.MoveNext();
            Assert.That(r.Current.LogType, Is.EqualTo(LogEntryType.CloseGroup));
            bool hasRemainingEntries = r.MoveNext();

            Assert.That(hasRemainingEntries, Is.False);
        }
Beispiel #2
0
        public async Task persistent_error_for_sender_deactivate_the_handler_Async()
        {
            FakeLogSender.Reset();
            // Let FakeLogSender.FakeSenderCanBeCreated = false: the handler is activated
            // but cannot create the sender yet.
            FakeLogSender.FakeSenderPersistentError = true;

            var host = await StartHostAsync();

            Debug.Assert(FakeLogSender.ActivatedSender != null);
            FakeLogSender.ActivatedSender.FakeSender.Should().BeNull();

            // Conditions to create the sender becomes true.
            FakeLogSender.FakeSenderCanBeCreated = true;

            // Handling a log entry triggers the sender creation but the "persistent error"
            // throws an exception: the handler is condemned (deactivation and removed).
            var monitor = new ActivityMonitor()
            {
                AutoTags = FakeLogSender.TestTag
            };

            monitor.Info("NOSHOW");
            await Task.Delay(50);

            FakeLogSender.ActivatedSender.Should().BeNull("The handler has been deactivated and removed.");

            await host.StopAsync();
        }
Beispiel #3
0
        public void buggy_clients_are_removed_from_Output()
        {
            ActivityMonitor.AutoConfiguration = null;
            ActivityMonitor monitor = new ActivityMonitor();

            int clientCount = 0;

            if (TestHelper.LogsToConsole)
            {
                ++clientCount;
                monitor.Output.RegisterClient(new ActivityMonitorConsoleClient());
            }
            ++clientCount;
            WaitActivityMonitorClient client = monitor.Output.RegisterClient(new WaitActivityMonitorClient());

            Assert.That(monitor.Output.Clients.Count, Is.EqualTo(clientCount));

            try
            {
                Task.Factory.StartNew(() =>
                {
                    monitor.Info().Send("Test must work in task");
                });

                client.WaitForOnUnfilteredLog();

                Assert.That(() => monitor.Info().Send("Test must fail"),
                            Throws.TypeOf(typeof(InvalidOperationException)).
                            And.Message.EqualTo(Impl.ActivityMonitorResources.ActivityMonitorConcurrentThreadAccess));

                Assert.That(monitor.Output.Clients.Count, Is.EqualTo(clientCount), "Still " + clientCount + ": Concurrent call: not the fault of the Client.");
            }
            finally
            {
                client.Free();
            }

            Thread.Sleep(50);
            monitor.Info().Send("Test must work after task");

            ++clientCount;
            monitor.Output.RegisterClient(new ActionActivityMonitorClient(() =>
            {
                Assert.That(() => monitor.Info().Send("Test must fail reentrant client"),
                            Throws.TypeOf(typeof(InvalidOperationException)).
                            And.Message.EqualTo(Impl.ActivityMonitorResources.ActivityMonitorReentrancyError));
            }));

            monitor.Info().Send("Test must work after reentrant client");
            Assert.That(monitor.Output.Clients.Count, Is.EqualTo(clientCount), "The RegisterClient action above is ok: it checks that it triggered a reentrant call.");

            ++clientCount;
            monitor.Output.RegisterClient(new ActionActivityMonitorClient(() =>
            {
                monitor.Info().Send("Test must fail reentrant client");
            }));

            monitor.Info().Send("Test must work after reentrant client");
            Assert.That(monitor.Output.Clients.Count, Is.EqualTo(clientCount - 1), "The BUGGY RegisterClient action above is NOT ok: it triggers a reentrant call exception => We have removed it.");
        }
Beispiel #4
0
        public void EventsTest()
        {
            bool IsSendOnStarImmediate = true; // or false

            // create monitor
            var monitor = new ActivityMonitor(IsSendOnStarImmediate);

            // assign events
            monitor.Hand2NoteStarted += H2NStarted;
            monitor.Hand2NoteClosed  += H2NStop;

            // you can change poll delay for ActivityMonitor (time interval between IsHand2NoteRunning checks)
            Assert.AreEqual(300, monitor.PollDelayMs); // 300ms by default
            monitor.PollDelayMs = 100;

            if (ActivityMonitor.IsHand2NoteRunning)
            {
                // if h2n is running and  IsSendOnStarImmediate is set to true we expect OnHand2NoteStart to be fired almost immediately
                Assert.AreEqual(IsSendOnStarImmediate, _waitH2NStart.WaitOne(500));

                // close h2n manually and wait some time for ActivityMonitor::OnHand2NoteStop
                // Thread.Sleep(10000);
            }

            // ActivityMonitor is IDisposable
            monitor.Dispose();
            monitor.Dispose();
        }
Beispiel #5
0
        public void handler_can_send_some_log()
        {
            using (var server = TestHelper.DefaultMockServer())
            {
                server.Open();

                using (var grandOutputServer = GrandOutputHelper.GetNewGrandOutputServer())
                    using (var grandOutputClient = GrandOutputHelper.GetNewGrandOutputClient())
                    {
                        var serverActivityMonitor = new ActivityMonitor {
                            MinimalFilter = LogFilter.Debug
                        };
                        grandOutputServer.EnsureGrandOutputClient(serverActivityMonitor);

                        var clientActivityMonitor = new ActivityMonitor {
                            MinimalFilter = LogFilter.Debug
                        };
                        grandOutputClient.EnsureGrandOutputClient(clientActivityMonitor);

                        var guid = Guid.NewGuid().ToString();
                        clientActivityMonitor.Info(guid);

                        Thread.Sleep(TestHelper.DefaultSleepTime);

                        server.GetLogEntry(guid).Validate(guid).Should().BeTrue();

                        serverActivityMonitor.CloseGroup();
                        clientActivityMonitor.CloseGroup();
                    }
            }
        }
Beispiel #6
0
        public async Task creating_sender_waits_for_SenderCanBeCreated_and_Sender_is_Disposed_Async()
        {
            FakeLogSender.Reset();
            var host = await StartHostAsync();

            Debug.Assert(FakeLogSender.ActivatedSender != null);

            var monitor = new ActivityMonitor()
            {
                AutoTags = FakeLogSender.TestTag
            };

            monitor.Info("NOSHOW");
            await Task.Delay(50);

            FakeLogSender.ActivatedSender.Should().NotBeNull();
            FakeLogSender.ActivatedSender.FakeSender.Should().BeNull();
            FakeLogSender.FakeSenderCanBeCreated = true;
            monitor.Info("NOSHOW");
            await Task.Delay(50);

            var sender = FakeLogSender.ActivatedSender.FakeSender;

            Debug.Assert(sender != null);
            sender.Disposed.Should().BeFalse();

            FakeLogSender.LogSent.Should().BeEmpty("FakeSenderIsActuallyConnected is false: no log can be sent.");

            await host.StopAsync();

            sender.Disposed.Should().BeTrue();
        }
        public void registering_multiple_times_the_same_client_is_an_error()
        {
            ActivityMonitor.AutoConfiguration = null;
            IActivityMonitor monitor = new ActivityMonitor();
            Assert.That( monitor.Output.Clients.Count, Is.EqualTo( 0 ) );

            var counter = new ActivityMonitorErrorCounter();
            monitor.Output.RegisterClient( counter );
            Assert.That( monitor.Output.Clients.Count, Is.EqualTo( 1 ) );
            Assert.Throws<InvalidOperationException>( () => TestHelper.ConsoleMonitor.Output.RegisterClient( counter ), "Counter can be registered in one source at a time." );

            var pathCatcher = new ActivityMonitorPathCatcher();
            monitor.Output.RegisterClient( pathCatcher );
            Assert.That( monitor.Output.Clients.Count, Is.EqualTo( 2 ) );
            Assert.Throws<InvalidOperationException>( () => TestHelper.ConsoleMonitor.Output.RegisterClient( pathCatcher ), "PathCatcher can be registered in one source at a time." );

            IActivityMonitor other = new ActivityMonitor( applyAutoConfigurations: false );
            ActivityMonitorBridge bridgeToConsole;
            using( monitor.Output.CreateBridgeTo( TestHelper.ConsoleMonitor.Output.BridgeTarget ) )
            {
                bridgeToConsole = monitor.Output.FindBridgeTo( TestHelper.ConsoleMonitor.Output.BridgeTarget );
                Assert.That( monitor.Output.Clients.Count, Is.EqualTo( 3 ) );
                Assert.That( bridgeToConsole.TargetMonitor, Is.SameAs( TestHelper.ConsoleMonitor ) );

                Assert.Throws<InvalidOperationException>( () => other.Output.RegisterClient( bridgeToConsole ), "Bridge can be associated to only one source monitor." );
            }
            Assert.That( monitor.Output.Clients.Count, Is.EqualTo( 2 ) );

            Assert.DoesNotThrow( () => other.Output.RegisterClient( bridgeToConsole ), "Now we can." );

            Assert.DoesNotThrow( () => monitor.Output.UnregisterClient( bridgeToConsole ), "Already removed." );
            monitor.Output.UnregisterClient( counter );
            monitor.Output.UnregisterClient( pathCatcher );
            Assert.That( monitor.Output.Clients.Count, Is.EqualTo( 0 ) );
        }
        public void FindInactiveRssFeeds_CompanyWithMultipleFeedMixActivity_ReturnEmptyList()
        {
            DateTimeOffset activeDate   = DateTimeOffset.Now.AddHours(-23);
            DateTimeOffset inactiveDate = DateTimeOffset.Now.AddHours(-25);
            string         companyName  = "Fake Company";

            var mock = new Mock <IRssReader>();

            mock.Setup(r => r.LoadRssFeed(It.IsAny <string>())).Returns(true);
            mock.SetupSequence(r => r.MostRecentItemPublished)
            .Returns(activeDate)
            .Returns(activeDate)
            .Returns(inactiveDate)
            .Returns(inactiveDate);
            mock.Setup(r => r.IsLoaded).Returns(true);
            mockReader = mock.Object;

            IRssActivityMonitor monitor = new ActivityMonitor(mockReader);

            Dictionary <string, List <string> > inputRssFeeds = new Dictionary <string, List <string> >();

            inputRssFeeds.Add(companyName, new List <string>()
            {
                "http://fake.feed.xml", "http://fake.second-feed.xml"
            });

            List <string> InactiveCompanies = monitor.FindInactiveRssFeeds(inputRssFeeds);

            Assert.AreEqual(0, InactiveCompanies.Count);
        }
        public void ApplyConfigSimple()
        {
            GrandOutputConfiguration c = new GrandOutputConfiguration();

            Assert.That(c.Load(XDocument.Parse(@"
<GrandOutputConfiguration AppDomainDefaultFilter=""Release"" >
    <Channel MinimalFilter=""{Trace,Info}"">
        <Add Type=""BinaryFile"" Name=""GlobalCatch"" Path=""Configuration/ApplyConfig"" />
    </Channel>
</GrandOutputConfiguration>").Root, TestHelper.ConsoleMonitor));

            Assert.That(c.ChannelsConfiguration.Configurations.Count, Is.EqualTo(1));

            ActivityMonitor m = new ActivityMonitor(false);

            using (GrandOutput g = new GrandOutput())
            {
                m.Info().Send("Before Registering - NOSHOW");
                g.Register(m);
                m.Info().Send("Before configuration - NOSHOW");
                Assert.That(g.SetConfiguration(c, TestHelper.ConsoleMonitor));
                m.Info().Send("After configuration. INFO1");

                Assert.That(m.ActualFilter, Is.EqualTo(new LogFilter(LogLevelFilter.Trace, LogLevelFilter.Info)));
                m.Trace().Send("TRACE1-NOSHOW (MinimalFilter of the Channel).");

                Assert.That(g.SetConfiguration(new GrandOutputConfiguration(), TestHelper.ConsoleMonitor));
                g.Dispose(TestHelper.ConsoleMonitor);

                m.Info().Send("After disposing - NOSHOW.");

                Assert.That(m.ActualFilter, Is.EqualTo(LogFilter.Undefined));
            }
        }
        public void FindInactiveRssFeeds_RssReaderErrorTreatAsInactive_ReturnListOfOne()
        {
            DateTimeOffset inactiveDate1 = DateTimeOffset.Now.AddHours(-21);
            DateTimeOffset inactiveDate2 = DateTimeOffset.Now.AddHours(-21);
            string         companyName1  = "Fake Company";
            string         companyName2  = "Other Company";

            var mock = new Mock <IRssReader>();

            mock.Setup(r => r.LoadRssFeed(It.IsAny <string>())).Returns(true);
            mock.SetupSequence(r => r.MostRecentItemPublished)
            .Returns(inactiveDate1)
            .Returns(inactiveDate1)
            .Throws(new Exception("This is a fake error"));
            mock.Setup(r => r.IsLoaded).Returns(true);
            mockReader = mock.Object;

            IRssActivityMonitor monitor = new ActivityMonitor(mockReader);

            Dictionary <string, List <string> > inputRssFeeds = new Dictionary <string, List <string> >();

            inputRssFeeds.Add(companyName1, new List <string>()
            {
                "http://fake.feed.xml"
            });
            inputRssFeeds.Add(companyName2, new List <string>()
            {
                "http://fake.second-feed.xml"
            });

            List <string> InactiveCompanies = monitor.FindInactiveRssFeeds(inputRssFeeds);

            Assert.AreEqual(1, InactiveCompanies.Count);
        }
        public void FindInactiveRssFeeds_RssReaderErrorGetThrown_ExceptionThrown()
        {
            DateTimeOffset inactiveDate1 = DateTimeOffset.Now.AddHours(-21);
            DateTimeOffset inactiveDate2 = DateTimeOffset.Now.AddHours(-21);
            string         companyName1  = "Fake Company";
            string         companyName2  = "Other Company";

            var mock = new Mock <IRssReader>();

            mock.Setup(r => r.LoadRssFeed(It.IsAny <string>())).Returns(true);
            mock.SetupSequence(r => r.MostRecentItemPublished)
            .Returns(inactiveDate1)
            .Returns(inactiveDate1)
            .Throws(new Exception("This is a fake error"));
            mock.Setup(r => r.IsLoaded).Returns(true);
            mockReader = mock.Object;

            IRssActivityMonitor monitor = new ActivityMonitor(mockReader);

            Dictionary <string, List <string> > inputRssFeeds = new Dictionary <string, List <string> >();

            inputRssFeeds.Add(companyName1, new List <string>()
            {
                "http://fake.feed.xml"
            });
            inputRssFeeds.Add(companyName2, new List <string>()
            {
                "http://fake.second-feed.xml"
            });

            List <string> InactiveCompanies = monitor.FindInactiveRssFeeds(inputRssFeeds, 1, false);

            Assert.Fail("Exeption should have been raised prior to this point");
        }
        public void FindInactiveRssFeeds_CompanyWith1InactiveFeed_ReturnCompanyInList()
        {
            DateTimeOffset inactiveDate = DateTimeOffset.Now.AddHours(-25);
            string         companyName  = "Fake Company";

            var mock = new Mock <IRssReader>();

            mock.Setup(r => r.LoadRssFeed(It.IsAny <string>())).Returns(true);
            mock.Setup(r => r.MostRecentItemPublished).Returns(inactiveDate);
            mock.SetupSequence(r => r.IsLoaded)
            .Returns(false)
            .Returns(true);
            mockReader = mock.Object;

            IRssActivityMonitor monitor = new ActivityMonitor(mockReader);

            Dictionary <string, List <string> > inputRssFeeds = new Dictionary <string, List <string> >();

            inputRssFeeds.Add(companyName, new List <string>()
            {
                "http://fake.feed.xml"
            });

            List <string> InactiveCompanies = monitor.FindInactiveRssFeeds(inputRssFeeds);

            Assert.AreEqual(1, InactiveCompanies.Count);
            Assert.AreEqual(companyName, InactiveCompanies[0], false, "Company Name is not the correct value");
        }
        public void SourceFileOverrideFilterTest()
        {
            {
                var m = new ActivityMonitor( applyAutoConfigurations: false );
                var c = m.Output.RegisterClient( new StupidStringClient() );

                Assert.That( m.ActualFilter, Is.EqualTo( LogFilter.Undefined ) );
                m.Trace().Send( "Trace1" );
                m.OpenTrace().Send( "OTrace1" );
                ActivityMonitor.SourceFilter.SetOverrideFilter( LogFilter.Release );
                m.Trace().Send( "NOSHOW" );
                m.OpenTrace().Send( "NOSHOW" );
                ActivityMonitor.SourceFilter.SetOverrideFilter( LogFilter.Undefined );
                m.Trace().Send( "Trace2" );
                m.OpenTrace().Send( "OTrace2" );

                CollectionAssert.AreEqual( new[] { "Trace1", "OTrace1", "Trace2", "OTrace2" }, c.Entries.Select( e => e.Text ).ToArray(), StringComparer.OrdinalIgnoreCase );
            }
            {
                var m = new ActivityMonitor( applyAutoConfigurations: false );
                var c = m.Output.RegisterClient( new StupidStringClient() );

                m.MinimalFilter = LogFilter.Terse;
                m.Trace().Send( "NOSHOW" );
                m.OpenTrace().Send( "NOSHOW" );
                ActivityMonitor.SourceFilter.SetOverrideFilter( LogFilter.Debug );
                m.Trace().Send( "Trace1" );
                m.OpenTrace().Send( "OTrace1" );
                ActivityMonitor.SourceFilter.SetOverrideFilter( LogFilter.Undefined );
                m.Trace().Send( "NOSHOW" );
                m.OpenTrace().Send( "NOSHOW" );

                CollectionAssert.AreEqual( new[] { "Trace1", "OTrace1" }, c.Entries.Select( e => e.Text ).ToArray(), StringComparer.OrdinalIgnoreCase );
            }
        }
 /// <summary>
 /// Resumes the given task.
 /// </summary>
 /// <param name="p_tskTask">The task to resume.</param>
 public void ResumeTask(IBackgroundTask p_tskTask)
 {
     if (ActivityMonitor.CanResume(p_tskTask))
     {
         ActivityMonitor.ResumeActivity(p_tskTask);
     }
 }
Beispiel #15
0
        public void ThreadSafeOnClientMinimalFilterChanged()
        {
            var monitor = new ActivityMonitor(false);
            var c       = monitor.Output.RegisterClient(new ActivityMonitorClientTester());

            Parallel.For(0, 20, i => c.AsyncSetMinimalFilterBlock(new LogFilter(LogLevelFilter.Info, (LogLevelFilter)(i % 5 + 1)), 1));
        }
 /// <summary>
 /// Puases the given task.
 /// </summary>
 /// <param name="p_tskTask">The task to pause.</param>
 public void PauseTask(IBackgroundTask p_tskTask)
 {
     if (ActivityMonitor.CanPause(p_tskTask))
     {
         ActivityMonitor.PauseActivity(p_tskTask);
     }
 }
        public void parsing_DependentToken_with_topics( string topic )
        {
            var monitor = new ActivityMonitor();
            var t1 = monitor.DependentActivity().CreateTokenWithTopic( topic );
            var t2 = monitor.DependentActivity().CreateTokenWithTopic( topic );
            var t3 = monitor.DependentActivity().CreateTokenWithTopic( topic );
            Assume.That( t2.CreationDate.Uniquifier + t3.CreationDate.Uniquifier > 0 );

            var r1 = ActivityMonitor.DependentToken.Parse( t1.ToString() );

            Assert.That( r1.OriginatorId, Is.EqualTo( t1.OriginatorId ) );
            Assert.That( r1.CreationDate, Is.EqualTo( t1.CreationDate ) );
            Assert.That( r1.Topic, Is.EqualTo( t1.Topic ) );
            Assert.That( r1.ToString(), Is.EqualTo( t1.ToString() ) );

            var r2 = ActivityMonitor.DependentToken.Parse( t2.ToString() );
            Assert.That( r2.OriginatorId, Is.EqualTo( t2.OriginatorId ) );
            Assert.That( r2.CreationDate, Is.EqualTo( t2.CreationDate ) );
            Assert.That( r2.Topic, Is.EqualTo( t2.Topic ) );
            Assert.That( r2.ToString(), Is.EqualTo( t2.ToString() ) );

            var r3 = ActivityMonitor.DependentToken.Parse( t3.ToString() );
            Assert.That( r3.OriginatorId, Is.EqualTo( t3.OriginatorId ) );
            Assert.That( r3.CreationDate, Is.EqualTo( t3.CreationDate ) );
            Assert.That( r3.Topic, Is.EqualTo( t3.Topic ) );
            Assert.That( r3.ToString(), Is.EqualTo( t3.ToString() ) );
        }
Beispiel #18
0
            static GrandOutput CreateGrandOutputWithFakeHandler(int handlerExtralLoad, bool useAdaptive, int dispatcherMaxCapacity)
            {
                IActivityMonitor mLoad = new ActivityMonitor(false);

                GrandOutputConfiguration c = new GrandOutputConfiguration();
                var textConfig             = @"<GrandOutputConfiguration><Channel><Add Type=""FakeHandler, CK.Monitoring.Tests"" Name=""GlobalCatch"" ExtraLoad="""
                                             + handlerExtralLoad.ToString()
                                             + @""" /></Channel></GrandOutputConfiguration>";

                Assert.That(c.Load(XDocument.Parse(textConfig).Root, mLoad));
                Assert.That(c.ChannelsConfiguration.Configurations.Count, Is.EqualTo(1));

                IGrandOutputDispatcherStrategy strat;

                if (useAdaptive)
                {
                    strat = new Impl.EventDispatcherLocalTestStrategy(dispatcherMaxCapacity);
                }
                else
                {
                    strat = new Impl.EventDispatcherBasicStrategy(dispatcherMaxCapacity);
                }
                GrandOutput g = new GrandOutput(strat);

                g.SetConfiguration(c, mLoad);
                return(g);
            }
Beispiel #19
0
        private static void Main(string[] args)
        {
            SetupActivityMonitor();
            var m = new ActivityMonitor();

            var doContinue = true;

            while (doContinue)
            {
                System.Console.WriteLine("Press q to quit, m to send a line, s to send a CriticalError");
                var k = System.Console.ReadKey(true);
                switch (k.Key)
                {
                case ConsoleKey.Q:
                    m.Info("Goodbye");
                    doContinue = false;
                    break;

                case ConsoleKey.M:
                    m.Info($"Hello world - {DateTime.Now:R} - {Guid.NewGuid()}");
                    break;

                case ConsoleKey.S:
                    m.Error($"CriticalError - {DateTime.Now:R}");
                    break;

                default:
                    m.Warn($"Unknown key {k.Key}");
                    break;
                }
            }
        }
        public void FindInactiveRssFeeds_ChangeDaysParamToTwo_ReturnListOfZero()
        {
            DateTimeOffset inactiveDate1 = DateTimeOffset.Now.AddHours(-26);
            DateTimeOffset inactiveDate2 = DateTimeOffset.Now.AddHours(-25);
            string         companyName1  = "Fake Company";
            string         companyName2  = "Other Company";

            var mock = new Mock <IRssReader>();

            mock.Setup(r => r.LoadRssFeed(It.IsAny <string>())).Returns(true);
            mock.SetupSequence(r => r.MostRecentItemPublished)
            .Returns(inactiveDate1)
            .Returns(inactiveDate1)
            .Returns(inactiveDate2)
            .Returns(inactiveDate2);
            mock.Setup(r => r.IsLoaded).Returns(true);
            mockReader = mock.Object;

            IRssActivityMonitor monitor = new ActivityMonitor(mockReader);

            Dictionary <string, List <string> > inputRssFeeds = new Dictionary <string, List <string> >();

            inputRssFeeds.Add(companyName1, new List <string>()
            {
                "http://fake.feed.xml"
            });
            inputRssFeeds.Add(companyName2, new List <string>()
            {
                "http://fake.second-feed.xml"
            });

            List <string> InactiveCompanies = monitor.FindInactiveRssFeeds(inputRssFeeds, 2);

            Assert.AreEqual(0, InactiveCompanies.Count);
        }
Beispiel #21
0
        public static void ConstructIndex()
        {
            if (_initialized)
            {
                return;
            }

            using (var server = TestHelper.DefaultGloutonServer())
            {
                server.Open(new HandlersManagerConfiguration
                {
                    GloutonHandlers = { LuceneGloutonHandlerConfiguration }
                });

                using (var grandOutputClient = GrandOutputHelper.GetNewGrandOutputClient())
                {
                    var activityMonitor = new ActivityMonitor(false)
                    {
                        MinimalFilter = LogFilter.Debug
                    };
                    grandOutputClient.EnsureGrandOutputClient(activityMonitor);

                    activityMonitor.Info("Hello world");
                    activityMonitor.Error("CriticalError");

                    TotalLogCount += 2;

                    activityMonitor.Fatal(ThrowAggregateException(3));
                }
            }
            _initialized = true;
        }
        public void ThreadSafeOnClientMinimalFilterChanged()
        {
            var monitor = new ActivityMonitor( false );
            var c = monitor.Output.RegisterClient( new ActivityMonitorClientTester() );
            Parallel.For( 0, 20, i => c.AsyncSetMinimalFilterBlock( new LogFilter( LogLevelFilter.Info, (LogLevelFilter)(i % 5 + 1) ), 1 ) );

        }
        public async Task Configuration_changes_dont_stutter_Async()
        {
            DemoSinkHandler.Reset();
            var config = new DynamicConfigurationSource();

            config["CK-Monitoring:GrandOutput:Handlers:CK.Monitoring.Hosting.Tests.DemoSinkHandler, CK.Monitoring.Hosting.Tests"] = "true";
            var host = new HostBuilder()
                       .ConfigureAppConfiguration((hostingContext, c) => c.Add(config))
                       .UseCKMonitoring()
                       .Build();
            await host.StartAsync();

            var m = new ActivityMonitor("The starting topic!");

            config["CK-Monitoring:GrandOutput:Handlers:Console"] = "true";

            await Task.Delay(200);

            m.Info("DONE!");

            await host.StopAsync();

            var texts = DemoSinkHandler.LogEvents.OrderBy(e => e.LogTime).Select(e => e.Text).Concatenate(System.Environment.NewLine);

            texts.Should()
            .Contain("GrandOutput.Default configuration n°0")
            .And.Contain("GrandOutput.Default configuration n°1")
            .And.NotContain("GrandOutput.Default configuration n°2")
            .And.Contain("DONE!");
        }
        public async Task Invalid_configurations_are_skipped_and_errors_go_to_the_current_handlers_Async()
        {
            DemoSinkHandler.Reset();
            var config = new DynamicConfigurationSource();

            config["CK-Monitoring:GrandOutput:Handlers:CK.Monitoring.Hosting.Tests.DemoSinkHandler, CK.Monitoring.Hosting.Tests"] = "true";
            var host = new HostBuilder()
                       .ConfigureAppConfiguration((hostingContext, c) => c.Add(config))
                       .UseCKMonitoring()
                       .Build();
            await host.StartAsync();

            var m = new ActivityMonitor("The topic!");

            m.Info("BEFORE");
            config["CK-Monitoring:GrandOutput:Handlers:Invalid Handler"] = "true";
            m.Info("AFTER");

            await host.StopAsync();

            DemoSinkHandler.LogEvents.Select(e => e.Text).Should()
            .Contain("Topic: The topic!")
            .And.Contain("BEFORE")
            .And.Contain("While applying dynamic configuration.")
            .And.Contain("AFTER");
        }
Beispiel #25
0
        static IActivityMonitor CreateMonitorAndRegisterGrandOutput(string topic, GrandOutput go)
        {
            var m = new ActivityMonitor(topic);

            go.Register(m);
            return(m);
        }
        public DispatcherSink(Action <IActivityMonitor> initialRegister,
                              IdentityCard identityCard,
                              TimeSpan timerDuration,
                              TimeSpan externalTimerDuration,
                              Action externalTimer,
                              Action <LogFilter?, LogLevelFilter?> filterChange,
                              bool isDefaultGrandOutput)
        {
            _initialRegister = initialRegister;
            _identityCard    = identityCard;
            _queue           = Channel.CreateUnbounded <IMulticastLogEntry?>(new UnboundedChannelOptions()
            {
                SingleReader = true
            });
            _handlers             = new List <IGrandOutputHandler>();
            _confTrigger          = new object();
            _stopTokenSource      = new CancellationTokenSource();
            _timerDuration        = timerDuration;
            _deltaTicks           = timerDuration.Ticks;
            _deltaExternalTicks   = externalTimerDuration.Ticks;
            _externalOnTimer      = externalTimer;
            _filterChange         = filterChange;
            _externalLogLock      = new object();
            _externalLogLastTime  = DateTimeStamp.MinValue;
            _isDefaultGrandOutput = isDefaultGrandOutput;
            _newConf = Array.Empty <GrandOutputConfiguration>();
            var monitor = new ActivityMonitor(applyAutoConfigurations: false);

            // We emit the identity card changed from this monitor (so we need its id).
            // But more importantly, this monitor identifier is the one of the GrandOutput: each log entry
            // references this identifier.
            _sinkMonitorId = monitor.UniqueId;
            _task          = ProcessAsync(monitor);
        }
Beispiel #27
0
        public void parsing_DependentToken_with_topics(string topic)
        {
            var monitor = new ActivityMonitor();
            var t1      = monitor.DependentActivity().CreateTokenWithTopic(topic);
            var t2      = monitor.DependentActivity().CreateTokenWithTopic(topic);
            var t3      = monitor.DependentActivity().CreateTokenWithTopic(topic);

            Assume.That(t2.CreationDate.Uniquifier + t3.CreationDate.Uniquifier > 0);

            var r1 = ActivityMonitor.DependentToken.Parse(t1.ToString());

            Assert.That(r1.OriginatorId, Is.EqualTo(t1.OriginatorId));
            Assert.That(r1.CreationDate, Is.EqualTo(t1.CreationDate));
            Assert.That(r1.Topic, Is.EqualTo(t1.Topic));
            Assert.That(r1.ToString(), Is.EqualTo(t1.ToString()));

            var r2 = ActivityMonitor.DependentToken.Parse(t2.ToString());

            Assert.That(r2.OriginatorId, Is.EqualTo(t2.OriginatorId));
            Assert.That(r2.CreationDate, Is.EqualTo(t2.CreationDate));
            Assert.That(r2.Topic, Is.EqualTo(t2.Topic));
            Assert.That(r2.ToString(), Is.EqualTo(t2.ToString()));

            var r3 = ActivityMonitor.DependentToken.Parse(t3.ToString());

            Assert.That(r3.OriginatorId, Is.EqualTo(t3.OriginatorId));
            Assert.That(r3.CreationDate, Is.EqualTo(t3.CreationDate));
            Assert.That(r3.Topic, Is.EqualTo(t3.Topic));
            Assert.That(r3.ToString(), Is.EqualTo(t3.ToString()));
        }
Beispiel #28
0
        public void SourceFileMinimalFilterTest()
        {
            {
                var m = new ActivityMonitor(applyAutoConfigurations: false);
                var c = m.Output.RegisterClient(new StupidStringClient());

                Assert.That(m.ActualFilter, Is.EqualTo(LogFilter.Undefined));
                m.Trace().Send("Trace1");
                m.OpenTrace().Send("OTrace1");
                ActivityMonitor.SourceFilter.SetMinimalFilter(LogFilter.Release);
                m.Trace().Send("NOSHOW");
                m.OpenTrace().Send("NOSHOW");
                ActivityMonitor.SourceFilter.SetMinimalFilter(LogFilter.Undefined);
                m.Trace().Send("Trace2");
                m.OpenTrace().Send("OTrace2");

                CollectionAssert.AreEqual(new[] { "Trace1", "OTrace1", "Trace2", "OTrace2" }, c.Entries.Select(e => e.Text).ToArray(), StringComparer.OrdinalIgnoreCase);
            }
            {
                var m = new ActivityMonitor(applyAutoConfigurations: false);
                var c = m.Output.RegisterClient(new StupidStringClient());

                m.MinimalFilter = LogFilter.Terse;
                m.Trace().Send("NOSHOW");
                m.OpenTrace().Send("NOSHOW");
                ActivityMonitor.SourceFilter.SetMinimalFilter(LogFilter.Debug);
                m.Trace().Send("Trace1");
                m.OpenTrace().Send("OTrace1");
                ActivityMonitor.SourceFilter.SetMinimalFilter(LogFilter.Undefined);
                m.Trace().Send("NOSHOW");
                m.OpenTrace().Send("NOSHOW");

                CollectionAssert.AreEqual(new[] { "Trace1", "OTrace1" }, c.Entries.Select(e => e.Text).ToArray(), StringComparer.OrdinalIgnoreCase);
            }
        }
        static void Main(string[] args)
        {
            var m = new ActivityMonitor(topic: "I'm full of colors (and I'm playing with levels and filters).");

            m.Output.RegisterClient(new ColoredActivityMonitorConsoleClient());

            m.MinimalFilter = LogFilter.Terse;
            using (m.OpenInfo($"Let's go: the actual filter is {m.ActualFilter}."))
            {
                m.Info("In Terse filter, only Info (and above) groups and only Error or Fatal lines are logged. So you won't see this.");

                using (m.OpenError("A whole group of error."))
                {
                    m.Debug("Debug is the lowest level.");
                    m.Debug($"In an Error or Fatal group, the minimal filter is automatically set to {m.ActualFilter} (that's why you can see this line).");
                    m.Trace("Trace is low level.");
                    m.Info("Info is interesting.");
                    m.Warn("Warning is not serious.");
                    m.Error("Error should be investigated.");
                    m.Fatal("Fatal ruins the process.");

                    m.CloseGroup("This concludes the error (the using } close below will do nothing).");
                }
                m.MinimalFilter = LogFilter.Verbose;
                m.Info("Verbose filter let's the Info lines be logged.");
                m.Info("Note that closing a group restores the minimal filter level that was set on the opening.");
            }
            Debug.Assert(m.ActualFilter == LogFilter.Terse);
            m.MinimalFilter = LogFilter.Monitor;
            m.Warn("Using Monitor filter, only Warn, Error and Fatal lines are logged.");

            System.Console.ReadLine();
        }
        public void BinaryGzip_reconfiguration()
        {
            string folder = TestHelper.PrepareLogFolder(nameof(BinaryGzip_reconfiguration));
            var    h      = new Handlers.BinaryFileConfiguration()
            {
                Path = folder + @"\FirstPath",
                UseGzipCompression = false
            };
            var c = new GrandOutputConfiguration().AddHandler(h);

            var m = new ActivityMonitor(applyAutoConfigurations: false);

            using (GrandOutput g = new GrandOutput(c))
            {
                g.EnsureGrandOutputClient(m);

                m.Trace("No Compression.");
                // We must ensure that the log above will use the current configuration.
                // This is by design and is a good thing: there is no causality/ordering between log emission and sink reconfigurations.
                Thread.Sleep(100);

                h.UseGzipCompression = true;
                g.ApplyConfiguration(c, true);
                m.Trace("With Compression.");
                Thread.Sleep(100);

                h.Path = folder + @"\SecondPath";
                g.ApplyConfiguration(c, true);
                m.Trace("With Compression (in second folder).");
                Thread.Sleep(100);

                h.UseGzipCompression = false;
                g.ApplyConfiguration(c, true);
                m.Trace("No Compression (in second folder).");
            }
            // First file is NOT compressed, the second one is.
            var fileNamesFirst = Directory.EnumerateFiles(folder + @"\FirstPath").ToList();

            fileNamesFirst.Should().BeInAscendingOrder().And.HaveCount(2).And.NotContain(s => s.EndsWith(".tmp"), "Temporary files have been closed.");
            File.ReadAllText(fileNamesFirst[0]).Should().Contain("No Compression.");
            File.ReadAllText(fileNamesFirst[1]).Should().NotContain("With Compression.", "Cannot read it in clear text since it is compressed...");
            using (var reader = LogReader.Open(fileNamesFirst[1]))
            {
                reader.MoveNext().Should().BeTrue();
                reader.Current.Text.Should().Be("With Compression.");
            }
            // First file is compressed, not the second one.
            var fileNamesSecond = Directory.EnumerateFiles(folder + @"\SecondPath").ToList();

            fileNamesSecond.Should().BeInAscendingOrder().And.HaveCount(2).And.NotContain(s => s.EndsWith(".tmp"), "Temporary files have been closed.");
            File.ReadAllText(fileNamesSecond[0]).Should().NotContain("With Compression (in second folder).", "The fist file is compressed...");
            // We restrict the log entries to the one of our monitor: this filters out the logs from the DispatcherSink.
            using (var reader = LogReader.Open(fileNamesSecond[0], filter: new LogReader.MulticastFilter(m)))
            {
                reader.MoveNext().Should().BeTrue();
                reader.Current.Text.Should().Be("With Compression (in second folder).");
            }
            File.ReadAllText(fileNamesSecond[1]).Should().Contain("No Compression (in second folder).");
        }
Beispiel #31
0
        public void can_add_alert()
        {
            using (var server = TestHelper.DefaultGloutonServer())
            {
                server.Open(new HandlersManagerConfiguration
                {
                    GloutonHandlers =
                    {
                        new AlertHandlerConfiguration {
                            DatabasePath = @"%localappdata%/Glouton/Alerts".GetPathWithSpecialFolders()
                        }
                    }
                });

                using (var grandOutputClient = GrandOutputHelper.GetNewGrandOutputClient())
                {
                    var activityMonitor = new ActivityMonitor(false)
                    {
                        MinimalFilter = LogFilter.Debug
                    };
                    grandOutputClient.EnsureGrandOutputClient(activityMonitor);

                    using (var receiver = new SingleHttpReceiver(SingleHttpReceiver.DefaultUrl))
                    {
                        activityMonitor.Info("Hello world");
                        Thread.Sleep(TestHelper.DefaultSleepTime);
                        receiver.Alerted.Should().BeFalse();
                    }

                    server.ApplyConfiguration(new HandlersManagerConfiguration
                    {
                        GloutonHandlers =
                        {
                            new AlertHandlerConfiguration               {
                                DatabasePath = @"%localappdata%/Glouton/Alerts".GetPathWithSpecialFolders(),
                                Alerts       = new List <IAlertExpressionModel>
                                {
                                    new AlertExpressionModelMock
                                    (
                                        new []                          { new []                      { "Text", "EqualTo", "Hello world" } },
                                        new IAlertSenderConfiguration[] { new HttpSenderConfiguration {
                                                                              Url = SingleHttpReceiver.DefaultUrl
                                                                          } }
                                    )
                                }
                            }
                        }
                    });
                    Thread.Sleep(TestHelper.DefaultSleepTime);

                    using (var receiver = new SingleHttpReceiver(SingleHttpReceiver.DefaultUrl))
                    {
                        activityMonitor.Info("Hello world");
                        Thread.Sleep(TestHelper.DefaultSleepTime * 10);
                        receiver.Alerted.Should().BeTrue();
                    }
                }
            }
        }
Beispiel #32
0
        public WorkQueueBatch WaitAll(int millisecondsTimeout)
        {
            var activityMonitor = new ActivityMonitor();

            Array.ForEach(CopyAndClearFutures(), future => activityMonitor.Monitor(() => future.Wait(millisecondsTimeout)));
            activityMonitor.Resolve();
            return(this);
        }
Beispiel #33
0
        public async Task ISender_buffers_the_logs_while_connection_is_lost_Async(string mode)
        {
            void Open(bool open)
            {
                if (mode == "UseIsActuallyConnected")
                {
                    FakeLogSender.FakeSenderImplIsActuallyConnected = open;
                    FakeLogSender.FakeSenderImplTrySendSuccess      = true;
                }
                else
                {
                    FakeLogSender.FakeSenderImplIsActuallyConnected = true;
                    FakeLogSender.FakeSenderImplTrySendSuccess      = open;
                }
            }

            FakeLogSender.Reset();
            FakeLogSender.FakeSenderCanBeCreated = true;
            Open(true);
            var host = await StartHostAsync();

            Debug.Assert(FakeLogSender.ActivatedSender != null, "The handler is activated.");

            var monitor = new ActivityMonitor()
            {
                AutoTags = FakeLogSender.TestTag
            };

            monitor.Info("n°1");
            await Task.Delay(50);

            Open(false);

            // The LostBufferSize is 3: these 3 will be eventually sent.
            monitor.Info("n°2");
            monitor.Info("n°3");
            monitor.Info("n°4");
            await Task.Delay(50);

            Open(true);
            monitor.Info("n°5");
            await Task.Delay(50);

            Open(false);
            monitor.Info("NOSHOW - will be evicted.");
            monitor.Info("n°6");
            monitor.Info("n°7");
            monitor.Info("n°8");
            await Task.Delay(50);

            Open(true);
            monitor.Info("n°9");
            await Task.Delay(50);

            FakeLogSender.LogSent.Concatenate().Should().Contain("n°1, n°2, n°3, n°4, n°5, n°6, n°7, n°8, n°9").And.NotContain("NOSHOW");

            await host.StopAsync();
        }
Beispiel #34
0
        void Create()
        {
            {
                var m = new ActivityMonitor();
            }
            {
                var m = new ActivityMonitor(applyAutoConfigurations: false);
            }
            {
                IActivityMonitor m = new ActivityMonitor();
                var counter        = new ActivityMonitorErrorCounter();
                m.Output.RegisterClient(counter);

                m.Fatal().Send("An horrible error occurred.");

                Assert.That(counter.Current.FatalCount == 1);
                m.Output.UnregisterClient(counter);
            }
            {
                IActivityMonitor m = new ActivityMonitor();

                int errorCount = 0;
                using (m.OnError(() => ++ errorCount))
                {
                    m.Fatal().Send("An horrible error occurred.");
                }
                Assert.That(errorCount == 1);
            }
            {
                IActivityMonitor m = new ActivityMonitor();
                m.MinimalFilter = LogFilter.Off;
                // ...
                m.MinimalFilter = LogFilter.Debug;
            }
            {
                IActivityMonitor m = new ActivityMonitor();
                m.MinimalFilter = LogFilter.Terse;
                using (m.SetMinimalFilter(LogFilter.Debug))
                {
                    Assert.That(m.ActualFilter == LogFilter.Debug);
                }
                Assert.That(m.ActualFilter == LogFilter.Terse, "Filter has been restored to previous value.");
            }
            {
                IActivityMonitor m = new ActivityMonitor();
                m.MinimalFilter = LogFilter.Off;
                // ...
                using (m.OpenWarn().Send("Ouch..."))
                {
                    Assert.That(m.ActualFilter == LogFilter.Off);
                    m.MinimalFilter = LogFilter.Debug;
                    // ... in debug filter ...
                }
                Assert.That(m.ActualFilter == LogFilter.Off, "Back to Off.");

                var strange = new LogFilter(LogLevelFilter.Fatal, LogLevelFilter.Trace);
            }
        }
Beispiel #35
0
        static void Main(string[] args)
        {
            ActivityMonitor monitor = new ActivityMonitor();
            monitor.ActivedTimeOut = 2000;// 2 秒钟超时
            monitor.TimerInterval = 1000;//1秒钟检查一次
            monitor.OnSleep += delegate { Console.WriteLine("无操作,等待中......"); };
            monitor.OnActive += delegate { Console.WriteLine("已捕捉到输入"); };

            monitor.Start();
            Console.ReadLine();
        }
        public void ClientFilterPropagatesToMonitor()
        {
            var monitor = new ActivityMonitor( false );
            var client = new ActivityMonitorConsoleClient();
            monitor.Output.RegisterClient( client );

            Assert.That( monitor.MinimalFilter, Is.EqualTo( LogFilter.Undefined ) );

            client.Filter = LogFilter.Release;

            Assert.That( client.Filter, Is.EqualTo( LogFilter.Release ) );
            Assert.That( monitor.ActualFilter, Is.EqualTo( LogFilter.Release ) );
        }
        public void TestArtificialCollision()
        {
            ActivityMonitor m = new ActivityMonitor( applyAutoConfigurations: false );
            var detect = new DateCollision();
            m.Output.RegisterClient( detect );

            DateTimeStamp now = DateTimeStamp.UtcNow;
            m.UnfilteredLog( ActivityMonitor.Tags.Empty, LogLevel.Info, "This should clash!", now, null );
            m.UnfilteredLog( ActivityMonitor.Tags.Empty, LogLevel.Info, "This should clash!", now, null );
            m.UnfilteredLog( ActivityMonitor.Tags.Empty, LogLevel.Info, "This should clash!", new DateTimeStamp( now.TimeUtc.AddDays( -1 ) ), null );
            m.UnfilteredOpenGroup( ActivityMonitor.Tags.Empty, LogLevel.Info, null, "This should clash!", now, null );
            m.UnfilteredOpenGroup( ActivityMonitor.Tags.Empty, LogLevel.Info, null, "This should clash!", new DateTimeStamp( now.TimeUtc.AddTicks( -1 ) ), null );
            m.CloseGroup( new DateTimeStamp( now.TimeUtc.AddTicks( -1 ) ) );
            m.CloseGroup( now );

            Assert.That( detect.NbClash, Is.EqualTo( 0 ) );
        }
        public void logging_multiple_lines()
        {
            TestHelper.LogsToConsole = true;
            var m = new ActivityMonitor( false );
            m.MinimalFilter = LogFilter.Debug;
            StringBuilder b = new StringBuilder();
            var client = new ActivityMonitorTextWriterClient( s => b.Append( s ) );
            m.Output.RegisterClient( client );
            using( TestHelper.ConsoleMonitor.SetMinimalFilter( LogFilter.Debug ) )
            using( m.Output.CreateBridgeTo( TestHelper.ConsoleMonitor.Output.BridgeTarget ) )
            {
                using( m.OpenInfo().Send( "IL1" + Environment.NewLine + "IL2" + Environment.NewLine + "IL3" ) )
                {
                    using( m.OpenTrace().Send( "TL1" + Environment.NewLine + "TL2" + Environment.NewLine + "TL3" ) )
                    {
                        m.Warn().Send( "WL1" + Environment.NewLine + "WL2" + Environment.NewLine + "WL3" );
                        m.CloseGroup( new[] 
                        {
                            new ActivityLogGroupConclusion("c1"),
                            new ActivityLogGroupConclusion("c2"),
                            new ActivityLogGroupConclusion("Multi"+Environment.NewLine+"Line"+Environment.NewLine),
                            new ActivityLogGroupConclusion("Another"+Environment.NewLine+"Multi"+Environment.NewLine+"Line"+Environment.NewLine)
                        } );
                    }
                }
            }
            string result = b.ToString();
            Assert.That( result, Is.EqualTo(
@"> Info: IL1
|       IL2
|       IL3
|  > Trace: TL1
|  |        TL2
|  |        TL3
|  |  - Warn: WL1
|  |          WL2
|  |          WL3
|  < c1 - c2
|  < Multi
|    Line
|  < Another
|    Multi
|    Line
".NormalizeEOL() ) );
        }
        public void automatic_configuration_of_monitors_just_uses_ActivityMonitor_AutoConfiguration_delegate()
        {
            StupidStringClient c = new StupidStringClient();

            ActivityMonitor.AutoConfiguration = null;
            ActivityMonitor.AutoConfiguration += m => m.Output.RegisterClient( c );
            int i = 0;
            ActivityMonitor.AutoConfiguration += m => m.Trace().Send( "This monitors has been created at {0:O}, n°{1}", DateTime.UtcNow, ++i );

            ActivityMonitor monitor1 = new ActivityMonitor();
            ActivityMonitor monitor2 = new ActivityMonitor();

            Assert.That( c.ToString(), Does.Contain( "This monitors has been created at" ) );
            Assert.That( c.ToString(), Does.Contain( "n°1" ) );
            Assert.That( c.ToString(), Does.Contain( "n°2" ) );

            ActivityMonitor.AutoConfiguration = null;
        }
        public void DependentToken_API_use()
        {
            var monitor = new ActivityMonitor();
            monitor.Output.CreateBridgeTo( TestHelper.ConsoleMonitor.Output.BridgeTarget );

            using( monitor.OpenTrace().Send( "Create token and dependent monitor." ) )
            {
                // Creates the token.
                var token = monitor.DependentActivity().CreateToken();
                // Creates a dependent monitor.
                using( var monitorDep = token.CreateDependentMonitor( m => m.Output.CreateBridgeTo( TestHelper.ConsoleMonitor.Output.BridgeTarget ) ) )
                {
                    monitor.Trace().Send( "Doing something..." );
                    // ...
                }
            }
            using( monitor.OpenTrace().Send( "Create token with delayed launch of the dependent activity." ) )
            {
                // Creates the token.
                var token = monitor.DependentActivity().CreateToken( delayedLaunch: true );
                // Signals the launch of the dependent activity.
                monitor.DependentActivity().Launch( token );
                // Creates a dependent monitor.
                using( var monitorDep = token.CreateDependentMonitor( m => m.Output.CreateBridgeTo( TestHelper.ConsoleMonitor.Output.BridgeTarget ) ) )
                {
                    monitor.Trace().Send( "Doing something..." );
                    // ...
                }
            }
            using( monitor.OpenTrace().Send( "Starting a dependent activity on an existing monitor." ) )
            {
                // Creates the token.
                var token = monitor.DependentActivity().CreateToken();
            
                IActivityMonitor wMonitor = monitor;
                using( wMonitor.StartDependentActivity( token ) )
                {
                    wMonitor.Trace().Send( "Doing something..." );
                    // ...
                }
            }
        }
 public void TestNaturalCollision()
 {
     ActivityMonitor m = new ActivityMonitor( applyAutoConfigurations: false );
     var detect = new DateCollision();
     m.Output.RegisterClient( detect );
     for( int i = 0; i < 10; ++i )
     {
         m.UnfilteredLog( ActivityMonitor.Tags.Empty, LogLevel.Info, "This should clash!", DateTimeStamp.UtcNow, null );
     }
     for( int i = 0; i < 10; ++i )
     {
         m.Trace().Send( "This should clash!" );
     }
     for( int i = 0; i < 10; ++i )
     {
         using( m.OpenTrace().Send( "This should clash!" ) )
         {
         }
     }
     Assert.That( detect.NbClash, Is.EqualTo( 0 ) );
 }
 private static StupidStringClient.Entry[] LaunchAndRunDependentActivityWithTopic( ActivityMonitor m, string dependentTopic )
 {
     StupidStringClient.Entry[] dependentLogs = null;
     m.DependentActivity().LaunchWithTopic( token => { dependentLogs = RunDependentActivity( token ); }, dependentTopic );
     return dependentLogs;
 }
        public void parsing_start_and_create_messages()
        {
            ActivityMonitor m = new ActivityMonitor( false );
            StupidStringClient cLaunch = m.Output.RegisterClient( new StupidStringClient() );
            StupidStringClient.Entry[] dependentLogs = null;

            string dependentTopic = "A topic 'with' quotes '-\"..." + Environment.NewLine + " and multi-line";
            dependentLogs = LaunchAndRunDependentActivityWithTopic( m, dependentTopic );

            string launchMessage = cLaunch.Entries[0].Text;
            string topicSetMessage = dependentLogs[0].Text;
            string startMessage = dependentLogs[1].Text;

            Assert.That( topicSetMessage, Is.EqualTo( ActivityMonitor.SetTopicPrefix + dependentTopic ) );
            Assert.That( dependentLogs[2].Text, Is.EqualTo( "Hello!" ) );

            Assert.That( launchMessage, Does.StartWith( "Launching dependent activity" ) );
            bool launched;
            bool launchWithTopic;
            string launchDependentTopic;
            Assert.That( ActivityMonitor.DependentToken.TryParseLaunchOrCreateMessage( launchMessage, out launched, out launchWithTopic, out launchDependentTopic ) );
            Assert.That( launched );
            Assert.That( launchWithTopic );
            Assert.That( launchDependentTopic, Is.EqualTo( dependentTopic ) );

            Assert.That( startMessage, Does.StartWith( "Starting dependent activity" ) );
            Guid id;
            DateTimeStamp time;
            Assert.That( ActivityMonitor.DependentToken.TryParseStartMessage( startMessage, out id, out time ) );
            Assert.That( id, Is.EqualTo( ((IUniqueId)m).UniqueId ) );
            Assert.That( time, Is.EqualTo( cLaunch.Entries[0].LogTime ) );
        }
        public void MultipleConclusions()
        {
            IActivityMonitor l = new ActivityMonitor();
            using( l.Output.CreateBridgeTo( TestHelper.ConsoleMonitor.Output.BridgeTarget ) )
            {
                l.Output.RegisterClient( new ActivityMonitorErrorCounter( true ) );
                var log = l.Output.RegisterClient( new StupidStringClient() );

                // No explicit close conclusion: Success!
                using( l.OpenTrace().Send( "G" ).ConcludeWith( () => "From Opener" ) )
                {
                    l.Error().Send( "Pouf" );
                    l.CloseGroup( new ObjectAsConclusion() );
                }
                Assert.That( log.Writer.ToString(), Does.Contain( "Explicit User Conclusion, From Opener, 1 Error" ) );
            }
        }
        public void PathCatcherToStringPath()
        {
            var monitor = new ActivityMonitor();
            ActivityMonitorPathCatcher p = monitor.Output.RegisterClient( new ActivityMonitorPathCatcher() );

            using( monitor.OpenTrace().Send( "!T" ) )
            using( monitor.OpenInfo().Send( "!I" ) )
            using( monitor.OpenWarn().Send( "!W" ) )
            using( monitor.OpenError().Send( "!E" ) )
            using( monitor.OpenFatal().Send( "!F" ) )
            {
                Assert.That( p.DynamicPath.ToStringPath(), Does.Contain( "!T" ).And.Contain( "!I" ).And.Contain( "!W" ).And.Contain( "!E" ).And.Contain( "!F" ) );
            }
            var path = p.DynamicPath;
            path = null;
            Assert.That( path.ToStringPath(), Is.Empty );
        }
 public void registering_a_null_client_is_an_error()
 {
     IActivityMonitor monitor = new ActivityMonitor();
     Assert.Throws<ArgumentNullException>( () => monitor.Output.RegisterClient( null ) );
     Assert.Throws<ArgumentNullException>( () => monitor.Output.UnregisterClient( null ) );
 }
        public void parsing_dependent_token_and_start_and_create_messages_with_time_collision()
        {
            ActivityMonitor m = new ActivityMonitor( false );
            m.Output.CreateBridgeTo( TestHelper.ConsoleMonitor.Output.BridgeTarget );
            StupidStringClient cLaunch = m.Output.RegisterClient( new StupidStringClient() );

            // Generates a token with time collision.
            int loopNeeded = 0;
            ActivityMonitor.DependentToken token;
            while( (token = m.DependentActivity().CreateTokenWithTopic( "Test..." )).CreationDate.Uniquifier == 0 ) ++loopNeeded;
            Assert.That( token.Topic, Is.EqualTo( "Test..." ) );
            m.Trace().Send( "Generating time collision required {0} loops.", loopNeeded );

            string launchMessage = cLaunch.Entries[loopNeeded].Text;
            {
                bool launched;
                bool launchWithTopic;
                string launchDependentTopic;
                Assert.That( ActivityMonitor.DependentToken.TryParseLaunchOrCreateMessage( launchMessage, out launched, out launchWithTopic, out launchDependentTopic ) );
                Assert.That( !launched, "We used CreateToken." );
                Assert.That( launchWithTopic );
                Assert.That( launchDependentTopic, Is.EqualTo( "Test..." ) );
            }

            string tokenToString = token.ToString();
            {
                ActivityMonitor.DependentToken t2 = ActivityMonitor.DependentToken.Parse( tokenToString );
                Assert.That( t2.OriginatorId, Is.EqualTo( ((IUniqueId)m).UniqueId ) );
                Assert.That( t2.CreationDate, Is.EqualTo( cLaunch.Entries[loopNeeded].LogTime ) );
                Assert.That( t2.Topic, Is.EqualTo( "Test..." ) );
            }

            StupidStringClient.Entry[] logs = RunDependentActivity( token );
            {
                Assert.That( logs[0].Text, Is.EqualTo( ActivityMonitor.SetTopicPrefix + "Test..." ) );
                Guid id;
                DateTimeStamp time;
                Assert.That( ActivityMonitor.DependentToken.TryParseStartMessage( logs[1].Text, out id, out time ) );
                Assert.That( id, Is.EqualTo( ((IUniqueId)m).UniqueId ) );
                Assert.That( time, Is.EqualTo( cLaunch.Entries[loopNeeded].LogTime ) );
            }
        }
        public void SimpleCollectorTest()
        {
            IActivityMonitor d = new ActivityMonitor();
            var c = new ActivityMonitorSimpleCollector();
            d.Output.RegisterClient( c );
            d.Warn().Send( "1" );
            d.Error().Send( "2" );
            d.Fatal().Send( "3" );
            d.Trace().Send( "4" );
            d.Info().Send( "5" );
            d.Warn().Send( "6" );
            Assert.That( String.Join( ",", c.Entries.Select( e => e.Text ) ), Is.EqualTo( "2,3" ) );

            c.MinimalFilter = LogLevelFilter.Fatal;
            Assert.That( String.Join( ",", c.Entries.Select( e => e.Text ) ), Is.EqualTo( "3" ) );

            c.MinimalFilter = LogLevelFilter.Off;
            Assert.That( String.Join( ",", c.Entries.Select( e => e.Text ) ), Is.EqualTo( "" ) );

            c.MinimalFilter = LogLevelFilter.Warn;
            using( d.OpenWarn().Send( "1" ) )
            {
                d.Error().Send( "2" );
                using( d.OpenFatal().Send( "3" ) )
                {
                    d.Trace().Send( "4" );
                    d.Info().Send( "5" );
                }
            }
            d.Warn().Send( "6" );
            Assert.That( String.Join( ",", c.Entries.Select( e => e.Text ) ), Is.EqualTo( "1,2,3,6" ) );

            c.MinimalFilter = LogLevelFilter.Fatal;
            Assert.That( String.Join( ",", c.Entries.Select( e => e.Text ) ), Is.EqualTo( "3" ) );
        }
        public void buggy_clients_are_removed_from_Output()
        {
            ActivityMonitor.AutoConfiguration = null;
            ActivityMonitor monitor = new ActivityMonitor();

            int clientCount = 0;
            if( TestHelper.LogsToConsole )
            {
                ++clientCount;
                monitor.Output.RegisterClient( new ActivityMonitorConsoleClient() );
            }
            ++clientCount;
            WaitActivityMonitorClient client = monitor.Output.RegisterClient( new WaitActivityMonitorClient() );

            Assert.That( monitor.Output.Clients.Count, Is.EqualTo( clientCount ) );

            try
            {
                Task.Factory.StartNew( () =>
                {
                    monitor.Info().Send( "Test must work in task" );
                } );

                client.WaitForOnUnfilteredLog();

                Assert.That( () => monitor.Info().Send( "Test must fail" ),
                    Throws.TypeOf( typeof( InvalidOperationException ) ).
                        And.Message.EqualTo( Impl.ActivityMonitorResources.ActivityMonitorConcurrentThreadAccess ) );
                
                Assert.That( monitor.Output.Clients.Count, Is.EqualTo( clientCount ), "Still " + clientCount + ": Concurrent call: not the fault of the Client." );
            }
            finally
            {
                client.Free();
            }

            Thread.Sleep( 50 );
            monitor.Info().Send( "Test must work after task" );

            ++clientCount;
            monitor.Output.RegisterClient( new ActionActivityMonitorClient( () =>
            {
                Assert.That( () => monitor.Info().Send( "Test must fail reentrant client" ),
                    Throws.TypeOf( typeof( InvalidOperationException ) ).
                        And.Message.EqualTo( Impl.ActivityMonitorResources.ActivityMonitorReentrancyError ) );
            } ) );

            monitor.Info().Send( "Test must work after reentrant client" );
            Assert.That( monitor.Output.Clients.Count, Is.EqualTo( clientCount ), "The RegisterClient action above is ok: it checks that it triggered a reentrant call." );

            ++clientCount;
            monitor.Output.RegisterClient( new ActionActivityMonitorClient( () =>
            {
                monitor.Info().Send( "Test must fail reentrant client" );
            } ) );

            monitor.Info().Send( "Test must work after reentrant client" );
            Assert.That( monitor.Output.Clients.Count, Is.EqualTo( clientCount - 1 ), "The BUGGY RegisterClient action above is NOT ok: it triggers a reentrant call exception => We have removed it." );

        }
        public void FilteredTextWriterTests()
        {
            StringBuilder sb = new StringBuilder();

            IActivityMonitor d = new ActivityMonitor();
            d.SetMinimalFilter( LogFilter.Debug );

            var c = new ActivityMonitorTextWriterClient(s => sb.Append(s), LogFilter.Release);
            d.Output.RegisterClient( c );

            d.Trace().Send( "NO SHOW" );
            d.Trace().Send( "NO SHOW" );
            using( d.OpenTrace().Send( "NO SHOW" ) )
            {
                d.Info().Send( "NO SHOW" );
                d.Info().Send( "NO SHOW" );
            }

            d.Error().Send( "Error line at root" );
            using( d.OpenInfo().Send( "NO SHOW" ) )
            {
                d.Warn().Send( "NO SHOW" );
                d.Error().Send( "Send error line inside group" );
                using( d.OpenError().Send( "Open error group" ) )
                {
                    d.Error().Send( "Send error line inside sub group" );
                }
            }

            Assert.That( sb.ToString(), Does.Not.Contain( "NO SHOW" ) );
            Assert.That( sb.ToString(), Does.Contain( "Error line at root" ) );
            Assert.That( sb.ToString(), Does.Contain( "Send error line inside group" ) );
            Assert.That( sb.ToString(), Does.Contain( "Open error group" ) );
            Assert.That( sb.ToString(), Does.Contain( "Send error line inside sub group" ) );
        }
Beispiel #51
0
 /// <summary>
 /// Initialize SensorCore 
 /// </summary>
 /// <param name="rec">Recording instance</param>
 /// <param name="type">Sense type</param>
 /// <returns>Asynchronous task</returns>
 private async Task HandleSensorActivity(Recording rec, SenseType type)
 {           
     if (rec.Recorder == null)
     {
         if (await CallSensorcoreApiAsync(async () =>
         {
             switch (type)
             {
                 case SenseType.Activity:
                     _aMonitor = await ActivityMonitor.GetDefaultAsync();
                     break;
                 case SenseType.Places:
                     _pMonitor = await PlaceMonitor.GetDefaultAsync();
                     break;
                 case SenseType.Route:
                     _rTracker = await TrackPointMonitor.GetDefaultAsync();
                     break;
                 case SenseType.Steps:
                     _sCounter = await StepCounter.GetDefaultAsync();
                     break;
             }
         }))
         {
             Debug.WriteLine("Recorder initialized.");
             switch (type)
             {
                 case SenseType.Activity:
                     rec.Recorder = new SenseRecorder(_aMonitor);
                     break;
                 case SenseType.Places:
                     rec.Recorder = new SenseRecorder(_pMonitor);
                     break;
                 case SenseType.Route:
                     rec.Recorder = new SenseRecorder(_rTracker);
                     break;
                 case SenseType.Steps:
                     rec.Recorder = new SenseRecorder(_sCounter);
                     break;
             }
         }
         else return;
     }
     if (rec.Recorder == null)
         return;
     else
     {
         await ActivateAsync();
         switch (rec.ItemState)
         {
             case Status.Recording:
                 await rec.Recorder.StartAsync();
                 break;
             case Status.Stopped:
                 await rec.Recorder.StopAsync();
                 break;
             case Status.Empty:
                 await rec.Recorder.GetRecording().SaveAsync();
                 break;
         }
     }
 }
 public void OnError_fires_synchronously()
 {
     var m = new ActivityMonitor( false );
     bool hasError = false;
     using( m.OnError( () => hasError = true ) )
     using( m.OpenInfo().Send( "Handling StObj objects." ) )
     {
         m.Fatal().Send( "Oops!" );
         Assert.That( hasError );
         hasError = false;
         m.OpenFatal().Send( "Oops! (Group)" ).Dispose();
         Assert.That( hasError );
         hasError = false;
     }
     hasError = false;
     m.Fatal().Send( "Oops!" );
     Assert.That( hasError, Is.False );
     
     bool hasFatal = false;
     using( m.OnError( () => hasFatal = true, () => hasError = true ) )
     {
         m.Fatal().Send( "Big Oops!" );
         Assert.That( hasFatal && !hasError );
         m.Error().Send( "Oops!" );
         Assert.That( hasFatal && hasError );
         hasFatal = hasError = false;
         m.OpenError().Send( "Oops! (Group)" ).Dispose();
         Assert.That( !hasFatal && hasError );
         m.OpenFatal().Send( "Oops! (Group)" ).Dispose();
         Assert.That( hasFatal && hasError );
         hasFatal = hasError = false;
     }
     m.Fatal().Send( "Oops!" );
     Assert.That( hasFatal || hasError, Is.False );
 }
 private static StupidStringClient.Entry[] RunDependentActivity( ActivityMonitor.DependentToken token )
 {
     string depMonitorTopic = null;
     StupidStringClient.Entry[] dependentLogs = null;
     var task = Task.Factory.StartNew( t =>
     {
         StupidStringClient cStarted = new StupidStringClient();
         using( var depMonitor = token.CreateDependentMonitor( mD => mD.Output.RegisterClient( cStarted ) ) )
         {
             depMonitorTopic = depMonitor.Topic;
             depMonitor.Trace().Send( "Hello!" );
         }
         dependentLogs = cStarted.Entries.ToArray();
     }, token );
     task.Wait();
     Assert.That( depMonitorTopic, Is.EqualTo( token.Topic ) );
     return dependentLogs;
 }
        public void AsyncSetMininimalFilter()
        {
            ActivityMonitor m = new ActivityMonitor( false );
            var tester = m.Output.RegisterClient( new ActivityMonitorClientTester() );

            Assert.That( m.ActualFilter, Is.EqualTo( LogFilter.Undefined ) );
            tester.AsyncSetMinimalFilterBlock( LogFilter.Monitor );
            Assert.That( m.ActualFilter, Is.EqualTo( LogFilter.Monitor ) );
        }
        public void simple_reentrancy_detection()
        {
            IActivityMonitor monitor = new ActivityMonitor();
            using( monitor.Output.CreateBridgeTo( TestHelper.ConsoleMonitor.Output.BridgeTarget ) )
            {
                int clientCount = monitor.Output.Clients.Count;
                Assert.That( monitor.Output.Clients.Count, Is.EqualTo( clientCount ) );

                BuggyActivityMonitorClient client = new BuggyActivityMonitorClient( monitor );
                monitor.Output.RegisterClient( client );
                Assert.That( monitor.Output.Clients.Count, Is.EqualTo( clientCount + 1 ) );
                monitor.Info().Send( "Test" );
                Assert.That( monitor.Output.Clients.Count, Is.EqualTo( clientCount ) );

                Assert.DoesNotThrow( () => monitor.Info().Send( "Test" ) );
            }
        }
		/// <summary>
		/// A simple constructor that initializes the object with its dependencies.
		/// </summary>
		/// <param name="p_amnActivityMonitor">The activity manager to use to manage the monitored activities.</param>
		/// <param name="p_setSettings">The application and user settings.</param>
		public ActivityMonitorVM(ActivityMonitor p_amnActivityMonitor, ISettings p_setSettings)
		{
			ActivityMonitor = p_amnActivityMonitor;
			Settings = p_setSettings;

			CancelTaskCommand = new Command<IBackgroundTask>("Cancel", "Cancels the selected activity.", CancelTask);
			RemoveTaskCommand = new Command<IBackgroundTask>("Remove", "Removes the selected activity.", RemoveTask);
			PauseTaskCommand = new Command<IBackgroundTask>("Pause", "Pauses the selected activity.", PauseTask);
			ResumeTaskCommand = new Command<IBackgroundTask>("Resume", "Resumes the selected activity.", ResumeTask);
		}
        public void PathCatcherTests()
        {
            var monitor = new ActivityMonitor( applyAutoConfigurations: false );
            using( monitor.Output.CreateBridgeTo( TestHelper.ConsoleMonitor.Output.BridgeTarget ) )
            {
                ActivityMonitorPathCatcher p = new ActivityMonitorPathCatcher();
                monitor.Output.RegisterClient( p );

                monitor.Trace().Send( "Trace n°1" );
                Assert.That( p.DynamicPath.Select( e => e.MaskedLevel.ToString() + '|' + e.Text ).Single(), Is.EqualTo( "Trace|Trace n°1" ) );
                Assert.That( p.LastErrorPath, Is.Null );
                Assert.That( p.LastWarnOrErrorPath, Is.Null );

                monitor.Trace().Send( "Trace n°2" );
                Assert.That( p.DynamicPath.Select( e => e.MaskedLevel.ToString() + '|' + e.Text ).Single(), Is.EqualTo( "Trace|Trace n°2" ) );
                Assert.That( p.LastErrorPath, Is.Null );
                Assert.That( p.LastWarnOrErrorPath, Is.Null );

                monitor.Warn().Send( "W1" );
                Assert.That( p.DynamicPath.Select( e => e.MaskedLevel.ToString() + '|' + e.Text ).Single(), Is.EqualTo( "Warn|W1" ) );
                Assert.That( p.LastErrorPath, Is.Null );
                Assert.That( p.LastWarnOrErrorPath.Select( e => e.MaskedLevel.ToString() + '|' + e.Text ).Single(), Is.EqualTo( "Warn|W1" ) );

                monitor.Error().Send( "E2" );
                monitor.Warn().Send( "W1bis" );
                Assert.That( p.DynamicPath.Select( e => e.MaskedLevel.ToString() + '|' + e.Text ).Single(), Is.EqualTo( "Warn|W1bis" ) );
                Assert.That( p.LastErrorPath.Select( e => e.MaskedLevel.ToString() + '|' + e.Text ).Single(), Is.EqualTo( "Error|E2" ) );
                Assert.That( p.LastWarnOrErrorPath.Select( e => e.MaskedLevel.ToString() + '|' + e.Text ).Single(), Is.EqualTo( "Warn|W1bis" ) );

                p.ClearLastWarnPath();
                Assert.That( p.LastErrorPath, Is.Not.Null );
                Assert.That( p.LastWarnOrErrorPath, Is.Null );

                p.ClearLastErrorPath();
                Assert.That( p.LastErrorPath, Is.Null );

                using( monitor.OpenTrace().Send( "G1" ) )
                {
                    using( monitor.OpenInfo().Send( "G2" ) )
                    {
                        Assert.That( String.Join( ">", p.DynamicPath.Select( e => e.Text ) ), Is.EqualTo( "G1>G2" ) );
                        Assert.That( p.LastErrorPath, Is.Null );
                        using( monitor.OpenTrace().Send( "G3" ) )
                        {
                            using( monitor.OpenInfo().Send( "G4" ) )
                            {
                                monitor.Warn().Send( "W1" );

                                Assert.That( String.Join( ">", p.DynamicPath.Select( e => e.Text ) ), Is.EqualTo( "G1>G2>G3>G4>W1" ) );

                                monitor.Info().Send(
                                    new Exception( "An exception logged as an Info.",
                                        new Exception( "With an inner exception. Since these exceptions have not been thrown, there is no stack trace." ) ),
                                    "Test With an exception: a Group is created. Since the text of the log is given, the Exception.Message must be displayed explicitely." );

                                Assert.That( String.Join( ">", p.DynamicPath.Select( e => e.Text ) ), Is.EqualTo( "G1>G2>G3>G4>Test With an exception: a Group is created. Since the text of the log is given, the Exception.Message must be displayed explicitely." ) );

                                try
                                {
                                    try
                                    {
                                        try
                                        {
                                            try
                                            {
                                                throw new Exception( "Deepest exception." );
                                            }
                                            catch( Exception ex )
                                            {
                                                throw new Exception( "Yet another inner with inner Exception.", ex );
                                            }
                                        }
                                        catch( Exception ex )
                                        {
                                            throw new Exception( "Exception with inner Exception.", ex );
                                        }
                                    }
                                    catch( Exception ex )
                                    {
                                        throw new Exception( "Log without log text: the text of the entry is the Exception.Message.", ex );
                                    }
                                }
                                catch( Exception ex )
                                {
                                    monitor.Trace().Send( ex );
                                    Assert.That( p.DynamicPath.ToStringPath().Length > 0 );
                                }

                                Assert.That( p.LastErrorPath, Is.Null );
                                Assert.That( String.Join( ">", p.LastWarnOrErrorPath.Select( e => e.MaskedLevel.ToString() + '|' + e.Text ) ), Is.EqualTo( "Trace|G1>Info|G2>Trace|G3>Info|G4>Warn|W1" ) );
                            }
                            Assert.That( String.Join( ">", p.DynamicPath.Select( e => e.ToString() ) ), Is.EqualTo( "G1>G2>G3>G4" ) );
                            Assert.That( p.LastErrorPath, Is.Null );
                            Assert.That( String.Join( ">", p.LastWarnOrErrorPath.Select( e => e.MaskedLevel.ToString() + '|' + e.Text ) ), Is.EqualTo( "Trace|G1>Info|G2>Trace|G3>Info|G4>Warn|W1" ) );

                            monitor.Error().Send( "E1" );
                            Assert.That( String.Join( ">", p.DynamicPath.Select( e => e.Text ) ), Is.EqualTo( "G1>G2>G3>E1" ) );
                            Assert.That( String.Join( ">", p.LastErrorPath.Select( e => e.MaskedLevel.ToString() + '|' + e.Text ) ), Is.EqualTo( "Trace|G1>Info|G2>Trace|G3>Error|E1" ) );
                            Assert.That( String.Join( ">", p.LastWarnOrErrorPath.Select( e => e.MaskedLevel.ToString() + '|' + e.Text ) ), Is.EqualTo( "Trace|G1>Info|G2>Trace|G3>Error|E1" ) );
                        }
                        Assert.That( String.Join( ">", p.DynamicPath.Select( e => e.Text ) ), Is.EqualTo( "G1>G2>G3" ) );
                        Assert.That( String.Join( ">", p.LastErrorPath.Select( e => e.MaskedLevel.ToString() + '|' + e.Text ) ), Is.EqualTo( "Trace|G1>Info|G2>Trace|G3>Error|E1" ) );
                        Assert.That( String.Join( ">", p.LastWarnOrErrorPath.Select( e => e.MaskedLevel.ToString() + '|' + e.Text ) ), Is.EqualTo( "Trace|G1>Info|G2>Trace|G3>Error|E1" ) );
                    }
                    Assert.That( String.Join( ">", p.DynamicPath.Select( e => e.Text ) ), Is.EqualTo( "G1>G2" ) );
                    using( monitor.OpenTrace().Send( "G2Bis" ) )
                    {
                        Assert.That( String.Join( ">", p.DynamicPath.Select( e => e.Text ) ), Is.EqualTo( "G1>G2Bis" ) );
                        Assert.That( String.Join( ">", p.LastErrorPath.Select( e => e.MaskedLevel.ToString() + '|' + e.Text ) ), Is.EqualTo( "Trace|G1>Info|G2>Trace|G3>Error|E1" ) );
                        Assert.That( String.Join( ">", p.LastWarnOrErrorPath.Select( e => e.MaskedLevel.ToString() + '|' + e.Text ) ), Is.EqualTo( "Trace|G1>Info|G2>Trace|G3>Error|E1" ) );

                        monitor.Warn().Send( "W2" );
                        Assert.That( String.Join( ">", p.DynamicPath.Select( e => e.Text ) ), Is.EqualTo( "G1>G2Bis>W2" ) );
                        Assert.That( String.Join( ">", p.LastWarnOrErrorPath.Select( e => e.MaskedLevel.ToString() + '|' + e.Text ) ), Is.EqualTo( "Trace|G1>Trace|G2Bis>Warn|W2" ) );
                        Assert.That( String.Join( ">", p.LastErrorPath.Select( e => e.MaskedLevel.ToString() + '|' + e.Text ) ), Is.EqualTo( "Trace|G1>Info|G2>Trace|G3>Error|E1" ) );
                    }
                    monitor.Fatal().Send( "F1" );
                    Assert.That( String.Join( ">", p.DynamicPath.Select( e => e.Text ) ), Is.EqualTo( "G1>F1" ) );
                    Assert.That( String.Join( ">", p.LastWarnOrErrorPath.Select( e => e.MaskedLevel.ToString() + '|' + e.Text ) ), Is.EqualTo( "Trace|G1>Fatal|F1" ) );
                    Assert.That( String.Join( ">", p.LastErrorPath.Select( e => e.MaskedLevel.ToString() + '|' + e.Text ) ), Is.EqualTo( "Trace|G1>Fatal|F1" ) );
                }

                // Extraneous closing are ignored.
                monitor.CloseGroup( null );

                monitor.Warn().Send( "W3" );
                Assert.That( String.Join( ">", p.DynamicPath.Select( e => e.Text ) ), Is.EqualTo( "W3" ) );
                Assert.That( String.Join( ">", p.LastWarnOrErrorPath.Select( e => e.MaskedLevel.ToString() + '|' + e.Text ) ), Is.EqualTo( "Warn|W3" ) );
                Assert.That( String.Join( ">", p.LastErrorPath.Select( e => e.MaskedLevel.ToString() + '|' + e.Text ) ), Is.EqualTo( "Trace|G1>Fatal|F1" ) );

                // Extraneous closing are ignored.
                monitor.CloseGroup( null );

                monitor.Warn().Send( "W4" );
                Assert.That( String.Join( ">", p.DynamicPath.Select( e => e.Text ) ), Is.EqualTo( "W4" ) );
                Assert.That( String.Join( ">", p.LastWarnOrErrorPath.Select( e => e.MaskedLevel.ToString() + '|' + e.Text ) ), Is.EqualTo( "Warn|W4" ) );
                Assert.That( String.Join( ">", p.LastErrorPath.Select( e => e.MaskedLevel.ToString() + '|' + e.Text ) ), Is.EqualTo( "Trace|G1>Fatal|F1" ) );

                p.ClearLastWarnPath( true );
                Assert.That( p.LastErrorPath, Is.Null );
                Assert.That( p.LastWarnOrErrorPath, Is.Null );
            }
        }
        public void Overloads()
        {
            Exception ex = new Exception( "EXCEPTION" );
            string fmt0 = "fmt", fmt1 = "fmt{0}", fmt2 = "fmt{0}{1}", fmt3 = "fmt{0}{1}{2}", fmt4 = "fmt{0}{1}{2}{3}", fmt5 = "fmt{0}{1}{2}{3}{4}", fmt6 = "fmt{0}{1}{2}{3}{4}{5}";
            string p1 = "p1", p2 = "p2", p3 = "p3", p4 = "p4", p5 = "p5", p6 = "p6";
            Func<string> onDemandText = () => "onDemand";
            Func<int,string> onDemandTextP1 = ( i ) => "onDemand" + i.ToString();
            Func<int,int,string> onDemandTextP2 = ( i, j ) => "onDemand" + i.ToString() + j.ToString();

            IActivityMonitor d = new ActivityMonitor();
            var collector = new ActivityMonitorSimpleCollector() { MinimalFilter = LogLevelFilter.Trace, Capacity = 1 };
            d.Output.RegisterClients( collector, new CheckAlwaysFilteredClient() );

            // d.UnfilteredLog( ActivityMonitor.Tags.Empty, LogLevel.Trace, "CheckAlwaysFilteredClient works", DateTime.UtcNow, null );

            d.Trace().Send( fmt0 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmt" ) );
            d.Trace().Send( fmt1, p1 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1" ) );
            Assert.Throws<ArgumentException>( () => d.Trace().Send( fmt1, ex ) );
            d.Trace().Send( onDemandText ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "onDemand" ) );
            d.Trace().Send( onDemandTextP1, 1 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "onDemand1" ) );
            d.Trace().Send( onDemandTextP2, 1, 2 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "onDemand12" ) );
            d.Trace().Send( fmt2, p1, p2 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2" ) );
            d.Trace().Send( fmt3, p1, p2, p3 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3" ) );
            d.Trace().Send( fmt4, p1, p2, p3, p4 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4" ) );
            d.Trace().Send( fmt5, p1, p2, p3, p4, p5 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5" ) );
            d.Trace().Send( fmt6, p1, p2, p3, p4, p5, p6 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5p6" ) );

            d.Info().Send( fmt0 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmt" ) );
            d.Info().Send( fmt1, p1 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1" ) );
            Assert.Throws<ArgumentException>( () => d.Info().Send( fmt1, ex ) );
            d.Info().Send( onDemandText ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "onDemand" ) );
            d.Info().Send( onDemandTextP1, 1 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "onDemand1" ) );
            d.Info().Send( onDemandTextP2, 1, 2 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "onDemand12" ) );
            d.Info().Send( fmt2, p1, p2 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2" ) );
            d.Info().Send( fmt3, p1, p2, p3 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3" ) );
            d.Info().Send( fmt4, p1, p2, p3, p4 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4" ) );
            d.Info().Send( fmt5, p1, p2, p3, p4, p5 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5" ) );
            d.Info().Send( fmt6, p1, p2, p3, p4, p5, p6 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5p6" ) );

            d.Warn().Send( fmt0 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmt" ) );
            d.Warn().Send( fmt1, p1 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1" ) );
            Assert.Throws<ArgumentException>( () => d.Warn().Send( fmt1, ex ) );
            d.Warn().Send( onDemandText ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "onDemand" ) );
            d.Warn().Send( onDemandTextP1, 1 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "onDemand1" ) );
            d.Warn().Send( onDemandTextP2, 1, 2 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "onDemand12" ) );
            d.Warn().Send( fmt2, p1, p2 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2" ) );
            d.Warn().Send( fmt3, p1, p2, p3 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3" ) );
            d.Warn().Send( fmt4, p1, p2, p3, p4 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4" ) );
            d.Warn().Send( fmt5, p1, p2, p3, p4, p5 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5" ) );
            d.Warn().Send( fmt6, p1, p2, p3, p4, p5, p6 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5p6" ) );

            d.Error().Send( fmt0 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmt" ) );
            d.Error().Send( fmt1, p1 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1" ) );
            Assert.Throws<ArgumentException>( () => d.Error().Send( fmt1, ex ) );
            d.Error().Send( onDemandText ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "onDemand" ) );
            d.Error().Send( onDemandTextP1, 1 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "onDemand1" ) );
            d.Error().Send( onDemandTextP2, 1, 2 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "onDemand12" ) );
            d.Error().Send( fmt2, p1, p2 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2" ) );
            d.Error().Send( fmt3, p1, p2, p3 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3" ) );
            d.Error().Send( fmt4, p1, p2, p3, p4 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4" ) );
            d.Error().Send( fmt5, p1, p2, p3, p4, p5 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5" ) );
            d.Error().Send( fmt6, p1, p2, p3, p4, p5, p6 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5p6" ) );

            d.Fatal().Send( fmt0 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmt" ) );
            d.Fatal().Send( fmt1, p1 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1" ) );
            Assert.Throws<ArgumentException>( () => d.Fatal().Send( fmt1, ex ) );
            d.Fatal().Send( onDemandText ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "onDemand" ) );
            d.Fatal().Send( onDemandTextP1, 1 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "onDemand1" ) );
            d.Fatal().Send( onDemandTextP2, 1, 2 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "onDemand12" ) );
            d.Fatal().Send( fmt2, p1, p2 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2" ) );
            d.Fatal().Send( fmt3, p1, p2, p3 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3" ) );
            d.Fatal().Send( fmt4, p1, p2, p3, p4 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4" ) );
            d.Fatal().Send( fmt5, p1, p2, p3, p4, p5 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5" ) );
            d.Fatal().Send( fmt6, p1, p2, p3, p4, p5, p6 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5p6" ) );

            d.OpenTrace().Send( fmt0 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmt" ) );
            d.OpenTrace().Send( fmt1, p1 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1" ) );
            d.OpenTrace().Send( fmt2, p1, p2 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2" ) );
            d.OpenTrace().Send( fmt3, p1, p2, p3 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3" ) );
            d.OpenTrace().Send( fmt4, p1, p2, p3, p4 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4" ) );
            d.OpenTrace().Send( fmt5, p1, p2, p3, p4, p5 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5" ) );
            d.OpenTrace().Send( fmt6, p1, p2, p3, p4, p5, p6 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5p6" ) );

            d.Trace().Send( ex ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "EXCEPTION" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Trace().Send( ex, fmt0 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmt" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Trace().Send( ex, fmt1, p1 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Trace().Send( ex, fmt2, p1, p2 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Trace().Send( ex, fmt3, p1, p2, p3 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Trace().Send( ex, fmt4, p1, p2, p3, p4 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Trace().Send( ex, fmt5, p1, p2, p3, p4, p5 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Trace().Send( ex, fmt6, p1, p2, p3, p4, p5, p6 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5p6" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );

            d.Info().Send( ex ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "EXCEPTION" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Info().Send( ex, fmt0 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmt" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Info().Send( ex, fmt1, p1 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Info().Send( ex, fmt2, p1, p2 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Info().Send( ex, fmt3, p1, p2, p3 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Info().Send( ex, fmt4, p1, p2, p3, p4 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Info().Send( ex, fmt5, p1, p2, p3, p4, p5 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Info().Send( ex, fmt6, p1, p2, p3, p4, p5, p6 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5p6" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );

            d.Warn().Send( ex ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "EXCEPTION" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Warn().Send( ex, fmt0 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmt" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Warn().Send( ex, fmt1, p1 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Warn().Send( ex, fmt2, p1, p2 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Warn().Send( ex, fmt3, p1, p2, p3 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Warn().Send( ex, fmt4, p1, p2, p3, p4 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Warn().Send( ex, fmt5, p1, p2, p3, p4, p5 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Warn().Send( ex, fmt6, p1, p2, p3, p4, p5, p6 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5p6" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );

            d.Error().Send( ex ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "EXCEPTION" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Error().Send( ex, fmt0 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmt" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Error().Send( ex, fmt1, p1 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Error().Send( ex, fmt2, p1, p2 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Error().Send( ex, fmt3, p1, p2, p3 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Error().Send( ex, fmt4, p1, p2, p3, p4 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Error().Send( ex, fmt5, p1, p2, p3, p4, p5 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Error().Send( ex, fmt6, p1, p2, p3, p4, p5, p6 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5p6" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );

            d.Fatal().Send( ex ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "EXCEPTION" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Fatal().Send( ex, fmt0 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmt" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Fatal().Send( ex, fmt1, p1 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Fatal().Send( ex, fmt2, p1, p2 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Fatal().Send( ex, fmt3, p1, p2, p3 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Fatal().Send( ex, fmt4, p1, p2, p3, p4 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Fatal().Send( ex, fmt5, p1, p2, p3, p4, p5 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.Fatal().Send( ex, fmt6, p1, p2, p3, p4, p5, p6 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5p6" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );

            d.OpenTrace().Send( ex ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "EXCEPTION" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.OpenTrace().Send( ex, fmt0 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmt" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.OpenTrace().Send( ex, fmt1, p1 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.OpenTrace().Send( ex, fmt2, p1, p2 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.OpenTrace().Send( ex, fmt3, p1, p2, p3 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.OpenTrace().Send( ex, fmt4, p1, p2, p3, p4 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.OpenTrace().Send( ex, fmt5, p1, p2, p3, p4, p5 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );
            d.OpenTrace().Send( ex, fmt6, p1, p2, p3, p4, p5, p6 ); Assert.That( collector.Entries.Last().Text, Is.EqualTo( "fmtp1p2p3p4p5p6" ) ); Assert.That( collector.Entries.Last().Exception, Is.SameAs( ex ) );

        }
        public void ErrorCounterTests()
        {
            var monitor = new ActivityMonitor( applyAutoConfigurations: false );
            using( monitor.Output.CreateBridgeTo( TestHelper.ConsoleMonitor.Output.BridgeTarget ) )
            {

                // Registers the ErrorCounter first: it will be the last one to be called, but
                // this does not prevent the PathCatcher to work: the path elements reference the group
                // so that any conclusion arriving after PathCatcher.OnClosing are available.
                ActivityMonitorErrorCounter c = new ActivityMonitorErrorCounter();
                monitor.Output.RegisterClient( c );

                // Registers the PathCatcher now: it will be called BEFORE the ErrorCounter.
                ActivityMonitorPathCatcher p = new ActivityMonitorPathCatcher();
                monitor.Output.RegisterClient( p );

                Assert.That( c.GenerateConclusion, Is.False, "False by default." );
                c.GenerateConclusion = true;
                Assert.That( c.Root.MaxLogLevel == LogLevel.None );

                monitor.Trace().Send( "T1" );
                Assert.That( !c.Root.HasWarnOrError && !c.Root.HasError );
                Assert.That( c.Root.MaxLogLevel == LogLevel.Trace );
                Assert.That( c.Root.ToString(), Is.Null );

                monitor.Warn().Send( "W1" );
                Assert.That( c.Root.HasWarnOrError && !c.Root.HasError );
                Assert.That( c.Root.MaxLogLevel == LogLevel.Warn );
                Assert.That( c.Root.ToString(), Is.Not.Null.And.Not.Empty );

                monitor.Error().Send( "E2" );
                Assert.That( c.Root.HasWarnOrError && c.Root.HasError );
                Assert.That( c.Root.ErrorCount == 1 );
                Assert.That( c.Root.MaxLogLevel == LogLevel.Error );
                Assert.That( c.Root.ToString(), Is.Not.Null.And.Not.Empty );

                c.Root.ClearError();
                Assert.That( c.Root.HasWarnOrError && !c.Root.HasError );
                Assert.That( c.Root.ErrorCount == 0 );
                Assert.That( c.Root.MaxLogLevel == LogLevel.Warn );
                Assert.That( c.Root.ToString(), Is.Not.Null );

                c.Root.ClearWarn();
                Assert.That( !c.Root.HasWarnOrError && !c.Root.HasError );
                Assert.That( c.Root.MaxLogLevel == LogLevel.Info );
                Assert.That( c.Root.ToString(), Is.Null );

                using( monitor.OpenTrace().Send( "G1" ) )
                {
                    string errorMessage;
                    using( monitor.OpenInfo().Send( "G2" ) )
                    {
                        monitor.Error().Send( "E1" );
                        monitor.Fatal().Send( "F1" );
                        Assert.That( c.Root.HasWarnOrError && c.Root.HasError );
                        Assert.That( c.Root.ErrorCount == 1 && c.Root.FatalCount == 1 );
                        Assert.That( c.Root.WarnCount == 0 );

                        using( monitor.OpenInfo().Send( "G3" ) )
                        {
                            Assert.That( !c.Current.HasWarnOrError && !c.Current.HasError );
                            Assert.That( c.Current.ErrorCount == 0 && c.Current.FatalCount == 0 && c.Current.WarnCount == 0 );

                            monitor.Error().Send( "An error..." );

                            Assert.That( c.Current.HasWarnOrError && c.Current.HasError );
                            Assert.That( c.Current.ErrorCount == 1 && c.Current.FatalCount == 0 && c.Current.WarnCount == 0 );

                            errorMessage = String.Join( "|", p.LastErrorPath.Select( e => e.Text + '-' + e.GroupConclusion.ToStringGroupConclusion() ) );
                            Assert.That( errorMessage, Is.EqualTo( "G1-|G2-|G3-|An error...-" ), "Groups are not closed: no conclusion exist yet." );
                        }
                        errorMessage = String.Join( "|", p.LastErrorPath.Select( e => e.Text + '-' + e.GroupConclusion.ToStringGroupConclusion() ) );
                        Assert.That( errorMessage, Is.EqualTo( "G1-|G2-|G3-1 Error|An error...-" ), "G3 is closed: its conclusion is available." );
                    }
                    errorMessage = String.Join( "|", p.LastErrorPath.Select( e => e.Text + '-' + e.GroupConclusion.ToStringGroupConclusion() ) );
                    Assert.That( errorMessage, Is.EqualTo( "G1-|G2-1 Fatal error, 2 Errors|G3-1 Error|An error...-" ) );
                    monitor.Error().Send( "E3" );
                    monitor.Fatal().Send( "F2" );
                    monitor.Warn().Send( "W2" );
                    Assert.That( c.Root.HasWarnOrError && c.Root.HasError );
                    Assert.That( c.Root.FatalCount == 2 );
                    Assert.That( c.Root.ErrorCount == 3 );
                    Assert.That( c.Root.MaxLogLevel == LogLevel.Fatal );
                }
                Assert.That( String.Join( ">", p.LastErrorPath.Select( e => e.Text + '-' + e.GroupConclusion.ToStringGroupConclusion() ) ), Is.EqualTo( "G1-2 Fatal errors, 3 Errors, 1 Warning>F2-" ) );
                Assert.That( String.Join( ">", p.LastWarnOrErrorPath.Select( e => e.Text + '-' + e.GroupConclusion.ToStringGroupConclusion() ) ), Is.EqualTo( "G1-2 Fatal errors, 3 Errors, 1 Warning>W2-" ) );
            }
        }
        public void concurrent_access_are_detected()
        {
            IActivityMonitor monitor = new ActivityMonitor();
            if( TestHelper.LogsToConsole ) monitor.Output.RegisterClient( new ActivityMonitorConsoleClient() );
            // Artficially slows down logging to ensure that concurrent access occurs.
            monitor.Output.RegisterClient( new ActionActivityMonitorClient( () => Thread.Sleep( 50 )) );

            object lockTasks = new object();
            object lockRunner = new object();
            int enteredThread = 0;

            Action getLock = () =>
            {
                lock( lockTasks )
                {
                    Interlocked.Increment( ref enteredThread );
                    lock( lockRunner )
                        Monitor.Pulse( lockRunner );
                    Monitor.Wait( lockTasks );
                }
            };

            Task[] tasks = new Task[] 
            {            
                new Task( () => { getLock(); monitor.Info().Send( "Test T1" ); } ),
                new Task( () => { getLock(); monitor.Info().Send( new Exception(), "Test T2" ); } ),
                new Task( () => { getLock(); monitor.Info().Send( "Test T3" ); } )
            };

            Parallel.ForEach( tasks, t => t.Start() );

            lock( lockRunner )
                while( enteredThread < tasks.Length )
                    Monitor.Wait( lockRunner );

            lock( lockTasks )
                Monitor.PulseAll( lockTasks );

            Assert.Throws<AggregateException>( () => Task.WaitAll( tasks ) );

            CollectionAssert.AllItemsAreInstancesOfType( tasks.Where( x => x.IsFaulted ).
                                                                SelectMany( x => x.Exception.Flatten().InnerExceptions ),
                                                                typeof( InvalidOperationException ) );

            Assert.DoesNotThrow( () => monitor.Info().Send( "Test" ) );
        }