Events not flowing to Application Insights when using secrets.json in localhost - asp.net-core-2.0

I used this Application Insights getting started guide for setting up my application. I'm running VS2017 version 15.5.7 and my application is using AspNetCore 2.0.0.
When I F5 debug my application using IIS Express from Visual Studio, I see Application Insights events within the debugger Events window. However, the same events are not flowing to Application Insights in Azure; I've configured the InstrumentationKey within secrets.json as you can see below. I've confirmed the key is loaded into my application configuration by setting a breakpoint.
As another debugging data point, I've confirmed events do successfully flow to Application Insights when running in a Azure Web App. This test uses the exact same code. Instead of loading the InstrumentationKey from secrets.json, however, I've configured APPINSIGHTS_INSTRUMENTATIONKEY environment variable to have the key (via ApplicationSettings pane of the Web App in the portal).
I'm at a loss for why my events are not flowing to Application Insights via localhost debugger, but they are when deployed to a Web App.
Program.cs
public static void Main( string[] args )
{
BuildWebHost( args ).Run();
}
public static IWebHost BuildWebHost( string[] args ) =>
WebHost.CreateDefaultBuilder( args )
.UseStartup<Startup>()
.UseApplicationInsights()
.Build();
Startup.cs
var configurationBuilder = new ConfigurationBuilder()
.SetBasePath( hostingEnvironment.ContentRootPath )
.AddJsonFile( $"appsettings.{hostingEnvironment.EnvironmentName}.json", optional: true, reloadOnChange: true );
if ( hostingEnvironment.IsDevelopment() )
{
configurationBuilder.AddUserSecrets<Startup>( optional: true );
}
this.Configuration = configurationBuilder
.AddEnvironmentVariables()
.Build();
secrets.json
{
"ApplicationInsights": {
"InstrumentationKey": "omitted for StackOverflow"
}
}
my.csproj
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.1.1" />
<PackageReference Include="Microsoft.ApplicationInsights.Web" Version="2.5.1" />
<PackageReference Include="Microsoft.AspNetCore" Version="2.0.0" />
launchSettings.json
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:2322/",
"sslPort": 44330
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "https://localhost:44330/",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"FrontDoor": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "https://localhost:44330/api/config",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:2323"
}
}
}

when you see appinsights events in the debugger output window, do those events say (unconfigured) in them? if that is present in the output window, that would mean that the sdk is running in debug, but not finding the instrumentation key in your appsettings.json (or in code) note that the application insights sdks don't look in usersecrets for this setting, only appsettings! (edit 5/28/2020: see OP's edit below, while this was the issue 2 years ago, if you use AddApplicationInsightsTelemetry instead of the obsolete UseApplicationInsights this limitation does not apply)
if the events in the debugger window do not say (unconfigured), the next step is to use something like Fiddler to watch your outbound http traffic, to make sure you're seeing outbound calls by the SDK going to dc.services.visualstudio.com, and that those outbound calls are succeeding. (and at this step, you can verify that the instrumentation key think you are using are using is the one the sdk is using to send the events)
if the events are being sent, and are using the ikey you have set, the last step is to verify that the ikey you're using is the one for the resource you're looking at in the portal. every once in a while, someone has an ikey for "dev" somewhere, and then is looking at a "prod" resource in the portal and not seeing the events they expect.
if you've gotten this far, with the events being sent, sent to the ikey you want, and verified the ikey is for the resource you expect it to be, then verify that there aren't any service outages or delays that might be affecting your data, which you can find at http://aka.ms/aistatus otherwise, you should see events normally in seconds~minutes depending on where in the world you are and what region your resource is in azure, etc.
OP edit for completeness of answer:
Indeed, I was hitting #1 and as John hinted in the comments, I needed to let AI SDK know about my iKey in another way. Instead of using UseApplicationInsights() in Program.cs, I've switched to using AddApplicationInsightsTelemetry(configuration) within StartUp.ConfigureServices(). The configuration passed along has my iKey loaded from secrets.json.

