revenium-middleware-litellm-node
Version:
Comprehensive middleware for Node.js applications using LiteLLM Proxy to automatically track LLM usage, costs, and performance metrics with Revenium
284 lines • 9.87 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.defaultLogger = void 0;
exports.loadConfigFromEnv = loadConfigFromEnv;
exports.validateConfig = validateConfig;
exports.getConfig = getConfig;
exports.setConfig = setConfig;
exports.getLogger = getLogger;
exports.setLogger = setLogger;
exports.resetConfig = resetConfig;
exports.resetConfigManager = resetConfigManager;
exports.initializeConfig = initializeConfig;
const logger_types_1 = require("./utils/logger-types");
const validation_1 = require("./utils/validation");
/**
* Type-safe console logger implementation
*/
class TypeSafeConsoleLogger {
getLogLevel() {
const envLevel = process.env.REVENIUM_LOG_LEVEL?.toUpperCase();
if (envLevel && Object.values(logger_types_1.LogLevel).includes(envLevel))
return envLevel;
return process.env.REVENIUM_DEBUG === 'true' ? logger_types_1.LogLevel.DEBUG : logger_types_1.LogLevel.INFO;
}
formatMessage(level, message, context) {
const timestamp = (0, logger_types_1.createTimestamp)();
const prefix = `[Revenium LiteLLM${level === logger_types_1.LogLevel.DEBUG ? ' Debug' : level === logger_types_1.LogLevel.WARNING ? ' Warning' : level === logger_types_1.LogLevel.ERROR ? ' Error' : ''}]`;
const contextStr = (0, logger_types_1.formatLogContext)(context, false);
return `${timestamp} ${prefix} ${message}${contextStr}`;
}
debug(message, context) {
if ((0, logger_types_1.shouldLog)(logger_types_1.LogLevel.DEBUG, this.getLogLevel())) {
console.debug(this.formatMessage(logger_types_1.LogLevel.DEBUG, message, context));
}
}
info(message, context) {
if ((0, logger_types_1.shouldLog)(logger_types_1.LogLevel.INFO, this.getLogLevel())) {
console.info(this.formatMessage(logger_types_1.LogLevel.INFO, message, context));
}
}
warn(message, context) {
if ((0, logger_types_1.shouldLog)(logger_types_1.LogLevel.WARNING, this.getLogLevel())) {
console.warn(this.formatMessage(logger_types_1.LogLevel.WARNING, message, context));
}
}
error(message, context) {
if ((0, logger_types_1.shouldLog)(logger_types_1.LogLevel.ERROR, this.getLogLevel())) {
console.error(this.formatMessage(logger_types_1.LogLevel.ERROR, message, context));
}
}
}
/**
* Legacy logger adapter for backward compatibility
*/
class LegacyLoggerAdapter {
constructor() {
this.typeSafeLogger = new TypeSafeConsoleLogger();
}
debug(message, ...args) {
// Convert legacy args to context - sanitize unknown data
const context = args.length > 0 ? {
legacyArgs: args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : String(arg))
} : {};
this.typeSafeLogger.debug(message, context);
}
info(message, ...args) {
const context = args.length > 0 ? {
legacyArgs: args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : String(arg))
} : {};
this.typeSafeLogger.info(message, context);
}
warn(message, ...args) {
const context = args.length > 0 ? {
legacyArgs: args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : String(arg))
} : {};
this.typeSafeLogger.warn(message, context);
}
error(message, ...args) {
const context = args.length > 0 ? {
legacyArgs: args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : String(arg))
} : {};
this.typeSafeLogger.error(message, context);
}
}
/**
* Default console logger implementation
*/
exports.defaultLogger = new LegacyLoggerAdapter();
/**
* Load configuration from environment variables
*/
function loadConfigFromEnv() {
const reveniumMeteringApiKey = process.env.REVENIUM_METERING_API_KEY;
const reveniumMeteringBaseUrl = process.env.REVENIUM_METERING_BASE_URL || 'https://api.revenium.io/meter';
const litellmProxyUrl = process.env.LITELLM_PROXY_URL;
const litellmApiKey = process.env.LITELLM_API_KEY;
const organizationId = process.env.REVENIUM_ORGANIZATION_ID;
const apiTimeout = process.env.REVENIUM_API_TIMEOUT ? parseInt(process.env.REVENIUM_API_TIMEOUT, 10) : undefined;
const failSilent = process.env.REVENIUM_FAIL_SILENT !== 'false'; // Default to true
const maxRetries = process.env.REVENIUM_MAX_RETRIES ? parseInt(process.env.REVENIUM_MAX_RETRIES, 10) : undefined;
if (!reveniumMeteringApiKey || !litellmProxyUrl)
return null;
return {
reveniumMeteringApiKey,
reveniumMeteringBaseUrl,
litellmProxyUrl,
litellmApiKey,
organizationId,
apiTimeout,
failSilent,
maxRetries
};
}
/**
* Validate Revenium configuration with enhanced error reporting
*/
function validateConfig(config) {
const validation = (0, validation_1.validateReveniumConfig)(config);
if (!validation.isValid) {
// Log detailed validation errors
getLogger().error('Configuration validation failed', {
errors: validation.errors,
warnings: validation.warnings,
suggestions: validation.suggestions
});
// Create detailed error message
let errorMessage = 'Configuration validation failed:\n';
validation.errors.forEach((error, index) => {
errorMessage += ` ${index + 1}. ${error}\n`;
});
if (validation.suggestions && validation.suggestions.length > 0) {
errorMessage += '\nSuggestions:\n';
validation.suggestions.forEach((suggestion, index) => {
errorMessage += ` • ${suggestion}\n`;
});
}
throw new Error(errorMessage.trim());
}
// Log warnings if any
if (validation.warnings && validation.warnings.length > 0) {
getLogger().warn('Configuration warnings', {
warnings: validation.warnings
});
}
}
/**
* Configuration manager singleton for proper state management
*/
class ConfigurationManager {
constructor() {
this.config = null;
this.logger = exports.defaultLogger;
// Private constructor to enforce singleton pattern
}
/**
* Get the singleton instance
*/
static getInstance() {
if (!ConfigurationManager.instance)
ConfigurationManager.instance = new ConfigurationManager();
return ConfigurationManager.instance;
}
/**
* Reset the singleton instance (for testing)
*/
static resetInstance() {
ConfigurationManager.instance = null;
}
/**
* Get the current configuration
*/
getConfig() {
return this.config;
}
/**
* Set the configuration
*/
setConfig(config) {
validateConfig(config);
this.config = config;
this.logger.debug('Revenium LiteLLM configuration updated', {
reveniumMeteringBaseUrl: config.reveniumMeteringBaseUrl,
litellmProxyUrl: config.litellmProxyUrl,
hasApiKey: !!config.reveniumMeteringApiKey,
hasProxyKey: !!config.litellmApiKey,
organizationId: config.organizationId,
apiTimeout: config.apiTimeout || 5000,
failSilent: config.failSilent !== false,
maxRetries: config.maxRetries || 3
});
}
/**
* Get the current logger
*/
getLogger() {
return this.logger;
}
/**
* Set a custom logger
*/
setLogger(logger) {
this.logger = logger;
this.logger.debug('Custom logger set for Revenium LiteLLM middleware');
}
/**
* Reset configuration and logger to defaults (for testing)
*/
reset() {
this.config = null;
this.logger = exports.defaultLogger;
}
/**
* Check if configuration is valid and complete
*/
isConfigured() {
return this.config !== null;
}
}
ConfigurationManager.instance = null;
/**
* Get the current global configuration
*/
function getConfig() {
return ConfigurationManager.getInstance().getConfig();
}
/**
* Set the global configuration
*/
function setConfig(config) {
ConfigurationManager.getInstance().setConfig(config);
}
/**
* Get the current logger
*/
function getLogger() {
return ConfigurationManager.getInstance().getLogger();
}
/**
* Set a custom logger
*/
function setLogger(logger) {
ConfigurationManager.getInstance().setLogger(logger);
}
/**
* Reset configuration manager (for testing)
*/
function resetConfig() {
ConfigurationManager.getInstance().reset();
}
/**
* Reset the entire configuration manager instance (for testing)
*/
function resetConfigManager() {
ConfigurationManager.resetInstance();
}
/**
* Initialize configuration from environment variables
*/
function initializeConfig() {
const envConfig = loadConfigFromEnv();
if (envConfig) {
try {
setConfig(envConfig);
getLogger().debug('Revenium LiteLLM middleware initialized from environment variables');
return true;
}
catch (error) {
getLogger().error('Failed to initialize Revenium LiteLLM configuration:', error);
return false;
}
}
// Log what's missing for easier debugging
const missing = [];
if (!process.env.REVENIUM_METERING_API_KEY)
missing.push('REVENIUM_METERING_API_KEY');
if (!process.env.LITELLM_PROXY_URL)
missing.push('LITELLM_PROXY_URL');
if (missing.length > 0) {
getLogger().warn(`Revenium LiteLLM middleware not initialized. Missing environment variables: ${missing.join(', ')}`);
getLogger().info('Check env.example for configuration guidance');
}
return false;
}
//# sourceMappingURL=config.js.map
;