Vercel Functions to GCP Cloud Logging

Vercel Functions to GCP Cloud Logging

Log Observability Implementation

ยท

3 min read

Table of contents

No heading

No headings in the article.

Well, Vercel Serverless architecture is easy to develop, developer-friendly, and easy to deploy. As and when you start to scale your hobby project into a scale-version, you need to implement several things to keep your systems up and running, error-free. One such system is logging to a log management tool. Vercel offers log-drain options to various services, thanks to their integration partners like Datadog, Logdna, etc. However, Google Cloud Platform's (GCP) Cloud Logging is not an integration provided out of the box. Let's learn to implement the Cloud Logging library and flow our logs into GCP.

โœ‹๐Ÿผ Before we dive deep inside - find if this article works for you

  • This implementation will require a GCP service account, specifically the client_email, private_key and project_id of the service account to connect.
  • This implementation is not async and you'll need to await each call due to the serverless architecture limitation. The function may terminate earlier than the log being sent to GCP if not await'ed.
  • This implementation will not work on Edge Functions like _middleware.ts since the edge functions runtime runs on browser environment and the logging library's dependencies like fs won't work.

Get your service account

  • Go to your GCP console, then IAM section, then Service accounts tab, and then create a new service account. Name it anything you want, give the Logging Admin permission to the service account.
  • Once created, select the service account and create a JSON key. The downloaded key will contain client_email, private_key and project_id key-value pairs. This is used to authenticate Google Cloud Logging library which we'll use.

โœ‹๐Ÿผ Note

Vercel environment variables are limited to 4 Kb in total since the underlying AWS Lambda layer supports only unto this limit. This is for each environment.

If you plan to use the service account JSON in the environment variable, plan to add all the permissions your functions may need to a single service account. Creating multiple service accounts for different GCP or Firebase services is not a great approach to follow with Vercel architecture constraints.

Let's create a reusable class for logging

  • We've used the service account credentials JSON key file as an environment variable named GOOGLE_SERVICE_ACCOUNT.
  • Install Cloud Logging library yarn add @google-cloud/logging.
  • VERCEL_ENV is either production, staging or development. This is used to log appropriately in a GCP project.
import { Logging } from '@google-cloud/logging';
import { VercelRequest } from "@vercel/node";

export class CloudLogging {
    logging = new Logging({
        projectId: JSON.parse(process.env.GOOGLE_SERVICE_ACCOUNT).project_id,
        credentials: {
            client_email: JSON.parse(process.env.GOOGLE_SERVICE_ACCOUNT).client_email,
            private_key: JSON.parse(process.env.GOOGLE_SERVICE_ACCOUNT).private_key,
        }
    });
    log = this.logging.log(process.env.VERCEL_ENV, {
        removeCircular: true
    });

    async logData(severity: string, data: string | JSON | any) {
        try {
            await this.log.write(this.log.entry({
                resource: {
                    type: 'global',
                },
                labels: {
                    label: 'exampleLabel'
                },
                severity: severity,
            }, data));
        } catch (error) {
            console.log(error);
        } finally {
            return;
        }
    }
}

Using the CloudLogging class we created

  • We import the class we just created called CloudLogging. Feel free to tweak the class as per your requirement.
  • We send logs to GCP Cloud Logging by using the logData() method inside the class.
import { CloudLogging } from '@/lib/gcp/logging';  // Refer where you create the class

async function someFunction() {
    //...
    await cloudLogging.logData('INFO', jsonData || stringData);
    //...
}

someClass {
    async someMethod() {
        //...
        await cloudLogging.logData('ERROR', jsonData || stringData);
        //...
    }
}

Viola, the log service implementation is done and logs will be visible in the GCP console for viewing or data querying.

ย