Note
This package is currently experimental and published under the labs.dart.dev pub publisher in order to solicit feedback.
For packages in the labs.dart.dev publisher we generally plan to either graduate the package into a supported publisher (dart.dev, tools.dart.dev) after a period of feedback and iteration, or discontinue the package. These packages have a much higher expected rate of API and breaking changes.
Your feedback is valuable and will help us evolve this package. For general feedback, suggestions, and comments, please file an issue in the bug tracker.
A package for serving HTTP requests on Google Cloud Platform using the shelf
framework. It is tailored for Google Cloud environments like Cloud Run, Cloud
Functions, and GKE, providing structured logging, trace correlation, exception
mapping, and graceful shutdown orchestration.
Features
- Google Cloud Structured Logging: Integrates Shelf middleware
(
createLoggingMiddleware,cloudLoggingMiddleware,errorLoggingMiddleware) that automatically formats application and error logs in GCP's native structured format. - Trace Correlation: Automatically parses Google Cloud trace context
headers (
X-Cloud-Trace-Context). Any log entry emitted usingcurrentLoggeror standardprint()within request execution is correlated and nested directly under the HTTP request log entry in the Cloud Logging viewer. - Standardized HTTP Exception Mapping: Throw client-safe exceptions in your
handlers using
HttpResponseException. Common factory constructors (e.g.,badRequest,unauthorized,notFound,tooManyRequests,internalServerError) allow returning clean, structured JSON/text status payloads safely, without leaking internal backend details. - Graceful Termination & Serving: Environment-aware port resolution (using
the
PORTenvironment variable) and signal-aware serving (SIGTERMandSIGINTsignal watch), ensuring requests finish before container shutdown.
Usage
1. Basic Setup
Integrate createLoggingMiddleware in your pipeline and use serveHandler to
launch the server. By default, this parses the port from the PORT environment
variable (falling back to 8080) and listens on all IP addresses.
import 'package:google_cloud_shelf/google_cloud_shelf.dart';
import 'package:shelf/shelf.dart';
Future<void> main() async {
final handler = const Pipeline()
.addMiddleware(createLoggingMiddleware())
.addHandler((_) => Response.ok('Hello, World!'));
await serveHandler(handler);
}
2. Contextual Logging & Trace Correlation
Enable request-log nesting in the Google Cloud Console by providing a
projectId to createLoggingMiddleware. Any logs written to currentLogger
or sent to standard print() inside the handler's execution flow are grouped
with the request log.
import 'package:google_cloud_shelf/google_cloud_shelf.dart';
import 'package:shelf/shelf.dart';
Future<void> main() async {
final handler = const Pipeline()
.addMiddleware(createLoggingMiddleware(projectId: 'my-gcp-project-id'))
.addHandler(_userHandler);
await serveHandler(handler);
}
Response _userHandler(Request request) {
// Get the logger specific to this request context
final logger = currentLogger;
logger.info('Fetching user profile from database.');
// A simple print statement is also captured as an INFO log with trace
// correlation
print('This print statement is correlated too!');
// Business logic here...
logger.info('User successfully retrieved.', payload: {'userId': 'user_123'});
return Response.ok('User Profile');
}
Note
When running in a Google Cloud environment (with a projectId provided),
successful HTTP request access logs are automatically captured by the Google
Cloud host infrastructure (such as the Cloud Run Load Balancer).
Therefore, cloudLoggingMiddleware intentionally avoids outputting successful
access log statements to prevent duplicate request logging.
3. Standardized Error & Exception Handling
Use HttpResponseException to return standard client-facing error codes and
messages. Unhandled exceptions (e.g., network failures) are caught, logged
with their full stack trace to the server logs, and safely mapped to a generic
500 Internal Server Error response to prevent data leaks.
import 'package:google_cloud_shelf/google_cloud_shelf.dart';
import 'package:shelf/shelf.dart';
Response _profileHandler(Request request) {
final userId = request.url.queryParameters['id'];
if (userId == null) {
// Automatically returns status 400 to the client
throw HttpResponseException.badRequest(
message: 'The "id" parameter is required.',
details: [
{'field': 'id', 'issue': 'must not be empty'},
],
);
}
if (userId != 'allowed-user') {
// Automatically returns status 403 to the client
throw HttpResponseException.forbidden(
message: 'Access denied to the requested profile.',
);
}
return Response.ok('User Profile Data');
}
4. Graceful Signal Termination
serveHandler uses waitForTerminate under the hood to listen for shutdown
signals (SIGTERM and SIGINT). SIGTERM is the standard signal sent by Google
Cloud Run and GKE when stopping or scaling down a container instance.
If you are customizing the server initialization, you can call
waitForTerminate manually:
import 'package:google_cloud_shelf/google_cloud_shelf.dart';
import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart' as shelf_io;
Future<void> main() async {
final handler = const Pipeline()
.addMiddleware(createLoggingMiddleware())
.addHandler((_) => Response.ok('Custom setup'));
// Start the server manually
final server = await shelf_io.serve(handler, '0.0.0.0', 8080);
// Await a shutdown signal (SIGTERM or SIGINT)
await waitForTerminate();
// Gracefully shut down the server
await server.close();
}
Libraries
- google_cloud_shelf
- Features for serving HTTP requests on Google Cloud Platform.