Application Insights not storing ILogger<> - messages - c#

I have a .net 5 web application that uses Application Insights. I try to log into AI trace by using ILogger<>. However: When analyzing the "traces" - Content in AI on Azure the logs are not shown.
Part of StartUp:
services.AddLogging(loggingbuilder =>
{
loggingbuilder.AddFilter<ApplicationInsightsLoggerProvider>("", LogLevel.Trace);
loggingbuilder.AddApplicationInsights();
});
services.AddApplicationInsightsTelemetry();
The constructor of the class that should do the logging injects ILogger and AppInsights via dependency injection:
public ImportService(ILogger<ImportService> log, TelemetryClient telemetryClient)
{
_log = log;
_telemetryClient = telemetryClient;
}
Inside the method I have the following two logging attempts:
public async Task<Customer> UpdateCustomerByEmail(string email)
{
_telemetryClient.TrackTrace("From Telemetry");
_log.LogWarning("From Log");
[...]
}
While the first one ("from Telemetry") ends up correctly in AI-traces, the second one ("From Log") never shows up there.
The instrumentationkey is stored in the appsettings (and obviously correct because the telemetryClient-Track is working)

Might this documentation be relevant for you? Adding the following code to program.cs worked for me:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddApplicationInsights("<instrumentationKeyHere>");
logging.AddFilter<Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider>("", LogLevel.Information);
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
The nuget package Microsoft.Extensions.Logging.ApplicationInsights must also be installed.
In your case it might be sufficient to simply provide the Instrumentation Key as a paramter to the AddApplicationInsights function.
As stated in the documentation "This code is required only when you use a standalone logging provider. For regular Application Insights monitoring, the instrumentation key is loaded automatically from the configuration path ApplicationInsights: Instrumentationkey."
This might explain why regular monitoring works, but not for logging.

Related

How does one set JsonSerializerOptions.DefaultIgnoreCondition for Serilog.Sinks.Seq

I'm using Serilog.Sinks.Seq in my C# app (see the configuration code below) but I can't figure out how to set the JsonSerializerOptions.DefaultIgnoreCondition to ignore nulls. Any help in this regard would be greatly appreciated...
using IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices((context, services) =>
{
services.AddHostedService<Worker>();
})
.UseSerilog((context, config) =>
{
var seqUri = new Uri(context.Configuration["SeqUri"]!);
var seqApiKey = context.Configuration["SeqApiKey"]!;
config.MinimumLevel.Debug()
.WriteTo.Seq(seqUri.AbsoluteUri, apiKey: seqApiKey);
})
.Build();
await host.RunAsync();
WriteTo.Seq does not provide any ways to use JsonSerializerOptions. The Seq server itself is responsible for handling the serialization of the log events. It's designed to work with structured log data so it uses its own serialization format which is built for optimization. I'm not aware of anyways to modify or override it.
You can use other sinks for logging which provide support for custom serialization Serilog.Sinks.File or Serilog.Sinks.Elasticsearch. You can use these sinks to log and then use Log Shipping to consume those logs in Seq.

Configuring Serilog before configuration is ready?

