Изменить событие

Событие изменения предоставляет подробную информацию о том, что изменилось в вашей учетной записи. При отчете об операции создания возвращаются все новые значения полей; а при составлении отчета об операции обновления возвращаются как новые, так и старые значения, что дает вам полную картину отдельных изменений.

Кроме того, указывается тип клиента (например, API или веб-клиент), который использовался для внесения изменения, а также то, какой пользователь внес это изменение, при условии, что информация также отображается в истории изменений веб-клиента.

Отслеживаются следующие типы ресурсов :

Тип ресурса Ценить
Объявление AD
Группа объявлений AD_GROUP
Объявление группы объявлений AD_GROUP_AD
Модификатор ставок на уровне группы объявлений AD_GROUP_BID_MODIFIER
Критерий группы объявлений AD_GROUP_CRITERION
Кампания CAMPAIGN
Бюджет кампании CAMPAIGN_BUDGET
Критерий кампании CAMPAIGN_CRITERION
Фид группы объявлений AD_GROUP_FEED
Фид кампании CAMPAIGN_FEED
Кормить FEED
Элемент фида FEED_ITEM
Объект ASSET
Актив клиента CUSTOMER_ASSET
Объект кампании CAMPAIGN_ASSET
Объект группы объявлений AD_GROUP_ASSET

Запрос

Список изменений необходимо фильтровать по дате. Диапазон дат должен быть в пределах последних 30 дней.

Запрос также должен включать предложение LIMIT , ограничивающее количество строк не более 10 000. Если вас интересует более 10 000 результатов, запишите временную метку последней записи в возвращаемом наборе результатов, а затем установите диапазон дат для следующего запроса, чтобы он начинался после этого времени, чтобы продолжить с того места, на котором вы остановились.

Изменение может занять до трех минут, прежде чем оно отразится в результатах события изменения.

В следующем примере показано, как получать события изменения и обрабатывать их, включая определение того, кто внес изменение, какой тип клиента они использовали для внесения изменения, а также старые и новые значения каждого поля в изменении:

private void runExample(GoogleAdsClient googleAdsClient, long customerId) {
 
// Defines a GAQL query to retrieve change_event instances from the last 14 days.
 
String query =
     
String.format(
         
"SELECT"
             
+ "  change_event.resource_name,"
             
+ "  change_event.change_date_time,"
             
+ "  change_event.change_resource_name,"
             
+ "  change_event.user_email,"
             
+ "  change_event.client_type,"
             
+ "  change_event.change_resource_type,"
             
+ "  change_event.old_resource,"
             
+ "  change_event.new_resource,"
             
+ "  change_event.resource_change_operation,"
             
+ "  change_event.changed_fields "
             
+ "FROM "
             
+ "  change_event "
             
+ "WHERE "
             
+ "  change_event.change_date_time <= '%s' "
             
+ "  AND change_event.change_date_time >= '%s' "
             
+ "ORDER BY"
             
+ "  change_event.change_date_time DESC "
             
+ "LIMIT 5",
         
LocalDate.now().toString("YYYY-MM-dd"),
         
LocalDate.now().minusDays(14).toString("YYYY-MM-dd"));

 
// Creates a GoogleAdsServiceClient instance.
 
try (GoogleAdsServiceClient client =
      googleAdsClient
.getLatestVersion().createGoogleAdsServiceClient()) {
   
// Issues the search query.
   
SearchPagedResponse response = client.search(String.valueOf(customerId), query);

   
// Processes the rows of the response.
   
for (GoogleAdsRow row : response.iterateAll()) {
     
ChangeEvent event = row.getChangeEvent();

     
// Prints some general information about the change event.
     
System.out.printf(
         
"On '%s', user '%s' used interface '%s' to perform a(n) '%s' operation on a '%s' with"
             
+ " resource name '%s'.%n",
         
event.getChangeDateTime(),
         
event.getUserEmail(),
         
event.getClientType(),
         
event.getResourceChangeOperation(),
         
event.getChangeResourceType(),
         
event.getResourceName());

     
// Prints some detailed information about update and create operations.
     
if (event.getResourceChangeOperation() == ResourceChangeOperation.UPDATE
         
|| event.getResourceChangeOperation() == ResourceChangeOperation.CREATE) {
       
// Retrieves the entity that was changed.
       
Optional<Message> oldResource =
            getResourceByType
(event.getOldResource(), event.getChangeResourceType());
       
Optional<Message> newResource =
            getResourceByType
(event.getNewResource(), event.getChangeResourceType());

       
// Prints the old and new values for each field that was updated/created.
       
for (String changedPath : row.getChangeEvent().getChangedFields().getPathsList()) {
         
// Uses the FieldMasks utility to retrieve a value from a . delimited path.
         
List<? extends Object> oldValue =
              oldResource
.isPresent()
                 
? FieldMasks.getFieldValue(changedPath, oldResource.get())
                 
: Collections.emptyList();
         
List<? extends Object> newValue =
              newResource
.isPresent()
                 
? FieldMasks.getFieldValue(changedPath, newResource.get())
                 
: Collections.emptyList();
         
// Prints different messages for UPDATE and CREATE cases.
         
if (event.getResourceChangeOperation() == ResourceChangeOperation.UPDATE) {
           
System.out.printf("\t %s changed from %s to %s.%n", changedPath, oldValue, newValue);
         
} else if (event.getResourceChangeOperation() == ResourceChangeOperation.CREATE) {
           
System.out.printf("\t %s set to %s.%n", changedPath, newValue);
         
}
       
}
     
}
   
}
 
}
}
     
