Once you've identified or created a report that satisfies your needs, it's time to generate output. Report output is stored in report files, which can be retrieved and manipulated programmatically. A report file is produced as the result of running a report.
This guide details how to programmatically generate report files via the Reports service .
Find a report
In order to run a report, you need to know the report's ID. If you've just created or updated a report
, this value can be found in the id
field of the report resource that was returned. It's recommended that users store these returned IDs for later lookup.
If you don't know the ID of the report you'd like to run, you can look through the list of all available reports to find the one you want. The example below illustrates how to look up a report by some user-defined criteria:
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
Refer to the reference documentation for optional parameters you can specify to control how the list of returned reports are sorted and ordered. Controlling the sorting and ordering of this list can be especially useful to find reports that were modified recently.
Run a report
Once you've found a suitable report, you can use the Report service to run it and generate a new report file. Reports can be run either synchronously or asynchronously (default), depending on the complexity of the report and the time it will take to process. See the Synchronous Reports guide for details on synchronous vs. asynchronous reporting.
To run a report, you make a call to the run method of the Report service, as in the example below:
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
)
The response to this request is a Files resource
. If this were a successful synchronous run request, all fields of the returned resource would be filled out and the file would be ready to download. Since this was an asynchronous run request, however, certain key fields will be missing and the file's status
will be set to PROCESSING
, since the report has not yet finished running.
When is a report finished running?
When you run a report asynchronously, a placeholder file is generated immediately and the report is put into a queue to be processed. The placeholder will contain two key pieces of information to help you determine when the report is finished running:
- An
id
field, which can be used to reference this file in subsequent requests. - A
status
field, which represents the current state of the report run.
To determine when a report has finished running, you'll need to periodically check the status
of the file, as in the example below:
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
When the status
changes to REPORT_AVAILABLE
, the file is ready to download. As shown in the above example, it is strongly recommended that you implement an exponential backoff strategy when polling like this, to optimize your request quota usage
.