6

I'm using Firebase functions along with Stackdriver.

Stackdriver is very well integrated with Firebase functions, so I can easily log errors with the console.error command. But, I want to record not only about error object but also query parameters. If I can record error object and query paramters in the same log line, they can be easily grouped and exported.

Is there a easy way to add information to error log on Stackdriver like below?

    console.error(new Error('Invalid query'), req.query)

Thanks.

--- edit

I tried the following code. This can add a query parameter to the log entry, but unfortunately Stackdriver puts all the errors in one group as shown in the screenshot below. All errors are grouped together even though each error is different type and occurs in different file. I expect Stackdriver Error Reporting to group errors by error type or stack trace as usual.

index.js

const functions = require('firebase-functions')
const raiseReferenceError = require('./raiseReferenceError')
const raiseSyntaxError = require('./raiseSyntaxError')
const raiseTypeError = require('./raiseTypeError')

exports.stackdriverErrorLogging = functions.https.onRequest((req, res) => {
  try {
    switch (Math.round(Math.random() * 2)) {
      case 0:
        raiseReferenceError()
        break

      case 1:
        raiseSyntaxError()
        break

      default:
        raiseTypeError()
        break
    }
  } catch (error) {
    console.error({
      error: error,
      method: req.method,
      query: req.query
    })
  }

  res.send('Hello from Firebase!')
})

raiseReferenceError.js

module.exports = () => {
  console.log(foo)
}

raiseSyntaxError.js

module.exports = () => {
  eval(',')
}

raiseTypeError.js

module.exports = () => {
  const foo = null
  foo()
}

Screenshot of results of 10 runs:

Stackdriver Error Reporting error summary page Stackdriver error summary page Stackdriver Error Reporting error details page Stackdriver error details page 1 Stackdriver error details page 2

astanet
  • 172
  • 1
  • 11

3 Answers3

3

Self answer:

I tried to find easy way, but there was not. So I decided to get off my lazy butt and learn how to use @google-cloud/logging that as Yuri Grinshteyn mentioned.

I found a lot of examples, but none were sufficient for this case. At last, I built a function that reports error with additional information easily.

The important points are as follows:

  1. To show custom error log on GCP console as normal error log, it needs to include severity, region, execution_id, trace ID. If lack of them, GCP console doesn't show them on default filter. Also can't group by execution ID tag.
  2. execution_id and trace ID should be extracted from http request. (I don't know how to get them on another trigger type functions.)

It took time, but finally, Stackdriver Error Reporting recognize and group each error type and successfully include custom information in the error log's JSON payload. This is what I wanted.

Now I can finally get back to work.

Here is a gist I made.

Here is a main code.

// https://firebase.google.com/docs/functions/reporting-errors#manually_reporting_errors
const { Logging } = require('@google-cloud/logging')

// Instantiates a client
const logging = new Logging()

module.exports = function reportError (err, context = {}, req = undefined) {
  // Use Stackdriver only on production environment.
  if (process.env.NODE_ENV !== 'production') {
    return new Promise((resolve, reject) => {
      console.error(err, context)
      return resolve()
    })
  }

  const log = logging.log('cloudfunctions.googleapis.com%2Fcloud-functions')

  // https://cloud.google.com/logging/docs/api/ref_v2beta1/rest/v2beta1/MonitoredResource
  const metadata = {
    severity: 'ERROR',
    resource: {
      type: 'cloud_function',
      labels: {
        function_name: process.env.FUNCTION_NAME,
        project: process.env.GCLOUD_PROJECT,
        region: process.env.FUNCTION_REGION
      }
    }
  }

  // Extract execution_id, trace from http request
  // https://stackoverflow.com/a/55642248/7908771
  if (req) {
    const traceId = req.get('x-cloud-trace-context').split('/')[0]
    Object.assign(metadata, {
      trace: `projects/${process.env.GCLOUD_PROJECT}/traces/${traceId}`,
      labels: {
        execution_id: req.get('function-execution-id')
      }
    })
  }

  // https://cloud.google.com/error-reporting/reference/rest/v1beta1/ErrorEvent
  const errorEvent = {
    message: err.stack,
    serviceContext: {
      service: process.env.FUNCTION_NAME,
      resourceType: 'cloud_function'
    },
    context: context
  }

  // Write the error log entry
  return new Promise((resolve, reject) => {
    log.write(log.entry(metadata, errorEvent), (error) => {
      if (error) {
        return reject(error)
      }
      return resolve()
    })
  })
}

Screenshot of results of 10 runs:

Stackdriver Error Reporting error summary page. Stackdriver Error Reporting error summary page.

Stackdriver Logging shows a error with custom information. Stackdriver Logging shows a error with custom information.

astanet
  • 172
  • 1
  • 11
  • I followed this helper function, but still i am unable to get my custom log into the stackdriver. When i trigger an API which explicitly throws an error, a DEBUG log gets logged but with no custom details. There is no key as jsonPayload in the logs as well. – Tech de Enigma Apr 22 '20 at 16:26
  • Checked with google-logging docs also, but still my custom logs are not getting logged – Tech de Enigma Apr 23 '20 at 05:56
0

When I work with errors I normally use an object structure that gives me all the information I need. Something like this:

const query = req.query;
const myErrorObject = new Error('some error');


console.error({
    method: req.method,
    query: req.query,
    error: myErrorObject
});

Hope that helps

ajorquera
  • 1,297
  • 22
  • 29
  • Thank you for the excellent suggestions. I tried it, but unfortunately Stackdriver didn't group the logs by individual error. All errors was grouped in one group together. I will add my tries to the question. Anyway, thank you for the useful information. – astanet Nov 04 '19 at 01:09
0

[update] - I see you've added more information that shows you're trying to use Error Reporting, rather than just logging. You can still use the logging library as documented here.

I would recommend using the Stackdriver logging library that should allow you to write structured logs. This is described in the Firebase documentation.

Yuri Grinshteyn
  • 727
  • 3
  • 13
  • Thank you for telling me the official information. However, it takes time to understand how to use Custom Logging, so I felt it is bother. Thus I was looking for an easy way. I also tried '[@google-cloud/error-reporting](https://github.com/googleapis/nodejs-error-reporting)', but couldn't find a good example for this case and couldn't use it well. That is why I asked this question. There may be no other way than your suggestion. I'm glad you are interested in this question. Thanks. – astanet Nov 04 '19 at 02:28
  • Thank you for telling me again! There might be no easy way. I will try it. – astanet Nov 09 '19 at 00:20