public void Run(GoogleAdsClient client, long customerId)
{
   
// Get the GoogleAdsService.
   
GoogleAdsServiceClient googleAdsService = client.GetService(
       
Services.V17.GoogleAdsService);

   
// Construct a query to find details for recent changes in your account.
   
// The LIMIT clause is required for the change_event resource.
   
// The maximum size is 10000, but a low limit was set here for demonstrative
   
// purposes.
   
// The WHERE clause on change_date_time is also required. It must specify a
   
// window of at most 30 days within the past 30 days.

   
string startDate = DateTime.Today.Subtract(TimeSpan.FromDays(25)).ToString("yyyyMMdd");
   
string endDate = DateTime.Today.Add(TimeSpan.FromDays(1)).ToString("yyyyMMdd");
   
string searchQuery = $@"
        SELECT
            change_event.resource_name,
            change_event.change_date_time,
            change_event.change_resource_name,
            change_event.user_email,
            change_event.client_type,
            change_event.change_resource_type,
            change_event.old_resource,
            change_event.new_resource,
            change_event.resource_change_operation,
            change_event.changed_fields
        FROM
            change_event
        WHERE
            change_event.change_date_time >= '{startDate}' AND
            change_event.change_date_time <= '{endDate}'
        ORDER BY
            change_event.change_date_time DESC
        LIMIT 5"
;

   
try
   
{
       
// Issue a search request.
        googleAdsService
.SearchStream(customerId.ToString(), searchQuery,
           
delegate (SearchGoogleAdsStreamResponse resp)
           
{
               
// Display the results.
               
foreach (GoogleAdsRow googleAdsRow in resp.Results)
               
{
                   
ChangeEvent changeEvent = googleAdsRow.ChangeEvent;
                   
ChangedResource oldResource = changeEvent.OldResource;
                   
ChangedResource newResource = changeEvent.NewResource;

                   
bool knownResourceType = true;
                   
IMessage oldResourceEntity = null;
                   
IMessage newResourceEntity = null;
                   
switch (changeEvent.ChangeResourceType)
                   
{
                       
case ChangeEventResourceType.Ad:
                            oldResourceEntity
= oldResource.Ad;
                            newResourceEntity
= newResource.Ad;
                           
break;

                       
case ChangeEventResourceType.AdGroup:
                            oldResourceEntity
= oldResource.AdGroup;
                            newResourceEntity
= newResource.AdGroup;
                           
break;

                       
case ChangeEventResourceType.AdGroupAd:
                            oldResourceEntity
= oldResource.AdGroupAd;
                            newResourceEntity
= newResource.AdGroupAd;
                           
break;

                       
case ChangeEventResourceType.AdGroupAsset:
                            oldResourceEntity
= oldResource.AdGroupAsset;
                            newResourceEntity
= newResource.AdGroupAsset;
                           
break;

                       
case ChangeEventResourceType.AdGroupBidModifier:
                            oldResourceEntity
= oldResource.AdGroupBidModifier;
                            newResourceEntity
= newResource.AdGroupBidModifier;
                           
break;

                       
case ChangeEventResourceType.AdGroupCriterion:
                            oldResourceEntity
= oldResource.AdGroupCriterion;
                            newResourceEntity
= newResource.AdGroupCriterion;
                           
break;

                       
case ChangeEventResourceType.AdGroupFeed:
                            oldResourceEntity
= oldResource.AdGroupFeed;
                            newResourceEntity
= newResource.AdGroupFeed;
                           
break;

                       
case ChangeEventResourceType.Asset:
                            oldResourceEntity
= oldResource.Asset;
                            newResourceEntity
= newResource.Asset;
                           
break;

                       
case ChangeEventResourceType.AssetSet:
                            oldResourceEntity
= oldResource.AssetSet;
                            newResourceEntity
= newResource.AssetSet;
                           
break;

                       
case ChangeEventResourceType.AssetSetAsset:
                            oldResourceEntity
= oldResource.AssetSetAsset;
                            newResourceEntity
= newResource.AssetSetAsset;
                           
break;

                       
case ChangeEventResourceType.Campaign:
                            oldResourceEntity
= oldResource.Campaign;
                            newResourceEntity
= newResource.Campaign;
                           
break;

                       
case ChangeEventResourceType.CampaignAsset:
                            oldResourceEntity
= oldResource.CampaignAsset;
                            newResourceEntity
= newResource.CampaignAsset;
                           
break;

                       
case ChangeEventResourceType.CampaignAssetSet:
                            oldResourceEntity
= oldResource.CampaignAssetSet;
                            newResourceEntity
= newResource.CampaignAssetSet;
                           
break;

                       
case ChangeEventResourceType.CampaignBudget:
                            oldResourceEntity
= oldResource.CampaignBudget;
                            newResourceEntity
= newResource.CampaignBudget;
                           
break;

                       
case ChangeEventResourceType.CampaignCriterion:
                            oldResourceEntity
= oldResource.CampaignCriterion;
                            newResourceEntity
= newResource.CampaignCriterion;
                           
break;

                       
case ChangeEventResourceType.CampaignFeed:
                            oldResourceEntity
= oldResource.CampaignFeed;
                            newResourceEntity
= newResource.CampaignFeed;
                           
break;

                       
case ChangeEventResourceType.CustomerAsset:
                            oldResourceEntity
= oldResource.CustomerAsset;
                            newResourceEntity
= newResource.CustomerAsset;
                           
break;

                       
case ChangeEventResourceType.Feed:
                            oldResourceEntity
= oldResource.Feed;
                            newResourceEntity
= newResource.Feed;
                           
break;

                       
case ChangeEventResourceType.FeedItem:
                            oldResourceEntity
= oldResource.FeedItem;
                            newResourceEntity
= newResource.FeedItem;
                           
break;

                       
default:
                            knownResourceType
= false;
                           
break;
                   
}

                   
if (!knownResourceType)
                   
{
                       
Console.WriteLine($"Unknown change_resource_type " +
                            $
"'{changeEvent.ChangeResourceType}'.");
                       
continue;
                   
}

                   
Console.WriteLine($"On #{changeEvent.ChangeDateTime}, user " +
                        $
"{changeEvent.UserEmail} used interface {changeEvent.ClientType} " +
                        $
"to perform a(n) '{changeEvent.ResourceChangeOperation}' " +
                        $
"operation on a '{changeEvent.ChangeResourceType}' with " +
                        $
"resource name {changeEvent.ChangeResourceName}.");

                   
foreach (string fieldMaskPath in changeEvent.ChangedFields.Paths)
                   
{
                       
if (changeEvent.ResourceChangeOperation ==
                           
ResourceChangeOperation.Create)
                       
{
                           
object newValue = FieldMasks.GetFieldValue(
                                fieldMaskPath
, newResourceEntity);
                           
Console.WriteLine($"\t{fieldMaskPath} set to '{newValue}'.");
                       
}
                       
else if (changeEvent.ResourceChangeOperation ==
                           
ResourceChangeOperation.Update)
                       
{
                           
object oldValue = FieldMasks.GetFieldValue(fieldMaskPath,
                                oldResourceEntity
);
                           
object newValue = FieldMasks.GetFieldValue(fieldMaskPath,
                                newResourceEntity
);

                           
Console.WriteLine($"\t{fieldMaskPath} changed from " +
                                $
"'{oldValue}' to '{newValue}'.");
                       
}
                   
}
               
}
           
});
   
}
   
catch (GoogleAdsException e)
   
{
       
Console.WriteLine("Failure:");
       
Console.WriteLine($"Message: {e.Message}");
       
Console.WriteLine($"Failure: {e.Failure}");
       
Console.WriteLine($"Request ID: {e.RequestId}");
       
throw;
   
}
}
     
