winston日志框架

winston是一个简单、通用的日志库,支持多种传输。传输是一个存储设备。每个winston日志可以有多个不同日志级别的传输.

winston目的是解耦日志处理,使得更自由及易扩展。关注点在日志格式、日志级别上更灵活,保证了这些api与传输日志解耦。

1、日志

日志级别有

const levels = {
error:0,
warn:1,
info:2,
http:3,
verbose:4,
debug:5,
silly:6
};

1.1 创建日志

const logger = winston.createLogger({
    transports:[
        new winston.transports.Console(),
        new winston.transports.File({filename:'combined.log'})
    ]
});

创建日志时支持下面的参数

名称默认值说明
level'info'当info.level小于或者等于此level时才输出日志
levelswinston.config.npm.levels表示日志优先级的级别
formatwinston.format.json格式化info消息
transports[]设置info消息的日志输出位置
exitOnErrortrue如果为false,处理异常不会导致process.exit
silentfalse如果为true,所有日志被抑制

提供给createLogger的日志级别会定义为返回的logger的方法。

logger.log({
    level:'info',
    message:'Hello distributed log files!'
});

logger.info('Hello distributed log files!');

一旦通过winston.createLogger创建logger后,可以添加或者删除transports

const files = new winston.transports.File({filename:'combined.log'});
const console = new winston.transports.Console();

logger
    .clear()
    .add(console)
    .add(files)
    .remove(console);

也可以通过configure方法重新配置winston.Logger实例

const logger = winston.createLogger({
    level:'info',
    transports:[
        new winston.transports.Console(),
        new winston.transports.File({filename:'combined.log'})
    ]
});

const DailyRotateFile = require('winston-daily-rotate-file');
logger.configure({
    level:'verbose',
    transports:[
        new DailyRotateFile(opts)
    ]
});

通过已有的日志传递元数据覆盖创建子日志

 const logger = winston.createLogger({
    transports:[
        new winston.transports.Console()
    ]
});

const childLogger = logger.child({requestId:'451'});

1.2 Streams, objectMode和Info对象

在winston中,Logger和Transport实例被当作objectMode流,接受info对象。

info参数表示一个日志消息,对象本身是可变的,每个info至少要包含level和message属性。

const info = {
    level:'info',
    message:'Hey! Log something?'
};

除了level和message之外的属性认为是meta元数据

const {level, message, ...meta} = info;

logform中的几种格式添加了另外的属性

属性由哪个格式添加说明
splatsplat()%d%s样式消息的字符串插值splat
timestamptimestamp()接受到消息的时间戳
labellabel()自定义关联消息的标签
msms()自上一个日志消息以来的毫秒数

你可以任意添加属性,内部状态通过Symbol属性来获取。

  • Symbol.for('level'):相当于level属性,不可修改
  • Symbole.for('message'):完整的由最终格式的消息
  1. json
  2. logstash
  3. printf
  4. prettyPrint
  5. simple
  • Symbol.for('splat'):另外的字符串插值参数。

Symbols存储在triple-beam库中。

2、格式

winston中的格式可以通过winston.format访问。在logform中实现,一个单独的源于winston的模块。这允许在编写自己的传输时具有灵活性,以防您希望在传输中包含默认格式。在node当前版本中,模板字符串是性能比较好的,在作用户端格式化时是推荐的方式。如果你想定制你的日志格式,使用winston.format.printf

const {createLogger, format, transports} = require('winston');
const {combine, timestamp, label, printf} = format;

const myFormat = printf(({level, mesage, label, timestamp}) => {
    return `${timestamp}[${label}]${level}:${message}`;
});

const logger = createLogger({
    format:combine(
        lable({label:'right meow!'}),
        timestamp(),
        myFormat
    ),
    transports:[new transports.Console()]
});

2.1 合并格式

多个格式通过format.combine合并成一个格式。由于format.combine不接受选项,因此为了方便起见,它会返回预先创建的组合格式实例。

const {createLogger, format, transports} = require('winston');
const {combine, timestamp, label, prettyPrint} = format;

const logger = createLogger({
    format:combine(
        lable({label:'right meow!'}),
        timestamp(),
        prettyPrint()
    ),
    transports:[new transports.Console()]
});

logger.log({
    level:'info',
    message:'What time is the testing at?'
});