This is a known limitation, being fixed in the coming beta.
https://github.com/microsoft/ApplicationInsights-dotnet/issues/1882
Until then workaround is to use the AddApplicationInsights(IConfiguration) overlaod.

Starting from Microsoft.ApplicationInsights.AspNetCore version 2.15.0 this problem has been fixed.
For lower versions the overload services.AddApplicationInsightsTelemetry(Configuration) would read also from secrets.json.
User secrets and other configuration providers
If you want to store the instrumentation key in ASP.NET Core user
secrets or retrieve it from another configuration provider, you can
use the overload with a
Microsoft.Extensions.Configuration.IConfiguration parameter. For
example, services.AddApplicationInsightsTelemetry(Configuration);.
Starting from Microsoft.ApplicationInsights.AspNetCore version 2.15.0,
calling services.AddApplicationInsightsTelemetry() will automatically
read the instrumentation key from
Microsoft.Extensions.Configuration.IConfiguration of the application.
There is no need to explicitly provide the IConfiguration.
https://learn.microsoft.com/en-us/azure/azure-monitor/app/asp-net-core

Related

Using application insights, metrics tracking is ok, but can not find the logs

I set up a POC/demo project to test application insights in order to have a full observability experience.
I think I followed the different recommandation, like using the workspace-based application insight resource, using the connection string approach (rather than the instrumentation key one), and used the C#/.net 6 minimal web api project template modified as described to enable/configure the application insights telemetry.
When I run my example, everything works fine regarding metrics, live metrics, application maps up to the application insight workspace (I can visualize charts, see the live metrics, start a map...).
BUT I can not see any logs... Where should I find those? How can I trouble shoot this?
(I added a console output for the loggs just to check if filtering is ok, but it works also...)
Do mind that if you write logs using the ILogger interface with severity level "Information" like this _logger.LogInformation("Some Info"); you need to adjust the loglevel settings because the default settings only log trace telemetry of level warning and up.
You can modify that in the configuration (also, see the docs):
{
"Logging": {
"LogLevel": {
"Default": "Information"
},
"ApplicationInsights": {
"LogLevel": {
"Default": "Information"
}
}
}
}
You can use the transaction search in the portal:
Or you can query the workspace directly:

How to configure Serilog settings in Azure Function?

