Application Insights for .NET Core Azure WebJob - .net-core

When I try to setup my .NET Core WebJob to use Application Insights, I get the following Exception on startup:
System.InvalidOperationException: 'Unable to resolve service for type 'Microsoft.AspNetCore.Hosting.IHostingEnvironment' while attempting to activate 'Microsoft.AspNetCore.Hosting.DefaultApplicationInsightsServiceConfigureOptions'.'
I'm sure I'm overlooking something, but I can't find it out. My Main method is like in many examples, like here
public static void Main(string[] args)
{
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
Configuration.EnvironmentName = environment;
Configuration.IsDevelopment = string.Equals(environment, "Development");
var host = new HostBuilder()
.UseEnvironment("Development")
.ConfigureWebJobs(b =>
{
b.UseHostId("ecad61-62cf-47f4-93b4-6efcded6")
.AddAzureStorageCoreServices()
.AddAzureStorage()
.AddTimers()
.AddEventHubs();
})
.ConfigureServices(x => ConfigureServices(x))
.ConfigureAppConfiguration(b =>
{
b.AddJsonFile("appsettings.json", false, false);
b.AddJsonFile($"appsettings.{environment}.json", true);
b.AddEnvironmentVariables();
Configuration.Config = b.Build();
})
.ConfigureLogging((context, b) =>
{
b.AddConfiguration(Configuration.Config);
b.SetMinimumLevel(LogLevel.Trace);
b.AddConsole();
b.AddDebug();
//TODO fix applicationInsights
string appInsightsKey = context.Configuration["APPINSIGHTS_INSTRUMENTATIONKEY"];
if (!string.IsNullOrEmpty(appInsightsKey))
{
b.AddApplicationInsights(o => o.InstrumentationKey = appInsightsKey);
}
})
.Build();
using (host)
{
host.Run();
}
}

At first glance (and true shot in the dark), I would check to see if context.Configuration this throwing the exception because APPINSIGHTS_INSTRUMENTATIONKEY doesn't exist in the collection. The missing key could be throwing an exception that's bubbling up to your DI container.
EDIT: Trying giving this package a try and let me know if works. It's currently in pre-release. https://www.nuget.org/packages/Microsoft.Extensions.Logging.ApplicationInsights/
EDIT: The call to AddApplicationInsightsTelemetry uses DefaultApplicationInsightsServiceConfigureOptions is dependent on IHostingEnvironment. IHostingEnvironment isn't used by the WebJobsSDK which is causing your exception. The WebJobsSDK has it's on usage of Application Insights and you should be able to use it similarily to https://github.com/Azure/azure-webjobs-sdk/tree/dev/sample/SampleHost sample

Related

Dotnet 5 to 6 migration - application fails to start - How to use IIS?