public static function runExample(GoogleAdsClient $googleAdsClient, int $customerId)
{
    $googleAdsServiceClient
= $googleAdsClient->getGoogleAdsServiceClient();

   
// Constructs a query to find details for recent changes in your account.
   
// The LIMIT clause is required for the change_event resource.
   
// The maximum size is 10000, but a low limit was set here for demonstrative
   
// purposes.
   
// The WHERE clause on change_date_time is also required. It must specify a
   
// window of at most 30 days within the past 30 days.
    $query
= 'SELECT change_event.resource_name, '
       
. 'change_event.change_date_time, '
       
. 'change_event.change_resource_name, '
       
. 'change_event.user_email, '
       
. 'change_event.client_type, '
       
. 'change_event.change_resource_type, '
       
. 'change_event.old_resource, '
       
. 'change_event.new_resource, '
       
. 'change_event.resource_change_operation, '
       
. 'change_event.changed_fields '
       
. 'FROM change_event '
       
. sprintf(
           
'WHERE change_event.change_date_time <= %s ',
            date_format
(new DateTime('+1 day'), 'Ymd')
       
) . sprintf(
           
'AND change_event.change_date_time >= %s ',
            date_format
(new DateTime('-14 days'), 'Ymd')
       
) . 'ORDER BY change_event.change_date_time DESC '
       
. 'LIMIT 5';
   
// Issues a search request.
    $response
=
        $googleAdsServiceClient
->search(SearchGoogleAdsRequest::build($customerId, $query));

   
// Iterates over all rows in all pages and prints the requested field values for
   
// the change event in each row.
   
foreach ($response->iterateAllElements() as $googleAdsRow) {
       
/** @var GoogleAdsRow $googleAdsRow */
        $changeEvent
= $googleAdsRow->getChangeEvent();
        $oldResource
= $changeEvent->getOldResource();
        $newResource
= $changeEvent->getNewResource();

        $isResourceTypeKnown
= true;
        $oldResourceEntity
= null;
        $newResourceEntity
= null;
       
switch ($changeEvent->getChangeResourceType()) {
           
case ChangeEventResourceType::AD:
                $oldResourceEntity
= $oldResource->getAd();
                $newResourceEntity
= $newResource->getAd();
               
break;
           
case ChangeEventResourceType::AD_GROUP:
                $oldResourceEntity
= $oldResource->getAdGroup();
                $newResourceEntity
= $newResource->getAdGroup();
               
break;
           
case ChangeEventResourceType::AD_GROUP_AD:
                $oldResourceEntity
= $oldResource->getAdGroupAd();
                $newResourceEntity
= $newResource->getAdGroupAd();
               
break;
           
case ChangeEventResourceType::AD_GROUP_ASSET:
                $oldResourceEntity
= $oldResource->getAdGroupAsset();
                $newResourceEntity
= $newResource->getAdGroupAsset();
               
break;
           
case ChangeEventResourceType::AD_GROUP_CRITERION:
                $oldResourceEntity
= $oldResource->getAdGroupCriterion();
                $newResourceEntity
= $newResource->getAdGroupCriterion();
               
break;
           
case ChangeEventResourceType::AD_GROUP_BID_MODIFIER:
                $oldResourceEntity
= $oldResource->getAdGroupBidModifier();
                $newResourceEntity
= $newResource->getAdGroupBidModifier();
               
break;
           
case ChangeEventResourceType::ASSET:
                $oldResourceEntity
= $oldResource->getAsset();
                $newResourceEntity
= $newResource->getAsset();
               
break;
           
case ChangeEventResourceType::ASSET_SET:
                $oldResourceEntity
= $oldResource->getAssetSet();
                $newResourceEntity
= $newResource->getAssetSet();
               
break;
           
case ChangeEventResourceType::ASSET_SET_ASSET:
                $oldResourceEntity
= $oldResource->getAssetSetAsset();
                $newResourceEntity
= $newResource->getAssetSetAsset();
               
break;
           
case ChangeEventResourceType::CAMPAIGN:
                $oldResourceEntity
= $oldResource->getCampaign();
                $newResourceEntity
= $newResource->getCampaign();
               
break;
           
case ChangeEventResourceType::CAMPAIGN_ASSET:
                $oldResourceEntity
= $oldResource->getCampaignAsset();
                $newResourceEntity
= $newResource->getCampaignAsset();
               
break;
           
case ChangeEventResourceType::CAMPAIGN_ASSET_SET:
                $oldResourceEntity
= $oldResource->getCampaignAssetSet();
                $newResourceEntity
= $newResource->getCampaignAssetSet();
               
break;
           
case ChangeEventResourceType::CAMPAIGN_BUDGET:
                $oldResourceEntity
= $oldResource->getCampaignBudget();
                $newResourceEntity
= $newResource->getCampaignBudget();
               
break;
           
case ChangeEventResourceType::CAMPAIGN_CRITERION:
                $oldResourceEntity
= $oldResource->getCampaignCriterion();
                $newResourceEntity
= $newResource->getCampaignCriterion();
               
break;
           
case ChangeEventResourceType::AD_GROUP_FEED:
                $oldResourceEntity
= $oldResource->getAdGroupFeed();
                $newResourceEntity
= $newResource->getAdGroupFeed();
               
break;
           
case ChangeEventResourceType::CAMPAIGN_FEED:
                $oldResourceEntity
= $oldResource->getCampaignFeed();
                $newResourceEntity
= $newResource->getCampaignFeed();
               
break;
           
case ChangeEventResourceType::CUSTOMER_ASSET:
                $oldResourceEntity
= $oldResource->getCustomerAsset();
                $newResourceEntity
= $newResource->getCustomerAsset();
               
break;
           
case ChangeEventResourceType::FEED:
                $oldResourceEntity
= $oldResource->getFeed();
                $newResourceEntity
= $newResource->getFeed();
               
break;
           
case ChangeEventResourceType::FEED_ITEM:
                $oldResourceEntity
= $oldResource->getFeedItem();
                $newResourceEntity
= $newResource->getFeedItem();
               
break;
           
default:
                $isResourceTypeKnown
= false;
               
break;
       
}
       
if (!$isResourceTypeKnown) {
            printf
(
               
"Unknown change_resource_type %s.%s",
               
ChangeEventResourceType::name($changeEvent->getChangeResourceType()),
                PHP_EOL
           
);
       
}
        $resourceChangeOperation
= $changeEvent->getResourceChangeOperation();
        printf
(
           
"On %s, user '%s' used interface '%s' to perform a(n) '%s' operation on a '%s' "
           
. "with resource name '%s'.%s",
            $changeEvent
->getChangeDateTime(),
            $changeEvent
->getUserEmail(),
           
ChangeClientType::name($changeEvent->getClientType()),
           
ResourceChangeOperation::name($resourceChangeOperation),
           
ChangeEventResourceType::name($changeEvent->getChangeResourceType()),
            $changeEvent
->getChangeResourceName(),
            PHP_EOL
       
);

       
if (
            $resourceChangeOperation
!== ResourceChangeOperation::CREATE
           
&& $resourceChangeOperation !== ResourceChangeOperation::UPDATE
       
) {
           
continue;
       
}
       
foreach ($changeEvent->getChangedFields()->getPaths() as $path) {
            $newValueStr
= self::convertToString(
               
FieldMasks::getFieldValue($path, $newResourceEntity, true)
           
);
           
if ($resourceChangeOperation === ResourceChangeOperation::CREATE) {
                printf
("\t'$path' set to '%s'.%s", $newValueStr, PHP_EOL);
           
} elseif ($resourceChangeOperation === ResourceChangeOperation::UPDATE) {
                printf
(
                   
"\t'$path' changed from '%s' to '%s'.%s",
                   
self::convertToString(
                       
FieldMasks::getFieldValue($path, $oldResourceEntity, true)
                   
),
                    $newValueStr
,
                    PHP_EOL
               
);
           
}
       
}
   
}
}

