|  |  |  |  | /******************************************************************************
 | 
					
						
							|  |  |  |  |  * file    lib/management/better_log.c  | 
					
						
							|  |  |  |  |  * author  YuLiang | 
					
						
							|  |  |  |  |  * version 1.0.0 | 
					
						
							|  |  |  |  |  * date    14-Sep-2021 | 
					
						
							|  |  |  |  |  * brief   This file provides all the log operation functions. | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  ****************************************************************************** | 
					
						
							|  |  |  |  |  * Attention | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * <h2><center>© COPYRIGHT(c) 2021 LandPower</center></h2> | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * Redistribution and use in source and binary forms, with or without modification, | 
					
						
							|  |  |  |  |  * are permitted provided that the following conditions are met: | 
					
						
							|  |  |  |  |  *   1. Redistributions of source code must retain the above copyright notice, | 
					
						
							|  |  |  |  |  *      this list of conditions and the following disclaimer. | 
					
						
							|  |  |  |  |  *   2. Redistributions in binary form must reproduce the above copyright notice, | 
					
						
							|  |  |  |  |  *      this list of conditions and the following disclaimer in the documentation | 
					
						
							|  |  |  |  |  *      and/or other materials provided with the distribution. | 
					
						
							|  |  |  |  |  *   3. Neither the name of LandPower nor the names of its contributors may be used to  | 
					
						
							|  |  |  |  |  *      endorse or promote products derived from this software without specific | 
					
						
							|  |  |  |  |  *      prior written permission. | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | 
					
						
							|  |  |  |  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
					
						
							|  |  |  |  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 
					
						
							|  |  |  |  |  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | 
					
						
							|  |  |  |  |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
					
						
							|  |  |  |  |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | 
					
						
							|  |  |  |  |  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | 
					
						
							|  |  |  |  |  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 
					
						
							|  |  |  |  |  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
					
						
							|  |  |  |  |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  ******************************************************************************/ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* Includes ------------------------------------------------------------------*/ | 
					
						
							|  |  |  |  | //#ifdef HAVE_CONFIG_H
 | 
					
						
							|  |  |  |  | #include "config.h"
 | 
					
						
							|  |  |  |  | //#endif
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 标准C库头文件. */ | 
					
						
							|  |  |  |  | #include <stdarg.h>
 | 
					
						
							|  |  |  |  | #include <sys/types.h>
 | 
					
						
							|  |  |  |  | #include <sys/stat.h>
 | 
					
						
							|  |  |  |  | #include <execinfo.h>
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 用户代码头文件. */ | 
					
						
							|  |  |  |  | #include <fifo.h>
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* Private define ------------------------------------------------------------*/ | 
					
						
							|  |  |  |  | #define LOG_DB_LOCK pthread_mutex_lock(&log_sys->log_db_mutex)
 | 
					
						
							|  |  |  |  | #define LOG_DB_UNLOCK pthread_mutex_unlock(&log_sys->log_db_mutex)
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #define LOG_OUT 0
 | 
					
						
							|  |  |  |  | #define LOG_SHOW 1
 | 
					
						
							|  |  |  |  | /* Private macro -------------------------------------------------------------*/ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* Private typedef -----------------------------------------------------------*/ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* Private variables ---------------------------------------------------------*/ | 
					
						
							|  |  |  |  | log_sys_t *log_sys; | 
					
						
							|  |  |  |  | static char *log_str = NULL; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* log等级. */ | 
					
						
							|  |  |  |  | static const log_lvl_t log_priority[] = | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     {LOG_LVL_ERR, "err"}, | 
					
						
							|  |  |  |  |     {LOG_LVL_WARN, "warn"}, | 
					
						
							|  |  |  |  |     {LOG_LVL_NOTIF, "notif"}, | 
					
						
							|  |  |  |  |     {LOG_LVL_INFO, "info"}, | 
					
						
							|  |  |  |  |     {LOG_LVL_DBG, "debug"}, | 
					
						
							|  |  |  |  |     {-1, NULL} | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* log模块. */ | 
					
						
							|  |  |  |  | static const log_module_t log_module_names[] = | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     {LOG_DEFAULT, "DEFAULT"}, | 
					
						
							|  |  |  |  |     {LOG_CLI, "CLI"}, | 
					
						
							|  |  |  |  |     {LOG_MEMORY, "MEMORY"}, | 
					
						
							|  |  |  |  |     {LOG_FIFO, "FIFO"}, | 
					
						
							|  |  |  |  |     {LOG_GPIO, "GPIO"}, | 
					
						
							|  |  |  |  |     {LOG_PD, "PD"}, | 
					
						
							|  |  |  |  |     {LOG_DAU, "DAU"}, | 
					
						
							|  |  |  |  |     {LOG_CSG, "CSG"}, | 
					
						
							|  |  |  |  |     {LOG_STORAGE, "STORAGE"}, | 
					
						
							|  |  |  |  |     {LOG_DEBUG, "DEBUG"}, | 
					
						
							|  |  |  |  |     {LOG_UPGRADE, "UPGRADE"}, | 
					
						
							|  |  |  |  |     {-1, NULL} | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* Private function prototypes -----------------------------------------------*/ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* Internal functions --------------------------------------------------------*/ | 
					
						
							|  |  |  |  | /* 删除多余的 log 保留 5000 条. */ | 
					
						
							|  |  |  |  | void _log_clean(void) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     log_sys_t *log = log_sys; | 
					
						
							|  |  |  |  |     char *zErrMsg = NULL; | 
					
						
							|  |  |  |  |     const char *sql = "delete from better_log where id<(select Max(id) from better_log)-5000;"; | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     if (sqlite3_exec(log->db, sql, 0, 0, &zErrMsg) != SQLITE_OK) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         printh("SQL delete error: %s\r\n", zErrMsg); | 
					
						
							|  |  |  |  |         sqlite3_free(zErrMsg); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 文件log输出底层函数. */ | 
					
						
							|  |  |  |  | void _log_out_db(LOG_MODULE_E module, LOG_LVL_E priority, const char *va_str) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     static uint16_t cnt = 0; | 
					
						
							|  |  |  |  |     log_sys_t *log = log_sys; | 
					
						
							|  |  |  |  |     char time_str[TIME_STR_LEN] = {0}; | 
					
						
							|  |  |  |  |     char *zErrMsg = NULL; | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     time_string(log->timestamp_precision, time_str, sizeof(time_str)); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     LOG_DB_LOCK; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     snprintf(log_str, LOG_CMD_LEN,  | 
					
						
							|  |  |  |  |         "INSERT INTO better_log (LEVEL,LOG) VALUES (%d, \"%s %s-%s: %s\"); ", | 
					
						
							|  |  |  |  |         priority, time_str, log_priority[priority].describe, log_module_names[module].describe, va_str );    //id 已设为自增
 | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     if (sqlite3_exec( log->db, log_str, 0, 0, &zErrMsg ) != SQLITE_OK) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         printh("SQL INSERT error: %s\r\n", zErrMsg); | 
					
						
							|  |  |  |  |         sqlite3_free(zErrMsg); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |          | 
					
						
							|  |  |  |  |     /*定量清除log*/ | 
					
						
							|  |  |  |  |     cnt++; | 
					
						
							|  |  |  |  |     if (cnt >= 500) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         clock_t begin,end; | 
					
						
							|  |  |  |  |         begin = clock(); | 
					
						
							|  |  |  |  |         _log_clean(); | 
					
						
							|  |  |  |  |         end = clock(); | 
					
						
							|  |  |  |  |         printh("Log clean runtimer : %lf\r\n",(double)(end-begin)/CLOCKS_PER_SEC); | 
					
						
							|  |  |  |  |         cnt = 0; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     LOG_DB_UNLOCK; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 解日志输出fifo数据封装 */ | 
					
						
							|  |  |  |  | static void _log_out(_log_out_t *data) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     _log_out_db(data->module, data->lvl, data->log_out_str); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 串口日志输出 */ | 
					
						
							|  |  |  |  | static void _log_out_std( LOG_MODULE_E module, LOG_LVL_E priority, const char *va_str ) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     log_sys_t *log = log_sys; | 
					
						
							|  |  |  |  |          | 
					
						
							|  |  |  |  |     char time_str[TIME_STR_LEN] = {0}; | 
					
						
							|  |  |  |  |     time_string(log->timestamp_precision, time_str, sizeof(time_str)); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     printh("%s %s-%s: %s\n", time_str, log_priority[priority].describe, log_module_names[module].describe, va_str); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 将日志按照格式串口打印 */ | 
					
						
							|  |  |  |  | static int _log_show_print(void *data, int argc, char **argv, char **azColName) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     printh("LOG id %s: %s\r\n", argv[0], argv[2]); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     return 0; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* log打印底层函数 */ | 
					
						
							|  |  |  |  | static void _log_show(_log_show_t *data) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     log_sys_t *log = log_sys; | 
					
						
							|  |  |  |  |     char *zErrMsg = NULL; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     LOG_DB_LOCK; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     memset(log_str, 0, LOG_CMD_LEN); | 
					
						
							|  |  |  |  |     switch (data->type) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |     case LOG_SHOW_CNT:      //打印指定数量的日志
 | 
					
						
							|  |  |  |  |         snprintf(log_str, LOG_CMD_LEN, "SELECT * FROM better_log ORDER BY id DESC LIMIT %d;", data->param); | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     case LOG_SHOW_LVL:      //打印指定等级的日志
 | 
					
						
							|  |  |  |  |         snprintf(log_str, LOG_CMD_LEN, "SELECT * FROM better_log WHERE LEVEL = %d ORDER BY id DESC LIMIT 100;", data->param); | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     case LOG_SHOW_KEYWORD:  //打印含关键词的日志
 | 
					
						
							|  |  |  |  |         if (data->param <= 0) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             snprintf(log_str, LOG_CMD_LEN, "SELECT * FROM better_log WHERE LOG GLOB \'*%s*\' ORDER BY id DESC;", | 
					
						
							|  |  |  |  |                       data->log_show_str); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         else | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             snprintf(log_str, LOG_CMD_LEN, "SELECT * FROM better_log WHERE LOG GLOB \'*%s*\' ORDER BY id DESC LIMIT %d;", | 
					
						
							|  |  |  |  |                       data->log_show_str, data->param); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     default:    //打印所有日志
 | 
					
						
							|  |  |  |  |         snprintf(log_str, LOG_CMD_LEN, "SELECT * FROM better_log ORDER BY id DESC;"); | 
					
						
							|  |  |  |  |         break; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     if (sqlite3_exec(log->db, log_str, _log_show_print, 0, &zErrMsg) != SQLITE_OK) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         printh("SQL show error: %s\r\n", zErrMsg); | 
					
						
							|  |  |  |  |         sqlite3_free(zErrMsg); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     LOG_DB_UNLOCK; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 封装数据并写fifo */ | 
					
						
							|  |  |  |  | int32_t _log_msg_send(uint32_t type, void *data) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     _log_msg_t log_msg; | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     /* 封装消息. */ | 
					
						
							|  |  |  |  |     log_msg.type = type; | 
					
						
							|  |  |  |  |     log_msg.data = data; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /* 发送消息 */ | 
					
						
							|  |  |  |  |     if (fifo_write(log_sys->log_fifo_id, (void*)(&log_msg), sizeof(_log_msg_t)) != sizeof(_log_msg_t)) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         DBG(DBG_M_FIFO, "LOG write ERROR!\r\n"); | 
					
						
							|  |  |  |  |         return E_ERROR; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     return E_NONE; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 经由fifo输出日志 */ | 
					
						
							|  |  |  |  | void _log_fifo_out(LOG_MODULE_E module, LOG_LVL_E priority, const char *va_str) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     _log_out_t *log_data = NULL; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     log_data = XMALLOC_Q(MTYPE_LOG, sizeof(_log_out_t)); | 
					
						
							|  |  |  |  |     if (!log_data) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         return; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     log_data->module = module; | 
					
						
							|  |  |  |  |     log_data->lvl = priority; | 
					
						
							|  |  |  |  |     snprintf(log_data->log_out_str, LOG_STR_LEN, va_str); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     _log_msg_send(LOG_OUT, log_data); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 读取log fifo数据循环线程 */ | 
					
						
							|  |  |  |  | void *_log_handle(void *arg) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     _log_msg_t *recv_msg = NULL; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     while(1) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         if (fifo_read(log_sys->log_fifo_id, (void **)&recv_msg) != 0) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             DBG(DBG_M_FIFO, "ERROR at fifo %d read!\r\n", log_sys->log_fifo_id); | 
					
						
							|  |  |  |  |             continue; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         if (recv_msg->type == LOG_OUT)  //输出日志,写数据库
 | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             _log_out((_log_out_t*) recv_msg->data); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         else if (recv_msg->type == LOG_SHOW)    //打印日志,读数据库
 | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |             _log_show((_log_show_t*) recv_msg->data); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         XFREE(MTYPE_LOG, recv_msg->data); | 
					
						
							|  |  |  |  |         fifo_push(log_sys->log_fifo_id); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return NULL; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* Interface functions -------------------------------------------------------*/ | 
					
						
							|  |  |  |  | /* log打印输出函数. */ | 
					
						
							|  |  |  |  | #define BLOG_FUNC(FUNCNAME,PRIORITY) \
 | 
					
						
							|  |  |  |  | void FUNCNAME(LOG_MODULE_E module, const char *format, ...) \ | 
					
						
							|  |  |  |  | { \ | 
					
						
							|  |  |  |  |     char str[LOG_STR_LEN] = {0}; \ | 
					
						
							|  |  |  |  |     log_sys_t *log = log_sys; \ | 
					
						
							|  |  |  |  |     if (NULL == log) return; \ | 
					
						
							|  |  |  |  |     va_list args; \ | 
					
						
							|  |  |  |  |     va_start(args, format); \ | 
					
						
							|  |  |  |  |     vsnprintf(str, LOG_STR_LEN, format, args); \ | 
					
						
							|  |  |  |  |     va_end(args); \ | 
					
						
							|  |  |  |  |     if ((1 << PRIORITY) & log->enable_lvl[LOG_MODE_STDOUT]) \ | 
					
						
							|  |  |  |  |         _log_out_std(module, PRIORITY, str); \ | 
					
						
							|  |  |  |  |     if (((1 << PRIORITY) & log->enable_lvl[LOG_MODE_FILE]) && log->db){ \ | 
					
						
							|  |  |  |  |         if (log_sys->log_fifo_id) \ | 
					
						
							|  |  |  |  |             _log_fifo_out(module, PRIORITY, str); \ | 
					
						
							|  |  |  |  |         else \ | 
					
						
							|  |  |  |  |             _log_out_db(module, PRIORITY, str);} \ | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | BLOG_FUNC(log_err, LOG_LVL_ERR) | 
					
						
							|  |  |  |  | BLOG_FUNC(log_warn, LOG_LVL_WARN) | 
					
						
							|  |  |  |  | BLOG_FUNC(log_info, LOG_LVL_INFO) | 
					
						
							|  |  |  |  | BLOG_FUNC(log_notice, LOG_LVL_NOTIF) | 
					
						
							|  |  |  |  | BLOG_FUNC(log_debug, LOG_LVL_DBG) | 
					
						
							|  |  |  |  | #undef BLOG_FUNC
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* description: log输出.
 | 
					
						
							|  |  |  |  |    param:   module      --  指定模块 | 
					
						
							|  |  |  |  |             priority    --  指定优先级 | 
					
						
							|  |  |  |  |    return: */ | 
					
						
							|  |  |  |  | void log_out(LOG_MODULE_E module, LOG_LVL_E priority, const char *format, ...) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     char str[LOG_STR_LEN] = {0}; \ | 
					
						
							|  |  |  |  |     log_sys_t *log = log_sys; | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     if (NULL == log) return; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     va_list args; | 
					
						
							|  |  |  |  |     va_start(args, format); | 
					
						
							|  |  |  |  |     vsnprintf(str, LOG_STR_LEN, format, args); | 
					
						
							|  |  |  |  |     va_end (args); | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     /* 串口log. */ | 
					
						
							|  |  |  |  |     if ((1 << priority) & log->enable_lvl[LOG_MODE_STDOUT]) | 
					
						
							|  |  |  |  |         _log_out_std(module, priority, str); | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     /* 判断是否是文件输出 */ | 
					
						
							|  |  |  |  |     if (((1 << priority) & log->enable_lvl[LOG_MODE_FILE]) && log->db) | 
					
						
							|  |  |  |  |         _log_out_db(module, priority, str); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 打印日志函数 */ | 
					
						
							|  |  |  |  | void log_show(int32_t show_cnt, LOG_LVL_E priority, const char *key_word) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     _log_show_t *log_data = NULL; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     log_data = XMALLOC_Q(MTYPE_LOG, sizeof(_log_show_t)); | 
					
						
							|  |  |  |  |     if (!log_data) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         return; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     if (priority != LOG_LVL_MAX)      // 按等级打印日志
 | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         log_data->type = LOG_SHOW_LVL; | 
					
						
							|  |  |  |  |         log_data->param = priority; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     else if (key_word != NULL)      // 高级打印功能
 | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         log_data->type = LOG_SHOW_KEYWORD; | 
					
						
							|  |  |  |  |         log_data->param = show_cnt; | 
					
						
							|  |  |  |  |         snprintf(log_data->log_show_str, LOG_STR_LEN, key_word); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     else if (show_cnt > 0)   // 按数量打印日志
 | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         log_data->type = LOG_SHOW_CNT; | 
					
						
							|  |  |  |  |         log_data->param = show_cnt; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     else | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         log_data->type = LOG_SHOW_MAX; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     _log_msg_send(LOG_SHOW, log_data); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* description: log系统初始化.
 | 
					
						
							|  |  |  |  |    param: | 
					
						
							|  |  |  |  |    return: (0)完成,(-1)失败 */ | 
					
						
							|  |  |  |  | int32_t log_open() | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     log_sys_t *log = NULL; | 
					
						
							|  |  |  |  |     int32_t i = 0; | 
					
						
							|  |  |  |  |     int32_t rv = 0; | 
					
						
							|  |  |  |  |     char *sql = NULL; | 
					
						
							|  |  |  |  |     char *zErrMsg = NULL; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /* 申请内存. */ | 
					
						
							|  |  |  |  |     log_str = XMALLOC(MTYPE_LOG, LOG_CMD_LEN); | 
					
						
							|  |  |  |  |     log_sys = XMALLOC(MTYPE_LOG, sizeof(log_sys_t)); | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     if (NULL == log_sys) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |        return E_MEM; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     log = log_sys; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     pthread_mutex_init(&log->log_db_mutex, NULL); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /* 打开 log 数据库. */ | 
					
						
							|  |  |  |  |     log->filename = XSTRDUP(MTYPE_LOG, LOG_FILE); | 
					
						
							|  |  |  |  |     rv = sqlite3_open(log->filename, &log->db); | 
					
						
							|  |  |  |  |     if (rv) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         log->db = NULL; | 
					
						
							|  |  |  |  |         printf("Can't open database: %s\r\n", sqlite3_errmsg(log->db)); | 
					
						
							|  |  |  |  |         return E_SYS_CALL; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /* 创建表. */ | 
					
						
							|  |  |  |  |     sql = "CREATE TABLE IF NOT EXISTS better_log(" \ | 
					
						
							|  |  |  |  |          "ID INTEGER PRIMARY KEY  AUTOINCREMENT NOT NULL," \ | 
					
						
							|  |  |  |  |          "LEVEL              INT8 NOT NULL," \ | 
					
						
							|  |  |  |  |          "LOG                TEXT);"; | 
					
						
							|  |  |  |  |     if (sqlite3_exec(log->db, sql, 0, 0, &zErrMsg) != SQLITE_OK) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         printf("SQL create error: %s\r\n", zErrMsg); | 
					
						
							|  |  |  |  |         sqlite3_free(zErrMsg); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     /* 设置默认log级别输出方式 */ | 
					
						
							|  |  |  |  |     for (i = 0; i < LOG_MODE_MAX; i++) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         log->enable_lvl[i] = 0; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     log->enable_lvl[LOG_MODE_FILE] = (1 << LOG_LVL_ERR) | (1 << LOG_LVL_WARN) | (1 << LOG_LVL_NOTIF); | 
					
						
							|  |  |  |  |     log->enable_lvl[LOG_MODE_STDOUT] = (1 << LOG_LVL_ERR) | (1 << LOG_LVL_WARN) | (1 << LOG_LVL_NOTIF); | 
					
						
							|  |  |  |  |     log->enable_lvl[LOG_MODE_MONITOR] = (1 << LOG_LVL_ERR) | (1 << LOG_LVL_WARN) | (1 << LOG_LVL_NOTIF); | 
					
						
							|  |  |  |  |     log->default_lvl = 0; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /* 清除多余的日志 */ | 
					
						
							|  |  |  |  |     _log_clean(); | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     return E_NONE; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* description: 配置对应等级的log的输出方式.
 | 
					
						
							|  |  |  |  |    param:   mode      --  输出方式 | 
					
						
							|  |  |  |  |             log_level   --  输出等级 | 
					
						
							|  |  |  |  |    return:  */ | 
					
						
							|  |  |  |  | void log_set_level(LOG_MODE_E mode, LOG_LVL_E log_level) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     log_sys->enable_lvl[mode] |= (1 << log_level); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* description: 取消对应等级的log的输出方式.
 | 
					
						
							|  |  |  |  |    param:   mode      --  输出方式 | 
					
						
							|  |  |  |  |             log_level   --  输出等级 | 
					
						
							|  |  |  |  |    return:  */ | 
					
						
							|  |  |  |  | void log_unset_level(LOG_MODE_E mode, LOG_LVL_E log_level) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     log_sys->enable_lvl[mode] &= ~(1 << log_level); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* description: 根据传入的字符串返回相应的log优先级.
 | 
					
						
							|  |  |  |  |    param:   lvl_name    --  输出等级的字符串 | 
					
						
							|  |  |  |  |    return:  (LOG_LVL_E)输出等级 */ | 
					
						
							|  |  |  |  | int32_t log_level_get_by_name(const char *lvl_name) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     int32_t level = LOG_LVL_MAX; | 
					
						
							|  |  |  |  |    | 
					
						
							|  |  |  |  |     for (level = 0 ; log_priority[level].describe != NULL ; level++) | 
					
						
							|  |  |  |  |     if (!strncmp(lvl_name, log_priority[level].describe, 2)) | 
					
						
							|  |  |  |  |         return log_priority[level].lvl; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     return LOG_LVL_MAX; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* 打印堆栈使用情况:  */ | 
					
						
							|  |  |  |  | /* description: 根据传入的字符串返回相应的log优先级.
 | 
					
						
							|  |  |  |  |    param:   priority    --  log优先级 | 
					
						
							|  |  |  |  |    return: */ | 
					
						
							|  |  |  |  | void log_backtrace(int32_t priority) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     void *array[BACKTRACE_SIZE] = {NULL}; | 
					
						
							|  |  |  |  |     int32_t size = 0; | 
					
						
							|  |  |  |  |     int32_t i = 0; | 
					
						
							|  |  |  |  |     char **strings = NULL; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     size = backtrace(array, BACKTRACE_SIZE); | 
					
						
							|  |  |  |  |     if ((size <= 0) || ((size_t)size > BACKTRACE_SIZE)) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         log_err(LOG_DEFAULT, "Cannot get backtrace, returned invalid # of frames %d " | 
					
						
							|  |  |  |  |                 "(valid range is between 1 and %d)", size, BACKTRACE_SIZE); | 
					
						
							|  |  |  |  |         return; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     log_out(LOG_DEFAULT, priority, "Backtrace for %d stack frames:", size); | 
					
						
							|  |  |  |  |     strings = backtrace_symbols(array, size); | 
					
						
							|  |  |  |  |     if (!strings) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         log_out(LOG_DEFAULT, priority, "Cannot get backtrace symbols (out of memory?)"); | 
					
						
							|  |  |  |  |         for (i = 0; i < size; i++) | 
					
						
							|  |  |  |  |             log_out(LOG_DEFAULT, priority, "[bt %d] %p", i, array[i]); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     else | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         for (i = 0; i < size; i++) | 
					
						
							|  |  |  |  |             log_out(LOG_DEFAULT, priority, "[bt %d] %s",i,strings[i]); | 
					
						
							|  |  |  |  |         free(strings); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | int32_t log_handle_init(void) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     struct sched_param param; | 
					
						
							|  |  |  |  |     pthread_attr_t attr; | 
					
						
							|  |  |  |  |     pthread_t pid; | 
					
						
							|  |  |  |  |     int rv = 0; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /* 初始化log fifo */ | 
					
						
							|  |  |  |  |     log_sys->log_fifo_id = fifo_create(LOG_DB_FIFO, 32); | 
					
						
							|  |  |  |  |     if (log_sys->log_fifo_id < 0) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         log_out(LOG_DEFAULT, LOG_LVL_ERR, "Open fifo " LOG_DB_FIFO " error."); | 
					
						
							|  |  |  |  |         return E_ERROR; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     /* 配置线程RR调度,优先级25 */ | 
					
						
							|  |  |  |  |     pthread_attr_init(&attr); | 
					
						
							|  |  |  |  |     param.sched_priority = 25; | 
					
						
							|  |  |  |  |     pthread_attr_setschedpolicy(&attr, SCHED_RR); | 
					
						
							|  |  |  |  |     pthread_attr_setschedparam(&attr, ¶m); | 
					
						
							|  |  |  |  |     pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); | 
					
						
							|  |  |  |  |     rv = pthread_create(&pid, &attr, _log_handle, NULL); | 
					
						
							|  |  |  |  |     if (rv != 0) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         log_out(LOG_DEFAULT, LOG_LVL_ERR, "PD can't create log db pthread %d.", rv); | 
					
						
							|  |  |  |  |         return E_SYS_CALL; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     else | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         thread_m_add("LOG_DB_THREAD", pid); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     pthread_attr_destroy(&attr); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     return E_NONE; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | /************************ (C) COPYRIGHT LandPower ***** END OF FILE ****************/ |