C语言日志处理
一、简介
zlog是一个高可靠性、高性能、线程安全、灵活、概念清晰的纯C日志函数库,在效率、功能、安全性上大大超过了log4c,并且是用c写成的,具有比较好的通用性。
二、安装
下载
https://github.com/HardySimpson/zlog
https://github.com/HardySimpson/zlog/archive/latest-stable.tar.gz
https://github.com/downloads/HardySimpson/zlog/zlog-latest-stable.tar.gz
三、实例
参考:
源码目录:test,包括了大量使用示例,如下:
四、系统日志
参考:
示例:
#include <syslog.h>
int main(int argc, char **argv)
{
openlog("MyMsgMARK", LOG_CONS | LOG_PID, 0);
syslog(LOG_INFO,
"This is a syslog test message generated by program '%s'\n",
argv[0]);
closelog();
return 0;
}
编译
gcc -g -o test test.c
运行
五、Apache 日志处理分析
Apache通过调用ap_log_XXX函数进行日志记录,此处以ap_log_perror为例进行分析
Apache启动时通过httpd/modules/core/mod_so.c:load_module函数进行DSO模块加载,加载成功后将调用ap_log_perror函数记录模块加载日志
266 ap_log_perror(APLOG_MARK, APLOG_DEBUG, 0, cmd->pool, APLOGNO(01575)"loaded module %s from %s", modname, module_file);
ap_log_perror函数事实上是一个宏,定义在文件:/httpd/include/http_log.h,如下:
412 #define ap_log_perror ap_log_perror_
而ap_log_perror_函数实现在文件:httpd/server/log.c,代码如下:
1409 AP_DECLARE(void) ap_log_perror_(const char *file, int line, int module_index,
1410 int level, apr_status_t status, apr_pool_t *p,
1411 const char *fmt, ...)
1412 {
1413 va_list args;
1414
1415 va_start(args, fmt);
1416 log_error_core(file, line, module_index, level, status, NULL, NULL, NULL,
1417 p, fmt, args);
1418 va_end(args);
1419 }
函数log_error_core,逻辑如下:
1、判断请求结构r是否为NULL,若不为空则:c = r->connection
2、判断服务器结构s是否为NULL,若为空则:logf = stderr_log,此处s为NULL
3、填充结构日志info
4、调用do_errorlog_default函数拼接要写入日志的内容并暂存在buf中,并返回相应长度len
5、调用write_logline函数进行实际的日志输出
6、运行日志钩子error_log
static void log_error_core(const char *file, int line, int module_index,
int level,
apr_status_t status, const server_rec *s,
const conn_rec *c,
const request_rec *r, apr_pool_t *pool,
const char *fmt, va_list args)
{
char errstr[MAX_STRING_LEN];
apr_file_t *logf = NULL;
int level_and_mask = level & APLOG_LEVELMASK;
const request_rec *rmain = NULL;
core_server_config *sconf = NULL;
ap_errorlog_info info; /* do we need to log once-per-req or once-per-conn info? */
int log_conn_info = 0, log_req_info = 0;
apr_array_header_t **lines = NULL;
int done = 0;
int line_number = 0; if (r)
{
AP_DEBUG_ASSERT(r->connection != NULL);
c = r->connection;
} if (s == NULL)
{
/*
* If we are doing stderr logging (startup), don't log messages that are
* above the default server log level unless it is a startup/shutdown
* notice
*/
#ifndef DEBUG
if ((level_and_mask != APLOG_NOTICE)
&& (level_and_mask > ap_default_loglevel))
{
return;
}
#endif logf = stderr_log;
}
else
{
int configured_level = r ? ap_get_request_module_loglevel(r, module_index) :
c ? ap_get_conn_server_module_loglevel(c, s, module_index) :
ap_get_server_module_loglevel(s, module_index);
if (s->error_log)
{
/*
* If we are doing normal logging, don't log messages that are
* above the module's log level unless it is a startup/shutdown notice
*/
if ((level_and_mask != APLOG_NOTICE)
&& (level_and_mask > configured_level))
{
}
else
{
/*
* If we are doing syslog logging, don't log messages that are
* above the module's log level (including a startup/shutdown notice)
*/
if (level_and_mask > configured_level)
{ }
} /* the faked server_rec from mod_cgid does not have s->module_config */ sconf = ap_get_core_module_config(s->module_config);
if (c && !c->log_id)
{
add_log_id(c, NULL);
if (sconf->error_log_conn && sconf->error_log_conn->nelts > 0)
log_conn_info = 1;
}
if (r)
{
if (r->main)
rmain = r->main;
else
rmain = r; if (!rmain->log_id)
{
/* XXX: do we need separate log ids for subrequests? */
if (sconf->error_log_req && sconf->error_log_req->nelts > 0)
log_req_info = 1;
/*
* XXX: potential optimization: only create log id if %L is
* XXX: actually used
*/
add_log_id(c, rmain);
}
}
}
} info.s = s;
info.c = c;
info.pool = pool;
info.file = NULL;
info.line = 0;
info.status = 0;
info.using_syslog = (logf == NULL);
info.startup = ((level & APLOG_STARTUP) == APLOG_STARTUP);
info.format = fmt; while (!done)
{
apr_array_header_t *log_format;
int len = 0, errstr_start = 0, errstr_end = 0;
/* XXX: potential optimization: format common prefixes only once */
if (log_conn_info)
{
/* once-per-connection info */
if (line_number == 0)
{
lines = (apr_array_header_t **)sconf->error_log_conn->elts;
info.r = NULL;
info.rmain = NULL;
info.level = -1;
info.module_index = APLOG_NO_MODULE;
} log_format = lines[line_number++]; if (line_number == sconf->error_log_conn->nelts)
{
/* this is the last line of once-per-connection info */
line_number = 0;
log_conn_info = 0;
}
}
else if (log_req_info)
{
/* once-per-request info */
if (line_number == 0)
{
lines = (apr_array_header_t **)sconf->error_log_req->elts;
info.r = rmain;
info.rmain = rmain;
info.level = -1;
info.module_index = APLOG_NO_MODULE;
} log_format = lines[line_number++]; if (line_number == sconf->error_log_req->nelts)
{
/* this is the last line of once-per-request info */
line_number = 0;
log_req_info = 0;
}
}
else
{
/* the actual error message */
info.r = r;
info.rmain = rmain;
info.level = level_and_mask;
info.module_index = module_index;
info.file = file;
info.line = line;
info.status = status;
log_format = sconf ? sconf->error_log_format : NULL;
done = 1;
} /*
* prepare and log one line
*/ if (log_format && !info.startup)
{
len += do_errorlog_format(log_format, &info, errstr + len,
MAX_STRING_LEN - len,
&errstr_start, &errstr_end, fmt, args);
}
else
{
len += do_errorlog_default(&info, errstr + len, MAX_STRING_LEN - len,
&errstr_start, &errstr_end, fmt, args);
} if (!*errstr)
{
/*
* Don't log empty lines. This can happen with once-per-conn/req
* info if an item with AP_ERRORLOG_FLAG_REQUIRED is NULL.
*/
continue;
}
write_logline(errstr, len, logf, level_and_mask); if (done)
{
/*
* We don't call the error_log hook for per-request/per-conn
* lines, and we only pass the actual log message, not the
* prefix and suffix.
*/
errstr[errstr_end] = '\0';
ap_run_error_log(&info, errstr + errstr_start);
} *errstr = '\0';
}
}
do_errorlog_default函数拼接要写入日志的内容并暂存在buf中,并返回相应长度len,此处拼接出的日志的内容如下:
[Sat Jun 20 22:08:19.506426 2015] [so:debug] [pid 3826] mod_so.c(266): AH01575: loaded module unixd_module from /app/HRP/lib/mod_unixd.so
do_errorlog_default函数实现在文件:httpd/server/log.c,代码如下:
static int do_errorlog_default(const ap_errorlog_info *info, char *buf,
int buflen, int *errstr_start, int *errstr_end,
const char *errstr_fmt, va_list args)
{
int len = 0;
int field_start = 0;
int item_len;
#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
char scratch[MAX_STRING_LEN];
#endif if (!info->using_syslog && !info->startup)
{
buf[len++] = '[';
len += log_ctime(info, "u", buf + len, buflen - len);
buf[len++] = ']';
buf[len++] = ' ';
} if (!info->startup)
{
buf[len++] = '[';
len += log_module_name(info, NULL, buf + len, buflen - len);
buf[len++] = ':';
len += log_loglevel(info, NULL, buf + len, buflen - len);
len += cpystrn(buf + len, "] [pid ", buflen - len); len += log_pid(info, NULL, buf + len, buflen - len);
#if APR_HAS_THREADS
field_start = len;
len += cpystrn(buf + len, ":tid ", buflen - len);
item_len = log_tid(info, NULL, buf + len, buflen - len);
if (!item_len)
len = field_start;
else
len += item_len;
#endif
buf[len++] = ']';
buf[len++] = ' ';
} if (info->level >= APLOG_DEBUG)
{
item_len = log_file_line(info, NULL, buf + len, buflen - len);
if (item_len)
{
len += item_len;
len += cpystrn(buf + len, ": ", buflen - len);
}
} if (info->status)
{
item_len = log_apr_status(info, NULL, buf + len, buflen - len);
if (item_len)
{
len += item_len;
len += cpystrn(buf + len, ": ", buflen - len);
}
} /*
* useragent_ip/client_ip can be client or backend server. If we have
* a scoreboard handle, it is likely a client.
*/
if (info->r)
{
len += apr_snprintf(buf + len, buflen - len,
info->r->connection->sbh ? "[client %s:%d] " : "[remote %s:%d] ",
info->r->useragent_ip,
info->r->useragent_addr ? info->r->useragent_addr->port : 0);
}
else if (info->c)
{
len += apr_snprintf(buf + len, buflen - len,
info->c->sbh ? "[client %s:%d] " : "[remote %s:%d] ",
info->c->client_ip,
info->c->client_addr ? info->c->client_addr->port : 0);
} /* the actual error message */
*errstr_start = len;
#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
if (apr_vsnprintf(scratch, MAX_STRING_LEN, errstr_fmt, args))
{
len += ap_escape_errorlog_item(buf + len, scratch,
buflen - len); }
#else
len += apr_vsnprintf(buf + len, buflen - len, errstr_fmt, args);
#endif
*errstr_end = len; field_start = len;
len += cpystrn(buf + len, ", referer: ", buflen - len);
item_len = log_header(info, "Referer", buf + len, buflen - len);
if (item_len)
len += item_len;
else
len = field_start; return len;
}
write_logline函数实现在文件:httpd/server/log.c,代码如下:
static void write_logline(char *errstr, apr_size_t len, apr_file_t *logf,
int level)
{
/* NULL if we are logging to syslog */
if (logf)
{
/* Truncate for the terminator (as apr_snprintf does) */
if (len > MAX_STRING_LEN - sizeof(APR_EOL_STR))
{
len = MAX_STRING_LEN - sizeof(APR_EOL_STR);
}
strcpy(errstr + len, APR_EOL_STR);
apr_file_puts(errstr, logf);
apr_file_flush(logf);
}
#ifdef HAVE_SYSLOG
else
{
syslog(level < LOG_PRIMASK ? level : APLOG_DEBUG, "%.*s",
(int)len, errstr);
}
#endif
}
C语言日志处理的更多相关文章
- 在android平台打印C语言日志
在android平台打印C语言日志 1.操作平台:AS2.0 2.步骤如下: 在C代码中添加如下代码: #define LOG_TAG "我的C语言日志:" #define LOG ...
- zlog小试(C语言日志工具)
test.c #include <stdio.h> #include "zlog.h" int main(int argc, char** argv) { int rc ...
- nxlog4go 简介 - 基于log4go的下一代go语言日志系统
nxlog4go的项目网址: https://github.com/ccpaging/nxlog4go 项目历史 ccpaging's log4go forked from https://githu ...
- c语言日志打印
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <stdarg.h> ...
- Java资源大全中文版(Awesome最新版)(转载)
原文地址:http://www.cnblogs.com/best/p/5876559.html 目录 业务流程管理套件 字节码操作 集群管理 代码分析 编译器生成工具 构建工具 外部配置工具 约束满足 ...
- Github优秀java项目集合(中文版) - 涉及java所有的知识体系
Java资源大全中文版 我想很多程序员应该记得 GitHub 上有一个 Awesome - XXX 系列的资源整理.awesome-java 就是 akullpp 发起维护的 Java 资源列表,内容 ...
- 改进log4go的一些设想
log4go 的 4.0.2 版本(https://github.com/ccpaging/log4go/tree/4.0.2)发布以后, 看了看别的 go 语言日志文件设计.发现了一篇好文: log ...
- AI 学习路线
[导读] 本文由知名开源平台,AI技术平台以及领域专家:Datawhale,ApacheCN,AI有道和黄海广博士联合整理贡献,内容涵盖AI入门基础知识.数据分析挖掘.机器学习.深度学习.强化学习.前 ...
- 自然语言处理(NLP)入门学习资源清单
Melanie Tosik目前就职于旅游搜索公司WayBlazer,她的工作内容是通过自然语言请求来生产个性化旅游推荐路线.回顾她的学习历程,她为期望入门自然语言处理的初学者列出了一份学习资源清单. ...
随机推荐
- SqlServer高级特性--存储过程
需求: 用户需要提交加密数据,提交之后需要解密还原,还原有两种结果:成功和失败! 100个用户,之前7天,判断是否有提交数据,如果有提交有数据,判断是否解密成功(分别存在两个表中).如果没有提交,显示 ...
- IO流常规操作
IO流 IO就是输入输出,IO设备在计算机中起着举足轻重的作用,IO流也就是输入输出流,用来交互数据,程序和程序交互,程序也可以和网络等媒介交互. 一.IO流的分类 要分类,肯定得站得不同角度来看这个 ...
- 用Navicat复制数据库到本地(导入.sql文件运行)
今天装数据库的机子没开,项目运行不了,于是还是决定在自己电脑上装数据库,由于新学数据库操作,记录一下 一.转储sql文件 右键点击数据库,转储sql文件,点击结构和数据 存放在本地,开始转储 转储完成 ...
- 三:背包DP
01背包问题描述 已知:有一个容量为V的背包和N件物品,第i件物品的重量是weight[i],收益是cost[i]. 限制:每种物品只有一件,可以选择放或者不放 问题:在不超过背包容量的情况下,最多能 ...
- Phonegap 工程项目介绍
一.工程项目的路径在www下面,www下面的文件如下图 1. index.html <!DOCTYPE html> <!-- Licensed to the Apache Softw ...
- Axis开发Web Service
可以自动生成代码的 一.Axis环境的安装 1.安装环境 J2SE SDK 1.4,Tomcat 5.0,eclipse 3.2. 2.到 http://xml.apache.org 网站下载Axis ...
- 记录tomcat的完整日志
Tomcat报的错太含糊了,什么错都没报出来,只提示了Error listenerStart.为了调试,我们要获得更详细的日志.可以在WEB-INF/classes目录下新建一个文件叫logging. ...
- VS解决方案的目录结构设置和管理
一个中等规模的解决方案通常都会包含多个项目,其中一些项目产出静态库,一些产出动态库,一些用于单元测试,还有的产出最终的应用程序执行档.除此以外,根据项目的需求,还会使用一些第三方的库. 所以为解决 ...
- bzoj 3615: MSS
Description 小C正在出一道题...因为语文水平有限他想不出复杂的背景,所以以下就是题意了. 平面上有N个点,开始时每个点属于一个不同的集合.不妨设点Pi属于集合Si.请维护数据结构支持以下 ...
- Jenkins集成selenium
目的:将selenium用例集成到Jenkins,需要执行时,只需要执行curl命令即可. 1.准备selenium测试脚本 from selenium import webdriver import ...