I have a web api (.NET Core 3.1) which is using Serilog for logging. Serilog is added to the IWebHostBuilder quite early:
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
return WebHost
.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseSerilog((context, configuration) =>
{
if (context.HostingEnvironment.IsDevelopment())
{
configuration.WriteTo.Console(LogEventLevel.Debug);
return;
}
configuration.WriteTo.ApplicationInsights(TelemetryConverter.Traces, LogEventLevel.Error);
});
}
This means (afaik) that I need to have already configured the logger at this point. So this is the very first thing I do in the main:
public static int Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(Configuration)
.CreateLogger();
var host = CreateWebHostBuilder(args).Build();
host.Run();
}
But the line .ReadFrom.Configuration(Configuration) requires the configuration to be set up. This is usually done in the StartUp (again, afaik) which has not yet been run at this time. Obviously I could move my LoggerConfiguration to later, but the .UseSerilog would be called before it was configured.
So how do I configure Serilog with IConfugration, when I haven't set it up yet?
#RubenBartelink pointed to a very good ressource in comment.
This is also described in the Serilog for ASP.NET Core documentation.
In particular the two-stage initialization part, which states:
Two-stage initialization
The example at the top of this page shows how to configure Serilog immediately when the application starts.
This has the benefit of catching and reporting exceptions thrown during set-up of the ASP.NET Core host.
The downside of initializing Serilog first is that services from the ASP.NET Core host, including the appsettings.json configuration and dependency injection, aren't available yet.
To address this, Serilog supports two-stage initialization. An initial "bootstrap" logger is configured immediately when the program starts, and this is replaced by the fully-configured logger once the host has loaded.
To use this technique, first replace the initial CreateLogger() call with CreateBootstrapLogger():
using Serilog;
using Serilog.Events;
public class Program
{
public static int Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext()
.WriteTo.Console()
.CreateBootstrapLogger(); // <-- Change this line!
Then, pass a callback to UseSerilog() that creates the final logger:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog((context, services, configuration) => configuration
.ReadFrom.Configuration(context.Configuration)
.ReadFrom.Services(services)
.Enrich.FromLogContext()
.WriteTo.Console())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
It's important to note that the final logger completely replaces the bootstrap logger: if you want both to log to the console, for instance, you'll need to specify WriteTo.Console() in both places, as the example shows.
Consuming appsettings.json configuration
Using two-stage initialization, insert the ReadFrom.Configuration(context.Configuration) call shown in the example above. The JSON configuration syntax is documented in the Serilog.Settings.Configuration README.

How to configure ApplicationInsightsTelemetry, in .NET Core Web Api

I am trying to adapt Application Insights to my liking. And I have some problems. I have it mounted like this.
In the startup.cs class:
public void ConfigureServices(IServiceCollection services)
{
services.AddApplicationInsightsTelemetry();
services.AddControllers();
}
In the Program.cs:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
logging.AddApplicationInsights("73985d32-dc3b-4a7e-915e-aa7ef37fbef8");
logging.AddFilter<ApplicationInsightsLoggerProvider>("", LogLevel.Information);
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
So I avoid using the appsettings.json configuration, because the log level will be variable.
My first question is, how can I make the dynamic log level, by querying the database?
Another question, is how can I add a custom parameter, type customer_name?
Finally, how can I make Application Insights register the values ​​that I want, using:
Only record the values ​​that come out of these functions, for example, if there is an exception, you would not have to register it.
_logger.LogInformation("Test info");
_logger.LogError(ex, ex.Message);
About your first question
I think it's impossible,for more details, you can check bowman's answer.
Overriding Log Level for Azure Functions
About second question
Jitendra Patil's code really great, this should be what you need.
Adding custom properties for each request in Application Insights metrics

How to turn on CircuitOptions.DetailedErrors?

I'm getting this message in the console when running a server-side Blazor app:
Error: There was an unhandled exception on the current circuit, so
this circuit will be terminated. For more details turn on detailed
exceptions in 'CircuitOptions.DetailedErrors'
I've had a look at the Blazor error handling documentation, but I can't work out how to actually turn on the detailed errors mentioned in that message?
More digging on this revealed that there are both non-Blazor specific .NET Core ways to turn on Detailed Errors, and also a Blazor specific approach:
The general .NET Core way to turn on Detailed Errors:
There are a number of ways to get the detailed errors as discussed in the .NET Core documentation, but I ended up using the Detailed Errors setting:
WebHost.CreateDefaultBuilder(args).UseSetting(WebHostDefaults.DetailedErrorsKey, "true")
And the Development Environment setting:
WebHost.CreateDefaultBuilder(args).UseEnvironment(Environments.Development)
Both of those are used in Program.cs:
If you are using the older (and eventually to be deprecated IWebHostBuilder approach) that looks like this:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseSetting(WebHostDefaults.DetailedErrorsKey, "true")
//.UseEnvironment(EnvironmentName.Development)
.UseStartup<Startup>();
And if you're using the newer IHostBuilder approach that was introduced with Core 2.1 that looks like this:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder
.UseStartup<Startup>()
.UseSetting(WebHostDefaults.DetailedErrorsKey, "true")
//.UseEnvironment(EnvironmentName.Development);
});
Once I set that I got more details about my misfiring Blazor code.
A Blazor specific approach:
An alternative approach for turning on detailed errors can also be found in this answer, which includes this code:
services.AddServerSideBlazor().AddCircuitOptions(options => { options.DetailedErrors = true; });
This approach can then be expanded to include a check for whether the code is being run in the development environment
services.AddServerSideBlazor().AddCircuitOptions(o =>
{
//only add details when debugging
o.DetailedErrors = _env.IsDevelopment();
});
as highlighted by #Eonasdan's answer below
A better way to add detailed errors is to check your environment first. In Startup.cs add IWebHostEnvironment env to your constructor.
Then you can do this:
services.AddServerSideBlazor().AddCircuitOptions(o =>
{
if (_env.IsDevelopment()) //only add details when debugging
{
o.DetailedErrors = true;
}
});
NO CODE : EASIER & More SECURE
Best Practice
This is easier than most of the proposed solutions and it does not introduce a possible security issue into the code. It is also considered a coding best practice.
Microsoft recommends adding the following to the appsettings.development.json file as it does not add code to the application that can become a security risk. Do not put this in your appsettings.json unless absolutely necessary (and then only temporarily in a staging or dev environment).
You can also use this approach to provide detailed error logging for SignalR.
src: Handle errors in ASP.NET Core Blazor apps: Detailed circuit errors
{
"DetailedErrors": true, // turns on CircuitOptions.DetailedErrors
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.AspNetCore.SignalR": "Debug" // turns on SignalR debugging
}
}
}
For .NET Core 6 you can use WebApplicationBuilder.
var builder = WebApplication.CreateBuilder(args);
if (builder.Environment.IsDevelopment())
{
builder.Services.AddServerSideBlazor().AddCircuitOptions(x => x.DetailedErrors = true);
}
else
{
builder.Services.AddServerSideBlazor();
}
For me it was slightly different
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseSetting(WebHostDefaults.DetailedErrorsKey, "true");
webBuilder.UseStartup<Startup>();
});

