From the Trenches: Managing API logs with the C# SDK

Any IT system can encounter unexpected behaviors or issues, more or less important, that could weaken the system and impact the users. It is then imperative to find a quick solution to the problem. To facilitate troubleshooting and problem solving, every system should have logging, tracing, and monitoring systems to accelerate the analysis process, either conducted locally by in-house IT staff, by the integration owner, or by DocuSign Support. In this post, I’m going to focus on logging.

Lots of administrator users already know the request logging system available under the DocuSign web interface that lets you enable API request logging on your account and to capture the next 50 API requests that will be generated by the system for the same user who enables logging. The feature includes a Download button enabling you to download a ZIP file of logs, including one log file per request.

It is possible to do the same using REST API methods to capture the logs. In this post I’ll show you how to use these methods and give you a concrete example how to implement them in a C# SDK environment.

Why use REST API logging methods?

Handling API logging using REST API methods rather than the DocuSign web interface offers these advantages:

  1. Once correctly implemented using a loop, you can capture more than 50 API requests, covering a longer time period.
  2. It can help for troubleshooting some issues for a developer to control where in the code the logging capture will start and end, or when logging will finish.
  3. When using JWT authentication, it is easy to specify which API user will be traced.

Warning: If not correctly implemented, API logging can generate a lot of GET queries (based especially on invoking the Diagnostics::getRequestLog method) and could lead to reaching the API resource limits of your account. Because of this, I recommend you only use this technique for debugging, removing it when debugging is complete. If you’d like to make this a permanent feature of your app, test extensively in your developer account first to make sure it doesn’t cause your app to exceed resource limits before deploying it in production.

API logging in action

I give below a possible use case of API log management based on C# SDK code.

With this sample code, I run the API logging during a period of five minutes. Every three seconds, it will check to see if I approach the buffer limit (50 entries). If there are less than 10 remaining entries, all the logs will be downloaded and the buffer will be cleared.

This code will need to be run in a task or a thread in order to perform these operations in the background while the rest of the system is running.

The API logging methods calls in the code below include:

  • DeleteRequestLogs()
  • UpdateRequestLogSettings()
  • GetRequestLogSettings()
  • ListRequestLogs()
  • GetRequestLog()()
DiagnosticsSettingsInformation dsi_init= new DiagnosticsSettingsInformation("true"); 
DiagnosticsApi dapi = new DiagnosticsApi(apiClient);
int idx = 1;
const int NUMBER_LOOPS=100, CHECK_TIME=3000, MAX_REMAINING=10;

dapi.DeleteRequestLogs();   // Delete all logs that could exist in the buffer
DiagnosticsSettingsInformation dsi = dapi.UpdateRequestLogSettings(dsi_init);  //Start to capture the logs
for (int i = 0; i < NUMBER_LOOPS; i++) 
{
    Thread.Sleep(CHECK_TIME);   // Wait some time between each logs check
    dsi = dapi.GetRequestLogSettings();    // Get the number of log files already captured on the server
    int remainingEntries = Convert.ToInt32(dsi.ApiRequestLogRemainingEntries);


    // If the number of remaining entries in the buffer is low enough OR doing the last loop
    if( (remainingEntries < MAX_REMAINING) || ((i == NUMBER_LOOPS-1)&&(remainingEntries < 50)) )
    {
        System.IO.Stream ios;
        ApiRequestLogsResult arlr = dapi.ListRequestLogs();  // Get a list of all the log files in the buffer
        foreach (ApiRequestLog log in arlr.ApiRequestLogs)
        {
            ios = dapi.GetRequestLog(log.RequestLogId); // Get a stream of the specified log file

            /*******************************************************/
            /* Create a file on the local disk from the stream     */
            /*******************************************************/
            String fileFullPath = @"c:\temp\" + idx + "_" + log.Description + "_" + log.RequestLogId + ".txt";
            FileStream filestream = File.Create(fileFullPath, (int)ios.Length);
            byte[] bytesInStream = new byte[ios.Length];
            ios.Read(bytesInStream, 0, bytesInStream.Length);
            filestream.WriteAsync(bytesInStream, 0, bytesInStream.Length);
            idx++;
        }
        dapi.DeleteRequestLogs();   // Delete all logs existing in the buffer
    }
}  

You need to pay particular attention to the constants NUMBER_LOOPS and CHECK_TIME, which must be calibrated with the running system:

  • If NUMBER_LOOPS is too low, the duration of the logs extraction could be too short and might not allow you to get all the transactions you need to capture.
  • If NUMBER_LOOPS is much too large or CHECK_TIME is much too low, the number of transactions will mechanically increase during a one-hour period and could lead to exceeding the API resource limits, meaning that no more API calls would be able to pass during this period.
  • If CHECK_TIME is too large, the buffer could overflow and some API requests might not be traced.

Here is an example of log files captured by this system and visible under Windows Explorer:

API log files in Windows Explorer

Because the buffer size is limited to 50 entries only, the Docusign API logging system cannot be adapted to environments where the traffic is too sporadic and unpredictable. It would be more reliable then to opt instead for a network analyzer such as Fiddler or Wireshark to capture a detailed trace of the traffic.

Additional resources

Sylvain Lebreton
Author
Sylvain Lebreton
Developer Support Engineer
Published