Azure / AppConfiguration-DotnetProvider

The .NET Standard configuration provider for Azure App Configuration
https://github.com/Azure/AppConfiguration
MIT License
82 stars 37 forks source link

Unable to tell why a certain value was selected when multiple filters exist #549

Open julealgon opened 5 months ago

julealgon commented 5 months ago

When working with IConfiguration in general, there is a GetDebugView in IConfigurationRoot that provides one with the keys and their sources. This is very helpful to understand what is happening when various providers are involved in generating the final set of settings.

However, when using AzureAppConfigurationProvider in more advanced scenarios, this becomes harder to reason about. For example, take this possible integration:

config.AddAzureAppConfiguration(
    c => c
        .Connect(
            endpoint: config.GetValue<Uri>("Azure:AppConfiguration:Endpoint"),
            credential: new DefaultAzureCredential())
        .Select(KeyFilter.Any, LabelFilter.Null)
        .Select(KeyFilter.Any, "Application: MyApp")
        .Select(KeyFilter.Any, $"Machine: {Environment.MachineName}"))

Given any key that was fetched from Azure AppConfiguration, there is no way to know why that key was fetched. Was it because it had no labels? If I was expecting value x but got value y, how can I tell which of the labels "won" between the application and the machine? There is no information regarding which labels matched a given key when inspecting the loaded configuration.

This becomes a bigger problem once we abstract this further. Currently, we have a UI in our system where people can navigate and change settings on the fly. We have this mapped to our own internal system which supports either global values, or per-machine values. To support that scenario in Azure AppConfiguration is easy enough: we just add the Machine: ... label and fetch it using the current machine name like the above with priority over the no label entries, and we get the exact same behavior. But when presenting those settings, we don't have a way to tell where they came from: were they defined globally, or where they defined on the specific machine?

If we had a way to know which label that value came from, we would be able to categorize the key properly.

I'm not even sure a workaround to this is possible right now. Even if we split all of our Select calls into completely separate AddAzureAppConfiguration calls (which would probably be vastly less efficient) I don't see how we would differentiate the various AzureAppConfigurationProvider instances either.

amerjusupovic commented 3 months ago

Thanks for your question! Off the top of my head, there may be a way to use the AzureAppConfigurationOptions.Map API to store each setting's label. For example, for each setting passed to your Map function, you could store the key and label in another data structure. Because you know the priority of the labels, you could have logic to determine which label was added to the configuration for each key.

options.Map(setting =>
{
    // Logic to check if setting.Label is a higher priority than any other labels seen for the key: setting.Key,
    // then save the key/label pair

    return new ValueTask<ConfigurationSetting>(setting);
});

This would be my suggested workaround to try for now. Even if it does work, I think this is something to look into and see if we can make it easier.

julealgon commented 3 months ago

@amerjusupovic that is very interesting indeed. It doesn't really solve the lack of information in the GetDebugView but it does allow one to work around it like you said. I was not aware that the Map function gave you access to the label for a key.

I appreciate the suggestion!

I would like to see a more evolved version of the configuration mechanism where each value could carry arbitrary metadata with it (like the Azure Portal allows today with the tags).