version 1.2, 2015/04/20 18:10:09
|
version 1.3, 2015/04/20 18:19:49
|
|
|
**============================================================================== | **============================================================================== |
*/ | */ |
| |
#include "log.h" |
#include "logbase.h" |
| |
#if defined(CONFIG_OS_WINDOWS) | #if defined(CONFIG_OS_WINDOWS) |
# include <windows.h> | # include <windows.h> |
|
|
# include <sys/time.h> | # include <sys/time.h> |
# include <sys/types.h> | # include <sys/types.h> |
# include <time.h> | # include <time.h> |
|
# if defined(linux) |
|
# include <syscall.h> |
|
# endif |
#endif | #endif |
| |
#include "strings.h" |
// Disable this by default as it slows down performance (by about 12% in tests with 2 threads) |
#include "io.h" |
// it can be re-activated if intermingled traces become too difficult to read and it doesnt affect repro in that particular case |
|
// Note though that It will not prevent the case of different executables logging to the same files |
|
//#define LOGC_USES_LOCK |
|
|
|
#include <pal/strings.h> |
|
#include <pal/format.h> |
|
#include <pal/process.h> |
|
#include <pal/thread.h> |
|
#ifdef LOGC_USES_LOCK |
|
#include <pal/lock.h> |
|
#endif |
| |
/* | /* |
**============================================================================== | **============================================================================== |
|
|
*/ | */ |
| |
static FILE* _os; | static FILE* _os; |
|
#ifdef LOGC_USES_LOCK |
|
static Lock _logLock; |
|
#endif |
|
static Log_Level _level = OMI_WARNING; |
|
|
| |
static const char* _levelStrings[] = | static const char* _levelStrings[] = |
{ | { |
|
|
"WARNING", | "WARNING", |
"INFO", | "INFO", |
"DEBUG", | "DEBUG", |
|
"VERBOSE", |
}; | }; |
| |
static Log_Level _level = LOG_WARNING; |
PAL_INLINE PAL_Boolean _ShouldLog(int level) |
static Log_Level _currentLevel = LOG_WARNING; |
{ |
|
if (level > Log_GetLevel()) |
|
return PAL_FALSE; |
|
else |
|
return PAL_TRUE; |
|
} |
|
|
|
#define FMTSIZE 1024 |
|
void FilePutLog( |
|
int priority, |
|
int eventId, |
|
const char * file, |
|
int line, |
|
const PAL_Char* format, |
|
...) |
|
{ |
|
if ((unsigned int)priority > OMI_VERBOSE) |
|
return; |
|
|
|
if (_ShouldLog(priority)) |
|
{ |
|
TChar fmt[FMTSIZE]; |
|
va_list ap; |
|
|
|
Stprintf(fmt, FMTSIZE, PAL_T("EventId=%d Priority=%s "), eventId, _levelStrings[priority]); |
|
Tcslcat(fmt, format, FMTSIZE); |
|
|
|
va_start(ap, format); |
|
Log_VPut((Log_Level)priority, file, line, fmt, ap); |
|
va_end(ap); |
|
} |
|
} |
| |
static int _GetCurrentTimeInUsec(MI_Uint64* usec) |
int _GetCurrentTimeInUsec(MI_Uint64* usec) |
{ | { |
#if defined(CONFIG_OS_WINDOWS) | #if defined(CONFIG_OS_WINDOWS) |
FILETIME ft; | FILETIME ft; |
|
|
| |
#define TIMESTAMP_SIZE 128 | #define TIMESTAMP_SIZE 128 |
| |
static int _GetTimeStamp(char buf[TIMESTAMP_SIZE]) |
static int _GetTimeStamp(_Pre_writable_size_(TIMESTAMP_SIZE) char buf[TIMESTAMP_SIZE]) |
{ |
|
MI_Uint64 usec; |
|
|
|
if (_GetCurrentTimeInUsec(&usec) != 0) |
|
{ | { |
buf[0] = '\0'; |
|
return -1; |
|
} |
|
|
|
#if defined(CONFIG_OS_WINDOWS) | #if defined(CONFIG_OS_WINDOWS) |
{ | { |
time_t t = usec / 1000000; |
SYSTEMTIME systime; |
struct tm tm; |
GetLocalTime(&systime); |
localtime_s(&tm, &t); |
|
sprintf_s( | sprintf_s( |
buf, | buf, |
TIMESTAMP_SIZE, | TIMESTAMP_SIZE, |
"%02u/%02u/%02u %02u:%02u:%02u", | "%02u/%02u/%02u %02u:%02u:%02u", |
tm.tm_year + 1900, |
systime.wYear, |
tm.tm_mon + 1, |
systime.wMonth, |
tm.tm_mday, |
systime.wDay, |
tm.tm_hour, |
systime.wHour, |
tm.tm_min, |
systime.wMinute, |
tm.tm_sec); |
systime.wSecond); |
} | } |
#else | #else |
|
MI_Uint64 usec; |
|
|
|
if (_GetCurrentTimeInUsec(&usec) != 0) |
|
{ |
|
buf[0] = '\0'; |
|
return -1; |
|
} |
|
|
{ | { |
time_t t = usec / 1000000; | time_t t = usec / 1000000; |
struct tm tm; | struct tm tm; |
|
|
return 0; | return 0; |
} | } |
| |
#if (MI_CHAR_TYPE == 2) |
|
static char* _StrdupWcharToASCII7(const MI_Char* str) |
|
{ |
|
char* p; |
|
|
|
/* Allocate room for string */ |
|
p = (char*)malloc(Wcslen(str) + 1); |
|
|
|
if (!p) |
|
return NULL; |
|
|
|
/* Copy string while failing on non-ASCII characters */ |
|
while (*str) |
|
{ |
|
if ((MI_Uint32)*str >= 128) |
|
{ |
|
free(p); |
|
return NULL; |
|
} |
|
*p++ = (char)*str++; |
|
} |
|
|
|
return p; |
|
} |
|
#endif |
|
|
|
static void _PutHeader( | static void _PutHeader( |
FILE* os, | FILE* os, |
const char* file, | const char* file, |
|
|
char buf[TIMESTAMP_SIZE]; | char buf[TIMESTAMP_SIZE]; |
| |
_GetTimeStamp(buf); | _GetTimeStamp(buf); |
fprintf(os, "%s: ", buf); |
Ftprintf(os, ZT("%s "), scs(buf)); |
fprintf(os, "%s: ", _levelStrings[(int)level]); |
Ftprintf(os, ZT("[%u,%lu] "), (unsigned int)Process_ID(), (unsigned long)Thread_TID()); |
fprintf(os, "%s(%u): ", file, line); |
Ftprintf(os, ZT("%s: "), scs(_levelStrings[(int)level])); |
|
|
|
if (file) |
|
Ftprintf(os, ZT("%s(%u): "), scs(file), line); |
} | } |
| |
/* | /* |
|
|
**============================================================================== | **============================================================================== |
*/ | */ |
| |
|
MI_Boolean Log_IsOpen() |
|
{ |
|
return (_os != NULL); |
|
} |
|
|
|
#if defined(CONFIG_OS_WINDOWS) |
|
#include <share.h> |
|
#endif |
|
|
MI_Result Log_Open( | MI_Result Log_Open( |
const MI_Char* path) |
const ZChar* path) |
{ | { |
if (!path || _os) | if (!path || _os) |
return MI_RESULT_FAILED; | return MI_RESULT_FAILED; |
| |
|
#ifdef LOGC_USES_LOCK |
|
Lock_Init(&_logLock); |
|
#endif |
|
|
#if defined(CONFIG_OS_WINDOWS) | #if defined(CONFIG_OS_WINDOWS) |
# if (MI_CHAR_TYPE == 1) | # if (MI_CHAR_TYPE == 1) |
{ | { |
if (fopen_s(&_os, path, "a") != 0) |
_os = _fsopen(path, "a", _SH_DENYWR); |
|
if (_os == NULL) |
return MI_RESULT_FAILED; | return MI_RESULT_FAILED; |
| |
return MI_RESULT_OK; | return MI_RESULT_OK; |
} | } |
# else | # else |
{ | { |
if (_wfopen_s(&_os, path, L"a") != 0) |
_os = _wfsopen(path, L"a", _SH_DENYWR); |
|
if (_os == NULL) |
return MI_RESULT_FAILED; | return MI_RESULT_FAILED; |
| |
return MI_RESULT_OK; | return MI_RESULT_OK; |
|
|
# if (MI_CHAR_TYPE == 1) | # if (MI_CHAR_TYPE == 1) |
{ | { |
_os = fopen(path, "a"); | _os = fopen(path, "a"); |
|
|
if (!_os) | if (!_os) |
return MI_RESULT_FAILED; | return MI_RESULT_FAILED; |
| |
|
|
} | } |
# else | # else |
{ | { |
char* path7 = _StrdupWcharToASCII7(path); |
char path7[PAL_MAX_PATH_SIZE]; |
|
if (StrWcslcpy(path7, path, PAL_MAX_PATH_SIZE) >= PAL_MAX_PATH_SIZE) |
if (!path7) |
|
return MI_RESULT_FAILED; | return MI_RESULT_FAILED; |
| |
_os = fopen(path7, _os, "a"); |
_os = fopen(path7, "a"); |
| |
if (!_os) | if (!_os) |
{ | { |
free(path7); |
|
return MI_RESULT_FAILED; | return MI_RESULT_FAILED; |
} | } |
| |
free(path7); |
|
return MI_RESULT_OK; | return MI_RESULT_OK; |
} | } |
# endif | # endif |
|
|
return MI_RESULT_OK; | return MI_RESULT_OK; |
} | } |
| |
|
MI_Boolean Log_IsRoutedToStdErr() |
|
{ |
|
return (_os == stderr); |
|
} |
|
|
void Log_Close() | void Log_Close() |
{ | { |
if (_os && _os != stderr) | if (_os && _os != stderr) |
|
|
return _level; | return _level; |
} | } |
| |
int Log_SetLevelFromString(const char* level) |
int Log_SetLevelFromString(_In_z_ const char* level) |
{ | { |
size_t i; | size_t i; |
| |
for (i = 0; i < sizeof(_levelStrings) / sizeof(_levelStrings[0]); i++) | for (i = 0; i < sizeof(_levelStrings) / sizeof(_levelStrings[0]); i++) |
{ | { |
char buf[32]; |
char buf[12]; |
|
size_t size; |
Snprintf(buf, sizeof(buf), "%u", (int)i); |
const char* str = Uint32ToStr(buf, (MI_Uint32)i, &size); |
| |
if (Strcasecmp(level, _levelStrings[i]) == 0 || | if (Strcasecmp(level, _levelStrings[i]) == 0 || |
Strcasecmp(level, buf) == 0) |
(str && Strcasecmp(level, str) == 0)) |
{ | { |
_level = (Log_Level)i; | _level = (Log_Level)i; |
return 0; | return 0; |
|
|
return -1; | return -1; |
} | } |
| |
|
int Log_SetLevelFromPalCharString(_In_z_ const PAL_Char* level) |
|
{ |
|
if(level && (Tcslen(level) < MAX_LOG_LEVEL_STRING_LENGTH)) |
|
{ |
|
char buf[MAX_LOG_LEVEL_STRING_LENGTH]; |
|
#if defined(CONFIG_ENABLE_WCHAR) |
|
StrWcslcpy(buf, level, MAX_LOG_LEVEL_STRING_LENGTH); |
|
#else |
|
Strlcpy(buf, level, MAX_LOG_LEVEL_STRING_LENGTH); |
|
#endif |
|
if(Log_SetLevelFromString(buf) != 0) |
|
{ |
|
return -1; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
return -1; |
|
} |
|
|
const char* Log_GetLevelString(Log_Level level) | const char* Log_GetLevelString(Log_Level level) |
{ | { |
return _levelStrings[(int)level]; | return _levelStrings[(int)level]; |
|
|
Log_Level level, | Log_Level level, |
const char* file, | const char* file, |
MI_Uint32 line, | MI_Uint32 line, |
const MI_Char* format, |
const ZChar* format, |
...) | ...) |
{ | { |
va_list ap; | va_list ap; |
|
|
if (!_os || level > _level) | if (!_os || level > _level) |
return 0; | return 0; |
| |
|
#ifdef LOGC_USES_LOCK |
|
Lock_Acquire(&_logLock); |
|
#endif |
|
|
_PutHeader(_os, file, line, level); | _PutHeader(_os, file, line, level); |
|
|
va_start(ap, format); | va_start(ap, format); |
#if (MI_CHAR_TYPE == 1) |
|
vfprintf(_os, format, ap); |
Vftprintf(_os, format, ap); |
#else |
|
vfwprintf(_os, format, ap); |
|
#endif |
|
va_end(ap); | va_end(ap); |
fputc('\n', _os); |
Ftprintf(_os, ZT("\n")); |
|
|
|
#ifdef LOGC_USES_LOCK |
|
Lock_Release(&_logLock); |
|
#endif |
| |
return 1; | return 1; |
} | } |
|
|
Log_Level level, | Log_Level level, |
const char* file, | const char* file, |
MI_Uint32 line, | MI_Uint32 line, |
const MI_Char* format, |
const ZChar* format, |
va_list ap) | va_list ap) |
{ | { |
if (!_os || level > _level) | if (!_os || level > _level) |
return 0; | return 0; |
| |
|
file = scs(file); |
|
|
|
#ifdef LOGC_USES_LOCK |
|
Lock_Acquire(&_logLock); |
|
#endif |
|
|
_PutHeader(_os, file, line, level); | _PutHeader(_os, file, line, level); |
#if (MI_CHAR_TYPE == 1) |
|
vfprintf(_os, format, ap); |
Vftprintf(_os, format, ap); |
#else |
|
vfwprintf(_os, format, ap); |
Ftprintf(_os, ZT("\n")); |
|
fflush(_os); |
|
|
|
#ifdef LOGC_USES_LOCK |
|
Lock_Release(&_logLock); |
#endif | #endif |
fputc('\n', _os); |
|
| |
return 1; | return 1; |
} | } |
| |
|
#if defined(CONFIG_ENABLE_DEBUG) |
|
|
int __Log_Put1( | int __Log_Put1( |
Log_Level level, | Log_Level level, |
const char* file, | const char* file, |
|
|
if (!_os || level > _level) | if (!_os || level > _level) |
return 0; | return 0; |
| |
_currentLevel = level; |
#ifdef LOGC_USES_LOCK |
|
Lock_Acquire(&_logLock); |
|
#endif |
_PutHeader(_os, file, line, level); | _PutHeader(_os, file, line, level); |
|
#ifdef LOGC_USES_LOCK |
|
Lock_Release(&_logLock); |
|
#endif |
| |
return 1; | return 1; |
} | } |
| |
|
#endif /* defined(CONFIG_ENABLE_DEBUG) */ |
|
|
void __Log_Put2( | void __Log_Put2( |
const MI_Char* format, |
const ZChar* format, |
...) | ...) |
{ | { |
va_list ap; | va_list ap; |
memset(&ap, 0, sizeof(ap)); | memset(&ap, 0, sizeof(ap)); |
| |
if (!_os || _currentLevel > _level) |
if (!_os) |
return; | return; |
| |
va_start(ap, format); |
#ifdef LOGC_USES_LOCK |
#if (MI_CHAR_TYPE == 1) |
Lock_Acquire(&_logLock); |
vfprintf(_os, format, ap); |
|
#else |
|
vfwprintf(_os, format, ap); |
|
#endif | #endif |
fputc('\n', _os); |
va_start(ap, format); |
|
|
|
Vftprintf(_os, format, ap); |
|
|
|
Ftprintf(_os, ZT("\n")); |
fflush(_os); | fflush(_os); |
|
#ifdef LOGC_USES_LOCK |
|
Lock_Release(&_logLock); |
|
#endif |
} | } |
| |
void __Log_Put2_char( |
void __Logf(const ZChar* format, ...) |
const char* format, |
|
...) |
|
{ | { |
va_list ap; | va_list ap; |
memset(&ap, 0, sizeof(ap)); |
va_start(ap, format); |
|
Log_VPut(OMI_FATAL, NULL, 0, format, ap); |
|
va_end(ap); |
|
} |
| |
if (!_os || _currentLevel > _level) |
void __Loge(const ZChar* format, ...) |
return; |
{ |
|
va_list ap; |
|
va_start(ap, format); |
|
Log_VPut(OMI_ERROR, NULL, 0, format, ap); |
|
va_end(ap); |
|
} |
| |
|
void __Logw(const ZChar* format, ...) |
|
{ |
|
va_list ap; |
va_start(ap, format); | va_start(ap, format); |
vfprintf(_os, format, ap); |
Log_VPut(OMI_WARNING, NULL, 0, format, ap); |
fputc('\n', _os); |
va_end(ap); |
fflush(_os); |
|
} | } |
|
|
|
void __Logi(const ZChar* format, ...) |
|
{ |
|
va_list ap; |
|
va_start(ap, format); |
|
Log_VPut(OMI_INFO, NULL, 0, format, ap); |
|
va_end(ap); |
|
} |
|
|
|
void __Logd(const ZChar* format, ...) |
|
{ |
|
va_list ap; |
|
va_start(ap, format); |
|
Log_VPut(OMI_DEBUG, NULL, 0, format, ap); |
|
va_end(ap); |
|
} |
|
|
|
void __Logv(const ZChar* format, ...) |
|
{ |
|
va_list ap; |
|
va_start(ap, format); |
|
Log_VPut(OMI_VERBOSE, NULL, 0, format, ap); |
|
va_end(ap); |
|
} |
|
|