UNPKG

hypertune

Version:

[Hypertune](https://www.hypertune.com/) is the most flexible platform for feature flags, A/B testing, analytics and app configuration. Built with full end-to-end type-safety, Git-style version control and local, synchronous, in-memory flag evaluation. Opt

170 lines 8.52 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const shared_1 = require("../shared"); const RemoteLogger_1 = __importDefault(require("../shared/helpers/RemoteLogger")); const LRUCache_1 = __importDefault(require("../shared/helpers/LRUCache")); const getNodeCacheKey_1 = __importDefault(require("./getNodeCacheKey")); const newTracedFetch_1 = __importDefault(require("../shared/helpers/newTracedFetch")); const fetchMaxKeepAliveRequestSizeBytes = 64000; /** * Logger provides a high level API for Node and generic SDK logs. It emits * these logs using the `localLogger` and it also forwards them to the * `remoteLogger` based on the provided `remoteLoggingMode`. */ class Logger { constructor({ id, traceId, token, remoteLoggingMode, remoteFlushIntervalMs, remoteLoggingEndpointUrl, localLogger, logsHandler, }) { this.remoteLogCache = new LRUCache_1.default(10000); this.id = id; this.remoteLoggingMode = remoteLoggingMode; this.logsHandler = logsHandler; this.localLogger = localLogger; this.remoteLogger = remoteLoggingMode === "off" ? null : new RemoteLogger_1.default({ traceId, token, createLogs: getCreateLogsFunction((0, newTracedFetch_1.default)({ timeoutMs: 20000, localLogger: this.localLogger, }), remoteLoggingEndpointUrl), localLogger: this.localLogger, flushIntervalMs: remoteFlushIntervalMs, }); if (remoteLoggingMode === "off") { this.localLogger(shared_1.LogLevel.Info, "Remote logging is disabled.", { traceId, }); } } nodeLog({ commitId, initDataHash, nodeTypeName, nodePath, nodeExpression, reductionLogs, }) { var _a, _b, _c, _d, _e, _f, _g, _h, _j; const baseLogMetadata = { sdkVersion: shared_1.sdkVersion, nodeTypeName, nodePath, nodeExpression, reductionLogs, }; this.logsHandler({ messageList: (_a = reductionLogs.messageList) !== null && _a !== void 0 ? _a : [], eventList: (_b = reductionLogs.eventList) !== null && _b !== void 0 ? _b : [], exposureList: (_c = reductionLogs.exposureList) !== null && _c !== void 0 ? _c : [], evaluationList: (_d = reductionLogs.evaluationList) !== null && _d !== void 0 ? _d : [], }); (_e = reductionLogs.messageList) === null || _e === void 0 ? void 0 : _e.forEach(({ level, message, metadata }) => { var _a; const logMessage = `${nodeTypeName}Node at ${nodePath}: ${message}`; const logMetadata = Object.assign(Object.assign({}, baseLogMetadata), metadata); if ((level === shared_1.LogLevel.Warn || level === shared_1.LogLevel.Error) && this.shouldRemoteNodeLog(initDataHash, nodePath, message)) { (_a = this.remoteLogger) === null || _a === void 0 ? void 0 : _a.log(shared_1.LogType.SdkNode, level, commitId, logMessage, logMetadata); } }); if (reductionLogs && (reductionLogs.evaluations || reductionLogs.eventList || reductionLogs.exposureList)) { if (!commitId) { const errorMessage = `${nodeTypeName}Node at ${nodePath}: Missing commitId so cannot remote log evaluations, events and exposures.`; this.localLogger(shared_1.LogLevel.Error, errorMessage, baseLogMetadata); if (this.shouldRemoteNodeLog(initDataHash, nodePath, errorMessage)) { (_f = this.remoteLogger) === null || _f === void 0 ? void 0 : _f.log(shared_1.LogType.SdkNode, shared_1.LogLevel.Error, commitId, errorMessage, baseLogMetadata); } return; } if (reductionLogs.evaluations && this.shouldRemoteNodeLog(initDataHash, nodePath, "evaluations")) { (_g = this.remoteLogger) === null || _g === void 0 ? void 0 : _g.evaluations(commitId, reductionLogs.evaluations); } if (reductionLogs.eventList) { // We always log events to the backend (_h = this.remoteLogger) === null || _h === void 0 ? void 0 : _h.events(commitId, reductionLogs.eventList); } if (reductionLogs.exposureList && this.shouldRemoteNodeLog(initDataHash, nodePath, "exposures")) { (_j = this.remoteLogger) === null || _j === void 0 ? void 0 : _j.exposures(commitId, reductionLogs.exposureList); } } } shouldRemoteNodeLog(initDataHash, nodePath, cacheKeySuffix) { switch (this.remoteLoggingMode) { case "session": { const cacheKey = (0, getNodeCacheKey_1.default)(initDataHash !== null && initDataHash !== void 0 ? initDataHash : "", nodePath, cacheKeySuffix); if (this.remoteLogCache.get(cacheKey)) { this.localLogger(shared_1.LogLevel.Debug, `Remote log cache hit.`, /* metadata */ { initDataHash, nodePath, cacheKeySuffix }); return false; } this.remoteLogCache.set(cacheKey, true); return true; } case "normal": { return true; } case "off": { return false; } default: { const neverLoggingMode = this.remoteLoggingMode; throw new Error(`Unexpected logging mode: ${neverLoggingMode}`); } } } log(level, commitId, message, metadata) { var _a; this.localLogger(level, message, metadata); if (this.remoteLoggingMode !== "off" && (level === shared_1.LogLevel.Warn || level === shared_1.LogLevel.Error)) { (_a = this.remoteLogger) === null || _a === void 0 ? void 0 : _a.log(shared_1.LogType.SdkMessage, level, commitId, message, Object.assign(Object.assign({}, metadata), { sdkVersion: shared_1.sdkVersion })); } } flush(traceId) { return this.remoteLogger ? this.remoteLogger.flush(traceId) : Promise.resolve(); } close(traceId) { return this.remoteLogger ? this.remoteLogger.close(traceId) : Promise.resolve(); } } exports.default = Logger; function getCreateLogsFunction(tracedFetch, logsUrl) { return (traceId, input) => __awaiter(this, void 0, void 0, function* () { const bodyJson = JSON.stringify(input); const bodyBlob = new Blob([bodyJson]); const response = yield tracedFetch(traceId, logsUrl, { method: "POST", headers: { "Content-Type": "application/json", "Cache-Control": "no-store", }, body: bodyJson, // Only use keepalive if the request is smaller than the maximum // allowed size with keepalive enabled. keepalive: bodyBlob.size < fetchMaxKeepAliveRequestSizeBytes, }); if (!response.ok) { throw new Error(`Failed to create logs status: "${response.status}" response: "${yield response.text()}"`); } const data = yield response.json(); if (!data.success) { throw new Error(`Failed to create logs status: "${response.status}" response: "${JSON.stringify(data)}"`); } }); } //# sourceMappingURL=Logger.js.map