2.2 字符串插值

log方法使用util.formt提供字符串插值。必须使用format.splat()来开启

const { createLogger, format, transports } = require('winston');
const logger = createLogger({
  format: format.combine(
    format.splat(),
    format.simple()
  ),
  transports: [new transports.Console()]
});

// info: test message my string {}
logger.log('info', 'test message %s', 'my string');

// info: test message 123 {}
logger.log('info', 'test message %d', 123);

// info: test message first second {number: 123}
logger.log('info', 'test message %s, %s', 'first', 'second', { number: 123 });

2.3 过滤info对象

如果希望过滤掉info对象,只需要返回false值

const { createLogger, format, transports } = require('winston');

// Ignore log messages if they have { private: true }
const ignorePrivate = format((info, opts) => {
  if (info.private) { return false; }
  return info;
});

const logger = createLogger({
  format: format.combine(
    ignorePrivate(),
    format.json()
  ),
  transports: [new transports.Console()]
});

// Outputs: {"level":"error","message":"Public error to share"}
logger.log({
  level: 'error',
  message: 'Public error to share'
});

// Messages with { private: true } will not be written when logged.
logger.log({
  private: true,
  level: 'error',
  message: 'This is super secret - hide it.'
});

2.4 自定义格式

格式是定义单个方法的原型对象,方法为transform(info,opts),返回可变的info

  • info:表示日志消息的对象
  • opts:指定当前格式实例的设置。

返回值有两种情况:

  • info 对象,表示可修改的info参数。
  • false值,表示info参数会被当前调用者忽略

 winston.format设计的足够简单,定义一个新的格式,只需要传递一个transform(info,opts)函数给format得到一个新的格式。

const { format } = require('winston');

const volume = format((info, opts) => {
  if (opts.yell) {
    info.message = info.message.toUpperCase();
  } else if (opts.whisper) {
    info.message = info.message.toLowerCase();
  }

  return info;
});

// `volume` is now a function that returns instances of the format.
const scream = volume({ yell: true });
console.dir(scream.transform({
  level: 'info',
  message: `sorry for making you YELL in your head!`
}, scream.options));
// {
//   level: 'info'
//   message: 'SORRY FOR MAKING YOU YELL IN YOUR HEAD!'
// }

// `volume` can be used multiple times to create different formats.
const whisper = volume({ whisper: true });
console.dir(whisper.transform({
  level: 'info',
  message: `WHY ARE THEY MAKING US YELL SO MUCH!`
}, whisper.options));
// {
//   level: 'info'
//   message: 'why are they making us yell so much!'
// }

3、日志级别

winston中的日志级别遵循rfc5424。每个级别给定一个整数权值。权值越高,消息越重要。

如果没有显示指定 日志级别,使用的是npm级别。

3.1 使用日志级别

设置日志消息级别可以使用两种方式,一种是传递表示日志级别的字符串给log方式,或者使用指明级别的方法

//
// Any logger instance
//
logger.log('silly', "127.0.0.1 - there's no place like home");
logger.log('debug', "127.0.0.1 - there's no place like home");
logger.log('verbose', "127.0.0.1 - there's no place like home");
logger.log('info', "127.0.0.1 - there's no place like home");
logger.log('warn', "127.0.0.1 - there's no place like home");
logger.log('error', "127.0.0.1 - there's no place like home");
logger.info("127.0.0.1 - there's no place like home");
logger.warn("127.0.0.1 - there's no place like home");
logger.error("127.0.0.1 - there's no place like home");

//
// Default logger
//
winston.log('info', "127.0.0.1 - there's no place like home");
winston.info("127.0.0.1 - there's no place like home");

winston允许你为每个传输定义level属性来指明传输日志的最高消息级别。例如,使用syslog级别日志,仅仅将error级别消息输出到控制台,info级别及以下的输出到文件。

const logger = winston.createLogger({
  levels: winston.config.syslog.levels,
  transports: [
    new winston.transports.Console({ level: 'error' }),
    new winston.transports.File({
      filename: 'combined.log',
      level: 'info'
    })
  ]
});

也可以动态修改传输的日志级别

const transports = {
  console: new winston.transports.Console({ level: 'warn' }),
  file: new winston.transports.File({ filename: 'combined.log', level: 'error' })
};

