共享单车(二):项目日志

stdin, stdout, stderr

Linux系统下,当一个用户进程被创建时,与之对应的三个数据流(stdin,stdout和stderr,即三个文件)也会被创建。

stdin,标准输入文件,通常对应着终端的键盘。
stdout,标准输出文件,通常对应着终端的屏幕。
stderr,标准错误输出文件,通常对应着终端的屏幕。

默认情况下,三个数据流对应的文件描述符分别是stdin---0,stdout---1,stderr---2

cpp 复制代码
#include <stdio.h>

int main(){
	fprintf(stdout, "hello");
	fprintf(stderr, "world");
	return 0;
}

程序运行结果:

cpp 复制代码
worldhello

stdout 存在一个缓冲区 ,它的输出会先放在缓冲区里面,遇到换行或者缓冲区刷新时 才会输出到屏幕上。而 stderr 不存在缓冲区,也就是说 stderr 的输出内容会直接打印在屏幕上。所以会出现上面的输出结果。

重定向

为了有效地让 Linux 程序协同工作,我们需要对命令输入输出进行重定向(Redirection),并将一个命令的输出通过管道(Pipes)连接到另一个程序的输入。

命令 说明
command > file 将输出重定向到 file
command < file 将输入重定向到 file
command >> file 将输出以追加的方式重定向到 file
n > file 将文件描述符为 n 的文件重定向到 file
n >> file 将文件描述符为 n 的文件以追加的方式重定向到 file
n >& m 将输出文件 m 和 n 合并
n <& m 将输入文件 m 和 n 合并
<< tag 将开始标记 tag 和结束标记 tag 之间的内容作为输入

原文链接:linux操作:重定向

Log4cpp

Log4cpp是一个开源的C++类库,它提供了在C++程序中使用日志和跟踪调试的功能。

日志库log4cpp剖析:日志记录和框架分析

Log4cpp有如下优点:

提供了可扩展的多种日志记录方式;

提供了NDC(嵌套诊断上下文),可用于多线程、多场景的跟踪调试;

提供了完整的日志动态优先级控制,可随时调整需要记录的日志优先级

可通过配置文件完成所有配置并动态加载;

性能优秀,内存占用小,经过编译后的log4cpp.dll大小仅有160kb;

代码级的平台无关性,Log4cpp源代码经过编译后,适用于大多数主流的操作系统和开发工具;

概念清晰,学习和使用方便,熟练程序员一天之内即可很好地应用log4cpp进行开发。

下载安装:

bash 复制代码
wget https://nchc.dl.sourceforge.net/project/log4cpp/log4cpp-1.1.x%20%28new%29/log4cpp-1.1/log4cpp-1.1.3.tar.gz
tar xzvf log4cpp-1.1.3.tar.gz
cd log4cpp-1.1.3
./configure --with-pthreads
./configure
make
make install

log4cpp库中主要分三大类:Category(种类)、Appender(附加目的地)、Layout(布局)
category类 是日志记录的主要执行类,相当于log4j中的Logger,它负责写日志,就是执行debug(Object msg)、info(Object msg)、warn(Object msg)、error(Object msg)等方法。
appender类 用来指明目的地,即日志要写到什么地方去。log4cpp已经实现了多种不同目标的输出方式,可以向文件输出日志、向控制台输出日志、向Socket输出日志等。

appender有以下这些:

cpp 复制代码
log4cpp::FileAppender // 输出到文件
log4cpp::RollingFileAppender // 输出到回卷文件,即当文件到达某个大小后回卷
log4cpp::OstreamAppender // 输出到一个ostream类
log4cpp::RemoteSyslogAppender // 输出到远程syslog服务器
log4cpp::StringQueueAppender // 内存队列
log4cpp::SyslogAppender // 本地syslog
log4cpp::Win32DebugAppender // 发送到缺省系统调试器
log4cpp::NTEventLogAppender // 发送到win 事件日志

layout类 指明日志输出的格式

日志输出格式控制有: PatternLayout supports following set of format characters:

