Disable application insights in debug - c#

How can I disable application insights automatically when using a debug configuration and enable it only on release?
Is it possible to do this without creating another instrumentation key only for debug?
I have trackevent statements scattered all over the code, enclosing them inside a debug preprocessor check is not an ideal solution.
My current solution is to set the Build Action of the ApplicationInsights.config file to None so that it's not copied to the project's output directory, but this isn't a process that can be automated based on the active build configuration.
There is a Developer Mode but needs to be changed manually (if it was possible to conditionally set the config file, emptying the instrumentationkey solved problem as well). See http://apmtips.com/blog/2015/02/02/developer-mode/
Reference: http://blogs.msdn.com/b/visualstudioalm/archive/2015/01/07/application-insights-support-for-multiple-environments-stamps-and-app-versions.aspx

You can try to use TelemetryConfiguration.DisableTelemetry Property
Something like this way..
#if DEBUG
TelemetryConfiguration.Active.DisableTelemetry = true;
#endif

As an addition to the other solutions I would suggest to add the following let's say to the Global.asax:
protected void Application_Start()
{
DisableApplicationInsightsOnDebug();
// do the other stuff
}
/// <summary>
/// Disables the application insights locally.
/// </summary>
[Conditional("DEBUG")]
private static void DisableApplicationInsightsOnDebug()
{
TelemetryConfiguration.Active.DisableTelemetry = true;
}
The advantage of this is, that it needs no change to the configs and it works better with some tools like ReSharper which will understand it better than #-directives.

NOTE: This option only existed in Visual Studio 2019
For ASP.NET Core projects the App Insights are ON by default, which actually logs a ton of info into debug window.
To disable it go to "TOOLS --> Options --> Projects and Solutions --> Web Projects" and check "Disable local Application Insights for Asp.Net Core web projects."
Below is the image for disabling local app insights.
For more info on the issue you can see the official github issue here

Running an ASP.NET Core 2.1 web application with Visual Studio 2017 (15.9.2) the "Disable local Application Insights for Asp.Net Core web projects" did not clear up the output in my Debug window.
However adding the following to Configure() in Startup.cs did the job;
if (_env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
TelemetryConfiguration.Active.DisableTelemetry = true;
TelemetryDebugWriter.IsTracingDisabled = true;
}
Note that the IsTracingDisabled was the key solution, but I left in DisableTelemetry for good measure! Plus having both lines next to one another is helpful when searching for similar references between .NET Framework & .NET Core projects in the same solution.

As explained in the question not deploying or deploying an ApplicationInsights.config without <instrumentationkey>key</instrumentationkey> block events from being generated.
You can then put the instrumentation key in code (only on release in my case)
#if !DEBUG
Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration.Active.InstrumentationKey = "instrumentation key";
#endif
Every TelemetryClient created after this call will have the correct key and will track events so you don't have to change the code in all places.
Not calling the method above or leaving the parameter empty will block events because there isn't a key configured.
Basically the ApplicationInsights.config file overrides any code that set the instrumentation key, removing the <instrumentationkey>key</instrumentationkey> inside it will let you use code to configure the key.
If you remove the file completely it doesn't work.
Here is the confirm:
"If you want to set the key dynamically - for example if you want to send results from your application to different resources - you can omit the key from the configuration file, and set it in code instead."
Reference: https://azure.microsoft.com/en-us/documentation/articles/app-insights-configuration-with-applicationinsights-config/#_instrumentationkey

As of ASP.NET Core 3.1:
To disable logging any App Insights telemetry to Azure:
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
TelemetryConfiguration configuration)
{
configuration.DisableTelemetry = true;
}
To disable logging telemetry events to the Output window:
TelemetryDebugWriter.IsTracingDisabled = true;
(the above can be called from anywhere, but the sooner in your application's lifecycle, the better).
Both can be used together to suppress all Application Insights activity in your code. I guard with an #if DEBUG directive to ensure that AppInsights does nothing on my local machine, but does emit events when published to our dev server in the Azure cloud:
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
TelemetryConfiguration configuration)
{
if (env.IsDevelopment())
{
#if DEBUG
configuration.DisableTelemetry = true;
TelemetryDebugWriter.IsTracingDisabled = true;
#endif
}
}

