I am running an Azure Function (V4) on .NET 7 in an isolated-process.
All exceptions are shown in Azure Application Insights as RpcExceptions. It looks like my function is wrapped inside this "Invoke" and that it can only return an RpcException instead of the AppUserException that I am explicitly throwing.
This results in very unclear data. What can I do?
I just made a new function to test it:
<PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.21.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.18.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="1.0.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.0.13" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Storage" Version="6.0.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Timer" Version="4.2.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.13.0" />
namespace FunctionApp1
{
public class Function1
{
private readonly ILogger _logger;
public Function1(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<Function1>();
}
[Function("Function1")]
public HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req)
{
_logger.LogInformation("C# HTTP trigger function processed a request.");
throw new AppUserException("usererror");
}
}
}
program.cs
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureAppConfiguration(builder =>
{
// KeyVault
var keyVaultEndpoint = GetKeyVaultEndpoint();
if (string.IsNullOrWhiteSpace(keyVaultEndpoint))
{
throw new Exception("keyVaultEndpoint wasn't provided.");
}
var credentials = new DefaultAzureCredential();
builder.AddAzureKeyVault(new Uri(keyVaultEndpoint), credentials, new KeyVaultSecretManager());
// Azure App Config
var azureAppConfigEndpoint = GetAzureAppConfigEndpoint();
if (string.IsNullOrWhiteSpace(azureAppConfigEndpoint))
{
throw new Exception("azureAppConfigEndpoint wasn't provided.");
}
builder.AddAzureAppConfiguration(options =>
{
options.Connect(azureAppConfigEndpoint)
.UseFeatureFlags(options =>
{
options.CacheExpirationInterval = TimeSpan.FromSeconds(60);
});
});
builder.AddJsonFile("appsettings.json", optional: true);
})
.ConfigureServices(services =>
{
services.AddApplicationInsightsTelemetryWorkerService();
services.ConfigureFunctionsApplicationInsights();
services.Configure<LoggerFilterOptions>(options =>
{
var toRemove = options.Rules.FirstOrDefault(rule => rule.ProviderName
== "Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider");
if (toRemove is not null)
{
options.Rules.Remove(toRemove);
}
});
services.AddSolutionServices();
})
.ConfigureLogging((hostingContext, logging) =>
{
// Make sure the configuration of the appsettings.json file is picked up.
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
})
.Build();
static string? GetKeyVaultEndpoint() => Environment.GetEnvironmentVariable("ASPNETCORE_HOSTINGSTARTUP__KEYVAULT__CONFIGURATIONVAULT");
static string? GetAzureAppConfigEndpoint() => Environment.GetEnvironmentVariable("AZURE_APPCONFIG_ENDPOINT");
host.Run();
2
Answers
It looks like RpcException is expected. There are multiple issues opened on Github around that, it seems to be a pending item on Application Insights team. You can get more information about them on:
https://github.com/Azure/azure-functions-dotnet-worker/issues/370
https://github.com/Azure/azure-functions-host/issues/6284
https://github.com/Azure/azure-functions-host/issues/4192#issuecomment-481813144
I believe I have figured out the issue, at least in my case.
It appears that the default behavior for Azure Function and AppInsights is to log ship the Azure Function Host logs to AppInsights. For whatever reason, the host logs replace all logged exceptions with an RpcException (even when setting the EnableUserCodeExceptions to true). Then, when the logs get shipped to AppInsights, you get the same behavior.
However, if you configure the function host to push logs directly to AppInsights, you get the exception types you expect.
https://learn.microsoft.com/en-us/azure/azure-functions/dotnet-isolated-process-guide#application-insights