const logger = winston.createLogger({
  transports: [
    transports.console,
    transports.file
  ]
});

logger.info('Will not be logged in either transport!');
transports.console.level = 'info';
transports.file.level = 'info';
logger.info('Will be logged in both transports!');

3.2 自定义日志级别

除了预先定义的npm,syslgo,cli级别外,也可以自定义。

const myCustomLevels = {
  levels: {
    foo: 0,
    bar: 1,
    baz: 2,
    foobar: 3
  },
  colors: {
    foo: 'blue',
    bar: 'green',
    baz: 'yellow',
    foobar: 'red'
  }
};

const customLevelLogger = winston.createLogger({
  levels: myCustomLevels.levels
});

customLevelLogger.foobar('some foobar level-ed message');

如果希望有颜色,除了传递levels到日志外,还需要添加颜色

winston.addColors(myCustomLevels.colors);

通过上面方法使得日志可以使用 colorize格式。

另外,也可以修改背景颜色、字体样式。

baz: 'italic yellow',
foobar: 'bold red cyanBG'

可用的选项如下

  • 字体样式:bold, dim,italic, underline, inverse, hidden, strikethrough
  • 字体背景颜色:black,red,green,yellow,blue, magenta,cyan,white,gray,grey
  • 背景颜色:blackBG,redBG,greenBG,yellowBG,blueBG,magentaBG,cyanBG,whiteBG

给标准的日志级别添加颜色

winston.format.combine(
  winston.format.colorize(),
  winston.format.json()
);

4、传输

4.1 同一类型的多个传输

有可能对同一个类型使用多个传输

const logger = winston.createLogger({
  transports: [
    new winston.transports.File({
      filename: 'combined.log',
      level: 'info'
    }),
    new winston.transports.File({
      filename: 'errors.log',
      level: 'error'
    })
  ]
});

如果后面想删除其中的一个传输,可以使用下面方法

const combinedLogs = logger.transports.find(transport => {
  return transport.filename === 'combined.log'
});

logger.remove(combinedLogs);

4.2 添加自定义传输

需要做的是接受你需要的选项,实现log方法。

const Transport = require('winston-transport');
const util = require('util');

//
// Inherit from `winston-transport` so you can take advantage
// of the base functionality and `.exceptions.handle()`.
//
module.exports = class YourCustomTransport extends Transport {
  constructor(opts) {
    super(opts);
    //
    // Consume any custom options here. e.g.:
    // - Connection information for databases
    // - Authentication information for APIs (e.g. loggly, papertrail, 
    //   logentries, etc.).
    //
  }

  log(info, callback) {
    setImmediate(() => {
      this.emit('logged', info);
    });

    // Perform the writing to the remote service
    callback();
  }
};

4.3 传输选项

每个传输继承自winston-transport,可以在每个传输设置自定义格式 及日志级别

const logger = winston.createLogger({
  transports: [
    new winston.transports.File({
      filename: 'error.log',
      level: 'error',
      format: winston.format.json()
    }),
    new transports.Http({
      level: 'warn',
      format: winston.format.json()
    }),
    new transports.Console({
      level: 'info',
      format: winston.format.combine(
        winston.format.colorize(),
        winston.format.simple()
      )
    })
  ]
});

5、异常

5.1 处理未捕获异常

winston可以捕获和记录异常。通过日志实例,可以在创建时或者以后开启这个行为

const { createLogger, transports } = require('winston');

// Enable exception handling when you create your logger.
const logger = createLogger({
  transports: [
    new transports.File({ filename: 'combined.log' }) 
  ],
  exceptionHandlers: [
    new transports.File({ filename: 'exceptions.log' })
  ]
});

// Or enable it later on by adding a transport or using `.exceptions.handle`
const logger = createLogger({
  transports: [
    new transports.File({ filename: 'combined.log' }) 
  ]
});

// Call exceptions.handle with a transport to handle exceptions
logger.exceptions.handle(
  new transports.File({ filename: 'exceptions.log' })
);

如果想在默认日志上使用这个特征,简单调用.exceptions.handle()推荐传输实例

//
// You can add a separate exception logger by passing it to `.exceptions.handle`
//
winston.exceptions.handle(
  new winston.transports.File({ filename: 'path/to/exceptions.log' })
);

