Skip to content

Commit ee4fb69

Browse files
authored
feat: Support for scheduled tasks (LMFS) via Cloud Logging & Readme refresh (#281)
* fix: Refresh Readme * feat: support for scheduled task via Cloud Logging
1 parent 90b0eae commit ee4fb69

File tree

5 files changed

+139
-101
lines changed

5 files changed

+139
-101
lines changed

README.md

Lines changed: 76 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,137 +1,131 @@
11
# Fleet Debugger Tool
22

3-
A visualization and debugging tool for Google Maps Platform's Mobility Solutions, supporting [Scheduled tasks](https://developers.google.com/maps/documentation/mobility/fleet-engine/essentials/tasks-intro) and [On-demand trips](https://developers.google.com/maps/documentation/mobility/fleet-engine/essentials/trip-intro).
3+
Fleet Debugger is an open-source web tool designed to help you visualize and analyze logs from Google Maps Platform's Mobility solutions, supporting both [Scheduled tasks](https://developers.google.com/maps/documentation/mobility/fleet-engine/essentials/tasks-intro) and [On-demand trips](https://developers.google.com/maps/documentation/mobility/fleet-engine/essentials/trip-intro). It provides an interactive map and timeline to analyze vehicle and task or trip data, running entirely in your browser.
44

5-
![Screenshot](docs/screenshots/vehiclereplay.gif)
5+
![Fleet Debugger interface showing a map and log entries](docs/screenshots/vehiclereplay.gif)
66

7-
## Using the Demo Site(s)
7+
## Key Features
88

9-
The fastest way to get started is using our GitHub hosted site: \
10-
[googlemaps.github.io/fleet-debugger/demos/multiple-trips](https://googlemaps.github.io/fleet-debugger/demos/multiple-trips)
9+
Fleet Debugger helps you understand complex journey and vehicle behaviors by offering:
1110

12-
We also have demo data for:
13-
- [Scheduled task](https://googlemaps.github.io/fleet-debugger/demos/lmfs/)
11+
* **Interactive map and timeline replay:** Observe vehicle movement in real time or at an accelerated time-lapse.
12+
* **Synchronization:** Events are linked across the map, data table, and timeline. Click an event in one place, and it's highlighted everywhere.
13+
* **Detailed log entry inspection:** Deep dive into API requests and responses.
14+
* **Filter & inspect log messages:** Use customizable table views to easily find and analyze specific log entries.
15+
* **File Import:** Load logs from JSON or ZIP files.
16+
* **Direct Cloud Logging Connection:** Securely fetch logs directly from your Google Cloud project.
17+
* **Flexible Filtering:** Easily narrow down data by time range, entity IDs, and more.
18+
* **View status changes:** Track changes in vehicle, trip, task, and navigation status.
19+
* **Visualize multiple trips:** View all trips or tasks for a single vehicle.
20+
* **Analyze GPS data:** Examine location, accuracy, and heading information.
21+
* **GPS accuracy, speed, and heading analysis:** Detailed analysis tools for these metrics ([GPS accuracy](docs/GPSAccuracy.md), [speed](docs/Speed.md), [heading](docs/Heading.md)).
22+
* **Analyze dwell times:** Measure time spent at specific locations ([dwell times](docs/DwellTimes.md)).
23+
* **View planned navigation routes:** See the routes with traffic conditions as experienced by drivers (requires [Restricted Use Logs](#restricted-use-logs)).
24+
* **See requested vs. actual pickup and dropoff points:** (requires [Restricted Use Logs](#restricted-use-logs)).
25+
* **Map and Timeslider Interaction:** Click directly on the map or the timeslider to select the nearest log event.
26+
* **Tracking (Chevron):** Use the tracking button to keep the map centered on the current event during replay.
27+
* **Exporting Logs:** Export loaded dataset to a local file for easy collaboration.
1428

15-
### Loading Your Data
29+
## Using the Demo Site
1630

17-
Click on any empy Dataset buttons `Load Dataset` to get the `Fleet Engine Logs Loading` UI.
31+
The fastest way to get started is using our GitHub hosted site.
1832

19-
![Fleet Engine Logs Loading](docs/screenshots/Fleet_Engine_Logs_Loading.png)
33+
This site includes demo data for:
2034

21-
#### Direct Cloud Logging Connection (Recommended)
35+
* [On-demand trips](https://googlemaps.github.io/fleet-debugger/demos/multiple-trips)
36+
* [Scheduled tasks](https://googlemaps.github.io/fleet-debugger/demos/lmfs/)
2237

23-
1. **Configure Parameters:** Configure the Cloud Logging query parameters directly within UI.
38+
## Loading Your Data
2439

25-
2. **Connect to Cloud Logging:** The Fleet Debugger can connect directly to your Google Cloud project's Cloud Logging. Click the `Sign in and Fetch Logs` button and follow the prompts to authenticate and grant access. You'll need appropriate IAM permissions (`roles/logging.viewer` which is also granted via `roles/viewer`) for the Fleet Debugger to read logs.
40+
Click on any empty "Load Dataset" button to open the data loading interface.
2641

27-
#### Log Files in JSON Format
42+
![Fleet Engine Logs Loading](docs/screenshots/Fleet_Engine_Logs_Loading.png)
2843

29-
1. Export your Fleet Engine logs from Cloud Logging using one of the following filters (customize as needed):
44+
### 1. Direct Cloud Logging Connection (Recommended)
3045

31-
```sql
32-
-- On-demand trips
33-
resource.type="fleetengine.googleapis.com/Fleet"
34-
AND (labels.vehicle_id="YOUR_VEHICLE_ID" OR
35-
labels.trip_id=~"(TRIP_ID_1|TRIP_ID_2)")
36-
AND timestamp >= "START_TIME" -- ISO 8601 format (YYYY-MM-DDTHH:MM:SS)
37-
AND timestamp <= "END_TIME" -- ISO 8601 format (YYYY-MM-DDTHH:MM:SS)
38-
AND (
39-
logName:"logs/fleetengine.googleapis.com%2Fcreate_vehicle" OR
40-
logName:"logs/fleetengine.googleapis.com%2Fupdate_vehicle" OR
41-
logName:"logs/fleetengine.googleapis.com%2Fcreate_trip" OR
42-
logName:"logs/fleetengine.googleapis.com%2Fupdate_trip"
43-
)
44-
```
46+
1. **Configure Parameters:** Input your Project ID, Vehicle ID(s) or Trip/Task ID(s), and the selected time range within the UI.
47+
2. **Connect to Cloud Logging:** Click the "Sign in and Fetch Logs" button and follow the prompts to authenticate with your Google Account and grant access. You'll need appropriate IAM permissions (e.g., `roles/logging.viewer`) to read logs.
4548

46-
```sql
47-
-- Scheduled tasks
48-
resource.type="fleetengine.googleapis.com/DeliveryFleet"
49-
AND (labels.delivery_vehicle_id="YOUR_VEHICLE_ID" OR
50-
labels.task_id=~"(TASK_ID_1|TASK_ID_2)")
51-
AND timestamp >= "START_TIME" -- ISO 8601 format (YYYY-MM-DDTHH:MM:SS)
52-
AND timestamp <= "END_TIME" -- ISO 8601 format (YYYY-MM-DDTHH:MM:SS)
53-
AND (
54-
logName:"logs/fleetengine.googleapis.com%2Fcreate_delivery_vehicle" OR
55-
logName:"logs/fleetengine.googleapis.com%2Fupdate_delivery_vehicle" OR
56-
logName:"logs/fleetengine.googleapis.com%2Fcreate_task" OR
57-
logName:"logs/fleetengine.googleapis.com%2Fupdate_task"
58-
)
59-
```
49+
### 2. Import from Log Files
6050

61-
2. Download the logs in JSON format and optionally zip them
62-
3. Import the JSON/ZIP file to Fleet Debugger, using the `Load JSON or ZIP file instead` button.
51+
You can load log data from JSON or ZIP files using the "Load JSON or ZIP file instead" button. This is useful for:
6352

64-
> **Note**: All data processing happens client-side. Your logs remain in your browser's Local Storage and are not uploaded to Google/GitHub.
53+
* Analyzing logs shared with you.
54+
* Loading previously exported datasets.
6555

66-
### Key Features
56+
You can export logs from the Google Cloud Console's Logs Explorer.
6757

68-
- **Filter & inspect log messages:** Use customizable table views to easily find and analyze specific log entries.
69-
- **View planned navigation routes:** See the routes with traffic conditions as experienced by drivers (requires [Restricted Use Logs](#restricted-use-logs)).
70-
- **Replay vehicle movement:** Observe vehicle movement in real time or at an accelerated time-lapse.
71-
- **See requested vs. actual pickup and dropoff points:** (requires [Restricted Use Logs](#restricted-use-logs)).
72-
- **View status changes:** Track changes in vehicle, trip, and navigation status.
73-
- **Analyze GPS data:** Examine location, accuracy, and heading information.
74-
- **Visualize multiple trips:** View all trips for a single vehicle.
75-
- **Analyze GPS accuracy, speed, and heading:** Detailed analysis tools for these metrics ([GPS accuracy](docs/GPSAccuracy.md), [speed](docs/Speed.md), [heading](docs/Heading.md)).
76-
- **Analyze dwell times:** Measure time spent at specific locations ([dwell times](docs/DwellTimes.md)).
77-
- **Map and Timeslider Interaction:** Click directly on the map or the timeslider to select the nearest log event.
78-
- **Tracking (Chevron):** Use the tracking button to keep the map centered on the current event during replay.
79-
- **Exporting Logs:** Export loaded dataset to a local file for easy collaboration.
58+
> **Note**: All data processing happens client-side. Your logs or API keys are not uploaded to any server. Data is stored in your browser's Local Storage.
8059
81-
### Restricted Use Logs
60+
## Restricted Use Logs
8261

83-
Planned navigation routes and requested Pickup/Dropoff points require enablement of [Restricted Use Logs](https://developers.google.com/maps/documentation/mobility/operations/cloud-logging/setup#enable_restricted_use_logs).
62+
To see features like the driver's planned navigation route, traffic, and original requested stop locations, you need to enable
63+
[Restricted Use Logs](https://developers.google.com/maps/documentation/mobility/operations/cloud-logging/setup#enable_restricted_use_logs) in your Google Cloud project. This is not required for the tool to function but highly recommended for a richer analysis.
8464

85-
### Managing Datasets
65+
## Managing Datasets
8666

87-
Each dataset (loaded from a file or Cloud Logging) has a dropdown menu:
67+
Each dataset has a dropdown menu:
8868

89-
- **Save (Export):** Save the current dataset as a JSON file.
90-
- **Delete:** Remove the dataset from the Fleet Debugger. This clears the data from your browser's local storage.
69+
- **Export:** Save the current dataset as a JSON file to your local system.
70+
- **Delete:** Remove the dataset from the Fleet Debugger and your browser's local storage.
9171

9272
### Restoring Demo Data
9373

9474
To reload the original demo data:
95-
1. Select "Delete" from `Dataset 1` dropdown menu.
96-
2. Refresh the page. The demo data will be automatically reloaded into Dataset 1.
75+
1. Select "Delete" from the `Dataset 1` dropdown menu.
76+
2. Refresh the page. The demo data will be automatically reloaded.
9777

9878
## Running Your Own Server
9979

10080
### Development Setup
10181

102-
1. Install dependencies:
103-
- [Node.js](https://nodejs.org/en/download)
104-
105-
2. Install node modules:
106-
```bash
107-
npm install
108-
```
82+
1. Install dependencies:
83+
* [Node.js](https://nodejs.org/en/download)
84+
2. Clone the repository:
85+
```bash
86+
git clone https://github.com/googlemaps/fleet-debugger.git
87+
cd fleet-debugger
88+
```
89+
3. Install node modules:
90+
```bash
91+
npm install
92+
```
93+
4. Add Maps Javascript API Key to src/constants.js
10994

11095
### Start development server
11196

11297
```bash
11398
npm start
11499
```
100+
This will open the app in your default browser, usually at `http://localhost:3000`.
115101

116102
### Building and Deploying
117103

118104
```bash
119105
# Generate static build
120106
npm run build
107+
```
108+
The static files will be in the `build` folder. You can deploy this folder to any static site hosting service. For Firebase Hosting:
121109

122-
# Deploy to firebase
110+
```bash
111+
# Optional: Install Firebase CLI globally
123112
npm install -g firebase-tools
113+
114+
# Deploy to Firebase Hosting
124115
firebase deploy --only hosting
125116
```
117+
(Requires Firebase project setup and `firebase login`)
126118

127-
## Privacy Policy
128-
129-
This project is 100% client-side and does not collect or store any user data on servers. Please see our [Privacy Policy](docs/PRIVACY.md) for full details.
119+
## Privacy
130120

131-
## Disclaimer
121+
This project is 100% client-side. Please see our [Privacy Policy](docs/PRIVACY.md) for full details.
132122

133-
This is not an officially supported Google product.
123+
## Support & Contributing
134124

135-
## Additional Resources
125+
This Fleet Debugger tool is offered under an open source license. It is not an officially supported Google product.
136126

137-
- [Reporting Issues](docs/reporting-issues.md)
127+
* To report bugs or request features, file an issue on
128+
[GitHub](https://github.com/googlemaps/fleet-debugger/issues).
129+
* For technical questions and discussions, use the
130+
[Google Maps Platform developer community channels](https://developers.google.com/maps/developer-community).
131+
* To contribute, check the [CONTRIBUTING.md](CONTRIBUTING.md) guide.

src/CloudLogging.js

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,53 @@ export function buildQueryFilter(params) {
2222
const startDate = params.startTime || new Date(0).toISOString();
2323
const endDate = params.endTime || new Date(Date.now() + 86400000).toISOString();
2424

25-
// Build vehicle/trip filter part
26-
let entityFilter = "";
25+
/*
26+
* Query for both On-demand Trips (Fleet) AND Scheduled Tasks (DeliveryFleet)
27+
*
28+
* We use "resource.type" OR logic because a single log entry has only one resource type.
29+
*
30+
* Structure:
31+
* (
32+
* (On-demand Trips (ODRD) Conditions) OR (Scheduled Tasks (LMFS) Conditions)
33+
* )
34+
* AND timestamp...
35+
* AND logName...
36+
*/
37+
38+
let vehicleFilter = "";
2739
if (params.vehicleId?.trim()) {
28-
entityFilter += `labels.vehicle_id="${params.vehicleId.trim()}"`;
40+
const vId = params.vehicleId.trim();
41+
vehicleFilter = `(labels.vehicle_id="${vId}" OR labels.delivery_vehicle_id="${vId}")`;
2942
}
43+
44+
let tripTaskFilter = "";
3045
if (params.tripIds?.trim()) {
31-
const trips = params.tripIds
46+
const ids = params.tripIds
3247
.split(",")
3348
.map((t) => t.trim())
3449
.filter(Boolean);
35-
if (trips.length > 0) {
36-
const tripFilter = trips.length === 1 ? `labels.trip_id="${trips[0]}"` : `labels.trip_id=~"(${trips.join("|")})"`;
37-
entityFilter = entityFilter ? `(${entityFilter} OR ${tripFilter})` : tripFilter;
50+
51+
if (ids.length > 0) {
52+
if (ids.length === 1) {
53+
const id = ids[0];
54+
tripTaskFilter = `(labels.trip_id="${id}" OR labels.task_id="${id}")`;
55+
} else {
56+
const joined = ids.join("|");
57+
tripTaskFilter = `(labels.trip_id=~"(${joined})" OR labels.task_id=~"(${joined})")`;
58+
}
3859
}
3960
}
4061

62+
// If both present: (vehicleFilter OR tripTaskFilter)
63+
let entityFilter = "";
64+
if (vehicleFilter && tripTaskFilter) {
65+
entityFilter = `(${vehicleFilter} OR ${tripTaskFilter})`;
66+
} else {
67+
entityFilter = vehicleFilter || tripTaskFilter;
68+
}
69+
4170
const filter = `
42-
resource.type="fleetengine.googleapis.com/Fleet"
71+
(resource.type="fleetengine.googleapis.com/Fleet" OR resource.type="fleetengine.googleapis.com/DeliveryFleet")
4372
AND ${entityFilter}
4473
AND timestamp >= "${startDate}"
4574
AND timestamp <= "${endDate}"
@@ -48,7 +77,12 @@ export function buildQueryFilter(params) {
4877
logName:"logs/fleetengine.googleapis.com%2Fupdate_vehicle" OR
4978
logName:"logs/fleetengine.googleapis.com%2Fcreate_trip" OR
5079
logName:"logs/fleetengine.googleapis.com%2Fupdate_trip" OR
51-
logName:"logs/fleetengine.googleapis.com%2Fget_trip"
80+
logName:"logs/fleetengine.googleapis.com%2Fget_trip" OR
81+
logName:"logs/fleetengine.googleapis.com%2Fcreate_delivery_vehicle" OR
82+
logName:"logs/fleetengine.googleapis.com%2Fupdate_delivery_vehicle" OR
83+
logName:"logs/fleetengine.googleapis.com%2Fcreate_task" OR
84+
logName:"logs/fleetengine.googleapis.com%2Fupdate_task" OR
85+
logName:"logs/fleetengine.googleapis.com%2Fget_task"
5286
)
5387
`;
5488

src/CloudLogging.test.js

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ describe("buildQueryFilter", () => {
1414
const filter = buildQueryFilter(params);
1515

1616
// Check for key components in the filter
17-
expect(filter).toContain('resource.type="fleetengine.googleapis.com/Fleet"');
18-
expect(filter).toContain('labels.vehicle_id="vehicle1"');
17+
expect(filter).toContain(
18+
'(resource.type="fleetengine.googleapis.com/Fleet" OR resource.type="fleetengine.googleapis.com/DeliveryFleet")'
19+
);
20+
expect(filter).toContain('(labels.vehicle_id="vehicle1" OR labels.delivery_vehicle_id="vehicle1")');
1921
expect(filter).toContain("2023-01-01T01:00:00");
2022
expect(filter).toContain("2023-01-02T02:00:00");
2123
});
@@ -31,8 +33,8 @@ describe("buildQueryFilter", () => {
3133

3234
const filter = buildQueryFilter(params);
3335

34-
// Should include regex for multiple trip IDs
35-
expect(filter).toContain('labels.trip_id=~"(trip1|trip2)"');
36+
// Should include regex for multiple trip IDs and verify task_id is included
37+
expect(filter).toContain('(labels.trip_id=~"(trip1|trip2)" OR labels.task_id=~"(trip1|trip2)")');
3638
});
3739

3840
test("builds filter with single trip ID", () => {
@@ -46,8 +48,8 @@ describe("buildQueryFilter", () => {
4648

4749
const filter = buildQueryFilter(params);
4850

49-
// Should use exact match for single trip ID
50-
expect(filter).toContain('labels.trip_id="trip1"');
51+
// Should use exact match for single trip ID and verify task_id is included
52+
expect(filter).toContain('(labels.trip_id="trip1" OR labels.task_id="trip1")');
5153
});
5254

5355
test("builds filter with both vehicle and trip IDs", () => {
@@ -62,7 +64,9 @@ describe("buildQueryFilter", () => {
6264
const filter = buildQueryFilter(params);
6365

6466
// Should combine vehicle and trip filters with OR
65-
expect(filter).toContain('(labels.vehicle_id="vehicle1" OR labels.trip_id=~"(trip1|trip2)")');
67+
expect(filter).toContain(
68+
'((labels.vehicle_id="vehicle1" OR labels.delivery_vehicle_id="vehicle1") OR (labels.trip_id=~"(trip1|trip2)" OR labels.task_id=~"(trip1|trip2)"))'
69+
);
6670
});
6771

6872
test("throws error for missing project ID", () => {

src/DatasetLoading.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,14 @@ const CloudLoggingFormComponent = ({ onLogsReceived, onFileUpload }) => {
101101
</div>
102102
<div className="form-field">
103103
<label className="form-label">
104-
Trip IDs (comma-separated):
104+
Trip/Task IDs (comma-separated):
105105
<input
106106
type="text"
107107
name="tripIds"
108108
value={queryParams.tripIds}
109109
onChange={(e) => setQueryParams({ ...queryParams, tripIds: e.target.value })}
110110
className="form-input"
111-
placeholder="TRIP_ID_1,TRIP_ID_2"
111+
placeholder="TRIP_ID, TASK_ID"
112112
autoComplete="on"
113113
/>
114114
</label>

src/Task.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,13 @@ class Task {
4040
taskInfo.taskoutcomelocation = lastUpdate.taskResp.taskoutcomelocation;
4141
taskInfo.taskoutcometime = lastUpdate.taskResp.taskoutcometime;
4242
taskInfo.trackingid = lastUpdate.taskResp.trackingid || lastUpdate.taskReq.task.trackingid;
43-
if (taskInfo.taskoutcomelocationsource && taskInfo.plannedlocation && taskInfo.taskoutcomelocation) {
43+
if (
44+
taskInfo.taskoutcomelocationsource &&
45+
taskInfo.plannedlocation &&
46+
taskInfo.plannedlocation.point &&
47+
taskInfo.taskoutcomelocation &&
48+
taskInfo.taskoutcomelocation.point
49+
) {
4450
taskInfo.plannedVsActualDeltaMeters = window.google.maps.geometry.spherical.computeDistanceBetween(
4551
{
4652
lat: taskInfo.plannedlocation.point.latitude,

0 commit comments

Comments
 (0)