public async Task LoggingToMemoryUsingCustomPathPlaceholderResolver()
        {
            const string appName     = "myapp";
            const string logsDirName = "Logs";

            var fileProvider = new MemoryFileProvider();

            var cts     = new CancellationTokenSource();
            var context = new TestFileLoggerContext(cts.Token, completionTimeout: Timeout.InfiniteTimeSpan);

            context.SetTimestamp(new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Utc));

            var services = new ServiceCollection();

            services.AddOptions();
            services.AddLogging(b => b.AddFile(context, o =>
            {
                o.FileAppender = new MemoryFileAppender(fileProvider);
                o.BasePath     = logsDirName;
                o.Files        = new[]
                {
                    new LogFileOptions
                    {
                        Path = "<appname>-<counter:000>.log"
                    }
                };
                o.PathPlaceholderResolver = (placeholderName, inlineFormat, context) => placeholderName == "appname" ? appName : null;
            }));

            FileLoggerProvider[] providers;

            using (ServiceProvider sp = services.BuildServiceProvider())
            {
                providers = context.GetProviders(sp).ToArray();
                Assert.Equal(1, providers.Length);

                ILogger <LoggingTest> logger1 = sp.GetService <ILogger <LoggingTest> >();

                logger1.LogInformation("This is a nice logger.");
                logger1.LogWarning(1, "This is a smart logger.");

                cts.Cancel();

                // ensuring that all entries are processed
                await context.GetCompletion(sp);

                Assert.True(providers.All(provider => provider.Completion.IsCompleted));
            }

            var logFile = (MemoryFileInfo)fileProvider.GetFileInfo($"{logsDirName}/{appName}-000.log");

            Assert.True(logFile.Exists && !logFile.IsDirectory);
        }
        public async Task FailingEntryDontGetStuck()
        {
            var logsDirName = Guid.NewGuid().ToString("D");

            var tempPath = Path.Combine(Path.GetTempPath());
            var logPath  = Path.Combine(tempPath, logsDirName);

            if (Directory.Exists(logPath))
            {
                Directory.Delete(logPath, recursive: true);
            }

            var fileProvider = new PhysicalFileProvider(tempPath);

            var options = new FileLoggerOptions
            {
                FileAppender = new PhysicalFileAppender(fileProvider),
                BasePath     = logsDirName,
                Files        = new[]
                {
                    new LogFileOptions
                    {
                        Path = "default.log",
                    },
                },
            };
            var optionsMonitor = new DelegatedOptionsMonitor <FileLoggerOptions>(_ => options);

            var completeCts         = new CancellationTokenSource();
            var completionTimeoutMs = 2000;
            var context             = new TestFileLoggerContext(completeCts.Token, TimeSpan.FromMilliseconds(completionTimeoutMs), writeRetryDelay: TimeSpan.FromMilliseconds(250));

            context.SetTimestamp(new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Utc));

            var services = new ServiceCollection();

            services.AddOptions();
            services.AddLogging(b => b.AddFile(context));
            services.AddSingleton <IOptionsMonitor <FileLoggerOptions> >(optionsMonitor);

            string filePath = Path.Combine(logPath, "default.log");

            try
            {
                FileLoggerProvider[] providers;

                using (ServiceProvider sp = services.BuildServiceProvider())
                {
                    providers = context.GetProviders(sp).ToArray();
                    Assert.Equal(1, providers.Length);

                    var resetTasks = new List <Task>();
                    foreach (FileLoggerProvider provider in providers)
                    {
                        provider.Reset += (s, e) => resetTasks.Add(e);
                    }

                    ILoggerFactory loggerFactory = sp.GetRequiredService <ILoggerFactory>();
                    ILogger        logger        = loggerFactory.CreateLogger("X");

                    logger.LogInformation("This should get through.");

                    optionsMonitor.Reload();
                    // ensuring that reset has been finished and the new settings are effective
                    await Task.WhenAll(resetTasks);

                    using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        logger.LogInformation("This shouldn't get through.");

                        Task completion = context.GetCompletion(sp);
                        Assert.False(completion.IsCompleted);

                        completeCts.Cancel();

                        Assert.Equal(completion, await Task.WhenAny(completion, Task.Delay(TimeSpan.FromMilliseconds(completionTimeoutMs * 2))));
                        Assert.Equal(TaskStatus.RanToCompletion, completion.Status);
                    }
                }

                IFileInfo logFile = fileProvider.GetFileInfo($"{logsDirName}/default.log");
                Assert.True(logFile.Exists && !logFile.IsDirectory);

                var lines = logFile.ReadAllText(out Encoding encoding).Split(new[] { Environment.NewLine }, StringSplitOptions.None);
                Assert.Equal(Encoding.UTF8, encoding);
                Assert.Equal(new[]
                {
                    $"info: X[0] @ {context.GetTimestamp().ToLocalTime():o}",
                    $"      This should get through.",
                    ""
                }, lines);
            }
            finally
            {
                Directory.Delete(logPath, recursive: true);
            }
        }
