Logging can provide us with the necessary information about the system’s behavior to locate online code problems without getting lost at 🤠. This is why logging is important, as it is for Node applications. There are a variety of logging tools, including Log4js, Bunyan, Winston, Today we will talk about Winston who has the most stars on GitHub
Installation needless to say, is the following code
npm install winston
The basic use
const logger = require('winston')
logger.info('is info') Logger. log('info', 'is info')
logger.warn('is warn') // logger.log('warn', 'is warn')
logger.error('is error') // logger.log('error', 'is error')
Copy the code
The log is printed to the console
[winston] Attempt to write logs with no transports {"message":"is info"."level":"info"}
[winston] Attempt to write logs with no transports {"message":"is warn"."level":"warn"}
[winston] Attempt to write logs with no transports {"message":"is error"."level":"error"}
Copy the code
Storage/Output mechanism (TranSports)
Built-in transports
Sometimes we want to receive logs on the console and save them to a file
Pm2 out.log to log the students above code can be achieved, and there is a level classification
If you use docker and other non-PM2 startup options, it is also very simple, such as saving to the specified server.log, just use the following code
const winston = require('winston')
const path = require('path')
const logger = winston.createLogger({
transports: [
new winston.transports.Console(),
new winston.transports.File({filename: path.resolve(__dirname, '.. /logs/server.log')})
]
})
logger.info('print to the console and the file')
Copy the code
The above is using the Winston built-in storage/output mechanism (TranSports) :
- Console: Console transmission
- File: indicates File transfer
In addition to the built-in TranSports
- Http:
http
transmission - Stream: indicates Stream transmission
Custom transports
You can write your own log method that inherits from the Winston.transport class and implements it
const Transport = require('winston-transport');
const util = require('util');
module.exports = class YourCustomTransport extends Transport {
constructor(opts) {
super(opts);
}
log(info, callback) {
setImmediate(() = > {
this.emit('logged', info); }); callback(); }};Copy the code
Log files are sliced (flipped) by time
Install the log rollover component
npm install winston-daily-rotate-file
const dailyRotateFile = require('winston-daily-rotate-file');
const dateTransport = new dailyRotateFile({
filename: path.resolve(__dirname, './logs/server.log'),
maxSize: '50m'.createSymlink: true.symlinkName: 'server.log'
})
const logger = winston.createLogger({
transports: [
dateTransport
]
});
Copy the code
MaxSize is the maximum size of the file after rotation. The units are K (KB), m(MB), g(GB).
You get the file server.log.2021.01.28
Can be obtained when the log file size is greater than maxSize
Server.log.2021.01.28.1, server.log.2021.01.28.2, server.log.2021.01.29…
When createSymlink is true, a symbolic link is created to the current active log file from the specified name (symlinkName)
Convenient ELK scanning
Log desensitization
In order to comply with the national protection level 3 regulations, the user privacy information in the log file must be encrypted, such as mobile phone number, ID card and so on
Use Winston’s custom formatting capabilities
That is, custom format is used at createLogger time
const { createLogger, format } = require('winston');
const util = require('util')
// Customize the format
const formatLog = format.printf(info= > {
// Logger. info('is info') info.message is info
const msg = info.message;
// logger.info('my name is %s, my personal information is %s', 'xiaolin',{ name: 'xiaolin', phone: '15811111111' })
// info[SPLAT] = 'xiaolin' and {name: 'xiaolin', phone: '15811111111'
if (typeof (msg) === 'string' && msg.includes('%s')) {// Compatible with old logs (format)
const splat = info[SPLAT] || info.splat || [];
// Desensitize the object
const splatInfo = splat.map(item= > {
if (typeof item === 'object') {
// encryptionLog (encryptionLog) encryptionLog (encryptionLog) // encryptionLog (encryptionLog
return util.inspect(encryptionLog(item), false.null)}returnitem }) info.message = util.format(msg, ... splatInfo);// String interpolation
}
// Info.timestamp is the value taken by the built-in formatting plugin format.timestamp
const finalLog = ` [${info.timestamp}] [${info.level}] ${info.message}`
return finalLog
})
exports.businessLog = createLogger({
format: format.combine(
format.timestamp({
format: 'YYYY-MM-DD HH:mm:ss'
}),
formatLog
)
});
Copy the code
Attached is desensitization I wrote myself
Here is my own simple desensitization rules, that is, to log in the object for desensitization
const encryRules = require('./encryRules').encryRules
/** * log desensitization for deep copy */ PS: desensitization for deep copy */
const encryptionLog = (splat, keyName) = > {
if (splat === null) return splat;
if (splat instanceof Date) return new Date(splat);
if (splat instanceof RegExp) return new RegExp(splat);
if (typeofsplat ! = ="object") {
if (encryRules.rules.hasOwnProperty(keyName)) {
// Match rules for regular desensitization
return encryRules.rules[keyName](splat)
}
return splat
};
let cloneSplat = new splat.constructor();
for (let key in splat) {
if (splat.hasOwnProperty(key)) {
// Recursive copycloneSplat[key] = encryptionLog(splat[key], key); }}return cloneSplat;
}
Copy the code
Encryption Rules (encryrules.js)
const regularEncrypt = (str, ruleName) = > {
if(str ! =null&& str ! =undefined) {
switch (ruleName) {
case 'phone':// phone
return String(str).replace(/(\d{3})\d{4}(\d{4})/g.'$1 $2 * * * *')
case 'email':/ / email
return str.replace(/ / / ^ @ *).word= > {
word.slice(0.3) + word.slice(3).replace(/.{1}/g.The '*')}}}return str
}
const encryptPhone = (str) = > regularEncrypt(str, 'phone')// Phone number desensitization
const encryptEmail = (str) = > regularEncrypt(str, 'email')// Desensitization of mailbox
// Rule object
const rules = {
phone: encryptPhone,
email: encryptEmail
}
exports.encryRules = {
rules
}
Copy the code
The last
The above features are sufficient for general scenarios 🤪. For Winston’s other features, I will not describe them here. For details, please go to Github to check the relevant documentation.
Finally, I hope you can give me a thumbs-up, MUA ~