Serilog not logging when published ASP.NET core - c#

I have Serilog configured to write to both an MSSQL table and to a File (to try and determine whats happening.) on a WebApi with ASP.NET core (running Core 2.1).
I add the Serilog logging in my startup.cs as follows;
public async void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
var log = new LoggerConfiguration()
.MinimumLevel.Verbose()
.WriteTo.MSSqlServer(
DbGlobals.DevDatabase, "Logs", schemaName:DbGlobals.SchemaName)
.WriteTo.File("Logs\\Serilog\\log.txt", rollingInterval: RollingInterval.Day)
.CreateLogger();
loggerFactory.AddSerilog(log);
where DbGlobals.DevDatbase and Dbglobals.SchemaName are string read from the configuration.
UPDATE For reference these values are;
DbGlobals.Schema = "MySchema";
DbGlobals.DevDatabase = "Data Source=xx.xx.xx.xx;Initial Catalog=DevDatabase;Integrated Security=False;Persist Security Info=False;User ID=LOGIN;Password=PASSWORD;MultipleActiveResultSets=true;";
When running locally with IIS Express and under both debug and release configurations, both logging functions are working correctly. So for example in my controller;
public class ReviewPublicController : Controller
{
private readonly IReviewService _service;
private readonly IMapper _mapper;
private readonly IMailService _mailService;
private readonly ILogger _logger;
public ReviewController(
IReviewService service,
ILogger<ReviewController> logger)
{
_service = service;
_logger = logger;
}
[HttpPost]
[ProducesResponseType(typeof(Review), 201)]
[Route("")]
public async Task<IActionResult> Post([FromBody]ReviewPostModel model)
{
_logger.LogDebug("Posting Review");
...
return Ok();
}
So locally "Posting Review" is written to both my File and DbSchema.
However, when I publish to my server, the above "Posting Review" entry is not written to either.
Both appear to be working as information entries are being added from EF and routing etc but not when I specifically try to write an entry?
Can anyone direct me here as to what the issue could be please?
The current nuget versions are;
Serilog 2.7.1
Serilog.AspNetCore 2.1.1
Serilog.Sinks.MSSqlServer 5.1.2
Serilog.Sinks.File 4.0.0
Also, I have the following in my appsettings.json;
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
}
},
"Release": {
"LogLevel": {
"Default": "Warning"
}
},
"Console": {
"LogLevel": {
"Default": "Warning"
}
}

update
As in the docs:
Default Level - if no MinimumLevel is specified, then Information level events and higher will be processed.
So basically, it seems that your configuration is either invalid or overwritten. see: https://github.com/serilog/serilog/wiki/Configuration-Basics
LogDebug is disabled by default in a Release build, which is probably what your publish is.
Please try with
_logger.LogInformation("Posting Review");

For me what was the solution is to remove the "restrictedToMinimumLevel": "Information" from appsettings.json.
It was exactly the same in appsettings.Development.json and it was working well in Development environment.

For me, I have configured all above. It logs db in my local environment, where as it does not work in dev environment. The issue is due to authentication. I am using azure ad authentication for my application that restricts serilog to write into server. So, In my program.cs file, I have added the below settings.
Program.cs
var sqlSinkOptions = new MSSqlServerSinkOptions
{
TableName = "MyLogTableName",
UseAzureManagedIdentity = true, // This line
AzureServiceTokenProviderResource = "https://database.windows.net/" // This line
};
After that, I can see logging is happening in dev environment too. May be this helps some one. Happy coding!

Related

c# The ConnectionString property has not been initialized

