Событие изменения предоставляет подробную информацию о том, что изменилось в вашей учетной записи. При отчете об операции создания возвращаются все новые значения полей; а при составлении отчета об операции обновления возвращаются как новые, так и старые значения, что дает вам полную картину отдельных изменений.
Кроме того, указывается тип клиента (например, API или веб-клиент), который использовался для внесения изменения, а также то, какой пользователь внес это изменение, при условии, что информация также отображается в истории изменений веб-клиента.
Изменить типы событий
Отслеживаются следующие типы ресурсов :
Тип ресурса | Ценить |
---|---|
Объявление | AD |
Группа объявлений | AD_ |
Объявление группы объявлений | AD_ |
Модификатор ставок на уровне группы объявлений | AD_ |
Критерий группы объявлений | AD_ |
Кампания | CAMPAIGN |
Бюджет кампании | CAMPAIGN_ |
Критерий кампании | CAMPAIGN_ |
Фид группы объявлений | AD_ |
Фид кампании | CAMPAIGN_ |
Кормить | FEED |
Элемент фида | FEED_ |
Объект | ASSET |
Актив клиента | CUSTOMER_ |
Объект кампании | CAMPAIGN_ |
Объект группы объявлений | AD_ |
Запрос
Список изменений необходимо фильтровать по дате. Диапазон дат должен быть в пределах последних 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 Рекламы