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有如下优点:
提供了可扩展的多种日志记录方式;
提供了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则是一种用来区分不同场景中交替出现的日志的手段。
应用时的大概流程:
- 定义一个logout类对象,确定输出日志信息的格式
- 定义一个appender类对象,确定日志输出到什么地方,然后把layout对象用setlayout方法绑定一下
- 定义一个category对象,与appender类对象绑定
- 调用category对象进行写日志
Category、Appender 和 Layout 三者的关系如下:
系统中可以有多个 Category,它们都是继承自同一个根,每个 Category 负责记录自己的日志
每个 Category 可以添加多个 Appender,每个 Appender 指定了一个日志的目的地,比如文件、网络、终端
当 Category 记录一条日志时,该复制被写入到所有附加到此Category的Appender
每个 Appender 都包含一个 Layout,该 Layout 定义了这个 Appender 上日志的格式(一个布局仅能绑定一个appender对象)
实现
文件: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)