Azure / azure-functions-dotnet-worker

Azure Functions out-of-process .NET language worker
MIT License
419 stars 184 forks source link

Logging not working in Azure Function Isolated Model #2389

Open chayankar opened 5 months ago

chayankar commented 5 months ago

What version of .NET does your existing project use?

.NET 6

What version of .NET are you attempting to target?

.NET 6

Description

Upgrading azure function in-process model into isolated model. Followed the steps mentioned [here](https://learn.microsoft.com/en-us/azure/azure-functions/dotnet-isolated-process-guide?tabs=windows#logging)

When running the function locally, I can see the logs reaching Application Insight, but after deploying it into azure I don't see logs reaching Application Insight, neither in Log Stream.

When working locally, I imported application settings from deployed function app in azure. I am sure that APPINSIGHTS_INSTRUMENTATIONKEY & APPLICATIONINSIGHTS_CONNECTION_STRING are correct.

I tried using Serilog for writing logs into Application Insight using Serilog.Sinks.ApplicationInsights (4.0.0) but the result is same as above.

Used both approaches for obtaining logger instance: Using dependency insjection & via FuctionContext.GetLogger(categoryName) method.

My question is: If function is generating logs when ran locally, then why is it not working as expected in azure? Is the worker process not communicating with host? Is there any other unknown configuration which is overriding my code? Do we have to define log level for the categaoryName parameter passed into FuctionContext.GetLogger(categoryName) host.json?

Below is the snippet from startup class.

string appInsightConnectionString = "<application insight connection string>";
var host = new HostBuilder()
.ConfigureServices((context, services) => 
{
    services.AddApplicationInsightsTelemetryWorkerService();
    services.ConfigureFunctionsApplicationInsights();
    services.AddLogging(builder =>{
        builder.AddApplicationInsights(
            telemetryConfig => {telemetryConfig.ConnectionString = appInsightConnectionString;},
                    loggerOptions =>{loggerOptions.FlushOnDispose = true;});
        });
})
.ConfigureLogging(logging =>
{
    logging.Services.Configure<LoggerFilterOptions>(options =>
    {
        LoggerFilterRule defaultRule = options.Rules.FirstOrDefault(rule => rule.ProviderName
            == "Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider");
        if (defaultRule is not null)
        {
            options.Rules.Remove(defaultRule);
        }
        options.MinLevel = LogLevel.Information;
    });
})
.Build();
await host.RunAsync();

host.json

{
  "version": "2.0",
  "logging": {
    "logLevel": {
      "default": "Information",
      "Function": "Information",
      "Host.Result": "Information",
      "Host.Aggregator": "Information"
    },
    "applicationInsights": {
      "samplingSettings": {
        "isEnabled": false,
        "excludedTypes": "Request;Exception;Trace"
      },
      "httpAutoCollectionOptions": {
        "enableHttpTriggerExtendedInfoCollection": false,
        "enableW3CDistributedTracing": true
      }
    },
    "extensions": {
      "durableTask": {
        "maxConcurrentActivityFunctions": 1000,
        "maxConcurrentOrchestratorFunctions": 100
      }
    }
  }
}

Links referred: https://github.com/Azure/azure-functions-dotnet-worker/issues/1123 https://github.com/Azure/azure-functions-dotnet-worker/pull/944 https://github.com/Azure/azure-functions-dotnet-worker/issues/702 https://github.com/Azure/azure-functions-dotnet-worker/issues/760 https://github.com/Azure/azure-functions-dotnet-worker/issues/1123

Project configuration and dependencies

Startup project .csproj file content

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <LangVersion>10</LangVersion>
    <AzureFunctionsVersion>v4</AzureFunctionsVersion>
    <AssemblyVersion>2.0.0</AssemblyVersion>
    <FileVersion>2.0.0</FileVersion>
    <_FunctionsSkipCleanOutput>true</_FunctionsSkipCleanOutput>
    <RuntimeIdentifiers>win-x86;win-x64;linux-x64</RuntimeIdentifiers>
    <OutputType>Exe</OutputType>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.22.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.21.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="1.2.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask" Version="1.1.1" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.1.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.ServiceBus" Version="5.17.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Timer" Version="4.3.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.17.2" />
    <PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
    <PackageReference Include="Microsoft.Extensions.Http.Polly" Version="6.0.6" />
    <PackageReference Include="Serilog" Version="3.1.1" />
    <PackageReference Include="Serilog.Extensions.Logging" Version="8.0.0" />
    <PackageReference Include="Serilog.Sinks.ApplicationInsights" Version="4.0.0" />
    <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.35.0" />
    <PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
    <None Update="local.settings.arc.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
</Project>

Link to a repository that reproduces the issue

No response

kshyju commented 5 months ago

Could you please try using the setup code mentioned in our documentation here?

When deploying your app, simply add the APPINSIGHTS_INSTRUMENTATIONKEY app setting entry with the correct value (which you can obtain from your Application Insights resource). That should do the trick.

By following this model, your dotnet isolated function will send logs directly to Application Insights, bypassing the host, similar to how AI integration works for any .NET application.

Let us know how that goes.

Frulfump commented 5 months ago

Could you please try using the setup code mentioned in our documentation here?

When deploying your app, simply add the APPINSIGHTS_INSTRUMENTATIONKEY app setting entry with the correct value (which you can obtain from your Application Insights resource). That should do the trick.

By following this model, your dotnet isolated function will send logs directly to Application Insights, bypassing the host, similar to how AI integration works for any .NET application.

Let us know how that goes.

Is there an issue with using the Application Insights connection string? Since instrumentation key support will end in less than a year. "On March 31, 2025, support for instrumentation key ingestion will end. Instrumentation key ingestion will continue to work, but we'll no longer provide updates or support for the feature. Transition to connection strings to take advantage of new capabilities." https://learn.microsoft.com/en-us/azure/azure-monitor/app/sdk-connection-string?tabs=dotnet5

https://azure.microsoft.com/en-us/updates/technical-support-for-instrumentation-key-based-global-ingestion-in-application-insights-will-end-on-31-march-2025/

https://github.com/azure-deprecation/dashboard/issues/212

chayankar commented 5 months ago

Could you please try using the setup code mentioned in our documentation here?

When deploying your app, simply add the APPINSIGHTS_INSTRUMENTATIONKEY app setting entry with the correct value (which you can obtain from your Application Insights resource). That should do the trick.

By following this model, your dotnet isolated function will send logs directly to Application Insights, bypassing the host, similar to how AI integration works for any .NET application.

Let us know how that goes.

I have followed the mentioned documentation

Deployed function app has right set of APPINSIGHTS_INSTRUMENTATIONKEY & APPLICATIONINSIGHTS_CONNECTION_STRING as well. How do I know it is right? Because the setting is imported into local.settings.json & when the function is running locally, I can see the logs in AI.

But logs are not reaching AI from deployed function app. I know that the function app is executing because i can see entries in exception table in AI. But I don't see any entries in traces.

I am obtaining logger instance from FunctionContext.GetLogger(

). Am I missing any settings in host.json?
kshyju commented 5 months ago

@chayankar

How do I know it is right?

How do you know "what" is right? Can you be more specific?

The local.settings.json is a file to define your app settings when running locally. It has no role when your app is running on azure. You need to specify your app settings under "Settings -> Environment variables -> App settings"

Can you try creating a new AI resource, copy it's connection string and update your deployed app's APPLICATIONINSIGHTS_CONNECTION_STRING app setting to have this new value, then restart the app and see that works? Also remove the APPINSIGHTS_INSTRUMENTATIONKEY (You don't need both of them(

sopya88 commented 3 months ago

Use below code in Program.cs, it will start working, Also do proper DI in function class for ILogger,

var host = new HostBuilder() .ConfigureFunctionsWebApplication() .ConfigureServices(services => {

services.AddApplicationInsightsTelemetryWorkerService();
services.ConfigureFunctionsApplicationInsights();

}) .ConfigureLogging(logging => { logging.Services.Configure(options => { LoggerFilterRule defaultRule = options.Rules.FirstOrDefault(rule => rule.ProviderName == "Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider"); if (defaultRule is not null) { options.Rules.Remove(defaultRule); } }); }) .Build(); host.Run();

ccarmannt commented 1 month ago

FYI, the workaround supplied by @sopya88 above doesn't fix anything, at least in the solution I'm running.

theerakr commented 1 month ago

Currently I'm using .net 8 isolated Have you consider move host var into Program.cs instead of Startup.cs

using Microsoft.Extensions.Hosting;

var host = new HostBuilder()
    .ConfigureFunctionsWebApplication()
    .ConfigureServices(services => {
        services.AddLogging();
    })
    .Build();

host.Run();

and if you need to use activity log, like getting the operationId or RootId (using System.Diagnostics), , I've found that Azure.Core under Functions.Worker need to be 1.41.0 or later image which should included the supported DiagnosticSource version image