static IActivityMonitor CreateMonitorAndRegisterGrandOutput(string topic, GrandOutput go) { var m = new ActivityMonitor(topic); go.Register(m); return(m); }
public async Task external_logs_stress_test_Async() { string folder = TestHelper.PrepareLogFolder("ExternalLogsStressTest"); var textConf = new Handlers.TextFileConfiguration() { Path = "ExternalLogsStressTest" }; var config = new GrandOutputConfiguration().AddHandler(textConf); int taskCount = 20; int logCount = 10; using (GrandOutput g = new GrandOutput(config)) { var tasks = Enumerable.Range(0, taskCount).Select(c => Task.Run(() => { for (int i = 0; i < logCount; ++i) { Thread.Sleep(2); g.ExternalLog(LogLevel.Info, message: $"{c} n°{i}."); } })).ToArray(); await Task.WhenAll(tasks); } string textLogged = File.ReadAllText(Directory.EnumerateFiles(folder).Single()); for (int c = 0; c < taskCount; ++c) { for (int i = 0; i < logCount; ++i) { textLogged.Should() .Contain($"{c} n°{i}."); } } }
public async Task request_monitor_handles_exceptions_but_does_not_swallow_them_by_default(bool swallow) { var text = new TextGrandOutputHandlerConfiguration(); var config = new GrandOutputConfiguration(); config.AddHandler(text); GrandOutput.EnsureActiveDefault(config); int rootExceptionCount = 0; try { var b = Tester.WebHostBuilderFactory.Create(null, null, services => { services.AddSingleton <StupidService>(); }, app => { app.Use(async(context, next) => { try { await next.Invoke(); } catch { ++rootExceptionCount; context.Response.StatusCode = StatusCodes.Status500InternalServerError; } }); app.UseRequestMonitor(o => { o.SwallowErrors = swallow; }); app.UseMiddleware <StupidMiddleware>(); }); using (var client = new TestServerClient(new TestServer(b))) { using (HttpResponseMessage bug = await client.Get("?bug")) { bug.StatusCode.Should().Be(HttpStatusCode.InternalServerError); text.GetText().Should().Contain("Bug!"); } using (HttpResponseMessage asyncBug = await client.Get("?asyncBug")) { asyncBug.StatusCode.Should().Be(HttpStatusCode.InternalServerError); text.GetText().Should().Contain("AsyncBug!"); } } } finally { GrandOutput.Default.Dispose(); } if (swallow) { Assert.That(rootExceptionCount, Is.EqualTo(0)); } else { Assert.That(rootExceptionCount, Is.EqualTo(2)); } }
public void dumping_text_file() { string folder = TestHelper.PrepareLogFolder("TextFile"); Random r = new Random(); GrandOutputConfiguration config = new GrandOutputConfiguration() .AddHandler(new Handlers.TextFileConfiguration() { Path = "TextFile" }); using (GrandOutput g = new GrandOutput(config)) { DumpSampleLogs1(r, g); DumpSampleLogs2(r, g); } FileInfo f = new DirectoryInfo(LogFile.RootLogPath + "TextFile").EnumerateFiles().Single(); string text = File.ReadAllText(f.FullName); Console.WriteLine(text); text.Should().Contain("First Activity..."); text.Should().Contain("End of first activity."); text.Should().Contain("another one"); text.Should().Contain("Something must be said"); text.Should().Contain("My very first conclusion."); text.Should().Contain("My second conclusion."); string lineWithSecondConclusion = text.Split("\n").Single(s => s.Contains("My second conclusion.")); lineWithSecondConclusion .Replace("My second conclusion.", "") .Replace(" ", "") .Replace("|", "") .Replace("\n", "") .Replace("\r", "") .Should().BeEmpty(); }
public RunContext( RunContextParam parameters ) { GrandOutput = CreateGrandOutputWithFakeHandler( parameters.HandlerExtraLoad, parameters.UseLocalTestStrategy, parameters.DispatcherMaxCapacity ); LoopCount = parameters.LoopCount; Barrier = new Barrier( parameters.PoolThreadCount + parameters.NewThreadCount + 1 ); _newThreadCount = parameters.NewThreadCount; }
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 async Task GrandOutput_configuration_with_a_text_log_from_Json() { var config = CreateDynamicJsonConfigurationSource("GrandOutput_configuration_from_Json", out string logPath); using (var g = new GrandOutput(new GrandOutputConfiguration())) { Action <IActivityMonitor> autoRegisterer = m => g.EnsureGrandOutputClient(m); ActivityMonitor.AutoConfiguration += autoRegisterer; try { using (var client = CreateServerWithUseMonitoring(config, g)) { (await client.Get("?sayHello")).Dispose(); } } finally { ActivityMonitor.AutoConfiguration -= autoRegisterer; } } var log = Directory.EnumerateFiles(logPath).Single(); File.ReadAllText(log).Should().Contain("/?sayHello"); }
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); }
public RunContext(RunContextParam parameters) { GrandOutput = CreateGrandOutputWithFakeHandler(parameters.HandlerExtraLoad, parameters.UseLocalTestStrategy, parameters.DispatcherMaxCapacity); LoopCount = parameters.LoopCount; Barrier = new Barrier(parameters.PoolThreadCount + parameters.NewThreadCount + 1); _newThreadCount = parameters.NewThreadCount; }
private static void SetupActivityMonitor() { System.Console.OutputEncoding = System.Text.Encoding.Unicode; ActivityMonitor.DefaultFilter = LogFilter.Debug; ActivityMonitor.AutoConfiguration += monitor => monitor.Output.RegisterClient(new ActivityMonitorConsoleClient()); LogFile.RootLogPath = GetLogDirectory(); var grandOutputConfig = new GrandOutputConfiguration(); grandOutputConfig.AddHandler(new TextFileConfiguration { MaxCountPerFile = 10000, Path = "Text", }); grandOutputConfig.AddHandler(new TcpHandlerConfiguration { Host = "127.0.0.1", Port = 33698, IsSecure = false, AppName = typeof(Program).GetTypeInfo().Assembly.GetName().Name, PresentEnvironmentVariables = true, PresentMonitoringAssemblyInformation = true, HandleSystemActivityMonitorErrors = true, }); GrandOutput.EnsureActiveDefault(grandOutputConfig); }
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)."); }
public void applying_empty_configuration_and_disposing() { TestHelper.InitalizePaths(); GrandOutput.EnsureActiveDefault(new GrandOutputConfiguration()); GrandOutput.Default.Should().NotBeNull(); GrandOutput.Default.Dispose(); GrandOutput.Default.Should().BeNull(); }
public async Task GrandOutput_dynamic_configuration_with_a_handler_using_the_configurationtype_property() { const string c1 = @"{ ""Monitoring"": { ""GrandOutput"": { ""Handlers"": { ""Handler1"": { ""ConfigurationType"": ""TextFile"", ""Path"": ""configurationtype_prop_test_1"" }, ""TextFile"": { ""ConfigurationType"": ""NonexistingTypeUsesKeyInstead!"", ""Path"": ""configurationtype_prop_test_2"" } } } } }"; var config = new DynamicJsonConfigurationSource(c1); string logPath1 = Path.Combine(LogFile.RootLogPath, "configurationtype_prop_test_1"); string logPath2 = Path.Combine(LogFile.RootLogPath, "configurationtype_prop_test_2"); if (Directory.Exists(logPath1)) { Directory.Delete(logPath1, true); } if (Directory.Exists(logPath2)) { Directory.Delete(logPath2, true); } using (var g = new GrandOutput(new GrandOutputConfiguration())) { Action <IActivityMonitor> autoRegisterer = m => g.EnsureGrandOutputClient(m); ActivityMonitor.AutoConfiguration += autoRegisterer; try { using (var client = CreateServerWithUseMonitoring(config, g)) { (await client.Get("?sayHello&configurationtype_prop_test")).Dispose(); } } finally { ActivityMonitor.AutoConfiguration -= autoRegisterer; } } var log1 = Directory.EnumerateFiles(logPath1).Single(); File.ReadAllText(log1).Should().Contain("/?sayHello&configurationtype_prop_test"); var log2 = Directory.EnumerateFiles(logPath2).Single(); File.ReadAllText(log2).Should().Contain("/?sayHello&configurationtype_prop_test"); }
public void FilteringBySource() { TestHelper.CleanupFolder(SystemActivityMonitor.RootLogPath + "FilteringBySource"); using (GrandOutput g = new GrandOutput()) { GrandOutputConfiguration config = new GrandOutputConfiguration(); config.Load(XDocument.Parse(@" <GrandOutputConfiguration> <Channel MinimalFilter=""Debug""> <Add Type=""BinaryFile"" Name=""All"" Path=""FilteringBySource"" /> <Channel Name=""HiddenTopic"" MinimalFilter=""Off"" TopicRegex=""(hidden\s+topic|hide\s+this\s+topic)"" MatchOptions=""CultureInvariant, ExplicitCapture, Compiled, Multiline"" /> </Channel> <SourceOverrideFilter> <Add File=""SourceFile-Debug.cs"" Filter=""Debug"" /> <Add File=""SourceFile-Off.cs"" Filter=""Off"" /> <Add File=""SourceFile-Strange.cs"" Filter=""{Trace,Fatal}"" /> </SourceOverrideFilter> </GrandOutputConfiguration>", LoadOptions.SetLineInfo).Root, TestHelper.ConsoleMonitor); Assert.That(g.SetConfiguration(config, TestHelper.ConsoleMonitor)); var m = new ActivityMonitor(false); g.Register(m); m.Fatal(fileName: "SourceFile-Off.cs").Send("NOSHOW"); m.SetTopic("This is a hidden topic..."); m.Trace(0, "SourceFile-Debug.cs").Send("Trace-1"); m.Trace().Send("NOSHOW"); m.SetTopic("Please, hide this topic!"); m.Trace(fileName: "SourceFile-Strange.cs").Send("NOSHOW"); using (m.OpenTrace(fileName: "SourceFile-Strange.cs").Send("Trace-2")) { m.Trace(fileName: "SourceFile-Strange.cs").Send("NOSHOW"); m.Fatal(fileName: "SourceFile-Strange.cs").Send("Fatal-1"); m.Fatal(fileName: "SourceFile-Off.cs").Send("NOSHOW"); } m.SetTopic(null); m.Trace(fileName: "SourceFile-Strange.cs").Send("NOSHOW"); m.Fatal(fileName: "SourceFile-Off.cs").Send("NOSHOW"); m.Trace().Send("Trace-3"); } List <StupidStringClient> logs = TestHelper.ReadAllLogs(new DirectoryInfo(SystemActivityMonitor.RootLogPath + "FilteringBySource"), false); Assert.That(logs.Count, Is.EqualTo(1)); Assert.That(logs[0].ToString(), Does.Not.Contain("NOSHOW")); var texts = logs[0].Entries.Select(e => e.Text).ToArray(); CollectionAssert.AreEqual(new string[] { "Trace-1", "Trace-2", "Fatal-1", ActivityMonitor.SetTopicPrefix, "Trace-3", }, texts, StringComparer.Ordinal); }
/// <summary> /// Initialize from IConfigurationSection instead of configurationPath. /// </summary> static IWebHostBuilder DoUseMonitoring(IWebHostBuilder builder, GrandOutput grandOutput, IConfigurationSection configuration) { var initializer = new GrandOutputConfigurationInitializer(grandOutput); builder.ConfigureLogging((ctx, loggingBuilder) => { initializer.Initialize(ctx.HostingEnvironment, loggingBuilder, configuration); }); return(AddPostInstanciationStartupFilter(builder, initializer)); }
public GrandOutputConfigurationInitializer(GrandOutput target) { if (target == null) { _isDefaultGrandOutput = true; target = GrandOutput.EnsureActiveDefault(new GrandOutputConfiguration()); } _target = target; _loggerProvider = new AspNetLoggerProvider(_target); }
private static void DuplicateTestWith6Entries(int nbEntries1, int nbEntries2, bool gzip = false) { var folder = String.Format("{0}\\ReadDuplicates", TestHelper.TestFolder); TestHelper.CleanupFolder(folder); string config = String.Format(@" <GrandOutputConfiguration> <Channel> <Add Type=""BinaryFile"" Name=""All-1"" MaxCountPerFile=""{1}"" Path=""{0}"" UseGzipCompression=""{3}"" /> <Add Type=""BinaryFile"" Name=""All-2"" MaxCountPerFile=""{2}"" Path=""{0}"" UseGzipCompression=""{3}"" /> </Channel> </GrandOutputConfiguration> ", folder, nbEntries1, nbEntries2, gzip); using (var o = new GrandOutput()) { GrandOutputConfiguration c = new GrandOutputConfiguration(); Assert.That(c.Load(XDocument.Parse(config).Root, TestHelper.ConsoleMonitor), Is.True); Assert.That(o.SetConfiguration(c, TestHelper.ConsoleMonitor), Is.True); var m = new ActivityMonitor(); o.Register(m); var direct = m.Output.RegisterClient(new CKMonWriterClient(folder, Math.Min(nbEntries1, nbEntries2), LogFilter.Debug, gzip)); // 6 traces that go to the GrandOutput but also to the direct CKMonWriterClient. m.Trace().Send("Trace 1"); m.OpenTrace().Send("OpenTrace 1"); m.Trace().Send("Trace 1.1"); m.Trace().Send("Trace 1.2"); m.CloseGroup(); m.Trace().Send("Trace 2"); System.Threading.Thread.Sleep(100); m.Output.UnregisterClient(direct); } var files = TestHelper.WaitForCkmonFilesInDirectory(folder, 3); for (int pageReadLength = 1; pageReadLength < 10; ++pageReadLength) { MultiLogReader reader = new MultiLogReader(); reader.Add(files); var map = reader.GetActivityMap(); Assert.That(map.ValidFiles.All(rawFile => rawFile.IsValidFile), Is.True, "All files are correctly closed with the final 0 byte and no exception occurred while reading them."); var readMonitor = map.Monitors.Single(); List <ParentedLogEntry> allEntries = new List <ParentedLogEntry>(); using (var pageReader = readMonitor.ReadFirstPage(pageReadLength)) { do { allEntries.AddRange(pageReader.Entries); }while(pageReader.ForwardPage() > 0); } CollectionAssert.AreEqual(new[] { "Trace 1", "OpenTrace 1", "Trace 1.1", "Trace 1.2", null, "Trace 2" }, allEntries.Select(e => e.Entry.Text).ToArray(), StringComparer.Ordinal); } }
private static void DuplicateTestWith6Entries(int nbEntries1, int nbEntries2, bool gzip = false) { var folder = TestHelper.PrepareLogFolder("ReadDuplicates"); var config = new GrandOutputConfiguration() .AddHandler(new Handlers.BinaryFileConfiguration() { Path = folder, MaxCountPerFile = nbEntries1, UseGzipCompression = gzip }) .AddHandler(new Handlers.BinaryFileConfiguration() { Path = folder, MaxCountPerFile = nbEntries2, UseGzipCompression = gzip }); using (var o = new GrandOutput(config)) { var m = new ActivityMonitor(); o.EnsureGrandOutputClient(m); var direct = m.Output.RegisterClient(new CKMonWriterClient(folder, Math.Min(nbEntries1, nbEntries2), LogFilter.Debug, gzip)); // 6 traces that go to the GrandOutput but also to the direct CKMonWriterClient. m.Trace("Trace 1"); m.OpenTrace("OpenTrace 1"); m.Trace("Trace 1.1"); m.Trace("Trace 1.2"); m.CloseGroup(); m.Trace("Trace 2"); Thread.Sleep(100); m.Output.UnregisterClient(direct); } var files = TestHelper.WaitForCkmonFilesInDirectory(folder, 3); for (int pageReadLength = 1; pageReadLength < 10; ++pageReadLength) { using MultiLogReader reader = new MultiLogReader(); reader.Add(files); var map = reader.GetActivityMap(); map.ValidFiles.All(rawFile => rawFile.IsValidFile).Should().BeTrue("All files are correctly closed with the final 0 byte and no exception occurred while reading them."); map.Monitors.Should().HaveCount(2); var allEntries1 = map.Monitors[0].ReadAllEntries().ToList(); var allEntries2 = map.Monitors[1].ReadAllEntries().ToList(); var allEntries = allEntries1.Any(e => e.Entry.Text == "Topic: CK.Monitoring.DispatcherSink") ? allEntries2 : allEntries1; allEntries.Select(e => e.Entry.Text) .SequenceEqual(new[] { "Trace 1", "OpenTrace 1", "Trace 1.1", "Trace 1.2", null, "Trace 2" }) .Should().BeTrue(); } }
public void external_logs_filtering() { string folder = TestHelper.PrepareLogFolder("ExternalLogsFiltering"); var textConf = new Handlers.TextFileConfiguration() { Path = "ExternalLogsFiltering" }; var config = new GrandOutputConfiguration().AddHandler(textConf); ActivityMonitor.DefaultFilter.Line.Should().Be(LogLevelFilter.Trace); using (GrandOutput g = new GrandOutput(config)) { g.ExternalLog(LogLevel.Debug, message: "NOSHOW"); g.ExternalLog(LogLevel.Trace, message: "SHOW 0"); g.ExternalLogLevelFilter = LogLevelFilter.Debug; g.ExternalLog(LogLevel.Debug, message: "SHOW 1"); g.ExternalLogLevelFilter = LogLevelFilter.Error; g.ExternalLog(LogLevel.Warn, message: "NOSHOW"); g.ExternalLog(LogLevel.Error, message: "SHOW 2"); g.ExternalLog(LogLevel.Fatal, message: "SHOW 3"); g.ExternalLog(LogLevel.Trace | LogLevel.IsFiltered, message: "SHOW 4"); g.ExternalLogLevelFilter = LogLevelFilter.None; g.ExternalLog(LogLevel.Debug, message: "NOSHOW"); g.ExternalLog(LogLevel.Trace, message: "SHOW 4"); g.IsExternalLogEnabled(LogLevel.Debug).Should().BeFalse(); g.IsExternalLogEnabled(LogLevel.Trace).Should().BeTrue(); ActivityMonitor.Tags.AddFilter(_myTag, new LogClamper(LogFilter.Verbose, true)); // Verbose allows Info, not Trace lines. g.ExternalLog(LogLevel.Info, _myTag, message: "SHOW 5"); g.ExternalLog(LogLevel.Trace, _myTag, message: "NOSHOW"); g.IsExternalLogEnabled(LogLevel.Info, _myTag).Should().BeTrue(); g.IsExternalLogEnabled(LogLevel.Trace, _myTag).Should().BeFalse(); ActivityMonitor.Tags.RemoveFilter(_myTag); g.IsExternalLogEnabled(LogLevel.Trace, _myTag).Should().BeTrue(); g.ExternalLog(LogLevel.Trace, _myTag, message: "SHOW 6"); } string textLogged = File.ReadAllText(Directory.EnumerateFiles(folder).Single()); textLogged.Should() .Contain("SHOW 0") .And.Contain("SHOW 1") .And.Contain("SHOW 2") .And.Contain("SHOW 3") .And.Contain("SHOW 4") .And.Contain("SHOW 5") .And.Contain("SHOW 6") .And.NotContain("NOSHOW"); }
private static void DuplicateTestWith6Entries( int nbEntries1, int nbEntries2, bool gzip = false ) { var folder = String.Format( "{0}\\ReadDuplicates", TestHelper.TestFolder ); TestHelper.CleanupFolder( folder ); string config = String.Format( @" <GrandOutputConfiguration> <Channel> <Add Type=""BinaryFile"" Name=""All-1"" MaxCountPerFile=""{1}"" Path=""{0}"" UseGzipCompression=""{3}"" /> <Add Type=""BinaryFile"" Name=""All-2"" MaxCountPerFile=""{2}"" Path=""{0}"" UseGzipCompression=""{3}"" /> </Channel> </GrandOutputConfiguration> ", folder, nbEntries1, nbEntries2, gzip ); using( var o = new GrandOutput() ) { GrandOutputConfiguration c = new GrandOutputConfiguration(); Assert.That( c.Load( XDocument.Parse( config ).Root, TestHelper.ConsoleMonitor ), Is.True ); Assert.That( o.SetConfiguration( c, TestHelper.ConsoleMonitor ), Is.True ); var m = new ActivityMonitor(); o.Register( m ); var direct = m.Output.RegisterClient( new CKMonWriterClient( folder, Math.Min( nbEntries1, nbEntries2 ), LogFilter.Debug, gzip ) ); // 6 traces that go to the GrandOutput but also to the direct CKMonWriterClient. m.Trace().Send( "Trace 1" ); m.OpenTrace().Send( "OpenTrace 1" ); m.Trace().Send( "Trace 1.1" ); m.Trace().Send( "Trace 1.2" ); m.CloseGroup(); m.Trace().Send( "Trace 2" ); System.Threading.Thread.Sleep( 100 ); m.Output.UnregisterClient( direct ); } var files = TestHelper.WaitForCkmonFilesInDirectory( folder, 3 ); for( int pageReadLength = 1; pageReadLength < 10; ++pageReadLength ) { MultiLogReader reader = new MultiLogReader(); reader.Add( files ); var map = reader.GetActivityMap(); Assert.That( map.ValidFiles.All( rawFile => rawFile.IsValidFile ), Is.True, "All files are correctly closed with the final 0 byte and no exception occurred while reading them." ); var readMonitor = map.Monitors.Single(); List<ParentedLogEntry> allEntries = new List<ParentedLogEntry>(); using( var pageReader = readMonitor.ReadFirstPage( pageReadLength ) ) { do { allEntries.AddRange( pageReader.Entries ); } while( pageReader.ForwardPage() > 0 ); } CollectionAssert.AreEqual( new[] { "Trace 1", "OpenTrace 1", "Trace 1.1", "Trace 1.2", null, "Trace 2" }, allEntries.Select( e => e.Entry.Text ).ToArray(), StringComparer.Ordinal ); } }
public void GrandOutputHasSameCompressedAndUncompressedLogs() { string rootPath = SystemActivityMonitor.RootLogPath + @"\GrandOutputGzip"; TestHelper.CleanupFolder(rootPath); GrandOutputConfiguration c = new GrandOutputConfiguration(); Assert.That(c.Load(XDocument.Parse(@" <GrandOutputConfiguration GlobalDefaultFilter=""Release"" > <Channel> <Add Type=""BinaryFile"" Name=""GzipGlobalCatch"" Path=""" + rootPath + @"\OutputGzip"" MaxCountPerFile=""200000"" UseGzipCompression=""True"" /> <Add Type=""BinaryFile"" Name=""RawGlobalCatch"" Path=""" + rootPath + @"\OutputRaw"" MaxCountPerFile=""200000"" UseGzipCompression=""False"" /> </Channel> </GrandOutputConfiguration>" ).Root, TestHelper.ConsoleMonitor)); Assert.That(c.ChannelsConfiguration.Configurations.Count, Is.EqualTo(2)); using (GrandOutput g = new GrandOutput()) { Assert.That(g.SetConfiguration(c, TestHelper.ConsoleMonitor), Is.True); var taskA = Task.Factory.StartNew <int>(() => { DumpMonitorOutput(CreateMonitorAndRegisterGrandOutput("Task A", g)); return(1); }); var taskB = Task.Factory.StartNew <int>(() => { DumpMonitorOutput(CreateMonitorAndRegisterGrandOutput("Task B", g)); return(1); }); var taskC = Task.Factory.StartNew <int>(() => { DumpMonitorOutput(CreateMonitorAndRegisterGrandOutput("Task C", g)); return(1); }); Task.WaitAll(taskA, taskB, taskC); } string[] gzipCkmons = TestHelper.WaitForCkmonFilesInDirectory(rootPath + @"\OutputGzip", 1); string[] rawCkmons = TestHelper.WaitForCkmonFilesInDirectory(rootPath + @"\OutputRaw", 1); Assert.That(gzipCkmons, Has.Length.EqualTo(1)); Assert.That(rawCkmons, Has.Length.EqualTo(1)); FileInfo gzipCkmonFile = new FileInfo(gzipCkmons.Single()); FileInfo rawCkmonFile = new FileInfo(rawCkmons.Single()); Assert.That(gzipCkmonFile.Exists, Is.True); Assert.That(rawCkmonFile.Exists, Is.True); // Test file size Assert.That(gzipCkmonFile.Length, Is.LessThan(rawCkmonFile.Length)); // Test de-duplication between Gzip and non-Gzip MultiLogReader mlr = new MultiLogReader(); var fileList = mlr.Add(new string[] { gzipCkmonFile.FullName, rawCkmonFile.FullName }); Assert.That(fileList, Has.Count.EqualTo(2)); var map = mlr.GetActivityMap(); Assert.That(map.Monitors.Count, Is.EqualTo(3)); }
public void FilteringBySource() { TestHelper.CleanupFolder( SystemActivityMonitor.RootLogPath + "FilteringBySource" ); using( GrandOutput g = new GrandOutput() ) { GrandOutputConfiguration config = new GrandOutputConfiguration(); config.Load( XDocument.Parse( @" <GrandOutputConfiguration> <Channel MinimalFilter=""Debug""> <Add Type=""BinaryFile"" Name=""All"" Path=""FilteringBySource"" /> <Channel Name=""HiddenTopic"" MinimalFilter=""Off"" TopicRegex=""(hidden\s+topic|hide\s+this\s+topic)"" MatchOptions=""CultureInvariant, ExplicitCapture, Compiled, Multiline"" /> </Channel> <SourceOverrideFilter> <Add File=""SourceFile-Debug.cs"" Filter=""Debug"" /> <Add File=""SourceFile-Off.cs"" Filter=""Off"" /> <Add File=""SourceFile-Strange.cs"" Filter=""{Trace,Fatal}"" /> </SourceOverrideFilter> </GrandOutputConfiguration>", LoadOptions.SetLineInfo ).Root, TestHelper.ConsoleMonitor ); Assert.That( g.SetConfiguration( config, TestHelper.ConsoleMonitor ) ); var m = new ActivityMonitor( false ); g.Register( m ); m.Fatal( fileName: "SourceFile-Off.cs" ).Send( "NOSHOW" ); m.SetTopic( "This is a hidden topic..." ); m.Trace( 0, "SourceFile-Debug.cs" ).Send( "Trace-1" ); m.Trace().Send( "NOSHOW" ); m.SetTopic( "Please, hide this topic!" ); m.Trace( fileName: "SourceFile-Strange.cs" ).Send( "NOSHOW" ); using( m.OpenTrace( fileName: "SourceFile-Strange.cs" ).Send( "Trace-2" ) ) { m.Trace( fileName: "SourceFile-Strange.cs" ).Send( "NOSHOW" ); m.Fatal( fileName: "SourceFile-Strange.cs" ).Send( "Fatal-1" ); m.Fatal( fileName: "SourceFile-Off.cs" ).Send( "NOSHOW" ); } m.SetTopic( null ); m.Trace( fileName: "SourceFile-Strange.cs" ).Send( "NOSHOW" ); m.Fatal( fileName: "SourceFile-Off.cs" ).Send( "NOSHOW" ); m.Trace().Send( "Trace-3" ); } List<StupidStringClient> logs = TestHelper.ReadAllLogs( new DirectoryInfo( SystemActivityMonitor.RootLogPath + "FilteringBySource" ), false ); Assert.That( logs.Count, Is.EqualTo( 1 ) ); Assert.That( logs[0].ToString(), Does.Not.Contain( "NOSHOW" ) ); var texts = logs[0].Entries.Select( e => e.Text ).ToArray(); CollectionAssert.AreEqual( new string[] { "Trace-1", "Trace-2", "Fatal-1", ActivityMonitor.SetTopicPrefix, "Trace-3", }, texts, StringComparer.Ordinal ); }
public void GrandOutputHasSameCompressedAndUncompressedLogs() { string rootPath = SystemActivityMonitor.RootLogPath + @"\GrandOutputGzip"; TestHelper.CleanupFolder( rootPath ); GrandOutputConfiguration c = new GrandOutputConfiguration(); Assert.That( c.Load( XDocument.Parse( @" <GrandOutputConfiguration GlobalDefaultFilter=""Release"" > <Channel> <Add Type=""BinaryFile"" Name=""GzipGlobalCatch"" Path=""" + rootPath + @"\OutputGzip"" MaxCountPerFile=""200000"" UseGzipCompression=""True"" /> <Add Type=""BinaryFile"" Name=""RawGlobalCatch"" Path=""" + rootPath + @"\OutputRaw"" MaxCountPerFile=""200000"" UseGzipCompression=""False"" /> </Channel> </GrandOutputConfiguration>" ).Root, TestHelper.ConsoleMonitor ) ); Assert.That( c.ChannelsConfiguration.Configurations.Count, Is.EqualTo( 2 ) ); using( GrandOutput g = new GrandOutput() ) { Assert.That( g.SetConfiguration( c, TestHelper.ConsoleMonitor ), Is.True ); var taskA = Task.Factory.StartNew<int>( () => { DumpMonitorOutput( CreateMonitorAndRegisterGrandOutput( "Task A", g ) ); return 1; } ); var taskB = Task.Factory.StartNew<int>( () => { DumpMonitorOutput( CreateMonitorAndRegisterGrandOutput( "Task B", g ) ); return 1; } ); var taskC = Task.Factory.StartNew<int>( () => { DumpMonitorOutput( CreateMonitorAndRegisterGrandOutput( "Task C", g ) ); return 1; } ); Task.WaitAll( taskA, taskB, taskC ); } string[] gzipCkmons = TestHelper.WaitForCkmonFilesInDirectory( rootPath + @"\OutputGzip", 1 ); string[] rawCkmons = TestHelper.WaitForCkmonFilesInDirectory( rootPath + @"\OutputRaw", 1 ); Assert.That( gzipCkmons, Has.Length.EqualTo( 1 ) ); Assert.That( rawCkmons, Has.Length.EqualTo( 1 ) ); FileInfo gzipCkmonFile = new FileInfo( gzipCkmons.Single() ); FileInfo rawCkmonFile = new FileInfo( rawCkmons.Single() ); Assert.That( gzipCkmonFile.Exists, Is.True ); Assert.That( rawCkmonFile.Exists, Is.True ); // Test file size Assert.That( gzipCkmonFile.Length, Is.LessThan( rawCkmonFile.Length ) ); // Test de-duplication between Gzip and non-Gzip MultiLogReader mlr = new MultiLogReader(); var fileList = mlr.Add( new string[] { gzipCkmonFile.FullName, rawCkmonFile.FullName } ); Assert.That( fileList, Has.Count.EqualTo( 2 ) ); var map = mlr.GetActivityMap(); Assert.That( map.Monitors.Count, Is.EqualTo( 3 ) ); }
/// <summary> /// Uses <see cref="CK.Monitoring"/> during the web host building and initializes an instance of the <see cref="GrandOutput"/> /// that must not be null nor be the <see cref="GrandOutput.Default"/> and bounds the configuration from the given configuration section. /// </summary> /// <param name="builder">Web host builder</param> /// <param name="grandOutput">The target <see cref="GrandOutput"/>.</param> /// <param name="configurationPath">The path of the monitoring configuration in the global configuration.</param> /// <returns>The builder.</returns> public static IWebHostBuilder UseMonitoring(this IWebHostBuilder builder, GrandOutput grandOutput, string configurationPath = "Monitoring") { if (grandOutput == null) { throw new ArgumentNullException(nameof(grandOutput)); } if (grandOutput == GrandOutput.Default) { throw new ArgumentException("The GrandOutput must not be the default one.", nameof(grandOutput)); } return(DoUseMonitoring(builder, grandOutput, configurationPath)); }
public async Task when_no_configuration_exists_the_default_is_a_Text_TextFile_handler_like_the_default_one_of_CK_Monitoring_Async(string newEmptyConfig) { var config = CreateDynamicJsonConfigurationSource("conf_before_default", out string logBefore); string logDefault = Path.Combine(LogFile.RootLogPath, "Text"); if (Directory.Exists(logDefault)) { Directory.Delete(logDefault, true); } using (var g = new GrandOutput(new GrandOutputConfiguration())) { Action <IActivityMonitor> autoRegisterer = m => g.EnsureGrandOutputClient(m); ActivityMonitor.AutoConfiguration += autoRegisterer; try { using (var client = CreateServerWithUseMonitoring(config, (g, "CK-Monitoring"))) { (await client.GetAsync("?sayHello&in_initial_config")).Dispose(); if (newEmptyConfig != null) { config.SetJson(newEmptyConfig); } else { config.Delete(); } await Task.Delay(150); (await client.GetAsync("?sayHello&in_default_config")).Dispose(); await Task.Delay(150); } } finally { ActivityMonitor.AutoConfiguration -= autoRegisterer; } } var log1 = Directory.EnumerateFiles(logBefore).Single(); File.ReadAllText(log1).Should().Contain("in_initial_config") .And.NotContain("in_default_config") .And.Contain("StupidMiddleware is here!"); var log2 = Directory.EnumerateFiles(logDefault).Single(); File.ReadAllText(log2).Should().NotContain("in_initial_config") .And.Contain("in_default_config") .And.Contain("StupidMiddleware is here!"); }
public void text_file_auto_delete_by_date() { string folder = TestHelper.PrepareLogFolder("AutoDelete_Date"); var textConf = new Handlers.TextFileConfiguration() { Path = "AutoDelete_Date" }; textConf.HousekeepingRate.Should().Be(1800, "Default HousekeepingRate configuration"); textConf.MinimumDaysToKeep.Should().Be(60, "Default HousekeepingRate configuration"); textConf.MinimumTimeSpanToKeep.Should().Be(TimeSpan.FromDays(60), "Default HousekeepingRate configuration"); textConf.MaximumTotalKbToKeep.Should().Be(100_000, "Default HousekeepingRate configuration"); // Change configuration for tests textConf.HousekeepingRate = 1; // Run every 500ms normally (here TimerDuration is set to 100ms). textConf.MaximumTotalKbToKeep = 0; // Always delete file beyond max size textConf.MinimumTimeSpanToKeep = TimeSpan.FromSeconds(3); // Delete files older than 3 seconds var config = new GrandOutputConfiguration().AddHandler(textConf); // Changes the default 500 ms to trigger OnTimerAsync more often. config.TimerDuration = TimeSpan.FromMilliseconds(100); // TEST DELETION BY DATE using (GrandOutput g = new GrandOutput(config)) { var m = new ActivityMonitor(false); g.EnsureGrandOutputClient(m); Thread.Sleep(5); m.Info("Hello world"); Thread.Sleep(30); string tempFile = Directory.EnumerateFiles(folder).Single(); File.Exists(tempFile).Should().BeTrue("Log file was created and exists"); // Wait for next flush (~100ms), and deletion threshold (3000ms) Thread.Sleep(3200); File.Exists(tempFile).Should().BeTrue("Log file wasn't deleted yet - it's still active"); } string finalLogFile = Directory.EnumerateFiles(folder).Single(); // Open another GrandOutput to trigger housekeeping using (GrandOutput g = new GrandOutput(config)) { // Wait for next flush (~100 ms) Thread.Sleep(200); } File.Exists(finalLogFile).Should().BeFalse("Inactive log file was deleted"); }
public void text_file_auto_delete_by_size() { string folder = TestHelper.PrepareLogFolder("AutoDelete_Size"); var textConf = new Handlers.TextFileConfiguration() { Path = "AutoDelete_Size" }; // Change configuration for tests textConf.HousekeepingRate = 1; // Run every 500ms normally (here TimerDuration is set to 100ms). textConf.MaximumTotalKbToKeep = 1; // Always delete file beyond max size textConf.MinimumTimeSpanToKeep = TimeSpan.Zero; // Make minimum timespan var config = new GrandOutputConfiguration().AddHandler(textConf); int lineLengthToLogToGet1000bytes = 500; // Changes the default 500 ms to trigger OnTimerAsync more often. config.TimerDuration = TimeSpan.FromMilliseconds(100); // Create 3*1 KB log files for (int i = 0; i < 3; i++) { using (GrandOutput g = new GrandOutput(config)) { var m = new ActivityMonitor(false); g.EnsureGrandOutputClient(m); m.Info(new string( 'X', lineLengthToLogToGet1000bytes )); } } long GetTotalLogSize() { return(Directory.EnumerateFiles(folder).Sum(x => new FileInfo(x).Length)); } var totalLogSize = GetTotalLogSize(); totalLogSize.Should().BeGreaterThan(2500); // Open another GrandOutput to trigger housekeeping. // Note: this DOES create a file! using (GrandOutput g = new GrandOutput(config)) { // Wait for next flush (~100 ms) Thread.Sleep(200); } var files = Directory.GetFiles(folder).Select(f => Path.GetFileName(f)); files.Should().HaveCount(2, $"Only 2 files should be kept - the last log file, and 1x~1KB file: {files.Concatenate()}"); }
public void sending_log_from_client() { string logPath = TestHelper.PrepareLogFolder("sending_log_from_client"); var c = new GrandOutputConfiguration() .AddHandler(new Handlers.TextFileConfiguration() { Path = logPath }) .AddHandler(new Handlers.BinaryFileConfiguration() { Path = logPath }); using (var g = new GrandOutput(c)) { var m = new ActivityMonitor(false); g.EnsureGrandOutputClient(m); var txt = new StupidStringClient(); m.Output.RegisterClient(txt); using (var r = SimpleLogPipeReceiver.Start(m, interProcess: false)) { RunClient(r.PipeName); r.WaitEnd(false).Should().Be(LogReceiverEndStatus.Normal); } var stupidLogs = txt.ToString(); stupidLogs.Should().Contain("From client.") .And.Contain("An Exception for the fun.") // StupidStringClient does not dump inner exception, only the top message. // .And.Contain( "With an inner exception!" ) .And.Contain("Info n°0") .And.Contain("Info n°19"); } // All temporary files have been closed. var fileNames = Directory.EnumerateFiles(logPath).ToList(); fileNames.Should().NotContain(s => s.EndsWith(".tmp")); // Brutallity here: opening the binary file as a text. // It is enough to check the serialized strings. var texts = fileNames.Select(n => File.ReadAllText(n)); foreach (var logs in texts) { logs.Should().Contain("From client.") .And.Contain("An Exception for the fun.") .And.Contain("With an inner exception!") .And.Contain("Info n°0") .And.Contain("Info n°19"); } }
static void DumpSampleLogs2(Random r, GrandOutput g) { var m = new ActivityMonitor(false); g.EnsureGrandOutputClient(m); m.Fatal("An error occured", _exceptionWithInner); m.Fatal("Same error occured (wrapped in CKException)", new CKException(CKExceptionData.CreateFrom(_exceptionWithInner))); m.SetTopic("This is a topic..."); m.Trace("a trace"); m.Trace("another one"); m.SetTopic("Please, show this topic!"); m.Trace("Anotther trace."); using (m.OpenTrace("A group trace.")) { m.Trace("A trace in group."); m.Info("An info..."); using (m.OpenInfo(@"A group information... with a multi -line message. This MUST be correctly indented!")) { m.Info("Info in info group."); m.Info("Another info in info group."); m.Error("An error.", _exceptionWithInnerLoader); m.Error("Same error occured (wrapped in CKException)", new CKException(CKExceptionData.CreateFrom(_exceptionWithInnerLoader))); m.Warn("A warning."); m.Trace("Something must be said."); m.CloseGroup("Everything is in place."); } } m.SetTopic(null); using (m.OpenTrace("A group with multiple conclusions.")) { using (m.OpenTrace("A group with no conclusion.")) { m.Trace("Something must be said."); } m.CloseGroup(new[] { new ActivityLogGroupConclusion("My very first conclusion."), new ActivityLogGroupConclusion("My second conclusion."), new ActivityLogGroupConclusion(@"My very last conclusion is a multi line one. and this is fine!") }); } m.Trace("This is the final trace."); }
private static void SetupActivityMonitor() { System.Console.OutputEncoding = System.Text.Encoding.Unicode; ActivityMonitor.DefaultFilter = LogFilter.Debug; ActivityMonitor.AutoConfiguration += monitor => monitor.Output.RegisterClient(new ActivityMonitorConsoleClient()); LogFile.RootLogPath = GetLogDirectory(); var grandOutputConfig = new GrandOutputConfiguration(); grandOutputConfig.AddHandler(new TextFileConfiguration { MaxCountPerFile = 10000, Path = "Text", }); GrandOutput.EnsureActiveDefault(grandOutputConfig); }
static IWebHostBuilder DoUseMonitoring(IWebHostBuilder builder, GrandOutput grandOutput, string configurationPath) { // Three steps initialization: // First creates the initializer instance. var initializer = new GrandOutputConfigurationInitializer(grandOutput); builder.ConfigureLogging((ctx, loggingBuilder) => { var section = ctx.Configuration.GetSection(configurationPath); // Second, give it the environment and its section. initializer.Initialize(ctx.HostingEnvironment, loggingBuilder, section); }); // Now, registers the PostInstanciationFilter as a transient object. // This startup filter will inject the Application service IApplicationLifetime. return(AddPostInstanciationStartupFilter(builder, initializer)); }
/// <summary> /// Configures a <see cref="GrandOutput"/> instance that must not be null nor be the <see cref="GrandOutput.Default"/> and /// bounds the configuration from the given configuration section. /// This automatically registers a <see cref="IActivityMonitor"/> as a scoped service in the services. /// </summary> /// <param name="builder">This Web host builder.</param> /// <param name="grandOutput">The target <see cref="GrandOutput"/>.</param> /// <param name="section">The configuration section.</param> /// <returns>The builder.</returns> public static IHostBuilder UseMonitoring(this IHostBuilder builder, GrandOutput grandOutput, IConfigurationSection section) { if (grandOutput == null) { throw new ArgumentNullException(nameof(grandOutput)); } if (grandOutput == GrandOutput.Default) { throw new ArgumentException("The GrandOutput must not be the default one.", nameof(grandOutput)); } if (section == null) { throw new ArgumentNullException(nameof(section)); } return(DoUseMonitoring(builder, grandOutput, c => section)); }
private void SetupActivityMonitor() { Console.OutputEncoding = Encoding.UTF8; SystemActivityMonitor.RootLogPath = GetTestLogDirectory(); ActivityMonitor.DefaultFilter = LogFilter.Debug; ActivityMonitor.AutoConfiguration += (monitor) => { monitor.Output.RegisterClient(new ActivityMonitorConsoleClient()); }; GrandOutputConfiguration grandOutputConfig = new GrandOutputConfiguration(); grandOutputConfig.AddHandler(new TextFileConfiguration() { MaxCountPerFile = 10000, Path = "Text", }); GrandOutput.EnsureActiveDefault(grandOutputConfig); }
public async Task external_logs_quick_test_Async() { string folder = TestHelper.PrepareLogFolder("ExternalLogsQuickTest"); var textConf = new Handlers.TextFileConfiguration() { Path = "ExternalLogsQuickTest" }; var config = new GrandOutputConfiguration().AddHandler(textConf); using (GrandOutput g = new GrandOutput(config)) { await Task.Run(() => { ActivityMonitor.StaticLogger.Info($"Async started from ActivityMonitor.StaticLogger."); g.ExternalLog(LogLevel.Info, message: "Async started."); }); var m = new ActivityMonitor(false); g.EnsureGrandOutputClient(m); m.Info("Normal monitor starts."); Task t = Task.Run(() => { for (int i = 0; i < 10; ++i) { ActivityMonitor.StaticLogger.Info($"Async n°{i} from ActivityMonitor.StaticLogger."); g.ExternalLog(LogLevel.Info, $"Async n°{i}."); } }); m.MonitorEnd("This is the end."); await t; } string textLogged = File.ReadAllText(Directory.EnumerateFiles(folder).Single()); textLogged.Should() .Contain("Normal monitor starts.") .And.Contain("Async started from ActivityMonitor.StaticLogger.") .And.Contain("Async started.") .And.Contain("Async n°0.") .And.Contain("Async n°9.") .And.Contain("Async n°0 from ActivityMonitor.StaticLogger.") .And.Contain("Async n°9 from ActivityMonitor.StaticLogger.") .And.Contain("This is the end."); }
public void dumping_text_file_with_multiple_monitors() { TestHelper.CleanupFolder( SystemActivityMonitor.RootLogPath + "TextFileMulti" ); Random r = new Random(); using( GrandOutput g = new GrandOutput() ) { GrandOutputConfiguration config = new GrandOutputConfiguration(); config.Load( XDocument.Parse( @" <GrandOutputConfiguration> <Channel MinimalFilter=""Debug""> <Add Type=""TextFile"" Name=""All"" Path=""TextFileMulti"" /> </Channel> </GrandOutputConfiguration>", LoadOptions.SetLineInfo ).Root, TestHelper.ConsoleMonitor ); Assert.That( g.SetConfiguration( config, TestHelper.ConsoleMonitor ) ); Parallel.Invoke( () => DumpSampleLogs1( r, g ), () => DumpSampleLogs1( r, g ), () => DumpSampleLogs1( r, g ), () => DumpSampleLogs1( r, g ), () => DumpSampleLogs1( r, g ), () => DumpSampleLogs1( r, g ), () => DumpSampleLogs1( r, g ), () => DumpSampleLogs1( r, g ), () => DumpSampleLogs2( r, g ), () => DumpSampleLogs1( r, g ), () => DumpSampleLogs1( r, g ), () => DumpSampleLogs1( r, g ), () => DumpSampleLogs1( r, g ), () => DumpSampleLogs1( r, g ), () => DumpSampleLogs2( r, g ), () => DumpSampleLogs1( r, g ), () => DumpSampleLogs1( r, g ), () => DumpSampleLogs1( r, g ), () => DumpSampleLogs2( r, g ) ); } FileInfo f = new DirectoryInfo( SystemActivityMonitor.RootLogPath + "TextFileMulti" ).EnumerateFiles().Single(); string text = File.ReadAllText( f.FullName ); Console.WriteLine( text ); }
public void ApplyEmptyAndDefaultConfig() { TestHelper.CleanupFolder( SystemActivityMonitor.RootLogPath + "ApplyEmptyAndDefaultConfig" ); using( GrandOutput g = new GrandOutput() ) { var m = new ActivityMonitor( false ); g.Register( m ); m.Trace().Send( "NoShow-1" ); Assert.That( g.SetConfiguration( new GrandOutputConfiguration(), TestHelper.ConsoleMonitor ) ); m.Trace().Send( "NoShow-2" ); Assert.That( g.SetConfiguration( CreateDefaultConfig( "ApplyEmptyAndDefaultConfig" ), TestHelper.ConsoleMonitor ) ); m.Trace().Send( "Show-1" ); Assert.That( g.SetConfiguration( new GrandOutputConfiguration(), TestHelper.ConsoleMonitor ) ); m.Trace().Send( "NoShow-3" ); } var replayed = new ActivityMonitor( false ); var c = replayed.Output.RegisterClient( new StupidStringClient() ); TestHelper.ReplayLogs( new DirectoryInfo( SystemActivityMonitor.RootLogPath + "ApplyEmptyAndDefaultConfig" ), true, mon => replayed, TestHelper.ConsoleMonitor ); CollectionAssert.AreEqual( new[] { "<Missing log data>", "Show-1" }, c.Entries.Select( e => e.Text ), StringComparer.OrdinalIgnoreCase ); }
public void dumping_text_file() { TestHelper.CleanupFolder( SystemActivityMonitor.RootLogPath + "TextFile" ); Random r = new Random(); using( GrandOutput g = new GrandOutput() ) { GrandOutputConfiguration config = new GrandOutputConfiguration(); config.Load( XDocument.Parse( @" <GrandOutputConfiguration> <Channel MinimalFilter=""Debug""> <Add Type=""TextFile"" Name=""All"" Path=""TextFile"" /> </Channel> </GrandOutputConfiguration>", LoadOptions.SetLineInfo ).Root, TestHelper.ConsoleMonitor ); Assert.That( g.SetConfiguration( config, TestHelper.ConsoleMonitor ) ); DumpSampleLogs1( r, g ); DumpSampleLogs2( r, g ); } CheckSampleTextFile(); }
public void FilteringByTopic() { TestHelper.CleanupFolder( SystemActivityMonitor.RootLogPath + "FilteringByTopic" ); using( GrandOutput g = new GrandOutput() ) { GrandOutputConfiguration config = new GrandOutputConfiguration(); config.Load( XDocument.Parse( @" <GrandOutputConfiguration> <Channel MinimalFilter=""Debug""> <Add Type=""BinaryFile"" Name=""All"" Path=""FilteringByTopic"" /> <Channel Name=""HiddenTopic"" MinimalFilter=""Off"" TopicFilter=""*H*T?pic*"" > <Channel Name=""SavedHiddenTopic"" MinimalFilter=""Release"" TopicFilter=""*DOSHOW*"" > </Channel> </Channel> <Channel Name=""MonitoredTopic"" MinimalFilter=""Monitor"" TopicFilter=""*MONITOR*"" > </Channel> </Channel> </GrandOutputConfiguration>", LoadOptions.SetLineInfo ).Root, TestHelper.ConsoleMonitor ); Assert.That( g.SetConfiguration( config, TestHelper.ConsoleMonitor ) ); var fullyHidden = new ActivityMonitor( false ); g.Register( fullyHidden ); fullyHidden.SetTopic( "A fully hidden topic: setting the topic before any send, totally hides the monitor if the Actual filter is Off. - NOSHOW" ); fullyHidden.Fatal().Send( "NOSHOW" ); using( fullyHidden.OpenFatal().Send( "NOSHOW" ) ) { fullyHidden.Fatal().Send( "NOSHOW" ); } var m = new ActivityMonitor( false ); g.Register( m ); m.Trace().Send( "Trace-1" ); m.SetTopic( "This is a Hidden Topic - NOSHOW" ); m.Fatal().Send( "NOSHOW" ); m.SetTopic( "Visible Topic" ); m.Trace().Send( "Trace-2" ); m.SetTopic( "This is a Hidden Topic but DOSHOW puts it in Release mode." ); m.Trace().Send( "NOSHOW" ); m.Info().Send( "NOSHOW" ); m.Warn().Send( "NOSHOW" ); m.Error().Send( "Error-1" ); m.Fatal().Send( "Fatal-1" ); m.SetTopic( "This is a HT?PIC (off). Match is case insensitive - NOSHOW" ); m.Fatal().Send( "NOSHOW" ); m.SetTopic( null ); m.Trace().Send( "Trace-3" ); m.SetTopic( "A MONITORed topic: If i wrote This is a t.o.p.i.c (without the dots), this would have matched the HiddenT.o.p.i.c channel..." ); m.Trace().Send( "NOSHOW" ); m.Warn().Send( "Warn-1" ); } List<StupidStringClient> logs = TestHelper.ReadAllLogs( new DirectoryInfo( SystemActivityMonitor.RootLogPath + "FilteringByTopic" ), false ); Assert.That( logs.Count, Is.EqualTo( 1 ), "Fully hidden monitor does not appear." ); Assert.That( logs[0].ToString(), Does.Not.Contain( "NOSHOW" ) ); var texts = logs[0].Entries.Select( e => e.Text ).ToArray(); CollectionAssert.AreEqual( new string[] { "Trace-1", ActivityMonitor.SetTopicPrefix + "Visible Topic", "Trace-2", ActivityMonitor.SetTopicPrefix + "This is a Hidden Topic but DOSHOW puts it in Release mode.", "Error-1", "Fatal-1", ActivityMonitor.SetTopicPrefix, "Trace-3", ActivityMonitor.SetTopicPrefix + "A MONITORed topic: If i wrote This is a t.o.p.i.c (without the dots), this would have matched the HiddenT.o.p.i.c channel...", "Warn-1" }, texts, StringComparer.Ordinal ); }
static IActivityMonitor CreateMonitorAndRegisterGrandOutput( string topic, GrandOutput go ) { var m = new ActivityMonitor( topic ); go.Register( m ); return m; }
static void DumpSampleLogs1( Random r, GrandOutput g ) { var m = new ActivityMonitor( false ); g.Register( m ); m.SetTopic( "First Activity..." ); if( r.Next( 3 ) == 0 ) System.Threading.Thread.Sleep( 100 + r.Next( 2500 ) ); using( m.OpenTrace().Send( "Opening trace" ) ) { if( r.Next( 3 ) == 0 ) System.Threading.Thread.Sleep( 100 + r.Next( 2500 ) ); m.Trace().Send( "A trace in group." ); if( r.Next( 3 ) == 0 ) System.Threading.Thread.Sleep( 100 + r.Next( 2500 ) ); m.Info().Send( "An info in group." ); if( r.Next( 3 ) == 0 ) System.Threading.Thread.Sleep( 100 + r.Next( 2500 ) ); m.Warn().Send( "A warning in group." ); if( r.Next( 3 ) == 0 ) System.Threading.Thread.Sleep( 100 + r.Next( 2500 ) ); m.Error().Send( "An error in group." ); if( r.Next( 3 ) == 0 ) System.Threading.Thread.Sleep( 100 + r.Next( 2500 ) ); m.Fatal().Send( "A fatal in group." ); } if( r.Next( 3 ) == 0 ) System.Threading.Thread.Sleep( 100 + r.Next( 2500 ) ); m.Trace().Send( "End of first activity." ); }
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; }
static void DumpSampleLogs2( Random r, GrandOutput g ) { var m = new ActivityMonitor( false ); g.Register( m ); m.Fatal().Send( ThrowExceptionWithInner( false ), "An error occured" ); m.SetTopic( "This is a topic..." ); m.Trace().Send( "a trace" ); m.Trace().Send( "another one" ); m.SetTopic( "Please, show this topic!" ); m.Trace().Send( "Anotther trace." ); using( m.OpenTrace().Send( "A group trace." ) ) { m.Trace().Send( "A trace in group." ); m.Info().Send( "An info..." ); using( m.OpenInfo().Send( @"A group information... with a multi -line message. This MUST be correctly indented!" ) ) { m.Info().Send( "Info in info group." ); m.Info().Send( "Another info in info group." ); m.Error().Send( ThrowExceptionWithInner( true ), "An error." ); m.Warn().Send( "A warning." ); m.Trace().Send( "Something must be said." ); m.CloseGroup( "Everything is in place." ); } } m.SetTopic( null ); using( m.OpenTrace().Send( "A group with multiple conclusions." ) ) { using( m.OpenTrace().Send( "A group with no conclusion." ) ) { m.Trace().Send( "Something must be said." ); } m.CloseGroup( new[] { new ActivityLogGroupConclusion( "My very first conclusion." ), new ActivityLogGroupConclusion( "My second conclusion." ), new ActivityLogGroupConclusion( @"My very last conclusion is a multi line one. and this is fine!" ) } ); } m.Trace().Send( "This is the final trace." ); }