Beispiel #3
0
        public async Task ReloadOptionsSettings()
        {
            var configJson =
                $@"{{
    ""{FileLoggerProvider.Alias}"": {{
        ""{nameof(FileLoggerOptions.IncludeScopes)}"" : true,
        ""{nameof(FileLoggerOptions.Files)}"": [
        {{
            ""{nameof(LogFileOptions.Path)}"": ""test.log"",
        }}],
        ""{nameof(LoggerFilterRule.LogLevel)}"": {{ 
            ""{LogFileOptions.DefaultCategoryName}"": ""{LogLevel.Trace}"" 
        }}
    }}
}}";

            var fileProvider = new MemoryFileProvider();

            fileProvider.CreateFile("config.json", configJson, Encoding.UTF8);

            var cb = new ConfigurationBuilder();

            cb.AddJsonFile(fileProvider, "config.json", optional: false, reloadOnChange: true);
            IConfigurationRoot config = cb.Build();

            var completeCts = new CancellationTokenSource();
            var context     = new TestFileLoggerContext(completeCts.Token, completionTimeout: Timeout.InfiniteTimeSpan);

            context.SetTimestamp(new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Utc));

            var services = new ServiceCollection();

            services.AddOptions();
            services.AddLogging(b =>
            {
                b.AddConfiguration(config);
                b.AddFile(context);
            });

            var fileAppender = new MemoryFileAppender(fileProvider);

            services.Configure <FileLoggerOptions>(o => o.FileAppender ??= fileAppender);

            FileLoggerProvider[] providers;

            using (ServiceProvider sp = services.BuildServiceProvider())
            {
                providers = context.GetProviders(sp).ToArray();
                Assert.Equal(1, providers.Length);

                var resetTasks = new List <Task>();
                foreach (FileLoggerProvider provider in providers)
                {
                    provider.Reset += (s, e) => resetTasks.Add(e);
                }

                ILoggerFactory         loggerFactory = sp.GetService <ILoggerFactory>();
                ILogger <SettingsTest> logger1       = loggerFactory.CreateLogger <SettingsTest>();

                using (logger1.BeginScope("SCOPE"))
                {
                    logger1.LogTrace("This is a nice logger.");

                    using (logger1.BeginScope("NESTED SCOPE"))
                    {
                        logger1.LogInformation("This is a smart logger.");

                        // changing switch and scopes inclusion
                        configJson =
                            $@"{{
    ""{FileLoggerProvider.Alias}"": {{
        ""{nameof(FileLoggerOptions.Files)}"": [
        {{
            ""{nameof(LogFileOptions.Path)}"": ""test.log"",
        }}],
        ""{nameof(LoggerFilterRule.LogLevel)}"": {{ 
            ""{LogFileOptions.DefaultCategoryName}"": ""{LogLevel.Information}"" 
        }}
    }}
}}";

                        Assert.Equal(0, resetTasks.Count);
                        fileProvider.WriteContent("config.json", configJson);

                        // reload is triggered twice due to a bug in the framework (https://github.com/aspnet/Logging/issues/874)
                        Assert.Equal(1 * 2, resetTasks.Count);

                        // ensuring that reset has been finished and the new settings are effective
                        await Task.WhenAll(resetTasks);

                        logger1 = loggerFactory.CreateLogger <SettingsTest>();

                        logger1.LogInformation("This one shouldn't include scopes.");
                        logger1.LogTrace("This one shouldn't be included at all.");
                    }
                }

                completeCts.Cancel();

                // ensuring that all entries are processed
                await context.GetCompletion(sp);

                Assert.True(providers.All(provider => provider.Completion.IsCompleted));
            }

            var logFile = (MemoryFileInfo)fileProvider.GetFileInfo("test.log");

            Assert.True(logFile.Exists && !logFile.IsDirectory);

            var lines = logFile.ReadAllText(out Encoding encoding).Split(new[] { Environment.NewLine }, StringSplitOptions.None);

            Assert.Equal(Encoding.UTF8, encoding);
            Assert.Equal(new[]
            {
                $"trce: {typeof(SettingsTest).FullName}[0] @ {context.GetTimestamp().ToLocalTime():o}",
                $"      => SCOPE",
                $"      This is a nice logger.",
                $"info: {typeof(SettingsTest).FullName}[0] @ {context.GetTimestamp().ToLocalTime():o}",
                $"      => SCOPE => NESTED SCOPE",
                $"      This is a smart logger.",
                $"info: {typeof(SettingsTest).FullName}[0] @ {context.GetTimestamp().ToLocalTime():o}",
                $"      This one shouldn't include scopes.",
                ""
            }, lines);
        }
Beispiel #4
0
        private async Task LoggingToMemoryWithoutDICore(LogFileAccessMode accessMode)
        {
            const string logsDirName = "Logs";

            var fileProvider = new MemoryFileProvider();

            var filterOptions = new LoggerFilterOptions {
                MinLevel = LogLevel.Trace
            };

            var options = new FileLoggerOptions
            {
                FileAppender   = new MemoryFileAppender(fileProvider),
                BasePath       = logsDirName,
                FileAccessMode = accessMode,
                FileEncoding   = Encoding.UTF8,
                MaxQueueSize   = 100,
                DateFormat     = "yyMMdd",
                CounterFormat  = "000",
                MaxFileSize    = 10,
                Files          = new[]
                {
                    new LogFileOptions
                    {
                        Path       = "<date>/<date:MM>/logger.log",
                        DateFormat = "yyyy",
                        MinLevel   = new Dictionary <string, LogLevel>
                        {
                            ["Karambolo.Extensions.Logging.File"] = LogLevel.None,
                            [LogFileOptions.DefaultCategoryName]  = LogLevel.Information,
                        }
                    },
                    new LogFileOptions
                    {
                        Path     = "test-<date>-<counter>.log",
                        MinLevel = new Dictionary <string, LogLevel>
                        {
                            ["Karambolo.Extensions.Logging.File"] = LogLevel.Information,
                            [LogFileOptions.DefaultCategoryName]  = LogLevel.None,
                        }
                    },
                },
                TextBuilder   = new CustomLogEntryTextBuilder(),
                IncludeScopes = true,
            };

            var completeCts = new CancellationTokenSource();
            var context     = new TestFileLoggerContext(completeCts.Token, completionTimeout: Timeout.InfiniteTimeSpan);

            context.SetTimestamp(new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Utc));

            var ex = new Exception();

            var provider = new FileLoggerProvider(context, Options.Create(options));

            try
            {
                using (var loggerFactory = new LoggerFactory(new[] { provider }, filterOptions))
                {
                    ILogger <LoggingTest> logger1 = loggerFactory.CreateLogger <LoggingTest>();

                    logger1.LogInformation("This is a nice logger.");
                    using (logger1.BeginScope("SCOPE"))
                    {
                        logger1.LogWarning(1, "This is a smart logger.");
                        logger1.LogTrace("This won't make it.");

                        using (logger1.BeginScope("NESTED SCOPE"))
                        {
                            ILogger logger2 = loggerFactory.CreateLogger("X");
                            logger2.LogWarning("Some warning.");
                            logger2.LogError(0, ex, "Some failure!");
                        }
                    }
                }
            }
            finally
            {
#if NETCOREAPP3_0
                await provider.DisposeAsync();
#else
                await Task.CompletedTask;
                provider.Dispose();
#endif
            }

            Assert.True(provider.Completion.IsCompleted);

            var logFile = (MemoryFileInfo)fileProvider.GetFileInfo($"{logsDirName}/test-{context.GetTimestamp().ToLocalTime():yyMMdd}-000.log");
            Assert.True(logFile.Exists && !logFile.IsDirectory);

            var lines = logFile.ReadAllText(out Encoding encoding).Split(new[] { Environment.NewLine }, StringSplitOptions.None);
            Assert.Equal(Encoding.UTF8, encoding);
            Assert.Equal(new[]
            {
                $"[info]: {typeof(LoggingTest)}[0] @ {context.GetTimestamp().ToLocalTime():o}",
                $"        This is a nice logger.",
                ""
            }, lines);

            logFile = (MemoryFileInfo)fileProvider.GetFileInfo($"{logsDirName}/test-{context.GetTimestamp().ToLocalTime():yyMMdd}-001.log");
            Assert.True(logFile.Exists && !logFile.IsDirectory);

            lines = logFile.ReadAllText(out encoding).Split(new[] { Environment.NewLine }, StringSplitOptions.None);
            Assert.Equal(Encoding.UTF8, encoding);
            Assert.Equal(new[]
            {
                $"[warn]: {typeof(LoggingTest)}[1] @ {context.GetTimestamp().ToLocalTime():o}",
                $"        => SCOPE",
                $"        This is a smart logger.",
                ""
            }, lines);

            logFile = (MemoryFileInfo)fileProvider.GetFileInfo(
                $"{logsDirName}/{context.GetTimestamp().ToLocalTime():yyyy}/{context.GetTimestamp().ToLocalTime():MM}/logger.log");
            Assert.True(logFile.Exists && !logFile.IsDirectory);

            lines = logFile.ReadAllText(out encoding).Split(new[] { Environment.NewLine }, StringSplitOptions.None);
            Assert.Equal(Encoding.UTF8, encoding);
            Assert.Equal(new[]
            {
                $"[warn]: X[0] @ {context.GetTimestamp().ToLocalTime():o}",
                $"        => SCOPE => NESTED SCOPE",
                $"        Some warning.",
                $"[fail]: X[0] @ {context.GetTimestamp().ToLocalTime():o}",
                $"        => SCOPE => NESTED SCOPE",
                $"        Some failure!",
            }
                         .Concat(ex.ToString().Split(new[] { Environment.NewLine }, StringSplitOptions.None))
                         .Append(""), lines);
        }
