Logger
VonaJS provides a powerful and flexible logging system based on winston.
Features
Clients: Each client has independent configurationsChildren: Child logs can be created for different scenariosRotate: Log files are rotated according to the specified rulesLevel: The content written to log files can be controlled based on levels
Log Directory
Different log directories are used by default for different runtime environments:
Test/Development:{project path}/.app/logsProduction:{home}/vona/{project name}/logs
Configuration can be modified in the App Config or .env file
1. App Config
src/backend/config/config/config.ts
// logger
config.logger = {
baseDir: '/new/path',
};2. .env
env/.env
# logger
LOGGER_DIR = /new/pathApp Config
Log configuration can be done in App Config:
src/backend/config/config/config.ts
// logger
config.logger = {
baseDir: '/new/path',
rotate(filename: string) {},
base: {},
clients: {},
};| Name | Description |
|---|---|
| baseDir | Log Directory |
| rotate | Log Rotate |
| base | Basic configuration, providing common basic configuration for all clients |
| clients | Configure multiple clients. The system provides a built-in default client, enabling out-of-the-box logging capabilities |
Rotate
The system provides a default rotation configuration, which is enabled. You can modify the configuration in the App Config or .env file
1. App Config
src/backend/config/config/config.ts
// logger
config.logger = {
rotate(filename: string) {
return {
enable: true,
filename: `${filename}-%DATE%.log`,
datePattern: 'YYYY-MM-DD',
maxSize: '20m',
maxFiles: '7d',
};
},
};| Name | Description |
|---|---|
| enable | Whether Rotate is enabled |
| filename | Filename template |
| datePattern | Date pattern |
| maxSize | Maximum size of each file |
| maxFiles | Keep only files from the last few days |
2. .env
env/.env
# logger
LOGGER_ROTATE_ENABLE = true
LOGGER_ROTATE_FILENAME = '{{filename}}-%DATE%.log'
LOGGER_ROTATE_DATEPATTERN = YYYY-MM-DD
LOGGER_ROTATE_MAXSIZE = 20m
LOGGER_ROTATE_MAXFILES = 7dAdding a New Client
The following explains the Client configuration by adding a new Client
1. Adding Type Definition
Add a new Client type definition using the interface merging mechanism, such as order, to output independent order-related logs
In the VSCode editor, enter the code snippet recordloggerclient, and the code skeleton will be automatically generated:
declare module 'vona' {
export interface ILoggerClientRecord {
: never;
}
}Adjust the code, and then add order
declare module 'vona' {
export interface ILoggerClientRecord {
+ order: never;
}
}2. Adding Client Configuration
src/backend/config/config/config.ts
// logger
config.logger = {
clients: {
order(this: VonaApplication, clientInfo) {
const transports = [
this.bean.logger.makeTransportFile(clientInfo, 'order'),
this.bean.logger.makeTransportConsole(clientInfo),
];
return { transports };
},
},
};order: Returns the Client configuration via a function. This configuration will be merged with the system-provided default configuration- Therefore, in general, only the required
transportsneed to be constructed
- Therefore, in general, only the required
clientInfo: Contains environment information used to construct thetransportmakeTransportFile: Used to construct the file transport, requiring the log file nameorder- Since the file name template is
${filename}-%DATE%.log, the actual generated file name isorder-2025-11-16.log
- Since the file name template is
makeTransportConsole: Used to construct the console transport
Obtaining Logger Client Instance
There are two ways to obtain a Logger Client instance:
Method 1
class ControllerStudent extends BeanBase {
async test() {
// logger: default
const loggerDefault = this.bean.logger.default;
// logger: order
const loggerOrder = this.bean.logger.get('order');
}
}Method 2
class ControllerStudent extends BeanBase {
async test() {
// logger: default
const loggerDefault = this.$logger;
// logger: order
const loggerOrder = this.$loggerClient('order');
}
}Method 2 is not only more concise, but it also automatically includes the beanFullName of the current Bean Class in the logs, making it easier to troubleshoot problems
- Example:
const loggerOrder = this.bean.logger.get('order');
loggerOrder.info('test');
// logger: default
this.$logger.info('test');
// logger: order
this.$loggerClient('order').info('test');
The image outputs beanFullName: [demo-student.controller.student]
Obtaining Logger Child Instance
For the same Logger Client, multiple Child instances can be generated, each corresponding to a different scenario
For example, generating a Child pay will clearly display the pay information in the log
// child of logger-default
this.$loggerChild('pay').info('$50');
// child of logger-order
this.$loggerChild('pay', 'order').info('$50');
The image outputs Child name: [pay]
Adding Type Definition
Similarly, a type definition for pay is required to support type hints
In the VSCode editor, enter the code snippet recordloggerchild, and the code skeleton will be automatically generated:
declare module 'vona' {
export interface ILoggerChildRecord {
: never;
}
}Adjust the code, and then add pay
declare module 'vona' {
export interface ILoggerChildRecord {
+ pay: never;
}
}Log Message
1. General Usage
this.$logger.info('test');2. String Interpolation
String interpolation is implemented based on util.format
this.$logger.info('%s has %d apples', 'Tom', 3);3. Delayed Messages
Due to log level, some leveled messages are not written to files. Therefore, constructing excessively large message contents will waste system resources
- Example
const obj = { data: 'more info' };
this.$logger.debug(JSON.stringify(obj));If the current level is info, then logs at the debug level will not be written to the file. Therefore, JSON.stringify will waste system resources
- Solution
A callback function can be provided. This function is executed only when writing to a file is required, thus generating the actual message
const obj = { data: 'more info' };
this.$logger.debug(() => {
return JSON.stringify(obj);
});4. Multi-Child
Multi-Child Loggers can be created from the current Logger instance, thus passing more metadata to the log message
this.$logger.child({ requestId: '451' }).child({ extra: 'some info' }).info('test');
this.$logger.child({ requestId: '578', extra: 'some info' }).info('test');As shown below: requestId/extra
