Azure specific implementation of telemetry logging. Uses the ITelemeteryLogger interface from Cloud.Core and can be used in conjunction with the Telemetry Logging Provider classes found in the Cloud.Core.Telemetry.Logging package.
As the logger follows the base ILogger
implementation, it's very flexible in how it can be used. To create an instance, do the following:
var logger = new AppInsightsLogger("insightsKey");
logger.LogInformation("Sample information message");
logger.LogWarning("Sample warning message");
logger.LogDebug("Sample debug message");
logger.LogException("Sample exception message");
Any of the logging methods can also handle exception, such as:
logger.LogWarning(new Exception("Something's gone wrong!"));
There are a number of ways to create an instance of the AppInsights logger, the simpliest and most direct way is the following:
var logger = new AppInsightsLogger("instrumentationKey", LogLevel.Debug);
A typical use case is as an instance of the ITelemetryLogger
interface and with an IServiceCollection. Therefore, leveraging the extensions methods that have been built for convenience as follows during the Logger configuration is probably easier:
private static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(config => {
// Import default configurations (env vars, command line args, appSettings.json etc).
config.UseDefaultConfigs();
})
.ConfigureLogging((context, logging) => {
// Add logging configuration and loggers.
logging.AddConfiguration(context.Configuration)
.AddConsole()
.AddDebug()
.AddAppInsightsLogger(); // automatically resolves instrumentation key and log levels.
})
.UseStartup<Startup>();
Here we can see we did not specify the config level or the instrumentation key. The instrumentation key is resolve automatically by pulling one of the following from config:
- InstrumentationKey
- APPINSIGHTS_INSTRUMENTATIONKEY
- Logging:InstrumentationKey
- AppInsights:InstrumentationKey
If It cannot find it here, it will throw an invalid argument exception.
public class Startup
{
public void ConfigureAppConfiguration(IConfigurationBuilder builder)
{
// Import default configurations (env vars, command line args, appSettings.json etc).
builder.UseDefaultConfigs();
}
public void ConfigureLogging(IConfiguration config, ILoggingBuilder builder)
{
builder.AddConfiguration(config.GetSection("Logging"));
// Add some default loggers.
builder.AddConsole();
.AddDebug();
// Explicitly specifying the instrumentation key.
var instrumentationKey = config.GetValue<string>("InstrumentationKey");
builder.AddAppInsightsLogger(instrumentationKey);
}
public void ConfigureServices(IConfiguration config, ILogger logger, IServiceCollection services)
{
// Configure services...
}
}
The second example (explicit setting of instrumentation key), you pass it an instruementation key you have loaded yourself.
Both examples above will look for log level from config specified in the "Logging:LogLevel:Telemetry" setting. If it cannot find that, it will default to Logging:LogLevel:Default for its setting. Failing that, it falls back to info.
ITelemeteryLogger logger = new AppInsightsLogger("instrumentationKey");
// Log metrics stats.
logger.LogMetric("Metric Name", 100);
// Log custom dimensions (as dictionary).
logger.LogInformation("Some log message", new Dictionary<string, string> {
{ "dimension1", "someVal" },
{ "dimension2", "someOtherVal" }
});
// Log custom dimensions (as object). This functionality allows for Pii data masking.
logger.LogInformation("Some log message", new ExampleModel { Property1 = "someval", Property2 = true });
Take this model that has Personal Data (Pii) flagged as an example:
public class ExampleModel {
public string Id { get; set; }
[PersonalData]
public string Name { get; set; }
public bool IsActive { get; set; }
}
When we log the model, the Name
field will be masked:
// Pii data model.
var model = new ExampleModel {
Id = "12345",
Name = "Robert",
IsActive = true
};
// Logging model allows for Pii data masking.
logger.LogInformation("Some log message", model);
NOTE: Fields that have been marked as Cloud.Core.Attributes.PersonalData
, Cloud.Core.Attributes.SensitiveInfo
or Microsoft.AspNetCore.Identity.PersonalData
are masked automatically when writing custom dimensions. The log message itself and the dicntionary are not checked for personal information - masking can only be used when logging a model (as then the properties can be reflected and inspected for the appropriate attributes).
Read more about logging providers and filters here: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-3.1
A threshold will be added to this package to ensure the test coverage is above 80% for branches, functions and lines. If it's not above the required threshold (threshold that will be implemented on ALL of the core repositories to gurantee a satisfactory level of testing), then the build will fail.
This package has has been written in .net Standard and can be therefore be referenced from a .net Core or .net Framework application. The advantage of utilising from a .net Core application, is that it can be deployed and run on a number of host operating systems, such as Windows, Linux or OSX. Unlike referencing from the a .net Framework application, which can only run on Windows (or Linux using Mono).
This package is built using .net Standard 2.1 and requires the .net Core 3.1 SDK, it can be downloaded here: https://www.microsoft.com/net/download/dotnet-core/
IDE of Visual Studio or Visual Studio Code, can be downloaded here: https://visualstudio.microsoft.com/downloads/
All of the Cloud.Core.* packages are published to a public NuGet feed. To consume this on your local development machine, please add the following feed to your feed sources in Visual Studio: https://dev.azure.com/cloudcoreproject/CloudCore/_packaging?_a=feed&feed=Cloud.Core
For help setting up, follow this article: https://docs.microsoft.com/en-us/vsts/package/nuget/consume?view=vsts