//
// Alternatively you can set `handleExceptions` to true when adding transports
// to winston.
//
winston.add(new winston.transports.File({
  filename: 'path/to/combined.log',
  handleExceptions: true
}));

5.2 退出还是不退出

默认情况下,winston在记录一个异常时会退出。可以通过设置exitOnError=false来不退出。

const logger = winston.createLogger({ exitOnError: false });

//
// or, like this:
//
logger.exitOnError = false;

当使用自定义日志实例时,你可以传递exceptionHandlers属性给单独的传输或者在任意传输上设置handleExceptions

const logger = winston.createLogger({
  transports: [
    new winston.transports.File({ filename: 'path/to/combined.log' })
  ],
  exceptionHandlers: [
    new winston.transports.File({ filename: 'path/to/exceptions.log' })
  ]
});
或者
const logger = winston.createLogger({
  transports: [
    new winston.transports.Console({
      handleExceptions: true
    })
  ],
  exitOnError: false
});

exitOnError选项也有可能是一个函数来防止在特定的错误类型上退出

function ignoreEpipe(err) {
  return err.code !== 'EPIPE';
}

const logger = winston.createLogger({ exitOnError: ignoreEpipe });

//
// or, like this:
//
logger.exitOnError = ignoreEpipe;

6、拒绝

6.1 处理未经批准的拒绝承诺

可能捕获uncaughtRejection事件。使用日志实例可以在创建时或者以后开启此行为

const { createLogger, transports } = require('winston');

// Enable rejection handling when you create your logger.
const logger = createLogger({
  transports: [
    new transports.File({ filename: 'combined.log' }) 
  ],
  rejectionHandlers: [
    new transports.File({ filename: 'rejections.log' })
  ]
});

// Or enable it later on by adding a transport or using `.rejections.handle`
const logger = createLogger({
  transports: [
    new transports.File({ filename: 'combined.log' }) 
  ]
});

// Call rejections.handle with a transport to handle rejections
logger.rejections.handle(
  new transports.File({ filename: 'rejections.log' })
);

如果想使用默认日志的特征,调用.rejections.handle()携带传输实例

//
// You can add a separate rejection logger by passing it to `.rejections.handle`
//
winston.rejections.handle(
  new winston.transports.File({ filename: 'path/to/rejections.log' })
);

//
// Alternatively you can set `handleRejections` to true when adding transports
// to winston.
//
winston.add(new winston.transports.File({
  filename: 'path/to/combined.log',
  handleRejections: true
}));

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
Winston是一个非常流行的Node.js日志库,可以轻松地在Vue项目中使用它来记录日志。以下是在Vue项目中使用Winston的步骤: 1. 安装Winston:在终端中使用以下命令安装Winston: ``` npm install winston ``` 2. 创建一个日志文件:在你的Vue项目根目录下创建一个logs文件夹,并在其中创建一个名为app.log的日志文件。 3. 创建Winston实例:在你的Vue项目中创建一个名为logger.js的文件,并在其中创建一个Winston实例,配置日志记录器。以下是一个示例配置: ``` const winston = require('winston'); const path = require('path'); const logger = winston.createLogger({ level: 'info', format: winston.format.combine( winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.printf(info => `${info.timestamp} [${info.level.toUpperCase()}] ${info.message}`) ), transports: [ new winston.transports.File({ filename: path.join(__dirname, '../logs/app.log') }) ] }); module.exports = logger; ``` 此配置将日志记录级别设置为info,并将日志记录到我们之前创建的app.log文件中。它还使用了Winston的格式化选项,以便在日志中包含时间戳。 4. 在Vue组件中使用日志记录器:在Vue组件中导入logger.js文件,并在需要记录日志的地方使用logger实例。例如: ``` import logger from './logger'; export default { name: 'MyComponent', created() { logger.info('Component created'); }, methods: { handleClick() { logger.warn('Button clicked'); } } }; ``` 在此示例中,我们在组件的created钩子中记录了一条“Component created”消息,并在按钮的单击事件处理程序中记录了一条“Button clicked”消息。这些消息将被记录到我们之前创建的app.log文件中。 这就是在Vue项目中使用Winston记录日志的基本步骤。你可以根据需要调整Winston配置,以满足你的特定需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kgduu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值