DbContext connection string and hosted service

I have a. NET core console app that implement IHostedService and a reference to another project with a DbContext definition.
This is the configuration of DbContext in console app:
IHost host = new HostBuilder()
.ConfigureHostConfiguration(configHost =>
{
configHost.SetBasePath(Directory.GetCurrentDirectory());
configHost.AddEnvironmentVariables(prefix: "ASPNETCORE_");
configHost.AddCommandLine(args);
})
.ConfigureAppConfiguration((hostContext, configApp) =>
{
configApp.SetBasePath(Directory.GetCurrentDirectory());
configApp.AddEnvironmentVariables(prefix: "ASPNETCORE_");
configApp.AddJsonFile($"appsettings.json", true);
configApp.AddJsonFile($"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json", true);
configApp.AddCommandLine(args);
})
.ConfigureServices((hostContext, services) =>
{
services.AddDbContext<MyAppDbContext>(options => options.UseNpgsql(hostContext.Configuration.GetConnectionString("DefaultConnection")));
services.AddHostedService<ApplicationLifetimeHostedService>();
})
.Build();
Now, in the OnStarted() method of ApplicationLifetimeHostedService I have:
using (var _context = new MyAppDbContext())
{
...
_context.SaveChanges();
}
Why MyAppDbContext take the connection string value from OnConfiguring method of dbcontext definition class (hard-coded, generated from scaffolding), and not from appsettings.{ASPNETCORE_ENVIROMENT}.json ()?
Thank you in advance!
Based on your configuration, currently the IHostBuilder is for non web applications and simulates a generic configuration, eventually this will replace the IWebHostBuilder. However, you do not need those... In your instance you would be better off with CreateDefaultBuilder.
Host Configuration
App Configuration
Both are provided by default, with more granular control. The primary item is the default services provided by the builder and what they compile or build.
To directly answer your issue though, in your top line, you are missing the following:
var host = new HostBuilder()
.ConfigureHostConfiguration(configuration =>
{
// For brevity, removed some.
configuration.AddJsonFile("appsettings.json", false, true);
}
That is why your appsettings.json is not working. The ConfigureHostConfiguration will carry through to the ConfigureAppConfiguration.
Host configuration automatically flows to app configuration
(ConfigureAppConfiguration and the rest of the app).
No providers are included by default. You must explicitly specify
whatever configuration providers the app requires in
ConfigureHostConfiguration, including:
File configuration (for example, from a hostsettings.json file).
Environment variable configuration.
Command-line argument configuration.
Any other required configuration providers.

Categories

Resources