После того как вы определили или создали отчет, отвечающий вашим потребностям, настало время сгенерировать выходные данные. Выходные данные отчета хранятся в файлах отчетов, которые можно получить и изменить программным способом. Файл отчета создается в результате выполнения отчета.
В этом руководстве подробно описано, как программно создавать файлы отчетов с помощью службы отчетов .
Найти отчет
Для запуска отчета необходимо знать его идентификатор (ID). Если вы только что создали или обновили отчет , это значение можно найти в поле id ресурса отчета, который был возвращен. Рекомендуется сохранять эти возвращенные идентификаторы для последующего поиска.
Если вы не знаете идентификатор нужного отчета, вы можете просмотреть список всех доступных отчетов, чтобы найти нужный. Пример ниже иллюстрирует поиск отчета по заданным пользователем критериям:
C#
Report target = null;
ReportList reports;
String nextPageToken = null;
do {
// Create and execute the reports list request.
ReportsResource.ListRequest request = service.Reports.List(profileId);
request.PageToken = nextPageToken;
reports = request.Execute();
foreach (Report report in reports.Items) {
if (IsTargetReport(report)) {
target = report;
break;
}
}
// Update the next page token.
nextPageToken = reports.NextPageToken;
} while (target == null
&& reports.Items.Any()
&& !String.IsNullOrEmpty(nextPageToken));
Java
Report target = null;
ReportList reports;
String nextPageToken = null;
do {
// Create and execute the reports list request.
reports = reporting.reports().list(profileId).setPageToken(nextPageToken).execute();
for (Report report : reports.getItems()) {
if (isTargetReport(report)) {
target = report;
break;
}
}
// Update the next page token.
nextPageToken = reports.getNextPageToken();
} while (target == null
&& !reports.getItems().isEmpty()
&& !Strings.isNullOrEmpty(nextPageToken));
PHP
$target = null;
$response = null;
$pageToken = null;
do {
// Create and execute the report list request.
$response = $this->service->reports->listReports(
$userProfileId,
['pageToken' => $pageToken]
);
foreach ($response->getItems() as $report) {
if ($this->isTargetReport($report)) {
$target = $report;
break;
}
}
$pageToken = $response->getNextPageToken();
} while (empty($target) && !empty($response->getItems()) && !empty($pageToken));
Python
target = None
# Construct the request.
request = service.reports().list(profileId=profile_id)
while True:
response = request.execute()
for report in response['items']:
if is_target_report(report):
target = report
break
if not target and response['items'] and response['nextPageToken']:
request = service.reports().list_next(request, response)
else:
break
Руби
page_token = nil
target = nil
loop do
result = service.list_reports(profile_id, page_token: page_token)
result.items.each do |report|
if target_report?(report)
target = report
break
end
end
page_token = (result.next_page_token if target.nil? && result.items.any?)
break if page_token.to_s.empty?
end
Для получения информации о дополнительных параметрах, которые можно указать для управления сортировкой и упорядочиванием списка возвращаемых отчетов, обратитесь к справочной документации . Управление сортировкой и упорядочиванием этого списка может быть особенно полезно для поиска отчетов, которые были недавно изменены.
Создать отчет
Найдя подходящий отчет, вы можете использовать службу отчетов для его запуска и создания нового файла отчета. Отчеты могут запускаться как синхронно, так и асинхронно (по умолчанию), в зависимости от сложности отчета и времени его обработки. Подробную информацию о синхронных и асинхронных отчетах см. в руководстве по синхронным отчетам.
Для запуска отчета необходимо вызвать метод `run` службы `Report`, как показано в примере ниже:
C#
// Run the report.
File file = service.Reports.Run(profileId, reportId).Execute();
Java
// Run the report.
File file = reporting.reports().run(profileId, reportId).execute();
PHP
// Run the report.
$file = $this->service->reports->run($userProfileId, $reportId);
Python
# Run the report.
report_file = service.reports().run(
profileId=profile_id, reportId=report_id).execute()
Руби
# Run the report.
report_file = service.run_report(profile_id, report_id)
В ответ на этот запрос выдается ресурс типа «Файлы» . Если бы это был успешный синхронный запрос на выполнение, все поля возвращенного ресурса были бы заполнены, и файл был бы готов к загрузке. Однако, поскольку это был асинхронный запрос на выполнение, некоторые ключевые поля будут отсутствовать, а status файла будет установлен на PROCESSING , поскольку выполнение отчета еще не завершено.
Когда завершается формирование отчета?
При асинхронном запуске отчета немедленно генерируется файл-заполнитель, и отчет помещается в очередь на обработку. Файл-заполнитель будет содержать две ключевые части информации, которые помогут вам определить, когда выполнение отчета завершено:
- Поле
id, которое можно использовать для ссылки на этот файл в последующих запросах. - Поле
status, отражающее текущее состояние выполнения отчета.
Чтобы определить, когда выполнение отчета завершено, необходимо периодически проверять status файла, как показано в примере ниже:
C#
// Wait for the report file to finish processing.
// An exponential backoff policy is used to limit retries and conserve quota.
int sleep = 0;
int startTime = GetCurrentTimeInSeconds();
do {
File file = service.Files.Get(reportId, fileId).Execute();
if ("REPORT_AVAILABLE".Equals(file.Status)) {
Console.WriteLine("File status is {0}, ready to download.", file.Status);
return;
} else if (!"PROCESSING".Equals(file.Status)) {
Console.WriteLine("File status is {0}, processing failed.", file.Status);
return;
} else if (GetCurrentTimeInSeconds() - startTime > MAX_RETRY_ELAPSED_TIME) {
Console.WriteLine("File processing deadline exceeded.");
return;
}
sleep = GetNextSleepInterval(sleep);
Console.WriteLine("File status is {0}, sleeping for {1} seconds.", file.Status, sleep);
Thread.Sleep(sleep * 1000);
} while (true);
Java
BackOff backOff =
new ExponentialBackOff.Builder()
.setInitialIntervalMillis(10 * 1000) // 10 second initial retry
.setMaxIntervalMillis(10 * 60 * 1000) // 10 minute maximum retry
.setMaxElapsedTimeMillis(60 * 60 * 1000) // 1 hour total retry
.build();
do {
File file = reporting.files().get(reportId, fileId).execute();
if ("REPORT_AVAILABLE".equals(file.getStatus())) {
// File has finished processing.
System.out.printf("File status is %s, ready to download.%n", file.getStatus());
return file;
} else if (!"PROCESSING".equals(file.getStatus())) {
// File failed to process.
System.out.printf("File status is %s, processing failed.", file.getStatus());
return null;
}
// The file hasn't finished processing yet, wait before checking again.
long retryInterval = backOff.nextBackOffMillis();
if (retryInterval == BackOff.STOP) {
System.out.println("File processing deadline exceeded.%n");
return null;
}
System.out.printf("File status is %s, sleeping for %dms.%n", file.getStatus(), retryInterval);
Thread.sleep(retryInterval);
} while (true);
PHP
// Wait for the report file to finish processing.
// An exponential backoff policy is used to limit retries and conserve
// quota.
$sleep = 0;
$startTime = time();
do {
$file = $this->service->files->get($reportId, $fileId);
if ($file->getStatus() === 'REPORT_AVAILABLE') {
printf('File status is %s, ready to download<br>', $file->getStatus());
return $file;
} elseif ($file->getStatus() !== 'PROCESSING') {
printf('File status is %s, processing failed<br>', $file->getStatus());
return null;
} elseif (time() - $startTime > self::MAX_RETRY_ELAPSED_TIME) {
printf('File processing deadline exceeded<br>');
return null;
}
$sleep = $this->getNextSleepInterval($sleep);
printf(
'File status is %s, sleeping for %d seconds<br>',
$file->getStatus(),
$sleep
);
$this->sleep($sleep);
} while (true);
Python
# Wait for the report file to finish processing.
# An exponential backoff strategy is used to conserve request quota.
sleep = 0
start_time = time.time()
while True:
report_file = service.files().get(
reportId=report_id, fileId=file_id).execute()
status = report_file['status']
if status == 'REPORT_AVAILABLE':
print 'File status is %s, ready to download.' % status
return
elif status != 'PROCESSING':
print 'File status is %s, processing failed.' % status
return
elif time.time() - start_time > MAX_RETRY_ELAPSED_TIME:
print 'File processing deadline exceeded.'
return
sleep = next_sleep_interval(sleep)
print 'File status is %s, sleeping for %d seconds.' % (status, sleep)
time.sleep(sleep)
Руби
# Wait for the report file to finish processing.
# An exponential backoff strategy is used to conserve request quota.
interval = 0
start_time = Time.now
loop do
report_file = service.get_file(report_id, file_id)
status = report_file.status
if status == 'REPORT_AVAILABLE'
puts format('File status is %s, ready to download.', status)
break
elsif status != 'PROCESSING'
puts format('File status is %s, processing failed.', status)
break
elsif Time.now - start_time > MAX_RETRY_ELAPSED_TIME
puts 'File processing deadline exceeded.'
break
end
interval = next_sleep_interval(interval)
puts format('File status is %s, sleeping for %d seconds.', status,
interval)
sleep(interval)
end
Когда status изменится на REPORT_AVAILABLE , файл будет готов к загрузке. Как показано в приведенном выше примере, настоятельно рекомендуется использовать стратегию экспоненциальной задержки при подобном опросе, чтобы оптимизировать использование квоты запросов .