I have migrated my web app from dotnet 5 to dotnet 6. Firstly, I updated dotnet version for all projects in solution, and then updated necessary nuget packages accordingly. After this, the application worked fine.
After that, I wanted to improve my Program.cs class, in order to get rid of Startup.cs. In dotnet 5, my program.cs looked like this:
public static int Main(string[] args)
{
.....
.....
var host = CreateHostBuilder(args).Build();
host.Run();
return 0;
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseNLog()
.ConfigureLogging((host, loggingBuilder) =>
{
loggingBuilder.ClearProviders();
if (host.HostingEnvironment.IsDevelopment())
{
loggingBuilder.AddConsole();
loggingBuilder.AddNLog(".\\nlog.config");
}
else
{
loggingBuilder.AddNLog(".\\nlog.config");
}
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseIIS();
webBuilder.UseStartup<Startup>();
});
I updated this to:
var builder = WebApplication.CreateBuilder(args);
builder.Host.ConfigureLogging((host, loggingBuilder) =>
{
loggingBuilder.ClearProviders();
if (host.HostingEnvironment.IsDevelopment())
{
loggingBuilder.AddConsole();
loggingBuilder.AddNLog(".\\nlog.config");
}
else
{
loggingBuilder.AddNLog(".\\nlog.config");
}
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseIIS();
//webBuilder.UseStartup<Startup>(); --> removed this
});
After this change, I get error:
I suspect, I cannot use ConfigureWebHostDefaults anymore. So how can I configure my app to UseIIS?
My hosting model is "InProc", and I cannot change that.
When I tried adding builder.Services.Configure<IISServerOptions>() or builder.WebHost.UseIIS();, but it only changed the error to:
The Event Logs show following two errors:
Application '/LM/W3SVC/1/ROOT/portal' with physical root 'C:\Users\zee\source\repos\Portal\Portal.Web\' has exited from Program.Main with exit code = '0'. Please check the stderr logs for more information.
Application '/LM/W3SVC/1/ROOT/portal' with physical root 'C:\Users\zee\source\repos\Portal\Portal.Web\' failed to load coreclr. Exception message: CLR worker thread exited prematurely
The docs HERE says that WebApplication.CreateBuilder calls Kestrel internally. How this behavior can be changed to use IIS instead?
I have tried few other things, but did not work.
Question:
Can someone point me to the right direction? Why there is no clear guidelines on using IIS? Several answers suggest that I should change to OutOfProc, which I cannot.

Serilog Cloudwatch logging not enriching the logs

I have used Serilog in the past and enriched logs with various properties. However I am playing around with the new AWS Lambda Serverless templates using .net core 3.1 and cannot get the logs to enrich. I have tried this in a basic Console app as well with the same result.
Example: code:
class Program
{
static void Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.AWSSeriLog(GetAwsSerilogConfiguration())
.Enrich.FromLogContext()
.Enrich.WithMachineName()
.CreateLogger();
using (LogContext.PushProperty("A", 1))
{
Log.Information("Starting web host");
Console.WriteLine("Hello World!");
}
}
private static AWSLoggerConfig GetAwsSerilogConfiguration()
{
var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
return new AWSLoggerConfig
{
LogGroup = $"AwsLoggingTestConsoleApp/{environmentName ?? "Development"}",
Region = RegionEndpoint.APSoutheast2.SystemName
};
}
}
The following screenshots from Cloudwatch Logs and Insights show the log generated by this code. The enriched property 'A' and MachineName do not appear
Cloudwatch Logs
Cloudwatch Insights
I feel like I am missing something obvious, but for the life of me I cannot see it.
Any ideas why the logs are not being enriched?
Many thanks,
M.

What's the correct way to set up NLog for logging in a .NET Core app?

What is the correct way to set up NLog logging for a .NET Core console application?
I see there is mention in Wiring and injected NLog into a .Net Core console application of using Microsoft.Extensions.Logging.ILogger somehow but no example and I'm having the same issue of getting a null. I tried the other examples in the posting but same thing, null object.
As an update, I got the code below to work by adding using statements for NLog.Config and then using the LogManager.GetCurrentClassLogger. I saw this in another post but I'm not sure why it works or if it's the correct way. So, I am still hoping someone can enlighten me on the correct way to get NLog setup in .NET Core or if this is the correct way, please let me know.
using Microsoft.Extensions.Logging;
using NLog;
using NLog.Config;
using NLog.Extensions.Logging;
static void Main(string[] args)
{
var logger = LogManager.GetCurrentClassLogger();
//service collection are were we register our services
var serviceCollection = new ServiceCollection();
ConfigureServices(serviceCollection);
serviceCollection.AddLogging();
//service provider is where we get our services
serviceProvider = serviceCollection.BuildServiceProvider();
//logging (ILoggerFactory requires Microsoft.Extensions.Logging dependency and adding a using statement)
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
//NLog.LogManager.LoadConfiguration("NLog.config");
//AddNLog required adding dependency NLog.Extensions.Logging and then adding a using statement
loggerFactory.AddNLog().ConfigureNLog("NLog.config");
logger.Debug("I successfully logged a debug via NLog!");
}
The best and most recent way to add and use NLog with support for ASP.Net Core 5 is described on github
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using NLog.Web;
namespace ASP.NET_Core_5_NLog_Example
{
public class Program
{
public static void Main(string[] args)
{
var logger = NLog.LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
try
{
logger.Debug("init main");
CreateHostBuilder(args).Build().Run();
}
catch (Exception exception)
{
//NLog: catch setup errors
logger.Error(exception, "Stopped program because of exception");
throw;
}
finally
{
// Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
NLog.LogManager.Shutdown();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.SetMinimumLevel(LogLevel.Trace);
})
.UseNLog(); // NLog: Setup NLog for Dependency injection
}
}

Application Insights in IHostedService console application

