ADAL Diagnostics
Every time somebody needs help troubleshooting an app using ADAL, one of the first things we ask is to provide ADAL logs (and possibly a Fiddler trace as well).
I usually have to write something like “you can find instructions on how to capture ADAL .NET logs in the Diagnostics section of https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/blob/master/README.md”, which is more typing work than I’d like (and occasionally people still can’t find the right section). And – there’s a different readme repo for each ADAL flavor. Hence, I am pasting here only that section from commonly used ADALs (.NET, Android, iOS) and plan to send a link to this post instead there you go:
Diagnostics for ADAL .NET
The following are the primary sources of information for diagnosing issues:
- Exceptions
- Logs
- Network traces
Also, note that correlation IDs are central to the diagnostics in the library. You can set your correlation IDs on a per request basis (by setting CorrelationId
property on AuthenticationContext
before calling an acquire token method) if you want to correlate an ADAL request with other operations in your code. If you don’t set a correlations id, then ADAL will generate a random one which changes on each request. All log messages and network calls will be stamped with the correlation id.
Exceptions
This is obviously the first diagnostic. We try to provide helpful error messages. If you find one that is not helpful please file an issue and let us know. Please also provide the target platform of your application (e.g. Desktop, Windows Store, Windows Phone).
Logs
You can configure the library to generate log messages that you can use to help diagnose issues. You configure logging by setting properties of the static class AdalTrace
; however, depending on the platform, logging methods and the properties of this class differ. Here is how logging works on each platform:
Desktop Applications
ADAL.NET for desktop applications by default logs via System.Diagnostics.Trace
class. You can add a trace listener to receive those logs. You can also control tracing using this method (e.g. change trace level or turn it off) using AdalTrace.LegacyTraceSwitch
.
The following example shows how to add a Console based listener and set trace level to Information
(the default trace level is Verbose
):
Trace.Listeners.Add(new ConsoleTraceListener());
AdalTrace.LegacyTraceSwitch.Level = TraceLevel.Info;
You can achieve the same result by adding the following lines to your application’s config file:
<system.diagnostics>
<sharedListeners>
<add name="console"
type="System.Diagnostics.ConsoleTraceListener"
initializeData="false"/>
</sharedListeners>
<trace autoflush="true">
<listeners>
<add name="console" />
</listeners>
</trace>
<switches>
<add name="ADALLegacySwitch" value="Info"/>
</switches>
</system.diagnostics>
If you would like to have more control over how tracing is done in ADAL, you can add a TraceListener
to ADAL’s dedicated TraceSource
with name “Microsoft.IdentityModel.Clients.ActiveDirectory”.
The following example shows how to write ADAL’s traces to a text file using this method:
Stream logFile = File.Create("logFile.txt");
AdalTrace.TraceSource.Listeners.Add(new TextWriterTraceListener(logFile));
AdalTrace.TraceSource.Switch.Level = SourceLevels.Information;
You can achieve the same result by adding the following lines to your application’s config file:
<system.diagnostics>
<trace autoflush="true"/>
<sources>
<source name="Microsoft.IdentityModel.Clients.ActiveDirectory"
switchName="sourceSwitch"
switchType="System.Diagnostics.SourceSwitch">
<listeners>
<add name="textListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="logFile.txt"/>
<remove name="Default" />
</listeners>
</source>
</sources>
<switches>
<add name="sourceSwitch" value="Information"/>
</switches>
</system.diagnostics>
Windows Store and Windows Phone Applications
Tracing in ADAL for Windows Store and Windows Phone is done via an instance of class System.Diagnostics.Tracing.EventSource
with name “Microsoft.IdentityModel.Clients.ActiveDirectory”. You can define your own EventListener
, connect it to the event source and set your desired trace level. Here is an example:
var eventListener = new SampleEventListener();
class SampleEventListener : EventListener
{
protected override void OnEventSourceCreated(EventSource eventSource)
{
if (eventSource.Name == "Microsoft.IdentityModel.Clients.ActiveDirectory")
{
this.EnableEvents(eventSource, EventLevel.Verbose);
}
}
protected override void OnEventWritten(EventWrittenEventArgs eventData)
{
...
}
}
There is also a default event listener which writes logs to a local file named “AdalTraces.log”. You can control the level of tracing to that event listener using the property AdalTrace.Level
. By default, trace level for this event listener is set to “None” and to enable tracing to this particular listener, you need to set the above property. This is an example:
AdalTrace.Level = AdalTraceLevel.Informational;
Windows Phone Silverlight Applications
Since Silverlight does not support EventSource/EventListener, we use LoggingChannel/LoginSession
for logging. There is a LoggingChannel
in AdalTrace
which you can connect your own LoggingSession/FileLoggingSession
to it and also control trace level using it. Here is an example:
LoggingSession loggingSession = new LoggingSession("ADAL Logging Session");
loggingSession.AddLoggingChannel(AdalTrace.AdalLoggingChannel, LoggingLevel.Verbose);
and then use loggingSession.SaveToFileAsync(...)
to copy the logs to a file. If you use emulator, you can then use ISETool.exe
and tracerpt.exe
tools to copy log file and convert it to text format.
Network Traces
You can use various tools to capture the HTTP traffic that ADAL generates. This is most useful if you are familiar with the OAuth protocol or if you need to provide diagnostic information to Microsoft or other support channels.
Fiddler is the easiest HTTP tracing tool. In order to be useful it is necessary to configure fiddler to record unencrypted SSL traffic.
NOTE: Traces generated in this way may contain highly privileged information such as access tokens, usernames and passwords. If you are using production accounts, do not share these traces with 3rd parties. If you need to supply a trace to someone in order to get support, reproduce the issue with a temporary account with usernames and passwords that you don’t mind sharing.
=================================
Diagnostics for ADAL Android
The following are the primary sources of information for diagnosing issues:
- Exceptions
- Logs
- Network traces
Also, note that correlation IDs are central to the diagnostics in the library. You can set your correlation IDs on a per request basis if you want to correlate an ADAL request with other operations in your code. If you don’t set a correlations id then ADAL will generate a random one and all log messages and network calls will be stamped with the correlation id. The self generated id changes on each request.
Exceptions
This is obviously the first diagnostic. We try to provide helpful error messages. If you find one that is not helpful please file an issue and let us know. Please also provide device information such as model and SDK#.
Logs
You can configure the library to generate log messages that you can use to help diagnose issues. You configure logging by making the following call to configure a callback that ADAL will use to hand off each log message as it is generated.
Logger.getInstance().setExternalLogger(new ILogger() { @Override public void Log(String tag, String message, String additionalMessage, LogLevel level, ADALError errorCode) { ... // You can write this to logfile depending on level or errorcode. writeToLogFile(getApplicationContext(), tag +":" + message + "-" + additionalMessage); } }
Messages can be written to a custom log file as seen below. Unfortunately, there is no standard way of getting logs from a device. There are some services that can help you with this. You can also invent your own, such as sending the file to a server.
private syncronized void writeToLogFile(Context ctx, String msg) { File directory = ctx.getDir(ctx.getPackageName(), Context.MODE_PRIVATE); File logFile = new File(directory, "logfile"); FileOutputStream outputStream = new FileOutputStream(logFile, true); OutputStreamWriter osw = new OutputStreamWriter(outputStream); osw.write(msg); osw.flush(); osw.close(); }
Logging Levels
- Error(Exceptions)
- Warn(Warning)
- Info(Information purposes)
- Verbose(More details)
You set the log level like this:
Logger.getInstance().setLogLevel(Logger.LogLevel.Verbose);
All log messages are sent to logcat in addition to any custom log callbacks. You can get log to a file form logcat as shown belog:
adb logcat > "C:\logmsg\logfile.txt"
More examples about adb cmds: https://developer.android.com/tools/debugging/debugging-log.html#startingLogcat
Network Traces
You can use various tools to capture the HTTP traffic that ADAL generates. This is most useful if you are familiar with the OAuth protocol or if you need to provide diagnostic information to Microsoft or other support channels.
Fiddler is the easiest HTTP tracing tool. Use the following links to setup it up to correctly record ADAL network traffic. In order to be useful it is necessary to configure fiddler, or any other tool such as Charles, to record unencrypted SSL traffic. NOTE: Traces generated in this way may contain highly privileged information such as access tokens, usernames and passwords. If you are using production accounts, do not share these traces with 3rd parties. If you need to supply a trace to someone in order to get support, reproduce the issue with a temporary account with usernames and passwords that you don’t mind sharing.
=================================
Diagnostics for ADAL iOS
The following are the primary sources of information for diagnosing issues:
- NSError
- Logs
- Network traces
Also, note that correlation IDs are central to the diagnostics in the library. You can set your correlation IDs on a per request basis if you want to correlate an ADAL request with other operations in your code. If you don’t set a correlations id then ADAL will generate a random one and all log messages and network calls will be stamped with the correlation id. The self generated id changes on each request.
NSError
This is obviously the first diagnostic. We try to provide helpful error messages. If you find one that is not helpful please file an issue and let us know. Please also provide device information such as model and SDK#. The error message is returned as a part of the ADAuthenticationResult where the status is set to AD_FAILED.
Logs
You can configure the library to generate log messages that you can use to help diagnose issues. ADAL uses NSLog by default to log the messages. Each API method call is decorated with API version and every other message is decorated with correlation id and UTC timestamp. This data is important to look of server side diagnostics. SDK also exposes the ability to provide a custom Logger callback as follows.
[ADLogger setLogCallBack:^(ADAL_LOG_LEVEL logLevel, NSString *message, NSString *additionalInformation, NSInteger errorCode) { //HANDLE LOG MESSAGE HERE }]
Logging Levels
- No_Log(Disable all logging)
- Error(Exceptions. Set as default)
- Warn(Warning)
- Info(Information purposes)
- Verbose(More details)
You set the log level like this:
[ADLogger setLevel:ADAL_LOG_LEVEL_INFO]
Network Traces
You can use various tools to capture the HTTP traffic that ADAL generates. This is most useful if you are familiar with the OAuth protocol or if you need to provide diagnostic information to Microsoft or other support channels.
Charles is the easiest HTTP tracing tool in OSX. Use the following links to setup it up to correctly record ADAL network traffic. In order to be useful it is necessary to configure Charles, to record unencrypted SSL traffic. NOTE: Traces generated in this way may contain highly privileged information such as access tokens, usernames and passwords. If you are using production accounts, do not share these traces with 3rd parties. If you need to supply a trace to someone in order to get support, reproduce the issue with a temporary account with usernames and passwords that you don’t mind sharing.