I’m in the process of creating my first production Azure Function and I’m trying to write log information to a local file and then eventually to Blob Storage. The local file is more for development troubleshooting and then ultimately I would like to have production information stored in Blob Storage. I’m not only new with Azure Functions but I’m also new with Serilog. I’ve used NLog in all my other applications but couldn’t get it to work with Azure Functions.
Currently I’m trying to get the local log working. I actually seem to have it working but I’m not understanding how I can tweak a couple things.
The first thing I’m trying to change is the amount of information that is getting logged. It seems to be logging a whole bunch of system type of information like Request info to the blob storage. There is so much stuff getting logged that what entry I'm adding in code gets lost. It looks like all the system entries are marked as Information which is why it’s probably showing up in my log. However, I would like to see if I could get it to only log data from when I specifically call the logger.Information(“some text”) in my code. Is there a way to suppress all of the Microsoft system information?
Second thing is how I can I make the Serilog configuration come from my local.settings.json file. Below is a sample of my file and I’m not sure if I would add the configuration information in the Values: property or if I would put it outside of that property into its own property? I’m assuming it would be in it’s own property but so far all my custom settings have been coming from the Values: property?
Do I need to add the Serilog.Settings.Configuration NuGet package? If so, then I’m not understanding how I configure my Startup.cs file to get the information from the local settings file instead of configuring the settings directly in code. Eventually, I would like to add it to Dependency Injection so I can use the logger in other classes as well.
Startup.cs
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddTransient<IDataManager, DataManager>();
ConfigureServices(builder.Services).BuildServiceProvider(true);
}
private IServiceCollection ConfigureServices(IServiceCollection services)
{
services
.AddLogging(loggingBuilder =>
loggingBuilder.AddSerilog(
new LoggerConfiguration()
.MinimumLevel.Information()
.WriteTo.Console()
.WriteTo.File(#"D:\logs\AzureFunction\log_.txt", rollingInterval: RollingInterval.Day)
.CreateLogger())
);
return services;
}
Local.settings.json
{
"IsEncrypted": false,
"Values": {
"ProcessLookBackDays": "90",
"SqlConnection": "connection info",
"StorageConnection": "connection info"
"AzureWebJobsStorage": "connection info"
"InputContainer": "test-files",
"InputFolder": "input",
"FUNCTIONS_WORKER_RUNTIME": "dotnet"
},
"Serilog": {
"Using": [ "Serilog.Sinks.File" ],
"MinimumLevel": {
"Default": "Information"
},
"WriteTo": [
{
"Name": "File",
"Args": {
"path": "D:\\logs\\AzureFunction\\log_.log",
"rollingInterval": "Day",
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} {CorrelationId} {Level:u3}] {Username} {Message:lj}{NewLine}{Exception}"
}
}
]
}
}
Setting up configuration in local-setting. Json will not reflect in the azure function app. local-setting as the name suggest is for local use only while with azure you need to use the app setting and read them.
Just add a new setting in the app setting and you can then use the below code to read the settings.
var appsettings = Environment.GetEnvironmentVariable("Name of the setting");
When you want to use the external configuration with serilog then you can use the Serilog.Settings.Configuration.
Now you can configure the minimum level of a log event so all the log event with less importance than the specified minimum level will not be logged.
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Information)
.CreateLogger();
Here we specify two things the .MinimumLevel.Debug() and restrictedToMinimumLevel this attribute dictates the minimum level for the that particular sink. A sink is just a place where you can log, they are configured using the Writeto tag. for e.g., in the above code the sink is a console. There are other sink too.
The minimum levels are verbose Debug, information, warning, error, fatal.
Reference:-
Read configuration from app setting by Ashish Patel
Use serilog to filter the logs
Serilog setting configuration

Azure Functions v2 - New .netcore Configuration and deployment

Now that we can use the hugely flexible configuration engine from .NETCore - we can do something like this :
private static IConfigurationRoot SetConfig(ExecutionContext executionContext)
{
return new ConfigurationBuilder()
.SetBasePath(executionContext.FunctionAppDirectory)
.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
}
Which is great as it allow you to put more complicated configuration data in the config file - for instance
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "<< removed >>",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"APPINSIGHTS_INSTRUMENTATIONKEY": "<< removed >>"
},
"MyCustomSettings": [
{
"ConnectionString": "<< removed >>",
"Folders": [
{
"ShareName": "share1",
"FolderName": "folder1"
},
{
"ShareName": "share2",
"FolderName": "folder2"
}
]
}
]
}
Again - great news! I can now get access to my strongly typed configuration with config["MyCustomSettings"]
What I don't get though - is how this can be deployed when publishing the function. Only the Values section is migrated to the Azure function Application Settings. I can obviously put this custom json in a json file and add it to the load statement like the local.settings.json
.AddJsonFile("my-custom-settings.json", optional: false, reloadOnChange: true)
but then this file has to be included in the deploy, and is not stored securely.
Any ideas?
This is not officially supported as of Nov 2019.
Warning
Avoid attempting to read values from files like local.settings.json or appsettings.{environment}.json on the Consumption plan. Values read from these files related to trigger connections aren't available as the app scales because the hosting infrastructure has no access to the configuration information.
There are so many blogs around advising to do this and it appears this may work if you only have a single instance, but as soon as the ScaleController triggers scaling, new instances will not be able to find the config files.
If you have triggers that use the %SettingName% syntax, they will not work as the function scales.
Functions team is considering possible Options (lol)
There is also the option of using the new App Configuration service but it is currently in preview and isn't available in all Azure regions.
It may be simpler to put your config in blob storage, and load it at startup? (Your blob store connectionstring will need to be in env variables)
So far the best we can do is to include your "not so secret" settings (things like MyThingTimeout or ExternalEndpointAddress) in a json file and use .AddJsonFile(...) and put secrets in KeyVault. This does force you to split your config and decide which goes where. (And also make sure your triggers only read from the Values section/Environment Variables)