I have decided to use both approaches. I have moved the InstrumentationKey to the Web.config and it will be replaced by the transformation from Web.Release.config or Web.Debug.config. (don't forget to remove it from the ApplicationInsights.config file). Then I have called this method from the Application_Start()
public static void RegisterTelemetryInstrumentationKey()
{
if (string.IsNullOrWhiteSpace(WebConfigurationManager.AppSettings["TelemetryInstrumentationKey"])
{
TelemetryConfiguration.Active.DisableTelemetry = true;
}
else
{
TelemetryConfiguration.Active.InstrumentationKey = AppSettings.TelemetryInstrumentationKey;
}
}

I've just had the same issue.
We wanted to control the setting in the web.config so added a DisableAITelemetry key within our app settings:
<appSettings>
<add key="DisableAITelemetry" value="true" />
</appSettings>
With live and demo builds, we won't include a value (so that it defaults to false).
We could then solve it by adding this:
bool disable;
string disableAiTelemetry = ConfigurationManager.AppSettings["DisableAITelemetry"];
bool.TryParse(disableAiTelemetry, out disable);
TelemetryConfiguration.Active.DisableTelemetry = disable;

Slightly different play on some of the other solutions. Put this in your global.asax:
Microsoft.ApplicationInsights.Extensibility.Implementation.TelemetryDebugWriter.IsTracingDisabled = Debugger.IsAttached;
It will turn off app insights debug output when running under the debugger, but allow it under Ctrl+F5 scenarios and debug builds published to test servers

We've found the easiest way to prevent it from tracing into the Debug log is as simple as:
Extensibility.Implementation.TelemetryDebugWriter.IsTracingDisabled = True

In an ASP.NET Core application, you can add the following to the Startus.cs to turn off Application Insights in the Development environment:
if (env.IsDevelopment()) {
TelemetryConfiguration.Active.DisableTelemetry = true;
}
Add this to the constructor, right after the builder.AddApplicationInsightsSettings(); command and you'll no longer see AI logs clogging up your debug console.

Microsoft.ApplicationInsights.AspNetCore Version 2.1
services.AddApplicationInsightsTelemetry(options =>
{
options.EnableDebugLogger = false;
});

The solution suggested above has been deprecated (reference: https://github.com/microsoft/applicationinsights-dotnet/issues/1152). In dotnet core the new way to dynamically disable telemetry is this:
public void ConfigureServices(IServiceCollection services)
{
services.AddApplicationInsightsTelemetry();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, TelemetryConfiguration configuration)
{
configuration.DisableTelemetry = true;
...
}
(reference: https://learn.microsoft.com/en-us/azure/azure-monitor/app/asp-net-core#disable-telemetry-dynamically)
And if you want to disable telemetry in a custom WebApplicationFactory (when doing integration tests) you can do this:
public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices((context, services) =>
{
// Disable application insights during testing.
services.Configure<TelemetryConfiguration>(
(telemetryConfig) => {
telemetryConfig.DisableTelemetry = true;
});
});
base.ConfigureWebHost(builder);
}
}
For more context about integration testing see https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-5.0

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
#region Disable Application Insights debug informations
#if DEBUG
TelemetryConfiguration.Active.DisableTelemetry = true;
TelemetryDebugWriter.IsTracingDisabled = true;
#endif
#endregion
//...
}

Since .NET Core 3.1:
var telemetryConfiguration = TelemetryConfiguration.CreateDefault();
telemetryConfiguration.DisableTelemetry = true;
var telemetryClient = new TelemetryClient(telemetryConfiguration); // Use this instance
TelemetryDebugWriter.IsTracingDisabled = true;

We can modify the file “appsetting.json” and add the following attributes
"ApplicationInsights": {
"EnableRequestTrackingTelemetryModule": false,
"EnableEventCounterCollectionModule": false,
"EnableDependencyTrackingTelemetryModule": false,
"EnablePerformanceCounterCollectionModule": false,
"EnableDiagnosticsTelemetryModule": false
}
More information you can find here.

Related

Application Insights is not including properties set by custom ITelemetryInitializer

(Added UPDATE 1 below which I think answers this question)
In a fairly simple ASP.NET Core 2 web app I have initialized in Program like this:
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseApplicationInsights()
.Build();
I haven't configured an instrumentation key in appSettings.json yet because for now I'm running locally. When I run my app and force an exception on load of my home page I can see the exception logged in Visual Studio's telemetry search for Application Insights.
I now want to capture some details about the request in every logged event. I've followed some guidance and created an implementation of ITelemetryInitializer:
public class CustomTelemetryInitializer : ITelemetryInitializer
{
private const string UserIdKey = "UserId";
private readonly IUserService _userService;
public CustomTelemetryInitializer(IUserService userService)
{
_userService = userService;
}
public void Initialize(ITelemetry telemetry)
{
if (!(telemetry is RequestTelemetry requestTelemetry)) return;
var props = requestTelemetry.Properties;
if (!props.ContainsKey(UserIdKey))
{
var user = _userService.GetCurrentUser();
if (user != null)
{
props.Add(UserIdKey, user.UserId);
}
}
}
}
This is largely following this guide. IUserService is just a service which uses IHttpContextAccessor to get the current ClaimsPrincipal. You can see I'm trying to add the user's ID to the custom telemetry properties.
I've registered this ITelemetryInitializer in Startup like this:
services.AddSingleton<ITelemetryInitializer, CustomTelemetryInitializer>();
When I run my app again, I can see the debugger running through CustomTelemetryInitializer and setting the property correctly. However, when I review the events logged in app insights, the custom property is not included. They look identical to the screenshot above.
I've tried moving the app insights initialization out of Program and instead initializing it in Startup after registering the ITelemetryInitializer using services.AddApplicationInsightsTelemetry(), but this makes no difference.
Anyone know what I'm doing wrong?
UPDATE 1
I've realised I made a mistake. My custom properties are being included for Request events after all. But not the Exception events. But I've now realised that these Exception events take a different implementation of ITelemetry in Initialize i.e. TraceTelemetry. So I hadn't realised I was excluding these events from my custom properties.
Glad you figured it out.
All ITelemetry implementations in the SDK implements, ISupportProperties which gives it Properties collection. If you want to attach properties to every telemetry, you can cast to ISupportProperties and set props.

How to use separate connection strings for Application and Migrations?

I am trying to get an ASP.NET Core 2 with EntityFramework Core 2.0 application up and running. As part of it, also looking to start using Migrations to manage data model changes.
Here is my appsettings.json file where I am storing connection strings. For keeping things simple here, I left the user/pwd open. In real scenario, encryption will be used. Main goal is to use two separate connection strings. One for Application usage, where the user account TestAppServiceAccount will be used only to perform reads/writes (DML operations only). Another one called DbChangeServiceAccount for applying migrations (DML + DDL operations).
{
"SqlServerMigrationsConnection": "Server=SqlServerInstance;Database=TestDb;User Id=DbChangeServiceAccount; Password=xyz$123;",
"SqlServerAppConnection": "Server=SqlServerInstance;Database=TestDb;User Id=TestAppServiceAccount; Password=xyz$123;"
}
Here is how my Startup.cs is setup. Based on my understanding, looks like both application and Migrations are going to depend on the same connection string that is passed in startup.cs to AddDbContext method.
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
var userServiceSqlConnection = Configuration["SqlServerAppConnection"];
services.AddDbContext<UserContext>(optiopns => optiopns.UseSqlServer(userServiceSqlConnection));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
}
Just wondering how do I pass a different connection strings, one that will be used purely for application and another one for just applying migrations?
After posting this question, I realized that, I could make use of multi environment setup.
So for migrations I will have a separate environment that will be used to manage CI/CD activities. I feel like this is a deployment concern,
So I could simply create appsettings.migrations.json or something similar and fall back to use just one connection string for both Application and Migrations. And my Startup.cs AddDbContext parameters will stay same.
My appsettings.development.json will look like
{
"SqlServerAppConnection": "Server=SqlServerInstance;Database=TestDb;User Id=TestAppServiceAccount; Password=xyz$123;"
}
My appsettings.migrations.json will look like
{
"SqlServerAppConnection": "Server=SqlServerInstance;Database=TestDb;User Id=DbChangeServiceAccount; Password=xyz$123;"
}
How to manage multiple environments in asp.net core from Microsoft has more details.

HangFire dashboard not displaying in PROD

I am using HangFire to schedule jobs but when I deployed to PROD, the website/hangfire url is not working. I am getting The system cannot find the file specified error.
On localhost, I am able to open the URL.
I followed this URL: http://docs.hangfire.io/en/latest/quick-start.html
Anyone know what I am missing.
Thanks
Hangfire Dashboard exposes sensitive information about your background jobs, including method names and serialized arguments as well as gives you an opportunity to manage them by performing different actions – retry, delete, trigger, etc. So it is really important to restrict access to the Dashboard.
To make it secure by default, only local requests are allowed, however you can change this by passing your own implementations of the IAuthorizationFilter interface, whose Authorize method is used to allow or prohibit a request. The first step is to provide your own implementation.
http://docs.hangfire.io/en/latest/configuration/using-dashboard.html#configuring-authorization
As Hangfire dashboard exposes sensitive information about your job which includes method names and serialized arguments. Also user can perform different actions like retry, trigger, delete etc. So it is very important to authenticate access to Dashboard.
By default Hangfire allows access to Dashboard pages only for local requests. In order to give appropriate rights for production or testing or UAT users, add your own implementation of authorization using the IDashboardAuthorizationFilter interface for the hangfire dashboard.
http://docs.hangfire.io/en/latest/configuration/configuring-authorization.html
See my sample code below
public class HangfireAuthorizationFilter : IDashboardAuthorizationFilter
{
private readonly string[] _roles;
public HangfireAuthorizationFilter(params string[] roles)
{
_roles = roles;
}
public bool Authorize(DashboardContext context)
{
var httpContext = ((AspNetCoreDashboardContext)context).HttpContext;
//Your authorization logic goes here.
return true; //I'am returning true for simplicity
}
}
Asp.net core startup class changes in Configure(IApplicationBuilder app, IHostingEnvironment env) method
Configure(IApplicationBuilder app, IHostingEnvironment env){
......
app.UseHangfireServer();
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
DashboardTitle = "Sample Jobs",
Authorization = new[]
{
new HangfireAuthorizationFilter("admin")
}
});
......
}
Maybe a late answer but might be usefull.
In my case, I had this code :
public class Startup
{
public void Configuration(IAppBuilder app)
{
#if !DEBUG
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
Authorization = new[] { new HangfireAuthFilter() }
});
#endif
}
}
}
It wasn't working on prod.
I realized that when I copy the application dll from the bin folder, it takes the debug configuration and doesn't start the hangfire.
When I publish the application via visual studio and than copy the DLL from the bin folder of published folder, it works correctly.