/**
 * Converts the specified value to string.
 *
 * @param mixed $value the value to be converted to string
 * @return string the value in string
 */

private static function convertToString($value)
{
   
if (is_null($value)) {
       
return 'no value';
   
}
   
if (gettype($value) === 'boolean') {
       
return $value ? 'true' : 'false';
   
} elseif (gettype($value) === 'object') {
       
if (get_class($value) === RepeatedField::class) {
            $strValues
= [];
           
foreach (iterator_to_array($value->getIterator()) as $element) {
               
/** @type Message $element */
                $strValues
[] = $element->serializeToJsonString();
           
}
           
return '[' . implode(',', $strValues) . ']';
       
}
       
return json_encode($value);
   
} else {
       
return strval($value);
   
}
}
     
def main(client, customer_id):
   
"""Gets specific details about the most recent changes in the given account.

    Args:
      client: The Google Ads client.
      customer_id: The Google Ads customer ID.
    """

    googleads_service
= client.get_service("GoogleAdsService")

   
# Construct a query to find details for recent changes in your account.
   
# The LIMIT clause is required for the change_event resource.
   
# The maximum size is 10000, but a low limit was set here for demonstrative
   
# purposes. For more information see:
   
# https://developers.google.com/google-ads/api/docs/change-event#getting_changes
   
