Reporting Errors

Automatically reporting errors

You can emit an error from a Cloud Function to Stackdriver Error Reporting by simply logging an Error object to the console on the error level:

console.error(new Error('message'));

You can view the reported errors in Stackdriver Error Reporting in the API Console. You can also see the errors reported from a particular function when you select it from the list of functions in the API Console.

Errors also appear in Stackdriver Error Reporting when your function produces an uncaught error, or if you explicitly throw an object of type Error. However, uncaught errors and exceptions force a cold start on future invocation. So for performance reasons, you should use the first approach (logging an Error object).

Note that the following will not emit a Stackdriver error:

  • Throwing something that is not an Error object: for example, throw 1;
  • Logging an error object on the info level: for example, console.info(new Error('message'));
  • Logging something that is not an Error object: for example, console.error('message');
  • Normal completion of your function with an error result: for example, res.status(500).send('message'); for HTTP functions and callback('message'); for all other background triggers.

When reporting errors in the catch block of a try-catch statement, or the catch callback of a Promise, the err object will often already be a typed Error object. If you are using Google services through a Google-provided library, you can simply log the provided err object directly:

Node.js

try {
  // Throw an Error object (to simulate a GCP API failure)
  throw new Error('Error object!');
} catch (err) {
  // err is already an Error object
  console.error(err);
}

If you are not sure whether the provided err is an Error object, you can check it as follows:

Node.js

try {
  // Throw an unknown error type
  if (someCondition) {
    throw 'Error string!';
  } else {
    throw new Error('Error object!');
  }
} catch (err) {
  // Determine the error type
  if (err instanceof Error) {
    console.error(err);
  } else {
    console.error(new Error(err));
  }
}

Manually reporting errors

To report an error to Stackdriver Error Reporting from a function, use the Stackdriver Logging API.

Importing dependencies

From your functions directory, install the Google Stackdriver Logging Client Library for Node.js:

npm install --save @google-cloud/logging

Import the Google Cloud Client Library to access the Logging API:

const Logging = require('@google-cloud/logging');

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

Sending to Stackdriver

A properly formed log entry requires a MonitoredResource object and an ErrorEvent object.

This example reportError function demonstrates the minimum data required to report an error to Stackdriver Error Reporting.

function reportError(err, context = {}) {
  // This is the name of the StackDriver log stream that will receive the log
  // entry. This name can be any valid log stream name, but must contain "err"
  // in order for the error to be picked up by StackDriver Error Reporting.
  const logName = 'errors';
  const log = logging.log(logName);

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

  // 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();
    });
  });
}

The reportError function can be used to manually report errors:

// Charge the Stripe customer whenever an amount is written to the Realtime database
exports.createStripeCharge = functions.database.ref('/stripe_customers/{userId}/charges/{id}')
    .onCreate((snap, context) => {
      const val = snap.val();
      // Look up the Stripe customer id written in createStripeCustomer
      return admin.database().ref(`/stripe_customers/${context.params.userId}/customer_id`)
          .once('value').then((snapshot) => {
            return snapshot.val();
          }).then((customer) => {
            // Create a charge using the pushId as the idempotency key
            // protecting against double charges
            const amount = val.amount;
            const idempotencyKey = context.params.id;
            const charge = {amount, currency, customer};
            if (val.source !== null) {
              charge.source = val.source;
            }
            return stripe.charges.create(charge, {idempotency_key: idempotencyKey});
          }).then((response) => {
            // If the result is successful, write it back to the database
            return snap.ref.set(response);
          }).catch((error) => {
            // We want to capture errors and render them in a user-friendly way, while
            // still logging an exception with StackDriver
            return snap.ref.child('error').set(userFacingMessage(error));
          }).then(() => {
            return reportError(error, {user: context.params.userId});
          });
        });

You can pass user details through the ErrorContext parameter. The Stackdriver UI displays these details and uses them to calculate the number of affected users.

ErrorContext can also be passed information on an HTTP Request:

export.httpError = functions.https.onRequest((request, response) => {
  const error = new Error('Test error');
  const httpRequest = {
    method: request.method,
    url: request.originalUrl,
    userAgent: request.get('user-agent'),
    referrer: '',
    remoteIp: request.ip
  };
  reportError(error, {httpRequest}).then(() => {
    response.end();
  });
});

傳送您對下列選項的寶貴意見...

這個網頁
需要協助嗎?請前往我們的支援網頁