@google-cloud/logging
Version:
Cloud Logging Client Library for Node.js
1,012 lines • 39.8 kB
JavaScript
;
/*!
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.v2 = exports.protos = exports.Logging = exports.Sink = exports.LogSync = exports.formatLogName = exports.assignSeverityToEntries = exports.Severity = exports.Log = exports.Entry = exports.detectServiceContext = exports.middleware = void 0;
const common_1 = require("@google-cloud/common");
const paginator_1 = require("@google-cloud/paginator");
const projectify_1 = require("@google-cloud/projectify");
const promisify_1 = require("@google-cloud/promisify");
const arrify = require("arrify");
const extend = require("extend");
const gax = require("google-gax");
// eslint-disable-next-line @typescript-eslint/no-var-requires
const pumpify = require('pumpify');
const streamEvents = require("stream-events");
const middleware = require("./middleware");
exports.middleware = middleware;
const metadata_1 = require("./utils/metadata");
Object.defineProperty(exports, "detectServiceContext", { enumerable: true, get: function () { return metadata_1.detectServiceContext; } });
const version = require('../../package.json').version;
// eslint-disable-next-line @typescript-eslint/no-var-requires
const v2 = require('@google-cloud/logging-api');
exports.v2 = v2;
const entry_1 = require("./entry");
Object.defineProperty(exports, "Entry", { enumerable: true, get: function () { return entry_1.Entry; } });
const log_common_1 = require("./utils/log-common");
Object.defineProperty(exports, "Severity", { enumerable: true, get: function () { return log_common_1.Severity; } });
Object.defineProperty(exports, "formatLogName", { enumerable: true, get: function () { return log_common_1.formatLogName; } });
Object.defineProperty(exports, "assignSeverityToEntries", { enumerable: true, get: function () { return log_common_1.assignSeverityToEntries; } });
const log_1 = require("./log");
Object.defineProperty(exports, "Log", { enumerable: true, get: function () { return log_1.Log; } });
const log_sync_1 = require("./log-sync");
Object.defineProperty(exports, "LogSync", { enumerable: true, get: function () { return log_sync_1.LogSync; } });
const sink_1 = require("./sink");
Object.defineProperty(exports, "Sink", { enumerable: true, get: function () { return sink_1.Sink; } });
const stream_1 = require("stream");
const logging_api_1 = require("@google-cloud/logging-api");
Object.defineProperty(exports, "protos", { enumerable: true, get: function () { return logging_api_1.protos; } });
/**
* @typedef {object} ClientConfig
* @property {string} [projectId] The project ID from the Google Developer's
* Console, e.g. 'grape-spaceship-123'. We will also check the environment
* variable `GCLOUD_PROJECT` for your project ID. If your app is running in
* an environment which supports {@link
* https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application
* Application Default Credentials}, your project ID will be detected
* automatically.
* @property {string} [keyFilename] Full path to the a .json, .pem, or .p12 key
* downloaded from the Google Developers Console. If you provide a path to a
* JSON file, the `projectId` option above is not necessary. NOTE: .pem and
* .p12 require you to specify the `email` option as well.
* @property {string} [email] Account email address. Required when using a .pem
* or .p12 keyFilename.
* @property {object} [credentials] Credentials object.
* @property {string} [credentials.client_email]
* @property {string} [credentials.private_key]
* @property {boolean} [autoRetry=true] Automatically retry requests if the
* response is related to rate limits or certain intermittent server errors.
* We will exponentially backoff subsequent requests by default.
* @property {number} [maxRetries=3] Maximum number of automatic retries
* attempted before returning the error.
* @property {Constructor} [promise] Custom promise module to use instead of
* native Promises.
*/
/**
* {@link https://cloud.google.com/logging/docs| Cloud Logging} allows you to
* store, search, analyze, monitor, and alert on log data and events from Google
* Cloud Platform and Amazon Web Services (AWS).
*
* @class
*
* See {@link https://cloud.google.com/logging/docs| What is Cloud Logging?}
*
* See {@link https://cloud.google.com/logging/docs/api| Introduction to the Cloud Logging API}
*
* See {@link https://www.npmjs.com/package/@google-cloud/logging-bunyan| Logging to Google Cloud from Bunyan}
*
* See {@link https://www.npmjs.com/package/@google-cloud/logging-winston| Logging to Google Cloud from Winston}
*
* @param {ClientConfig} [options] Configuration options.
*
* @example Import the client library
* ```
* const {Logging} = require('@google-cloud/logging');
*
* ```
* @example Create a client that uses <a href="https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application">Application Default Credentials (ADC)</a>:
* ```
* const logging = new Logging();
*
* ```
* @example Create a client with <a href="https://cloud.google.com/docs/authentication/production#obtaining_and_providing_service_account_credentials_manually">explicitcredentials</a>:
* ```
* const logging = new Logging({ projectId:
* 'your-project-id', keyFilename: '/path/to/keyfile.json'
* });
*
* ```
* @example <caption>include:samples/quickstart.js</caption>
* region_tag:logging_quickstart
* Full quickstart example:
*/
class Logging {
constructor(options, gaxInstance) {
// Determine what scopes are needed.
// It is the union of the scopes on all three clients.
const scopes = [];
const clientClasses = [
v2.ConfigServiceV2Client,
v2.LoggingServiceV2Client,
v2.MetricsServiceV2Client,
];
for (const clientClass of clientClasses) {
for (const scope of clientClass.scopes) {
if (scopes.indexOf(scope) === -1) {
scopes.push(scope);
}
}
}
const options_ = extend({
libName: 'gccl',
libVersion: version,
scopes,
}, options);
this.api = {};
this.auth = new (gaxInstance !== null && gaxInstance !== void 0 ? gaxInstance : gax).GoogleAuth(options_);
this.options = options_;
this.projectId = this.options.projectId || '{{projectId}}';
this.configService = new v2.ConfigServiceV2Client(this.options, gaxInstance);
this.loggingService = new v2.LoggingServiceV2Client(this.options, gaxInstance);
}
// jscs:disable maximumLineLength
/**
* Create a sink.
*
* See {@link https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.sinks|Sink Overview}
* See {@link https://cloud.google.com/logging/docs/view/advanced_filters|Advanced Logs Filters}
* See {@link https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.sinks/create|projects.sinks.create API Documentation}
*
* @param {string} name Name of the sink.
* @param {CreateSinkRequest} config Config to set for the sink.
* @param {CreateSinkCallback} [callback] Callback function.
* @returns {Promise<CreateSinkResponse>}
* @throws {Error} If a name is not provided.
* @throws {Error} if a config object is not provided.
* @see Sink#create
*
* @example
* ```
* const {Storage} = require('@google-cloud/storage');
* const storage = new Storage({
* projectId: 'grape-spaceship-123'
* });
* const {Logging} = require('@google-cloud/logging');
* const logging = new Logging();
*
* const config = {
* destination: storage.bucket('logging-bucket'),
* filter: 'severity = ALERT'
* };
*
* function callback(err, sink, apiResponse) {
* // `sink` is a Sink object.
* }
*
* logging.createSink('new-sink-name', config, callback);
*
* //-
* // If the callback is omitted, we'll return a Promise.
* //-
* logging.createSink('new-sink-name', config).then(data => {
* const sink = data[0];
* const apiResponse = data[1];
* });
*
* ```
* @example <caption>include:samples/sinks.js</caption>
* region_tag:logging_create_sink
* Another example:
*/
async createSink(name, config) {
if (typeof name !== 'string') {
throw new Error('A sink name must be provided.');
}
if (typeof config !== 'object') {
throw new Error('A sink configuration object must be provided.');
}
if (common_1.util.isCustomType(config.destination, 'bigquery/dataset')) {
await this.setAclForDataset_(config);
}
if (common_1.util.isCustomType(config.destination, 'pubsub/topic')) {
await this.setAclForTopic_(config);
}
if (common_1.util.isCustomType(config.destination, 'storage/bucket')) {
await this.setAclForBucket_(config);
}
const reqOpts = {
parent: 'projects/' + this.projectId,
sink: extend({}, config, { name }),
uniqueWriterIdentity: config.uniqueWriterIdentity,
};
delete reqOpts.sink.gaxOptions;
delete reqOpts.sink.uniqueWriterIdentity;
await this.setProjectId(reqOpts);
const [resp] = await this.configService.createSink(reqOpts, config.gaxOptions);
const sink = this.sink(resp.name);
sink.metadata = resp;
return [sink, resp];
}
/**
* Create an entry object.
*
* Using this method will not itself make any API requests. You will use
* the object returned in other API calls, such as
* {@link Log#write}.
*
* Note, {@link https://cloud.google.com/logging/quotas|Cloud Logging Quotas and limits}
* dictates that the maximum log entry size, including all
* [LogEntry Resource properties]{@link https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry},
* cannot exceed _approximately_ 256 KB.
*
* See {@link https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry|LogEntry JSON representation}
*
* @param {?object|?string} [resource] See a
* [Monitored
* Resource](https://cloud.google.com/logging/docs/reference/v2/rest/v2/MonitoredResource).
* @param {object|string} data The data to use as the value for this log
* entry.
* @returns {Entry}
*
* @example
* ```
* const {Logging} = require('@google-cloud/logging');
* const logging = new Logging();
*
* const resource = {
* type: 'gce_instance',
* labels: {
* zone: 'global',
* instance_id: '3'
* }
* };
*
* const entry = logging.entry(resource, {
* delegate: 'my_username'
* });
*
* entry.toJSON();
* // {
* // resource: {
* // type: 'gce_instance',
* // labels: {
* // zone: 'global',
* // instance_id: '3'
* // }
* // },
* // jsonPayload: {
* // delegate: 'my_username'
* // }
* // }
* ```
*/
entry(resource, data) {
return new entry_1.Entry(resource, data);
}
async getEntries(opts) {
const options = opts ? opts : {};
// By default, sort entries by descending timestamp
let reqOpts = extend({ orderBy: 'timestamp desc' }, options);
// By default, filter entries to last 24 hours only
const time = new Date();
time.setDate(time.getDate() - 1);
const timeFilter = `timestamp >= "${time.toISOString()}"`;
if (!options.filter) {
reqOpts = extend({ filter: timeFilter }, reqOpts);
}
else if (!options.filter.includes('timestamp')) {
reqOpts.filter += ` AND ${timeFilter}`;
}
this.projectId = await this.auth.getProjectId();
const resourceName = 'projects/' + this.projectId;
reqOpts.resourceNames = arrify(reqOpts.resourceNames);
if (reqOpts.resourceNames.length === 0) {
// If no resource names are provided, default to the current project.
reqOpts.resourceNames.push(resourceName);
}
delete reqOpts.autoPaginate;
delete reqOpts.gaxOptions;
let gaxOptions = extend({
autoPaginate: options.autoPaginate,
}, options.gaxOptions);
if (options === null || options === void 0 ? void 0 : options.maxResults) {
gaxOptions = extend({
maxResults: options.maxResults,
}, gaxOptions);
}
const resp = await this.loggingService.listLogEntries(reqOpts, gaxOptions);
const [entries] = resp;
if (entries) {
resp[0] = entries.map(entry_1.Entry.fromApiResponse_);
}
return resp;
}
/**
* List the {@link Entry} objects in your logs as a readable object
* stream.
*
* @method Logging#getEntriesStream
* @param {GetEntriesRequest} [query] Query object for listing entries.
* @returns {ReadableStream} A readable stream that emits {@link Entry}
* instances.
*
* @example
* ```
* const {Logging} = require('@google-cloud/logging');
* const logging = new Logging();
*
* logging.getEntriesStream()
* .on('error', console.error)
* .on('data', entry => {
* // `entry` is a Cloud Logging entry object.
* // See the `data` property to read the data from the entry.
* })
* .on('end', function() {
* // All entries retrieved.
* });
*
* //-
* // If you anticipate many results, you can end a stream early to prevent
* // unnecessary processing and API requests.
* //-
* logging.getEntriesStream()
* .on('data', function(entry) {
* this.end();
* });
* ```
*/
getEntriesStream(options = {}) {
let requestStream;
const userStream = streamEvents(pumpify.obj());
userStream.abort = () => {
if (requestStream) {
requestStream.abort();
}
};
const toEntryStream = new stream_1.Transform({
objectMode: true,
transform: (chunk, encoding, callback) => {
callback(null, entry_1.Entry.fromApiResponse_(chunk));
},
});
userStream.once('reading', () => {
this.auth.getProjectId().then(projectId => {
this.projectId = projectId;
if (options.log) {
if (options.filter) {
options.filter = `(${options.filter}) AND logName="${(0, log_common_1.formatLogName)(this.projectId, options.log)}"`;
}
else {
options.filter = `logName="${(0, log_common_1.formatLogName)(this.projectId, options.log)}"`;
}
delete options.log;
}
const reqOpts = extend({
orderBy: 'timestamp desc',
}, options);
reqOpts.resourceNames = arrify(reqOpts.resourceNames);
reqOpts.resourceNames.push(`projects/${this.projectId}`);
delete reqOpts.autoPaginate;
delete reqOpts.gaxOptions;
const gaxOptions = extend({
autoPaginate: options.autoPaginate,
}, options.gaxOptions);
let gaxStream;
requestStream = streamEvents(new stream_1.PassThrough({ objectMode: true }));
requestStream.abort = () => {
if (gaxStream && gaxStream.cancel) {
gaxStream.cancel();
}
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (!global.GCLOUD_SANDBOX_ENV) {
requestStream.once('reading', () => {
try {
gaxStream = this.loggingService.listLogEntriesStream(reqOpts, gaxOptions);
}
catch (error) {
requestStream.destroy(error);
return;
}
gaxStream
.on('error', (err) => {
requestStream.destroy(err);
})
.pipe(requestStream);
return;
});
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
userStream.setPipeline(requestStream, toEntryStream);
});
});
return userStream;
}
/**
* Query object for streaming entries.
*
* @typedef {object} TailEntriesRequest
* @property {Array.<string>|string} [resourceNames] Names of project
* resources to stream logs out of.
* @property {string} [filter] An
* [advanced logs
* filter](https://cloud.google.com/logging/docs/view/advanced_filters). An
* empty filter matches all log entries.
* @property {number} [bufferWindow=2] A setting to balance the tradeoff
* between viewing the log entries as they are being written and viewing
* them in ascending order.
* @property {string} [log] A name of the log specifying to only return
* entries from this log.
* @property {object} [gaxOptions] Request configuration options, outlined
* here: https://googleapis.github.io/gax-nodejs/global.html#CallOptions.
*/
/**
* Streaming read of live logs as log entries are ingested. Until the stream
* is terminated, it will continue reading logs.
*
* @method Logging#tailEntries
* @param {TailEntriesRequest} [query] Query object for tailing entries.
* @returns {DuplexStream} A duplex stream that emits TailEntriesResponses
* containing an array of {@link Entry} instances.
*
* @example
* ```
* const {Logging} = require('@google-cloud/logging');
* const logging = new Logging();
*
* logging.tailEntries()
* .on('error', console.error)
* .on('data', resp => {
* console.log(resp.entries);
* console.log(resp.suppressionInfo);
* })
* .on('end', function() {
* // All entries retrieved.
* });
*
* //-
* // If you anticipate many results, you can end a stream early to prevent
* // unnecessary processing and API requests.
* //-
* logging.getEntriesStream()
* .on('data', function(entry) {
* this.end();
* });
* ```
*/
tailEntries(options = {}) {
const userStream = streamEvents(pumpify.obj());
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let gaxStream;
userStream.abort = () => {
if (gaxStream && gaxStream.cancel) {
gaxStream.cancel();
}
};
const transformStream = new stream_1.Transform({
objectMode: true,
transform: (chunk, encoding, callback) => {
callback(null, (() => {
const formattedEntries = [];
chunk.entries.forEach((entry) => {
formattedEntries.push(entry_1.Entry.fromApiResponse_(entry));
});
const resp = {
entries: formattedEntries,
suppressionInfo: chunk.suppressionInfo,
};
return resp;
})());
},
});
this.auth.getProjectId().then(projectId => {
this.projectId = projectId;
if (options.log) {
if (options.filter) {
options.filter = `(${options.filter}) AND logName="${(0, log_common_1.formatLogName)(this.projectId, options.log)}"`;
}
else {
options.filter = `logName="${(0, log_common_1.formatLogName)(this.projectId, options.log)}"`;
}
}
options.resourceNames = arrify(options.resourceNames);
options.resourceNames.push(`projects/${this.projectId}`);
const writeOptions = {
resourceNames: options.resourceNames,
...(options.filter && { filter: options.filter }),
...(options.bufferWindow && { bufferwindow: options.bufferWindow }),
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (!global.GCLOUD_SANDBOX_ENV) {
gaxStream = this.loggingService.tailLogEntries(options.gaxOptions);
// Write can only be called once in a single tail streaming session.
gaxStream.write(writeOptions);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
userStream.setPipeline(gaxStream, transformStream);
}
});
return userStream;
}
async getLogs(opts) {
const options = opts ? opts : {};
this.projectId = await this.auth.getProjectId();
const reqOpts = extend({}, options, {
parent: 'projects/' + this.projectId,
});
delete reqOpts.autoPaginate;
delete reqOpts.gaxOptions;
const gaxOptions = extend({
autoPaginate: options.autoPaginate,
}, options.gaxOptions);
const resp = await this.loggingService.listLogs(reqOpts, gaxOptions);
const [logs] = resp;
if (logs) {
resp[0] = logs.map((logName) => this.log(logName));
}
return resp;
}
/**
* List the {@link Log} objects in your project as a readable object stream.
*
* @method Logging#getLogsStream
* @param {GetLogsRequest} [query] Query object for listing entries.
* @returns {ReadableStream} A readable stream that emits {@link Log}
* instances.
*
* @example
* ```
* const {Logging} = require('@google-cloud/logging');
* const logging = new Logging();
*
* logging.getLogsStream()
* .on('error', console.error)
* .on('data', log => {
* // `log` is a Cloud Logging log object.
* })
* .on('end', function() {
* // All logs retrieved.
* });
*
* //-
* // If you anticipate many results, you can end a stream early to prevent
* // unnecessary processing and API requests.
* //-
* logging.getLogsStream()
* .on('data', log => {
* this.end();
* });
* ```
*/
getLogsStream(options = {}) {
options = options || {};
let requestStream;
const userStream = streamEvents(pumpify.obj());
userStream.abort = () => {
if (requestStream) {
requestStream.abort();
}
};
const toLogStream = new stream_1.Transform({
objectMode: true,
transform: (chunk, encoding, callback) => {
callback(null, this.log(chunk));
},
});
userStream.once('reading', () => {
this.auth.getProjectId().then(projectId => {
this.projectId = projectId;
const reqOpts = extend({}, options, {
parent: 'projects/' + this.projectId,
});
delete reqOpts.gaxOptions;
const gaxOptions = extend({
autoPaginate: options.autoPaginate,
}, options.gaxOptions);
let gaxStream;
requestStream = streamEvents(new stream_1.PassThrough({ objectMode: true }));
requestStream.abort = () => {
if (gaxStream && gaxStream.cancel) {
gaxStream.cancel();
}
};
requestStream.once('reading', () => {
try {
gaxStream = this.loggingService.listLogsStream(reqOpts, gaxOptions);
}
catch (error) {
requestStream.destroy(error);
return;
}
gaxStream
.on('error', (err) => {
requestStream.destroy(err);
})
.pipe(requestStream);
return;
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
userStream.setPipeline(requestStream, toLogStream);
});
});
return userStream;
}
async getSinks(opts) {
const options = opts ? opts : {};
this.projectId = await this.auth.getProjectId();
const reqOpts = extend({}, options, {
parent: 'projects/' + this.projectId,
});
delete reqOpts.autoPaginate;
delete reqOpts.gaxOptions;
const gaxOptions = extend({
autoPaginate: options.autoPaginate,
}, options.gaxOptions);
const resp = await this.configService.listSinks(reqOpts, gaxOptions);
const [sinks] = resp;
if (sinks) {
resp[0] = sinks.map((sink) => {
const sinkInstance = this.sink(sink.name);
sinkInstance.metadata = sink;
return sinkInstance;
});
}
return resp;
}
/**
* Get the {@link Sink} objects associated with this project as a
* readable object stream.
*
* @method Logging#getSinksStream
* @param {GetSinksRequest} [query] Query object for listing sinks.
* @returns {ReadableStream} A readable stream that emits {@link Sink}
* instances.
*
* @example
* ```
* const {Logging} = require('@google-cloud/logging');
* const logging = new Logging();
*
* logging.getSinksStream()
* .on('error', console.error)
* .on('data', sink => {
* // `sink` is a Sink object.
* })
* .on('end', function() {
* // All sinks retrieved.
* });
*
* //-
* // If you anticipate many results, you can end a stream early to prevent
* // unnecessary processing and API requests.
* //-
* logging.getSinksStream()
* .on('data', function(sink) {
* this.end();
* });
* ```
*/
getSinksStream(options) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const self = this;
options = options || {};
let requestStream;
const userStream = streamEvents(pumpify.obj());
userStream.abort = () => {
if (requestStream) {
requestStream.abort();
}
};
const toSinkStream = new stream_1.Transform({
objectMode: true,
transform: (chunk, encoding, callback) => {
const sinkInstance = self.sink(chunk.name);
sinkInstance.metadata = chunk;
callback(null, sinkInstance);
},
});
userStream.once('reading', () => {
this.auth.getProjectId().then(projectId => {
this.projectId = projectId;
const reqOpts = extend({}, options, {
parent: 'projects/' + self.projectId,
});
delete reqOpts.gaxOptions;
const gaxOptions = extend({
autoPaginate: options.autoPaginate,
}, options.gaxOptions);
let gaxStream;
requestStream = streamEvents(new stream_1.PassThrough({ objectMode: true }));
requestStream.abort = () => {
if (gaxStream && gaxStream.cancel) {
gaxStream.cancel();
}
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (!global.GCLOUD_SANDBOX_ENV) {
requestStream.once('reading', () => {
try {
gaxStream = this.configService.listSinksStream(reqOpts, gaxOptions);
}
catch (error) {
requestStream.destroy(error);
return;
}
gaxStream
.on('error', (err) => {
requestStream.destroy(err);
})
.pipe(requestStream);
return;
});
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
userStream.setPipeline(requestStream, toSinkStream);
});
});
return userStream;
}
/**
* Get a reference to a Cloud Logging log.
*
* See {@link https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.logs|Log Overview}
*
* @param {string} name Name of the existing log.
* @param {object} [options] Configuration object.
* @param {boolean} [options.removeCircular] Replace circular references in
* logged objects with a string value, `[Circular]`. (Default: false)
* @returns {Log}
*
* @example
* ```
* const {Logging} = require('@google-cloud/logging');
* const logging = new Logging();
* const log = logging.log('my-log');
* ```
*/
log(name, options) {
return new log_1.Log(this, name, options);
}
/**
* Get a reference to a Cloud Logging logSync.
*
* @param {string} name Name of the existing log.
* @param {object} transport An optional write stream.
* @param {LogSyncOptions} options An optional configuration object.
* @returns {LogSync}
*
* @example
* ```
* const {Logging} = require('@google-cloud/logging');
* const logging = new Logging();
*
* // Optional: enrich logs with additional context
* await logging.setProjectId();
* await logging.setDetectedResource();
*
* // Default transport writes to process.stdout
* const log = logging.logSync('my-log');
* ```
*/
logSync(name, transport, options) {
return new log_sync_1.LogSync(this, name, transport, options);
}
/**
* Get a reference to a Cloud Logging sink.
*
* See {@link https://cloud.google.com/logging/docs/reference/v2/rest/v2/projects.sinks|Sink Overview}
*
* @param {string} name Name of the existing sink.
* @returns {Sink}
*
* @example
* ```
* const {Logging} = require('@google-cloud/logging');
* const logging = new Logging();
* const sink = logging.sink('my-sink');
* ```
*/
sink(name) {
return new sink_1.Sink(this, name);
}
/**
* Funnel all API requests through this method, to be sure we have a project
* ID.
*
* @param {object} config Configuration object.
* @param {object} config.gaxOpts GAX options.
* @param {function} config.method The gax method to call.
* @param {object} config.reqOpts Request options.
* @param {function} [callback] Callback function.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
request(config, callback) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const self = this;
const isStreamMode = !callback;
let gaxStream;
let stream;
if (isStreamMode) {
stream = streamEvents(new stream_1.PassThrough({ objectMode: true }));
stream.abort = () => {
if (gaxStream && gaxStream.cancel) {
gaxStream.cancel();
}
};
stream.once('reading', makeRequestStream);
}
else {
makeRequestCallback();
}
function prepareGaxRequest(callback) {
self.auth.getProjectId((err, projectId) => {
if (err) {
callback(err);
return;
}
self.projectId = projectId;
let gaxClient = self.api[config.client];
if (!gaxClient) {
// Lazily instantiate client.
gaxClient = new v2[config.client](self.options);
self.api[config.client] = gaxClient;
}
let reqOpts = extend(true, {}, config.reqOpts);
reqOpts = (0, projectify_1.replaceProjectIdToken)(reqOpts, projectId);
const requestFn = gaxClient[config.method].bind(gaxClient, reqOpts, config.gaxOpts);
callback(null, requestFn);
});
}
function makeRequestCallback() {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (global.GCLOUD_SANDBOX_ENV) {
return;
}
prepareGaxRequest((err, requestFn) => {
if (err) {
callback(err);
return;
}
requestFn(callback);
});
}
function makeRequestStream() {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (global.GCLOUD_SANDBOX_ENV) {
return new stream_1.PassThrough({ objectMode: true });
}
prepareGaxRequest((err, requestFn) => {
if (err) {
stream.destroy(err);
return;
}
gaxStream = requestFn();
gaxStream
.on('error', (err) => {
stream.destroy(err);
})
.pipe(stream);
});
return;
}
return stream;
}
/**
* This method is called when creating a sink with a Bucket destination. The
* bucket must first grant proper ACL access to the Cloud Logging
* account.
*
* The parameters are the same as what {@link Logging#createSink} accepts.
*
* @private
*/
async setAclForBucket_(config) {
const bucket = config.destination;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
await bucket.acl.owners.addGroup('cloud-logs@google.com');
config.destination = 'storage.googleapis.com/' + bucket.name;
}
/**
* This method is called when creating a sink with a Dataset destination. The
* dataset must first grant proper ACL access to the Cloud Logging
* account.
*
* The parameters are the same as what {@link Logging#createSink} accepts.
*
* @private
*/
async setAclForDataset_(config) {
const dataset = config.destination;
const [metadata] = await dataset.getMetadata();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const access = [].slice.call(arrify(metadata.access));
access.push({
role: 'WRITER',
groupByEmail: 'cloud-logs@google.com',
});
await dataset.setMetadata({
access,
});
const baseUrl = 'bigquery.googleapis.com';
const pId = dataset.parent.projectId;
const dId = dataset.id;
config.destination = `${baseUrl}/projects/${pId}/datasets/${dId}`;
}
/**
* This method is called when creating a sink with a Topic destination. The
* topic must first grant proper ACL access to the Cloud Logging
* account.
*
* The parameters are the same as what {@link Logging#createSink} accepts.
*
* @private
*/
async setAclForTopic_(config) {
const topic = config.destination;
const [policy] = await topic.iam.getPolicy();
policy.bindings = arrify(policy.bindings);
policy.bindings.push({
role: 'roles/pubsub.publisher',
members: ['serviceAccount:cloud-logs@system.gserviceaccount.com'],
});
await topic.iam.setPolicy(policy);
const baseUrl = 'pubsub.googleapis.com';
const topicName = topic.name;
config.destination = `${baseUrl}/${topicName}`;
}
/**
* setProjectId detects and sets a projectId string on the Logging instance.
* It can be invoked once to ensure ensuing LogSync entries have a projectID.
* @param reqOpts
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async setProjectId(reqOpts) {
if (this.projectId === '{{projectId}}')
this.projectId = await this.auth.getProjectId();
if (reqOpts)
reqOpts = (0, projectify_1.replaceProjectIdToken)(reqOpts, this.projectId);
}
/**
* setResource detects and sets a detectedresource object on the Logging
* instance. It can be invoked once to ensure ensuing LogSync entries contain
* resource context.
*/
async setDetectedResource() {
if (!this.detectedResource) {
this.detectedResource = await (0, metadata_1.getDefaultResource)(this.auth);
}
}
}
exports.Logging = Logging;
/*! Developer Documentation
* All async methods (except for streams) will execute a callback in the event
* that a callback is provided.
*/
(0, promisify_1.callbackifyAll)(Logging, {
exclude: ['request'],
});
/*! Developer Documentation
*
* These methods can be auto-paginated.
*/
paginator_1.paginator.extend(Logging, ['getEntries', 'getLogs', 'getSinks']);
/**
* Reference to the low-level auto-generated clients for the V2 Logging service.
*
* @type {object}
* @property {constructor} LoggingServiceV2Client
* Reference to {@link v2.LoggingServiceV2Client}
* @property {constructor} ConfigServiceV2Client
* Reference to {@link v2.ConfigServiceV2Client}
* @property {constructor} MetricsServiceV2Client
* Reference to {@link v2.MetricsServiceV2Client}
*/
module.exports.v2 = v2;
__exportStar(require("@opentelemetry/api"), exports);
//# sourceMappingURL=index.js.map