Skip to content

Commit 1e4c111

Browse files
committed
feat: add configurable log levels in CLI and API
- Introduced `--log-level` option in CLI for granular logging control. - Enhanced `CodegenLogger` to support log levels (DEBUG, INFO, WARN, ERROR, SILENT). - Updated APIBuilder to allow log level configuration.
1 parent c134ba7 commit 1e4c111

4 files changed

Lines changed: 92 additions & 6 deletions

File tree

src/api/builder.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { mkTypeSchemaIndex, type TreeShake, type TypeSchemaIndex, treeShake } fr
1515
import { generateTypeSchemas } from "@typeschema/index";
1616
import { extractNameFromCanonical, packageMetaToFhir, packageMetaToNpm, type TypeSchema } from "@typeschema/types";
1717
import type { TypeSchemaConfig } from "../config";
18-
import { CodegenLogger, createLogger } from "../utils/codegen-logger";
18+
import { CodegenLogger, createLogger, LogLevel } from "../utils/codegen-logger";
1919
import { TypeScript, type TypeScriptOptions } from "./writer-generator/typescript";
2020
import type { FileBuffer, FileSystemWriter, WriterOptions } from "./writer-generator/writer";
2121

@@ -35,6 +35,8 @@ export interface APIBuilderOptions {
3535
throwException?: boolean;
3636
exportTypeTree?: string;
3737
treeShake?: TreeShake;
38+
/** Log level for the logger. Default: INFO */
39+
logLevel?: LogLevel;
3840
}
3941