Beispiel #5
0
        private async Task LoggingToPhysicalUsingDICore(LogFileAccessMode accessMode)
        {
            var logsDirName = Guid.NewGuid().ToString("D");

            var configData = new Dictionary <string, string>
            {
                [$"{nameof(FileLoggerOptions.BasePath)}"]         = logsDirName,
                [$"{nameof(FileLoggerOptions.FileEncodingName)}"] = "UTF-16",
                [$"{nameof(FileLoggerOptions.DateFormat)}"]       = "yyMMdd",
                [$"{nameof(FileLoggerOptions.FileAccessMode)}"]   = accessMode.ToString(),
                [$"{nameof(FileLoggerOptions.Files)}:0:{nameof(LogFileOptions.Path)}"] = "logger-<date>.log",
                [$"{nameof(FileLoggerOptions.Files)}:0:{nameof(LogFileOptions.MinLevel)}:Karambolo.Extensions.Logging.File"]    = LogLevel.None.ToString(),
                [$"{nameof(FileLoggerOptions.Files)}:0:{nameof(LogFileOptions.MinLevel)}:{LogFileOptions.DefaultCategoryName}"] = LogLevel.Information.ToString(),
                [$"{nameof(FileLoggerOptions.Files)}:1:{nameof(LogFileOptions.Path)}"] = "test-<date>.log",
                [$"{nameof(FileLoggerOptions.Files)}:1:{nameof(LogFileOptions.MinLevel)}:Karambolo.Extensions.Logging.File.Test"] = LogLevel.Information.ToString(),
                [$"{nameof(FileLoggerOptions.Files)}:1:{nameof(LogFileOptions.MinLevel)}:{LogFileOptions.DefaultCategoryName}"]   = LogLevel.None.ToString(),
            };

            var cb = new ConfigurationBuilder();

            cb.AddInMemoryCollection(configData);
            IConfigurationRoot config = cb.Build();

            var tempPath = Path.Combine(Path.GetTempPath());
            var logPath  = Path.Combine(tempPath, logsDirName);

            var fileProvider = new PhysicalFileProvider(tempPath);

            var cts     = new CancellationTokenSource();
            var context = new TestFileLoggerContext(cts.Token, completionTimeout: Timeout.InfiniteTimeSpan);

            context.SetTimestamp(new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Utc));

            var services = new ServiceCollection();

            services.AddOptions();
            services.AddLogging(b => b.AddFile(context, o => o.FileAppender = new PhysicalFileAppender(fileProvider)));
            services.Configure <FileLoggerOptions>(config);

            if (Directory.Exists(logPath))
            {
                Directory.Delete(logPath, recursive: true);
            }

            try
            {
                var ex = new Exception();

                FileLoggerProvider[] providers;

                using (ServiceProvider sp = services.BuildServiceProvider())
                {
                    providers = context.GetProviders(sp).ToArray();
                    Assert.Equal(1, providers.Length);

                    ILogger <LoggingTest> logger1 = sp.GetService <ILogger <LoggingTest> >();

                    logger1.LogInformation("This is a nice logger.");
                    using (logger1.BeginScope("SCOPE"))
                    {
                        logger1.LogWarning(1, "This is a smart logger.");
                        logger1.LogTrace("This won't make it.");

                        using (logger1.BeginScope("NESTED SCOPE"))
                        {
                            ILoggerFactory loggerFactory = sp.GetService <ILoggerFactory>();
                            ILogger        logger2       = loggerFactory.CreateLogger("X");
                            logger2.LogError(0, ex, "Some failure!");
                        }
                    }

                    cts.Cancel();

                    // ensuring that all entries are processed
                    await context.GetCompletion(sp);

                    Assert.True(providers.All(provider => provider.Completion.IsCompleted));
                }

                IFileInfo logFile = fileProvider.GetFileInfo($"{logsDirName}/test-{context.GetTimestamp().ToLocalTime():yyMMdd}.log");
                Assert.True(logFile.Exists && !logFile.IsDirectory);

                var lines = logFile.ReadAllText(out Encoding encoding).Split(new[] { Environment.NewLine }, StringSplitOptions.None);
                Assert.Equal(Encoding.Unicode, encoding);
                Assert.Equal(new[]
                {
                    $"info: {typeof(LoggingTest)}[0] @ {context.GetTimestamp().ToLocalTime():o}",
                    $"      This is a nice logger.",
                    $"warn: {typeof(LoggingTest)}[1] @ {context.GetTimestamp().ToLocalTime():o}",
                    $"      This is a smart logger.",
                    ""
                }, lines);

                logFile = fileProvider.GetFileInfo(
                    $"{logsDirName}/logger-{context.GetTimestamp().ToLocalTime():yyMMdd}.log");
                Assert.True(logFile.Exists && !logFile.IsDirectory);

                lines = logFile.ReadAllText(out encoding).Split(new[] { Environment.NewLine }, StringSplitOptions.None);
                Assert.Equal(Encoding.Unicode, encoding);
                Assert.Equal(new[]
                {
                    $"fail: X[0] @ {context.GetTimestamp().ToLocalTime():o}",
                    $"      Some failure!",
                }
                             .Concat(ex.ToString().Split(new[] { Environment.NewLine }, StringSplitOptions.None))
                             .Append(""), lines);
            }
            finally
            {
                Directory.Delete(logPath, recursive: true);
            }
        }
        public void LoggingToMemoryUsingFactory()
        {
            var fileProvider = new MemoryFileProvider();

            var settings = new FileLoggerSettings
            {
                FileAppender   = new MemoryFileAppender(fileProvider),
                BasePath       = LogsDirName,
                EnsureBasePath = true,
                FileEncoding   = Encoding.UTF8,
                MaxQueueSize   = 100,
                DateFormat     = "yyyyMMdd",
                CounterFormat  = "000",
                MaxFileSize    = 10,
                Switches       = new Dictionary <string, LogLevel>
                {
                    { FileLoggerSettingsBase.DefaultCategoryName, LogLevel.Information }
                },
                FileNameMappings = new Dictionary <string, string>
                {
                    { "Karambolo.Extensions.Logging.File.Test", "test.log" },
                    { "Karambolo.Extensions.Logging.File", "logger.log" },
                },
                TextBuilder   = new CustomLogEntryTextBuilder(),
                IncludeScopes = true,
            };

            var cts     = new CancellationTokenSource();
            var context = new TestFileLoggerContext(cts.Token);

            var completionTasks = new List <Task>();

            context.Complete += (s, e) => completionTasks.Add(e);

            context.SetTimestamp(new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Utc));

            var ex = new Exception();

            using (var loggerFactory = new LoggerFactory())
            {
                loggerFactory.AddFile(context, settings);
                ILogger <LoggingTest> logger1 = loggerFactory.CreateLogger <LoggingTest>();

                logger1.LogInformation("This is a nice logger.");
                using (logger1.BeginScope("SCOPE"))
                {
                    logger1.LogWarning(1, "This is a smart logger.");
                    logger1.LogTrace("This won't make it.");

                    using (logger1.BeginScope("NESTED SCOPE"))
                    {
                        ILogger logger2 = loggerFactory.CreateLogger("X");
                        logger2.LogError(0, ex, "Some failure!");
                    }
                }

                // ensuring that all entries are processed
                cts.Cancel();
                Assert.Single(completionTasks);
                Task.WhenAll(completionTasks).GetAwaiter().GetResult();
            }

            var logFile = (MemoryFileInfo)fileProvider.GetFileInfo($@"{LogsDirName}\test-{context.GetTimestamp().ToLocalTime():yyyyMMdd}-000.log");

            Assert.True(logFile.Exists && !logFile.IsDirectory);

            var lines = logFile.Content.Split(new[] { Environment.NewLine }, StringSplitOptions.None);

            Assert.Equal(Encoding.UTF8, logFile.Encoding);
            Assert.Equal(new[]
            {
                $"[info]: {typeof(LoggingTest).FullName}[0] @ {context.GetTimestamp().ToLocalTime():o}",
                $"        This is a nice logger.",
                ""
            }, lines);

            logFile = (MemoryFileInfo)fileProvider.GetFileInfo($@"{LogsDirName}\test-{context.GetTimestamp().ToLocalTime():yyyyMMdd}-001.log");
            Assert.True(logFile.Exists && !logFile.IsDirectory);

            lines = logFile.Content.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
            Assert.Equal(Encoding.UTF8, logFile.Encoding);
            Assert.Equal(new[]
            {
                $"[warn]: {typeof(LoggingTest).FullName}[1] @ {context.GetTimestamp().ToLocalTime():o}",
                $"        => SCOPE",
                $"        This is a smart logger.",
                ""
            }, lines);

            logFile = (MemoryFileInfo)fileProvider.GetFileInfo(
                $@"{LogsDirName}\{Path.ChangeExtension(FallbackFileName, null)}-{context.GetTimestamp().ToLocalTime():yyyyMMdd}-000{Path.GetExtension(FallbackFileName)}");
            Assert.True(logFile.Exists && !logFile.IsDirectory);

            lines = logFile.Content.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
            Assert.Equal(Encoding.UTF8, logFile.Encoding);
            Assert.Equal(new[]
            {
                $"[fail]: X[0] @ {context.GetTimestamp().ToLocalTime():o}",
                $"        => SCOPE => NESTED SCOPE",
                $"        Some failure!",
            }
                         .Concat(ex.ToString().Split(new[] { Environment.NewLine }, StringSplitOptions.None))
                         .Append(""), lines);
        }
        public void LoggingToPhysicalUsingProvider()
        {
            var configData = new Dictionary <string, string>
            {
                [$"{nameof(FileLoggerOptions.BasePath)}"]         = LogsDirName,
                [$"{nameof(FileLoggerOptions.EnsureBasePath)}"]   = "true",
                [$"{nameof(FileLoggerOptions.FileEncodingName)}"] = "UTF-16",
                [$"{nameof(FileLoggerOptions.MaxQueueSize)}"]     = "100",
                [$"{nameof(FileLoggerOptions.DateFormat)}"]       = "yyyyMMdd",
                [$"{ConfigurationFileLoggerSettings.LogLevelSectionName}:{FileLoggerSettingsBase.DefaultCategoryName}"] = "Information",
                [$"{nameof(FileLoggerOptions.FileNameMappings)}:Karambolo.Extensions.Logging.File.Test"] = "test.log",
                [$"{nameof(FileLoggerOptions.FileNameMappings)}:Karambolo.Extensions.Logging.File"]      = "logger.log",
            };

            var cb = new ConfigurationBuilder();

            cb.AddInMemoryCollection(configData);
            IConfigurationRoot config = cb.Build();

            var cts = new CancellationTokenSource();

            var tempPath = Path.GetTempPath();
            var logPath  = Path.Combine(tempPath, LogsDirName);

            var context = new TestFileLoggerContext(new PhysicalFileProvider(tempPath), "fallback.log", cts.Token);

            var completionTasks = new List <Task>();

            context.Complete += (s, e) => completionTasks.Add(e);

            context.SetTimestamp(new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Utc));

            var services = new ServiceCollection();

            services.AddOptions();
            services.AddLogging(b => b.AddFile(context));
            services.Configure <FileLoggerOptions>(config);

            if (Directory.Exists(logPath))
            {
                Directory.Delete(logPath, recursive: true);
            }

            try
            {
                var             ex = new Exception();
                ServiceProvider serviceProvider = services.BuildServiceProvider();

                ILogger <LoggingTest> logger1 = serviceProvider.GetService <ILogger <LoggingTest> >();

                logger1.LogInformation("This is a nice logger.");
                using (logger1.BeginScope("SCOPE"))
                {
                    logger1.LogWarning(1, "This is a smart logger.");
                    logger1.LogTrace("This won't make it.");

                    using (logger1.BeginScope("NESTED SCOPE"))
                    {
                        ILoggerFactory loggerFactory = serviceProvider.GetService <ILoggerFactory>();
                        ILogger        logger2       = loggerFactory.CreateLogger("X");
                        logger2.LogError(0, ex, "Some failure!");
                    }
                }

                // ensuring that all entries are processed
                cts.Cancel();
                Assert.Single(completionTasks);
                Task.WhenAll(completionTasks).GetAwaiter().GetResult();

#pragma warning disable CS0618 // Type or member is obsolete
                IFileInfo logFile = context.FileProvider.GetFileInfo($@"{LogsDirName}\test-{context.GetTimestamp().ToLocalTime():yyyyMMdd}.log");
#pragma warning restore CS0618 // Type or member is obsolete
                Assert.True(logFile.Exists && !logFile.IsDirectory);

                var lines = ReadContent(logFile, out Encoding encoding).Split(new[] { Environment.NewLine }, StringSplitOptions.None);
                Assert.Equal(Encoding.Unicode, encoding);
                Assert.Equal(new[]
                {
                    $"info: {typeof(LoggingTest).FullName}[0] @ {context.GetTimestamp().ToLocalTime():o}",
                    $"      This is a nice logger.",
                    $"warn: {typeof(LoggingTest).FullName}[1] @ {context.GetTimestamp().ToLocalTime():o}",
                    $"      This is a smart logger.",
                    ""
                }, lines);

#pragma warning disable CS0618 // Type or member is obsolete
                logFile = context.FileProvider.GetFileInfo(
                    $@"{LogsDirName}\{Path.ChangeExtension(context.FallbackFileName, null)}-{context.GetTimestamp().ToLocalTime():yyyyMMdd}{Path.GetExtension(context.FallbackFileName)}");
#pragma warning restore CS0618 // Type or member is obsolete
                Assert.True(logFile.Exists && !logFile.IsDirectory);

                lines = ReadContent(logFile, out encoding).Split(new[] { Environment.NewLine }, StringSplitOptions.None);
                Assert.Equal(Encoding.Unicode, encoding);
                Assert.Equal(new[]
                {
                    $"fail: X[0] @ {context.GetTimestamp().ToLocalTime():o}",
                    $"      Some failure!",
                }
                             .Concat(ex.ToString().Split(new[] { Environment.NewLine }, StringSplitOptions.None))
                             .Append(""), lines);
            }
            finally
            {
                Directory.Delete(logPath, recursive: true);
            }

            string ReadContent(IFileInfo fileInfo, out Encoding encoding)
            {
                using (Stream stream = fileInfo.CreateReadStream())
                    using (var reader = new StreamReader(stream))
                    {
                        var result = reader.ReadToEnd();
                        encoding = reader.CurrentEncoding;
                        return(result);
                    }
            }
        }
