אחרי שזיהיתם או יצרתם דוח שמתאים לצרכים שלכם, הגיע הזמן להפיק את הדוח. פלט הדוח מאוחסן בקובצי דוח, שאותם ניתן לאחזר ולשנות באופן פרוגרמטי. קובץ דוח נוצר כתוצאה מהרצת דוח.
במדריך הזה מוסבר איך ליצור קובצי דוחות באופן פרוגרמטי באמצעות שירות הדוחות.
חיפוש דוח
כדי להריץ דוח, צריך לדעת מהו מזהה הדוח. אם יצרתם או עדכנתם דוח לפני זמן קצר, הערך הזה מופיע בשדה 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
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
במאמרי העזרה תוכלו למצוא פרמטרים אופציונליים שאפשר להגדיר כדי לקבוע איך יתבצע המיון והסדר של רשימת הדוחות המוחזרים. שליטה במיון ובסדר של הרשימה הזו יכולה להיות שימושית במיוחד כדי למצוא דוחות ששונו לאחרונה.
הרצת דוח
לאחר שתמצאו דוח מתאים, תוכלו להשתמש בשירות הדוחות כדי להפיק אותו וליצור קובץ דוח חדש. הרצת דוחות יכולה להתבצע באופן סינכרוני או אסינכרוני (ברירת המחדל), בהתאם למורכבות הדוח ולמשך הזמן הדרוש לעיבוד שלו. לפרטים על דיווח סינכרוני לעומת דיווח אסינכרוני, אפשר לעיין במדריך דוחות סינכרוניים.
כדי להפיק דוח, צריך להפעיל את שיטת ההרצה של שירות הדיווח, כמו בדוגמה הבאה:
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()
Ruby
# Run the report.
report_file = service.run_report(profile_id, report_id)
התשובה לבקשה הזו היא משאב של קבצים. אם זו בקשת הרצה מסונכרנת בהצלחה, כל השדות של המשאב שהוחזר ימולאו והקובץ יהיה מוכן להורדה. עם זאת, מכיוון שזו הייתה בקשת הרצה אסינכרונית, שדות מפתח מסוימים יהיו חסרים וה-status
של הקובץ יוגדר ל-PROCESSING
, מכיוון שהרצת הדוח עדיין לא הסתיימה.
מתי מסתיים הפקת הדוח?
כאשר מריצים דוח באופן אסינכרוני, קובץ placeholder נוצר באופן מיידי והדוח מועבר לתור לעיבוד. ה-placeholder מכיל שני פרטים חשובים שיעזרו לכם לקבוע מתי הרצת הדוח הסתיימה:
- שדה
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)
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
כשהערך של status
ישתנה ל-REPORT_AVAILABLE
, הקובץ יהיה מוכן להורדה. כפי שמוצג בדוגמה שלמעלה, מומלץ מאוד להטמיע אסטרטגיית השהיה מעריכית לפני ניסיון חוזר (exponential backoff) במהלך דגימה כזו כדי לבצע אופטימיזציה של השימוש במכסת הבקשות.