/// \brief Map a log level enumerated value back to the name /// \param level Enumerated value of the log level /// \return Log level name. "unknown" if not found. QString logLevelGetName(LogLevel_t level) { QMutexLocker locker(&loglevelMapMutex); if (!verboseInitialized) { locker.unlock(); verboseInit(); locker.relock(); } LoglevelMap::iterator it = loglevelMap.find((int)level); if ( it == loglevelMap.end() ) return QString("unknown"); return (*it)->name; }
/// \brief Map a log level name back to the enumerated value /// \param level QString containing the log level name /// \return Log level as enumerated type. LOG_UNKNOWN if not found. LogLevel_t logLevelGet(QString level) { QMutexLocker locker(&loglevelMapMutex); if (!verboseInitialized) { locker.unlock(); verboseInit(); locker.relock(); } for (LoglevelMap::iterator it = loglevelMap.begin(); it != loglevelMap.end(); ++it) { LoglevelDef *item = (*it); if ( item->name == level.toLower() ) return (LogLevel_t)item->value; } return LOG_UNKNOWN; }
/// \brief Add a log level to the logLevelMap. Done at initialization. /// \param value log level enumerated value (LOG_*) - matches syslog /// levels /// \param name name of the log level /// \param shortname one-letter short name for output into logs void loglevelAdd(int value, QString name, char shortname) { LoglevelDef *item = new LoglevelDef; item->value = value; name.detach(); // LOG_CRIT -> crit name.remove(0, 4); name = name.toLower(); item->name = name; item->shortname = shortname; loglevelMap.insert(value, item); }
/// \brief Process a log message, writing to the console /// \param item LoggingItem containing the log message to process bool LoggerThread::logConsole(LoggingItem *item) { char line[MAX_STRING_LENGTH]; char usPart[9]; char timestamp[TIMESTAMP_MAX]; if (m_quiet || (m_progress && item->m_level > LOG_ERR)) return false; if (!(item->m_type & kMessage)) return false; item->IncrRef(); if (item->m_type & kStandardIO) snprintf( line, MAX_STRING_LENGTH, "%s", item->m_message ); else { time_t epoch = item->epoch(); struct tm tm; localtime_r(&epoch, &tm); strftime( timestamp, TIMESTAMP_MAX-8, "%Y-%m-%d %H:%M:%S", (const struct tm *)&tm ); snprintf( usPart, 9, ".%06d", (int)(item->m_usec) ); strcat( timestamp, usPart ); char shortname; { QMutexLocker locker(&loglevelMapMutex); LoglevelDef *lev = loglevelMap.value(item->m_level, NULL); if (!lev) shortname = '-'; else shortname = lev->shortname; } snprintf( line, MAX_STRING_LENGTH, "%s %c %s\n", timestamp, shortname, item->m_message ); } int result = write( 1, line, strlen(line) ); (void)result; item->DecrRef(); return true; }
/// \brief Initialize the logging levels and verbose levels. void verboseInit(void) { QMutexLocker locker(&verboseMapMutex); QMutexLocker locker2(&loglevelMapMutex); verboseMap.clear(); loglevelMap.clear(); // This looks funky, so I'll put some explanation here. The verbosedefs.h // file gets included as part of the mythlogging.h include, and at that // time, the normal (without _IMPLEMENT_VERBOSE defined) code case will // define the VerboseMask enum. At this point, we force it to allow us // to include the file again, but with _IMPLEMENT_VERBOSE set so that the // single definition of the VB_* values can be shared to define also the // contents of verboseMap, via repeated calls to verboseAdd() #undef VERBOSEDEFS_H_ #define _IMPLEMENT_VERBOSE #include "verbosedefs.h" verboseInitialized = true; }
bool FileLogger::logmsg(LoggingItem *item) { char line[MAX_STRING_LENGTH]; char usPart[9]; char timestamp[TIMESTAMP_MAX]; char *threadName = NULL; pid_t pid = getpid(); if (!m_opened || m_quiet || (m_progress && item->level > LOG_ERR)) return false; item->refcount.ref(); strftime( timestamp, TIMESTAMP_MAX-8, "%Y-%m-%d %H:%M:%S", (const struct tm *)&item->tm ); snprintf( usPart, 9, ".%06d", (int)(item->usec) ); strcat( timestamp, usPart ); char shortname; { QMutexLocker locker(&loglevelMapMutex); LoglevelMap::iterator it = loglevelMap.find(item->level); if (it == loglevelMap.end()) shortname = '-'; else shortname = (*it)->shortname; } if (item->type & kStandardIO) { snprintf( line, MAX_STRING_LENGTH, "%s", item->message ); } else if (m_fd == 1) { // Stdout snprintf( line, MAX_STRING_LENGTH, "%s %c %s\n", timestamp, shortname, item->message ); } else { threadName = getThreadName(item); pid_t tid = getThreadTid(item); if( tid ) snprintf( line, MAX_STRING_LENGTH, "%s %c [%d/%d] %s %s:%d (%s) - %s\n", timestamp, shortname, pid, tid, threadName, item->file, item->line, item->function, item->message ); else snprintf( line, MAX_STRING_LENGTH, "%s %c [%d] %s %s:%d (%s) - %s\n", timestamp, shortname, pid, threadName, item->file, item->line, item->function, item->message ); } int fd = (item->type & kStandardIO) ? 1 : m_fd; int result = write( fd, line, strlen(line) ); deleteItem(item); if( result == -1 ) { LOG(VB_GENERAL, LOG_ERR, QString("Closed Log output on fd %1 due to errors").arg(m_fd)); m_opened = false; if( m_fd != 1 ) close( m_fd ); return false; } return true; }