Vercel's serverless architecture provides an excellent developer experience with its simplicity and deployment efficiency. However, as your application scales from a hobby project to production, implementing robust logging becomes crucial for monitoring, debugging, and maintaining system reliability.
While Vercel offers built-in log drain integrations with popular services like Datadog and LogDNA, Google Cloud Platform's Cloud Logging isn't available as a native integration. This guide will walk you through implementing a custom solution to stream your Vercel logs directly to GCP Cloud Logging.
Prerequisites and Important Considerations
Before implementing this solution, please note the following requirements and limitations:
Authentication Requirements:
- • A GCP service account with the necessary credentials (
client_email
,private_key
, andproject_id
). - • Appropriate IAM permissions for Cloud Logging.
Technical Limitations:
- • Synchronous Operations: Due to Vercel's serverless architecture, logging operations must be awaited to prevent premature function termination.
- • Edge Functions Incompatibility: This implementation cannot be used with Vercel Edge Functions (such as
_middleware.ts
) because the Edge Runtime operates in a browser-like environment that doesn't support Node.js dependencies likefs
.
Setting Up GCP Service Account
To authenticate with Google Cloud Logging, you'll need to create a service account with appropriate permissions:
Step 1: Create the Service Account
- Navigate to the Google Cloud Console
- Go to IAM & Admin → Service Accounts
- Click Create Service Account
- Provide a descriptive name (e.g., "vercel-logging-service")
- Assign the Logging Admin role to ensure proper write permissions
Step 2: Generate Authentication Keys
- Select your newly created service account
- Navigate to the Keys tab
- Click Add Key → Create new key
- Choose JSON format and download the key file
The downloaded JSON file contains the essential credentials we'll use:
- •
client_email
: Service account email address - •
private_key
: Private key for authentication - •
project_id
: Your GCP project identifier
Implementation: Creating the CloudLogging Class
Now let's implement a reusable TypeScript class that handles the integration with GCP Cloud Logging.
Step 1: Install Dependencies
1yarn add @google-cloud/logging2# or3npm install @google-cloud/logging
Step 2: Environment Setup
Store your service account credentials as an environment variable in Vercel:
- •
GOOGLE_SERVICE_ACCOUNT
: The entire JSON key file contents as a string - •
VERCEL_ENV
: Automatically provided by Vercel (production, preview, or development)
Step 3: CloudLogging Class Implementation
1import { Logging } from '@google-cloud/logging';2 3export class CloudLogging {4 private logging: Logging;5 private log: any;6 7 constructor() {8 // Parse the service account credentials from environment9 const credentials = JSON.parse(process.env.GOOGLE_SERVICE_ACCOUNT!);10 11 // Initialize the Google Cloud Logging client12 this.logging = new Logging({13 projectId: credentials.project_id,14 credentials: {15 client_email: credentials.client_email,16 private_key: credentials.private_key,17 }18 });19 20 // Create a log instance with environment-specific naming21 this.log = this.logging.log(`vercel-${process.env.VERCEL_ENV}`, {22 removeCircular: true23 });24 }25 26 /**27 * Logs data to GCP Cloud Logging with specified severity level28 * @param severity - Log severity (INFO, WARNING, ERROR, etc.)29 * @param data - Data to log (string, object, or any serializable type)30 * @param labels - Optional custom labels for log organization31 */32 async logData(33 severity: string, 34 data: string | object | any, 35 labels: Record<string, string> = {}36 ): Promise<void> {37 try {38 const entry = this.log.entry({39 resource: {40 type: 'global',41 },42 labels: {43 environment: process.env.VERCEL_ENV || 'unknown',44 source: 'vercel',45 ...labels46 },47 severity: severity.toUpperCase(),48 }, data);49 50 await this.log.write(entry);51 } catch (error) {52 // Fallback to console logging if GCP logging fails53 console.error('Failed to write to GCP Cloud Logging:', error);54 console.log('Original log data:', { severity, data });55 }56 }57 58 /**59 * Convenience methods for common log levels60 */61 async info(data: any, labels?: Record<string, string>): Promise<void> {62 return this.logData('INFO', data, labels);63 }64 65 async warn(data: any, labels?: Record<string, string>): Promise<void> {66 return this.logData('WARNING', data, labels);67 }68 69 async error(data: any, labels?: Record<string, string>): Promise<void> {70 return this.logData('ERROR', data, labels);71 }72}
Usage Examples
With our CloudLogging class implemented, let's explore various ways to integrate it into your Vercel application.
Basic Usage
1import { CloudLogging } from '@/lib/gcp/logging';2 3const logger = new CloudLogging();4 5// API Route Example6export default async function handler(req: NextApiRequest, res: NextApiResponse) {7 try {8 // Your business logic here9 const result = await processUserData(req.body);10 11 // Log successful operation12 await logger.info({13 message: 'User data processed successfully',14 userId: req.body.userId,15 timestamp: new Date().toISOString()16 }, { operation: 'user-processing' });17 18 res.status(200).json(result);19 } catch (error) {20 // Log error with context21 await logger.error({22 message: 'Failed to process user data',23 error: error.message,24 stack: error.stack,25 requestBody: req.body26 }, { operation: 'user-processing' });27 28 res.status(500).json({ error: 'Processing failed' });29 }30}
Advanced Usage with Custom Labels
1class UserService {2 private logger = new CloudLogging();3 4 async createUser(userData: any) {5 try {6 const user = await this.saveToDatabase(userData);7 8 await this.logger.info({9 message: 'New user created',10 userId: user.id,11 email: user.email12 }, { 13 service: 'user-service',14 operation: 'create-user',15 version: 'v1'16 });17 18 return user;19 } catch (error) {20 await this.logger.error({21 message: 'User creation failed',22 error: error.message,23 userData: { ...userData, password: '[REDACTED]' }24 }, { 25 service: 'user-service',26 operation: 'create-user'27 });28 29 throw error;30 }31 }32}
Serverless Function Example
1import { VercelRequest, VercelResponse } from '@vercel/node';2import { CloudLogging } from '../lib/gcp/logging';3 4const logger = new CloudLogging();5 6export default async function handler(req: VercelRequest, res: VercelResponse) {7 const startTime = Date.now();8 9 try {10 // Log request start11 await logger.info({12 message: 'Processing webhook',13 method: req.method,14 url: req.url,15 headers: req.headers16 }, { type: 'webhook', stage: 'start' });17 18 // Process webhook19 const result = await processWebhook(req.body);20 21 // Log success with performance metrics22 await logger.info({23 message: 'Webhook processed successfully',24 duration: Date.now() - startTime,25 result: result26 }, { type: 'webhook', stage: 'complete' });27 28 res.status(200).json({ success: true });29 30 } catch (error) {31 await logger.error({32 message: 'Webhook processing failed',33 duration: Date.now() - startTime,34 error: error.message35 }, { type: 'webhook', stage: 'error' });36 37 res.status(500).json({ error: 'Webhook failed' });38 }39}
Viewing Your Logs
Once implemented, your logs will be available in the Google Cloud Console:
- Navigate to Logging → Logs Explorer
- Filter by your log name (e.g.,
vercel-production
) - Use labels and severity levels to organize and query your logs
- Set up log-based metrics and alerts for monitoring