Merge pull request #12976 from keymanapp/feat/developer/12975-verbose-and-debug-log-levels

feat(developer): add 'verbose' and 'debug' log levels to kmc
This commit is contained in:
Marc Durdin 2025-01-23 14:42:59 +07:00 committed by GitHub
commit ae148984b8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 55 additions and 23 deletions

View file

@ -28,11 +28,13 @@
namespace CompilerErrorSeverity {
// We use a namespace to stop the enum names leaking out into global namespace scope
enum {
Info = 0x000000, // Informational, not necessarily a problem
Hint = 0x100000, // Something the user might want to be aware of
Warn = 0x200000, // Warning: Not great, but we can keep going.
Error = 0x300000, // Severe error where we can't continue
Fatal = 0x400000, // OOM or should-not-happen internal problem
Debug = 0x000000, // log everything including internal debug
Verbose = 0x100000, // log everything, except debug
Info = 0x200000, // Informational, not necessarily a problem
Hint = 0x300000, // Something the user might want to be aware of
Warn = 0x400000, // Warning: Not great, but we can keep going.
Error = 0x500000, // Severe error where we can't continue
Fatal = 0x600000, // OOM or should-not-happen internal problem
};
};

View file

@ -2,7 +2,8 @@ import * as fs from 'fs';
import * as path from 'path';
import { CompilerEvent, CompilerCallbacks, CompilerPathCallbacks, CompilerFileSystemCallbacks,
CompilerError, CompilerNetAsyncCallbacks, DefaultCompilerFileSystemAsyncCallbacks,
CompilerFileSystemAsyncCallbacks } from '@keymanapp/developer-utils';
CompilerFileSystemAsyncCallbacks,
CompilerErrorSeverity} from '@keymanapp/developer-utils';
import { fileURLToPath } from 'url';
const { TEST_SAVE_FIXTURES } = process.env;
@ -27,6 +28,10 @@ export class TestCompilerCallbacks implements CompilerCallbacks {
this.messages = [];
}
filteredMessages(severity: CompilerErrorSeverity = CompilerErrorSeverity.Info) {
return this.messages.filter(m => CompilerError.severity(m.code) >= severity);
}
printMessages() {
if(this.messages.length) {
process.stdout.write(CompilerError.formatEvent(this.messages));

View file

@ -31,7 +31,7 @@ export function verifyCompilerMessagesObject(source: Record<string,any>, namespa
// Verify each object member matches the pattern we expect
if(typeof m[key] == 'function') {
const o = /^(Info|Hint|Warn|Error|Fatal)_([A-Za-z0-9_]+)$/.exec(key);
const o = /^(Debug|Verbose|Info|Hint|Warn|Error|Fatal)_([A-Za-z0-9_]+)$/.exec(key);
expect(o).to.be.instanceOf(Array, `Expected member ${key} to be a valid message function name`);
const c = o[1].toUpperCase() + '_' + o[2];
@ -41,7 +41,7 @@ export function verifyCompilerMessagesObject(source: Record<string,any>, namespa
expect(v.code).to.equal(m[c], `Function ${key} returns the wrong code`);
}
else if(typeof m[key] == 'number') {
const o = /^(INFO|HINT|WARN|ERROR|FATAL)_([A-Za-z0-9_]+)$/.exec(key);
const o = /^(DEBUG|VERBOSE|INFO|HINT|WARN|ERROR|FATAL)_([A-Za-z0-9_]+)$/.exec(key);
expect(o).to.be.instanceOf(Array);
const f = toTitleCase(o[1]) + '_' + o[2];
@ -53,7 +53,7 @@ export function verifyCompilerMessagesObject(source: Record<string,any>, namespa
// Verify severify masks
if(typeof m[key] == 'number') {
const o = /^(INFO|HINT|WARN|ERROR|FATAL)_([A-Za-z0-9_]+)$/.exec(key);
const o = /^(DEBUG|VERBOSE|INFO|HINT|WARN|ERROR|FATAL)_([A-Za-z0-9_]+)$/.exec(key);
expect(o).to.be.instanceOf(Array);
const mask = CompilerError.formatSeverity(m[key]).toUpperCase();

View file

@ -21,14 +21,18 @@ export interface CompilerEvent {
};
export enum CompilerErrorSeverity {
Info = 0x000000, // Informational, not necessarily a problem
Hint = 0x100000, // Something the user might want to be aware of
Warn = 0x200000, // Warning: Not great, but we can keep going.
Error = 0x300000, // Severe error where we can't continue
Fatal = 0x400000, // OOM or should-not-happen internal problem
Debug = 0x000000, // log everything including internal debug
Verbose = 0x100000, // log everything, except debug
Info = 0x200000, // Informational, not necessarily a problem
Hint = 0x300000, // Something the user might want to be aware of
Warn = 0x400000, // Warning: Not great, but we can keep going.
Error = 0x500000, // Severe error where we can't continue
Fatal = 0x600000, // OOM or should-not-happen internal problem
};
export const CompilerErrorSeverityValues = [
CompilerErrorSeverity.Debug,
CompilerErrorSeverity.Verbose,
CompilerErrorSeverity.Info,
CompilerErrorSeverity.Hint,
CompilerErrorSeverity.Warn,
@ -48,6 +52,8 @@ export enum CompilerErrorMask {
};
const errorSeverityName = {
[CompilerErrorSeverity.Debug]: 'debug',
[CompilerErrorSeverity.Verbose]: 'verbose',
[CompilerErrorSeverity.Info]: 'info',
[CompilerErrorSeverity.Hint]: 'hint',
[CompilerErrorSeverity.Warn]: 'warn',
@ -415,8 +421,9 @@ export const ALL_COMPILER_LOG_LEVELS = [
'error', /// Only errors emitted
'warn', /// Errors + warnings
'hint', /// Errors + warnings + hints
'info', /// All messages: errors + warnings + hints + info
'debug' /// All messages: errors + warnings + hints + info, plus debug logs
'info', /// All normal messages: errors + warnings + hints + info
'verbose', /// All messages + verbose logging
'debug', /// All messages + verbose + internal debug
] as const;
type CompilerLogLevelTuple = typeof ALL_COMPILER_LOG_LEVELS;
@ -428,7 +435,8 @@ export const compilerLogLevelToSeverity: {[index in CompilerLogLevel]: number} =
'warn': CompilerErrorSeverity.Warn,
'hint': CompilerErrorSeverity.Hint,
'info': CompilerErrorSeverity.Info,
'debug': CompilerErrorSeverity.Info
'verbose': CompilerErrorSeverity.Verbose,
'debug': CompilerErrorSeverity.Debug,
};
export const ALL_COMPILER_LOG_FORMATS = [

View file

@ -63,9 +63,10 @@ export class KeymanCloudSource {
}
public async downloadFolderFromGitHub(ref: GitHubRef): Promise<{filename:string,type:'dir'|'file'}[]> {
// this.callbacks.reportMessage(CopierMessages.Info_DownloadingFile({ref})); // TODO-COPY: verbose mode support
const url = `https://api.github.com/repos/${ref.owner}/${ref.repo}/contents/${ref.path}?ref=${ref.branch}`;
this.callbacks.reportMessage(CopierMessages.Verbose_DownloadingFolder({path:ref.path, url}));
let folder: any;
try {
folder = await this.callbacks.net.fetchJSON(url);
@ -94,6 +95,7 @@ export class KeymanCloudSource {
}
const url = `https://raw.githubusercontent.com/${ref.owner}/${ref.repo}/refs/heads/${ref.branch}${ref.path}`;
this.callbacks.reportMessage(CopierMessages.Verbose_DownloadingFile({filename:this.callbacks.path.basename(ref.path), url}));
try {
return await this.callbacks.net.fetchBlob(url);

View file

@ -7,6 +7,7 @@
import { CompilerErrorNamespace, CompilerErrorSeverity, CompilerMessageSpec as m, CompilerMessageDef as def, CompilerMessageSpecWithException } from "@keymanapp/developer-utils";
const Namespace = CompilerErrorNamespace.Copier;
const SevVerbose = CompilerErrorSeverity.Verbose | Namespace;
const SevInfo = CompilerErrorSeverity.Info | Namespace;
// const SevHint = CompilerErrorSeverity.Hint | Namespace;
const SevWarn = CompilerErrorSeverity.Warn | Namespace;
@ -198,4 +199,16 @@ export class CopierMessages {
the provided error details for more details.`
);
static VERBOSE_DownloadingFile = SevVerbose | 0x001C;
static Verbose_DownloadingFile = (o:{filename: string, url: string}) => m(
this.VERBOSE_DownloadingFile,
`Downloading '${def(o.filename)}' from '${def(o.url)}'`,
);
static VERBOSE_DownloadingFolder = SevVerbose | 0x001D;
static Verbose_DownloadingFolder = (o:{path: string, url: string}) => m(
this.VERBOSE_DownloadingFolder,
`Downloading folder '${def(o.path)}' from '${def(o.url)}'`,
);
};

View file

@ -315,7 +315,7 @@ describe('KeymanProjectCopier', function() {
//
assert.isOk(result);
assert.isEmpty(callbacks.messages);
assert.isEmpty(callbacks.filteredMessages());
if(TEST_SAVE_ARTIFACTS) {
assert.isTrue(await copier.write(result.artifacts));
@ -377,7 +377,7 @@ describe('KeymanProjectCopier', function() {
// We should have no messages and a successful result
assert.isOk(result);
assert.isEmpty(callbacks.messages);
assert.isEmpty(callbacks.filteredMessages());
// TODO-COPY: verify outcome using pattern above
@ -404,7 +404,7 @@ describe('KeymanProjectCopier', function() {
// We should have no messages and a successful result
assert.isOk(result);
assert.isEmpty(callbacks.messages);
assert.isEmpty(callbacks.filteredMessages());
// TODO-COPY: verify outcome using pattern above

View file

@ -178,7 +178,7 @@ function allMessageDetails(): CompilerMessageDetail[] {
const toTitleCase = (s: string) => s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase();
function getMessageDetail(cls: any, id: string, escapeMarkdown: boolean): CompilerEvent {
const o = /^(INFO|HINT|WARN|ERROR|FATAL)_([A-Za-z0-9_]+)$/.exec(id);
const o = /^(DEBUG|VERBOSE|INFO|HINT|WARN|ERROR|FATAL)_([A-Za-z0-9_]+)$/.exec(id);
if(!o) {
throw new Error(`Unexpected compiler message ${id}, does not match message error format`);
}

View file

@ -23,6 +23,8 @@ const severityColors: {[value in CompilerErrorSeverity]: chalk.Chalk} = {
[CompilerErrorSeverity.Warn]: color.hex('FFA500'), // orange
[CompilerErrorSeverity.Error]: color.redBright,
[CompilerErrorSeverity.Fatal]: color.redBright,
[CompilerErrorSeverity.Verbose]: color.gray,
[CompilerErrorSeverity.Debug]: color.blueBright,
};
/**

View file

@ -114,7 +114,7 @@ begin
state := plsFatal;
Result := False;
end
else // assume msgType = 'info'
else // assume msgType = 'info' (fine also for 'verbose', 'debug')
state := plsInfo;
FGlobalProject.Log(state, msgFilename, msgText, msgCode, msgLine);
end