4042
/**
@@ -70,7 +72,7 @@ export type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
7072

7173
type APIBuilderConfig = PartialBy<
7274
Required<APIBuilderOptions>,
73-
"logger" | "typeSchemaConfig" | "typeSchemaOutputDir" | "exportTypeTree" | "treeShake"
75+
"logger" | "typeSchemaConfig" | "typeSchemaOutputDir" | "exportTypeTree" | "treeShake" | "logLevel"
7476
> & {
7577
cleanOutput: boolean;
7678
};
@@ -208,6 +210,7 @@ export class APIBuilder {
208210
createLogger({
209211
verbose: this.options.verbose,
210212
prefix: "API",
213+
level: options.logLevel,
211214
});
212215
}
213216

@@ -297,6 +300,15 @@ export class APIBuilder {
297300
return this;
298301
}
299302

303+
/**
304+
* Set the log level for the logger
305+
* @param level - The log level to set (DEBUG, INFO, WARN, ERROR, SILENT)
306+
*/
307+
setLogLevel(level: LogLevel): APIBuilder {
308+
this.logger?.setLevel(level);
309+
return this;
310+
}
311+
300312
throwException(enabled = true): APIBuilder {
301313
this.options.throwException = enabled;
302314
return this;

src/api/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ export type { APIBuilderOptions } from "./builder";
1111
export { APIBuilder } from "./builder";
1212
export type { CSharpGeneratorOptions } from "./writer-generator/csharp/csharp";
1313
export type { TypeScriptOptions } from "./writer-generator/typescript";
14+
export { LogLevel } from "../utils/codegen-logger";

src/cli/commands/index.ts

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Modern CLI with subcommands for typeschema and code generation
77
*/
88

9-
import { configure, error, header } from "@root/utils/codegen-logger";
9+
import { configure, error, header, LogLevel } from "@root/utils/codegen-logger";
1010
import yargs from "yargs";
1111
import { hideBin } from "yargs/helpers";
1212
import { generateCommand } from "./generate";
@@ -19,16 +19,45 @@ export interface CLIArgv {
1919
config?: string;
2020
verbose?: boolean;
2121
debug?: boolean;
22+
logLevel?: "debug" | "info" | "warn" | "error" | "silent";
23+
}
24+
25+
/**
26+
* Map string log level to LogLevel enum
27+
*/
28+
function parseLogLevel(level: string | undefined): LogLevel | undefined {
29+
if (!level) return undefined;
30+
const levelMap: Record<string, LogLevel> = {
31+
debug: LogLevel.DEBUG,
32+
info: LogLevel.INFO,
33+
warn: LogLevel.WARN,
34+
error: LogLevel.ERROR,
35+
silent: LogLevel.SILENT,
36+
};
37+
return levelMap[level.toLowerCase()];
2238
}
2339

2440
/**
2541
* Middleware to setup logging
2642
*/
2743
async function setupLoggingMiddleware(argv: any) {
44+
// Determine log level: explicit --log-level takes precedence over --verbose/--debug
45+
let level = parseLogLevel(argv.logLevel);
46+
47+
// If no explicit log level, use --verbose or --debug as shortcuts
48+
if (level === undefined) {
49+
if (argv.debug || argv.verbose) {
50+
level = LogLevel.DEBUG;
51+
} else {
52+
level = LogLevel.INFO;
53+
}
54+
}
55+
2856
// Configure the CliLogger with user preferences
2957
configure({
3058
verbose: argv.verbose || argv.debug,
3159
timestamp: argv.debug,
60+
level,
3261
});
3362
}
3463

@@ -56,6 +85,13 @@ export function createCLI() {
5685
default: false,
5786
global: true,
5887
})
88+
.option("log-level", {
89+
alias: "l",
90+
type: "string",
91+
choices: ["debug", "info", "warn", "error", "silent"] as const,
92+
description: "Set the log level (default: info)",
93+
global: true,
94+
})
5995
.option("config", {
6096
alias: "c",
6197
type: "string",

src/utils/codegen-logger.ts

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ export interface LogOptions {
1919
timestamp?: boolean;
2020
verbose?: boolean;
2121
suppressLoggingLevel?: LogLevel[] | "all";
22+
/** Minimum log level to display. Messages below this level are suppressed. Default: INFO */
23+
level?: LogLevel;
2224
}
2325

2426
/**
@@ -32,8 +34,20 @@ export class CodegenLogger {
3234
this.options = {
3335
timestamp: false,
3436
verbose: false,
37+
level: LogLevel.INFO,
3538
...options,
3639
};
40+
if (options.verbose === true && options.level === undefined) {
41+
this.options.level = LogLevel.DEBUG;
42+
}
43+
}
44+
45+
/**
46+
* Check if a message at the given level should be logged
47+
*/
48+
private shouldLog(messageLevel: LogLevel): boolean {
49+
const currentLevel = this.options.level ?? LogLevel.INFO;
50+
return messageLevel >= currentLevel;
3751
}
3852

3953
private static consoleLevelsMap: Record<LogLevel, (...data: any[]) => void> = {
@@ -58,6 +72,7 @@ export class CodegenLogger {
5872

5973
private tryWriteToConsole(level: LogLevel, formattedMessage: string): void {
6074
if (this.isSuppressed(level)) return;
75+
if (!this.shouldLog(level)) return;
6176
const logFn = CodegenLogger.consoleLevelsMap[level] || console.log;
6277
logFn(formattedMessage);
6378
}
@@ -74,8 +89,11 @@ export class CodegenLogger {
7489
*/
7590
error(message: string, error?: Error): void {
7691
if (this.isSuppressed(LogLevel.ERROR)) return;
92+
if (!this.shouldLog(LogLevel.ERROR)) return;
7793
console.error(this.formatMessage("X", message, pc.red));
78-
if (error && this.options.verbose) {
94+
// Show error details if verbose or log level is DEBUG
95+
const showDetails = this.options.verbose || this.options.level === LogLevel.DEBUG;
96+
if (error && showDetails) {
7997
console.error(pc.red(` ${error.message}`));
8098
if (error.stack) {
8199
console.error(pc.gray(error.stack));
@@ -105,10 +123,11 @@ export class CodegenLogger {
105123
}
106124

107125
/**
108-
* Debug message (only shows in verbose mode)
126+
* Debug message (only shows when log level is DEBUG or verbose is true)
109127
*/
110128
debug(message: string): void {
111-
if (this.options.verbose) {
129+
// Debug shows if verbose is true OR log level allows DEBUG
130+
if (this.options.verbose || this.shouldLog(LogLevel.DEBUG)) {
112131
this.tryWriteToConsole(LogLevel.DEBUG, this.formatMessage("🐛", message, pc.magenta));
113132
}
114133
}
@@ -158,6 +177,24 @@ export class CodegenLogger {
158177
*/
159178
configure(options: Partial<LogOptions>): void {
160179
this.options = { ...this.options, ...options };
180+
// If verbose is set to true and level wasn't explicitly provided, set level to DEBUG
181+
if (options.verbose === true && options.level === undefined) {
182+
this.options.level = LogLevel.DEBUG;
183+
}
184+
}
185+
186+
/**
187+
* Get the current log level
188+
*/
189+
getLevel(): LogLevel {
190+
return this.options.level ?? LogLevel.INFO;
191+
}
192+
193+
/**
194+
* Set the log level
195+
*/
196+
setLevel(level: LogLevel): void {
197+
this.options.level = level;
161198
}
162199
}
163200

0 commit comments

Comments
 (0)