Logging

Fleet Engine offers a simple logging service that lets you save its API requests and response payloads. With these logs, you can debug your integration, create monitoring metrics, and analyze traffic patterns.

Fleet Engine sends the logs as platform logs to Cloud Logging, so that you can use the Cloud Logging tools to access them.

What Fleet Engine logs

Fleet Engine sends multiple pieces of information to Cloud Logging, such as:

  • All authenticated REST and gRPC requests and responses
  • Error responses
  • Requests, responses, and error messages from calls initiated by the Driver SDK to the Fleet Engine.
  • Split logs for supported log types:

See documentation for available log messages and schema in the Logging Reference.

Use restricted and default log buckets to comply with data retention policies

Using "restricted" and "default" buckets ensures a clear picture of your restricted and unrestricted data usage. Some of the log data that Fleet Engine sends to Google Maps Platform may only be retained for a limited period of time, according to the Mobility Service Specific Terms. To make sure you retain restricted data for only the amount of time allowed, such data should be labeled as TOS_RESTRICTED (Fleet Engine does this already) and logged to a dedicated bucket called "restricted".

From there, you can control how long it's retained and purge it automatically on expiration using Cloud Logging settings. For example, restricted-use logs should only be retained for 30 days.

Log all remaining unrestricted data to the "default" bucket, where it can be retained for longer durations as defined in the Mobility Service Specific Terms (typically for 1 year). Using "restricted" and "default" buckets ensures clear picture of your restricted and unrestricted data usage.

Get a complete view by merging restricted and unrestricted logs

Restricted-use logs contain the restricted-use data and a reference to the default log so that they can be considered together. The restricted-use log contains the default log's insertId as a reference in the parent_insert_id field. You can use this field to join the data from both logs and get the complete picture.

See documentation for all available log messages and schema in the Logging Reference.

Enabling Cloud Logging

Fleet Engine automatically enables default logs for new Mobility customers, starting with projects created on February 10, 2022. You can confirm whether logging is enabled by using the following query in the Logs Explorer :

resource.type:"fleetengine.googleapis.com/DeliveryFleet"

If you don't see any logs for that query, Cloud Logging might not have been enabled for your project. Contact Support if you want to enable the feature.

Enable restricted-use logs

Restricted-use logs are enabled on request. To enable these logs for your Google Cloud project, complete the following steps:

Prepare your project to receive restricted-use logs

  1. In the Google Cloud console, open the Log Router page.
  2. Update the _Default logging bucket to exclude restricted-use logs.
    1. Select the _Default logging bucket and then choose Edit sink.
    2. On the "Choose logs to filter out of sink" section, click the "Add Exclusion" button:
      1. Exclusion filter name: ExcludeRestrictedLogs
      2. Exclusion filter: labels.restriction="TOS_RESTRICTED"
    3. Click "Update sink".
  3. Update the Restricted logging bucket to store the restricted-use logs.
    1. From the Log Router page, select "Create sink".
    2. Create a sink with the following settings:
      1. Sink details:
        1. Name: RestrictedLogs
        2. Description: Routes Fleet Engine restricted-use logs
      2. Sink destination:
        1. Sink service: Logging bucket
        2. Select log bucket: Create new log bucket
          1. Name: Restricted
          2. Description: Contains Fleet Engine restricted-use logs
        3. Retention period: 30 days
          1. Note: The retention period must not exceed 30 days.
      3. Logs to include in sink: leave empty
      4. Logs to filter out of sink: Click "Add Exclusion"
        1. Exclusion filter name: ExcludeNonRestrictedLogs
        2. Exclusion filter: NOT (resource.type = "fleetengine.googleapis.com/Fleet" OR resource.type = "fleetengine.googleapis.com/DeliveryFleet") NOT (labels.restriction = "TOS_RESTRICTED")
      5. Click "Create sink"

Contact support to enable restricted-use logs

Then, contact support and provide the following information in your support request:

  1. Project ID(s) to enable:
  2. Email address of the person requesting the change:
    1. Note: This person should have Edit access to the Google Cloud Projects listed.
  3. By enabling restricted-use Google Maps Content in Cloud Logging, you agree to adhere to the Google Maps Platform terms and Mobility service specific terms, including caching and permitted use requirements as they relate to Google Maps Content. Yes / No

Once the support team receives your request, it sends confirmation that logging has been enabled for your project

Split Cloud Logs

