@atomist/skill-logging
Version:
Atomist Skill Logging API
160 lines • 6.03 kB
JavaScript
;
/*
* Copyright © 2022 Atomist, Inc.
*
* 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.createLogger = createLogger;
exports.chunk = chunk;
exports.instanceId = instanceId;
const logging_1 = require("@google-cloud/logging");
const Queue = require("better-queue");
const metadata = require("gcp-metadata");
const os = require("os");
const util = require("util");
const middleware_1 = require("./middleware");
/**
* Create an instance of Logger from the current GCF context object
* @param context the context parameter passed into the GCF handler entry point
* @param labels additional labels to be added to the audit log
*/
function createLogger(context, labels = {}, name = "skills_logging", project) {
if (!context ||
!context.correlationId ||
!context.workspaceId ||
!context.skillId) {
throw new Error(`Provided context is missing correlationId, workspaceId, skillId: ${JSON.stringify(context)}`);
}
const logging = new logging_1.Logging({
projectId: project,
});
const log = logging.log(name);
let skipGl = false;
// eslint-disable-next-line @typescript-eslint/no-var-requires
const Store = require("better-queue-memory");
const logQueue = new Queue({
store: new Store(),
process: async (entries, cb) => {
const gl = async (cb, fcb) => {
if (skipGl) {
fcb();
}
else {
// Allow to write through to the console if requested
if (process.env.ATOMIST_CONSOLE_LOG) {
fcb();
}
try {
await cb();
}
catch (e) {
if (e.message.startsWith("Unable to detect a Project Id in the current environment.")) {
fcb();
skipGl = true;
}
}
}
};
const id = await instanceId();
const filteredEntries = entries.filter(e => e.metadata.severity !== "EXIT");
filteredEntries.forEach(e => (e.metadata.labels.instance_id = id));
await gl(() => log.write(filteredEntries), () => {
filteredEntries.forEach(e => console.log(`${severityToPrefix(e.metadata.severity.toString())}${e.data}`));
});
cb();
},
concurrent: 1,
batchSize: 10,
});
logQueue.resume();
let closing = false;
let started = false;
const drained = new Promise(resolve => {
logQueue.on("drain", () => {
if (closing) {
resolve();
}
});
});
const queueLog = (msg, severity, ...parameters) => {
started = true;
const traceIds = (0, middleware_1.getTraceIds)();
const traceId = context.traceId || (traceIds === null || traceIds === void 0 ? void 0 : traceIds.traceId);
const metadata = {
labels: Object.assign(Object.assign({}, labels), { event_id: context.eventId, correlation_id: context.correlationId, workspace_id: context.workspaceId, skill_id: context.skillId, execution_id: traceIds === null || traceIds === void 0 ? void 0 : traceIds.executionId, trace_id: traceId ? traceId.split("/")[0] : undefined, host: os.hostname() === "localhost" ? undefined : os.hostname() }),
resource: {
type: "global",
},
severity: severity.toUpperCase(),
timestamp: new Date(),
};
chunk(util.format(msg, ...parameters)).forEach(c => {
const entry = log.entry(metadata, c);
if (!c) {
entry.metadata = Object.assign(Object.assign({}, entry.metadata), entry.data);
entry.data = c;
}
logQueue.push(entry);
});
};
return {
debug: (msg, ...parameters) => queueLog(msg, "DEBUG", ...parameters),
info: (msg, ...parameters) => queueLog(msg, "INFO", ...parameters),
warn: (msg, ...parameters) => queueLog(msg, "WARNING", ...parameters),
error: (msg, ...parameters) => queueLog(msg, "ERROR", ...parameters),
close: async () => {
if (!started) {
return Promise.resolve();
}
closing = true;
queueLog("", "EXIT");
(0, middleware_1.clearTraceIds)();
return drained;
},
};
}
function severityToPrefix(severity) {
switch (severity) {
case "DEBUG":
return "[debug] ";
case "INFO":
return " [info] ";
case "WARNING":
return " [warn] ";
case "ERROR":
return "[error] ";
}
return "";
}
function chunk(s, maxBytes = 256000) {
if (!s || Buffer.byteLength(s) <= maxBytes) {
return [s];
}
// eslint-disable-next-line @typescript-eslint/no-var-requires
const chunk = require("chunk-text");
return chunk(s, maxBytes, { charLengthMask: 0 });
}
let InstanceId;
async function instanceId() {
if (!InstanceId) {
try {
InstanceId = await metadata.instance("id");
}
catch (e) {
InstanceId = "<invalid>";
}
}
return InstanceId !== "<invalid>" ? InstanceId : undefined;
}
//# sourceMappingURL=logging.js.map