ASP.NET 5 Template crashes on first run

I'm starting a new project in VS 2015.
File -> New -> Project -> ASP.NET Web Application -> ASP.NET 5 Templates -> Web API
A project is initialized. I would assume that if I run the project with IIS Express a service would be available.
It runs through the startup methods.
public class Startup
{
public Startup(IHostingEnvironment env)
{
// Set up configuration sources.
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; set; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseIISPlatformHandler();
app.UseStaticFiles();
app.UseMvc();
}
// Entry point for the application.
public static void Main(string[] args) =>
WebApplication.Run<Startup>(args);
}
}
But then it crashes. I don't know how to implement global error handling.
I looked at this example.
But when I try to use System.Net.Http or System.Web.Http.ExceptionHandling they can't be found.
I also noticed that through intellisense it says Core 5.0 is no available.
Here is my project.json as requested.
{
"version":"1.0.0-*",
"compilationOptions":{
"emitEntryPoint":true
},
"dependencies":{
"Microsoft.AspNet.IISPlatformHandler":"1.0.0-rc1-final",
"Microsoft.AspNet.Mvc":"6.0.0-rc1-final",
"Microsoft.AspNet.Server.Kestrel":"1.0.0-rc1-final",
"Microsoft.AspNet.StaticFiles":"1.0.0-rc1-final",
"Microsoft.Extensions.Configuration.FileProviderExtensions":"1.0.0-rc1-final",
"Microsoft.Extensions.Configuration.Json":"1.0.0-rc1-final",
"Microsoft.Extensions.Logging":"1.0.0-rc1-final",
"Microsoft.Extensions.Logging.Console":"1.0.0-rc1-final",
"Microsoft.Extensions.Logging.Debug":"1.0.0-rc1-final"
},
"commands":{
"web":"Microsoft.AspNet.Server.Kestrel"
},
"frameworks":{
"dnx451":{
"frameworkAssemblies":{
"System.Web":"4.0.0.0"
}
},
"dnxcore50":{
}
},
"exclude":[
"wwwroot",
"node_modules"
],
"publishExclude":[
"**.user",
"**.vspscc"
]
}
Try to open Visual Studio Administrator Mode
I guess it depends on what is crashing - it's not clear from your description what crashes, when it crashes and how it crashes.
You can use UseExceptionHandler and UseDeveloperExceptionPage extension methods to configure an error handling page. This article describes it in more details.
If the exception happens during startup you may need to use UseCaptureStartupErrors extension method (it was recently renamed to CaptureStartupErrors).
Also, you already have logging enabled - the logs may also have some useful information. If you can't see logs because you log to the console consider logging to a file.
If this is IIS/IISExpress crashing check event log.
What is your runtime version ?
Maybe you can try scaffolding your application with the AspNet Yeoman generator and compare the files.
Personally I prefer to use the scaffolder as it is often up to date.
Hope this helps !

How to register different services for different environments in ASP.NET MVC 6?

What is the right way to configure services for different environments?
For example I want to add FakeService to services collection for DEV configuration and RealService for Release configuration.
public void ConfigureServices(IServiceCollection services)
{
/* Need to check environment */
services.AddSingleton<IService, FakeService>();
....
}
MVC 6 has a value that defines what environment it is, this can be set by the environment variable ASPNET_ENV. You can grab that value from IHostingEnvironment:
public void ConfigureServices(IServiceCollection services)
{
var env = services.BuildServiceProvider().GetRequiredService<IHostingEnvironment>();
if (env.IsDevelopment())
Console.WriteLine("Development");
else if (env.IsProduction())
Console.WriteLine("Production");
else if (env.IsEnvironment("MyCustomEnvironment"))
Console.WriteLine("MyCustomEnvironment");
}
You can set the value in VS2015 on your project by Right-click > Properties > Debug > Environment Variables:
Here's some more info on configuring with environment variables.
It's just a matter of reading this from your configuration file, and making a decision in code accordingly:
bool isDev = Boolean.Parse(ConfigurationManager.AppSettings["IsDev"]);
if (isDev) {
services.AddSingleton<IService, FakeService>();
} else {
services.AddSingleton<IService, RealService>();
}
Another option is to use compiler directives:
if #DEBUG
services.AddSingleton<IService, FakeService>();
#else
services.AddSingleton<IService, RealService>();
#endif
While in debug configuration there is a DEBUG defined constant (automatically defined by Visual Studio) while there is no such constant defined for release mode.
if #DEBUG will work only for debug.
Check out the conditional methods https://msdn.microsoft.com/en-us/library/aa288458(v=vs.71).aspx
Use [Conditional("DEV")] or [Conditional("RELEASE")] before that method. It will execute when it matches mentioned configuration.
I'd suggest adding a layer of indirection. That is, use the IoC container to inject the appropriate version of the service:
services.AddService(container.Resolve<IMyServiceType>);
... of course you'll need to make sure the container returns the appropriate type for each environment.
I'm not sure you can do this with the default IoC container though; you might need to replace it with Ninject, Autofac, or whatever.

Categories

Resources