Skip to content

Filter Azure monitor logs when customer does not subscribe for the categories #10982

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: dev
Choose a base branch
from

Conversation

manikantanallagatla
Copy link
Contributor

Issue describing the changes in this PR

For a few SKUs in functions, we want to filter azure monitor logs based on the categories subscribed by the user. This PR checks for the env variable for the categories and skips logging.

Pull request checklist

IMPORTANT: Currently, changes must be backported to the in-proc branch to be included in Core Tools and non-Flex deployments.

  • Backporting to the in-proc branch is not required
    • Otherwise: Link to backporting PR
  • My changes do not require documentation changes
    • Otherwise: Documentation issue linked to PR
  • My changes should not be added to the release notes for the next release
    • Otherwise: I've added my notes to release_notes.md
  • My changes do not need to be backported to a previous version
    • Otherwise: Backport tracked by issue/PR #issue_or_pr
  • My changes do not require diagnostic events changes
    • Otherwise: I have added/updated all related diagnostic events and their documentation (Documentation issue linked to PR)
  • I have added all required tests (Unit tests, E2E tests)

Additional information

Additional PR information

@manikantanallagatla manikantanallagatla requested a review from a team as a code owner April 7, 2025 09:10
Copy link
Contributor

@jviau jviau left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you give an example of these categories? Are they regular ILogger categories?

If so, we should use built in filtering with Microsoft.Extensions.Logging. We can either transform configuration, or we can simply call:

Part 1: log level filter

// condition on if this is the right sku
services.AddOptions<LoggerFilterOptions>()
    .Configure<IConfiguration>((options, config) =>
    {
        string setting = config[EnvironmentSettingNames.AzureMonitorCategories];
        options.AddFilter<AzureMonitorDiagnosticLoggerProvider>((category, level) =>
        {
            // return false when AzureMonitorCategories does not contain FunctionAppLogs
        });
    });

Part 2: IsEnabled update

// AzureMonitorDiagnosticLogger.cs
// Update the below method to return false when AzureMonitorCategories does not contain FunctionAppLogs
public bool IsEnabled(LogLevel logLevel)
{
    // We want to instantiate this Logger in placeholder mode to warm it up, but do not want to log anything.
    return !string.IsNullOrEmpty(_hostNameProvider.Value) && !_environment.IsPlaceholderModeEnabled();
}

Although I have to ask - who sets EnvironmentSettingNames.AzureMonitorCategories? Is it from the platform, or does the user explicitly set it?

@RohitRanjanMS
Copy link
Member

I agree with @jviau that providing more context about the scenario would be beneficial.
A simple list of categories alone might not be enough; the log level will also be necessary.
The environment variable is applicable only to LinuxContainerEventGenerator and does not extend to AzureMonitor/Diagnostic Settings integrations for other skus.
If these are specified by the customer, can the existing logging configuration in host.json be leveraged instead?

@manikantanallagatla
Copy link
Contributor Author

Can you give an example of these categories? Are they regular ILogger categories?

If so, we should use built in filtering with Microsoft.Extensions.Logging. We can either transform configuration, or we can simply call:

Part 1: log level filter

// condition on if this is the right sku
services.AddOptions<LoggerFilterOptions>()
    .Configure<IConfiguration>((options, config) =>
    {
        string setting = config[EnvironmentSettingNames.AzureMonitorCategories];
        options.AddFilter<AzureMonitorDiagnosticLoggerProvider>((category, level) =>
        {
            // return false when AzureMonitorCategories does not contain FunctionAppLogs
        });
    });

Part 2: IsEnabled update

// AzureMonitorDiagnosticLogger.cs
// Update the below method to return false when AzureMonitorCategories does not contain FunctionAppLogs
public bool IsEnabled(LogLevel logLevel)
{
    // We want to instantiate this Logger in placeholder mode to warm it up, but do not want to log anything.
    return !string.IsNullOrEmpty(_hostNameProvider.Value) && !_environment.IsPlaceholderModeEnabled();
}

Although I have to ask - who sets EnvironmentSettingNames.AzureMonitorCategories? Is it from the platform, or does the user explicitly set it?

I have removed all the changes. We already have category filter in the host code. I just had to called it in isenabled class

@jviau
Copy link
Contributor

jviau commented Apr 17, 2025

@manikantanallagatla I believe you will need to also add the filter callback I suggested. It may seem redundant but they have different purposes:

  1. filter: avoid running templating on the log message
  2. IsEnabled: give Logger users a hook to wrap their log statements in incase they have pre-templating code they want to skip.

I also am wondering about the IsAzureMonitorEnabled implementation as is being used in this new code paths. These are hot-paths, we need to make sure they are as performant as possible. IsAzureMonitorEnabled will be allocating an array and perform string comparison on each run. Can we optimize that? Cache the results of it somewhere?

