diff --git a/.readme-partials.yml b/.readme-partials.yml index fa34c25d..ebaa8479 100644 --- a/.readme-partials.yml +++ b/.readme-partials.yml @@ -164,6 +164,8 @@ body: |- It is recommended to set `redirectToStdout: true` in serverless environments like Cloud Functions since it could decrease logging record loss upon execution termination - since all logs are written to `process.stdout` those would be picked up by the Cloud Logging Agent running in Google Cloud managed environment. + Note that there is also a `useMessageField` option which controls if "message" field is used to store + structured, non-text data inside `jsonPayload` field when `redirectToStdout` is set. By default `useMessageField` is always `true`. ```js // Imports the Google Cloud client library for Bunyan diff --git a/README.md b/README.md index 698a6f68..1ac076b1 100644 --- a/README.md +++ b/README.md @@ -246,6 +246,8 @@ The agent can parse structured logs printed to `process.stdout` and capture addi It is recommended to set `redirectToStdout: true` in serverless environments like Cloud Functions since it could decrease logging record loss upon execution termination - since all logs are written to `process.stdout` those would be picked up by the Cloud Logging Agent running in Google Cloud managed environment. +Note that there is also a `useMessageField` option which controls if "message" field is used to store +structured, non-text data inside `jsonPayload` field when `redirectToStdout` is set. By default `useMessageField` is always `true`. ```js // Imports the Google Cloud client library for Bunyan diff --git a/package.json b/package.json index 5a9e187f..edac9eec 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "precompile": "gts clean" }, "dependencies": { - "@google-cloud/logging": "^10.0.2", + "@google-cloud/logging": "^10.1.1", "google-auth-library": "^8.0.2" }, "devDependencies": { diff --git a/src/index.ts b/src/index.ts index a206c88f..87628d7f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -37,6 +37,7 @@ import * as types from './types/core'; import {ApiResponseCallback} from '@google-cloud/logging/build/src/log'; import {LogSeverityFunctions} from '@google-cloud/logging/build/src/utils/log-common'; +import {LogSyncOptions} from '@google-cloud/logging/build/src/log-sync'; // Map of Stackdriver logging levels. const BUNYAN_TO_STACKDRIVER: Map = new Map([ @@ -177,6 +178,7 @@ export class LoggingBunyan extends Writable { private defaultCallback?: ApiResponseCallback; cloudLog: LogSeverityFunctions; redirectToStdout: boolean; + constructor(options?: types.Options) { options = options || {}; super({objectMode: true}); @@ -195,7 +197,14 @@ export class LoggingBunyan extends Writable { maxEntrySize: options.maxEntrySize || 250000, }); } else { - this.cloudLog = new Logging(options).logSync(this.logName); + const logSyncOptions: LogSyncOptions = { + useMessageField: options.useMessageField ?? true, + }; + this.cloudLog = new Logging(options).logSync( + this.logName, + undefined, + logSyncOptions + ); } // serviceContext.service is required by the Error Reporting diff --git a/src/types/core.d.ts b/src/types/core.d.ts index 7ead43dd..f79823ef 100644 --- a/src/types/core.d.ts +++ b/src/types/core.d.ts @@ -91,6 +91,13 @@ export interface Options { * agent. Redirected logs are formatted as one line Json string following the structured logging guidelines. */ redirectToStdout?: boolean; + + /** + * Boolean flag indicating if "message" field should be used to store structured, + * non-text data inside jsonPayload field. This flag applies only when {@link Options#redirectToStdout} is set. + * By default this value is true + */ + useMessageField?: boolean; } export interface MonitoredResource { diff --git a/system-test/logging-bunyan.ts b/system-test/logging-bunyan.ts index 45119b1d..9cbba911 100644 --- a/system-test/logging-bunyan.ts +++ b/system-test/logging-bunyan.ts @@ -57,6 +57,16 @@ describe('LoggingBunyan', function () { assert.ok(loggingBunyan.cloudLog instanceof LogSync); }); + it('should create LoggingBunyan with LogSync and useMessageField is off', () => { + const loggingBunyan = new LoggingBunyan({ + logName: LOG_NAME, + redirectToStdout: true, + useMessageField: false, + }); + assert.ok(loggingBunyan.cloudLog instanceof LogSync); + assert.ok(loggingBunyan.cloudLog.useMessageField_ === false); + }); + it('should write diagnostic entry', async () => { instrumentation.setInstrumentationStatus(false); const start = Date.now();