Cloud Logging limits size on incoming logs to 256KB. The service drops logs beyond that threshold. To ensure that Cloud Logging retains large logs, Fleet Engine can split them into a series of logs under the 256KB threshold. Such logs have a common insertId prefix to indicate the order in which the service split the smaller log from the original oversized log. You can then rejoin them together based on their insertId.

To access the original unsplit log, merge the split logs by their insertIds in the original order that they were split, as indicated by their index in the cloud log entry.

The split log structure is the same as the structure mentioned in Split audit log entries guide for Cloud Audit Logs. The major difference for split logs in Fleet Logging is that the split occurs in the jsonPayload field, instead of in the protoPayload field. See the example split shown in the next section.

Supported log types

Fleet Engine supports log splitting only for the following logs types whose log size exceeds 256KB:

Example split log structure

// First Split Log
{
  // insertId appended with an increasing number
  "insertId": "ABCDE-1",
  "jsonPayload": {
    "request": {
      "filter": "tracking_id=tracking-test-splitting-task"
    },
    "@type": "type.googleapis.com/maps.fleetengine.delivery.log.v1.ListTasksLog",
    "response": {
      "tasks": [
        {
          "name": "providers/providers-123/tasks/test-splitting-task-id-0",
          // ...
        },
        {
          "name": "providers/providers-123/tasks/test-splitting-task-id-1",
          // ...
        },
        {
          "name": "providers/providers-123/tasks/test-splitting-task-id-2"
          // ...
        },
        {
          "name": "providers/providers-123/tasks/test-splitting-task-id-3",
          // ...
        },
      ]
    },
    "header": {}
  },
  "resource": {
    "type": "fleetengine.googleapis.com/DeliveryFleet",
    "labels": {
      "resource_container": "projects/providers-123",
      "location": "global"
    }
  },
  // Same timestamp
  "timestamp": "2024-01-29T23:35:58.076515Z",
  "labels": {
  },
  "logName": "projects/providers-123/logs/fleetengine.googleapis.com%2Flist_tasks",
  "receiveTimestamp": "2024-01-29T23:35:59.278858322Z",
  "split": {
    // UID for this logical log entry (same across splits)
    "uid": "ABCDE",
    "totalSplits": 2
  }
}
// Second Split Log
{
  // insertId appended with an increasing number
  "insertId": "ABCDE-2",
  "jsonPayload": {
    "request": {
      "filter": "tracking_id=tracking-test-splitting-task"
    },
    "@type": "type.googleapis.com/maps.fleetengine.delivery.log.v1.ListTasksLog",
    "response": {
      "tasks": [
         // Previous tasks appear as empty objects in subsequent splits
        {}, {}, {}, {},
        {
          "name": "providers/providers-123/tasks/test-splitting-task-id-4",
          // ...
        }
      ]
    },
    "header": {}
  },
  "resource": {
    "type": "fleetengine.googleapis.com/DeliveryFleet",
    "labels": {
      "resource_container": "projects/providers-123",
      "location": "global"
    }
  },
  // Same timestamp
  "timestamp": "2024-01-29T23:35:58.076515Z",
  "labels": {
  },
  "logName": "projects/providers-123/logs/fleetengine.googleapis.com%2Flist_tasks",
  "receiveTimestamp": "2024-01-29T23:35:59.278858322Z",
  "split": {
    // UID for this logical log entry (same across splits)
    "uid": "ABCDE",
    // Subsequent logs after the original will have a zero based index
    "index": 1,
    "totalSplits": 2
  }
}

Access your logs

Cloud Logs are structured around the LogEntry format. Fleet Engine sends logs to Cloud Logging with the LogEntry's resource.type set to fleetengine.googleapis.com. You can use the Logs Explorer to write queries for viewing your logs.

For example, to view all RPCs to Fleet Engine that returned an error, use the following Logs Explorer query:

resource.type:"fleetengine.googleapis.com/DeliveryFleet"
severity=ERROR

To view logs of RPCs made to the UpdateDeliveryVehicle method for the project example-project-id, use the following Logs Explorer query:

logName="projects/project-id/logs/fleetengine.googleapis.com%2Fupdate_delivery_vehicle"

