Logging

The .NET client library logs requests, responses, and summary messages made to the Google Ads API. The logs can be written to a custom TraceListener, or to a custom ILogger instance.

TraceListener

You can enable logging to a TraceListener by adding the following line in your Main method before making any API calls.

using Google.Ads.GoogleAds.Util;
...

// Detailed logs.
TraceUtilities.Configure(TraceUtilities.DETAILED_REQUEST_LOGS_SOURCE,
    "C:\\logs\\details.log", System.Diagnostics.SourceLevels.All);

// Summary logs.
TraceUtilities.Configure(TraceUtilities.SUMMARY_REQUEST_LOGS_SOURCE,
    "C:\\logs\\details.log", System.Diagnostics.SourceLevels.All);

ILogger

If you're already using an ILogger for your application logs, this solution lets you integrate Google Ads API logs in your existing logs.

First, create a LoggerFactory, or if you already have one, add the filters for Google Ads API logs:

var loggerFactory = LoggerFactory.Create(delegate (ILoggingBuilder builder)
{
  // Log to stdout.
  builder.AddConsole();
  builder.AddFilter(TraceUtilities.SUMMARY_REQUEST_LOGS_SOURCE, LogLevel.Trace);
  builder.AddFilter(TraceUtilities.DETAILED_REQUEST_LOGS_SOURCE, LogLevel.Trace);
});

Then, use the LoggerFactory to create loggers for request and response summaries and details:

ILogger summaryLogger = loggerFactory.CreateLogger(TraceUtilities.SUMMARY_REQUEST_LOGS_SOURCE);
ILogger detailLogger = loggerFactory.CreateLogger(TraceUtilities.DETAILED_REQUEST_LOGS_SOURCE);

Finally, configure the client library to redirect its traces to your ILogger instances:

TraceUtilities.ConfigureSummaryLogger(summaryLogger);
TraceUtilities.ConfigureDetailLogger(detailLogger);

This solution lets you integrate Google Ads API request and response logs into existing logging frameworks, such as Log4Net, NLog, and Serilog.

Log levels

The library logs different types of events to different log levels. For a successful API response, the summary is logged at INFO, and the full request and responses are logged at DEBUG.

On a request that results in an API error, the summary message is logged at WARN, and the full request and response are logged at INFO.

Partial failures are logged at DEBUG.

Request ID

In most cases, the logs generated by the client library provide sufficient details to troubleshoot your issues. When reaching out to the support forum/aliases, you can either provide the logs (which redacts sensitive information by default) or just share the request ID (which is logged as part of the response log).

If you prefer capturing the request ID yourself, you could use one of the following approaches:

Extraction through ordinary API calls

You can use a custom CallSetting with a TrailingMetadataHandler to capture request IDs from regular unary calls.

CallSettings callSettings = CallSettings.FromTrailingMetadataHandler(
    delegate (Metadata metadata) {
        // Extract the request ID from the trailing metadata.
        string requestId = metadata.Get("request-id").Value;
    });
// Add the campaigns.
MutateCampaignsResponse retVal = campaignService.MutateCampaigns(
    customerId.ToString(), operations.ToArray(), callSettings);

Extraction through streaming API calls

The request ID is returned as part of the response object for streaming API calls. For example, you can get the request ID for a SearchStream call as follows:

// Get the GoogleAdsService.
GoogleAdsServiceClient googleAdsService = client.GetService(
    Services.V12.GoogleAdsService);

// Retrieve all campaigns.
string query = @"SELECT
                campaign.id,
                campaign.name,
                campaign.network_settings.target_content_network
            FROM campaign
            ORDER BY campaign.id";

// Issue a search request.
googleAdsService.SearchStream(customerId.ToString(), query,
    delegate (SearchGoogleAdsStreamResponse resp)
    {
        // Extract the request ID from the response.
        string requestId = resp.RequestId;
        foreach (GoogleAdsRow googleAdsRow in resp.Results)
        {
            Console.WriteLine("Campaign with ID {0} and name '{1}' was found.",
                googleAdsRow.Campaign.Id, googleAdsRow.Campaign.Name);
        }
    }
);

Exceptions

The request ID is returned as part of the GoogleAdsException exception whenever an API call fails.

try
{
  // Make an API call.
  ...
}
catch (GoogleAdsException e)
{
    string requestId = e.RequestId;
}

Advanced logging

If the API log doesn't give you enough details, enable more low level logging at the gRPC level. Keep in mind that the output can be voluminous. The gRPC logs are written to stderr, but you can attach your own logger as shown below. Supported environment variables.

Environment.SetEnvironmentVariable("GRPC_VERBOSITY", "DEBUG");
Environment.SetEnvironmentVariable("GRPC_TRACE", "http");
GrpcEnvironment.SetLogger(new ConsoleLogger());

TraceListener configuration using App.config (legacy)

If your app builds for a .NET Framework target, you can load the logging configuration from your app's App.config or Web.config file. This is a legacy .NET functionality that is not supported for apps built for .NET Core targets.

To use this feature, you need to add the following changes to your configuration file:

  1. Add the following snippet under the <configuration> section.

    <system.diagnostics>
      <sources>
        <source name="GoogleAds.DeprecationMessages"
            switchName="GoogleAds.DeprecationMessages"
            switchType="System.Diagnostics.SourceSwitch">
          <listeners>
            <add name="myListener" type="System.Diagnostics.EventLogTraceListener"
               initializeData="Application"/>
          </listeners>
        </source>
        <source name="GoogleAds.DetailedRequestLogs"
            switchName="GoogleAds.DetailedRequestLogs"
            switchType="System.Diagnostics.SourceSwitch">
          <listeners>
            <add name="detailedRequestLogListener" type="System.Diagnostics.ConsoleTraceListener"
               initializeData="true"/>
            <!-- Use the following to log to file. Modify the initializeData
                 attribute to control the path to the detailed request log file. -->
            <!--
            <add name="detailedRequestLogListener" type="System.Diagnostics.TextWriterTraceListener"
                 initializeData="C:\Logs\detailed_logs.log"/>
            <remove name="Default"/>
            -->
          </listeners>
        </source>
        <source name="GoogleAds.SummaryRequestLogs" switchName="GoogleAds.SummaryRequestLogs"
            switchType="System.Diagnostics.SourceSwitch">
          <listeners>
            <add name="summaryRequestLogListener" type="System.Diagnostics.ConsoleTraceListener"
               initializeData="true"/>
            <!-- Use the following to log to file. Modify the initializeData
                 attribute to control the path to the summary request log file. -->
            <!--
            <add name="summaryRequestLogListener" type="System.Diagnostics.TextWriterTraceListener"
                 initializeData="C:\Logs\summary_logs.log"/>
            -->
            <remove name="Default"/>
          </listeners>
        </source>
      </sources>
      <switches>
        <!-- Use this trace switch to control the deprecation trace messages
             written by Ads* .NET libraries. The default is level is set to
             Warning. To disable all messages, set this value to Off. See
             msdn.microsoft.com/en-us/library/system.diagnostics.sourcelevels.aspx
             for all possible values this key can take. -->
        <add name="GoogleAds.DeprecationMessages" value="Warning"/>
        <!-- Use this trace switch to control the detailed request logs written by Ads*
             .NET libraries. The default level is set to Off. Logs are generated at
             both the Error and Information levels. -->
        <add name="GoogleAds.DetailedRequestLogs" value="Off"/>
        <!-- Use this trace switch to control the summary request logs written by
             Ads* .NET libraries. The default level is set to Off. Logs are
             generated at both the Error and Information levels. -->
        <add name="GoogleAds.SummaryRequestLogs" value="Off"/>
      </switches>
      <trace autoflush="true"/>
    </system.diagnostics>
    
  2. Add the following snippet under the <configSections> section.

    <section name="system.diagnostics" type="System.Diagnostics.SystemDiagnosticsSection"/>
    

    Your App.config then looks like this:

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <configSections>
        <section name="GoogleAdsApi" type="System.Configuration.DictionarySectionHandler"/>
        <section name="system.diagnostics" type="System.Diagnostics.SystemDiagnosticsSection"/>
      </configSections>
      <GoogleAdsApi>
        <!-- Google Ads API settings. -->
      </GoogleAdsApi>
      <system.diagnostics>
        <!-- Logging settings. -->
      </system.diagnostics>
    </configuration>