/*************************************************************************** * Licensed Materials - Property of IBM * Copyright IBM Corp. 2013 All rights reserved. * * Source filename : dc.c * Description : Read records from files and send the contain to TO by TTAPI * * Parameter : * 1 start mode: 0- automatic mode, start by crontab; 1- re-run modle; * 2 DC monitoring target file path; * 3 DC monitoring target filename; * 4 servername, on which the program runs * 5 send log data mode, 1-TTAPI mode 2-Socket mode 3-Mixed mode with TTAPI & Socket * * Author : Wang An Nian * * Update History * DATE OWNER DESCRIPTION * ----------- ------------ ----------- * 2012-11-06 Wang An Nian Generated * 2013-11-06 Wang An Nian Domestic * 2014-xx-xx Wang An Nian While list Function added * 2014-08-18 Wang An Nian MCIS TXN fillter added -p403 * 1 if connect failed then retry socket,if socket send fail then retry socket * 2 add MCIS white name list filter function * 3 SIGPIPE ignored * 4 if monitored file is null, do not exit and wait till life cycle ended * * 2014-09-xx Wang An Nian Euro Africa modification * 5 socket sending for abroad transactions ( have not finished yet) * * 2014-12-30 Li Bo Feng Fix problems & Code Formatting * 1. 调整代码可读性,不改变处理逻辑 * 代码函数分割 * 常量定义,结构定义 dc.h * 通用函数 dc_code * 参数处理 dc_args * 网络直连发送处理 dc_socket * TT发送处理 dc_ttapi * 文件缓存处理 dc_file_buffer * 目标数据处理过程 dc_target * 主程序 dc.c * 2. 修改文件监控轮询时间 * 原来检查文件是否存在间隔时间为 2 分钟, 改为 10 秒 * 原来检查文件是否有内容间隔时间为 1 分钟, 改为 10 秒 * 原来检查文件内容是否为当前监控周期内容间隔时间为 1 分钟, 改为 10 秒 * 原来检查文件内容是否有新增内容间隔时间为 5 秒,保持为 5 秒 * 3. 去掉再运行模式 - 从文件尾读取交易流水日志数据 * 因为实际代码已经不支持该模式,参数已经不起作用 * 4. 增加内存释放 * 动态申请的内存,需要释放 * * 2015-1-6 Li Bo Feng Code structure Formatting & File bufferred reading * 1. 调整代码结构 * 合并重复代码 * 简化代码逻辑 * 增加函数返回码 * 2. 增加扫描内容控制方式,依据 * 方便测试期间回放旧数据,配置依据环境变量 * SCAN_BEGIN_TIME=1970-1-1 00:00:00 * SCAN_END_TIME=1970-1-1 00:00:00 * 根据起始时间点、结束时间点、数据时间、当前时间决定数据是否发送 * 根据数据交易码白名单决定数据发送目标 * 3. 增加数据回放时间同步功能 * 回放旧数据时,保持数据扫描周期与数据时间一致,精确到 DATA_SCAN_INTERVAL_SECONDS = 10 秒 * 4. 增加文件缓存功能 * 增加 FileBuffer 基础功能 * 一次读入整块内容 * 5. 增加文件变更重读功能 * 文件内容发生变化(非追加变化,内容修改或减少),重新读取文件内容 * 6. 增加文件内容校验功能 * 每次读取内容时,重复读取部分上次缓存内容,比较两次读取内容的重叠区域,以此判定文件内容是否改变 * 7. 增加文件定时刷新功能 * 回放旧数据,系统处于等待数据周期时,及时发现数据变化 * * 2015-1-13 Li Bo Feng new function & Performance Optimizing * 1. 增加 Socket 发送心跳功能 * 心跳间隔 NETWORK_IDLE_HEARTBEAT_SECONDS = 10 秒 * 2. 调整程序日志输出内容 * 增加可读性 * 增加日志分类输出: Error Metrics State Detail Flow * 3. 增加处理状态控制 * 用状态控制取代逻辑控制,简化数据处理逻辑 * * 2015-1-15 Li Bo Feng new function & Performance Optimizing * 1. 数据扫描性能优化 * 运行参数集中管理功能 * 通过 key-value Mapping 结构存储配置信息 * 提高白名单及编码转换匹配效率 * * 2015-1-26 Li Bo Feng * 1. 调整启动参数 * 第5个启动参数 send_mode, 形式改为下列各参数的16进制数值组合 * 1000 SEND_MODE_ABROAD_SOCKET * 0100 SEND_MODE_DOMESTIC_SOCKET * 0010 SEND_MODE_ABROAD_TTAPI * 0001 SEND_MODE_DOMESTIC_TTAPI * 对应的服务器(地址:端口)设置关键字改为 * SOCKET_ABROAD_SERVER="地址:端口" * SOCKET_DOMESTIC_SERVER="地址:端口" * TTAPI_ABROAD_SERVER="tcp:地址:端口" * TTAPI_DOMESTIC_SERVER="tcp:地址:端口" * 2. 功能调整 * 根据配置, 可同时发送 国内/海内 Socket/TTAPI * * 2015-2-2 Li Bo Feng * 1. 增加TTAPI输出字段内容 * ChannelID (Added Field) Channel and its transaction id information, only have this when it's the first hop * ReturnCode (Added Field) Return code in the application log * TragetSystem (Added Field) ComponentName(aka. system name) of the target system, only have this for data timetype 02 and 03 * 2. 调整To Socket Server输出字段内容 * TragetTxnID (Added Field) 有目标交易码的系统,在LinkSys后增加","分割的目标交易码 * * * 2015-2-10 Li Bo Feng * 1. 增加调试环境 * windows-cygwin 环境下可编译执行 * * 2015-3-4 Li Bo Feng * 1. DC运行日志文件输出 * 原日志输出不能以日期时间分割输出,影响实现程序常驻 * 按指定时间模式分隔, * 根据当前时间,修正参数给定的文件名中的时间标记 [YYYY] [MM] [DD] [HH] [MI] * 按指定周期删除旧文件 * 为提高效率进程间需同步删除旧文件 * 2. 文件名时间模式转换功能 * 根据当前时间,修正参数给定的文件名中的时间标记 [YYYY] [MM] [DD] [HH] [MI] * * 2015-3-5 Li Bo Feng * 1. 取消环境变量设置 FILESWITCHMODE * 以时间模式文件名取代 * 2. 增加环境变量设置 IDLE_TIMEOUT_HOURS * 空闲超时 * * 2015-3-10 Li Bo Feng * 1. 互斥运行逻辑 * 保留原来的定时启动,以系统防止意外终止 * 如果启动时发现指定日志文件已经有DC进程在处理,立即结束当前进程 * 2. 执行效率优化 * 测试机运行 平均CPU占比 0.1% 以下,内存占用 10MB 以下 * * 2015-3-16 Li Bo Feng * 1. 时间偏移量修正 * 通过环境变量设定虚拟当前时间 virtual_current_time * VIRTUAL_TIME=缺省为当前时间`date +"%Y-%m-%d %H:%M:%S"` * 文件名中的时间与当前时间的偏移量修正,用于目标交易日志文件名及DC运行日志文件名的定时更换 * 目标交易日志数据时间与当前时间的偏移量修正,用于目标交易日志回放/测试中,同步数据扫描周期 * 2. 修正文件名模式转换功能 * 根据虚拟当前时间,修正参数给定的文件名中的时间标记 [YYYY] [MM] [DD] [HH] [MI] * 根据系统当前时间,修正参数给定的文件名中的时间标记 [yyyy] [mm] [dd] [hh] [mi] * 根据当前进程ID,修正参数给定的文件名中的PID标记 [pid] [PID] * * 2015-3-17 Li Bo Feng * 1. 调整启动参数 * 合并参数 file_path 和 file_name,以便于进程查询处理 * 2. 调整启动参数 * 参数 send_mode, 形式改为下列各参数的标记字符组合,以增加可读性,如:AS|DS * AS SEND_MODE_ABROAD_SOCKET * DS SEND_MODE_DOMESTIC_SOCKET * AT SEND_MODE_ABROAD_TTAPI * DT SEND_MODE_DOMESTIC_TTAPI * 对应的服务器(地址:端口)设置在config.map文件中配置,根据业务需求调整配置关键字如下: * socket.server.abroad.NFXS=地址:端口 * socket.server.abroad.BOCNET=地址:端口 * socket.server.domestic.BOCNET=地址:端口 * ttapi.server.abroad=tcp:地址:端口 * ttapi.server.domestic=tcp:地址:端口 * * 2015-3-19 Li Bo Feng * 1. 增加按时间同步扫描功能 * 扫描数据的时间与虚拟当前时间同步 * SCAN_DATA_BY_TIME=default 1 :scan data by virtual time / 0 :scan data from top of file and immediately begin. * * 2015-3-25 * 1. 持续运行测试 * date etime cputime rss * 2015-3-23 3-01:33:10 00:00:24 1952 * 2015-3-25 5-03:38:34 00:00:40 1952 * 2015-3-26 6-05:36:11 00:00:48 1952 * 2015-3-30 10-07:39:12 00:01:20 1952 * * * 2015-3-30 Li Bo Feng * 1. 调整参数,增加运行参数 SysName,AppName,ServerName,InstanceName * 解锁与文件名的关联,避免每个系统的规则不一样导致的程序硬代码 * * * 2015-4-6 Li Bo Feng * 1. Fix内存泄露问题 * 删除旧日志时,扫描目录功能(scandir)导致内存泄露 * 重写,改用readdir功能扫描目录. * 2. 压力测试 * 同时开启36进程,持续运行5天,系统状态正常 * 3. 修改amake脚本,同时打包三个版本: 测试,演练,生产. * 4. 修改dc.sh启动脚本,根据task.lst自动选择不同运行环境参数 * task.lst中可同时配置所有环境的运行参数 * * 2015-4-16 Li Bo Feng * 1. 发布版本 3.0 * * * 2015-5-8 Li Bo Feng * 1. 应用交易日志输出一次写盘信息不完整,导致不能完整读取一行日志记录 * 需要在读取记录不完整(没有换行符)的情况下,需要等待数据完整后,再进行数据解析 * 2. 等待数据完整中,如果发现新交易日志文件已经产生,则直接解析最后的不完整记录,并放弃等待 * 等待时间 15 ~ 20秒 = * 数据文件再刷新间隔 TIMEOUT_REFRESH_FILE_BUFFER_SECONDS 5秒 * 等待文件变更间隔 WAIT_FOR_FILE_CHANGE_SECONDS 10秒 * 数据扫描间隔 DATA_SCAN_INTL_SECONDS 5秒 * * 2015-5-11 Li Bo Feng * 1. 发布版本 3.1 * * 2015-9-2 Li Bo Feng * 1. 增加程序注释信息 * 2. 调整程序格式 * * 2015-11-23 Li Bo Feng * 1. 修正叠加数据的容错处理 * 当文件切换时,读取到的内容可能发生错乱 * 增加更严格的记录数据格式判断,包括: * 记录时间格式判断 * 记录重叠判断 * 2. 增加缺省程序日志的输出 * 缺省输出告警信息: * 忽略的记录 * 等待数据状态 * 3. 发布版本 3.2 * ***************************************************************************/ /* * 环境变量说明: * VIRTUAL_TIME * 虚拟当前时间,用于确定虚拟当前时间和系统当前时间的时间偏移,缺省值与系统当前时间一致 * * SCAN_BEGIN_TIME * 扫描数据开始时间点,格式为yyyy-mm-dd hh:mi:ss,缺省空表示从虚拟当前时间开始扫描数据 * SCAN_END_TIME * 扫描数据结束时间点,格式为yyyy-mm-dd hh:mi:ss,缺省空表示不限制结束时间 * IDLE_TIMEOUT_HOURS * 空闲超时(小时数),待处理数据没有任何变化,导致空闲超时,程序自动退出,缺省为0表示不设置空闲超时 * * TXNCDFILE * 交易码白名单配置文件 * TXNFILE * 交易码/交易名称映射配置文件 * RTNCDFILE * 交易返回码配置文件 * FSYSMATCH * 应用系统别名配置文件 * CONFIG_FILE * mapping样式的通用配置文件 * 渠道信息配置 * channel.BOCNET=BOCNET * 数据接收服务器地址端口 * socket.server.domestic.BOCNET=127.0.0.1:5001 * socket.server.abroad.BOCNET=127.0.0.1:5001 * socket.server.abroad.NFXS=127.0.0.1:5005 * ttapi.server.domestic=tcp:127.0.0.1:5455 * ttapi.server.abroad=tcp:127.0.0.1:5455 * * ABLOG_KEEP_HOURS * 本程序(DC)运行日志保留时间,缺省120小时(5天) * ABLOG_STDOUT * 是否输出到标准输出,0 不输出, 缺省为 1 输出 * ABLOG_FILE * 本程序(DC)运行日志输出文件 * 如果不指定输出文件,日志信息会输出到标准输出(忽略ABLOG_STDOUT指定) * 文件名支持时间模式替换,自动修正参数给定的文件名中的替换标记 * 模式中可以替换内容包括: * [PID] 用当前进程id * [YYYY] 虚拟当前时间的年 * [yyyy] 系统当前时间的年 * [MM] 虚拟当前时间的月 * [mm] 系统当前时间的月 * [DD] 虚拟当前时间的日 * [dd] 系统当前时间的日 * [HH] 虚拟当前时间的时 * [hh] 系统当前时间的时 * [MI] 虚拟当前时间的分 * [mi] 系统当前时间的分 * ABLOG_CLASS * 本程序(DC)运行日志输出内容,由下列标识文字用逗号分隔组合而成,如"Error,Metrics" * All 缺省,全部信息 * Error 程序运行错误信息 * Metrics 程序运行过程重要提示信息 * State 程序运行状态提示信息 * Detail 程序运行详细信息 * Flow 程序运行流程 * Flow_Public 公共的程序运行流程 * Flow_Private 私有的程序运行流程 * Flow_Restricted 受限的程序运行流程 * Flow_Minor 次要的程序运行流程 * * SCAN_DATA_BY_TIME * =default 1 :scan data by virtual time / 0 :scan data from top of file and immediately begin. * * VALIDATE_DATA * 是否验证数据,0 不验证,缺省 1 验证 * CHECK_FILE_STATUS * 检查文件状态 * 读文件前,是否检查文件非追加变更状态(删除,改名,裁减,重写,修改), * 缺省0不检查,缓存数据使用完后,继续读取文件内容过程中,才会发现文件非追加变更(删除,裁减,重写,修改),改名不影响数据继续读取 * 1检查,检查到文件发生非追加变更立即重读,放弃缓存中的数据,测试或回放旧数据时可以通过此设置 * */ /* * 数据扫描周期设定方式: * 开始条件: * 1. 从指定数据时间点开始发送 * SCAN_BEGIN_TIME=yyyy-MM-dd HH:mm:ss * SCAN_BEGIN_TIME=0 //不限开始时间,从文件头开始 * * 处理频率/周期: * 1. 按分钟对应数据发生速率,精确到 5 秒 * * 结束条件: * 1. 到达指定数据时间点结束 * SCAN_END_TIME=yyyy-MM-dd HH:mm:ss * SCAN_END_TIME=0 //持续运行,程序不会退出 * 2. 空闲超时(小时) * IDLE_TIMEOUT_HOURS=0 // 待处理数据没有任何变化,导致空闲超时,程序自动退出 * */ #include "dc.h" #include "dc_code.h" #include "dc_args.h" #include "dc_socket.h" #include "dc_ttapi.h" #include "dc_target.h" #include "ab_map.h" /*------------------------------------------------------------------------ * MAIN() * * 运行参数说明: * scan_from_new * 第1个参数,是否只扫描新增内容, 0 从头开始扫描数据, 1从文件尾开始扫描新产生的数据 * 在打开文件时就已经确定,读取位置,优先级很高,但只有刚开始时起作用,文件切换或重读时,此参数将失去意义. * log_file_path * 第2个参数,目标日志文件路径,文件名支持模式替换 * 模式中可以替换内容包括: * [PID] 用当前进程id * [YYYY] 虚拟当前时间的年 * [yyyy] 系统当前时间的年 * [MM] 虚拟当前时间的月 * [mm] 系统当前时间的月 * [DD] 虚拟当前时间的日 * [dd] 系统当前时间的日 * [HH] 虚拟当前时间的时 * [hh] 系统当前时间的时 * [MI] 虚拟当前时间的分 * [mi] 系统当前时间的分 * sys_name * 第3个参数,系统名称 * app_name * 第4个参数,应用名称 * server_name * 第5个参数,应用服务器名称 * istance_name * 第6个参数,实例名称 * send_mode * 第7个参数,数据发送模式,下列各参数的标记字符组合,如:AS|DS * AS SEND_MODE_ABROAD_SOCKET * DS SEND_MODE_DOMESTIC_SOCKET * AT SEND_MODE_ABROAD_TTAPI * DT SEND_MODE_DOMESTIC_TTAPI * * RTN: * others - reference to return code * *------------------------------------------------------------------------*/ int main(int argc, char *argv[]) { ABLOG_Entry(Public, main); DEFINE_DC_RETURN_CODE(); int iRtn; // 防止因网络异常导致程序退出 // 当服务器close一个连接时,若client端接着发数据。根据TCP 协议的规定,会收到一个RST响应, // client再往这个服务器发送数据时,系统会发出一个SIGPIPE信号给进程,告诉进程这个连接已经断开了,不要再写了。 // 根据信号的默认处理规则SIGPIPE信号的默认执行动作是terminate(终止、退出),所以client会退出。 // 若不想客户端退出可以把SIGPIPE设为SIG_IGN // 这时SIGPIPE交给了系统处理。 // 服务器采用了fork的话,要收集垃圾进程,防止僵尸进程的产生,可以这样处理: // signal(SIGCHLD,SIG_IGN); 交给系统init去回收。 // 这里子进程就不会产生僵尸进程了。 signal(SIGPIPE, SIG_IGN); // 收集验证启动参数 iRtn = check_args(argc, argv); if (iRtn == DC_RET_OK) { ABLOG_Printf(Metrics, (ABLOG,"[I] <---------------------------------------------------------------->")); ABLOG_Printf(Metrics, (ABLOG,"[I] <------------------------ Log DC Started ------------------------>")); ABLOG_Printf(Metrics, (ABLOG,"[I] <---------------------------------------------------------------->")); // 程序日志文件变更时,打印程序运行参数信息 on_ablog_reinitialized = print_args; // DC处理主过程 iRtn = main_process(); ABLOG_Printf(Metrics, (ABLOG,"[I] <------------------------- Log DC end -------------------------->")); } // 清理启动参数使用的资源 clear_args(); // 清理ab_code 使用的资源 clear_coding(); // 数据超时退出属于正常退出 ABLOG_Return_Code(iRtn == DC_RET_TIMEOUT_QUIT?DC_RET_OK:iRtn); }