Reputation: 18328
In this application I've pulled in and setup Serilog, which works for exceptions, and I wanted to use the Microsoft's Logger with Serilog, but I can't seem to figure out how to DI it into services without this error during dotnet build
.
I'm not sure what I'm missing to have ILogger be using an instance of Serilog?
Error on dotnet build
:
[13:56:21 FTL] Host terminated unexpectedly
System.AggregateException: Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: Unable to resolve service for type 'Microsoft.Extensions.Logging.ILogger' while attempting to activate 'App.Services.MyService'.)
Dependency Injection into Service:
using Microsoft.Extensions.Logging;
public class MyService : BaseService
{
private readonly ILogger _logger;
public MyService(
ILogger logger)
: base(context, httpContext)
{
_logger = logger;
}
// ... Removed for brevity
}
Implementation
public static int Main(string[] args)
{
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
{
// Ensure buffered logs are written to their target sink
Log.CloseAndFlush();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>())
.UseSerilog();
private static void CreateLogger()
{
string path = PrimeConstants.LOG_FILE_PATH;
try
{
if (isDevelopment())
{
Directory.CreateDirectory(path);
}
}
catch (Exception e)
{
Console.WriteLine("Creating the logging directory failed: {0}", e.ToString());
}
var name = Assembly.GetExecutingAssembly().GetName();
var outputTemplate = "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}";
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Information)
.MinimumLevel.Override("System", LogEventLevel.Warning)
.Enrich.FromLogContext()
.Enrich.WithMachineName()
.Enrich.WithProperty("Assembly", $"{name.Name}")
.Enrich.WithProperty("Version", $"{name.Version}")
.WriteTo.Console(
outputTemplate: outputTemplate,
theme: AnsiConsoleTheme.Code)
.WriteTo.Async(a => a.File(
$@"{path}/prime.log",
outputTemplate: outputTemplate,
rollingInterval: RollingInterval.Day,
shared: true))
.WriteTo.Async(a => a.File(
new JsonFormatter(),
$@"{path}/prime.json",
rollingInterval: RollingInterval.Day))
.CreateLogger();
}
Upvotes: 3
Views: 4492
Reputation: 93283
ILogger
isn't available to DI. You can use one of the following approaches:
Inject ILogger<TCategoryName>
:
public class MyService : BaseService
{
private readonly ILogger _logger;
public MyService(ILogger<MyService> logger)
: base(context, httpContext)
{
_logger = logger;
}
// ...
}
Inject ILoggerFactory
and use its CreateLogger
method:
public class MyService : BaseService
{
private readonly ILogger _logger;
public MyService(ILoggerFactory loggerFactory)
: base(context, httpContext)
{
_logger = loggerFactory.CreateLogger("<YOUR_CATEGORY_NAME>");
}
// ...
}
I'd recommend option #1, unless you want full control over the log category. See the docs to learn more about what that means:
That category is included with each log message created by that instance of
ILogger
.
Upvotes: 7