google cloud trace not working in express

948 Views Asked by At

I'm trying to implement google trace in my MERN project, hosted in google cloud platform.

I've followed the guide and the examples offered by Google, but I can't make it work in any way.

import gCloudTrace from '@google-cloud/trace-agent';
// initialize gcloud trace
if (process.env.NODE_ENV === 'production') {
  console.log(`Starting google cloud trace...`);
  const tracer = gCloudTrace.start();
  console.log(JSON.stringify(tracer,null,2));
};

import express from 'express';
import apiRoute  from './api.js';
import indexRoute from './index/indexRoute.js';

try {

  // setup
  const host = process.env.HOST || '0.0.0.0';
  const port = process.env.PORT || 5050;
  const app = express();

  // routes
  app.use('/', indexRoute);
  app.use('/api', checkGloblalSettings, apiRoute);

  // create and run HTTP server
  app.listen(port, host, () => {
    console.log(`EXPRESS SERVER HTTP BACKEND UP AND RUNNING ON ${host} : ${port}`);
  });

  } catch(error) {
    globalErrorHandler(error);
};

When I deploy (google app engine, flex env) everything works great, all route works but I can't find any trace in my project. I've double checked gcloud settings: Trace API is enabled, no need to create custom credentials.

Any suggestion?

1

There are 1 best solutions below

1
On BEST ANSWER

I finally solved the problem. While the code in the question seems correct, the problem inherently lies in how NodeJS handles ES6 import() instead of require().

Throughout the Google Trace documentation you will find only examples with require(). Here an example:

if (process.env.NODE_ENV === 'production') {
  require('@google-cloud/trace-agent').start();
}

const express = require('express');
const got = require('got');

const app = express();
const DISCOVERY_URL = 'https://www.googleapis.com/discovery/v1/apis';

// This incoming HTTP request should be captured by Trace
app.get('/', async (req, res) => {
  // This outgoing HTTP request should be captured by Trace
  try {
    const {body} = await got(DISCOVERY_URL, {responseType: 'json'});
    const names = body.items.map(item => item.name);
    res.status(200).send(names.join('\n')).end();
  } catch (err) {
    console.error(err);
    res.status(500).end();
  }
});

// Start the server
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
  console.log(`App listening on port ${PORT}`);
  console.log('Press Ctrl+C to quit.');
});

The fact is that while using require the import order is respected (so if you place require('@ google-cloud/trace-agent').start(); in the first place everything works), using import() the code runs AFTER importing the express module as well, so nothing is tracked.

To solve, I recreated the require syntax (here the documentation), then using require() everything worked perfectly:

import { createRequire } from 'module';
const require = createRequire(import.meta.url);
if (process.env.NODE_ENV === 'production') {
  // [START trace_setup_nodejs_implicit]
  require('@google-cloud/trace-agent').start({
    logLevel: 2,
    flushDelaySeconds: 30,
    ignoreUrls: ['/_ah/health', '/api/status'],
    ignoreMethods: ['OPTIONS'],
    samplingRate: 10,
    bufferSize: 1000,
    onUncaughtException: 'ignore',
  });
  // [END trace_setup_nodejs_implicit]
};

const express = await require('express');

I hope this can serve others and avoid the headaches it caused me :)