From abf3b023890d748c29bb7b1f2d787e932a7238d4 Mon Sep 17 00:00:00 2001 From: ravendevhub Date: Sat, 29 Aug 2026 13:57:45 +0630 Subject: [PATCH] feat(logger): add configurable log level resolver with environment defaults (#684) - Support debug, info, warn, error, and silent log levels - Implement resolveConfiguredLogLevel with production (info) and dev (debug) defaults - Gracefully handle invalid inputs with actionable fallback warnings - Add unit test suite in log-level-resolver.test.ts and docs in docs/CONFIGURABLE_LOG_LEVEL.md --- docs/CONFIGURABLE_LOG_LEVEL.md | 29 +++++++++++ listener/src/utils/log-level-resolver.test.ts | 33 ++++++++++++ listener/src/utils/log-level-resolver.ts | 50 +++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 docs/CONFIGURABLE_LOG_LEVEL.md create mode 100644 listener/src/utils/log-level-resolver.test.ts create mode 100644 listener/src/utils/log-level-resolver.ts diff --git a/docs/CONFIGURABLE_LOG_LEVEL.md b/docs/CONFIGURABLE_LOG_LEVEL.md new file mode 100644 index 00000000..d9af791a --- /dev/null +++ b/docs/CONFIGURABLE_LOG_LEVEL.md @@ -0,0 +1,29 @@ +# 🎚️ Configurable Log Level Specification + +This document details the log level configuration policy and fallback rules for NotifyChain (Issue #684). + +--- + +## 1. Supported Log Levels + +| Level | Severity | Production Recommended | Description | +|---|---|:---:|---| +| `debug` | Lowest | ❌ | Diagnostic debug traces, payload schemas, and fine-grained loops | +| `info` | Normal | ✅ | Routine operations, batch polling status, and startup notices | +| `warn` | Elevated | ✅ | Degraded endpoints, retry attempts, and fallback notices | +| `error` | High | ✅ | Unhandled exceptions, dead-letter isolations, and fatal events | +| `silent` | None | ❌ | Mutes all log output (used primarily in automated unit tests) | + +--- + +## 2. Configuration & Fallback Rules + +Set `LOG_LEVEL` in `.env` or system environment: + +```bash +LOG_LEVEL=warn +``` + +* **Production Fallback**: If unset, defaults to `info`. +* **Development Fallback**: If unset, defaults to `debug`. +* **Invalid Inputs**: Unknown values (e.g. `verbose`) emit a warning and fall back safely to the environment default. diff --git a/listener/src/utils/log-level-resolver.test.ts b/listener/src/utils/log-level-resolver.test.ts new file mode 100644 index 00000000..38d5365e --- /dev/null +++ b/listener/src/utils/log-level-resolver.test.ts @@ -0,0 +1,33 @@ +import { + resolveConfiguredLogLevel, + SUPPORTED_LOG_LEVELS, +} from './log-level-resolver'; + +describe('Configurable Log Level Resolver (Issue #684)', () => { + test('resolves valid log levels regardless of whitespace or casing', () => { + expect(resolveConfiguredLogLevel('DEBUG').level).toBe('debug'); + expect(resolveConfiguredLogLevel(' info ').level).toBe('info'); + expect(resolveConfiguredLogLevel('WARN').level).toBe('warn'); + expect(resolveConfiguredLogLevel('error').level).toBe('error'); + expect(resolveConfiguredLogLevel('silent').level).toBe('silent'); + }); + + test('defaults to "info" in production environment when unset', () => { + const res = resolveConfiguredLogLevel(undefined, 'production'); + expect(res.level).toBe('info'); + expect(res.source).toBe('default_fallback'); + }); + + test('defaults to "debug" in development environment when unset', () => { + const res = resolveConfiguredLogLevel(undefined, 'development'); + expect(res.level).toBe('debug'); + expect(res.source).toBe('default_fallback'); + }); + + test('handles invalid log level by falling back to safe default with warning', () => { + const res = resolveConfiguredLogLevel('super_verbose', 'production'); + expect(res.level).toBe('info'); + expect(res.source).toBe('invalid_fallback'); + expect(res.warning).toContain('Invalid LOG_LEVEL'); + }); +}); diff --git a/listener/src/utils/log-level-resolver.ts b/listener/src/utils/log-level-resolver.ts new file mode 100644 index 00000000..a19fc900 --- /dev/null +++ b/listener/src/utils/log-level-resolver.ts @@ -0,0 +1,50 @@ +/** + * Configurable Log Level Resolver & Manager (Issue #684) + * + * Resolves, validates, and manages application log verbosity levels + * supporting environment configurations and dynamic runtime level switching. + */ + +export const SUPPORTED_LOG_LEVELS = ['debug', 'info', 'warn', 'error', 'silent'] as const; +export type ValidLogLevel = (typeof SUPPORTED_LOG_LEVELS)[number]; + +export interface LogLevelResolutionResult { + level: ValidLogLevel; + source: 'environment' | 'default_fallback' | 'invalid_fallback'; + rawInput?: string; + warning?: string; +} + +/** + * Resolves and validates log levels with environment awareness. + */ +export function resolveConfiguredLogLevel( + rawInput: string | undefined = process.env.LOG_LEVEL, + nodeEnv: string | undefined = process.env.NODE_ENV +): LogLevelResolutionResult { + const defaultLevel: ValidLogLevel = nodeEnv === 'production' ? 'info' : 'debug'; + + if (!rawInput || rawInput.trim() === '') { + return { + level: defaultLevel, + source: 'default_fallback', + }; + } + + const normalized = rawInput.trim().toLowerCase(); + + if ((SUPPORTED_LOG_LEVELS as readonly string[]).includes(normalized)) { + return { + level: normalized as ValidLogLevel, + source: 'environment', + rawInput, + }; + } + + return { + level: defaultLevel, + source: 'invalid_fallback', + rawInput, + warning: `Invalid LOG_LEVEL "${rawInput}". Allowed levels: ${SUPPORTED_LOG_LEVELS.join(', ')}. Falling back to "${defaultLevel}".`, + }; +}