The following example shows a LogEntry for the UpdateDeliveryVehicle log. The RPC request and response are located inside the jsonPayload field:

    {
      "insertId": "c6b85fbc927343fc8a85338c57a65733",
      "jsonPayload": {
        "request": {
          "header": {4},
          "updateMask": "deviceSettings",
          "vehicleId": "uniqueVehicleId",
          "vehicle": {2}
        },
        "response": {
          "name": "providers/example-project-id/vehicles/uniqueVehicleId",
          "availableCapacity": 2,
          "state": "VEHICLE_STATE_OFFLINE",
          "maximumCapacity": 2,
          "vehicleType": {1},
          "supportedTrips": {1}
        },
        "@type": "type.googleapis.com/maps.fleetengine.v1.UpdateDeliveryVehicleLog"
      },
      "resource": {
        "type": "fleetengine.googleapis.com/DeliveryFleet",
        "labels": {2}
      },
      "timestamp": "2021-01-01T00:00:00.000000000Z",
      "labels": {2},
      "logName": "projects/example-project-id/logs/fleetengine.googleapis.com%2Fupdate_delivery_vehicle",
      "receiveTimestamp": "2021-01-01T00:00:00.000000000Z"
    }

If an RPC error is returned, the responseDeliveryVehicle field is cleared and the errorResponse field is set and populated within jsonPayload:

    {
      "insertId": "2ead60bdec561836a1bb84a90e9915cd",
      "jsonPayload": {
        "@type": "type.googleapis.com/maps.fleetengine.delivery.log.v1.UpdateDeliveryVehicleLog",
        "header": {
          "languageCode": "en",
          "osVersion": "11",
          "platform": "PLATFORM_LOG_ANDROID",
          "regionCode": "US",
          "sdkType": "SDK_TYPE_LOG_DRIVER",
          "sdkVersion": "4.4.3"
        },
        "request": {
          "deliveryVehicle": {4},
          "deliveryVehicleId": "uniqueDeliveryVehicleId",
          "updateMask": "lastLocation"
        },
        "response": {
          "lastLocation": {14},
          "name": "providers/example-project-id/deliveryVehicles/uniqueDeliveryVehicleId",
          "navigationStatus": "NAVIGATION_STATUS_ARRIVED_AT_DESTINATION",
          "remainingDistanceMeters": "430",
          "remainingDuration": "10s"
        }
      },
      "labels": {
        "delivery_vehicle_id": "uniqueDeliveryVehicleId"
      },
      "logName": "projects/example-project-id/logs/fleetengine.googleapis.com%2Fupdate_delivery_vehicle",
      "receiveTimestamp": "2023-07-14T22:57:51.156515110Z",
      "resource": {
        "labels": {2},
        "type": "fleetengine.googleapis.com/DeliveryFleet"
      },
      "timestamp": "2023-07-14T22:57:51.018045Z"
    }

For more information about the logging query language, see Logging query language. For information about how you can use your logs to create metrics, see Overview of logs-based metrics.

Manage logging costs

After logging is enabled, you are responsible for setting up how you would like to route, store, and retain your logs. You may incur extra Google Cloud charges for log ingestion and retention if you exceed the usage and retention limits for no charge. However, you can control logging costs by doing one of the following:

Reduce logging usage

You can limit the amount of log data ingestion by excluding certain log entries.

Export or route logs

You can route logs to other Google Cloud or external destinations to avoid the default ingestion and storage costs. Make sure you turn off log ingestion, as described in the next section, to avoid ingestion costs.

Turn off log ingestion to avoid charges

Reducing logging usage, or exporting or routing logs, are preferred over turning off log ingestion. However, if you don't intend to use Fleet Engine logs, you can avoid potential Cloud Logging charges by turning off ingestion. By default, Fleet Engine logs are routed to the _Default log bucket.

The following command updates the _Default logging bucket to not ingest Fleet Engine logs.

gcloud logging sinks update _Default \
--log-filter='NOT LOG_ID("cloudaudit.googleapis.com/activity") \
AND NOT LOG_ID("externalaudit.googleapis.com/activity") \
AND NOT LOG_ID("cloudaudit.googleapis.com/system_event") \
AND NOT LOG_ID("externalaudit.googleapis.com/system_event") \
AND NOT LOG_ID("  cloudaudit.googleapis.com/access_transparency") \
AND NOT LOG_ID("externalaudit.googleapis.com/access_transparency") \
AND NOT resource.type:"fleetengine.googleapis.com"''

For more information, see: Cloud Logging Exclusions and Excluding logs. Cloud Logging Exports and Exporting logs

Use the Logs Explorer

