Berichte suchen und erstellen

Wenn Sie einen Bericht gefunden oder erstellt haben, der Ihren Anforderungen entspricht, können Sie die Ausgabe generieren. Die Berichtsausgabe wird in Berichtsdateien gespeichert, die programmatisch abgerufen und bearbeitet werden können. Eine Berichtsdatei wird als Ergebnis der Ausführung eines Berichts erstellt.

In dieser Anleitung wird beschrieben, wie Sie Berichtsdateien programmatisch über den Reports-Dienst erstellen.

Bericht suchen

Um einen Bericht zu erstellen, benötigen Sie die ID des Berichts. Wenn Sie gerade einen Bericht erstellt oder aktualisiert haben, finden Sie diesen Wert im Feld id der zurückgegebenen Berichtsressource. Es wird empfohlen, dass Nutzer diese zurückgegebenen IDs für die spätere Suche speichern.

Wenn Sie die ID des Berichts, den Sie ausführen möchten, nicht kennen, können Sie in der Liste aller verfügbaren Berichte nach dem gewünschten Bericht suchen. Im folgenden Beispiel wird veranschaulicht, wie Sie einen Bericht anhand einiger benutzerdefinierter Kriterien suchen:

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=str(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

Ruby

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

In der Referenzdokumentation finden Sie optionale Parameter, mit denen Sie festlegen können, wie die Liste der zurückgegebenen Berichte sortiert und angeordnet wird. Die Sortierung und Reihenfolge dieser Liste zu steuern, kann besonders nützlich sein, um Berichte zu finden, die kürzlich geändert wurden.

Bericht erstellen

Wenn Sie einen geeigneten Bericht gefunden haben, können Sie ihn mit dem Report-Dienst ausführen und eine neue Berichtsdatei generieren. Berichte können je nach Komplexität und Verarbeitungszeit synchron oder asynchron (Standard) ausgeführt werden. Weitere Informationen zu synchronen und asynchronen Berichten finden Sie im Leitfaden Synchrone Berichte.

Wenn Sie einen Bericht ausführen möchten, rufen Sie die Methode „run“ des Report-Dienstes auf, wie im folgenden Beispiel:

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=str(profile_id), reportId=str(report_id))
    .execute()
)

Ruby

# Run the report.
report_file = service.run_report(profile_id, report_id)

Die Antwort auf diese Anfrage ist eine Files-Ressource. Wäre dies eine erfolgreiche synchrone Anfrage, wären alle Felder der zurückgegebenen Ressource ausgefüllt und die Datei wäre zum Herunterladen bereit. Da es sich um eine asynchrone Anfrage handelt, fehlen jedoch bestimmte Schlüsselfelder und status der Datei ist auf PROCESSING festgelegt, da die Ausführung des Berichts noch nicht abgeschlossen ist.

Wann ist die Ausführung eines Berichts abgeschlossen?

Wenn Sie einen Bericht asynchron ausführen, wird sofort eine Platzhalterdatei generiert und der Bericht wird in eine Warteschlange zur Verarbeitung gestellt. Der Platzhalter enthält zwei wichtige Informationen, mit denen Sie feststellen können, wann der Bericht fertig ist:

  1. Ein id-Feld, mit dem in nachfolgenden Anfragen auf diese Datei verwiesen werden kann.
  2. Ein status-Feld, das den aktuellen Status der Berichterstellung darstellt.

Um festzustellen, wann ein Bericht fertig ist, müssen Sie regelmäßig den status der Datei prüfen, wie im folgenden Beispiel:

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=str(report_id), fileId=str(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)

Ruby

# 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

Wenn sich status in REPORT_AVAILABLE ändert, kann die Datei heruntergeladen werden. Wie im obigen Beispiel gezeigt, wird dringend empfohlen, bei solchen Polling-Vorgängen eine Strategie für den exponentiellen Backoff zu implementieren, um die Nutzung des Anforderungskontingents zu optimieren.