diff --git a/packages/logging-bunyan/README.md b/packages/logging-bunyan/README.md index 7fa101183f2..300e85a3aae 100644 --- a/packages/logging-bunyan/README.md +++ b/packages/logging-bunyan/README.md @@ -66,7 +66,29 @@ var loggingBunyan = require('@google-cloud/logging-bunyan')({ // ...you're good to go! ``` +## Formatting Request Logs + +To format your request logs you can provide a `httpRequest` property on the bunyan metadata you provide along with the log message. We will treat this as the [`HttpRequest`][http-request-message] message and Stackdriver logging will show this as a request log. Example: + +![Request Log Example](/doc/images/request-log.png) + +```js +logger.info({ + httpRequest: { + status: res.statusCode, + requestUrl: req.url, + requestMethod: req.method, + remoteIp: req.connection.remoteAddress, + // etc. + } +}, req.path); +``` + +The `httpRequest` proprety must be a properly formatted [`HttpRequest`][http-request-message] message. + + [bunyan]: https://github.com/trentm/node-bunyan [@google-cloud/logging]: https://www.npmjs.com/package/@google-cloud/logging [gce-how-to]: https://cloud.google.com/compute/docs/authentication#using +[http-request-message]: https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#HttpRequest [dev-console]: https://console.developers.google.com/project \ No newline at end of file diff --git a/packages/logging-bunyan/doc/images/request-log.png b/packages/logging-bunyan/doc/images/request-log.png new file mode 100644 index 00000000000..a58853afa15 Binary files /dev/null and b/packages/logging-bunyan/doc/images/request-log.png differ diff --git a/packages/logging-bunyan/src/index.js b/packages/logging-bunyan/src/index.js index 11bf4691be0..8723898a053 100644 --- a/packages/logging-bunyan/src/index.js +++ b/packages/logging-bunyan/src/index.js @@ -141,13 +141,12 @@ LoggingBunyan.prototype.formatEntry_ = function(record) { ); } + record = extend({}, record); + // Stackdriver Log Viewer picks up the summary line from the 'message' field // of the payload. Unless the user has provided a 'message' property also, // move the 'msg' to 'message'. if (!record.message) { - // Clone the object before modifying it. - record = extend({}, record); - // If this is an error, report the full stack trace. This allows Stackdriver // Error Reporting to pick up errors automatically (for severity 'error' or // higher). In this case we leave the 'msg' property intact. @@ -171,6 +170,17 @@ LoggingBunyan.prototype.formatEntry_ = function(record) { severity: BUNYAN_TO_STACKDRIVER[record.level] }; + // If the record contains a httpRequest property, provide it on the entry + // metadata. This allows Stackdriver to use request log formatting. + // https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#HttpRequest + // Note that the httpRequest field must properly validate as a HttpRequest + // proto message, or the log entry would be rejected by the API. We do no + // validation here. + if (record.httpRequest) { + entryMetadata.httpRequest = record.httpRequest; + delete record.httpRequest; + } + return this.log_.entry(entryMetadata, record); }; diff --git a/packages/logging-bunyan/test/index.js b/packages/logging-bunyan/test/index.js index bb16ddd9334..3a27c364558 100644 --- a/packages/logging-bunyan/test/index.js +++ b/packages/logging-bunyan/test/index.js @@ -201,6 +201,28 @@ describe('logging-bunyan', function() { loggingBunyan.formatEntry_(record); }); + + it('should promote the httpRequest property to metadata', function(done) { + var HTTP_REQUEST = { + statusCode: 418 + }; + var recordWithRequest = extend({ + httpRequest: HTTP_REQUEST, + }, RECORD); + + loggingBunyan.log_.entry = function(entryMetadata, record) { + assert.deepStrictEqual(entryMetadata, { + resource: loggingBunyan.resource_, + timestamp: RECORD.time, + severity: LoggingBunyan.BUNYAN_TO_STACKDRIVER[RECORD.level], + httpRequest: HTTP_REQUEST + }); + assert.deepStrictEqual(record, RECORD); + done(); + }; + + loggingBunyan.formatEntry_(recordWithRequest); + }); }); describe('_write', function() {