I am trying to enable Application Insights in a console application using IHostedService (for the moment, it's a simple console application which we run as WebJob, in future in containers).
As far as my knowledge goes, in the following code, so far we do not have any extension to register globally Application Insights as an implementation of ILogger:
public static class Program
{
public static Task Main(string[] args)
{
var hostBuilder = new HostBuilder()
.ConfigureHostConfiguration(config =>
{
config.SetBasePath(Directory.GetCurrentDirectory());
config.AddJsonFile("appsettings.json", optional: false);
config.AddEnvironmentVariables();
})
.ConfigureLogging((context, logging) =>
{
logging.AddConfiguration(context.Configuration.GetSection("Logging"));
if (context.HostingEnvironment.IsDevelopment())
{
logging.AddConsole();
}
else
{
//TODO: register ApplicationInsights
}
});
return hostBuilder.RunConsoleAsync();
}
}
So far, I found out that potentially, I should be able to set everything up using custom implementation of the logger, i.e. public class ApplicationInsightsLogger : ILogger, and then... register it in the container so that DI resolves it.
Is this the right direction?
I made an extension that I could use from either an IHost or an IWebHost:
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.ApplicationInsights;
public static class LoggingBuilderExtensions
{
public static ILoggingBuilder AddLogging(this ILoggingBuilder loggingBuilder)
{
loggingBuilder.AddFilter<ApplicationInsightsLoggerProvider>("", LogLevel.Trace);
loggingBuilder.AddAzureWebAppDiagnostics();
loggingBuilder.AddApplicationInsights();
return loggingBuilder;
}
}
Since I'm not sending in the context (HostBuilderContext or WebHostBuilderContext), I can use it in either app type like this:
new HostBuilder().ConfigureLogging(loggingBuilder => loggingBuilder.AddLogging())
or
WebHost.CreateDefaultBuilder().ConfigureLogging(loggingBuilder => loggingBuilder.AddLogging())
If you needed a specific property from the context (like environment type), you could extract that and send it in as a parameter to the extension.
Here's a reference: https://github.com/Microsoft/ApplicationInsights-dotnet-logging/blob/develop/src/ILogger/Readme.md

Log event datetime with.Net Core Console logger

I'm using logging to Console output, that built-in to .Net Core framework.
Here initialization of the logger:
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton(new LoggerFactory()
.AddConsole());
Also for logging I'm using Microsoft.Extensions.Logging.LoggerExtensions class with methods Log...
Here an example of logging in my App:
_logger.LogInformation(eventId, "Action is started.");
Where _logger is instance of ILogger<T> class and initialized in the class constructor with built-in dependency injection.
As result of calling of the above method Console output shows following string:
info: NameSpaceName.ClassName[eventId] Action is started.
I would like to display date-time in the Console output, that points to time, when the Log method is executed, but it seems that Log.. methods don't contain any methods that allow to display date time.
Does it exist some method or additioanl classes-formatters that allow to display the action datetime in console output without passing it to the method as part of the message?
The feature was added into version 3 of the Microsoft.Extensions.Logging.Console(here is the pr). You can activate this with setting the TimestampFormat:
new ServiceCollection()
.AddLogging(opt =>
{
opt.AddConsole(c =>
{
c.TimestampFormat = "[HH:mm:ss] ";
});
})
Example in .NET 5 (ASP.NET Core):
public void ConfigureServices(IServiceCollection services)
{
services.AddLogging(options =>
{
options.AddSimpleConsole(c =>
{
c.TimestampFormat = "[yyyy-MM-dd HH:mm:ss] ";
// c.UseUtcTimestamp = true; // something to consider
});
});
// ...
}
Output example:
[2020-12-13 12:55:44] info: Microsoft.Hosting.Lifetime[0] Application is shutting down...
For ASP.NET Core, you might prefer to use configuration file appsettings.json over wiring it directly into the code.
{
"Logging": {
"Console": {
"TimestampFormat": "[yyyy-MM-dd HH:mm:ss] "
}
}
}
This works out of the box, provided that Host.CreateDefaultBuilder() is invoked in Program.cs
Built-in .NET Core console logger doesn't log date-time. Track this issue to get more details. The easiest workaround is:
logger.Log(LogLevel.Information, 1, someObj, null, (s, e) => DateTime.Now + " " + s.ToString());
I wrote a custom console logger to automatically log the timestamp and do other useful tricks:
[2017.06.15 23:46:44] info: WebHost[1] Request starting HTTP/1.1 GET http://localhost:6002/hc

Resources