Поиск и выполнение отчетов

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

В этом руководстве подробно описано, как программно генерировать файлы отчетов с помощью службы Reports .

Найти отчет

Чтобы запустить отчет, вам нужно знать идентификатор отчета. Если вы только что создали или обновили отчет , это значение можно найти в поле id возвращенного ресурса отчета. Пользователям рекомендуется сохранять эти возвращенные идентификаторы для последующего поиска.

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

С#

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));

Джава

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));

Питон

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 службы отчетов, как в примере ниже:

С#

// Run the report.
File file = service.Reports.Run(profileId, reportId).Execute();

Джава

// Run the report.
File file = reporting.reports().run(profileId, reportId).execute();

PHP

// Run the report.
$file = $this->service->reports->run($userProfileId, $reportId);

питон

# 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)

Ответом на этот запрос является ресурс Files . Если бы это был успешный запрос синхронного запуска, все поля возвращаемого ресурса были бы заполнены, и файл был бы готов к загрузке. Однако, поскольку это был асинхронный запрос на выполнение, некоторые ключевые поля будут отсутствовать, а status файла будет установлен на PROCESSING , так как отчет еще не завершен.

Когда отчет закончен?

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

  1. Поле id , которое можно использовать для ссылки на этот файл в последующих запросах.
  2. Поле status , которое представляет текущее состояние выполнения отчета.

Чтобы определить, когда отчет завершен, вам необходимо периодически проверять status файла, как в примере ниже:

С#

// 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);

Джава

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);

питон

# 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 , файл готов к загрузке. Как показано в приведенном выше примере, настоятельно рекомендуется реализовать экспоненциальную стратегию отсрочки при подобном опросе, чтобы оптимизировать использование квоты запросов .