Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Cloud Functions Error Reporting sample #140

Merged
merged 6 commits into from
Jun 28, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Tweak error reporting sample code.
  • Loading branch information
jmdobry committed Jun 27, 2016
commit a3d2f5404068b23e1408b978fce8727dba495d14
11 changes: 6 additions & 5 deletions functions/errorreporting/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ var gcloud = require('gcloud');
var logging = gcloud.logging();
// [END setup]

// [START reporting]
var reporting = require('./report');
// [END reporting]
// [START reportDetailedError]
var reportDetailedError = require('./report');
// [END reportDetailedError]

// [START helloSimpleErrorReport]
/**
Expand Down Expand Up @@ -104,9 +104,10 @@ exports.helloHttpError = function helloHttpError (req, res) {
// All is good, respond to the HTTP request
return res.send('Hello ' + (req.body.message || 'World') + '!').end();
} catch (err) {
// Set the response status code before reporting the error
res.status(err.code || 500);
// Report the error
return reporting.reportHttpError(err, req, res, function () {
return reportDetailedError(err, req, res, function () {
// Now respond to the HTTP request
res.send(err.message);
});
Expand All @@ -131,7 +132,7 @@ exports.helloBackgroundError = function helloBackgroundError (context, data) {
return context.success('Hello World!');
} catch (err) {
// Report the error
return reporting.reportError(err, function () {
return reportDetailedError(err, function () {
// Now finish mark the execution failure
context.failure(err.message);
});
Expand Down
110 changes: 50 additions & 60 deletions functions/errorreporting/report.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,43 +16,33 @@
var gcloud = require('gcloud');
var logging = gcloud.logging();

function getVersion (options) {
try {
if (options.version === undefined) {
var pkg = require('./package.json');
options.version = pkg.version;
}
} catch (err) {}
if (options.version === undefined) {
options.version = 'unknown';
}
}

function getRequest (options) {
if (options.req && options.req) {
var req = options.req;
return {
method: req.method,
url: req.originalUrl,
userAgent: typeof req.get === 'function' ? req.get('user-agent') : 'unknown',
referrer: '',
responseStatusCode: options.res.statusCode,
remoteIp: req.ip
};
// [START helloHttpError]
/**
* Report an error to StackDriver Error Reporting. Writes up to the maximum data
* accepted by StackDriver Error Reporting.
*
* @param {Error} err The Error object to report.
* @param {Object} [req] Request context, if any.
* @param {Object} [res] Response context, if any.
* @param {Object} [options] Additional context, if any.
* @param {Function} callback Callback function.
*/
function reportDetailedError (err, req, res, options, callback) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this perhaps be upstreamed into gcloud?

if (typeof req === 'function') {
callback = req;
req = null;
res = null;
options = {};
} else if (typeof options === 'function') {
callback = options;
options = {};
}
}

function report (options, callback) {
options || (options = {});
options.err || (options.err = {});
options.req || (options.req = {});

var FUNCTION_NAME = process.env.FUNCTION_NAME;
var FUNCTION_TRIGGER_TYPE = process.env.FUNCTION_TRIGGER_TYPE;
var ENTRY_POINT = process.env.ENTRY_POINT;

getVersion(options);

var log = logging.log('errors');

// MonitoredResource
Expand All @@ -77,11 +67,20 @@ function report (options, callback) {
// ErrorEvent.context.user
context.user = options.user;
}
if (FUNCTION_TRIGGER_TYPE === 'HTTP_TRIGGER') {
if (FUNCTION_TRIGGER_TYPE === 'HTTP_TRIGGER' && req && res) {
// ErrorEvent.context.httpRequest
context.httpRequest = getRequest(options);
context.httpRequest = {
method: req.method,
url: req.originalUrl,
userAgent: typeof req.get === 'function' ? req.get('user-agent') : 'unknown',
referrer: '',
remoteIp: req.ip
};
if (typeof res.statusCode === 'number') {
context.httpRequest.responseStatusCode = res.statusCode;
}
}
if (!(options.err instanceof Error)) {
if (!(err instanceof Error) || typeof err.stack !== 'string') {
// ErrorEvent.context.reportLocation
context.reportLocation = {
filePath: typeof options.filePath === 'string' ? options.filePath : 'unknown',
Expand All @@ -90,6 +89,16 @@ function report (options, callback) {
};
}

try {
if (options.version === undefined) {
var pkg = require('./package.json');
options.version = pkg.version;
}
} catch (err) {}
if (options.version === undefined) {
options.version = 'unknown';
}

// ErrorEvent
// See https://cloud.google.com/error-reporting/reference/rest/v1beta1/ErrorEvent
var structPayload = {
Expand All @@ -105,35 +114,16 @@ function report (options, callback) {
};

// ErrorEvent.message
if (options.err instanceof Error && typeof options.err.stack === 'string') {
structPayload.message = options.err.stack;
} else if (typeof options.err === 'string') {
structPayload.message = options.err;
} else if (typeof options.err.message === 'string') {
structPayload.message = options.err.message;
if (err instanceof Error && typeof err.stack === 'string') {
structPayload.message = err.stack;
} else if (typeof err === 'string') {
structPayload.message = err;
} else if (typeof err.message === 'string') {
structPayload.message = err.message;
}

log.write(log.entry(resource, structPayload), callback);
}
// [END helloHttpError]

exports.report = report;

exports.reportError = function reportError (err, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
options.err = err;
report(options, callback);
};

exports.reportHttpError = function reportHttpError (err, req, res, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
options.err = err;
options.req = req;
options.res = res;
report(options, callback);
};
module.exports = reportDetailedError;
26 changes: 25 additions & 1 deletion functions/log/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,32 @@
'use strict';

// [START log]
exports.helloWorld = function (context, data) {
exports.helloWorld = function helloWorld (context, data) {
console.log('I am a log entry!');
context.success();
};
// [END log]

exports.retrieve = function retrieve () {
// [START retrieve]
// By default, gcloud will authenticate using the service account file specified
// by the GOOGLE_APPLICATION_CREDENTIALS environment variable and use the
// project specified by the GCLOUD_PROJECT environment variable. See
// https://googlecloudplatform.github.io/gcloud-node/#/docs/guides/authentication
var gcloud = require('gcloud');
var logging = gcloud.logging();

// Retrieve the latest Cloud Function log entries
// See https://googlecloudplatform.github.io/gcloud-node/#/docs/logging
logging.getEntries({
pageSize: 10,
filter: 'resource.type="cloud_function"'
}, function (err, entries) {
if (err) {
console.error(err);
} else {
console.log(entries);
}
});
// [END retrieve]
}