cpp 复制代码
%% - a single percent sign
%c - the category
%d - the date\n Date format: The date format character may be followed by a date format specifier enclosed between braces. For example, %d{%\H:%M:%S,%l} or %d{%\d %m %Y %H:%\M:%S,%l}. If no date format specifier is given then the following format is used: "Wed Jan 02 02:03:55 1980". The date format specifier admits the same syntax as the ANSI C function strftime, with 1 addition. The addition is the specifier %l for milliseconds, padded with zeros to make 3 digits.
%m - the message
%n - the platform specific line separator
%p - the priority
%r - milliseconds since this layout was created.
%R - seconds since Jan 1, 1970
%u - clock ticks since process start
%x - the NDC
%t - thread name
By default, ConversionPattern for PatternLayout is set to "%m%n".

此外还有Priority(优先级)和NDC(嵌套的诊断上下文)等。
Priority 被用来指定Category的优先级和日志的优先级

日志的级别总共有:NOTSET < DEBUG < INFO < NOTICE < WARN < ERROR < CRIT < ALERT < FATAL = EMERG日志级别的意思是低于该级别的日志不会被记录

NDC则是一种用来区分不同场景中交替出现的日志的手段。

应用时的大概流程:

  1. 定义一个logout类对象,确定输出日志信息的格式
  2. 定义一个appender类对象,确定日志输出到什么地方,然后把layout对象用setlayout方法绑定一下
  3. 定义一个category对象,与appender类对象绑定
  4. 调用category对象进行写日志

Category、Appender 和 Layout 三者的关系如下:

系统中可以有多个 Category,它们都是继承自同一个根,每个 Category 负责记录自己的日志

每个 Category 可以添加多个 Appender,每个 Appender 指定了一个日志的目的地,比如文件、网络、终端

当 Category 记录一条日志时,该复制被写入到所有附加到此Category的Appender

每个 Appender 都包含一个 Layout,该 Layout 定义了这个 Appender 上日志的格式(一个布局仅能绑定一个appender对象)

C/C++编程:log4cpp使用学习

实现

文件:conf/log.conf

bash 复制代码
#定义Root category的属性
log4cpp.rootCategory=DEBUG, RootLog
#定义RootLog属性
log4cpp.appender.RootLog=RollingFileAppender
log4cpp.appender.RootLog.layout=PatternLayout
#log4cpp.appender.RootLog.layout.ConversionPattern=%d{% m-%d %H:%M:%S %l} [%t][%p]%m%n
log4cpp.appender.RootLog.layout.ConversionPattern=%d{%m-%d %H:%M:%S %l} [%t][%p]%m%n
log4cpp.appender.RootLog.fileName=/home/feng/文档/feng/cppCode/shared_bike/log/shared_bike.log
log4cpp.appender.RootLog.maxFileSize=268435456 #256MB
log4cpp.appender.RootLog.fileNamePattern=shared_bike_%i.log
log4cpp.appender.RootLog.maxBackupIndex=256

文件:src/common/CMakeLists.txt

将 Log4cpp 添加:

bash 复制代码
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

# 搜集所有在指定路径下的源文件的文件名,将输出结果列表储存在指定的变量中
aux_source_directory(. SOURCE_COMMON_FILES)

# add_ 1 ibrary (<name>[ STATIC | SHARED |MODULE] [ EXCLUDE_FROM_ALL] sourcel [source2...])
# 构建库供他人模块使用
ADD_LIBRARY(common ${SOURCE_COMMON_FILES})

# 用来显式的定义变量
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic -Wall -m64 -pipe -std=c++0x -lrt -Wno-reorder -Wdeprecated-declarations")

# 将指定目录添加到编译器的头文件搜索路径之下
INCLUDE_DIRECTORIES(../../third/include)

# 将指定目录添加到需要链接的库文件目录之下
LINK_DIRECTORIES(../../third/lib/iniparser)
LINK_DIRECTORIES(../../third/lib/log4cpp)

# 该指令的作用为将目标文件与库文件进行链接
TARGET_LINK_LIBRARIES(common iniparser)
TARGET_LINK_LIBRARIES(common log4cpp)
TARGET_LINK_LIBRARIES(common dl)

cmake

文件:src/main.cpp

bash 复制代码
#include <iostream>
#include "iniconfig.h"
#include "configdef.h"

#include "Logger.h"


