FreeSWITCH日志功能分析及apr模拟
- freeswitch日志功能及相关源码分析
- 日志功能实现可行性分析
- 使用示例及运行效果
- 资源获取
一、功能说明及源码分析
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "ENUM Reloaded\n");


1、switch_log_printf函数分析
SWITCH_DECLARE(void) switch_log_printf(switch_text_channel_t channel, const char *file, const char *func, int line,
const char *userdata, switch_log_level_t level, const char *fmt, ...)
{
va_list ap; va_start(ap, fmt);
switch_log_meta_vprintf(channel, file, func, line, userdata, level, NULL, fmt, ap);
va_end(ap);
}

从实现代码可以看出,switch_log_printf函数的参数列表里面有channel、file、func、line等参数,但调用时并未传入。
#define SWITCH_CHANNEL_LOG SWITCH_CHANNEL_ID_LOG, __FILE__, __SWITCH_FUNC__, __LINE__, NULL

从代码实现来看,这个宏把需要的参数都传入了。

2、switch_log_meta_vprintf函数分析

SWITCH_DECLARE(void) switch_log_meta_vprintf(switch_text_channel_t channel, const char *file, const char *func, int line,
const char *userdata, switch_log_level_t level, cJSON **meta, const char *fmt, va_list ap)
{
cJSON *log_meta = NULL;
char *data = NULL;
char *new_fmt = NULL;
int ret = 0;
FILE *handle;
const char *filep = (file ? switch_cut_path(file) : "");
const char *funcp = (func ? func : "");
char *content = NULL;
switch_time_t now = switch_micro_time_now();
uint32_t len;
#ifdef SWITCH_FUNC_IN_LOG
const char *extra_fmt = "%s [%s] %s:%d %s()%c%s";
#else
const char *extra_fmt = "%s [%s] %s:%d%c%s";
#endif
switch_log_level_t limit_level = runtime.hard_log_level;
switch_log_level_t special_level = SWITCH_LOG_UNINIT; if (meta && *meta) {
log_meta = *meta;
*meta = NULL;
} if (limit_level == SWITCH_LOG_DISABLE) {
goto end;
} if (channel == SWITCH_CHANNEL_ID_SESSION && userdata) {
switch_core_session_t *session = (switch_core_session_t *) userdata;
special_level = session->loglevel;
if (limit_level < session->loglevel) {
limit_level = session->loglevel;
}
} if (level > 100) {
if ((uint32_t) (level - 100) > runtime.debug_level) {
goto end;
} level = 1;
} if (level > limit_level) {
goto end;
} switch_assert(level < SWITCH_LOG_INVALID); handle = switch_core_data_channel(channel); if (channel != SWITCH_CHANNEL_ID_LOG_CLEAN) {
char date[80] = "";
//switch_size_t retsize;
switch_time_exp_t tm; switch_time_exp_lt(&tm, now);
switch_snprintf(date, sizeof(date), "%0.4d-%0.2d-%0.2d %0.2d:%0.2d:%0.2d.%0.6d %0.2f%%%%",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec, switch_core_idle_cpu()); //switch_strftime_nocheck(date, &retsize, sizeof(date), "%Y-%m-%d %T", &tm); #ifdef SWITCH_FUNC_IN_LOG
len = (uint32_t) (strlen(extra_fmt) + strlen(date) + strlen(filep) + 32 + strlen(funcp) + strlen(fmt));
#else
len = (uint32_t) (strlen(extra_fmt) + strlen(date) + strlen(filep) + 32 + strlen(fmt));
#endif
new_fmt = malloc(len + 1);
switch_assert(new_fmt);
#ifdef SWITCH_FUNC_IN_LOG
switch_snprintf(new_fmt, len, extra_fmt, date, switch_log_level2str(level), filep, line, funcp, 128, fmt);
#else
switch_snprintf(new_fmt, len, extra_fmt, date, switch_log_level2str(level), filep, line, 128, fmt);
#endif fmt = new_fmt;
} ret = switch_vasprintf(&data, fmt, ap); if (ret == -1) {
fprintf(stderr, "Memory Error\n");
goto end;
} if (channel == SWITCH_CHANNEL_ID_LOG_CLEAN) {
content = data;
} else {
if ((content = strchr(data, 128))) {
*content = ' ';
}
} if (channel == SWITCH_CHANNEL_ID_EVENT) {
switch_event_t *event;
if (switch_event_running() == SWITCH_STATUS_SUCCESS && switch_event_create(&event, SWITCH_EVENT_LOG) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Log-Data", data);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Log-File", filep);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Log-Function", funcp);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Log-Line", "%d", line);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Log-Level", "%d", (int) level);
if (!zstr(userdata)) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "User-Data", userdata);
}
switch_event_fire(&event);
data = NULL;
} goto end;
} if (console_mods_loaded == 0 || !do_mods) {
if (handle) {
int aok = 1;
#ifndef WIN32 fd_set can_write;
int fd;
struct timeval to; fd = fileno(handle);
memset(&to, 0, sizeof(to));
FD_ZERO(&can_write);
FD_SET(fd, &can_write);
to.tv_sec = 0;
to.tv_usec = 100000;
if (select(fd + 1, NULL, &can_write, NULL, &to) > 0) {
aok = FD_ISSET(fd, &can_write);
} else {
aok = 0;
}
#endif
if (aok) {
if (COLORIZE) { #ifdef WIN32
SetConsoleTextAttribute(hStdout, COLORS[level]);
WriteFile(hStdout, data, (DWORD) strlen(data), NULL, NULL);
SetConsoleTextAttribute(hStdout, wOldColorAttrs);
#else
fprintf(handle, "%s%s%s", COLORS[level], data, SWITCH_SEQ_DEFAULT_COLOR);
#endif
} else {
fprintf(handle, "%s", data);
}
}
}
} if (do_mods && level <= MAX_LEVEL) {
switch_log_node_t *node = switch_log_node_alloc(); node->data = data;
data = NULL;
switch_set_string(node->file, filep);
switch_set_string(node->func, funcp);
node->line = line;
node->level = level;
node->slevel = special_level;
node->content = content;
node->timestamp = now;
node->channel = channel;
node->tags = NULL;
node->meta = log_meta;
log_meta = NULL;
if (channel == SWITCH_CHANNEL_ID_SESSION) {
switch_core_session_t *session = (switch_core_session_t *) userdata;
node->userdata = userdata ? strdup(switch_core_session_get_uuid(session)) : NULL;
if (session) {
switch_channel_get_log_tags(switch_core_session_get_channel(session), &node->tags);
}
} else {
node->userdata = !zstr(userdata) ? strdup(userdata) : NULL;
} if (switch_queue_trypush(LOG_QUEUE, node) != SWITCH_STATUS_SUCCESS) {
switch_log_node_free(&node);
}
} end: cJSON_Delete(log_meta);
switch_safe_free(data);
switch_safe_free(new_fmt); }

会使用 switch_queue_trypush 函数进行入队操作:

说明:

3、mod_logfile_load函数分析

4、switch_log_bind_logger函数分析

5、log_thread函数

日志线程在初始化时就启动了。

6、mod_logfile_raw_write函数

函数调用链如下:
mod_logfile_load
=> mod_logfile_logger
=> process_node
=> mod_logfile_raw_write
7、mod_logfile_rotate函数

二、实现可行性分析
1、配置文件

2、基于队列实现日志功能
3、日志轮转
三、使用示例及运行效果
1、配置文件添加及解析
<setting>
<server>192.168.137.100:5060</server>
<log>
<dirPath>/tmp/log</dirPath>
<fileName>test.log</fileName>
<rollSize>100</rollSize> MB
<rollCount>5</rollCount>
</log>
</setting>

完整代码可从如下渠道获取:
关注微信公众号(聊聊博文,文末可扫码)后回复 20250102 获取。
2、logger实现

完整代码可从如下渠道获取:
关注微信公众号(聊聊博文,文末可扫码)后回复 20250102 获取。

完整代码可从如下渠道获取:
关注微信公众号(聊聊博文,文末可扫码)后回复 20250102 获取。
3、主程序实现
#pragma once #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/resource.h>
#include <sys/prctl.h>
#include <arpa/inet.h> #include <apr_portable.h>
#include "apr_queue.h"
#include "apr_thread_pool.h"
#include "apr_time.h"
#include "apr_hash.h"
#include "apr_thread_mutex.h"
#include <pthread.h> #include <libxml/parser.h>
#include <libxml/tree.h> typedef struct logger_vars_t {
apr_pool_t *apr_pool; char server[256];
char log_dirname[256];
char log_filename[128];
int log_rollsize;
int log_rollcount; }logger_vars_t;