Deploy .netcore to iis

I have a .net core app and runs fine on kestrel server.
http://localhost:5000/mapapi/v1.0/branch
I have deployed the app to IIS using publish tool in visual studio 2017 and with in program.cs, I have this line of code
.UseIISIntegration()
when I run the app I get an error
An error occurred while starting the application.
Exception: Cannot read variable
It is not reading the variable from launchsettings.json. I also created a profile by the name "IIS"
"IIS": {
"commandName": "iis",
"launchBrowser": true,
"launchUrl": "mapapi/v1.0/Branch",
"environmentVariables": {
"ConnectionString": "myhiddenconnectionstring",
}
}
What am I doing wrong? what other places do I have to look and make sure the application reads the values appropriately. Anyone in the community who had experience .net core to IIS, please share you knowledge with the community. We would appreciate it.

Azure Web App error 500 on Connection String

I've a simple ASP.NET Core 1.0 application which seeds some data in to SQL Server in Azure. I've 2 databases, one is for development and other is for Production (Azure SQL), I'm using Identity. When I run my application on my local machine, it works fine, but when I deploy it I get the error 500 (Internal Server Error) with no further explanation here is my code.
if (CurrentEnvironment.IsDevelopment())
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
}
else if (CurrentEnvironment.IsStaging() || CurrentEnvironment.IsProduction())
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Environment.GetEnvironmentVariable("SQLCONNSTR_kConnectionString")));
}
If I change the environment setting from Production to Development using Azure Application Settings, it says that error is at Configuration.GetConnectionString("DefaultConnection") saying connection string cannot be null.
There is a special pattern to be used, when you want to set the Variables from Environmental Variables.
In Azure App Service you set up your connection string as "DefaultConnection" or "SQLCONNSTR_kConnectionString" respectively, but you need to use. So if your connection string is "DefaultConnection", your appsetting.json must look like this
"ConnectionStrings" : {
"DefaultConnection" : "..."
}
when you obtain it with Configuration.GetConnectionString("DefaultConnection") (alternatively you can get it via Configuration["ConnectionStrings:DefaultConnection"]).
If you load it from environmental variables, it's better to override the default connection string via
var builder = new ConfigurationBuilder()
.SetBasePath(hostEnv.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{hostEnv.EnvironmentName}.json", optional: true, reloadOnChange: true);
.AddEnvironmentVariables();
Then the environmental variables will automatically override your settings in the appsettings.json or appsettings.Production.json.
If you want to get it via Environment.GetEnvironmentVariable you need to make it Environment.GetEnvironmentVariable("ConnectionStrings__SQLCONNSTR_kConnectionString") on Linux and Environment.GetEnvironmentVariable("ConnectionStrings:SQLCONNSTR_kConnectionString") on Windows. It's on top of my head, but the convention was something similar to this
I might misunderstand what you meant by "Azure SQL", but if you're using hosted Azure DB, then the prefix for the environment variable will be SQLAZURECONNSTR_ instead of SQLCONNSTR_. The latter would be used, for example, if you have SQL on your own VM in Azure (IaaS).
Also, it may help you to break apart your combined line of:
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Environment.GetEnvironmentVariable("SQLCONNSTR_kConnectionString")));
into separate lines, something like the following, then you might be able to diagnose the issue a bit easier.
var envConnectionString = Environment.GetEnvironmentVariable(...);
if (string.IsNullOrEmpty(envConnectionString))
{
// log error, throw exception, etc
}
else
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(envConnectionString)));
}
Thank for your respond, actually I resolved my issue. Since ASP.NET Core RC 2, we have to use
"publishOptions": {
"include": [
"wwwroot",
"Views",
"Areas/**/Views",
"appsettings.json",
"web.config"
] },
options in project.json in order work them. :)

Resources