Asp.net core get logger in ConfigureAppConfiguration - asp.net-core

I would like to use logger in "TODO" line, because I need to log when I add a "AddJsonConfigurationSourceDecryption" method, Is there any way to get a logger?
Logging in ASP.NET Core
public class Program
{
public static void Main(string[] args)
{
ILogger<Program> logger = null;
try
{
var host = CreateWebHostBuilder(args).Build();
ApplicationLogging.LoggerFactory = host.Services.GetRequiredService<ILoggerFactory>();
logger = host.Services.GetRequiredService<ILogger<Program>>();
logger.LogInformation("start thin API service...");
host.Run();
}
catch (Exception ex)
{
logger?.LogError(ex, "Stopped program because of exception");
throw;
}
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
return WebHost.CreateDefaultBuilder(args)
.UseKestrel(option => option.AddServerHeader = false)
.ConfigureLogging((host, builder) => { builder.SetMinimumLevel(LogLevel.Trace); })
.UseNLog()
.ConfigureServices(services => services.AddAutofac())
.ConfigureAppConfiguration((context, builder) =>
{
//TODO: Logger.............
builder.SetBasePath(Directory.GetCurrentDirectory());
builder.AddJsonConfigurationSourceDecryption();
})
.UseStartup<Startup>();
}
}

#0xced answered this question here
How to create a LoggerFactory with a ConsoleLoggerProvider?
as of dotnetcore3.1 the code could be written this way
private static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args).ConfigureAppConfiguration(
(hostContext, config) =>
{
var loggerFactory = LoggerFactory.Create(
builder =>
{
builder
.AddFilter("Microsoft", LogLevel.Warning)
.AddFilter("System", LogLevel.Warning)
.AddFilter("YourProgramNamespsace.Program", LogLevel.Debug)
.AddConsole();
});
var logger = loggerFactory.CreateLogger<Program>();
logger.LogInformation("Hello from ConfigureAppConfiguration");
...
})

Related

ASP.NET core how could i get my websites url/hostname when the program starts up

I need to get my site's host name so I can change the directory of the JSON file that I am adding to my project. I just have no clue how I can collect the URL.
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) => {
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
config.SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("wwwroot/sites/"environment"/"environment".json", optional: false, reloadOnChange: true);
})
.UseStartup<Startup>()
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddLog4Net();
logging.SetMinimumLevel(LogLevel.Information);
});
You can get the url in the following ways.
public static void Main()
{
var host = BuildWebHost(null);
host.Start();
var serverAddress = host.ServerFeatures.Get<IServerAddressesFeature>().Addresses;
foreach (var address in serverAddress)
{
var uri = new Uri(address);
var port = uri.Port;
Console.WriteLine($"Bound to port: {port}");
}
host.WaitForShutdown();
}
private static IWebHost BuildWebHost(string[] args)
{
return WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}

Hooking into SignalR event in Blazor ServerSide

I have found this piece of code for the default logging mechanism provided by Microsoft:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.AddConsole();
logging.AddFilter(
"Microsoft.AspNetCore.SignalR", LogLevel.Trace);
logging.AddFilter(
"Microsoft.AspNetCore.Http.Connections",
LogLevel.Trace);
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
My set for Serilog is as follows:
public class Program
{
public static void Main(string[] args)
{
try
{
using IHost host = CreateHostBuilder(args).Build();
host.Run();
}
catch (Exception ex)
{
if (Log.Logger == null || Log.Logger.GetType().Name == "SilentLogger")
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console()
.CreateLogger();
}
Log.Fatal(ex, "Host terminated unexpectedly");
}
finally
{
Log.CloseAndFlush();
}
}
private static IHostBuilder CreateHostBuilder(string[] args)
=> Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory(Register))
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>()
.CaptureStartupErrors(true)
.ConfigureAppConfiguration(config => { config.AddJsonFile("appsettings.Local.json", optional: true); })
.UseSerilog((hostingContext, loggerConfiguration) =>
{
loggerConfiguration
.ReadFrom.Configuration(hostingContext.Configuration)
.Enrich.FromLogContext()
.Enrich.WithProperty("ApplicationName", typeof(Program).Assembly.GetName().Name)
.Enrich.WithProperty("Environment", hostingContext.HostingEnvironment);
#if DEBUG
loggerConfiguration.Enrich.WithProperty("DebuggerAttached", Debugger.IsAttached);
#endif
});
});
private static void Register(ContainerBuilder builder) => builder.RegisterLogger(autowireProperties: true);
}
How do I add SignalR filters to my setup?
In Serilog terminology you need to override the minimum level for the Microsoft SignalR namespaces.
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args)
.UseSerilog((context, config) =>
{
/*
* the rest of the Serilog configuration here
*/
config.MinimumLevel.Override("Microsoft.AspNetCore.SignalR", LogEventLevel.Debug);
config.MinimumLevel.Override("Microsoft.AspNetCore.Http.Connections", LogEventLevel.Debug);
})
.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });

Configure NServicebus in Asp.net Core 5

I am using the NServiceBus.Extensions.Hosting extension to configure NServicebus
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
private static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseNServiceBus(c =>
{
var endpointConfiguration = new EndpointConfiguration("nsb.medusa");
endpointConfiguration.UseTransport<RabbitMQTransport>().ConnectionString("How do I access app settings?");
endpointConfiguration.SendOnly();
return endpointConfiguration;
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
The problem I am having is that I don't know how to get an instance of IConfiguration from a IHostBuilder. I need IConfiguration so I can get the connection string to RabbitMQ.
Also can this be moved to the startup class?
Microsoft has some excellent documentation. After reading it I just added two lines of code and I can now access the configuration.
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
private static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseNServiceBus(c =>
{
var configuration = c.Configuration; /* New */
var cnnStr = configuration.GetSection("mq:connection").Value; /* New */
var endpointConfiguration = new EndpointConfiguration("nsb.medusa");
endpointConfiguration.UseTransport<RabbitMQTransport>().ConnectionString(cnnStr);
endpointConfiguration.SendOnly();
return endpointConfiguration;
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}

Blazor application logging with Serilog

In a blazor application I have start-up logging configured in main as follows;
public static void Main(string[] args)
{
var assembly = Assembly.GetExecutingAssembly().GetName();
var appInsightsTelemetryConfiguration = TelemetryConfiguration.CreateDefault();
appInsightsTelemetryConfiguration.InstrumentationKey = "aa11aa11aa-a1a1-a1-aa-a111-aa11";
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Override("Microsoft.AspNetCore", Serilog.Events.LogEventLevel.Warning)
.Enrich.FromLogContext()
.Enrich.WithProperty("Application", $"{assembly.Name}")
.WriteTo.Console()
.WriteTo.Seq(serverUrl: "http://myseqserver.inthecloud.azurecontainer.io:5341/")
.WriteTo.ApplicationInsights(appInsightsTelemetryConfiguration, TelemetryConverter.Traces)
.CreateLogger();
try
{
Log.Information(Constants.Logging.Messages.SERVICE_STARTED, assembly.Name);
var host = CreateHostBuilder(args).Build();
using (var serviceScope = host.Services.CreateScope())
{
var context = serviceScope.ServiceProvider.GetRequiredService<MyDbContext>();
context.Database.Migrate(); // apply outstanding migrations automatically
}
host.Run();
return;
}
catch (Exception ex)
{
Log.Fatal(ex, Constants.Logging.Messages.SERVICE_STARTED, assembly.Name);
return;
}
finally
{
// make sure all batched messages are written.
Log.CloseAndFlush();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
and request logging in StartUp Configure;
public void ConfigureServices(IServiceCollection services)
{
//...
services.AddApplicationInsightsTelemetry("aa11aa11aa-a1a1-a1-aa-a111-aa11");
//...
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
/// ...
// Add this line; you'll need `using Serilog;` up the top, too
app.UseSerilogRequestLogging();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
On my blazor pages I cannot get this working;
#inject ILogger<ThisRazorPage> Logger
#code{
protected override void OnInitialized()
{
Logger.LogTrace("Log something. Please!");
}
}
But this does work;
#inject ILoggerFactory LoggerFactory
#code{
protected override void OnInitialized()
{
var logger = LoggerFactory.CreateLogger<Incident>();
logger.LogTrace("Log something. Please!");
}
}
According to this the .UseSerilog() method adds the DI for ILoggerFactory. Is there a way for me to do something similar for ILogger<T> within the DI framework so that ILogger<T> can be used, rather than having to explicitly create a LoggerFactory on every page.
Static method works for me.
#using Serilog
#code {
Log.Information("Log something. Please!");
}
You need:
add Serilog.Extensions.Logging
add in your Main()
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
// ...
builder.Services.AddTransient<AccountsViewModel>();
var levelSwitch = new LoggingLevelSwitch();
Log.Logger = new LoggerConfiguration()
.MinimumLevel.ControlledBy(levelSwitch)
.Enrich.WithProperty("InstanceId", Guid.NewGuid().ToString("n"))
.CreateLogger();
// ------------- this is what you'r looking for
builder.Logging.AddSerilog();
// ...
await builder.Build().RunAsync();
}
and in your ViewModel
public class AccountsViewModel
{
private readonly ILogger<AccountsViewModel> Logger;
private readonly HttpClient Http;
public AccountsViewModel(
ILogger<AccountsViewModel> logger,
HttpClient http
)
{
Http = http;
Logger = logger;
Logger.LogInformation("AccountsViewModel()");
}
}
or in your razor-page:
#inject ILogger<ThisRazorPage> logger;

Is it possible to set a specific formatter for an ILoggerProvider wrapped by serilog?

I have followed the instructions from https://github.com/serilog/serilog-aspnetcore and have the following code:
public class Program
{
static readonly LoggerProviderCollection Providers = new LoggerProviderCollection();
public static int Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext()
.WriteTo.Console(new CompactJsonFormatter())
.WriteTo.Providers(Providers)
.CreateLogger();
try
{
Log.Information("Starting web host");
CreateHostBuilder(args).Build().Run();
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly");
return 1;
}
finally
{
Log.CloseAndFlush();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.AddAzureWebAppDiagnostics();
})
.UseSerilog(providers: Providers)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
logging.AddAzureWebAppDiagnostics() configures logging to azure blob storage with BlobLoggerProvider, serilog is able to use this provider and write to the blob storage.
I would like to change the formatter for the BlobLoggerProvider to CompactJsonFormatter, but I can't figure out how. Is it possible to set a specific formatter for an ILoggerProvider wrapped by serilog?
The short answer is that this is not possible to set a specific formatter for an ILoggerProvider wrapped by serilog, nor would it make much sense.
Serilog has a sink that forwards log calls to each ILoggerProvider instance in the Providers collection. It is not possible to configure output formatting in this sink.
class LoggerProviderCollectionSink : ILogEventSink, IDisposable
{
// ...
public void Emit(LogEvent logEvent)
{
string categoryName = null;
if (logEvent.Properties.TryGetValue("SourceContext", out var sourceContextProperty) &&
sourceContextProperty is ScalarValue sourceContextValue &&
sourceContextValue.Value is string sourceContext)
{
categoryName = sourceContext;
}
var level = LevelConvert.ToExtensionsLevel(logEvent.Level);
var slv = new SerilogLogValues(logEvent.MessageTemplate, logEvent.Properties);
foreach (var provider in _providers.Providers)
{
var logger = provider.CreateLogger(categoryName);
logger.Log(
level,
default,
slv,
logEvent.Exception,
(s, e) => s.ToString());
}
}
// ...
}
LoggerProviderCollectionSink.cs
The ILoggerProvider implementation BlobLoggerProvider inherits from BatchingLoggerProvider, the logger created by the BlobLoggerProvider is a BatchingLogger. This logger does its own formatting of the log message before writing it to a queue, so it would not be much help if serilog provided a json string to the logger.
internal class BatchingLogger : ILogger
{
// ...
public void Log<TState>(DateTimeOffset timestamp, LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (!IsEnabled(logLevel))
{
return;
}
var builder = new StringBuilder();
builder.Append(timestamp.ToString("yyyy-MM-dd HH:mm:ss.fff zzz"));
builder.Append(" [");
builder.Append(logLevel.ToString());
builder.Append("] ");
builder.Append(_category);
var scopeProvider = _provider.ScopeProvider;
if (scopeProvider != null)
{
scopeProvider.ForEachScope((scope, stringBuilder) =>
{
stringBuilder.Append(" => ").Append(scope);
}, builder);
builder.AppendLine(":");
}
else
{
builder.Append(": ");
}
builder.AppendLine(formatter(state, exception));
if (exception != null)
{
builder.AppendLine(exception.ToString());
}
_provider.AddMessage(timestamp, builder.ToString());
}
// ...
}
BatchingLogger