public void ApplicationLogsReaderWillNotOpenUnlimitedNumberOfFiles()
        {
            // This test would preferrably use a mocked file system but the System.IO.Abstractions.TestHelpers have
            // some issues with returning the correct LastWrittenUtc and so this needs to run against a real file system for now.
            var fs = new FileSystem();

            FileSystemHelpers.Instance = fs;

            using (var dir = new TemporaryApplicationLogDirectory(fs))
            {
                var logFileCount = 100;
                var timestamp    = DateTimeOffset.UtcNow;
                for (int i = 0; i < logFileCount; i++)
                {
                    timestamp = timestamp.AddSeconds(1);
                    dir.AddLogFile(
                        string.Format("log-{0}.txt", i),
                        string.Format("{0:s}  PID[20108] Information this is a log\r\n", timestamp)
                        );
                }

                var env    = new ApplicationLogsTestEnvironment(dir.RootDir);
                var reader = new ApplicationLogsReader(env, Mock.Of <ITracer>());

                var results = reader.GetRecentLogs(logFileCount).ToList();

                // In this degenerate case with a large number of log files with only one line each, the limit
                // on the number of log files that can be read will be hit and so not all 100 log entries will
                // be returned.
                Assert.Equal(ApplicationLogsReader.FileOpenLimit, results.Count);
                results[0].AssertLogEntry(timestamp.ToString("s"), "Information", "this is a log");
            }
        }
        public void ResumableLogReaderCanReadFromFilesOpenForWriting()
        {
            var fs = new FileSystem();

            FileSystemHelpers.Instance = fs;

            using (var dir = new TemporaryApplicationLogDirectory(fs))
            {
                var logFile = dir.AddLogFile("log-1.txt", "2013-12-06T00:29:20  PID[20108] Information this is a log\r\n");
                using (var writer = new StreamWriter(fs.File.Open(logFile.FullName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
                {
                    AutoFlush = true
                })
                    using (var reader = new ApplicationLogsReader.ResumableLogFileReader(logFile, Mock.Of <ITracer>()))
                    {
                        writer.WriteLine("2013-12-06T00:29:21  PID[20108] Warning     this is a warning");
                        var results = reader.ReadNextBatch(1);
                        Assert.Equal(1, results.Count);
                        results[0].AssertLogEntry("2013-12-06T00:29:21+00:00", "Warning", "this is a warning");

                        writer.WriteLine("2013-12-06T00:29:22  PID[20108] Error       this is an error");
                        results = reader.ReadNextBatch(1);
                        Assert.Equal(1, results.Count);
                        results[0].AssertLogEntry("2013-12-06T00:29:20+00:00", "Information", "this is a log");
                    }
            }
        }
        public void ApplicationLogsReaderReturnsTheCorrectResultsWhenAccessedByMultipleThreads()
        {
            var fs = new FileSystem();

            FileSystemHelpers.Instance = fs;

            using (var dir = new TemporaryApplicationLogDirectory(fs))
            {
                dir.AddLogFile("log-1.txt",
                               @"2013-12-06T00:29:20  PID[20108] Information this is a log
2013-12-06T00:29:21  PID[20108] Warning     this is a warning
2013-12-06T00:29:22  PID[20108] Error       this is an error"
                               );

                dir.AddLogFile("log-2.txt",
                               @"2013-12-06T00:29:20  PID[20108] Information this is a log
2013-12-06T00:29:21  PID[20108] Warning     this is a warning
2013-12-06T00:29:22  PID[20108] Error       this is an error"
                               );

                dir.AddLogFile("log-3.txt", @"2014-01-09T00:18:30 NOT A VALID LOG FILE");

                dir.AddLogFile("abc-123-logging-errors.txt",
                               @"2014-01-09T00:18:30
System.ApplicationException: The trace listener AzureTableTraceListener is disabled. 
   at Microsoft.WindowsAzure.WebSites.Diagnostics.AzureTableTraceListener.GetCloudTableClientFromEnvironment()
   at Microsoft.WindowsAzure.WebSites.Diagnostics.AzureTableTraceListener.RefreshConfig()
   --- End of inner exception stack trace ---"
                               );

                dir.AddLogFile("log-4.txt",
                               @"2013-12-06T00:29:23  PID[20108] Information this is a log
2013-12-06T00:29:24  PID[20108] Information this is a log
2013-12-06T00:29:25  PID[20108] Information this is a log
2013-12-06T00:29:26  PID[20108] Information this is a log
2013-12-06T00:29:27  PID[20108] Information this is a log
2013-12-06T00:29:28  PID[20108] Information this is a log
2013-12-06T00:29:29  PID[20108] Warning     this is a warning
2013-12-06T00:29:30  PID[20108] Error       this is an error"
                               );

                var env    = new ApplicationLogsTestEnvironment(dir.RootDir);
                var reader = new ApplicationLogsReader(env, Mock.Of <ITracer>());

                var loopResult = Parallel.For(0, 10, (i) =>
                {
                    var results = reader.GetRecentLogs(20).ToList();
                    Assert.Equal(14, results.Count);
                });

                Assert.True(loopResult.IsCompleted);
            }
        }
        public void ResumableLogReaderDoesNotBlockLogWriters()
        {
            var fs = new FileSystem();

            FileSystemHelpers.Instance = fs;

            using (var dir = new TemporaryApplicationLogDirectory(fs))
            {
                var logFile = dir.AddLogFile("log-1.txt",
                                             @"2013-12-06T00:29:20  PID[20108] Information this is a log
2013-12-06T00:29:21  PID[20108] Warning     this is a warning
");

                // Open a reader and read the lines while the writer appends a new line
                using (var reader = new ApplicationLogsReader.ResumableLogFileReader(logFile, Mock.Of <ITracer>()))
                {
                    var results = reader.ReadNextBatch(1);
                    Assert.Equal(1, results.Count);
                    results[0].AssertLogEntry("2013-12-06T00:29:21+00:00", "Warning", "this is a warning");

                    using (var writer = new StreamWriter(fs.File.Open(logFile.FullName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite)))
                    {
                        writer.WriteLine("2013-12-06T00:29:22  PID[20108] Error       this is an error");
                    }

                    results = reader.ReadNextBatch(1);
                    Assert.Equal(1, results.Count);
                    results[0].AssertLogEntry("2013-12-06T00:29:20+00:00", "Information", "this is a log");
                }

                // Open a new reader and confirm that the new line written by the writer is present
                using (var reader = new ApplicationLogsReader.ResumableLogFileReader(logFile, Mock.Of <ITracer>()))
                {
                    var results = reader.ReadNextBatch(1);
                    Assert.Equal(1, results.Count);
                    results[0].AssertLogEntry("2013-12-06T00:29:22+00:00", "Error", "this is an error");
                }
            }
        }