Beispiel #8
0
        public void FailingEntryDontGetStuck()
        {
            var tempPath = Path.GetTempPath();
            var logPath  = Path.Combine(tempPath, LogsDirName);

            if (Directory.Exists(logPath))
            {
                Directory.Delete(logPath, recursive: true);
            }
            Directory.CreateDirectory(logPath);
            try
            {
                var context = new TestFileLoggerContext(new PhysicalFileProvider(tempPath), "fallback.log");

                context.SetWriteRetryDelay(TimeSpan.FromMilliseconds(250));
                context.SetCompletionTimeout(TimeSpan.FromMilliseconds(2000));

                var completionTasks = new List <Task>();
                context.Complete += (s, e) => completionTasks.Add(e);

                var cts      = new CancellationTokenSource();
                var settings = new FileLoggerSettings
                {
                    BasePath         = LogsDirName,
                    FileNameMappings = new Dictionary <string, string>
                    {
                        { "Default", "default.log" }
                    },
                    Switches = new Dictionary <string, LogLevel>
                    {
                        { FileLoggerSettingsBase.DefaultCategoryName, LogLevel.Information }
                    },
                    ChangeToken = new CancellationChangeToken(cts.Token)
                };

                var filePath = Path.Combine(logPath, "default.log");
                using (var loggerProvider = new FileLoggerProvider(context, settings))
                {
                    ILogger logger = loggerProvider.CreateLogger("X");

                    logger.LogInformation("This should get through.");

                    var newCts = new CancellationTokenSource();
                    settings.ChangeToken = new CancellationChangeToken(newCts.Token);
                    cts.Cancel();
                    cts = newCts;
                    Assert.Single(completionTasks);
                    Task.WhenAll(completionTasks).GetAwaiter().GetResult();

                    using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        logger.LogInformation("This shouldn't get through.");

                        cts.Cancel();
                        Assert.Equal(2, completionTasks.Count);

                        var delayTask = Task.Delay(5000);
                        Assert.Equal(completionTasks[1], Task.WhenAny(completionTasks[1], delayTask).GetAwaiter().GetResult());
                        Assert.Equal(TaskStatus.RanToCompletion, completionTasks[1].Status);
                    }
                }

                var lines = System.IO.File.ReadAllLines(filePath);
                Assert.Equal(lines, new[]
                {
                    $"info: X[0] @ {context.GetTimestamp().ToLocalTime():o}",
                    $"      This should get through.",
                });
            }
            finally
            {
                Directory.Delete(logPath, recursive: true);
            }
        }
Beispiel #9
0
        public void ReloadOptionsSettings()
        {
            var configJson =
                $@"{{ 
    '{nameof(ConfigurationFileLoggerSettings.IncludeScopes)}' : true,
    '{ConfigurationFileLoggerSettings.LogLevelSectionName}': {{
        '{FileLoggerSettingsBase.DefaultCategoryName}': '{LogLevel.Trace}',
    }}
}}";

            var fileProvider = new MemoryFileProvider();

            fileProvider.CreateFile("config.json", configJson, Encoding.UTF8);

            var cb = new ConfigurationBuilder();

            cb.AddJsonFile(fileProvider, "config.json", optional: false, reloadOnChange: true);
            var config = cb.Build();

            var settings = new ConfigurationFileLoggerSettings(config);

            var cts     = new CancellationTokenSource();
            var context = new TestFileLoggerContext(cts.Token);

            var completionTasks = new List <Task>();

            context.Complete += (s, e) => completionTasks.Add(e);

            context.SetTimestamp(new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Utc));

            var services = new ServiceCollection();

            services.AddOptions();
            services.AddLogging(b => b.AddFile(context));
            services.Configure <FileLoggerOptions>(config);

            using (var serviceProvider = services.BuildServiceProvider())
            {
                var loggerFactory = serviceProvider.GetService <ILoggerFactory>();
                var logger1       = loggerFactory.CreateLogger <LoggingTest>();

                using (logger1.BeginScope("SCOPE"))
                {
                    logger1.LogInformation("This is a nice logger.");

                    using (logger1.BeginScope("NESTED SCOPE"))
                    {
                        logger1.LogInformation("This is a smart logger.");

                        // changing switch and scopes inclusion
                        configJson =
                            $@"{{
    '{ConfigurationFileLoggerSettings.LogLevelSectionName}': {{
        '{FileLoggerSettingsBase.DefaultCategoryName}': '{LogLevel.Information}',
    }}
}}";
                        fileProvider.WriteContent("config.json", configJson);

                        Assert.Equal(1, completionTasks.Count);
                        Task.WhenAll(completionTasks).GetAwaiter().GetResult();

                        logger1 = loggerFactory.CreateLogger <LoggingTest>();

                        logger1.LogInformation("This one shouldn't include scopes.");
                        logger1.LogTrace("This one shouldn't be included at all.");
                    }
                }

                // ensuring that the entry is processed
                completionTasks.Clear();
                cts.Cancel();
                Assert.Equal(1, completionTasks.Count);
                Task.WhenAll(completionTasks).GetAwaiter().GetResult();
            }

            var logFile = (MemoryFileInfo)context.FileProvider.GetFileInfo($@"fallback.log");

            Assert.True(logFile.Exists && !logFile.IsDirectory);

            var lines = logFile.Content.Split(new[] { Environment.NewLine }, StringSplitOptions.None);

            Assert.Equal(Encoding.UTF8, logFile.Encoding);
            Assert.Equal(lines, new[]
            {
                $"info: {typeof(LoggingTest).FullName}[0] @ {context.GetTimestamp().ToLocalTime():o}",
                $"      => SCOPE",
                $"      This is a nice logger.",
                $"info: {typeof(LoggingTest).FullName}[0] @ {context.GetTimestamp().ToLocalTime():o}",
                $"      => SCOPE => NESTED SCOPE",
                $"      This is a smart logger.",
                $"info: {typeof(LoggingTest).FullName}[0] @ {context.GetTimestamp().ToLocalTime():o}",
                $"      This one shouldn't include scopes.",
                ""
            });
        }