To use the Logs Explorer, open the Cloud Console, select Logging, and then Logs Explorer. To see a list of all the Fleet Engine logs available, click the Fleet Engine Resource Type. Some Delivery API logs are labeled with a Task ID and a Delivery Vehicle ID. You can use these labels to select logs for the tasks or vehicles that interest you.

Log labels

Filter logs by delivery vehicle ID

In the Logs Explorer, you can use the following query to restrict logs to a specific vehicle: none resource.type="fleetengine.googleapis.com/DeliveryFleet" labels.delivery_vehicle_id="delivery_vehicle_id"

Filter vehicle

Filter logs by task ID

In the Logs Explorer, you can use the following query to restrict logs to a specific task: none resource.type="fleetengine.googleapis.com/DeliveryFleet" labels.task_id=~"task_id"

Filter logs for a vehicle over a specific time period

In the Logs Explorer, you can use the following query to restrict logs to those for a vehicle over a specific time period: none resource.type="fleetengine.googleapis.com/DeliveryFleet" labels.delivery_vehicle_id="delivery_vehicle_id" timestamp>="2020-09-24T20:00:00.000Z" timestamp<"2020-09-24T21:00:00.000Z"

Log-based metrics example

The following example shows how to use log-based metrics to track the number of tasks created over time.

  1. In the Cloud Console, select Logging and then Logs Explorer to open the Logs Explorer. Then apply the following filter:

    resource.type="fleetengine.googleapis.com/DeliveryFleet" resource.labels.location="global"
    logName="projects/ProjectID/logs/fleetengine.googleapis.com%2Fupdate_task"
    jsonPayload.request.task.taskOutcome="TASK_OUTCOME_LOG_SUCCEEDED"
    jsonPayload.request.updateMask="taskOutcome"
    jsonPayload.response.type= ("TASK_TYPE_LOG_PICKUP" OR "TASK_TYPE_LOG_DELIVERY")
    
  2. In the Query Results pane, select the Actions drop-down and then select Create Metric.

    Create metric

  3. In the Metric Editor dialog:

    • Specify a metric name (for example, billable_tasks).
    • Specify a metric description (for example, The number of Billable Tasks).
    • Leave the Units option blank. _ Leave the Type option as Counter.

    Then select the Create Metric button.

  4. On the Logs-Based Metrics page, you should see a message confirming that the metric was created successfully, and the new metric should appear in the User-define metrics section. The metric will now be populated as matching logs are generated.

  5. Select the vertical drop down on the right side of the new metric and then select View in Metrics Explorer.

    View metric

  6. On the left pane under Build Your Query, set the Resource Type to Fleet Engine and search for the billable_tasks metric.

    Search metric

    The graph on the right shows the rate of billable_tasks calls.

Using BigQuery

BigQuery is a powerful tool for performing analytics. It can be used to store longer-term logs and to perform ad hoc SQL-like queries against the data.

Routing logs to BigQuery

To take advantage of BigQuery, logs must be routed to a BigQuery datastore, as follows:

  1. In the Cloud Console, select Logging and then Logs Explorer.

  2. Create a filter that isolates Fleet Engine logs. In the Logs Field Explorer, select the Fleetengine.googleapis.com/DeliveryFleet resource type.

    Create
filter

  3. In the Query Results pane, click the Actions drop-down and choose Create Sink.

    Create
sink

  4. In the Select sink service dialog, select BigQuery dataset.

    Select
sink

  5. In the Edit Sink dialog, specify the following options:

    • Specify an sink name (for example, FleetEngineLogsSink).
    • Leave Sink Service as BigQuery.
    • Select the Use Partitioned Tables option. This will boost query performance.
    • Under Sink Destination, select Create New BigQuery Dataset, and then specify a BigQuery dataset name (for example, FleetEngineLogs).
    • Click the Create Sink button.

    Edit
    sink

Your logs should now begin to populate the BigQuery dataset. You can see the data in the BigQuery section of the Cloud Console.

BigQuery
section

Several tables under the FleetEngineLogs dataset will be populated automatically, one for each log type:

  • CreateDeliveryVehicle
  • GetDeliveryVehicle
  • ListDeliveryVehicle
  • UpdateDeliveryVehicle
  • CreateTask
  • GetTask
  • UpdateTask
  • ListTasks
  • SearchTasks

The table names use the following pattern:

project_id.data_set.log_name

