I want to be able to configure the nested levels like Microsoft.AspNetCore.Mvc/DataProtection independently of just Microsoft.*, is this possible, if so how do I do it?
The logging works and I see currently see everything at debug but nothing is excluded.
I'm injecting the settings etc into a class which is configured in Program.cs like this
var builder = new ConfigurationBuilder().SetBasePath(Environment.CurrentDirectory);
builder.AddJsonFile("appsettings.json", true, true);
var envName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
if (string.IsNullOrWhiteSpace(envName))
builder.AddJsonFile($"appsettings.${envName}.json", true);
builder.AddEnvironmentVariables();
builder.AddCommandLine(args);
var configurationRoot = builder.Build();
new WebHostBuilder()
.UseKestrel(options =>
{ options.Limits.MaxRequestBodySize = null; })
.UseContentRoot(Directory.GetCurrentDirectory())
.UseConfiguration(configurationRoot)
.ConfigureLogging(lb =>
{
lb.AddConsole();
lb.AddDebug();
lb.SetMinimumLevel(LogLevel.Trace);
})
.UseStartup<Startup>()
.UseIISIntegration()
.Build()
.Run();
with Startup.cs injecting the logger and config like
public Startup(ILogger<Startup> iLogger, IConfiguration iConfiguration)
{
_configuration = iConfiguration;
_logger = iLogger;
_logger.LogDebug("Configured logger, config and builder.");
}
with logging config in appsettings.json like
"Logging": {
"IncludeScopes": true,
"LogLevel": {
"Microsoft.AspNetCore.Mvc": "Warning",
"Microsoft.AspNetCore.DataProtection": "Warning",
"Default": "Debug"
}
}
Coming from log4j I'd attempt something like the above but it's not working, where have I gone wrong?
You need to read the how to setup a host page to understand what needs to go into the program.cs code. This has changed for .Net Core 2.x and has reduced the amount of code we need to load the settings and setup logging.
Related
Despite hours spent on google, I am not getting there. We have a Core 3.1 MVC Web App project, and I've been asked to use SeriLog to write logs to Azure Table Storage. For the life of me, I can't find a working example or tutorial online. Here's what I've done so far:
Added the following NuGet's:
Serilog
Serilog.Extensions.Logging
Serilog.Sinks.AzureTableStorage
In appsettings.json,I replaced this:
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Information",
"Microsoft.Hosting.Lifetime": "Warning"
}
With this:
"Serilog": {
"WriteTo": [
{
"Name": "AzureTableStorage",
"Args": {
"storageTableName": "Logs",
"connectionString": "DefaultEndpointsProtocol=https;AccountName=***;AccountKey=***;EndpointSuffix=core.windows.net"
}
}
]
},
And now I am stuck. This is currently in Program.cs in CreateHostBuilder :
.ConfigureLogging(logging =>
{
logging.AddConsole();
})
I assume I should replace this? But, with what? I am not sure where to go from here. The serilog-sinks-azuretablestorage page on Github isn't much help. And I've been unable to find anything via Google that explains how to finish the implementation.
Well, I didn't get any bites on this. But after reading about 5 different articles, I managed to figure it out. In Program.cs, this was there by default:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
logging.AddConsole();
})
And I replaced it with this:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging((hostingContext, logging) =>
{
var logger = new LoggerConfiguration()
.ReadFrom.Configuration(hostingContext.Configuration)
.CreateLogger();
logging.AddSerilog(logger);
})
hostingContext is an instance of HostBuilderContext and it contains '.Configuration' which is an instance of IConfiguration. So hostingContext.Configuration contains all your settings in appsetting.json.
In addition to the NuGet packages I mentioned in the OP, I also had to add this one:
Serilog.Settings.Configuration
(It's amazing how sometimes it can take 7 or 8 hours to write 4 lines of code.)
Add Serilog.Settings.Configuration and Microsoft.Extensions.Logging nuget package to your project it helps to read serilog configuration settings from appsettings.json and ensure you have below Serilog config in your Sartup.cs file.
public Startup(IConfiguration configuration)
{
Configuration = configuration;
//logger config
var logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
logger.Information("Logging configured");
Log.Logger = logger;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.AddLogging(loggingBuilder =>
{
loggingBuilder.AddConfiguration(Configuration.GetSection("Logging"));
loggingBuilder.AddConsole();
loggingBuilder.AddDebug();
//Add Serilog config to logbuilder
loggingBuilder.AddSerilog(Log.Logger);
});
}
//Add this config in appsettings.json
"Serilog": {
"Using": [ "Serilog.Sinks.AzureTableStorage" ],
"WriteTo": [
{
"Name": "AzureTableStorage",
"Args": {
"storageTableName": "MyAppLogs
"connectionString": ""
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ],
"Properties": {
"Application": MyApp
}
},
I'm trying to work out what I'm missing in this snippet of code. I'm creating an Azure WebJob that I'm hoping to deploy to Azure, but I need to load a section of JSON from my appsettings.json file into a customer object I have created. I don't seem to have the GetSection method available on the builder object and I don't understand what I'm missing so that I can map a section of config to my HostOptions class (the POCO taking the config section).
Here's my code, I am using .NET Core 3.0.
private static void Main(string[] args)
{
var builder = new HostBuilder()
.ConfigureWebJobs(config =>
{
config.AddTimers();
config.AddAzureStorageCoreServices();
})
.ConfigureAppConfiguration((builderContext, config) =>
{
config.AddJsonFile("appsettings.json", optional: true);
config.AddJsonFile($"appsettings.{builderContext.HostingEnvironment.EnvironmentName}.json", optional: true);
config.AddEnvironmentVariables();
})
.ConfigureServices(services =>
{
// Some IoC mappings...
})
.Build();
builder.Run();
}
Use the overload for IWebHostBuilder.ConfigureServices
.ConfigureServices((builderContext, services) => {
IConfiguration configuration = builderContext.Configuration;
HostOptions options = configuration.GetSection("MySection").Get<HostOptions>();
services.AddSingleton(options);
// Some IoC mappings...
})
I am creating an Azure web job in .Net Core 2.1 (via a "console" app in Visual Studio). In this project, I have a static function that reads messages from a queue. Within this function, I need to use connection strings (from my configuration) to write to a database. This is my setup:
Program.cs
class Program
{
static void Main(string[] args)
{
var builder = new HostBuilder();
builder.ConfigureWebJobs(b =>
{
b.AddAzureStorageCoreServices();
b.AddAzureStorage();
});
builder.ConfigureAppConfiguration((hostContext, config) =>
{
var conf = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true).Build();
config.AddConfiguration(conf);
config.AddEnvironmentVariables();
})
builder.ConfigureLogging((context, b) =>
{
b.AddConsole();
});
var host = builder.Build();
using (host)
{
host.Run();
}
}
}
Functions.cs
public class Functions
{
public static void ProcessQueueMessage([QueueTrigger("myqueue")] string message, ILogger logger, IConfiguration configuration)
{
logger.LogInformation(message);
logger.LogInformation(configuration.GetConnectionString("MyDatabase"));
}
}
appsettings.json
{
"ConnectionStrings": {
"MyDatabase": "foo",
"AzureWebJobsDashboard": "foo2",
"AzureWebJobsStorage": "foo3"
}
}
However, when I run this, I get the following error:
Error indexing method 'Functions.ProcessQueueMessage'
Cannot bind parameter 'configuration' to type IConfiguration. Make
sure the parameter Type is supported by the binding. If you're using
binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make
sure you've called the registration method for the extension(s) in
your startup code (e.g. builder.AddAzureStorage(),
builder.AddServiceBus(), builder.AddTimers(), etc.).
I am very new to .Net Core, especially the DI pattern. And I believe that is the issue. I also see many examples of how to implement and use the configuration from within the Main function, but not from within a static helper function like this. How do I properly implement my configuration from within my static function?
Consider changing the approach and not try to inject IConfiguration.
Create a class to hold your desired settings
public class MyOptions {
public string MyDatabase { get; set; }
}
Refactor the setup to also use ConfigureServices and extract the desired configuration to populate the settings object and add it to the service collection
var builder = new HostBuilder();
builder
.ConfigureWebJobs(b => {
b.AddAzureStorageCoreServices();
b.AddAzureStorage();
})
.ConfigureAppConfiguration(config => { //not using context so no need for it really
config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true).Build();
config.AddEnvironmentVariables();
})
//...ADDITION HERE
.ConfigureServices((context, services) => {
//Configuration should be available by now, so access what you need.
var connectionString = context.Configuration.GetConnectionString("MyDatabase");
//If null you have the option to fail early, otherwise carry on.
var myOptions = new MyOptions {
MyDatabase = connectionString,
};
services.AddSingleton(myOptions);
}
.ConfigureLogging((context, b) => {
b.AddConsole();
});
//...
That way at this point you should be able to add your object as a dependency to the function
public class Functions {
public static void ProcessQueueMessage(
[QueueTrigger("myqueue")] string message,
ILogger logger,
MyOptions options) {
logger.LogInformation(message);
logger.LogInformation(options.MyDatabase);
}
}
I personally believe trying to access IConfiguration outside of startup to be more trouble than its worth and would even rank it with service locator anti-pattern and injecting IServiceProvider. Get what you need from it during setup, register that with service collection so it's available for injection where needed explicitly.
In ASP.NET Core 2.0 we have this
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
That CreateDefaultBuilder(args) has many helpful defaults. However it contains this:
.ConfigureLogging((context, logging) => {
logging.AddConfiguration(context.Configuration.GetSection("Logging"));
logging.AddConsole(); // HERE IS THE PROBLEM
logging.AddDebug(); // HERE IS THE PROBLEM
})
So the console and debug logging providers are always registered.
I used to register them like this
if (env.IsDevelopment())
{
// register them here
}
How do I remove/unregister them when running in production mode? I don't mean changing the logging level, I mean I don't want them registered at all in production mode.
I would say the designed way to do this would be by changing the logging configuration not to log anything to those providers. But I understand that you want to remove any calls for production; and you can still do this properly in code.
You can simply access the hosting environment from the HostBuilderContext that gets passed to the ConfigureLogging lambda:
.ConfigureLogging((context, logging) =>
{
logging.AddConfiguration(context.Configuration.GetSection("Logging"));
if (context.HostingEnvironment.IsDevelopment())
{
logging.AddConsole();
logging.AddDebug();
}
});
Obviously, this alone does not help to undo what the CreateDefaultBuilder call already set up. First, you would need to unregister those providers. For that, you can use the new ILoggingBuilder.ClearProviders method:
.ConfigureLogging((context, logging) =>
{
// clear all previously registered providers
logging.ClearProviders();
// now register everything you *really* want
// …
});
This was introduced in response to this logging issue on GitHub.
I found that it is better to remove a specific logging provider from the services as follows:
.ConfigureLogging((context, logging) => {
foreach (ServiceDescriptor serviceDescriptor in logging.Services)
{
if (serviceDescriptor.ImplementationType == typeof(Microsoft.Extensions.Logging.Console.ConsoleLoggerProvider))
{
// remove ConsoleLoggerProvider service only
logging.Services.Remove(serviceDescriptor);
break;
}
}
// now you can register any new logging provider service; e.g.,
logging.AddLog4Net();
logging.AddEventSourceLogger();
})
I think you cant use the CreateDefaultBuilder then or set the LogLevels to None maybe. According to the docs you can use this.
public static void Main(string[] args)
{
var webHost = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true,
reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json",
optional: true, reloadOnChange: true);
config.AddEnvironmentVariables();
})
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddConsole();
logging.AddDebug();
})
.UseStartup<Startup>()
.Build();
webHost.Run();
}
How to Add providers Section https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging?tabs=aspnetcore2x
Found another option, just add a Logging Filter for Console in your appsettings.json
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
},
"Console": {
"LogLevel": {
"Default": "None"
}
}
}
I can't seem to get Trace level log information outputted after upgrading to .NET Core 2.0 (+ASP.NET Core 2.0).
In fact, if I do a dotnet new webproject and add the code below in Startup for Configure, I do not get any trace or debug log messages, but I get the Information and Error messages twice. Commenting out the .AddConsole()call will output these (Information and Error) only once - suggesting that it gets configured automatically with a console provider by default. Keep in mind, this is a "File -> New" project experience, there is nothing setup in Program.cs for logging or configuration at all for this - except for what I've added. Anyone seen things? Or should I register a GitHub issue for it.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Microsoft.Extensions.Logging.LogLevel.Trace);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.Run(async (context) =>
{
var logger = loggerFactory.CreateLogger("Blah");
logger.LogTrace("Hello world : Trace");
logger.LogDebug("Hello world : Debug");
logger.LogInformation("Hello world : Information");
logger.LogError("Hello world : Error");
await context.Response.WriteAsync("Hello World!");
});
}
The way logging is configured has changed a little... The recommended way (and it's pretty well documented in this GitHub issue/announcement to do it now is to configure the loggers on the AddLogging method, such as
services.AddLogging(builder =>
{
builder.AddConfiguration(Configuration.GetSection("Logging"))
.AddConsole()
.AddDebug();
});
And have an appsettings.json like
Notice
Seems a few people are confused, because the example only demonstrates the configuration of Console provider and not all loggers.
The LogLevel section configures logging level for all namespaces (Default key) or for a specific namespace (System overrides the default value for all classes logging whose namespace starts with System.*.
This is for the class used in T in ILogger<T>). This allows to set a higher or lower than default logging level for loggers from this namespace.
{
"ApplicationInsights": {
"InstrumentationKey": ""
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Information",
"System": "Warning",
"Microsoft": "Information"
},
"Console": {
"LogLevel": {
"Default": "Warning",
"System": "Information",
"Microsoft": "Information"
}
}
}
}
Please note that the structure of the appsettings.json changed from what it used to be in .NET Core 1.x and that Logging entry in the appsettings.json now has logger provider names in it, which allows you to configure logging levels per logging provider.
Previously, the entry in appsettings.json would only be applicable to the console logger.
Alternatively, the logging can now be moved within the WebHostBuilder instead.
public static void Main()
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddJsonFile("hosting.json", optional: false)
.AddEnvironmentVariables();
})
.ConfigureLogging((webhostContext, builder) => {
builder.AddConfiguration(webhostContext.Configuration.GetSection("Logging"))
.AddConsole()
.AddDebug();
})
.UseIISIntegration()
.UseStartup<Startup>()
.UseApplicationInsights()
.Build();
host.Run();
}
Update
In case one doesn't want to use the appsettings.json, one can register the filters in code too.
services.AddLogging(builder =>
{
builder.AddConfiguration(Configuration.GetSection("Logging"))
// filter for all providers
.AddFilter("System", LogLevel.Debug)
// Only for Debug logger, using the provider type or it's alias
.AddFilter("Debug", "System", LogLevel.Information)
// Only for Console logger by provider type
.AddFilter<DebugLoggerProvider>("System", LogLevel.Error)
.AddConsole()
.AddDebug();
});
I spent almost twenty minutes to realize that since Configuration.GetSection("Logging") in the Startup.cs file reads the section "Logging" from the config in the appsettings.json file, which was configured as "Error". Changing it to "Information" or anything lower, fixed the issue.
Here's what the appsettinsg.json file looks now:
{
"Logging": {
"IncludeScopes": true,
"Debug": {
"LogLevel": {
"Default": "Information"
}
},
"Console": {
"LogLevel": {
"Default": "Information"
}
}
}
}
To find out more about the levels of logging (such as in "Information"), check out this link, that also provides general information on ASP.NET Core logging.
I'm just posting here, just in case you bump into any trouble with getting the logging to work, make sure you've been through that JSON file.
Nothing of the above works for me
The only workaround was to write a method
private void ConfigLogging( ILoggingBuilder builder ) {
builder.SetMinimumLevel( LogLevel.Trace );
//... additional configuration...
}
and when using the AddLogging extension method write it as
services.AddLogging( ConfigLogging );
The following structure of appsettings.json seems to work fine:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"System": "Information",
"Microsoft": "Information"
},
"Console":
{
"IncludeScopes": true
}
}
}
Taken from https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-2.1
Also, see what your start up calls are, I find the following works for me:
public class Startup
{
public Startup(IHostingEnvironment env)
{
var logger = new LoggerConfiguration()
.MinimumLevel.Information()
.WriteTo.Sink(jsonSink)
.Enrich.WithExceptionDetails()
.CreateLogger();
Log.Logger = logger;
}
}