Beispiel #10
0
        public void ReloadConfigurationSettings()
        {
            var configJson =
                $@"{{ 
    '{nameof(ConfigurationFileLoggerSettings.MaxFileSize)}' : 10000,
    '{ConfigurationFileLoggerSettings.LogLevelSectionName}': {{
        '{FileLoggerSettingsBase.DefaultCategoryName}': '{LogLevel.Information}',
    }}
}}";

            var fileProvider = new MemoryFileProvider();

            fileProvider.CreateFile("config.json", configJson, Encoding.UTF8);

            var cb = new ConfigurationBuilder();

            cb.AddJsonFile(fileProvider, "config.json", optional: false, reloadOnChange: true);
            var config = cb.Build();

            var settings = new ConfigurationFileLoggerSettings(config);

            var cts     = new CancellationTokenSource();
            var context = new TestFileLoggerContext(cts.Token);

            var completionTasks = new List <Task>();

            context.Complete += (s, e) => completionTasks.Add(e);

            context.SetTimestamp(new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Utc));

            using (var loggerFactory = new LoggerFactory())
            {
                loggerFactory.AddFile(context, settings);
                var logger1 = loggerFactory.CreateLogger <LoggingTest>();

                logger1.LogInformation("This is a nice logger.");

                // changing date format, counter format and max file size
                configJson =
                    $@"{{
    '{nameof(ConfigurationFileLoggerSettings.DateFormat)}' : 'yyyyMMdd',
    '{nameof(ConfigurationFileLoggerSettings.MaxFileSize)}' : 1,
    '{nameof(ConfigurationFileLoggerSettings.CounterFormat)}' : '00',
    '{ConfigurationFileLoggerSettings.LogLevelSectionName}': {{
        '{FileLoggerSettingsBase.DefaultCategoryName}': '{LogLevel.Information}',
    }}
}}";
                fileProvider.WriteContent("config.json", configJson);

                Assert.Equal(1, completionTasks.Count);
                Task.WhenAll(completionTasks).GetAwaiter().GetResult();

                logger1.LogInformation("This is a smart logger.");

                // ensuring that the entry is processed
                completionTasks.Clear();
                cts.Cancel();
                Assert.Equal(1, completionTasks.Count);
                Task.WhenAll(completionTasks).GetAwaiter().GetResult();
            }

            var logFile = (MemoryFileInfo)context.FileProvider.GetFileInfo($@"fallback-0.log");

            Assert.True(logFile.Exists && !logFile.IsDirectory);

            var lines = logFile.Content.Split(new[] { Environment.NewLine }, StringSplitOptions.None);

            Assert.Equal(Encoding.UTF8, logFile.Encoding);
            Assert.Equal(lines, new[]
            {
                $"info: {typeof(LoggingTest).FullName}[0] @ {context.GetTimestamp().ToLocalTime():o}",
                $"      This is a nice logger.",
                ""
            });

            logFile = (MemoryFileInfo)context.FileProvider.GetFileInfo($@"fallback-{context.GetTimestamp().ToLocalTime():yyyyMMdd}-00.log");
            Assert.True(logFile.Exists && !logFile.IsDirectory);

            lines = logFile.Content.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
            Assert.Equal(Encoding.UTF8, logFile.Encoding);
            Assert.Equal(lines, new[]
            {
                $"info: {typeof(LoggingTest).FullName}[0] @ {context.GetTimestamp().ToLocalTime():o}",
                $"      This is a smart logger.",
                ""
            });
        }
