/* * This file is part of Motion. * * Motion is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Motion is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Motion. If not, see . * */ #include "motion.hpp" #include "util.hpp" #include "conf.hpp" #include "logger.hpp" cls_log *motlog; const char *log_type_str[] = {NULL, "COR", "STR", "ENC", "NET", "DBS", "EVT", "TRK", "VID", "ALL"}; const char *log_level_str[] = {NULL, "EMG", "ALR", "CRT", "ERR", "WRN", "NTC", "INF", "DBG", "ALL"}; void ff_log(void *var1, int errnbr, const char *fmt, va_list vlist) { (void)var1; char buff[1024]; int fflvl; vsnprintf(buff, sizeof(buff), fmt, vlist); buff[strlen(buff)-1] = 0; if (strstr(buff, "forced frame type") != nullptr) { return; } /* AV_LOG_QUIET -8 1 AV_LOG_PANIC 0 2 AV_LOG_FATAL 8 3 AV_LOG_ERROR 16 4 AV_LOG_WARNING 24 5 AV_LOG_INFO 32 6 AV_LOG_VERBOSE 40 7 AV_LOG_DEBUG 48 8 AV_LOG_TRACE 56 9 */ fflvl = ((motlog->log_fflevel -2) * 8); if (errnbr <= fflvl ) { MOTPLS_LOG(INF, TYPE_ALL, NO_ERRNO,"%s",buff ); } } void cls_log::log_history_init() { int indx; ctx_log_item log_item; log_item.log_msg= ""; for (indx=0;indx<200;indx++){ log_item.log_nbr = indx; log_vec.push_back(log_item); } } void cls_log::log_history_add(std::string msg) { int indx, mx; mx = (int)log_vec.size(); for (indx=0;indx50000000L) { log_history_init(); } log_vec[mx-1].log_nbr++; log_vec[mx-1].log_msg = msg; } void cls_log::write_flood(int loglvl) { char flood_repeats[1024]; if (flood_cnt <= 1) { return; } snprintf(flood_repeats, sizeof(flood_repeats) , "%s Above message repeats %d times\n" , msg_prefix, flood_cnt-1); if (log_mode == LOGMODE_FILE) { fputs(flood_repeats, log_file_ptr); fflush(log_file_ptr); } else { /* The syslog level values are one less*/ syslog(loglvl-1, "%s", flood_repeats); fputs(flood_repeats, stderr); fflush(stderr); } log_history_add(flood_repeats); } void cls_log::write_norm(int loglvl, uint prefixlen) { flood_cnt = 1; if (snprintf(msg_flood, sizeof(msg_flood), "%s", &msg_full[prefixlen]) < 0) { return; } if (snprintf(msg_prefix, prefixlen, "%s", msg_full) < 0) { return; } if (log_mode == LOGMODE_FILE) { strcpy(msg_full + strlen(msg_full),"\n"); fputs(msg_full, log_file_ptr); fflush(log_file_ptr); } else { syslog(loglvl-1, "%s", msg_full); strcpy(msg_full + strlen(msg_full),"\n"); fputs(msg_full, stderr); fflush(stderr); } log_history_add(msg_full); } void cls_log::add_errmsg(int flgerr, int err_save) { size_t errsz, msgsz; char err_buf[90]; if (flgerr == NO_ERRNO) { return; } memset(err_buf, 0, sizeof(err_buf)); #if defined(XSI_STRERROR_R) /* XSI-compliant strerror_r() */ (void)strerror_r(err_save, err_buf, sizeof(err_buf)); #else/* GNU-specific strerror_r() */ (void)snprintf(err_buf, sizeof(err_buf),"%s" , strerror_r(err_save, err_buf, sizeof(err_buf))); #endif errsz = strlen(err_buf); msgsz = strlen(msg_full); if ((msgsz+errsz+2) >= sizeof(msg_full)) { msgsz = msgsz-errsz-2; memset(msg_full+msgsz, 0, sizeof(msg_full) - msgsz); } strcpy(msg_full+msgsz,": "); memcpy(msg_full+msgsz + 2, err_buf, errsz); } void cls_log::set_mode(int mode_new) { if ((log_mode != LOGMODE_SYSLOG) && (mode_new == LOGMODE_SYSLOG)) { openlog("motion", LOG_PID, LOG_USER); } if ((log_mode == LOGMODE_SYSLOG) && (mode_new != LOGMODE_SYSLOG)) { closelog(); } log_mode = mode_new; } void cls_log::set_log_file(std::string pname) { if ((pname == "") || (pname == "syslog")) { if (log_file_ptr != nullptr) { myfclose(log_file_ptr); log_file_ptr = nullptr; } if (log_file_name == "") { set_mode(LOGMODE_SYSLOG); log_file_name = "syslog"; MOTPLS_LOG(NTC, TYPE_ALL, NO_ERRNO, "Logging to syslog"); } } else if ((pname != log_file_name) || (log_file_ptr == nullptr)) { if (log_file_ptr != nullptr) { myfclose(log_file_ptr); log_file_ptr = nullptr; } log_file_ptr = myfopen(pname.c_str(), "ae"); if (log_file_ptr != nullptr) { log_file_name = pname; set_mode(LOGMODE_SYSLOG); MOTPLS_LOG(NTC, TYPE_ALL, NO_ERRNO, "Logging to file (%s)" ,pname.c_str()); set_mode(LOGMODE_FILE); } else { log_file_name = "syslog"; set_mode(LOGMODE_SYSLOG); MOTPLS_LOG(EMG, TYPE_ALL, SHOW_ERRNO, "Cannot create log file %s" , pname.c_str()); } } } void cls_log::write_msg(int loglvl, int msg_type, int flgerr, int flgfnc, ...) { int err_save, n; uint prefixlen; std::string usrfmt; char msg_time[32]; char threadname[32]; va_list ap; time_t now; if (loglvl > log_level) { return; } pthread_mutex_lock(&mutex_log); err_save = errno; memset(msg_full, 0, sizeof(msg_full)); mythreadname_get(threadname); now = time(NULL); strftime(msg_time, sizeof(msg_time) , "%b %d %H:%M:%S", localtime(&now)); if (log_mode == LOGMODE_FILE) { n = snprintf(msg_full, sizeof(msg_full) , "%s [%s][%s][%s] ", msg_time , log_level_str[loglvl],log_type_str[msg_type], threadname ); } else { n = snprintf(msg_full, sizeof(msg_full) , "[%s][%s][%s] " , log_level_str[loglvl],log_type_str[msg_type], threadname ); } prefixlen = (uint)n; /* flgfnc must be an int. Bool has compile error*/ va_start(ap, flgfnc); usrfmt = va_arg(ap, char *); if (flgfnc == 1) { usrfmt.append(": ").append(va_arg(ap, char *)); } n += vsnprintf(msg_full + n , sizeof(msg_full) - (uint)n - 1 , usrfmt.c_str(), ap); va_end(ap); add_errmsg(flgerr, err_save); if ((flood_cnt <= 5000) && mystreq(msg_flood, &msg_full[prefixlen])) { flood_cnt++; pthread_mutex_unlock(&mutex_log); return; } write_flood(loglvl); write_norm(loglvl, prefixlen); pthread_mutex_unlock(&mutex_log); } void cls_log::shutdown() { if (log_file_ptr != nullptr) { myfclose(log_file_ptr); log_file_ptr = nullptr; } } void cls_log::startup() { motlog->log_level = app->cfg->log_level; motlog->log_fflevel = app->cfg->log_fflevel; motlog->set_log_file(app->cfg->log_file); } cls_log::cls_log(cls_motapp *p_app) { app = p_app; log_mode = LOGMODE_NONE; log_level = LEVEL_DEFAULT; log_fflevel = 4; log_file_ptr = nullptr; log_file_name = ""; flood_cnt = 0; restart = false; set_mode(LOGMODE_SYSLOG); pthread_mutex_init(&mutex_log, NULL); memset(msg_prefix,0,sizeof(msg_prefix)); memset(msg_flood,0,sizeof(msg_flood)); memset(msg_full,0,sizeof(msg_full)); log_history_init(); av_log_set_callback(ff_log); } cls_log::~cls_log() { shutdown(); pthread_mutex_destroy(&mutex_log); }