DartVM服务器开发(五)-日志工具

今天我们来学习一下使用logging这个强大的日志工具库

1. 添加logging依赖

在项目根目录下的pubspec.yaml文件中添加logging的依赖

1
2
3
4
#....
dependencies:
http_server: ^0.9.8
logging: ^0.11.3+2

然后运行pub get命令
运行成功.png

2.初始化

导入logging这个包到你需要使用的dart文件中

1
import 'package:logging/logging.dart';

初始化logging工具

1
2
3
4
5
6
7
//监听器能监听的范围
Logger.root.level=Level.ALL;
//日志监听器
Logger.root.onRecord.listen((rec){
//rec的类为LogRecord
print('${rec.level}::${rec.time}::${rec.message}');
});

上面代码的level就是下面onRecord监听能覆盖的范围,我们传入ALL,就是全部的日志输出都监听,LogRecord是一个日志记录类,里面包换的日志的相关信息,我们来了解下这个类吧
| 类型 |参数|介绍|
| -| - | - |
| Level | level | 日志的覆盖范围(重要性相反):ALL>FINEST>FINER>FINE>CONFIG>INFO>WARNING>SEVERE>SHOUT>OFF |
| String | message | 日志消息 |
| Object | object | 非字符串日志消息|
| String | loggerName | 日志名字|
| DateTime | time | 日志时间|
| int | sequenceNumber | 唯一序列号|
| Object | error | 非字符串错误信息|
| StackTrace | stackTrace | 记录时的堆栈|
| Zone | zone | 日志所属区域 |
接下来,我们在服务器初始化后,输出一条日志

1
2
3
4
//....
var requestServer = await HttpServer.bind(InternetAddress.loopbackIPv6, 8080);
Logger.root.info('服务器启动:http://localhost:${requestServer.port}');
//....

然后运行我们的项目
image.png
可以看到我们成功的输出了一条日志,日志等级为Info
接下来,我们改一下初始化日志工具的等级

1
2
3
//...监听器只接受错误范围的信息
Logger.root.level=Level.WARNING;
//...

然后再次运行一下项目
可以看到没有记录消息.png
可以看到,日志监听没有接收到INFO的输出的日志,所以,只能接收WARNING以上的等级

3.记录日志输出到文件中

logging这个日志工具库,本质上是不帮你输出到文件的,所以,我们之前不是已经定义过一个记录到文件的方法嘛,下面是结合日志工具方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
   Logger.root.level=Level.ALL;
Logger.root.onRecord.listen((rec){
//基本的消息
String log='${rec.sequenceNumber}::${rec.level}::${rec.time}::${rec.message}';
//添加错误信息
if(rec.error!=null){
log+='\n::${rec.error}';
}
//添加错误的堆栈
if(rec.stackTrace!=null){
log+='\n::${rec.stackTrace.toString()}';
}
//输出日志到控制台
print(log);
//只记录等级大于等于info的信息
if(rec.level.value>=Level.INFO.value){
writeLog(log);
}
});

//.....
void writeLog(String log) async {
var date = DateTime.now();
var year = date.year;
var month = date.month;
var day = date.day;

//如果recursive为true,会创建命名目录及父级目录
Directory directory =
await new Directory('log/$year').create(recursive: true);

File file = new File('${directory.path}/$year-$month-$day.log');
file.exists().then((isExists) {
file.writeAsString(isExists ? '\n\n$log' : log, mode: FileMode.append);
});
}

4.记录异常

当发生异常时,我们可以把它记录下来,并输出到文件中,这个是很有必要的,在维护中,可以根据这个异常信息,去排查bug,下面介绍添加异常,及堆栈信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
staticFiles.errorPageHandler=(request){
if(request.uri.pathSegments.last.endsWith('.html')){
staticFiles.serveFile(new File(webPath+'/404.html'), request);
}else{
try{
handleMessage(request);
throw ArgumentError('Warning happen');
}catch(e){
try{
//有可能没有回复客户端,所以这里回复一次
request.response
..statusCode=HttpStatus.internalServerError
..close();
}catch(_){}
Logger.root.warning('请求消息发生异常',e,e.runtimeType==ArgumentError?e.stackTrace:null);
}
}
};

我这里手动触发一条异常,然后我们运行服务器,给服务器发送一条请求消息
异常.png

可以看到,我们的服务器产生了异常,异常详细的记录我们在哪里出现错误,我们再来看看日志文件
生成了日志文件了.png
生成了日志文件了,来看看里面的内容
异常文件.png

可以看到跟日志文件一样,接下来,来看一下我封装的日志工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import 'dart:io';
import 'package:logging/logging.dart';

class LogUt {
static LogUt log=new LogUt();
final Level level=Level.ALL;
LogUt(){
Logger.root..level=level
..onRecord.listen((rec){
//基本的消息
String log='${rec.sequenceNumber}::${rec.level}::${rec.time}::${rec.message}';
//添加错误信息
if(rec.error!=null){
log+='\n::${rec.error}';
}
//添加错误的堆栈
if(rec.stackTrace!=null){
log+='\n::${rec.stackTrace.toString()}';
}
print(log);

//只记录等级大于info的信息
if(rec.level.value>=Level.INFO.value){
writeLog(log);
}
});
}

void finest(message, [Object error, StackTrace stackTrace]) =>
Logger.root.log(Level.FINEST, message, error, stackTrace);

void finer(message, [Object error, StackTrace stackTrace]) =>
Logger.root.log(Level.FINER, message, error, stackTrace);

void fine(message, [Object error, StackTrace stackTrace]) =>
Logger.root.log(Level.FINE, message, error, stackTrace);

void config(message, [Object error, StackTrace stackTrace]) =>
Logger.root.log(Level.CONFIG, message, error, stackTrace);

void info(message, [Object error, StackTrace stackTrace]) =>
Logger.root.log(Level.INFO, message, error, stackTrace);

void warning(message, [Object error, StackTrace stackTrace]) =>
Logger.root.log(Level.WARNING, message, error, stackTrace);

void severe(message, [Object error, StackTrace stackTrace]) =>
Logger.root.log(Level.SEVERE, message, error, stackTrace);

void shout(message, [Object error, StackTrace stackTrace]) =>
Logger.root.log(Level.SHOUT, message, error, stackTrace);

}

void writeLog(String log) async {
var date = DateTime.now();
var year = date.year;
var month = date.month;
var day = date.day;

//如果recursive为true,会创建命名目录及父级目录
Directory directory =
await new Directory('log/$year').create(recursive: true);

File file = new File('${directory.path}/$year-$month-$day.log');
file.exists().then((isExists) {
file.writeAsString(isExists ? '\n\n$log' : log, mode: FileMode.append);
});
}

然后就可以通过导入该工具使用了,并且不用初始化,下面是使用

1
LogUt.log.finest('服务器启动:http://localhost:${requestServer.port}');

好了,今天的学习就到这里了,明天见!

评论系统未开启,无法评论!