diff --git a/tools/src/Logger.ts b/tools/src/Logger.ts index 3585f1ecb..61a3f7284 100644 --- a/tools/src/Logger.ts +++ b/tools/src/Logger.ts @@ -16,10 +16,20 @@ export enum LogLevel { export class Logger { level: LogLevel - constructor (level: LogLevel) { + static messages = { + [LogLevel.error]: 'ERROR', + [LogLevel.warn]: 'WARNING', + [LogLevel.info]: 'INFO' + } + + constructor (level: LogLevel = LogLevel.warn) { this.level = level } + log (message: string): void { + console.log(message) + } + info (message: string): void { this.#log(LogLevel.info, message) } @@ -34,9 +44,7 @@ export class Logger { #log (level: LogLevel, message: string): void { if (level > this.level) return - const output = `[${level}] ${message}` - if (level === LogLevel.error) console.error(output) - if (level === LogLevel.warn) console.warn(output) - if (level === LogLevel.info) console.info(output) + const output = `[${Logger.messages[level]}] ${message}` + console.log(output) } } diff --git a/tools/src/merger/OpenApiMerger.ts b/tools/src/merger/OpenApiMerger.ts index 4cded34bb..67af89e56 100644 --- a/tools/src/merger/OpenApiMerger.ts +++ b/tools/src/merger/OpenApiMerger.ts @@ -24,8 +24,8 @@ export default class OpenApiMerger { paths: Record> = {} // namespace -> path -> path_item_object schemas: Record> = {} // category -> schema -> schema_object - constructor (root_folder: string, log_level: LogLevel = LogLevel.warn) { - this.logger = new Logger(log_level) + constructor (root_folder: string, logger: Logger = new Logger(LogLevel.warn)) { + this.logger = logger this.root_folder = fs.realpathSync(root_folder) this.spec = { openapi: '3.1.0', @@ -47,6 +47,8 @@ export default class OpenApiMerger { this.#generate_global_params() this.#generate_superseded_ops() + this.logger.info(`Writing ${output_path} ...`) + if (output_path !== '') write_yaml(output_path, this.spec) return this.spec as OpenAPIV3.Document } @@ -55,6 +57,7 @@ export default class OpenApiMerger { #merge_namespaces (): void { const folder = `${this.root_folder}/namespaces` fs.readdirSync(folder).forEach(file => { + this.logger.info(`Merging namespaces in ${folder}/${file} ...`) const spec = read_yaml(`${folder}/${file}`) this.redirect_refs_in_namespace(spec) this.spec.paths = { ...this.spec.paths, ...spec.paths } @@ -78,6 +81,7 @@ export default class OpenApiMerger { #merge_schemas (): void { const folder = `${this.root_folder}/schemas` fs.readdirSync(folder).forEach(file => { + this.logger.info(`Merging schema ${folder}/${file} ...`) const spec = read_yaml(`${folder}/${file}`) const category = file.split('.yaml')[0] this.redirect_refs_in_schema(category, spec) diff --git a/tools/src/merger/SupersededOpsGenerator.ts b/tools/src/merger/SupersededOpsGenerator.ts index 7f941c1c3..72f8ee5b6 100644 --- a/tools/src/merger/SupersededOpsGenerator.ts +++ b/tools/src/merger/SupersededOpsGenerator.ts @@ -30,7 +30,7 @@ export default class SupersededOpsGenerator { const superseded_path = this.copy_params(superseded_by, path) const path_entry = _.entries(spec.paths as Document).find(([path, _]) => regex.test(path)) if (path_entry != null) spec.paths[superseded_path] = this.path_object(path_entry[1], operation_keys) - else this.logger.warn(`Warning: ${path} is superseded by a path that does not exist: ${superseded_by}`) + else this.logger.warn(`${path} is superseded by a path that does not exist: ${superseded_by}`) } } diff --git a/tools/src/merger/merge.ts b/tools/src/merger/merge.ts index 470a274fe..50af3360b 100644 --- a/tools/src/merger/merge.ts +++ b/tools/src/merger/merge.ts @@ -10,16 +10,19 @@ import { Command, Option } from '@commander-js/extra-typings' import OpenApiMerger from './OpenApiMerger' import { resolve } from 'path' +import { Logger, LogLevel } from '../Logger' const command = new Command() .description('Merges the multi-file OpenSearch spec into a single file for programmatic use.') .addOption(new Option('-s, --source ', 'path to the root folder of the multi-file spec').default(resolve(__dirname, '../../../spec'))) .addOption(new Option('-o, --output ', 'output file name').default(resolve(__dirname, '../../../build/opensearch-openapi.yaml'))) + .addOption(new Option('--verbose', 'show merge details').default(false)) .allowExcessArguments(false) .parse() const opts = command.opts() -const merger = new OpenApiMerger(opts.source) -console.log(`Merging ${opts.source} into ${opts.output} ...`) +const logger = new Logger(opts.verbose ? LogLevel.info : LogLevel.warn) +const merger = new OpenApiMerger(opts.source, logger) +logger.log(`Merging ${opts.source} into ${opts.output} ...`) merger.merge(opts.output) -console.log('Done.') +logger.log('Done.') diff --git a/tools/tests/Logger.test.ts b/tools/tests/Logger.test.ts new file mode 100644 index 000000000..77d9ad0b6 --- /dev/null +++ b/tools/tests/Logger.test.ts @@ -0,0 +1,102 @@ +/* +* Copyright OpenSearch Contributors +* SPDX-License-Identifier: Apache-2.0 +* +* The OpenSearch Contributors require contributions made to +* this file be licensed under the Apache-2.0 license or a +* compatible open source license. +*/ + +import { Logger, LogLevel } from '../src/Logger' + +describe('Logger', () => { + let log: jest.Mock + + beforeEach(() => { + log = console.log = jest.fn() + }) + + afterEach(() => { + log.mockClear() + }) + + describe('at default log level', () => { + const logger = new Logger() + + test('sets log level at warn', () => { + expect(logger.level).toEqual(LogLevel.warn) + }) + + test('does not log info level messages', () => { + logger.log('log') + logger.error('error') + logger.warn('warn') + logger.info('info') + expect(log.mock.calls).toEqual([ + ['log'], + ['[ERROR] error'], + ['[WARNING] warn'] + ]) + }) + }) + + describe('at info log level', () => { + const logger = new Logger(LogLevel.info) + + test('sets log level at info', () => { + expect(logger.level).toEqual(LogLevel.info) + }) + + test('logs all messages', () => { + logger.log('log') + logger.error('error') + logger.warn('warn') + logger.info('info') + expect(log.mock.calls).toEqual([ + ['log'], + ['[ERROR] error'], + ['[WARNING] warn'], + ['[INFO] info'] + ]) + }) + }) + + describe('at warn log level', () => { + const logger = new Logger(LogLevel.warn) + + test('sets log level at warn', () => { + expect(logger.level).toEqual(LogLevel.warn) + }) + + test('does not log info messages', () => { + logger.log('log') + logger.error('error') + logger.warn('warn') + logger.info('info') + expect(log.mock.calls).toEqual([ + ['log'], + ['[ERROR] error'], + ['[WARNING] warn'] + ]) + }) + }) + + describe('at error log level', () => { + const logger = new Logger(LogLevel.error) + + test('sets log level at error', () => { + expect(logger.level).toEqual(LogLevel.error) + }) + + test('does not log warn and info messages', () => { + logger.log('log') + logger.error('error') + logger.warn('warn') + logger.info('info') + expect(log.mock.calls).toEqual([ + ['log'], + ['[ERROR] error'] + ]) + }) + }) +})