# The WHERE clause on change_date_time is also required. It must specify a
   
# window within the past 30 days.
    tomorrow
= (datetime.now() + timedelta(1)).strftime("%Y-%m-%d")
    two_weeks_ago
= (datetime.now() + timedelta(-14)).strftime("%Y-%m-%d")
    query
= f"""
        SELECT
          change_event.resource_name,
          change_event.change_date_time,
          change_event.change_resource_name,
          change_event.user_email,
          change_event.client_type,
          change_event.change_resource_type,
          change_event.old_resource,
          change_event.new_resource,
          change_event.resource_change_operation,
          change_event.changed_fields
        FROM change_event
        WHERE change_event.change_date_time <= '{tomorrow}'
        AND change_event.change_date_time >= '{two_weeks_ago}'
        ORDER BY change_event.change_date_time DESC
        LIMIT 5"""


    search_request
= client.get_type("SearchGoogleAdsRequest")
    search_request
.customer_id = customer_id
    search_request
.query = query

    results
= googleads_service.search(request=search_request)

   
for row in results:
       
event = row.change_event
        resource_type
= event.change_resource_type.name
       
if resource_type == "AD":
            old_resource
= event.old_resource.ad
            new_resource
= event.new_resource.ad
       
elif resource_type == "AD_GROUP":
            old_resource
= event.old_resource.ad_group
            new_resource
= event.new_resource.ad_group
       
elif resource_type == "AD_GROUP_AD":
            old_resource
= event.old_resource.ad_group_ad
            new_resource
= event.new_resource.ad_group_ad
       
elif resource_type == "AD_GROUP_ASSET":
            old_resource
= event.old_resource.ad_group_asset
            new_resource
= event.new_resource.ad_group_asset
       
elif resource_type == "AD_GROUP_CRITERION":
            old_resource
= event.old_resource.ad_group_criterion
            new_resource
= event.new_resource.ad_group_criterion
       
elif resource_type == "AD_GROUP_BID_MODIFIER":
            old_resource
= event.old_resource.ad_group_bid_modifier
            new_resource
= event.new_resource.ad_group_bid_modifier
       
elif resource_type == "AD_GROUP_FEED":
            old_resource
= event.old_resource.ad_group_feed
            new_resource
= event.new_resource.ad_group_feed
       
elif resource_type == "ASSET":
            old_resource
= event.old_resource.asset
            new_resource
= event.new_resource.asset
       
elif resource_type == "ASSET_SET":
            old_resource
= event.old_resource.asset_set
            new_resource
= event.new_resource.asset_set
       
elif resource_type == "ASSET_SET_ASSET":
            old_resource
= event.old_resource.asset_set_asset
            new_resource
= event.new_resource.asset_set_asset
       
elif resource_type == "CAMPAIGN":
            old_resource
= event.old_resource.campaign
            new_resource
= event.new_resource.campaign
       
elif resource_type == "CAMPAIGN_ASSET":
            old_resource
= event.old_resource.campaign_asset
            new_resource
= event.new_resource.campaign_asset
       
elif resource_type == "CAMPAIGN_ASSET_SET":
            old_resource
= event.old_resource.campaign_asset_set
            new_resource
= event.new_resource.campaign_asset_set
       
