📄 log.c
字号:
// ----------------------------------------------------------------------------// Copyright 2006-2007, Martin D. Flynn// All rights reserved// ----------------------------------------------------------------------------//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at// // http://www.apache.org/licenses/LICENSE-2.0// // Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.//// ----------------------------------------------------------------------------// Description:// Debug/Info logging.// - Since each platform may provide its own type of logging facilities, this// module has been placed in the 'custom/' folder.// - The logging facility provided here now includes support for Linux 'syslog'// output (which may be overkill for some embedded systems).// ---// Change History:// 2006/01/04 Martin D. Flynn// -Initial release// 2006/01/12 Martin D. Flynn// -Upgraded with syslog support// 2007/01/28 Martin D. Flynn// -WindowsCE port// -Added Aux storage logging// -Added threaded logging (to prevent logging from blocking other threads)// ----------------------------------------------------------------------------#include "stdafx.h" // TARGET_WINCE#include "custom/defaults.h"// For auxiliary message logging, the following must be defined:// "LOGGING_MESSAGE_FILE"// "LOGGING_AUX_DIRECTORY"// ----------------------------------------------------------------------------// uncomment to include syslog support#if defined(TARGET_LINUX) || defined(TARGET_GUMSTIX)# define INCLUDE_SYSLOG_SUPPORT#endif// uncomment to display log messages in a separate thread#define SYSLOG_THREAD// ----------------------------------------------------------------------------#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdarg.h>#include <ctype.h>#if defined(INCLUDE_SYSLOG_SUPPORT)# include <syslog.h>#endif#include "custom/log.h"#include "tools/stdtypes.h"#include "tools/strtools.h"#include "tools/utctools.h"#include "tools/threads.h"#include "tools/buffer.h"#include "tools/io.h"// ----------------------------------------------------------------------------#if defined(TARGET_WINCE)// (Windows return '-1' if lengths exceeds 'size' which is different than Linux)# define VSNPRINTF _vsnprintf#else// (Linux return the number of bytes that would have been written if the buffer were long enough)# define VSNPRINTF vsnprintf#endif// ----------------------------------------------------------------------------// This value may be overridden in "defaults.h" by defining "LOGGING_DEFAULT_LEVEL"#if defined(LOGGING_DEFAULT_LEVEL)# define DEFAULT_LOG_LEVEL LOGGING_DEFAULT_LEVEL#else# define DEFAULT_LOG_LEVEL -SYSLOG_ERROR // (neg) default to 'stderr'#endif#define MAX_MESSAGE_LENGTH 512#define CONSOLE_OUTPUT stderr#define FLUSH_MODULO 5L// ----------------------------------------------------------------------------static char syslogName[32];static int syslogLevel = (DEFAULT_LOG_LEVEL >= 0)? DEFAULT_LOG_LEVEL : -DEFAULT_LOG_LEVEL;static utBool syslogInit = utFalse;#if defined(INCLUDE_SYSLOG_SUPPORT)static utBool syslogEnabled = utTrue;#endifstatic threadMutex_t syslogMutex;#define LOG_LOCK MUTEX_LOCK(&syslogMutex);#define LOG_UNLOCK MUTEX_UNLOCK(&syslogMutex);#if defined(SYSLOG_THREAD)# define LOG_BUFFER_SIZE 3000 // should be sufficient for most casesstatic utBool syslogRunThread = utFalse;static threadThread_t syslogThread;static CircleBuffer_t *syslogBuffer = (CircleBuffer_t*)0;static threadCond_t syslogCond;static struct timespec syslogCondWaitTime;# define LOG_WAIT(T) CONDITION_TIMED_WAIT(&syslogCond,&syslogMutex,utcGetAbsoluteTimespec(&syslogCondWaitTime,(T)));# define LOG_NOTIFY CONDITION_NOTIFY(&syslogCond);#endif#if defined(LOGGING_MESSAGE_FILE) && defined(LOGGING_AUX_DIRECTORY)static FILE *syslogAuxFile = (FILE*)0;#endifstatic UInt32 syslogMsgCount = 0L;// ----------------------------------------------------------------------------/* maintain debug mode */static utBool _isDebugMode = utFalse;utBool isDebugMode() { return _isDebugMode; }/* set debug mode */void setDebugMode(utBool mode){ _isDebugMode = mode; logSetLevel(_isDebugMode? SYSLOG_DEBUG : DEFAULT_LOG_LEVEL); logEnableSyslog(utFalse);}// ----------------------------------------------------------------------------/* extract the source file name from the full path (ie. from '__FILE__') */const char *logSrcFile(const char *fn){ if (fn && *fn) { int fnLen = strlen(fn), fi = fnLen - 1, fLen = 0; const char *f = (char*)fn, *fp = (char*)0; for (; fi >= 0; fi--) { if (fn[fi] == '.') { fp = &fn[fi]; } if ((fn[fi] == '/') || (fn[fi] == '\\')) { f = &fn[fi + 1]; fLen = fp? (fp - f) : (fnLen - (fi + 1)); break; } } // 'f' - points to the beginning of the source file name // 'fp' - points to the (first) '.' before the extension // 'fLen' - is the length of the source file name without the extension return f; // just return the source file pointer } else { return fn; }}// ----------------------------------------------------------------------------/* syslog output */#if defined(INCLUDE_SYSLOG_SUPPORT)static void _logSyslogPrint(int level, const char *trace, const char *fmt, va_list ap){ char buf[MAX_MESSAGE_LENGTH]; if (!syslogInit) { logInitialize(0); } // <-- if not yet initialized int maxLen = 1 + strlen(trace) + 2 + strlen(fmt) + 1; if (trace && *trace && (maxLen < sizeof(buf))) { // combine 'trace' with 'fmt' sprintf(buf, "[%s] %s", trace, fmt); fmt = buf; } vsyslog(level, fmt, ap);}#endif// ----------------------------------------------------------------------------/* auxilliary output */#if defined(LOGGING_MESSAGE_FILE) && defined(LOGGING_AUX_DIRECTORY)static void _logAuxlogPrint(int level, const char *msg, int msgLen){ // Log to aux storage. // - Log to aux storage, but minimize the burden on the CPU. // - Allow the aux storage media to be removed at any time. if (syslogAuxFile || ioIsDirectory(LOGGING_AUX_DIRECTORY)) { // aux-storage dir exists (SD/MMC card is available) // Note: opening/closing the log file multiple times does impact // performance, so this feature should only be used for debugging purposes. if (!syslogAuxFile) { // open aux file syslogAuxFile = ioOpenStream(LOGGING_MESSAGE_FILE, IO_OPEN_APPEND); } if (syslogAuxFile) { // aux file is open, continue ... if (msgLen < 0) { msgLen = strlen(msg); } // includes '\n' if (fwrite(msg,1,msgLen,syslogAuxFile) < 0) { // write error occurred, close file ioCloseStream(syslogAuxFile); syslogAuxFile = (FILE*)0; } } }}#endif/* console output */#if defined(LOGGING_CONSOLE)static void _logConsolePrint(int level, const char *msg, int msgLen){ if ((level <= SYSLOG_INFO) || isDebugMode()) { fwrite(msg, 1, msgLen, CONSOLE_OUTPUT); }}#endif/* lock and log */static void _logMessagePrint(const char *msg, int msgLen){ /* nothing to print? */ if (!msg || !*msg || (msgLen <= 0)) { return; } /* skip first message character */ int level = *msg - '0'; const char *m = msg + 1; int mLen = msgLen - 1; /* aux file logging */#if defined(LOGGING_MESSAGE_FILE) && defined(LOGGING_AUX_DIRECTORY) _logAuxlogPrint(level, m, mLen);#endif /* console logging */#if defined(LOGGING_CONSOLE) _logConsolePrint(level, m, mLen);#endif}/* flush output */static void _logMessageFlush(){#if defined(LOGGING_MESSAGE_FILE) && defined(LOGGING_AUX_DIRECTORY) if (syslogAuxFile) { //if (isDebugMode()) { fprintf(CONSOLE_OUTPUT, "Flush ...\n"); } // ignore returned error code ioCloseStream(syslogAuxFile); // flush & close syslogAuxFile = (FILE*)0; }#endif#if defined(LOGGING_CONSOLE) ioFlushStream(CONSOLE_OUTPUT);#endif}// ----------------------------------------------------------------------------/* base logging print function */static void _logPrint(utBool force, int level, const char *fn, int line, const char *fmt, va_list ap){ // Levels: // LOG_EMERG 0 [not used] // LOG_ALERT 1 [not used] // LOG_CRIT 2 // LOG_ERR 3 // LOG_WARNING 4 // LOG_NOTICE 5 [not used] // LOG_INFO 6 // LOG_DEBUG 7 /* skip this message? */ if (!force && (level > syslogLevel)) { return; } /* extract source file from name */ // It is important that 'fn' not contain any string formatting characters char trace[80]; if (fn && *fn && (line > 0)) { int fnLen = strlen(fn), fi = fnLen - 1, fLen = 0; const char *f = (char*)fn, *fp = (char*)0; for (; fi >= 0; fi--) { if (fn[fi] == '.') { fp = &fn[fi]; } if ((fn[fi] == '/') || (fn[fi] == '\\')) { f = &fn[fi + 1]; fLen = fp? (fp - f) : (fnLen - (fi + 1)); break; } } if ((fLen + 7) < sizeof(trace)) { sprintf(trace,"%.*s:%d",fLen,f,line); fn = trace; } } /* syslog */#if defined(INCLUDE_SYSLOG_SUPPORT) if (syslogEnabled) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -