「项目复现」Web服务器编程之简易日志模块
[TOC]
本文总结作者学习的Web服务器项目(WebServer),分析其中的主要模块的作用及相关知识点。一个WebServer是一个运行在linux系统上的C++编码的服务器程序,其需要处理来自浏览器程序(客户端)的各种HTTP请求,并对其请求作出HTTP响应。
从上述图中可以看出其中共有7个模块:日志系统模块、监听套接字模块、IO复用模型epoll模块、线程池模块、数据库连接池模块、HTTP连接模
一、日志模块的作用
1、对于程序来讲
日志模块用来程序执行的过程,帮助开发人员了解程序的运行情况,以便快速维护和调试。
2、对程序员来讲
日志模块提供几个输出日志信息的接口(API),该接口的输入参数可能有:日志等级、日志输出平台。
日志等级:info、debug、warning、error。可以标记日志信息的重要程度,控制不同等级的日志信息的输出
日志输出平台:文件、控制台
二、日志模块的实现
1、设置为单例模式
为什么要将日志模块的输出类设置为单例模式:日志模块需要在程序的任何地方被调用,且最好只有一个对象
2、格式化输出
日志输出本质上是对printf()函数的封装。
日志输出信息一般格式:日志等级+时间戳+格式化输出信息
C++的日志模块如何实现格式化输出?
(1)C++的函数的可变参数列表
C++允许定义形参个数和类型不确定的函数,不确定的形参可以使用可变参数列表。
(2)C++的vprintf()函数
vprintf(format,args);
vprintf()作用和printf()相同, 参数format 格式也相同。
printf
底层就是调用 vprintf
函数来将内容输出到控制台的,常规情况下,输出到控制台,多数情况下使用 printf
函数即可。当你需要自己写一个自定义 printf
函数时候才需要 vprintf
函数
vprintf
函数一般和 va_start
/ va_end
配套使用;
(3)宏和可变参数宏
为了更加方便地调用日志类的输出函数,我们需要将其经常定义为宏。
在C++中经常使用#define来定义宏:
1 |
宏在调用时进行宏替换,宏替换发生在静态编译期,是简单的文本替换,例如
1 | int a=AREA(2+2);//a=8,不等于16,AREA(2+2)等价于2+2*2+2 |
带参数的宏也经常被叫做宏函数,但是宏函数不是真正的函数,其发生在静态编译期,是简单的文本替换。
由于输出函数可能使用了可变参数列表,这时我们就要使用可变参数宏__VA_ARGS__
可变参数宏的定义如下:
1 |
其中,...
代表一个可以变化的参数表。使用保留名 VA_ARGS 把参数传递给宏。例如:
1 | // 调用宏,因为DEBUG()是可变参数宏,所以传递不同个数的参数 |
3、日志等级
(1)C++中的enum的使用
枚举类型(enumeration)是 C++ 中的一种派生数据类型,它是由用户定义的若干枚举常量的集合。
应用举例:
1 | enum color_set1 {RED, BLUE, WHITE, BLACK}; // 定义枚举类型color_set1 |
枚举常量代表该枚举类型的变量可能取的值,编译系统为每个枚举常量指定一个整数值,默认状态下,这个整数就是所列举元素的序号,序号从0开始。 可以在定义枚举类型时为部分或全部枚举常量指定整数值,在指定值之前的枚举常量仍按默认方式取值,而指定值之后的枚举常量按依次加1的原则取值。 各枚举常量的值可以重复。例如:
1 | enum fruit_set {apple, orange, banana=1, peach, grape} |
枚举常量只能以标识符形式表示,而不能是整型、字符型等文字常量。例如,以下定义非法:
1 | enum letter_set {'a','d','F','s','T'}; //枚举常量不能是字符常量 |
可改为以下形式则定义合法:
1 | enum letter_set {a, d, F, s, T}; |
枚举类型的使用:
定义枚举类型之后,就可以定义该枚举类型的变量,如:
1 | color_set1 color1, color2; |
亦可类型与变量同时定义(甚至类型名可省),格式如下:
1 | enum {Sun,Mon,Tue,Wed,Thu,Fri,Sat} weekday1, weekday2; |
3、日志输出平台
(1)C++的写入文件
1 |
|