I've been trying to create a migration and then update the database (using EF Core tools and SSMS to check the database). I've been struggling because I have different projects. The organization of my solution is the following:
I want to have the migration and the related DB interactions in VSC.Repo. This means that the context is in this project. Besides that, I have my connection string in the default appsettings, which is in VSC.API (different assembly). I've tried various ways of trying to get the connection string from there, but I always get the following error when I run the "dotnet ef database update" in the VSC.Repo project:
This is my context class:
public class DataContext : DbContext
{
private readonly string connectionString;
public DataContext()
{
}
public DataContext(DbContextOptions<DataContext> options, IConfiguration configuration) : base(options)
{
connectionString = configuration.GetSection("ConnectionStrings:DefaultConnection").Value;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(connectionString);
}
I can't figure out what I'm doing wrong. Any help would me much appreciated.
EDIT: With the hardcoded string it works perfectly fine, but this is bad practice and I don't want to implement this way.
appsettings.json:
"ConnectionStrings": {
"DefaultConnection": "server=localhost;database=vscDatabase;trusted_connection=true;TrustServerCertificate=True;"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
program.cs:
WebApplicationBuilder? builder =
WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
var connectionString =
builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<DataContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
//builder.AddRepoConfigurations();
var app = builder.Build();
Okay so #Panagiotis Kanavos found out that I was executing the command in the wrong project, more precisely, in one that did not have the program.cs, and this was the issue. When I executed in the correct one, it worked just fine.

how to log to app insights from .net core 6

I have a solution with 2 projects:
function app project
web api .net core 6.0 project
The function app is succesfully logging to app insights, but the web api project is not! Azure portal is showing that both of the projects are configured to write to the same instance of app insights.
Is it a problem that two different resources are writing to the same app insights instance? If not, what am I doing wrong?
To configure Application Insights with telemetry you need to configure both telemetry and logging independently. Manual configuration or convention based in config configuration can both be used:
https://learn.microsoft.com/en-us/azure/azure-monitor/app/asp-net-core?tabs=netcore6
Manually setting options when configuring DI:
public void ConfigureServices(IServiceCollection service)
{
// ...
ApplicationInsightsServiceOptions telemetryOptions = new ();
telemetryOptions.InstrumentationKey = YourInstrumentationKey;
// Can enable/disable adaptive sampling here.
// https://learn.microsoft.com/en-us/azure/azure-monitor/app/sampling
telemetryOptions.EnableAdaptiveSampling = false;
services.AddApplicationInsightsTelemetry(telemetryOptions);
services.AddLogging(logBuilder =>
{
logBuilder.AddApplicationInsights(YourInstrumentationKey)
// adding custom filter for specific use case.
.AddFilter("Orleans", (level) => level == LogLevel.Error);
});
// ...
}
When using appsettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ApplicationInsights": {
"ConnectionString": "Copy connection string from Application Insights Resource Overview"
}
}
Then DI is can be slightly simplified:
public void ConfigureServices(IServiceCollection service)
{
// ...
services.AddApplicationInsightsTelemetry();
services.AddLogging(logBuilder => logBuilder.AddApplicationInsights()});
// ...
}

.NET Core Web API and Postgres DB Connection String

I am starting a web api which uses postgres as the backend.
I am on a team of developers that will each have a local db for development. How can I ensure that if a new developer comes on the team that their local db is created without manually creating it themself.
As of right now, we each created our local db's through command line and update our appsettings.Development.json to use our local db connection string (which is on the gitignore incase we use sensitive passwords).
It's annoying to have to manually set this portion up however. Is there anyway to just have a database be created on the fly? As in, right when they launch the API, the db should be created and the migrations applied onto it.
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"Local": "Server=localhost;Port=5432;Database=mydb;User ID=xxx;Password=xxx;"
}
}
Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
UpdateDatabase(app);
// Other configurations
}
public virtual void UpdateDatabase(IApplicationBuilder app)
{
using var serviceScope = app.ApplicationServices
.GetRequiredService<IServiceScopeFactory>()
.CreateScope();
using var context = serviceScope.ServiceProvider.GetService<MyDbContext>();
context.Database.EnsureCreated();
context.Database.Migrate();
}

Why do some logging calls not reach app insights?