For example, if the project is called test_project and the dataset name is FleetEngineLogs, the CreateTask table has the following name:

test_project.FleetEngineLogs.fleetengine_googleapis_com_create_task

Example queries

This section shows examples of queries you can create.

Tasks created per hour

The following query counts the number of CreateTasks logs and groups them by hour. sql SELECT TIMESTAMP_TRUNC(timestamp, HOUR) as hour, count(*) as num_tasks_created FROM `ProjectId.FleetEngineLogs.fleetengine_googleapis_com_create_task` GROUP BY hour ORDER by hour #### Number of stops per vehicle per hour

The following query generates a count of the stops that a vehicle served, broken down by hour.

For example, this query could indicate that in the last hour:

  • Vehicle A completed 10 stops in hour 12 and 8 stops in hour 13.
  • Vehicle B completed 5 stops in hour 11 and 7 stops in hour 12.
  • Vehicle C completed 12 stops in hour 13 and 9 stops in hour 14.

    SELECT
      jsonpayload_v1_updatedeliveryvehiclelog.request.deliveryvehicleid AS vehicle,
      TIMESTAMP_TRUNC(timestamp, HOUR) AS hour,
      COUNT(*) AS num_stops
    FROM
      `ProjectId.FleetEngineLogs.fleetengine_googleapis_com_update_delivery_vehicle`
    WHERE
    ARRAY_LENGTH(jsonpayload_v1_updatedeliveryvehiclelog.request.deliveryvehicle.remainingvehiclejourneysegments) > 0
    AND jsonpayload_v1_updatedeliveryvehiclelog.request.deliveryvehicle.remainingvehiclejourneysegments[
    OFFSET
    (0)].stop.state = 'VEHICLE_STOP_STATE_LOG_ARRIVED'
    GROUP BY
    1,
    2
    ORDER BY
    2
    

First delivery success rate

The following query that shows the percentage of success in the first delivery attempt rate.

    SELECT
     vehicle_id,
     COUNTIF(outcome = "TASK_OUTCOME_LOG_SUCCEEDED") AS num_success,
     COUNT(*) AS total_deliveries,
     COUNTIF(outcome = "TASK_OUTCOME_LOG_SUCCEEDED") * 100/ COUNT(*) AS success_rate
    FROM (
     SELECT
       labels.delivery_vehicle_id AS vehicle_id,
       jsonpayload_v1_updatetasklog.response.trackingid AS trackingid,
       ARRAY_AGG(jsonpayload_v1_updatetasklog.response.taskoutcome
       ORDER BY
         timestamp ASC)[ORDINAL(1)] AS outcome,
     FROM
     `ProjectId.FleetEngineLogsfleetengine_googleapis_com_update_task`
     WHERE
      jsonpayload_v1_updatetasklog.response.type = "TASK_TYPE_LOG_DELIVERY"
     GROUP BY 1, 2
     ORDER BY 1, 2)
    GROUP BY 1
    ORDER BY 1

Datastudio dashboards

BigQuery can be integrated with business intelligence tools and dashboards can be created for business analytics.

The following example shows how to build a dashboard on which tasks and vehicle movements can be visualized on a map.

  1. Launch a new Datastudio dashboard and select BigQuery as the data connection.

    Data
connection

  2. Select Custom Query and select the Cloud Project to which it should be billed.

    Select
project

  3. Enter the following query into the query box.

    Enter
query

    SELECT
     timestamp,
     labels.delivery_vehicle_id,
    jsonpayload_v1_updatedeliveryvehiclelog.response.lastlocation.rawlocation.latitude AS lat,
    jsonpayload_v1_updatedeliveryvehiclelog.response.lastlocation.rawlocation.longitude AS lng
    FROM
    `ProjectId.FleetEngineLogs.fleetengine_googleapis_com_update_delivery_vehicle`
  1. Select Chart Type as Bubble Map, and then select the location field.

    Chart
type

  2. Select Create Field.

    Create
field

  3. Name the field and add the following formula: CONCAT(lat, ",", lng).

    Then set type to Geo->Latitude, Longitude.

    Set
type

  4. You can add controls to the dashboard to filter data. For example, select the Date-range filter.

    Add
controls

  5. Edit the date range box to select a default date range.

    Date
range

  6. You can add additional Drop-down list controls for delivery_vehicle_id.

    Drop-down
list

With these controls, you can visualize the movement of the vehicle or the movement within a delivery.