elif resource_type == "CAMPAIGN_BUDGET":
            old_resource
= event.old_resource.campaign_budget
            new_resource
= event.new_resource.campaign_budget
       
elif resource_type == "CAMPAIGN_CRITERION":
            old_resource
= event.old_resource.campaign_criterion
            new_resource
= event.new_resource.campaign_criterion
       
elif resource_type == "CAMPAIGN_FEED":
            old_resource
= event.old_resource.campaign_feed
            new_resource
= event.new_resource.campaign_feed
       
elif resource_type == "CUSTOMER_ASSET":
            old_resource
= event.old_resource.customer_asset
            new_resource
= event.new_resource.customer_asset
       
elif resource_type == "FEED":
            old_resource
= event.old_resource.feed
            new_resource
= event.new_resource.feed
       
elif resource_type == "FEED_ITEM":
            old_resource
= event.old_resource.feed_item
            new_resource
= event.new_resource.feed_item
       
else:
           
print(
               
"Unknown change_resource_type: '{event.change_resource_type}'"
           
)
           
# If the resource type is unrecognized then we continue to
           
# the next row.
           
continue

       
print(
            f
"On {event.change_date_time}, user {event.user_email} "
            f
"used interface {event.client_type.name} to perform a(n) "
            f
"{event.resource_change_operation.name} operation on a "
            f
"{event.change_resource_type.name} with resource name "
            f
"'{event.change_resource_name}'"
       
)

        operation_type
= event.resource_change_operation.name

       
if operation_type in ("UPDATE", "CREATE"):
           
for changed_field in event.changed_fields.paths:
               
# Change field name from "type" to "type_" so that it doesn't
               
# raise an exception when accessed on the protobuf object, see:
               
# https://developers.google.com/google-ads/api/docs/client-libs/python/library-version-10#field_names_that_are_reserved_words
               
if changed_field == "type":
                    changed_field
= "type_"

                new_value
= get_nested_attr(new_resource, changed_field)
               
# If the field value is an Enum get the human readable name
               
# so that it is printed instead of the field ID integer.
               
if isinstance(type(new_value), ProtoEnumMeta):
                    new_value
= new_value.name

               
if operation_type == "CREATE":
                   
print(f"\t{changed_field} set to {new_value}")
               
else:
                    old_value
= get_nested_attr(old_resource, changed_field)
                   
# If the field value is an Enum get the human readable name
                   
# so that it is printed instead of the field ID integer.
                   
if isinstance(type(old_value), ProtoEnumMeta):
                        old_value
= old_value.name

                   
print(
                        f
"\t{changed_field} changed from {old_value} to {new_value}"
                   
)
     
def get_change_details(customer_id)
 
# GoogleAdsClient will read a config file from
 
# ENV['HOME']/google_ads_config.rb when called without parameters
  client
= Google::Ads::GoogleAds::GoogleAdsClient.new

 
# Construct a query to find details for recent changes in your account.
 
# The LIMIT clause is required for the change_event resource.
 
# The maximum size is 10000, but a low limit was set here for demonstrative
 
# purposes.
 
# The WHERE clause on change_date_time is also required. It must specify a
 
# window of at most 30 days within the past 30 days.
  query
= <<~QUERY
    SELECT
      change_event
.resource_name,
      change_event
.change_date_time,
      change_event
.change_resource_name,
      change_event
.user_email,
      change_event
.client_type,
      change_event
.change_resource_type,
      change_event
.old_resource,
      change_event
.new_resource,
      change_event
.resource_change_operation,
      change_event
.changed_fields
    FROM
      change_event
    WHERE
      change_event
.change_date_time <= '#{(Date.today + 1).to_s}'
      AND change_event
.change_date_time >= '#{(Date.today - 14).to_s}'
    ORDER BY
      change_event
.change_date_time DESC
    LIMIT
5
  QUERY

 
# Execute the query to fetch results from the API.
  response
= client.service.google_ads.search(
    customer_id
: customer_id,
    query
: query,
   
# The page size is superfluous with the default limit set above, but it's
   
# shown here since it's a good practice to use a reasonable page size when
   
# you set a higher limit.
    page_size
: PAGE_SIZE
 
)

 
# Process the results and output changes.
  response
.each do |row|
   
event = row.change_event
    old_resource
, new_resource = case event.change_resource_type
   
when :AD
     
[event.old_resource.ad, event.new_resource.ad]
   
when :AD_GROUP
     
[event.old_resource.ad_group, event.new_resource.ad_group]
   
when :AD_GROUP_AD
     
[event.old_resource.ad_group_ad, event.new_resource.ad_group_ad]
   
when :AD_GROUP_ASSET
     
[event.old_resource.ad_group_asset, event.new_resource.ad_group_asset]
   
when :AD_GROUP_CRITERION
     
[event.old_resource.ad_group_criterion, event.new_resource.ad_group_criterion]
   
when :AD_GROUP_BID_MODIFIER
     
[event.old_resource.ad_group_bid_modifier, event.new_resource.ad_group_bid_modifier]
   
when :ASSET
     
[event.old_resource.asset, event.new_resource.asset]
   
when :ASSET_SET
     
