  def ExecuteQuery(
      self, qfilter: Optional[List[str]] = None) -> List[Dict[str, Any]]:
    """Query logs in GCP project.

    Args:
      qfilter (List[str]): Optional. A list of query filters to use.

    Returns:
      List[Dict]: Log entries returned by the query, e.g. [{'projectIds':
          [...], 'resourceNames': [...]}, {...}]

    Raises:
      RuntimeError: If API call failed.
      ValueError: If the number of project IDs being queried doesn't match
          the number of provided filters.
    """

    entries = []
    gcl_instance_client = self.GclApi().entries() # pylint: disable=no-member

    if qfilter and len(self.project_ids) != len(qfilter):
      raise ValueError(
          'Several project IDs detected ({0:d}) but only {1:d} query filters '
          'provided.'.format(len(self.project_ids), len(qfilter)))

    for idx, project_id in enumerate(self.project_ids):
      body = {
          'resourceNames': 'projects/' + project_id,
          'filter': qfilter[idx] if qfilter else '',
          'orderBy': 'timestamp desc',
      }
      responses = common.ExecuteRequest(
          gcl_instance_client, 'list', {'body': body}, throttle=True)
      for response in responses:
        for entry in response.get('entries', []):
          entries.append(entry)
    return entries
Query logs in GCP project.

Args:
qfilter (List[str]): Optional. A list of query filters to use.

Returns:
List[Dict]: Log entries returned by the query, e.g. [{'projectIds':
[...], 'resourceNames': [...]}, {...}]

Raises:
RuntimeError: If API call failed.
ValueError: If the number of project IDs being queried doesn't match
the number of provided filters.
libcloudforensics/providers/gcp/internal/log.py