skip to Main Content

Why is it that when I inject ILogger<MyClassName> and call Logger.LogInformation I don’t see that in Application Insights, but when I call Logger.LogError I do?

Here is my code

    public async ValueTask DeleteMessageAsync(string chatId, int messageId)
    {
        Logger.LogInformation(
            "Deleting message: {chatId} {messageId}",
            chatId,
            messageId);

        try
        {
            await TelegramBotClient.DeleteMessageAsync(chatId, messageId);
        }
        catch (ApiRequestException ex)
            when (ex.ErrorCode == (int)HttpStatusCode.BadRequest)
        {
            Logger.LogError(ex, "Could not Delete message");
        }
    }

Here is an example of the event showing up in the Live Metrics section of Application Insights.

Live Metrics

Here is the result of searching for that InvokationId

Search

I also get zero results when searching for the word "Piff", which is clearly in the live view.

Here is the logging section of my host.json file

  "logging": {
    "applicationInsights": {
      "samplingSettings": {
        "isEnabled": true,
        "excludedTypes": "Request"
      },
      "enableLiveMetricsFilters": true
    },
    "DurableTask.AzureStorage": "Information",
    "DurableTask.Core": "Information",
    "logLevel": {
      "Default": "Information",
      "Microsoft": "Information",
      "Microsoft.Hosting.Lifetime": "Information"
    }
}

Here is the host builder for my Azure functions app

IHost host = new HostBuilder()
    .AddServiceDefaults(useOtlpExporter: false, isDevelopment: true)
    .ConfigureFunctionsWorkerDefaults()
    .ConfigureServices(services =>
    {
        services.AddApplicationInsightsTelemetryWorkerService();
        services.ConfigureFunctionsApplicationInsights();
        services.AddSingleton<ITelegramBroadcastService, TelegramBroadcastService>();
        services.AddSingleton<IAuthorizationService, AuthorizationService>();
        services.AddDurableTaskClient(x =>
        {
        });
        services.AddAzureClients(clientBuilder =>
        {
            clientBuilder.AddBlobServiceClient(Environment.GetEnvironmentVariable("AzureWebJobsStorage"));
        });
    })
    .ConfigureAppConfiguration((context, config) =>
    {
        if (context.HostingEnvironment.IsDevelopment())
            config.AddUserSecrets<Program>();
    })
    .Build();

host.Run();

The AddServiceDefaults extension is the one added by default in a new Aspire app.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Logging;
using OpenTelemetry.Logs;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;

namespace Microsoft.Extensions.Hosting;

public static class Extensions
{
    public static T AddServiceDefaults<T>(this T builder, bool useOtlpExporter, bool isDevelopment)
        where T : IHostBuilder
    {
        builder.ConfigureOpenTelemetry(
            useOtlpExporter: useOtlpExporter,
            isDevelopment: isDevelopment);
        builder.AddDefaultHealthChecks();
        builder.AddServiceDiscovery();
        return builder;
    }

    public static T AddServiceDiscovery<T>(this T builder)
        where T : IHostBuilder
    {
        builder.ConfigureServices(services =>
        {
            services.AddServiceDiscovery();
        });
        return builder;
    }

    public static T ConfigureHttpClientDefaults<T>(this T builder)
        where T : IHostBuilder
    {
        builder.ConfigureServices(services =>
        {
            services.ConfigureHttpClientDefaults(http =>
            {
                // Turn on resilience by default
                http.AddStandardResilienceHandler();

                // Turn on service discovery by default
                http.UseServiceDiscovery();
            });
        });
        return builder;
    }

    public static T ConfigureOpenTelemetry<T>(this T builder, bool useOtlpExporter, bool isDevelopment)
        where T : IHostBuilder
    {
        builder.ConfigureLogging(logging =>
        {
            logging.AddOpenTelemetry(telemetry =>
            {
                telemetry.IncludeFormattedMessage = true;
                telemetry.IncludeScopes = true;
            });
        });

        builder.ConfigureServices(services =>
        {
            services.AddOpenTelemetry()
                .WithMetrics(metrics =>
                {
                    metrics.AddRuntimeInstrumentation()
                           .AddBuiltInMeters();
                })
                .WithTracing(tracing =>
                {
                    if (isDevelopment)
                    {
                        // We want to view all traces in development
                        tracing.SetSampler(new AlwaysOnSampler());
                    }

                    tracing.AddAspNetCoreInstrumentation()
                           .AddGrpcClientInstrumentation()
                           .AddHttpClientInstrumentation();
                });
        });

        builder.AddOpenTelemetryExporters(useOtlpExporter);

        return builder;
    }