Beispiel #11
0
        public void ReloadSettings()
        {
            var cts = new CancellationTokenSource();

            var settings = new FileLoggerSettings
            {
                Switches = new Dictionary <string, LogLevel>
                {
                    { FileLoggerSettingsBase.DefaultCategoryName, LogLevel.Information }
                },
                ChangeToken = new CancellationChangeToken(cts.Token)
            };

            var context = new TestFileLoggerContext(CancellationToken.None);

            var completionTasks = new List <Task>();

            context.Complete += (s, e) => completionTasks.Add(e);

            context.SetTimestamp(new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Utc));

            using (var loggerFactory = new LoggerFactory())
            {
                loggerFactory.AddFile(context, settings);
                var logger1 = loggerFactory.CreateLogger <LoggingTest>();

                logger1.LogInformation("This is a nice logger.");

                // changing text format
                settings.TextBuilder = new CustomLogEntryTextBuilder();

                var newCts = new CancellationTokenSource();
                settings.ChangeToken = new CancellationChangeToken(newCts.Token);
                cts.Cancel();
                cts = newCts;
                Assert.Equal(1, completionTasks.Count);
                Task.WhenAll(completionTasks).GetAwaiter().GetResult();

                logger1.LogInformation("This is a smart logger.");

                // changing base path, file encoding and filename mapping
                settings.BasePath         = "Logs";
                settings.EnsureBasePath   = true;
                settings.FileEncoding     = Encoding.Unicode;
                settings.FileNameMappings = new Dictionary <string, string>
                {
                    { typeof(LoggingTest).FullName, "test.log" }
                };

                completionTasks.Clear();
                newCts = new CancellationTokenSource();
                settings.ChangeToken = new CancellationChangeToken(newCts.Token);
                cts.Cancel();
                cts = newCts;
                Assert.Equal(1, completionTasks.Count);
                Task.WhenAll(completionTasks).GetAwaiter().GetResult();

                logger1.LogWarning("This goes to another file.");

                // ensuring that the entry is processed
                completionTasks.Clear();
                cts.Cancel();
                Assert.Equal(1, completionTasks.Count);
                Task.WhenAll(completionTasks).GetAwaiter().GetResult();
            }

            var logFile = (MemoryFileInfo)context.FileProvider.GetFileInfo($@"fallback.log");

            Assert.True(logFile.Exists && !logFile.IsDirectory);

            var lines = logFile.Content.Split(new[] { Environment.NewLine }, StringSplitOptions.None);

            Assert.Equal(Encoding.UTF8, logFile.Encoding);
            Assert.Equal(lines, new[]
            {
                $"info: {typeof(LoggingTest).FullName}[0] @ {context.GetTimestamp().ToLocalTime():o}",
                $"      This is a nice logger.",
                $"[info]: {typeof(LoggingTest).FullName}[0] @ {context.GetTimestamp().ToLocalTime():o}",
                $"        This is a smart logger.",
                ""
            });

            logFile = (MemoryFileInfo)context.FileProvider.GetFileInfo($@"Logs\test.log");
            Assert.True(logFile.Exists && !logFile.IsDirectory);

            lines = logFile.Content.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
            Assert.Equal(Encoding.Unicode, logFile.Encoding);
            Assert.Equal(lines, new[]
            {
                $"[warn]: {typeof(LoggingTest).FullName}[0] @ {context.GetTimestamp().ToLocalTime():o}",
                $"        This goes to another file.",
                ""
            });
        }
        public async Task LoggingToPhysicalUsingDIAndExpectingDiagnosticEvents()
        {
            var logsDirName = Guid.NewGuid().ToString("D");

            var tempPath = Path.Combine(Path.GetTempPath());
            var logPath  = Path.Combine(tempPath, logsDirName);

            var fileProvider = new PhysicalFileProvider(tempPath);

            var cts     = new CancellationTokenSource();
            var context = new TestFileLoggerContext(cts.Token, completionTimeout: Timeout.InfiniteTimeSpan);

            context.SetTimestamp(new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Utc));

            var diagnosticEvents = new List <IFileLoggerDiagnosticEvent>();

            context.DiagnosticEvent += diagnosticEvents.Add;

            var services = new ServiceCollection();

            services.AddOptions();
            services.AddLogging(b => b.AddFile(context, o =>
            {
                o.FileAppender   = new PhysicalFileAppender(fileProvider);
                o.BasePath       = logsDirName;
                o.FileAccessMode = LogFileAccessMode.KeepOpen;
                o.Files          = new[]
                {
                    new LogFileOptions
                    {
                        Path = "<invalid_filename>.log"
                    }
                };
            }));

            if (Directory.Exists(logPath))
            {
                Directory.Delete(logPath, recursive: true);
            }

            try
            {
                FileLoggerProvider[] providers;

                using (ServiceProvider sp = services.BuildServiceProvider())
                {
                    providers = context.GetProviders(sp).ToArray();
                    Assert.Equal(1, providers.Length);

                    ILogger <LoggingTest> logger1 = sp.GetService <ILogger <LoggingTest> >();

                    logger1.LogInformation("This is a nice logger.");
                    logger1.LogWarning(1, "This is a smart logger.");

                    cts.Cancel();

                    // ensuring that all entries are processed
                    await context.GetCompletion(sp);

                    Assert.True(providers.All(provider => provider.Completion.IsCompleted));
                }

                Assert.NotEmpty(diagnosticEvents);
                Assert.All(diagnosticEvents, e =>
                {
                    Assert.IsType <FileLoggerDiagnosticEvent.LogEntryWriteFailed>(e);
                    Assert.IsType <FileLoggerProcessor>(e.Source);
                    Assert.NotNull(e.FormattableMessage);
                    Assert.NotNull(e.Exception);
                });
            }
            finally
            {
                if (Directory.Exists(logPath))
                {
                    Directory.Delete(logPath, recursive: true);
                }
            }
        }
        public void ReloadOptionsSettingsMultipleProviders()
        {
            var fileProvider = new MemoryFileProvider();
            var fileAppender = new MemoryFileAppender(fileProvider);

            dynamic settings      = new JObject();
            dynamic globalFilters = settings[ConfigurationFileLoggerSettings.LogLevelSectionName] = new JObject();

            globalFilters[FileLoggerSettingsBase.DefaultCategoryName] = LogLevel.None.ToString();

            settings[FileLoggerProvider.Alias] = new JObject();
            dynamic fileFilters = settings[FileLoggerProvider.Alias][ConfigurationFileLoggerSettings.LogLevelSectionName] = new JObject();

            fileFilters[FileLoggerSettingsBase.DefaultCategoryName] = LogLevel.Warning.ToString();

            settings[OtherFileLoggerProvider.Alias] = new JObject();
            settings[OtherFileLoggerProvider.Alias][nameof(FileLoggerOptions.FallbackFileName)] = "fallback.log";
            dynamic otherFileFilters = settings[OtherFileLoggerProvider.Alias][ConfigurationFileLoggerSettings.LogLevelSectionName] = new JObject();

            otherFileFilters[FileLoggerSettingsBase.DefaultCategoryName] = LogLevel.Information.ToString();
            var settingsJson = ((JObject)settings).ToString();

            fileProvider.CreateFile("config.json", settingsJson);

            IConfigurationRoot config = new ConfigurationBuilder()
                                        .AddJsonFile(fileProvider, "config.json", optional: false, reloadOnChange: true)
                                        .Build();

            var context = new TestFileLoggerContext();

            var completionTasks = new List <Task>();

            context.Complete += (s, e) => completionTasks.Add(e);

            var services = new ServiceCollection();

            services.AddOptions();
            services.AddLogging(lb =>
            {
                lb.AddConfiguration(config);
                lb.AddFile(context, o => o.FileAppender = o.FileAppender ?? fileAppender);
                lb.AddFile <OtherFileLoggerProvider>(context, o => o.FileAppender = o.FileAppender ?? fileAppender);
            });

            using (ServiceProvider sp = services.BuildServiceProvider())
            {
                ILoggerFactory loggerFactory = sp.GetRequiredService <ILoggerFactory>();

                ILogger logger = loggerFactory.CreateLogger("X");

                logger.LogInformation("This is an info.");
                logger.LogWarning("This is a warning.");

                fileFilters[FileLoggerSettingsBase.DefaultCategoryName]      = LogLevel.Information.ToString();
                otherFileFilters[FileLoggerSettingsBase.DefaultCategoryName] = LogLevel.Warning.ToString();
                settingsJson = ((JObject)settings).ToString();
                fileProvider.WriteContent("config.json", settingsJson);

                // reload is triggered twice due to a bug in the framework (https://github.com/aspnet/Logging/issues/874)
                Assert.Equal(2 * 2, completionTasks.Count);
                Task.WhenAll(completionTasks).GetAwaiter().GetResult();

                logger.LogInformation("This is another info.");
                logger.LogWarning("This is another warning.");
            }

            var logFile = (MemoryFileInfo)fileProvider.GetFileInfo(LoggingTest.FallbackFileName);

            Assert.True(logFile.Exists && !logFile.IsDirectory);

            var lines = logFile.Content.Split(new[] { Environment.NewLine }, StringSplitOptions.None);

            Assert.Equal(Encoding.UTF8, logFile.Encoding);
            Assert.Equal(new[]
            {
                $"warn: X[0] @ {context.GetTimestamp().ToLocalTime():o}",
                $"      This is a warning.",
                $"info: X[0] @ {context.GetTimestamp().ToLocalTime():o}",
                $"      This is another info.",
                $"warn: X[0] @ {context.GetTimestamp().ToLocalTime():o}",
                $"      This is another warning.",
                ""
            }, lines);

            logFile = (MemoryFileInfo)fileProvider.GetFileInfo((string)settings[OtherFileLoggerProvider.Alias].FallbackFileName);
            Assert.True(logFile.Exists && !logFile.IsDirectory);

            lines = logFile.Content.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
            Assert.Equal(Encoding.UTF8, logFile.Encoding);
            Assert.Equal(new[]
            {
                $"info: X[0] @ {context.GetTimestamp().ToLocalTime():o}",
                $"      This is an info.",
                $"warn: X[0] @ {context.GetTimestamp().ToLocalTime():o}",
                $"      This is a warning.",
                $"warn: X[0] @ {context.GetTimestamp().ToLocalTime():o}",
                $"      This is another warning.",
                ""
            }, lines);
        }