Also this change will affect all skus - is the behavior of that env variable consistent across all skus?

@manikantanallagatla manikantanallagatla force-pushed the user/mnallagatla/diagnostic_logging branch from 6f22843 to 14d46af Compare April 22, 2025 05:21
@manikantanallagatla manikantanallagatla force-pushed the user/mnallagatla/diagnostic_logging branch from 14d46af to e8a0b4c Compare April 28, 2025 13:53
@manikantanallagatla
Copy link
Contributor Author

Can you give an example of these categories? Are they regular ILogger categories?

If so, we should use built in filtering with Microsoft.Extensions.Logging. We can either transform configuration, or we can simply call:

Part 1: log level filter

// condition on if this is the right sku
services.AddOptions<LoggerFilterOptions>()
    .Configure<IConfiguration>((options, config) =>
    {
        string setting = config[EnvironmentSettingNames.AzureMonitorCategories];
        options.AddFilter<AzureMonitorDiagnosticLoggerProvider>((category, level) =>
        {
            // return false when AzureMonitorCategories does not contain FunctionAppLogs
        });
    });

Part 2: IsEnabled update

// AzureMonitorDiagnosticLogger.cs
// Update the below method to return false when AzureMonitorCategories does not contain FunctionAppLogs
public bool IsEnabled(LogLevel logLevel)
{
    // We want to instantiate this Logger in placeholder mode to warm it up, but do not want to log anything.
    return !string.IsNullOrEmpty(_hostNameProvider.Value) && !_environment.IsPlaceholderModeEnabled();
}

Although I have to ask - who sets EnvironmentSettingNames.AzureMonitorCategories? Is it from the platform, or does the user explicitly set it?

Addressed it

@manikantanallagatla
Copy link
Contributor Author

@manikantanallagatla I believe you will need to also add the filter callback I suggested. It may seem redundant but they have different purposes:

  1. filter: avoid running templating on the log message
  2. IsEnabled: give Logger users a hook to wrap their log statements in incase they have pre-templating code they want to skip.

I also am wondering about the IsAzureMonitorEnabled implementation as is being used in this new code paths. These are hot-paths, we need to make sure they are as performant as possible. IsAzureMonitorEnabled will be allocating an array and perform string comparison on each run. Can we optimize that? Cache the results of it somewhere?

Also this change will affect all skus - is the behavior of that env variable consistent across all skus?

Addressed it. Made changes to happen only for legion based SKUs

Copy link
Contributor

@jviau jviau left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple suggestions to embrace the options pattern a bit more.

@manikantanallagatla
Copy link
Contributor Author

Addressed all comments and updates unit tests as well

@@ -91,6 +93,18 @@ public static IHostBuilder AddWebScriptHost(this IHostBuilder builder, IServiceP
loggingBuilder.AddWebJobsSystem<SystemLoggerProvider>();
if (environment.IsAzureMonitorEnabled())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, this is awkward. Going back and forth on this PR and it looks like it is completely unnecessary. We already completely disable AzureMonitor / shoebox by simply not registering the AzureMonitorDiagnosticLoggerProvider - and this is applicable to all skus.

Which means, is this PR even necessary anymore?

Copy link
Contributor Author

@manikantanallagatla manikantanallagatla May 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup. I looked at this code and tested the flow. Without the PR, the logs are not getting disabled. I think what was happening is that:

  • Legion pods start in placeholder mode and this code is executed at that time. That time, we enable azure monitor.
  • When legion pods are specialized, the env variable is set(lets say to None when categories are not subscribed) and we never disable the Azure monitor as we are not doing any options monitor or env variable monitor without the PR.
  • Thats why I started with checking for this env variable in is_enabled flow in aAzureMonitorDiagnosticLogger.cs in the PR initially
  • Then we went through this options monitor flow which is more efficient.

In summary, specialization is updating the env variable and we need options monitor on that env variable in order to enable/ disable azure monitor logs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you saying AzureMonitor env variable is set during placeholder mode? I would expect it to be the opposite: no env variable set, logger not registered, specialization brings in the azure monitor variable, but it has no effect.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean:

During placeholder mode, WEBSITE_FUNCTIONS_AZUREMONITOR_CATEGORIES env is set to null. it is not set to anything. So, logger is initialized as we are returning true here for null case:

It is also mentioned here that the logger is initialized but the logs are filtered out in placeholder mode:
https://github.com/Azure/azure-functions-host/blob/dev/src/WebJobs.Script.WebHost/Diagnostics/AzureMonitorDiagnosticLogger.cs#L58

So, specialization updates the env variable but it has no effect of disabling the logs.

I think we both are saying samething.

As env variable update is not taking effect, we need this PR so we can disable logging when that env variable is set to None.

@manikantanallagatla manikantanallagatla requested a review from jviau May 2, 2025 10:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants