热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C语言日志处理

一、简介zlog是一个高可靠性、高性能、线程安全、灵活、概念清晰的纯C日志函数库,在效率、功能、安全性上大大超过了log4c,并且是用c写成的,具有比较好的通用性。二、安装下载

一、简介

zlog是一个高可靠性、高性能、线程安全、灵活、概念清晰的纯C日志函数库,在效率、功能、安全性上大大超过了log4c,并且是用c写成的,具有比较好的通用性。

 

二、安装

下载

https://github.com/HardySimpson/zlog
https://github.com/HardySimpson/zlog/archive/latest-stable.tar.gzhttps://github.com/downloads/HardySimpson/zlog/zlog-latest-stable.tar.gz

 

三、实例

参考:

http://blog.itpub.net/26834829/viewspace-721002/
https://github.com/HardySimpson/zlog

 

源码目录:test,包括了大量使用示例,如下:

image

 

四、系统日志

参考:

http://blog.sina.com.cn/s/blog_5f70c7060100i4j5.html

 

示例:

#include 
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

运行

1

 

五、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
"%.*s",
(
int)len, errstr);
}
#endif
}

推荐阅读
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • 本文介绍了一些Java开发项目管理工具及其配置教程,包括团队协同工具worktil,版本管理工具GitLab,自动化构建工具Jenkins,项目管理工具Maven和Maven私服Nexus,以及Mybatis的安装和代码自动生成工具。提供了相关链接供读者参考。 ... [详细]
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 如何去除Win7快捷方式的箭头
    本文介绍了如何去除Win7快捷方式的箭头的方法,通过生成一个透明的ico图标并将其命名为Empty.ico,将图标复制到windows目录下,并导入注册表,即可去除箭头。这样做可以改善默认快捷方式的外观,提升桌面整洁度。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • Windows下配置PHP5.6的方法及注意事项
    本文介绍了在Windows系统下配置PHP5.6的步骤及注意事项,包括下载PHP5.6、解压并配置IIS、添加模块映射、测试等。同时提供了一些常见问题的解决方法,如下载缺失的msvcr110.dll文件等。通过本文的指导,读者可以轻松地在Windows系统下配置PHP5.6,并解决一些常见的配置问题。 ... [详细]
  • 本文介绍了作者在开发过程中遇到的问题,即播放框架内容安全策略设置不起作用的错误。作者通过使用编译时依赖注入的方式解决了这个问题,并分享了解决方案。文章详细描述了问题的出现情况、错误输出内容以及解决方案的具体步骤。如果你也遇到了类似的问题,本文可能对你有一定的参考价值。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了StartingzookeeperFAILEDTOSTART相关的知识,希望对你有一定的参考价值。下载路径:https://ar ... [详细]
  • IT方面的论坛太多了,有综合,有专业,有行业,在各个论坛里混了几年,体会颇深,以前是论坛哪里人多 ... [详细]
  • CEPH LIO iSCSI Gateway及其使用参考文档
    本文介绍了CEPH LIO iSCSI Gateway以及使用该网关的参考文档,包括Ceph Block Device、CEPH ISCSI GATEWAY、USING AN ISCSI GATEWAY等。同时提供了多个参考链接,详细介绍了CEPH LIO iSCSI Gateway的配置和使用方法。 ... [详细]
author-avatar
电信他爹_186
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有