I have an issue where some logging calls are not reaching App Insights, but others are
I added a controller to test this
public class LogController : ControllerBase
{
private readonly ILogger<BankingController> _logger;
private readonly IServiceProvider _services;
public LogController(ILogger<LogController> logger,
IServiceProvider services)
{
_logger = logger;
_services = services;
}
[HttpGet("test-logging")]
public async Task TestLogging()
{
_logger.Log(LogLevel.Information, "Test Logging controller - information manual");
_logger.LogTrace("Test Logging controller - trace");
_logger.LogInformation("Test Logging controller - information");
_logger.LogWarning("Test Logging controller - warning");
_logger.LogError("Test Logging controller - error");
_logger.LogCritical("Test Logging controller - critical");
var logger = _services.GetRequiredService<ILogger<LoggingController>>();
logger.Log(LogLevel.Information, "DIRECT Test Logging controller - information manual");
logger.LogTrace("DIRECT Test Logging controller - trace");
logger.LogInformation("DIRECT Test Logging controller - information");
logger.LogWarning("DIRECT Test Logging controller - warning");
logger.LogError("DIRECT Test Logging controller - error");
logger.LogCritical("DIRECT Test Logging controller - critical");
}
}
None of the logging calls here reach App Insights
However, in another part of the API, in program.cs we have a logging call that does reach App Insights
public static class IWebHostExtensions
{
public static IWebHost MigrateDbContext<TContext>(this IWebHost webHost, Action<TContext,IServiceProvider> seeder) where TContext : DbContext
{
using (var scope = webHost.Services.CreateScope())
{
var services = scope.ServiceProvider;
var logger = services.GetRequiredService<ILogger<TContext>>();
var context = services.GetService<TContext>();
try
{
logger.LogInformation($"Migrating database associated with context {typeof(TContext).Name}");
var retry = Policy.Handle<SqlException>()
.WaitAndRetry(new TimeSpan[]
{
TimeSpan.FromSeconds(3),
TimeSpan.FromSeconds(5),
TimeSpan.FromSeconds(8),
});
retry.Execute(() =>
{
//if the sql server container is not created on run docker compose this
//migration can't fail for network related exception. The retry options for DbContext only
//apply to transient exceptions.
context.Database.Migrate();
});
logger.LogInformation($"Migrated database associated with context {typeof(TContext).Name}");
}
catch (Exception ex)
{
logger.LogError(ex, $"An error occurred while migrating the database used on context {typeof(TContext).Name}");
}
}
return webHost;
}
}
Has anyone ever come across this?
I tried a totally fresh App Insights instance
As you can see, the method used for logger uses ServiceProvider like the approach that works for migrations
I really need the normal ILogger convention to work reliably
Im using .NET Core 3.1
In my startup.cs I have
services.AddApplicationInsightsTelemetry();
I have tried changing the logging levels in my appsettings and still my custom messages are not being logged
"Logging": {
"ApplicationInsights": {
"LogLevel": {
"Default": "Trace",
"Microsoft": "Trace",
"System": "Trace"
}
},
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"System": "Warning"
}
},
Paul
Have you tried using the right type for ILogger? In your code I can see you're using BankingController as the Type but on a different class. Try this:
from:
public class LogController : ControllerBase
{
private readonly ILogger<BankingController> _logger;
to:
public class LogController : ControllerBase
{
private readonly ILogger<LogController > _logger;

Microsoft ILogger not working inside Controller if Host started inside unit test library

Things to clarify first is that I use NLog/Serilog/etc for neat configuration, across all applications I only use Microsoft.* namespce logging interfaces.
Here is example of my Site startup class, which just reference host builder form real app, so it is complete integration friendly class which I can use in SetUp and TearDown in NUnit:
public sealed class Site
{
private IHost _host;
public readonly string BaseAddress;
public Site(string baseAddress)
{
BaseAddress = baseAddress;
}
public async Task StartAsync()
{
if (_host != null)
throw new InvalidOperationException("Already started.");
var cfgBuilder = new ConfigurationBuilder();
var args = string.Format("--urls {0}", BaseAddress);
cfgBuilder.AddCommandLine(args.Split(' ', System.StringSplitOptions.RemoveEmptyEntries));
cfgBuilder.AddJsonFile("appsettings.json");
cfgBuilder.AddEnvironmentVariables();
using (var cts = new CancellationTokenSource())
{
cts.CancelAfter(5000);
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console()
.CreateLogger();
_host = Performance.Program.CreateHostBuilder(cfgBuilder.Build()).UseSerilog(Log.Logger).Build();
await _host.StartAsync(cts.Token).ConfigureAwait(false);
}
}
public async Task StopAsync()
{
if (_host == null)
return;
using (var cts = new CancellationTokenSource())
{
cts.CancelAfter(5000);
await _host.StopAsync(cts.Token).ConfigureAwait(false);
}
}
}
My appsettings..json* pretty much default:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
But here is the problem. Microsoft ILogger work inside IHostedService or Startup instances, BUT it stop working entirely in any controller/middleware:
public class ErrorController : ControllerBase
{
private readonly ILogger<ErrorController> _logger;
public ErrorController(ILogger<ErrorController> logger)
{
_logger = logger;
}
[HttpGet]
[Route("error")]
public async Task<IActionResult> OnError()
{
_logger.LogError("This one won't ever show up in test library except if you stop using serilog/nlog/whatever.");
return BadRequest();
}
}
If I start my app normally through Program.cs rather than from TestExplorer - everything fine and logging. So here is table of error replication with same configuration on different loggers I used:
Framework |NUnit.Startup |NUnit.Controller |Program.Startup |Program.Controller
___________________________________________________________________________________
NLog |good |bad |good |good
Serilog |good |bad |good |good
Microsoft logger |good |good |good |good
So, as you see, Microsoft logger works everywhere and project is pretty much clean default generation in VS. I tried completely clearing providers, various combination of extension, etc. What am I missing?
Turns out this some strange behavior of..... Console+ IHost and thread in which its running! Yes, you didn't misread. Things happens and for some reason Console will not work in thread of your IHost class after it starts - it will be back once you call StopAsync though. It will be nice if someone would explain this behavior further, I don't have decompiler at the moment in machine.
Solution is just to enable background processing of your logs, so they will be logged to Console but in some other thread.
For example in Serilog:
var logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Async(a=>
{
a.Console();
})
.CreateLogger();
In NLog you could use their async wrapper, but I didn't tested that.
Microsoft probably knew this behavior and their logging.AddConsole() extension works through background process, so this is the reason why their logger worked and others didn't.

Categories

Resources