Download src/logging/config.ts from SaylorTwift/openclaw: direct link, hf CLI and curl.
- Browser
- Download file 5 kB
-
https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/logging/config.ts
- Command line
-
hf download hf://SaylorTwift/openclaw/src/logging/config.ts
-
curl -L -o config.ts https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/logging/config.ts
5 kB
| // Logging config helpers read and normalize logger configuration. | |
| import fs from "node:fs"; | |
| import { isRecord as isObjectRecord } from "@openclaw/normalization-core/record-coerce"; | |
| import { resolveConfigEnvVars } from "../config/env-substitution.js"; | |
| import { resolveConfigIncludes, resolveConfigIncludesForTopLevelKey } from "../config/includes.js"; | |
| import { resolveConfigPath, resolveIncludeRoots } from "../config/paths.js"; | |
| import type { OpenClawConfig } from "../config/types.openclaw.js"; | |
| import { tryProcessCwd } from "../infra/safe-cwd.js"; | |
| import { parseJsonWithJson5Fallback } from "../utils/parse-json-compat.js"; | |
| import { APPLIED_LOGGING_CONFIG_UNOWNED, loggingState } from "./state.js"; | |
| // Lightweight logging-config reader used before the full config runtime is safe to load. | |
| type LoggingConfig = NonNullable<OpenClawConfig["logging"]>; | |
| let cachedLoggingConfig: | |
| | { | |
| selector: string; | |
| logging: LoggingConfig | undefined; | |
| } | |
| | undefined; | |
| export function invalidateLoggingConfigCache(): void { | |
| cachedLoggingConfig = undefined; | |
| } | |
| function resolveLoggingConfigSelector(): string { | |
| const env = process.env; | |
| return [ | |
| env.OPENCLAW_CONFIG_PATH, | |
| env.OPENCLAW_STATE_DIR, | |
| env.OPENCLAW_HOME, | |
| env.OPENCLAW_PROFILE, | |
| env.HOME, | |
| env.USERPROFILE, | |
| env.HOMEDRIVE, | |
| env.HOMEPATH, | |
| env.PREFIX, | |
| env.ANDROID_DATA, | |
| env.OPENCLAW_TEST_FAST, | |
| tryProcessCwd() ?? "", | |
| ] | |
| .map((value) => value ?? "") | |
| .join("\0"); | |
| } | |
| function resolvePartialDiagnosticLoggingConfig(logging: unknown): LoggingConfig | undefined { | |
| if (!isObjectRecord(logging)) { | |
| return undefined; | |
| } | |
| const partial: Record<string, unknown> = {}; | |
| if (typeof logging.consoleStyle === "string") { | |
| try { | |
| const resolved = resolveConfigEnvVars({ consoleStyle: logging.consoleStyle }); | |
| if ( | |
| isObjectRecord(resolved) && | |
| (resolved.consoleStyle === "pretty" || | |
| resolved.consoleStyle === "compact" || | |
| resolved.consoleStyle === "json") | |
| ) { | |
| partial.consoleStyle = resolved.consoleStyle; | |
| } | |
| } catch { | |
| // Keep resolving independent diagnostic fields. | |
| } | |
| } | |
| if (Array.isArray(logging.redactPatterns)) { | |
| try { | |
| const resolved = resolveConfigEnvVars({ redactPatterns: logging.redactPatterns }); | |
| if ( | |
| isObjectRecord(resolved) && | |
| Array.isArray(resolved.redactPatterns) && | |
| resolved.redactPatterns.every((entry) => typeof entry === "string") | |
| ) { | |
| partial.redactPatterns = resolved.redactPatterns; | |
| } | |
| } catch { | |
| // A missing variable in one pattern must not hide a separately resolvable style. | |
| } | |
| } | |
| return Object.keys(partial).length > 0 ? (partial as LoggingConfig) : undefined; | |
| } | |
| /** Reads the logging block from config, caching by resolved config path. */ | |
| export function readLoggingConfig(): LoggingConfig | undefined { | |
| try { | |
| if (loggingState.appliedConfig !== APPLIED_LOGGING_CONFIG_UNOWNED) { | |
| return loggingState.appliedConfig; | |
| } | |
| const selector = resolveLoggingConfigSelector(); | |
| if (cachedLoggingConfig?.selector === selector) { | |
| return cachedLoggingConfig.logging; | |
| } | |
| const configPath = resolveConfigPath(); | |
| if (!fs.existsSync(configPath)) { | |
| cachedLoggingConfig = { selector, logging: undefined }; | |
| return undefined; | |
| } | |
| const parsed = parseJsonWithJson5Fallback(fs.readFileSync(configPath, "utf8")); | |
| const allowedRoots = resolveIncludeRoots(); | |
| let includedConfig: unknown; | |
| try { | |
| includedConfig = resolveConfigIncludesForTopLevelKey( | |
| parsed, | |
| configPath, | |
| "logging", | |
| undefined, | |
| { allowedRoots }, | |
| ); | |
| } catch { | |
| // Validation commands still need a directly-authored logging style when an unrelated | |
| // root include is malformed. Resolve only that subtree through the same canonical rules. | |
| const directLogging = isObjectRecord(parsed) ? parsed.logging : undefined; | |
| if (directLogging === undefined) { | |
| return undefined; | |
| } | |
| try { | |
| includedConfig = resolveConfigIncludes({ logging: directLogging }, configPath, undefined, { | |
| allowedRoots, | |
| }); | |
| } catch { | |
| const logging = resolvePartialDiagnosticLoggingConfig(directLogging); | |
| return logging; | |
| } | |
| } | |
| let resolvedConfig: unknown; | |
| try { | |
| resolvedConfig = resolveConfigEnvVars(includedConfig); | |
| } catch { | |
| const includedLogging = isObjectRecord(includedConfig) ? includedConfig.logging : undefined; | |
| const logging = resolvePartialDiagnosticLoggingConfig(includedLogging); | |
| return logging; | |
| } | |
| const logging = isObjectRecord(resolvedConfig) ? resolvedConfig.logging : undefined; | |
| const resolvedLogging = isObjectRecord(logging) ? (logging as LoggingConfig) : undefined; | |
| cachedLoggingConfig = { | |
| selector, | |
| logging: resolvedLogging, | |
| }; | |
| return resolvedLogging; | |
| } catch { | |
| return undefined; | |
| } | |
| } | |