-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Can you use filelogger with XML configuration? #8
Comments
I discovered that the exception was caused by disposing of the ServiceProvider too soon. Console logger didn't mind that but filelogger did. Now filelogger just fails silently, but debug window repeatedly shows using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.IO;
using System.Windows.Forms;
using WFAppLogger.Properties;
namespace WFAppLogger
{
internal class Program
{
// Global Service Provider for dependency injection
static ServiceProvider serviceProvider;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// FYI: the roaming configuration that applies to the current user is at
// %LOCALAPPDATA%\\<Company Name>\<appdomainname>_<eid>_<hash>\<version>\user.config
//string userConfig = System.Configuration.ConfigurationManager.OpenExeConfiguration(
// System.Configuration.ConfigurationUserLevel.PerUserRoamingAndLocal).FilePath;
// If no user.config file exists, then the application.exe.config file is used
//string appConfig = System.Configuration.ConfigurationManager.OpenExeConfiguration(
// System.Configuration.ConfigurationUserLevel.None).FilePath;
// Get logging configuration from settings in app.config (or user.config)
var loggingConfig = Settings.Default.LoggingConfig;
var stream = new MemoryStream();
loggingConfig.Save(stream);
stream.Position = 0;
var configuration = new ConfigurationBuilder()
.AddXmlStream(stream)
.Build();
var config = configuration.GetSection("Logging");
// Initialize application logging via dependency injection
var services = new ServiceCollection();
services.AddLogging(builder =>
{
builder.AddConfiguration(config);
builder.AddConsole();
// Utilize Karambolo.Extensions.Logging.File from https://github.com/adams85/filelogger
builder.AddFile(o => o.RootPath = AppContext.BaseDirectory);
});
serviceProvider = services.BuildServiceProvider();
// Create logger for Program class and log that we're starting up
var logger = CreateLogger<Program>();
logger.LogTrace("This is a trace message.");
logger.LogDebug("This is a debug message.");
logger.LogInformation("This is an info message.");
logger.LogWarning("This is a warning message.");
logger.LogError("This is an error message.");
logger.LogCritical("This is a critical message.");
logger.LogInformation($"Starting {Application.ProductName}...");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// Run the application
Application.Run(new Form1(CreateLogger<Form1>()));
// Log that we're exiting
logger.LogInformation($"Exiting {Application.ProductName}.");
}
/// <summary>
/// Creates a new Microsoft.Extensions.Logging.ILogger instance using the full name of the given type
/// </summary>
/// <typeparam name="T">The class type to create a logger for</typeparam>
/// <returns>The Microsoft.Extensions.Logging.ILogger that was created</returns>
public static ILogger<T> CreateLogger<T>()
{
// Create and return Logger instance for the given type using global dependency injection for logger factory
return serviceProvider.GetRequiredService<ILoggerFactory>().CreateLogger<T>();
}
}
} |
After a LOT of debugging and trial & error, I got filelogger working with an XML configuration. Many of the problems could have been located/resolved quicker if there was some validation on the configuration parameters. The working simple test project is at WFAppLogger, with the main code snippets below. Note that I also set Program.cs: using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.IO;
using System.Windows.Forms;
using WFAppLogger.Properties;
namespace WFAppLogger
{
internal class Program
{
// Global Service Provider for dependency injection
static ServiceProvider serviceProvider;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// FYI: the roaming configuration that applies to the current user is at
// %LOCALAPPDATA%\\<Company Name>\<appdomainname>_<eid>_<hash>\<version>\user.config
//string userConfig = System.Configuration.ConfigurationManager.OpenExeConfiguration(
// System.Configuration.ConfigurationUserLevel.PerUserRoamingAndLocal).FilePath;
// If no user.config file exists, then the application.exe.config file is used
//string appConfig = System.Configuration.ConfigurationManager.OpenExeConfiguration(
// System.Configuration.ConfigurationUserLevel.None).FilePath;
// Get logging configuration from settings in app.config (or user.config)
var loggingConfig = Settings.Default.LoggingConfig;
var stream = new MemoryStream();
loggingConfig.Save(stream);
stream.Position = 0;
var configuration = new ConfigurationBuilder()
.AddXmlStream(stream)
.Build();
var config = configuration.GetSection("Logging");
// Initialize application logging via dependency injection
var services = new ServiceCollection();
services.AddLogging(builder =>
{
builder.AddConfiguration(config);
builder.AddConsole();
// Utilize Karambolo.Extensions.Logging.File from https://github.com/adams85/filelogger
builder.AddFile<CustomFileLoggerProvider>(configure: o => o.RootPath = Path.GetTempPath());
});
serviceProvider = services.BuildServiceProvider();
// Create logger for Program class and log that we're starting up
var logger = CreateLogger<Program>();
logger.LogInformation($"Starting {Application.ProductName}...");
logger.LogTrace("This is a trace message.");
logger.LogDebug("This is a debug message.");
logger.LogInformation("This is an info message.");
logger.LogWarning("This is a warning message.");
logger.LogError("This is an error message.");
logger.LogCritical("This is a critical message.");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// Run the application
Application.Run(new Form1(CreateLogger<Form1>()));
// Log that we're exiting
logger.LogInformation($"Exiting {Application.ProductName}.");
}
/// <summary>
/// Creates a new Microsoft.Extensions.Logging.ILogger instance using the full name of the given type
/// </summary>
/// <typeparam name="T">The class type to create a logger for</typeparam>
/// <returns>The Microsoft.Extensions.Logging.ILogger that was created</returns>
public static ILogger<T> CreateLogger<T>()
{
// Create and return Logger instance for the given type using global dependency injection for logger factory
return serviceProvider.GetRequiredService<ILoggerFactory>().CreateLogger<T>();
}
}
} Snippet from App.config: <?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="WFAppLogger.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
<!-- some sections omitted for brevity ... !-->
<userSettings>
<WFAppLogger.Properties.Settings>
<setting name="DefaultLogMessage" serializeAs="String">
<value>Sample log message</value>
</setting>
<setting name="LoggingConfig" serializeAs="Xml">
<value>
<Root>
<Logging>
<LogLevel>
<Default>Debug</Default>
<WFAppLogger>Trace</WFAppLogger>
<Microsoft>Warning</Microsoft>
<System>Warning</System>
</LogLevel>
<Console>
<IncludeScopes>true</IncludeScopes>
</Console>
<File>
<IncludeScopes>true</IncludeScopes>
<!-- Log files will be written to %TEMP%[\%BasePath%]\<appname>-<date>-<counter>.log -->
<!--<BasePath>Logs</BasePath>-->
<Files>
<File>
<Path><appname>-<date>-<counter:000>.log</Path>
<MaxFileSize>100000</MaxFileSize>
</File>
</Files>
</File>
</Logging>
</Root>
</value>
</setting>
</WFAppLogger.Properties.Settings>
</userSettings>
</configuration> |
Hi! Sorry, I just got to review your issue. Disposing the service provider too early is definitely a problem at your end because the SP disposes the services resolved by it (including the file logger). I recommend this pattern: // Initialize application logging via dependency injection
services = new ServiceCollection();
services.AddLogging(builder =>
{
builder.AddConfiguration(config);
builder.AddConsole();
builder.AddFile(o => o.RootPath = AppContext.BaseDirectory);
});
using (var sp = services.BuildServiceProvider())
{
var loggerFactory = sp.GetRequiredService<ILoggerFactory>();
// Create logger for Program class and log that we're starting up
var logger = loggerFactory.CreateLogger<Program>();
logger.LogInformation($"Starting {Application.ProductName}...");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// Run the application
Application.Run(new Form1(loggerFactory.CreateLogger<Form1>()));
// Log that we're exiting
logger.LogInformation($"Exiting {Application.ProductName}.");
} The other problem is a bit more tricky. When the logger fails to write an entry due to some file system error it keeps retrying until success. (This is the reason behind the repeated exception you got.) The |
Thank you for sharing your file logger.
I would like to use this in a WinForm app. My business layer uses EF Core, so I have been using Microsoft.Extension.Logging.Console in development and wanted to add file logging.
WinForm apps use the XML-based App.config file instead of appsetting.json, so I was looking to include the logging configuration in App.config.
Configurable settings are normally defined in the VS-generated .Properties.Settings class. I defined an XML node for the logging parameters and loaded them via ConfigurationBuilder().AddXmlStream(stream).Build(). Console logging works OK using those settings, but filelogger raises exceptions when I call CreateLogger().
Do you have any examples or guidance for using XML configuration, particularly within App.config?
Below are some snippets for context, but the simple test project is at WFAppLogger if you want to reproduce the exception.
Program.cs:
Snippet from App.config
The text was updated successfully, but these errors were encountered: