Configure logging

  • The .NET client library logs Google Ads API requests, responses, and summary messages.

  • Logs can be directed to a TraceListener or integrated into an existing ILogger instance.

  • Log levels vary based on the outcome of the API call (success, error, partial failure).

  • The request ID, crucial for troubleshooting, can be extracted from logs, API call responses, or exceptions.

  • Advanced gRPC-level logging is available for more detailed troubleshooting but can be voluminous.

  • Legacy .NET Framework apps can configure TraceListener logging via App.config.

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 lines in your Main method before making any API calls:

using Google.Ads.GoogleAds.Util;

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

// Summary logs.
TraceUtilities.Configure(
    TraceUtilities.SUMMARY_REQUEST_LOGS_SOURCE,
    "logs/summary.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 into your existing logging infrastructure.

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

var loggerFactory = LoggerFactory.Create(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 at different log levels:

  • Successful API response: Summary is logged at INFO; full request and response are logged at DEBUG.
  • API error response: Summary message is logged at WARN; full request and response are logged at INFO.
  • Partial failures: Logged at DEBUG.

Request ID

In most cases, the logs generated by the client library provide sufficient details to troubleshoot your issues. When you reach out to support, either provide the logs (which redact sensitive authentication fields by default) or share the request ID, which is logged as part of the response log.

If you prefer capturing the request ID programmatically, use one of the following approaches.

Extract from ordinary unary API calls

You can use a custom CallSettings with a TrailingMetadataHandler to capture request IDs from regular unary calls:

CallSettings callSettings = CallSettings.FromTrailingMetadataHandler(
    metadata =>
    {
        // Extract and log the request ID from the trailing metadata.
        string requestId = metadata.Get("request-id")?.Value;
        Console.WriteLine($"Request ID: {requestId}");
    });
// Add the campaigns.
MutateCampaignsResponse retVal = campaignService.MutateCampaigns(
    customerId.ToString(), operations.ToArray(), callSettings);

Extract from 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.V25.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,
    (SearchGoogleAdsStreamResponse resp) =>
    {
        // Extract the request ID from the response.
        string requestId = resp.RequestId;
        Console.WriteLine($"Request ID: {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;
    Console.WriteLine($"Failed Request ID: {requestId}");
}

Configure advanced logging

If the API log doesn't give you enough details, enable lower-level logging at the gRPC transport level. Keep in mind that the output can be voluminous.

When using the default Grpc.Net.Client transport, configure transport-level logs through .NET's ILogger provider by adding a filter for the Grpc category (for example, builder.AddFilter("Grpc", LogLevel.Debug)).

If you are using the legacy Grpc.Core transport (UseGrpcCore = true), gRPC logs are written to stderr by default, or you can attach your own logger as shown in the following example. For more details, see the supported gRPC 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 modern .NET targets.

To use this feature, 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 a 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 a 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 Google Ads .NET libraries. The default level is set to
             Warning. To disable all messages, set this value to Off. -->
        <add name="GoogleAds.DeprecationMessages" value="Warning" />
        <!-- Use this trace switch to control the detailed request logs written
             by Google 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 Google 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>