Exemple #1
0
    public void ThrowsOnNegativeFlushInterval()
    {
        var options = new W3CLoggerOptions();
        var ex      = Assert.Throws <ArgumentOutOfRangeException>(() => options.FlushInterval = TimeSpan.FromSeconds(-1));

        Assert.Contains("FlushInterval must be positive", ex.Message);
    }
Exemple #2
0
    public async Task WritesToTextFile()
    {
        var mockSystemDateTime = new MockSystemDateTime
        {
            Now = _today
        };
        var path = Path.Combine(TempPath, Path.GetRandomFileName());

        try
        {
            string fileName;
            var    options = new W3CLoggerOptions()
            {
                LogDirectory = path
            };
            await using (var logger = new FileLoggerProcessor(new OptionsWrapperMonitor <W3CLoggerOptions>(options), new HostingEnvironment(), NullLoggerFactory.Instance))
            {
                logger.SystemDateTime = mockSystemDateTime;
                logger.EnqueueMessage(_messageOne);
                fileName = Path.Combine(path, FormattableString.Invariant($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}.0000.txt"));
                // Pause for a bit before disposing so logger can finish logging
                await WaitForFile(fileName, _messageOne.Length).DefaultTimeout();
            }
            Assert.True(File.Exists(fileName));

            Assert.Equal(_messageOne + Environment.NewLine, File.ReadAllText(fileName));
        }
        finally
        {
            Helpers.DisposeDirectory(path);
        }
    }
Exemple #3
0
    private IOptionsMonitor <W3CLoggerOptions> CreateOptionsAccessor()
    {
        var options         = new W3CLoggerOptions();
        var optionsAccessor = Mock.Of <IOptionsMonitor <W3CLoggerOptions> >(o => o.CurrentValue == options);

        return(optionsAccessor);
    }
Exemple #4
0
    public void ThrowsOnNegativeFileSizeLimit()
    {
        var options = new W3CLoggerOptions();
        var ex      = Assert.Throws <ArgumentOutOfRangeException>(() => options.FileSizeLimit = -1);

        Assert.Contains("FileSizeLimit must be positive", ex.Message);
    }
Exemple #5
0
    public async Task StopsLoggingAfter10000Files()
    {
        var path = Path.Combine(TempPath, Path.GetRandomFileName());

        Directory.CreateDirectory(path);
        var mockSystemDateTime = new MockSystemDateTime
        {
            Now = _today
        };

        try
        {
            string lastFileName;
            var    options = new W3CLoggerOptions()
            {
                LogDirectory           = path,
                FileSizeLimit          = 5,
                RetainedFileCountLimit = 10000
            };
            var testSink   = new TestSink();
            var testLogger = new TestLoggerFactory(testSink, enabled: true);
            await using (var logger = new FileLoggerProcessor(new OptionsWrapperMonitor <W3CLoggerOptions>(options), new HostingEnvironment(), testLogger))
            {
                logger.SystemDateTime = mockSystemDateTime;
                for (int i = 0; i < 10000; i++)
                {
                    logger.EnqueueMessage(_messageOne);
                }
                lastFileName = Path.Combine(path, FormattableString.Invariant($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}.9999.txt"));
                await WaitForFile(lastFileName, _messageOne.Length).DefaultTimeout();

                // directory is full, no warnings yet
                Assert.Equal(0, testSink.Writes.Count);

                logger.EnqueueMessage(_messageOne);
                await WaitForCondition(() => testSink.Writes.FirstOrDefault()?.EventId.Name == "MaxFilesReached").DefaultTimeout();
            }

            Assert.Equal(10000, new DirectoryInfo(path)
                         .GetFiles()
                         .ToArray().Length);

            // restarting the logger should do nothing since the folder is still full
            var testSink2   = new TestSink();
            var testLogger2 = new TestLoggerFactory(testSink2, enabled: true);
            await using (var logger = new FileLoggerProcessor(new OptionsWrapperMonitor <W3CLoggerOptions>(options), new HostingEnvironment(), testLogger2))
            {
                Assert.Equal(0, testSink2.Writes.Count);

                logger.SystemDateTime = mockSystemDateTime;
                logger.EnqueueMessage(_messageOne);
                await WaitForCondition(() => testSink2.Writes.FirstOrDefault()?.EventId.Name == "MaxFilesReached").DefaultTimeout();
            }
        }
        finally
        {
            Helpers.DisposeDirectory(path);
        }
    }
Exemple #6
0
    public void DoesNotInitializeWithOptionalFields()
    {
        var options = new W3CLoggerOptions();

        // Optional fields shouldn't be logged by default
        Assert.False(options.LoggingFields.HasFlag(W3CLoggingFields.UserName));
        Assert.False(options.LoggingFields.HasFlag(W3CLoggingFields.Cookie));
    }
    public async Task WritesToNewFileOnOptionsChange()
    {
        var mockSystemDateTime = new MockSystemDateTime
        {
            Now = _today
        };

        var path = Path.Combine(TempPath, Path.GetRandomFileName());

        Directory.CreateDirectory(path);

        try
        {
            var options = new W3CLoggerOptions()
            {
                LogDirectory  = path,
                LoggingFields = W3CLoggingFields.Time,
                FileSizeLimit = 10000
            };
            var fileName1 = Path.Combine(path, FormattableString.Invariant($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}.0000.txt"));
            var fileName2 = Path.Combine(path, FormattableString.Invariant($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}.0001.txt"));
            var monitor   = new OptionsWrapperMonitor <W3CLoggerOptions>(options);

            await using (var logger = new FileLoggerProcessor(monitor, new HostingEnvironment(), NullLoggerFactory.Instance))
            {
                logger.SystemDateTime = mockSystemDateTime;
                logger.EnqueueMessage(_messageOne);
                await WaitForFile(fileName1, _messageOne.Length).DefaultTimeout();

                options.LoggingFields = W3CLoggingFields.Date;
                monitor.InvokeChanged();
                logger.EnqueueMessage(_messageTwo);
                // Pause for a bit before disposing so logger can finish logging
                await WaitForFile(fileName2, _messageTwo.Length).DefaultTimeout();
            }

            var actualFiles = new DirectoryInfo(path)
                              .GetFiles()
                              .Select(f => f.Name)
                              .OrderBy(f => f)
                              .ToArray();

            Assert.Equal(2, actualFiles.Length);

            Assert.True(File.Exists(fileName1));
            Assert.True(File.Exists(fileName2));

            Assert.Equal(_messageOne + Environment.NewLine, File.ReadAllText(fileName1));
            Assert.Equal(_messageTwo + Environment.NewLine, File.ReadAllText(fileName2));
        }
        finally
        {
            Helpers.DisposeDirectory(path);
        }
    }
Exemple #8
0
    public async Task RespectsMaxFileCount()
    {
        var path = Path.Combine(TempPath, Path.GetRandomFileName());

        Directory.CreateDirectory(path);
        File.WriteAllText(Path.Combine(path, "randomFile.txt"), "Text");
        var mockSystemDateTime = new MockSystemDateTime
        {
            Now = _today
        };

        try
        {
            string lastFileName;
            var    options = new W3CLoggerOptions()
            {
                LogDirectory           = path,
                RetainedFileCountLimit = 3,
                FileSizeLimit          = 5
            };
            await using (var logger = new FileLoggerProcessor(new OptionsWrapperMonitor <W3CLoggerOptions>(options), new HostingEnvironment(), NullLoggerFactory.Instance))
            {
                logger.SystemDateTime = mockSystemDateTime;
                for (int i = 0; i < 10; i++)
                {
                    logger.EnqueueMessage(_messageOne);
                }
                lastFileName = Path.Combine(path, FormattableString.Invariant($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}.0009.txt"));
                // Pause for a bit before disposing so logger can finish logging
                await WaitForFile(lastFileName, _messageOne.Length).DefaultTimeout();

                for (int i = 0; i < 6; i++)
                {
                    await WaitForRoll(Path.Combine(path, FormattableString.Invariant($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}.{i:0000}.txt"))).DefaultTimeout();
                }
            }

            var actualFiles = new DirectoryInfo(path)
                              .GetFiles()
                              .Select(f => f.Name)
                              .OrderBy(f => f)
                              .ToArray();

            Assert.Equal(4, actualFiles.Length);
            Assert.Equal("randomFile.txt", actualFiles[0]);
            for (int i = 1; i < 4; i++)
            {
                Assert.True((actualFiles[i].StartsWith($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}", StringComparison.InvariantCulture)));
            }
        }
        finally
        {
            Helpers.DisposeDirectory(path);
        }
    }
Exemple #9
0
    public async Task RollsTextFilesBasedOnDate()
    {
        var mockSystemDateTime = new MockSystemDateTime
        {
            Now = _today
        };
        var tomorrow = _today.AddDays(1);

        var path    = Path.Combine(TempPath, Path.GetRandomFileName());
        var options = new W3CLoggerOptions()
        {
            LogDirectory = path
        };

        try
        {
            string fileNameToday;
            string fileNameTomorrow;

            await using (var logger = new FileLoggerProcessor(new OptionsWrapperMonitor <W3CLoggerOptions>(options), new HostingEnvironment(), NullLoggerFactory.Instance))
            {
                logger.SystemDateTime = mockSystemDateTime;
                logger.EnqueueMessage(_messageOne);

                fileNameToday = Path.Combine(path, FormattableString.Invariant($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}.0000.txt"));

                await WaitForFile(fileNameToday, _messageOne.Length).DefaultTimeout();

                mockSystemDateTime.Now = tomorrow;
                logger.EnqueueMessage(_messageTwo);

                fileNameTomorrow = Path.Combine(path, FormattableString.Invariant($"{options.FileName}{tomorrow.Year:0000}{tomorrow.Month:00}{tomorrow.Day:00}.0000.txt"));

                await WaitForFile(fileNameTomorrow, _messageTwo.Length).DefaultTimeout();
            }

            Assert.True(File.Exists(fileNameToday));
            Assert.Equal(_messageOne + Environment.NewLine, File.ReadAllText(fileNameToday));
            Assert.True(File.Exists(fileNameTomorrow));
            Assert.Equal(_messageTwo + Environment.NewLine, File.ReadAllText(fileNameTomorrow));
        }
        finally
        {
            Helpers.DisposeDirectory(path);
        }
    }
Exemple #10
0
    public async Task WritesDateTime()
    {
        var path    = Path.GetTempFileName() + "_";
        var now     = DateTime.UtcNow;
        var options = new W3CLoggerOptions()
        {
            LoggingFields = W3CLoggingFields.Date | W3CLoggingFields.Time,
            LogDirectory  = path
        };

        try
        {
            await using (var logger = new TestW3CLogger(new OptionsWrapperMonitor <W3CLoggerOptions>(options), new HostingEnvironment(), NullLoggerFactory.Instance))
            {
                var elements          = new string[W3CLoggingMiddleware._fieldsLength];
                var additionalHeaders = new string[0];
                AddToList(elements, W3CLoggingMiddleware._dateIndex, _timestampOne.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture));
                AddToList(elements, W3CLoggingMiddleware._timeIndex, _timestampOne.ToString("HH:mm:ss", CultureInfo.InvariantCulture));

                logger.Log(elements, additionalHeaders);
                await logger.Processor.WaitForWrites(4).DefaultTimeout();

                var lines = logger.Processor.Lines;
                Assert.Equal("#Version: 1.0", lines[0]);

                Assert.StartsWith("#Start-Date: ", lines[1]);
                var startDate = DateTime.Parse(lines[1].Substring(13), CultureInfo.InvariantCulture);
                // Assert that the log was written in the last 10 seconds
                // W3CLogger writes start-time to second precision, so delta could be as low as -0.999...
                var delta = startDate.Subtract(now).TotalSeconds;
                Assert.InRange(delta, -1, 10);

                Assert.Equal("#Fields: date time", lines[2]);

                Assert.StartsWith("2021-01-02 03:04:05", lines[3]);
            }
        }
        finally
        {
            Helpers.DisposeDirectory(path);
        }
    }
Exemple #11
0
    public async Task HandlesNullValuesAsync()
    {
        var path    = Path.GetTempFileName() + "_";
        var now     = DateTime.UtcNow;
        var options = new W3CLoggerOptions()
        {
            LoggingFields = W3CLoggingFields.UriQuery | W3CLoggingFields.Host | W3CLoggingFields.ProtocolStatus,
            LogDirectory  = path
        };

        try
        {
            await using (var logger = new TestW3CLogger(new OptionsWrapperMonitor <W3CLoggerOptions>(options), new HostingEnvironment(), NullLoggerFactory.Instance))
            {
                var elements          = new string[W3CLoggingMiddleware._fieldsLength];
                var additionalHeaders = new string[0];
                AddToList(elements, W3CLoggingMiddleware._uriQueryIndex, null);
                AddToList(elements, W3CLoggingMiddleware._hostIndex, null);
                AddToList(elements, W3CLoggingMiddleware._protocolStatusIndex, null);

                logger.Log(elements, additionalHeaders);
                await logger.Processor.WaitForWrites(4).DefaultTimeout();

                var lines = logger.Processor.Lines;
                Assert.Equal("#Version: 1.0", lines[0]);

                Assert.StartsWith("#Start-Date: ", lines[1]);
                var startDate = DateTime.Parse(lines[1].Substring(13), CultureInfo.InvariantCulture);
                // Assert that the log was written in the last 10 seconds
                // W3CLogger writes start-time to second precision, so delta could be as low as -0.999...
                var delta = startDate.Subtract(now).TotalSeconds;
                Assert.InRange(delta, -1, 10);

                Assert.Equal("#Fields: cs-uri-query sc-status cs-host", lines[2]);
                Assert.Equal("- - -", lines[3]);
            }
        }
        finally
        {
            Helpers.DisposeDirectory(path);
        }
    }
    /// <summary>
    /// Initializes <see cref="W3CLoggingMiddleware" />.
    /// </summary>
    /// <param name="next"></param>
    /// <param name="options"></param>
    /// <param name="w3cLogger"></param>
    public W3CLoggingMiddleware(RequestDelegate next, IOptionsMonitor <W3CLoggerOptions> options, W3CLogger w3cLogger)
    {
        if (next == null)
        {
            throw new ArgumentNullException(nameof(next));
        }

        if (options == null)
        {
            throw new ArgumentNullException(nameof(options));
        }

        if (w3cLogger == null)
        {
            throw new ArgumentNullException(nameof(w3cLogger));
        }

        _next      = next;
        _options   = options;
        _w3cLogger = w3cLogger;
        _additionalRequestHeaders = W3CLoggerOptions.FilterRequestHeaders(options.CurrentValue);
    }
Exemple #13
0
    internal static ISet <string> FilterRequestHeaders(W3CLoggerOptions options)
    {
        var clonedSet = new SortedSet <string>(options.AdditionalRequestHeaders, StringComparer.InvariantCultureIgnoreCase);

        if (options.LoggingFields.HasFlag(W3CLoggingFields.Host))
        {
            clonedSet.Remove(HeaderNames.Host);
        }
        if (options.LoggingFields.HasFlag(W3CLoggingFields.Referer))
        {
            clonedSet.Remove(HeaderNames.Referer);
        }
        if (options.LoggingFields.HasFlag(W3CLoggingFields.UserAgent))
        {
            clonedSet.Remove(HeaderNames.UserAgent);
        }
        if (options.LoggingFields.HasFlag(W3CLoggingFields.Cookie))
        {
            clonedSet.Remove(HeaderNames.Cookie);
        }
        return(clonedSet);
    }
Exemple #14
0
    public async Task RollsTextFilesBasedOnSize()
    {
        var path = Path.Combine(TempPath, Path.GetRandomFileName());

        try
        {
            string filePath1;
            string filePath2;
            var    mockSystemDateTime = new MockSystemDateTime
            {
                Now = _today
            };
            var options = new W3CLoggerOptions()
            {
                LogDirectory  = path,
                FileSizeLimit = 5
            };
            await using (var logger = new FileLoggerProcessor(new OptionsWrapperMonitor <W3CLoggerOptions>(options), new HostingEnvironment(), NullLoggerFactory.Instance))
            {
                logger.SystemDateTime = mockSystemDateTime;
                logger.EnqueueMessage(_messageOne);
                logger.EnqueueMessage(_messageTwo);
                filePath1 = GetLogFilePath(path, options.FileName, _today, 0);
                filePath2 = GetLogFilePath(path, options.FileName, _today, 1);
                // Pause for a bit before disposing so logger can finish logging
                await WaitForFile(filePath2, _messageTwo.Length).DefaultTimeout();
            }
            Assert.True(File.Exists(filePath1));
            Assert.True(File.Exists(filePath2));

            Assert.Equal(_messageOne + Environment.NewLine, File.ReadAllText(filePath1));
            Assert.Equal(_messageTwo + Environment.NewLine, File.ReadAllText(filePath2));
        }
        finally
        {
            Helpers.DisposeDirectory(path);
        }
    }
Exemple #15
0
    public async Task RollsTextFilesWhenFirstLogOfDayIsMissing()
    {
        var mockSystemDateTime = new MockSystemDateTime
        {
            Now = _today
        };

        var path = Path.Combine(TempPath, Path.GetRandomFileName());

        Directory.CreateDirectory(path);

        try
        {
            var options = new W3CLoggerOptions()
            {
                LogDirectory           = path,
                FileSizeLimit          = 5,
                RetainedFileCountLimit = 2,
            };
            var fileName1 = Path.Combine(path, FormattableString.Invariant($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}.0000.txt"));
            var fileName2 = Path.Combine(path, FormattableString.Invariant($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}.0001.txt"));
            var fileName3 = Path.Combine(path, FormattableString.Invariant($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}.0002.txt"));
            var fileName4 = Path.Combine(path, FormattableString.Invariant($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}.0003.txt"));

            await using (var logger = new FileLoggerProcessor(new OptionsWrapperMonitor <W3CLoggerOptions>(options), new HostingEnvironment(), NullLoggerFactory.Instance))
            {
                logger.SystemDateTime = mockSystemDateTime;
                logger.EnqueueMessage(_messageOne);
                logger.EnqueueMessage(_messageTwo);
                logger.EnqueueMessage(_messageThree);
                // Pause for a bit before disposing so logger can finish logging
                await WaitForFile(fileName3, _messageThree.Length).DefaultTimeout();
            }

            // Even with a big enough FileSizeLimit, we still won't try to write to files from a previous instance.
            options.FileSizeLimit = 10000;

            await using (var logger = new FileLoggerProcessor(new OptionsWrapperMonitor <W3CLoggerOptions>(options), new HostingEnvironment(), NullLoggerFactory.Instance))
            {
                logger.SystemDateTime = mockSystemDateTime;
                logger.EnqueueMessage(_messageFour);
                // Pause for a bit before disposing so logger can finish logging
                await WaitForFile(fileName4, _messageFour.Length).DefaultTimeout();
            }

            var actualFiles = new DirectoryInfo(path)
                              .GetFiles()
                              .Select(f => f.Name)
                              .OrderBy(f => f)
                              .ToArray();

            Assert.Equal(2, actualFiles.Length);

            Assert.False(File.Exists(fileName1));
            Assert.False(File.Exists(fileName2));
            Assert.True(File.Exists(fileName3));
            Assert.True(File.Exists(fileName4));

            Assert.Equal(_messageThree + Environment.NewLine, File.ReadAllText(fileName3));
            Assert.Equal(_messageFour + Environment.NewLine, File.ReadAllText(fileName4));
        }
        finally
        {
            Helpers.DisposeDirectory(path);
        }
    }
Exemple #16
0
    public void ThrowsOnEmptyLogDirectory()
    {
        var options = new W3CLoggerOptions();

        Assert.Throws <ArgumentNullException>(() => options.LogDirectory = "");
    }
Exemple #17
0
    public async Task InstancesWriteToSameDirectory()
    {
        var mockSystemDateTime = new MockSystemDateTime
        {
            Now = _today
        };

        var path = Path.Combine(TempPath, Path.GetRandomFileName());

        Directory.CreateDirectory(path);

        try
        {
            var options = new W3CLoggerOptions()
            {
                LogDirectory           = path,
                RetainedFileCountLimit = 10,
                FileSizeLimit          = 5
            };
            await using (var logger = new FileLoggerProcessor(new OptionsWrapperMonitor <W3CLoggerOptions>(options), new HostingEnvironment(), NullLoggerFactory.Instance))
            {
                logger.SystemDateTime = mockSystemDateTime;
                for (int i = 0; i < 3; i++)
                {
                    logger.EnqueueMessage(_messageOne);
                }
                var filePath = Path.Combine(path, FormattableString.Invariant($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}.0002.txt"));
                // Pause for a bit before disposing so logger can finish logging
                await WaitForFile(filePath, _messageOne.Length).DefaultTimeout();
            }

            // Second instance should pick up where first one left off
            await using (var logger = new FileLoggerProcessor(new OptionsWrapperMonitor <W3CLoggerOptions>(options), new HostingEnvironment(), NullLoggerFactory.Instance))
            {
                logger.SystemDateTime = mockSystemDateTime;
                for (int i = 0; i < 3; i++)
                {
                    logger.EnqueueMessage(_messageOne);
                }
                var filePath = Path.Combine(path, FormattableString.Invariant($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}.0005.txt"));
                // Pause for a bit before disposing so logger can finish logging
                await WaitForFile(filePath, _messageOne.Length).DefaultTimeout();
            }

            var actualFiles1 = new DirectoryInfo(path)
                               .GetFiles()
                               .Select(f => f.Name)
                               .OrderBy(f => f)
                               .ToArray();

            Assert.Equal(6, actualFiles1.Length);
            for (int i = 0; i < 6; i++)
            {
                Assert.Contains($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}.{i:0000}.txt", actualFiles1[i]);
            }

            // Third instance should roll to 5 most recent files
            options.RetainedFileCountLimit = 5;
            await using (var logger = new FileLoggerProcessor(new OptionsWrapperMonitor <W3CLoggerOptions>(options), new HostingEnvironment(), NullLoggerFactory.Instance))
            {
                logger.SystemDateTime = mockSystemDateTime;
                logger.EnqueueMessage(_messageOne);
                // Pause for a bit before disposing so logger can finish logging
                await WaitForFile(Path.Combine(path, FormattableString.Invariant($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}.0006.txt")), _messageOne.Length).DefaultTimeout();
                await WaitForRoll(Path.Combine(path, FormattableString.Invariant($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}.0000.txt"))).DefaultTimeout();
                await WaitForRoll(Path.Combine(path, FormattableString.Invariant($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}.0001.txt"))).DefaultTimeout();
            }

            var actualFiles2 = new DirectoryInfo(path)
                               .GetFiles()
                               .Select(f => f.Name)
                               .OrderBy(f => f)
                               .ToArray();

            Assert.Equal(5, actualFiles2.Length);
            for (int i = 0; i < 5; i++)
            {
                Assert.Equal($"{options.FileName}{_today.Year:0000}{_today.Month:00}{_today.Day:00}.{i + 2:0000}.txt", actualFiles2[i]);
            }
        }
        finally
        {
            Helpers.DisposeDirectory(path);
        }
    }
 public W3CLoggerProcessor(IOptionsMonitor <W3CLoggerOptions> options, IHostEnvironment environment, ILoggerFactory factory) : base(options, environment, factory)
 {
     _loggingFields            = options.CurrentValue.LoggingFields;
     _additionalRequestHeaders = W3CLoggerOptions.FilterRequestHeaders(options.CurrentValue);
 }
    public FileLoggerProcessor(IOptionsMonitor <W3CLoggerOptions> options, IHostEnvironment environment, ILoggerFactory factory)
    {
        _logger = factory.CreateLogger(typeof(FileLoggerProcessor));

        _options = options;
        var loggerOptions = _options.CurrentValue;

        _path = loggerOptions.LogDirectory;
        // If user supplies no LogDirectory, default to {ContentRoot}/logs.
        // If user supplies a relative path, use {ContentRoot}/{LogDirectory}.
        // If user supplies a full path, use that.
        if (string.IsNullOrEmpty(_path))
        {
            _path = Path.Join(environment.ContentRootPath, "logs");
        }
        else if (!Path.IsPathRooted(_path))
        {
            _path = Path.Join(environment.ContentRootPath, _path);
        }

        _fileName          = loggerOptions.FileName;
        _maxFileSize       = loggerOptions.FileSizeLimit;
        _maxRetainedFiles  = loggerOptions.RetainedFileCountLimit;
        _flushInterval     = loggerOptions.FlushInterval;
        _fields            = loggerOptions.LoggingFields;
        _additionalHeaders = W3CLoggerOptions.FilterRequestHeaders(loggerOptions);

        _options.OnChange(options =>
        {
            lock (_pathLock)
            {
                // Clear the cached settings.
                loggerOptions = options;

                // Move to a new file if the fields have changed
                if (_fields != loggerOptions.LoggingFields || !_additionalHeaders.SetEquals(loggerOptions.AdditionalRequestHeaders))
                {
                    _fileNumber++;
                    if (_fileNumber >= W3CLoggerOptions.MaxFileCount)
                    {
                        _maxFilesReached = true;
                        Log.MaxFilesReached(_logger);
                    }
                    _fields            = loggerOptions.LoggingFields;
                    _additionalHeaders = W3CLoggerOptions.FilterRequestHeaders(loggerOptions);
                }

                if (!string.IsNullOrEmpty(loggerOptions.LogDirectory))
                {
                    _path = loggerOptions.LogDirectory;
                }

                _fileName         = loggerOptions.FileName;
                _maxFileSize      = loggerOptions.FileSizeLimit;
                _maxRetainedFiles = loggerOptions.RetainedFileCountLimit;
                _flushInterval    = loggerOptions.FlushInterval;
            }
        });

        _today = SystemDateTime.Now;

        // Start message queue processor
        _cancellationTokenSource = new CancellationTokenSource();
        _outputTask = Task.Run(ProcessLogQueue);
    }
Exemple #20
0
    public async Task WritesToNewFileOnNewInstance()
    {
        var mockSystemDateTime = new MockSystemDateTime
        {
            Now = _today
        };

        var path = Path.Combine(TempPath, Path.GetRandomFileName());

        Directory.CreateDirectory(path);

        try
        {
            var options = new W3CLoggerOptions()
            {
                LogDirectory  = path,
                FileSizeLimit = 5
            };
            var filePath1 = GetLogFilePath(path, options.FileName, _today, 0);
            var filePath2 = GetLogFilePath(path, options.FileName, _today, 1);
            var filePath3 = GetLogFilePath(path, options.FileName, _today, 2);

            await using (var logger = new FileLoggerProcessor(new OptionsWrapperMonitor <W3CLoggerOptions>(options), new HostingEnvironment(), NullLoggerFactory.Instance))
            {
                logger.SystemDateTime = mockSystemDateTime;
                logger.EnqueueMessage(_messageOne);
                logger.EnqueueMessage(_messageTwo);
                // Pause for a bit before disposing so logger can finish logging
                await WaitForFile(filePath2, _messageTwo.Length).DefaultTimeout();
            }

            // Even with a big enough FileSizeLimit, we still won't try to write to files from a previous instance.
            options.FileSizeLimit = 10000;

            await using (var logger = new FileLoggerProcessor(new OptionsWrapperMonitor <W3CLoggerOptions>(options), new HostingEnvironment(), NullLoggerFactory.Instance))
            {
                logger.SystemDateTime = mockSystemDateTime;
                logger.EnqueueMessage(_messageThree);
                // Pause for a bit before disposing so logger can finish logging
                await WaitForFile(filePath3, _messageThree.Length).DefaultTimeout();
            }

            var actualFiles = new DirectoryInfo(path)
                              .GetFiles()
                              .Select(f => f.Name)
                              .OrderBy(f => f)
                              .ToArray();

            Assert.Equal(3, actualFiles.Length);

            Assert.True(File.Exists(filePath1));
            Assert.True(File.Exists(filePath2));
            Assert.True(File.Exists(filePath3));

            Assert.Equal(_messageOne + Environment.NewLine, File.ReadAllText(filePath1));
            Assert.Equal(_messageTwo + Environment.NewLine, File.ReadAllText(filePath2));
            Assert.Equal(_messageThree + Environment.NewLine, File.ReadAllText(filePath3));
        }
        finally
        {
            Helpers.DisposeDirectory(path);
        }
    }
Exemple #21
0
    public void ThrowsOnEmptyFileName()
    {
        var options = new W3CLoggerOptions();

        Assert.Throws <ArgumentNullException>(() => options.FileName = "");
    }
Exemple #22
0
    public async Task WritesToNewFileOnOptionsChange(bool fieldsChanged, bool headersChanged)
    {
        var mockSystemDateTime = new MockSystemDateTime
        {
            Now = _today
        };

        var path = Path.Combine(TempPath, Path.GetRandomFileName());

        Directory.CreateDirectory(path);

        try
        {
            var options = new W3CLoggerOptions()
            {
                LogDirectory  = path,
                LoggingFields = W3CLoggingFields.Time,
                FileSizeLimit = 10000,
            };
            options.AdditionalRequestHeaders.Add("one");
            var filePath1 = GetLogFilePath(path, options.FileName, _today, 0);
            var filePath2 = GetLogFilePath(path, options.FileName, _today, 1);
            var monitor   = new OptionsWrapperMonitor <W3CLoggerOptions>(options);

            await using (var logger = new FileLoggerProcessor(monitor, new HostingEnvironment(), NullLoggerFactory.Instance))
            {
                logger.SystemDateTime = mockSystemDateTime;
                logger.EnqueueMessage(_messageOne);
                await WaitForFile(filePath1, _messageOne.Length).DefaultTimeout();

                if (fieldsChanged)
                {
                    options.LoggingFields = W3CLoggingFields.Date;
                }

                if (headersChanged)
                {
                    options.AdditionalRequestHeaders.Remove("one");
                    options.AdditionalRequestHeaders.Add("two");
                }
                monitor.InvokeChanged();
                logger.EnqueueMessage(_messageTwo);
                // Pause for a bit before disposing so logger can finish logging
                await WaitForFile(filePath2, _messageTwo.Length).DefaultTimeout();
            }

            var actualFiles = new DirectoryInfo(path)
                              .GetFiles()
                              .Select(f => f.Name)
                              .OrderBy(f => f)
                              .ToArray();

            Assert.Equal(2, actualFiles.Length);

            Assert.True(File.Exists(filePath1));
            Assert.True(File.Exists(filePath2));

            Assert.Equal(_messageOne + Environment.NewLine, File.ReadAllText(filePath1));
            Assert.Equal(_messageTwo + Environment.NewLine, File.ReadAllText(filePath2));
        }
        finally
        {
            Helpers.DisposeDirectory(path);
        }
    }