[event.old_resource.asset_set, event.new_resource.asset_set]
   
when :ASSET_SET_ASSET
     
[event.old_resource.asset_set_asset, event.new_resource.asset_set_asset]
   
when :CAMPAIGN
     
[event.old_resource.campaign, event.new_resource.campaign]
   
when :CAMPAIGN_ASSET
     
[event.old_resource.campaign_asset, event.new_resource.campaign_asset]
   
when :CAMPAIGN_ASSET_SET
     
[event.old_resource.campaign_asset_set, event.new_resource.campaign_asset_set]
   
when :CAMPAIGN_BUDGET
     
[event.old_resource.campaign_budget, event.new_resource.campaign_budget]
   
when :CAMPAIGN_CRITERION
     
[event.old_resource.campaign_criterion, event.new_resource.campaign_criterion]
   
when :AD_GROUP_FEED
     
[event.old_resource.ad_group_feed, event.new_resource.ad_group_feed]
   
when :ASSET
     
[event.old_resource.asset, event.new_resource.asset]
   
when :CAMPAIGN_FEED
     
[event.old_resource.campaign_feed, event.new_resource.campaign_feed]
   
when :CUSTOMER_ASSET
     
[event.old_resource.customer_asset, event.new_resource.customer_asset]
   
when :FEED
     
[event.old_resource.feed, event.new_resource.feed]
   
when :FEED_ITEM
     
[event.old_resource.feed_item, event.new_resource.feed_item]
   
else
      puts
"Unknown change_resource_type #{event.change_resource_type}."
     
next
   
end
    puts
"On #{event.change_date_time}, user #{event.user_email} used interface " \
     
"#{event.client_type} to perform a(n) #{event.resource_change_operation} " \
     
"operation on a #{event.change_resource_type} with resource name " \
     
"#{event.change_resource_name}."
   
if [:UPDATE, :CREATE].include? event.resource_change_operation
     
event.changed_fields.paths.each do |changed_field|
        new_value
= get_value_from_path(changed_field, new_resource)
       
if :CREATE == event.resource_change_operation
          puts
"\t#{changed_field} set to '#{new_value}'."
       
else
          old_value
= get_value_from_path(changed_field, old_resource)
          puts
"\t#{changed_field} changed from '#{old_value}' to '#{new_value}'."
       
end
     
end
   
end
 
end
end

# Given the string value of a path from the response, look up the value of the
# field located at that path on the given object.
def get_value_from_path(path, object)
  path
.split(".").inject(object) {|obj, key| obj.send(key)}
end
     
sub get_change_details {
 
my ($api_client, $customer_id) = @_;

 
# Construct a query to find details for recent changes in your account.
 
# The LIMIT clause is required for the change_event resource.
 
# The maximum size is 10000, but a low limit was set here for demonstrative
 
# purposes.
 
# The WHERE clause on change_date_time is also required. It must specify a
 
# window of at most 30 days within the past 30 days.
 
my $search_query =
   
"SELECT change_event.resource_name, change_event.change_date_time, " .
   
"change_event.change_resource_name, change_event.user_email, " .
   
"change_event.client_type, change_event.change_resource_type, " .
   
"change_event.old_resource, change_event.new_resource, " .
   
"change_event.resource_change_operation, change_event.changed_fields " .
   
"FROM change_event " .
   
"WHERE change_event.change_date_time DURING LAST_14_DAYS " .
   
"ORDER BY change_event.change_date_time DESC LIMIT 5";

 
# Create a search Google Ads request that will retrieve all change events using
 
# pages of the specified page size.
 
my $search_request =
   
Google::Ads::GoogleAds::V17::Services::GoogleAdsService::SearchGoogleAdsRequest
   
->new({
      customerId
=> $customer_id,
      query      
=> $search_query
   
});

 
# Get the GoogleAdsService.
 
my $google_ads_service = $api_client->GoogleAdsService();

 
my $iterator = Google::Ads::GoogleAds::Utils::SearchGoogleAdsIterator->new({
    service
=> $google_ads_service,
    request
=> $search_request
 
});

 
# Iterate over all rows in all pages and print the requested field values for
 
# the change event in each row.
 
while ($iterator->has_next) {
   
my $google_ads_row = $iterator->next;

   
my $change_event = $google_ads_row->{changeEvent};
    printf
"On %s, user %s used interface %s to perform a(n) %s operation " .
     
"on a %s with resource name '%s'.\n", $change_event->{changeDateTime},
      $change_event
->{userEmail}, $change_event->{clientType},
      $change_event
->{resourceChangeOperation},
      $change_event
->{changeResourceType}, $change_event->{changeResourceName};

   
if (grep /$change_event->{resourceChangeOperation}/, (CREATE, UPDATE)) {
     
my ($old_resource, $new_resource) =
        _get_changed_resources_for_resource_type
($change_event);

     
foreach my $changed_field (split /,/, $change_event->{changedFields}) {
       
my $new_value =
          _convert_to_string
(get_field_value($new_resource, $changed_field))
         
|| "";
       
if ($change_event->{resourceChangeOperation} eq CREATE) {
         
print "\t$changed_field set to '$new_value'.\n";
       
} else {
         
my $old_value =
            _convert_to_string
(get_field_value($old_resource, $changed_field))
           
|| "";
         
print "\t$changed_field changed from '$old_value' to '$new_value'.\n";
       
}
     
}
   
}
 
}

 
return 1;
}

