@google-cloud/logging
Version:
Cloud Logging Client Library for Node.js
203 lines • 9.52 kB
JavaScript
;
/*!
* Copyright 2022 Google LLC
*
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.MAX_INSTRUMENTATION_COUNT = exports.NODEJS_DEFAULT_LIBRARY_VERSION = exports.NODEJS_LIBRARY_NAME_PREFIX = exports.INSTRUMENTATION_SOURCE_KEY = exports.DIAGNOSTIC_INFO_KEY = void 0;
exports.populateInstrumentationInfo = populateInstrumentationInfo;
exports.createDiagnosticEntry = createDiagnosticEntry;
exports.getNodejsLibraryVersion = getNodejsLibraryVersion;
exports.setInstrumentationStatus = setInstrumentationStatus;
const arrify = require("arrify");
const entry_1 = require("../entry");
// The global variable keeping track if instrumentation record was already written or not.
// The instrumentation record should be generated only once per process and contain logging
// libraries related info.
global.instrumentationAdded = false;
// The global variable to avoid records inspection once instrumentation already written to prevent perf impact
global.shouldSkipInstrumentationCheck = false;
// Max length for instrumentation library name and version values
const maxDiagnosticValueLen = 14;
exports.DIAGNOSTIC_INFO_KEY = 'logging.googleapis.com/diagnostic';
exports.INSTRUMENTATION_SOURCE_KEY = 'instrumentation_source';
exports.NODEJS_LIBRARY_NAME_PREFIX = 'nodejs';
/**
* Default library version to be used
* Using release-please annotations to update DEFAULT_INSTRUMENTATION_VERSION with latest version.
* See https://github.com/googleapis/release-please/blob/main/docs/customizing.md#updating-arbitrary-files
*/
exports.NODEJS_DEFAULT_LIBRARY_VERSION = '11.2.1'; // {x-release-please-version}
exports.MAX_INSTRUMENTATION_COUNT = 3;
/**
* This method helps to populate entries with instrumentation data
* @param entry {Entry} The entry or array of entries to be populated with instrumentation info
* @returns [Entry[], boolean] Array of entries which contains an entry with current library
* instrumentation info and boolean flag indicating if instrumentation was added or not in this call
*/
function populateInstrumentationInfo(entry) {
var _a, _b;
// Check if instrumentation data was already written once. This prevents also inspection of
// the entries for instrumentation data to prevent perf degradation
if (global.shouldSkipInstrumentationCheck) {
return [arrify(entry), false];
}
// Update the flag indicating that instrumentation entry was already added once,
// so any subsequent calls to this method will not add a separate instrumentation log entry
let isWritten = setInstrumentationStatus(true);
// Flag keeping track if this specific call added any instrumentation info
let isInfoAdded = false;
const entries = [];
if (entry) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
for (const entryItem of arrify(entry)) {
if (entryItem) {
const info = (_b = (_a = entryItem.data) === null || _a === void 0 ? void 0 : _a[exports.DIAGNOSTIC_INFO_KEY]) === null || _b === void 0 ? void 0 : _b[exports.INSTRUMENTATION_SOURCE_KEY];
if (info) {
// Validate and update the instrumentation info with current library info
entryItem.data[exports.DIAGNOSTIC_INFO_KEY][exports.INSTRUMENTATION_SOURCE_KEY] =
validateAndUpdateInstrumentation(info);
// Indicate that instrumentation info log entry already exists
// and that current library info was added to existing log entry
global.shouldSkipInstrumentationCheck =
isInfoAdded =
isWritten =
true;
}
entries.push(entryItem);
}
}
}
// If no instrumentation info was added before, append a separate log entry with
// instrumentation data for this library
if (!isWritten) {
entries.push(createDiagnosticEntry(undefined, undefined));
global.shouldSkipInstrumentationCheck = isInfoAdded = true;
}
return [entries, isInfoAdded];
}
/**
* The helper method to generate a log entry with diagnostic instrumentation data.
* @param libraryName {string} The name of the logging library to be reported. Should be prefixed with 'nodejs'.
* Will be truncated if longer than 14 characters.
* @param libraryVersion {string} The version of the logging library to be reported. Will be truncated if longer than 14 characters.
* @returns {Entry} The entry with diagnostic instrumentation data.
*/
function createDiagnosticEntry(libraryName, libraryVersion) {
// Validate the libraryName first and make sure it starts with 'nodejs' prefix.
if (!libraryName || !libraryName.startsWith(exports.NODEJS_LIBRARY_NAME_PREFIX)) {
libraryName = exports.NODEJS_LIBRARY_NAME_PREFIX;
}
const entry = new entry_1.Entry(undefined, {
[exports.DIAGNOSTIC_INFO_KEY]: {
[exports.INSTRUMENTATION_SOURCE_KEY]: [
{
// Truncate libraryName and libraryVersion if more than 14 characters length
name: truncateValue(libraryName, maxDiagnosticValueLen),
version: truncateValue(libraryVersion !== null && libraryVersion !== void 0 ? libraryVersion : getNodejsLibraryVersion(), maxDiagnosticValueLen),
},
],
},
});
return entry;
}
/**
* This method validates that provided instrumentation info list is valid and also adds current library info to a list.
* @param infoList {InstrumentationInfo} The array of InstrumentationInfo to be validated and updated.
* @returns {InstrumentationInfo} The updated list of InstrumentationInfo.
*/
function validateAndUpdateInstrumentation(infoList) {
const finalInfo = [];
// First, iterate through given list of libraries and for each entry perform validations and transformations.
// Limit amount of entries to be up to MAX_INSTRUMENTATION_COUNT
let count = 1;
for (const info of infoList) {
if (isValidInfo(info)) {
finalInfo.push({
name: truncateValue(info.name, maxDiagnosticValueLen),
version: truncateValue(info.version, maxDiagnosticValueLen),
});
if (++count === exports.MAX_INSTRUMENTATION_COUNT)
break;
}
}
// Finally, add current library information to be the last entry added
finalInfo.push({
name: exports.NODEJS_LIBRARY_NAME_PREFIX,
version: getNodejsLibraryVersion(),
});
return finalInfo;
}
/**
* A helper function to truncate a value (library name or version for example). The value is truncated
* when it is longer than {maxLen} chars and '*' is added instead of truncated suffix.
* @param value {object|string} The value to be truncated.
* @param maxLen {number} The max length to be used for truncation.
* @returns {string} The truncated value.
*/
function truncateValue(value, maxLen) {
// Currently there are cases when we get here JSON object instead of string
// Adding here additional validation to see if version still can be retrieved
if (typeof value !== 'string') {
try {
if (Object.prototype.hasOwnProperty.call(value, 'version')) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
value = value.version;
}
}
catch (err) {
// Ignore error since flow should continue
}
}
// Return NODEJS_DEFAULT_LIBRARY_VERSION if version cannot be retrieved
if (typeof value !== 'string') {
return exports.NODEJS_DEFAULT_LIBRARY_VERSION;
}
if (value && value.length > maxLen) {
return value.substring(0, maxLen).concat('*');
}
return value;
}
/**
* The helper function to retrieve current library version from annotated NODEJS_DEFAULT_LIBRARY_VERSION
* @returns {string} A current library version.
*/
function getNodejsLibraryVersion() {
return exports.NODEJS_DEFAULT_LIBRARY_VERSION;
}
/**
* The helper function which checks if given InstrumentationInfo is valid.
* @param info {InstrumentationInfo} The info to be validated.
* @returns true if given info is valid, false otherwise
*/
function isValidInfo(info) {
if (!info ||
!info.name ||
!info.version ||
!info.name.startsWith(exports.NODEJS_LIBRARY_NAME_PREFIX)) {
return false;
}
return true;
}
/**
* The helper method used to set a status of a flag which indicates if instrumentation info already written or not.
* @param value {boolean} The value to be set.
* @returns The value of the flag before it is set.
*/
function setInstrumentationStatus(value) {
const status = global.instrumentationAdded;
global.instrumentationAdded = value;
return status;
}
//# sourceMappingURL=instrumentation.js.map