Reputation: 1967
What are some example methods for logging and handling exceptions using try/except and DefaultAzureCredential()
?
Example:
When DefaultAzureCredential()
is used in a Python Azure Function, it generates a few WARNING
messages and one of the .get_token
methods in the credential chain succeeds.
I want to log which one succeeded and which ones failed.
WARNING:azure.identity._internal.decorators:EnvironmentCredential.get_token failed: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
WARNING:azure.identity._internal.decorators:ManagedIdentityCredential.get_token failed: ManagedIdentityCredential authentication unavailable, no managed identity endpoint found.
WARNING:azure.identity._internal.decorators:SharedTokenCacheCredential.get_token failed: SharedTokenCacheCredential authentication unavailable. No accounts were found in the cache.
WARNING:azure.identity._internal.decorators:VisualStudioCodeCredential.get_token failed: Failed to get Azure user details from Visual Studio Code.
And then it just succeeds, but there is no message indicating which one succeeded. In this case, running snippets in a .ipynb
file in VS Code).
How do I log and handle errors when using DefaultAzureCredential()
in production?
Looking for an example of something like:
try:
credentials = DefaultAzureCredential()
logging.info(f'<whichever>.get_token succeeded')
except Error1 as e1:
logging.error(f'EnvironmentCredential.get_token failed: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.', e1)
except Error2 as e2:
logging.error(f'ManagedIdentityCredential.get_token failed: ManagedIdentityCredential authentication unavailable, no managed identity endpoint found.', e2)
...<etc>
Upvotes: 4
Views: 13794
Reputation: 241
Just to supplement the accepted answer with some more details, let me add that DefaultAzureCredential
does log this information. For example, if you enable INFO-level logging:
import logging
from azure.identity import DefaultAzureCredential
logger = logging.getLogger('azure.identity')
logger.setLevel(logging.INFO)
handler = logging.StreamHandler(stream=sys.stdout)
formatter = logging.Formatter('[%(levelname)s %(name)s] %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
You'll see log messages like these from DefaultAzureCredential
:
[INFO] DefaultAzureCredential - EnvironmentCredential is unavailable
[INFO] DefaultAzureCredential - ManagedIdentityCredential is unavailable
[INFO] DefaultAzureCredential - SharedTokenCacheCredential is unavailable
[INFO] DefaultAzureCredential acquired a token from VisualStudioCodeCredential
You'll see the failed attempts logged only the first time the DefaultAzureCredential
instance acquires a token. Once one of its constituent credentials provides a token, it uses that credential exclusively. So this particular DefaultAzureCredential
will always authenticate through Visual Studio Code, and in the logs you'll see this message whenever it does so:
[INFO] DefaultAzureCredential acquired a token from VisualStudioCodeCredential
Upvotes: 8
Reputation: 609
There are a few ways I might approach this but none are particularly pretty. At the risk of a naive suggestion, if you want a fine-grained understanding of what worked in sequence, you could take an approach similar to what your example sketched out using the components credentials listed here:
for credential in [EnvironmentCredential, ManagedIdentityCredential, ...]:
try:
credentials = credential()
# Validate credential functionality...
logging.info('{}.get_token succeeded'.format(credential))
except Error1 as e1:
logging.error('{} failed due to {}'.format(credential, e1))
I suggest this because it does not seem like what you want is exposed in an easily accessible manner, looking at the ChainedCredential
source here (history is built up but only used in the log message).
More "self-contained" approaches might involve creating a custom wrapper that basically does what ChainedCredential
does for DefaultAzureCredential
in running the list of get_token calls, but with more ability to export the success history, you could likely hack that off of the code I linked in 2 and do something directly comparable to the DefaultAzureCredential logic, but at the end of the day it's all isomorphisms of the sample above.
Don't hesitate to shout if I've misunderstood some aspect of the question or your requirements/constraints; and as always feel free to reach out if you need to get in touch with us on our github (full disclosure, am a maintainer for some of the other Python Azure SDKs)
Upvotes: 2