    private static T AddOpenTelemetryExporters<T>(this T builder, bool useOtlpExporter)
        where T : IHostBuilder
    {
        builder.ConfigureServices(services =>
        {
            if (useOtlpExporter)
            {
                services.Configure<OpenTelemetryLoggerOptions>(logging => logging.AddOtlpExporter());
                services.ConfigureOpenTelemetryMeterProvider(metrics => metrics.AddOtlpExporter());
                services.ConfigureOpenTelemetryTracerProvider(tracing => tracing.AddOtlpExporter());
            }

            // Uncomment the following lines to enable the Prometheus exporter (requires the OpenTelemetry.Exporter.Prometheus.AspNetCore package)
            //services
            //    .AddOpenTelemetry();
            //    .WithMetrics(metrics => metrics.AddPrometheusExporter());

            // Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.Exporter package)
            //services
            //    .AddOpenTelemetry()
            //    .UseAzureMonitor();
        });
         
        return builder;
    }

    public static T AddDefaultHealthChecks<T>(this T builder)
        where T : IHostBuilder
    {
        builder.ConfigureServices(services =>
        {
            services.AddHealthChecks()
                // Add a default liveness check to ensure app is responsive
                .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]);
        });
        return builder;
    }

    public static WebApplication MapDefaultHealthCheckEndpoints(this WebApplication app)
    {
        // Uncomment the following line to enable the Prometheus endpoint (requires the OpenTelemetry.Exporter.Prometheus.AspNetCore package)
        // app.MapPrometheusScrapingEndpoint();

        // All health checks must pass for app to be considered ready to accept traffic after starting
        app.MapHealthChecks("/health");

        // Only health checks tagged with the "live" tag must pass for app to be considered alive
        app.MapHealthChecks("/alive", new HealthCheckOptions
        {
            Predicate = r => r.Tags.Contains("live")
        });

        return app;
    }

    private static MeterProviderBuilder AddBuiltInMeters(this MeterProviderBuilder meterProviderBuilder) =>
        meterProviderBuilder.AddMeter(
            "Microsoft.AspNetCore.Hosting",
            "Microsoft.AspNetCore.Server.Kestrel",
            "System.Net.Http");
}

Here are the app settings that are applied according to portal.azure.com

{
    "deployment_branch": "master",
    "SCM_TRACE_LEVEL": "Verbose",
    "SCM_COMMAND_IDLE_TIMEOUT": "60",
    "SCM_LOGSTREAM_TIMEOUT": "7200",
    "SCM_BUILD_ARGS": "",
    "AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=...AccountKey=...=;EndpointSuffix=core.windows.net",
    "AzureWebJobsSecretStorageType": "Blob",
    "WEBSITE_USE_PLACEHOLDER_DOTNETISOLATED": "1",
    "APPLICATIONINSIGHTS_CONNECTION_STRING": "InstrumentationKey=...IngestionEndpoint=https://eastus-8.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus.livediagnostics.monitor.azure.com/",
    "WEBSITE_SLOT_NAME": "Production",
    "SCM_USE_LIBGIT2SHARP_REPOSITORY": "0",
    "WEBSITE_SITE_NAME": "...",
    "FUNCTIONS_EXTENSION_VERSION": "~4",
    "WEBSITE_AUTH_ENABLED": "False",
    "ScmType": "None",
    "WEBSITE_RUN_FROM_PACKAGE": "1",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
}

2

Answers


  1. In your appsettings.json :

    "Logging": {
      "LogLevel": {
        "Default": "Information",
        "Microsoft": "Information",
        "Microsoft.Hosting.Lifetime": "Information"
      }
    },
    

    If you have multiple appsettings.json based on your environment, be sure to select your environment properly and edit that specific appsettings.json.

    For example, if you are in development environment, make sure to set these settings in appsettings.Development.json.

    Login or Signup to reply.
  2. The AddApplicationInsightsTelemetryWorkerService() adds a default logging rule that only allows Warning or higher to go to Application Insights.

    Check the documentation here at https://learn.microsoft.com/en-us/azure/azure-functions/dotnet-isolated-process-guide?tabs=windows#start-up-and-configuration

    It has a specific part that removes this default rule. Why it was implemented in the first place I don’t know, but it confused me at first as well why it wasn’t showing all my logs.

    s.Configure<LoggerFilterOptions>(options =>
    {
        // The Application Insights SDK adds a default logging filter that instructs ILogger to capture only Warning and more severe logs. Application Insights requires an explicit override.
        // Log levels can also be configured using appsettings.json. For more information, see https://learn.microsoft.com/en-us/azure/azure-monitor/app/worker-service#ilogger-logs
        LoggerFilterRule toRemove = options.Rules.FirstOrDefault(rule => rule.ProviderName
            == "Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider");
    
        if (toRemove is not null)
        {
            options.Rules.Remove(toRemove);
        }
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search