//shared_bike.exe conf/shared_bike.ini
int main(int argc, char const *argv[]){
    if(argc !=3){
        std::cout <<"Please input shared_bike <config file path> <log file config> !"<<std::endl;
        return -1;
    }

    if(!Logger::instance()->init(std::string(argv[2]))){
        fprintf(stderr, "init log module failed.\n");
        return -2;
    }

    Iniconfig config;
    if(!config.loadfile(std::string(argv[1]))){
        std::cout <<"Load "<< argv[1] << "failed!" << std::endl;
        LOG_ERROR("Load %s failed.", argv[1]); // Logger::instance()->GetHandle()->error
        return -3;
    }

    st_env_config conf_args = config.getconfig();

    std::cout <<"[database] ip: "<<conf_args.db_ip.c_str()<<std::endl;
    std::cout <<"[database] port: "<<conf_args.db_port<<std::endl;
    std::cout <<"[database] user: "<<conf_args.db_user.c_str()<<std::endl;
    std::cout <<"[database] pwd: "<<conf_args.db_pwd.c_str()<<std::endl;

    std::cout <<"[server] port: "<<conf_args.svr_port<<std::endl;

    LOG_INFO("[database] ip:%s  port:%d  user:%s pwd:%s db:%s [server]port:%d\n",
		conf_args.db_ip.c_str(),conf_args.db_port,
		conf_args.db_user.c_str(),conf_args.db_pwd.c_str(),
		conf_args.db_name.c_str(),conf_args.svr_port);

    
    return 0;
}

文件:src/CMakeLists.txt

bash 复制代码
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

# project name
PROJECT(shared_bike)

# 将指定目录添加到编译器的头文件搜索路径之下
INCLUDE_DIRECTORIES(../third/include)
INCLUDE_DIRECTORIES(./common)

# 将指定目录添加到需要链接的库文件目录之下
LINK_DIRECTORIES(../third/lib/iniparser)
LINK_DIRECTORIES(../third/lib/log4cpp)
LINK_DIRECTORIES(./common)

# 搜集所有在指定路径下的源文件的文件名,将输出结果列表储存在指定的变量中
# 内置变量: CMAKE_SOURCE_DIR 定义了顶级 CMakeLists.txt 所在的文件夹,PROJECT_SOURCE_DIR 定义了包含最近的 project() 命令的 CMakeLists.txt 所在的文件夹
aux_source_directory(${PROJECT_SOURCE_DIR} SOURCE_FILES)

# 使用给定的源文件,为工程引入一个可执行文件
ADD_EXECUTABLE(shared_bike ${SOURCE_FILES})

# 用来显式的定义变量
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic -Wall -m64 -pipe -std=c++0x -lrt -Wno-reorder -Wdeprecated-declarations")

TARGET_LINK_LIBRARIES(shared_bike iniparser)
TARGET_LINK_LIBRARIES(shared_bike log4cpp)
# TARGET_LINK_LIBRARIES(${PROJECT_NAME} liblog4cpp.a) //replace
TARGET_LINK_LIBRARIES(shared_bike pthread)
TARGET_LINK_LIBRARIES(shared_bike common)

# 增加子目录
ADD_SUBDIRECTORY(common)

SET(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR})
INSTALL(TARGETS shared_bike DESTINATION bin)
相关推荐
Beau_Will4 分钟前
数据结构-树状数组专题(1)
数据结构·c++·算法
迷迭所归处8 分钟前
动态规划 —— 子数组系列-单词拆分
算法·动态规划
爱吃烤鸡翅的酸菜鱼8 分钟前
Java算法OJ(8)随机选择算法
java·数据结构·算法·排序算法
哎呦喂-ll31 分钟前
Linux进阶:环境变量
linux
Rverdoser32 分钟前
Linux环境开启MongoDB的安全认证
linux·安全·mongodb
hunandede36 分钟前
av_image_get_buffer_size 和 av_image_fill_arrays
c++
PigeonGuan43 分钟前
【jupyter】linux服务器怎么使用jupyter
linux·ide·jupyter
寻找码源1 小时前
【头歌实训:利用kmp算法求子串在主串中不重叠出现的次数】
c语言·数据结构·算法·字符串·kmp
Matlab精灵1 小时前
Matlab科研绘图:自定义内置多款配色函数
算法·matlab