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 ...
随机推荐
- Robust Loop Closure by Textual Cues in Challenging Environments
arxiv | 南洋理工大学开源 基于文本线索实现复杂环境中的鲁棒闭环检测 [Robust Loop Closure by Textual Cues in Challenging Environmen ...
- Hugging Face 与 TruffleHog 合作,实现风险预警
我们非常高兴地宣布与 Truffle Security 建立合作伙伴关系并在我们的平台集成 TruffleHog 强大的风险信息扫描功能.这些特性是 我们持续致力于提升安全性 的重要举措之一. Tru ...
- games101_Homework1
本次作业的任务是填写一个旋转矩阵和一个透视投影矩阵.给定三维下三个 点 v0(2.0, 0.0, −2.0), v1(0.0, 2.0, −2.0), v2(−2.0, 0.0, −2.0), 你需要 ...
- Ymodem协议详解
Xmodem.Ymodem和Zmodem协议是最常用的三种通信协议. Xmodem协议是最早的,传输128字节信息块. Ymodem是Xmodem的改进版协议,具有传输快速稳定的优点.它可以一次传输1 ...
- Visual Studio 快速分析 .NET Dump 文件
前言 在开发和维护 .NET 应用程序的过程中,有时会遇到难以捉摸的性能瓶颈或内存泄漏等问题.这些问题往往发生在生产环境中,难以复现.为了更准确地诊断这些运行时问题,通常会收集应用程序在生产环境中的内 ...
- 5、oracle内存及进程操作讲解
内存结构 1.shared pool 缓存着sql.sql执行计划 查询shared pool大小: select * from v$sga_dynamic_components; 2.buffer ...
- 不错的PHP扩展
不错的PHP扩展 ext name ext description ds data structure 提供list hash queue等数据结构 igbinary 数据压缩(速度快 压缩后内容小) ...
- vue中登录超时跳转到登录页面设置拦截器
axios中添加响应拦截器 Axios.interceptors.response.use(res = > { let resData = res.data; if (resData.code ...
- Linux之JSON处理工具jq
一个灵活的轻量级命令行JSON处理器 补充说明 jq 是 stedolan 开发的一个轻量级的和灵活的命令行JSON处理器,源码请参考 jq 项目主页 jq 用于处理JSON输入,将给定过滤器应用于其 ...
- yum之镜像加速
有没有遇到使用yum安装软件慢如龟,默认的系统使用的是centos的镜像源,我们可以修改为国内镜像源加速软件安装 163)http://mirrors.163.com/.help/centos.htm ...