# This method converts the specified value to a string.
sub _convert_to_string {
 
my $value        = shift;
 
my $string_value = "";

 
if (ref($value) eq "ARRAY") {
    $string_value
.= "[";
   
foreach my $item (@$value) {
     
if (is_hash_ref($item)) {
        $string_value
.= (JSON::XS->new->utf8->encode($item) . ",");
     
} else {
        $string_value
.= ($item . ",");
     
}
   
}
    $string_value
.= "]";
 
} elsif (is_hash_ref($value)) {
    $string_value
.= JSON::XS->new->utf8->encode($value);
 
} else {
    $string_value
= $value;
 
}
 
return $string_value;
}

# This method returns the old resource and new resource based on the change
# resource type of a change event.
sub _get_changed_resources_for_resource_type {
 
my $change_event  = shift;
 
my $resource_type = $change_event->{changeResourceType};
 
if ($resource_type eq AD) {
   
return $change_event->{oldResource}{ad}, $change_event->{newResource}{ad};
 
} elsif ($resource_type eq AD_GROUP) {
   
return $change_event->{oldResource}{adGroup},
      $change_event
->{newResource}{adGroup};
 
} elsif ($resource_type eq AD_GROUP_AD) {
   
return $change_event->{oldResource}{adGroupAd},
      $change_event
->{newResource}{adGroupAd};
 
} elsif ($resource_type eq AD_GROUP_ASSET) {
   
return $change_event->{oldResource}{adGroupAsset},
      $change_event
->{newResource}{adGroupAsset};
 
} elsif ($resource_type eq AD_GROUP_CRITERION) {
   
return $change_event->{oldResource}{adGroupCriterion},
      $change_event
->{newResource}{adGroupCriterion};
 
} elsif ($resource_type eq AD_GROUP_BID_MODIFIER) {
   
return $change_event->{oldResource}{adGroupBidModifier},
      $change_event
->{newResource}{adGroupBidModifier};
 
} elsif ($resource_type eq AD_GROUP_FEED) {
   
return $change_event->{oldResource}{adGroupFeed},
      $change_event
->{newResource}{adGroupFeed};
 
} elsif ($resource_type eq ASSET) {
   
return $change_event->{oldResource}{asset},
      $change_event
->{newResource}{asset};
 
} elsif ($resource_type eq ASSET_SET) {
   
return $change_event->{oldResource}{assetSet},
      $change_event
->{newResource}{assetSet};
 
} elsif ($resource_type eq ASSET_SET_ASSET) {
   
return $change_event->{oldResource}{assetSetAsset},
      $change_event
->{newResource}{assetSetAsset};
 
} elsif ($resource_type eq CAMPAIGN) {
   
return $change_event->{oldResource}{campaign},
      $change_event
->{newResource}{campaign};
 
} elsif ($resource_type eq CAMPAIGN_ASSET) {
   
return $change_event->{oldResource}{campaignAsset},
      $change_event
->{newResource}{campaignAsset};
 
} elsif ($resource_type eq CAMPAIGN_ASSET_SET) {
   
return $change_event->{oldResource}{campaignAssetSet},
      $change_event
->{newResource}{campaignAssetSet};
 
} elsif ($resource_type eq CAMPAIGN_BUDGET) {
   
return $change_event->{oldResource}{campaignBudget},
      $change_event
->{newResource}{campaignBudget};
 
} elsif ($resource_type eq CAMPAIGN_CRITERION) {
   
return $change_event->{oldResource}{campaignCriterion},
      $change_event
->{newResource}{campaignCriterion};
 
} elsif ($resource_type eq CAMPAIGN_FEED) {
   
return $change_event->{oldResource}{campaignFeed},
      $change_event
->{newResource}{campaignFeed};
 
} elsif ($resource_type eq CUSTOMER_ASSET) {
   
return $change_event->{oldResource}{customerAsset},
      $change_event
->{newResource}{customerAsset};
 
} elsif ($resource_type eq FEED) {
   
return $change_event->{oldResource}{feed},
      $change_event
->{newResource}{feed};
 
} elsif ($resource_type eq FEED_ITEM) {
   
return $change_event->{oldResource}{feedItem},
      $change_event
->{newResource}{feedItem};
 
} else {
   
print "Unknown change_resource_type $resource_type.\n";
 
}
}
     

Ограничения

Событие изменения не может включать в себя все строки из истории изменений в веб-клиенте. Для представления, аналогичного Истории изменений, используйте вместо этого ресурс статуса изменения .

Ресурс события изменения предназначен для детального изучения особенностей отдельного изменения. Вы можете получить такие данные, как конкретные значения полей, которые были изменены, кто внес изменения и какой тип клиента использовался для внесения изменений. Однако не для всех изменений в вашей учетной записи будет соответствующая запись о событии изменения.

Некоторые ключевые типы клиентов, которые записывают свои изменения для использования с событиями изменения, включают:

  • API Google Рекламы
  • Веб-клиент Google Рекламы