UNPKG

@yachteye/signalk-engineroom-plugin

Version:

Get EngineRoom data from the source (database or other) and add it to the SignalK graph.

199 lines (198 loc) 7.53 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()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.init = init; exports.log = log; exports.logTelemetry = logTelemetry; exports.shutdown = shutdown; const client_cloudwatch_logs_1 = require("@aws-sdk/client-cloudwatch-logs"); const BUFFER_MAX = 10000; const CW_MAX_BATCH_EVENTS = 10000; const CW_MAX_BATCH_BYTES = 1048576; // 1 MB const CW_EVENT_OVERHEAD = 26; let client = null; let buffer = []; let flushTimer = null; let enabledLevels = new Set(); let excludedPaths = new Set(); let telemetryMode = 'full'; let lastTelemetrySnapshot = {}; let logGroupName = ''; let logStreamName = ''; let debugFn = () => { }; function init(settings, debug) { return __awaiter(this, void 0, void 0, function* () { debugFn = debug; try { const clientConfig = { region: settings.cloudwatchRegion, }; if (settings.cloudwatchAccessKeyId && settings.cloudwatchSecretAccessKey) { clientConfig.credentials = { accessKeyId: settings.cloudwatchAccessKeyId, secretAccessKey: settings.cloudwatchSecretAccessKey, }; } client = new client_cloudwatch_logs_1.CloudWatchLogsClient(clientConfig); logGroupName = settings.cloudwatchLogGroupName; logStreamName = settings.cloudwatchLogStreamName; enabledLevels = new Set(settings.cloudwatchLogLevels); excludedPaths = new Set(settings.cloudwatchExcludedPaths); telemetryMode = settings.cloudwatchTelemetryMode; try { yield client.send(new client_cloudwatch_logs_1.CreateLogGroupCommand({ logGroupName })); } catch (err) { if (err.name !== 'ResourceAlreadyExistsException') { debugFn(`[CloudWatch] Failed to create log group '${logGroupName}': ${err.message}`); client = null; return; } } try { yield client.send(new client_cloudwatch_logs_1.CreateLogStreamCommand({ logGroupName, logStreamName })); } catch (err) { if (err.name !== 'ResourceAlreadyExistsException') { debugFn(`[CloudWatch] Failed to create log stream '${logStreamName}': ${err.message}`); client = null; return; } } flushTimer = setInterval(() => { flush().catch((err) => debugFn(`[CloudWatch] flush() unexpected error: ${err === null || err === void 0 ? void 0 : err.message}`)); }, settings.cloudwatchFlushInterval * 1000); debugFn(`[CloudWatch] Initialized: group=${logGroupName}, stream=${logStreamName}, flush=${settings.cloudwatchFlushInterval}s, levels=${[...enabledLevels].join(',')}`); } catch (err) { debugFn(`[CloudWatch] init() failed: ${err.message}`); client = null; } }); } function log(level, message, data) { try { if (client === null) return; if (!enabledLevels.has(level)) return; if (buffer.length >= BUFFER_MAX) { debugFn(`[CloudWatch] Buffer full (${BUFFER_MAX}), dropping log entry`); return; } buffer.push({ timestamp: Date.now(), level, message, data, }); } catch (err) { debugFn(`[CloudWatch] log() error: ${err.message}`); } } function logTelemetry(data) { try { if (client === null) return; const filtered = {}; for (const key of Object.keys(data)) { if (!excludedPaths.has(key)) { filtered[key] = data[key]; } } if (telemetryMode === 'changes') { const changed = {}; for (const key of Object.keys(filtered)) { if (filtered[key] !== lastTelemetrySnapshot[key]) { changed[key] = filtered[key]; } } lastTelemetrySnapshot = Object.assign({}, filtered); if (Object.keys(changed).length === 0) return; log('info', 'telemetry', changed); } else { if (Object.keys(filtered).length === 0) return; log('info', 'telemetry', filtered); } } catch (err) { debugFn(`[CloudWatch] logTelemetry() error: ${err.message}`); } } function flush() { return __awaiter(this, void 0, void 0, function* () { if (client === null || buffer.length === 0) return; const entries = buffer; buffer = []; const serialized = entries.map((entry) => ({ timestamp: entry.timestamp, message: JSON.stringify({ level: entry.level, message: entry.message, data: entry.data }), })); const batches = []; let currentBatch = []; let currentBatchBytes = 0; for (const event of serialized) { const eventBytes = Buffer.byteLength(event.message, 'utf8') + CW_EVENT_OVERHEAD; if (currentBatch.length >= CW_MAX_BATCH_EVENTS || currentBatchBytes + eventBytes > CW_MAX_BATCH_BYTES) { if (currentBatch.length > 0) { batches.push(currentBatch); } currentBatch = []; currentBatchBytes = 0; } currentBatch.push(event); currentBatchBytes += eventBytes; } if (currentBatch.length > 0) { batches.push(currentBatch); } for (const batch of batches) { try { const logEvents = batch; yield client.send(new client_cloudwatch_logs_1.PutLogEventsCommand({ logGroupName, logStreamName, logEvents, })); } catch (err) { debugFn(`[CloudWatch] flush() failed for batch of ${batch.length} events: ${err.message}`); } } }); } function shutdown() { return __awaiter(this, void 0, void 0, function* () { try { if (flushTimer !== null) { clearInterval(flushTimer); flushTimer = null; } yield flush(); if (client !== null) { client.destroy(); client = null; } buffer = []; lastTelemetrySnapshot = {}; enabledLevels = new Set(); excludedPaths = new Set(); } catch (err) { debugFn(`[CloudWatch] shutdown() error: ${err.message}`); } }); }