完整代码可从如下渠道获取:
关注微信公众号(聊聊博文,文末可扫码)后回复 20250102 获取。
4、编译脚本及Makefile
#! /bin/bash
BASEDIR=${PWD}
APRDIR=${BASEDIR}/libs/apr-1.7.4
APRUTILDIR=${BASEDIR}/libs/apr-util-1.6.3
echo ${BASEDIR}
#exit 0
cd ${APRDIR}
./configure --enable-static
make
cd ${APRUTILDIR}
./buildconf --with-apr=${APRDIR}
./configure --with-apr=${APRDIR}
make
cd ${BASEDIR}
make testMain
CC=gcc
CFLAGS=-g -gstabs+ -I/usr/include/libks -Ilibs/apr-1.7.4/include -Ilibs/apr-util-1.6.3/include -I/usr/include/libxml2/
LIBS=libs/apr-util-1.6.3/.libs/libaprutil-1.a libs/apr-1.7.4/.libs/libapr-1.a -lpthread -lxml2 #
BASEDIR=${PWD}
APRDIR=${BASEDIR}/libs/apr-1.7.4
APRUTILDIR=${BASEDIR}/libs/apr-util-1.6.3 all:
#make apr
#make apr-util
make testMain apr:
cd $(APRDIR) && ./configure --enable-static && make apr-util:
cd $(APRUTILDIR) && ./buildconf --with-apr=$(APRDIR) && ./configure --with-apr=$(APRDIR) && make testMain: testMain.o logger.o
$(CC) -o testMain testMain.o logger.o $(LIBS) clean:
rm -f testMain
rm -f *.o .c.o:
$(CC) $(CFLAGS) -c -o $*.o $<

5、示例效果

关注微信公众号(聊聊博文,文末可扫码)后回复 20250102 获取。
四、其它
1、添加core dump支持
void core_setrlimits(void)
{
// set core dump
struct rlimit rlp; memset(&rlp, 0, sizeof(rlp));
rlp.rlim_cur = 999999;
rlp.rlim_max = 999999;
setrlimit(RLIMIT_NOFILE, &rlp); memset(&rlp, 0, sizeof(rlp));
rlp.rlim_cur = RLIM_INFINITY;
rlp.rlim_max = RLIM_INFINITY; setrlimit(RLIMIT_CPU, &rlp);
setrlimit(RLIMIT_DATA, &rlp);
setrlimit(RLIMIT_FSIZE, &rlp); setrlimit(RLIMIT_CORE, &rlp); return;
}
2、日志乱码问题及队列操作注意事项
关注微信公众号(聊聊博文,文末可扫码)后回复 20250102 获取。
五、资源获取

FreeSWITCH日志功能分析及apr模拟的更多相关文章
- 出现错误日志:The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path
tomcat6出现错误日志: 信息: The APR based Apache Tomcat Native library which allows optimal performance in ...
- MySQL慢日志功能分析及优化增强
本文由 网易云发布. MySQL慢日志(slow log)是MySQL DBA及其他开发.运维人员需经常关注的一类信息.使用慢日志可找出执行时间较长或未走索引等SQL语句,为进行系统调优提供依据.本 ...
- freeswitch APR库
概述 freeswitch依赖库源代码基本都可以在libs目录下找到. 在freeswitch的官方手册中,可以找到freeswitch的依赖库表格,其中freeswitch的core核心代码依赖库主 ...
- 日志切割logrotate和定时任务crontab详解
1.关于日志切割 日志文件包含了关于系统中发生的事件的有用信息,在排障过程中或者系统性能分析时经常被用到.对于忙碌的服务器,日志文件大小会增长极快,服务器会很快消耗磁盘空间,这成了个问题.除此之外,处 ...
- freeswitch对接其它SIP设备
这几天用到freeswitch对接其它设备方面的知识,这里整理下,也方便我以后查阅. 操作系统:debian8.5_x64 freeswitch 版本 : 1.6.8 一.freeswitch作为被叫 ...
- [转]Linux日志文件总管——logrotate
FROM : https://linux.cn/article-4126-1.html 日志文件包含了关于系统中发生的事件的有用信息,在排障过程中或者系统性能分析时经常被用到.对于忙碌的服务器,日志文 ...
- 切割haproxy的日志
日志的切割有以下几种方法: 1.写个定时任务,每天某个时间点把旧的日志重命名,并对服务重启使其重新打开日志并写入. 2.通过管道的方式把新产生的日志写到另外一个日志文件里. 3.通过logrotate ...
- tomcat并发优化之三种接收处理请求方式(BIO、NIO、APR)介绍
原文链接:http://blog.csdn.net/xyang81/article/details/51502766 Tomcat支持三种接收请求的处理方式:BIO.NIO.APR 1>.BIO ...
- Linux日志文件总管——logrotate
日志文件包含了关于系统中发生的事件的有用信息,在排障过程中或者系统性能分析时经常被用到.对于忙碌的服务器,日志文件大小会增长极快,服务器会很快消耗磁盘空间,这成了个问题.除此之外,处理一个单个的庞大日 ...
- Python之logging日志模块
logging 用于便捷既然日志切线程安全的模块 vim log_test.py import logging logging.basicConfig(filename='log.log', form ...
随机推荐
- OKR 目标和关键成果
OKR(Objectives and Key Results)是目标与关键成果管理法,是一套明确和跟踪目标及其完成情况的管理工具和方法.1.OKR首先是沟通工具:团队中的每个人都要写OKR,所有这些O ...
- ToDesk再度出手,加快云电脑高性能发展,剑指千亿级市场
根据中国信通院发布的<云计算白皮书(2023年)>(以下简称白皮书)显示,云计算引发了软件开发部署模式的创新,成为承载各类应用的关键基础设施,为大数据.物联网.人工智能等新兴领域的发展提供 ...
- Halcon 快速入门教程
文章首发于我的 github 仓库-cv算法工程师成长之路,欢迎关注我的公众号-嵌入式视觉. 本人水平有限,文章如有问题,欢迎及时指出.如果看完文章有所收获,一定要先点赞后收藏.毕竟,赠人玫瑰,手有余 ...
- 3D数学基础:图形和游戏开发(第二版)--读书笔记(1)
简介: 本书是关于3D数学.三维空间的几何和代数的入门教材.它旨在告诉你如何使用数学描述三维中的物体及其位置.方向和轨迹.这不是一本关于计算机图形学.模拟,甚至计算几何的书,但是,如果读者打算研究这些 ...
- 2024强网杯pwn short wp
这时2024强网杯的pwn部分的short的WP 分析以下程序的基本安全措施 *] '/home/ysly/solve/tmp/short' Arch: i386-32-little RELRO: P ...
- 怎样在Windows 环境下安装Git附详细步骤图
Git下载路径:https://git-scm.com/ [步骤] 在非C盘创建一个git_install作为git的安装目录,双击安装包,按下一步默认安装即可 (后面有时间来补充各个参数意思,目前按 ...
- 感谢华为:iPhone 16全球价格对比:中国最便宜!比均价低1200元
相关: https://baijiahao.baidu.com/s?id=1811582397991377070&wfr=spider&for=pc 苹果最新的iPhone 16系列已 ...
- apisix~限流插件的使用
参考: https://i4t.com/19399.html https://github.com/apache/apisix/issues/9193 https://github.com/apach ...
- langchain_chatchat+ollama部署本地知识库,联网查询以及对数据库(Oracle)数据进行查询
langchain_chatchat+ollama部署本地知识库,联网查询以及对数据库(Oracle)数据进行查询 涉及的内容其实挺多的,所以尽量减少篇幅 目录 langchain_chatchat+ ...
- 国产数据库oceanBbase,达梦,金仓与mysql数据库的性能对比 四、python读mysql写入达梦数据库
一.说明 安装达梦的驱动 pip install dmPython==2.5.5 参数接收那里,其他数据库都是用%,达梦要用? 二.源码 #coding=utf-8 import pymysql im ...