415 lines
9.9 KiB
C
415 lines
9.9 KiB
C
|
/**
|
||
|
* WinPR: Windows Portable Runtime
|
||
|
* WinPR Logger
|
||
|
*
|
||
|
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
#include "config.h"
|
||
|
#endif
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <stdarg.h>
|
||
|
|
||
|
#include <winpr/crt.h>
|
||
|
#include <winpr/print.h>
|
||
|
#include <winpr/sysinfo.h>
|
||
|
#include <winpr/environment.h>
|
||
|
|
||
|
#include "wlog.h"
|
||
|
|
||
|
#include "wlog/Layout.h"
|
||
|
|
||
|
#if defined __linux__ && !defined ANDROID
|
||
|
#include <unistd.h>
|
||
|
#include <sys/syscall.h>
|
||
|
#endif
|
||
|
|
||
|
extern const char* WLOG_LEVELS[7];
|
||
|
|
||
|
/**
|
||
|
* Log Layout
|
||
|
*/
|
||
|
|
||
|
static void WLog_PrintMessagePrefixVA(wLog* log, wLogMessage* message, const char* format,
|
||
|
va_list args)
|
||
|
{
|
||
|
if (!strchr(format, '%'))
|
||
|
sprintf_s(message->PrefixString, WLOG_MAX_PREFIX_SIZE - 1, "%s", format);
|
||
|
else
|
||
|
wvsnprintfx(message->PrefixString, WLOG_MAX_PREFIX_SIZE - 1, format, args);
|
||
|
}
|
||
|
|
||
|
static void WLog_PrintMessagePrefix(wLog* log, wLogMessage* message, const char* format, ...)
|
||
|
{
|
||
|
va_list args;
|
||
|
va_start(args, format);
|
||
|
WLog_PrintMessagePrefixVA(log, message, format, args);
|
||
|
va_end(args);
|
||
|
}
|
||
|
|
||
|
BOOL WLog_Layout_GetMessagePrefix(wLog* log, wLogLayout* layout, wLogMessage* message)
|
||
|
{
|
||
|
char* p;
|
||
|
int index;
|
||
|
int argc = 0;
|
||
|
void* args[32];
|
||
|
char format[256];
|
||
|
SYSTEMTIME localTime;
|
||
|
GetLocalTime(&localTime);
|
||
|
index = 0;
|
||
|
p = (char*)layout->FormatString;
|
||
|
|
||
|
while (*p)
|
||
|
{
|
||
|
if (*p == '%')
|
||
|
{
|
||
|
p++;
|
||
|
|
||
|
if (*p)
|
||
|
{
|
||
|
if ((p[0] == 'l') && (p[1] == 'v')) /* log level */
|
||
|
{
|
||
|
args[argc++] = (void*)WLOG_LEVELS[message->Level];
|
||
|
format[index++] = '%';
|
||
|
format[index++] = 's';
|
||
|
p++;
|
||
|
}
|
||
|
else if ((p[0] == 'm') && (p[1] == 'n')) /* module name */
|
||
|
{
|
||
|
args[argc++] = (void*)log->Name;
|
||
|
format[index++] = '%';
|
||
|
format[index++] = 's';
|
||
|
p++;
|
||
|
}
|
||
|
else if ((p[0] == 'f') && (p[1] == 'l')) /* file */
|
||
|
{
|
||
|
char* file;
|
||
|
file = strrchr(message->FileName, '/');
|
||
|
|
||
|
if (!file)
|
||
|
file = strrchr(message->FileName, '\\');
|
||
|
|
||
|
if (file)
|
||
|
file++;
|
||
|
else
|
||
|
file = (char*)message->FileName;
|
||
|
|
||
|
args[argc++] = (void*)file;
|
||
|
format[index++] = '%';
|
||
|
format[index++] = 's';
|
||
|
p++;
|
||
|
}
|
||
|
else if ((p[0] == 'f') && (p[1] == 'n')) /* function */
|
||
|
{
|
||
|
args[argc++] = (void*)message->FunctionName;
|
||
|
format[index++] = '%';
|
||
|
format[index++] = 's';
|
||
|
p++;
|
||
|
}
|
||
|
else if ((p[0] == 'l') && (p[1] == 'n')) /* line number */
|
||
|
{
|
||
|
args[argc++] = (void*)(size_t)message->LineNumber;
|
||
|
format[index++] = '%';
|
||
|
format[index++] = 'u';
|
||
|
p++;
|
||
|
}
|
||
|
else if ((p[0] == 'p') && (p[1] == 'i') && (p[2] == 'd')) /* process id */
|
||
|
{
|
||
|
args[argc++] = (void*)(size_t)GetCurrentProcessId();
|
||
|
format[index++] = '%';
|
||
|
format[index++] = 'u';
|
||
|
p += 2;
|
||
|
}
|
||
|
else if ((p[0] == 't') && (p[1] == 'i') && (p[2] == 'd')) /* thread id */
|
||
|
{
|
||
|
#if defined __linux__ && !defined ANDROID
|
||
|
/* On Linux we prefer to see the LWP id */
|
||
|
args[argc++] = (void*)(size_t)syscall(SYS_gettid);
|
||
|
format[index++] = '%';
|
||
|
format[index++] = 'l';
|
||
|
format[index++] = 'd';
|
||
|
#else
|
||
|
args[argc++] = (void*)(size_t)GetCurrentThreadId();
|
||
|
format[index++] = '%';
|
||
|
format[index++] = '0';
|
||
|
format[index++] = '8';
|
||
|
format[index++] = 'x';
|
||
|
#endif
|
||
|
p += 2;
|
||
|
}
|
||
|
else if ((p[0] == 'y') && (p[1] == 'r')) /* year */
|
||
|
{
|
||
|
args[argc++] = (void*)(size_t)localTime.wYear;
|
||
|
format[index++] = '%';
|
||
|
format[index++] = 'u';
|
||
|
p++;
|
||
|
}
|
||
|
else if ((p[0] == 'm') && (p[1] == 'o')) /* month */
|
||
|
{
|
||
|
args[argc++] = (void*)(size_t)localTime.wMonth;
|
||
|
format[index++] = '%';
|
||
|
format[index++] = '0';
|
||
|
format[index++] = '2';
|
||
|
format[index++] = 'u';
|
||
|
p++;
|
||
|
}
|
||
|
else if ((p[0] == 'd') && (p[1] == 'w')) /* day of week */
|
||
|
{
|
||
|
args[argc++] = (void*)(size_t)localTime.wDayOfWeek;
|
||
|
format[index++] = '%';
|
||
|
format[index++] = '0';
|
||
|
format[index++] = '2';
|
||
|
format[index++] = 'u';
|
||
|
p++;
|
||
|
}
|
||
|
else if ((p[0] == 'd') && (p[1] == 'y')) /* day */
|
||
|
{
|
||
|
args[argc++] = (void*)(size_t)localTime.wDay;
|
||
|
format[index++] = '%';
|
||
|
format[index++] = '0';
|
||
|
format[index++] = '2';
|
||
|
format[index++] = 'u';
|
||
|
p++;
|
||
|
}
|
||
|
else if ((p[0] == 'h') && (p[1] == 'r')) /* hours */
|
||
|
{
|
||
|
args[argc++] = (void*)(size_t)localTime.wHour;
|
||
|
format[index++] = '%';
|
||
|
format[index++] = '0';
|
||
|
format[index++] = '2';
|
||
|
format[index++] = 'u';
|
||
|
p++;
|
||
|
}
|
||
|
else if ((p[0] == 'm') && (p[1] == 'i')) /* minutes */
|
||
|
{
|
||
|
args[argc++] = (void*)(size_t)localTime.wMinute;
|
||
|
format[index++] = '%';
|
||
|
format[index++] = '0';
|
||
|
format[index++] = '2';
|
||
|
format[index++] = 'u';
|
||
|
p++;
|
||
|
}
|
||
|
else if ((p[0] == 's') && (p[1] == 'e')) /* seconds */
|
||
|
{
|
||
|
args[argc++] = (void*)(size_t)localTime.wSecond;
|
||
|
format[index++] = '%';
|
||
|
format[index++] = '0';
|
||
|
format[index++] = '2';
|
||
|
format[index++] = 'u';
|
||
|
p++;
|
||
|
}
|
||
|
else if ((p[0] == 'm') && (p[1] == 'l')) /* milliseconds */
|
||
|
{
|
||
|
args[argc++] = (void*)(size_t)localTime.wMilliseconds;
|
||
|
format[index++] = '%';
|
||
|
format[index++] = '0';
|
||
|
format[index++] = '3';
|
||
|
format[index++] = 'u';
|
||
|
p++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
format[index++] = *p;
|
||
|
}
|
||
|
|
||
|
p++;
|
||
|
}
|
||
|
|
||
|
format[index++] = '\0';
|
||
|
|
||
|
switch (argc)
|
||
|
{
|
||
|
case 0:
|
||
|
WLog_PrintMessagePrefix(log, message, format);
|
||
|
break;
|
||
|
|
||
|
case 1:
|
||
|
WLog_PrintMessagePrefix(log, message, format, args[0]);
|
||
|
break;
|
||
|
|
||
|
case 2:
|
||
|
WLog_PrintMessagePrefix(log, message, format, args[0], args[1]);
|
||
|
break;
|
||
|
|
||
|
case 3:
|
||
|
WLog_PrintMessagePrefix(log, message, format, args[0], args[1], args[2]);
|
||
|
break;
|
||
|
|
||
|
case 4:
|
||
|
WLog_PrintMessagePrefix(log, message, format, args[0], args[1], args[2], args[3]);
|
||
|
break;
|
||
|
|
||
|
case 5:
|
||
|
WLog_PrintMessagePrefix(log, message, format, args[0], args[1], args[2], args[3],
|
||
|
args[4]);
|
||
|
break;
|
||
|
|
||
|
case 6:
|
||
|
WLog_PrintMessagePrefix(log, message, format, args[0], args[1], args[2], args[3],
|
||
|
args[4], args[5]);
|
||
|
break;
|
||
|
|
||
|
case 7:
|
||
|
WLog_PrintMessagePrefix(log, message, format, args[0], args[1], args[2], args[3],
|
||
|
args[4], args[5], args[6]);
|
||
|
break;
|
||
|
|
||
|
case 8:
|
||
|
WLog_PrintMessagePrefix(log, message, format, args[0], args[1], args[2], args[3],
|
||
|
args[4], args[5], args[6], args[7]);
|
||
|
break;
|
||
|
|
||
|
case 9:
|
||
|
WLog_PrintMessagePrefix(log, message, format, args[0], args[1], args[2], args[3],
|
||
|
args[4], args[5], args[6], args[7], args[8]);
|
||
|
break;
|
||
|
|
||
|
case 10:
|
||
|
WLog_PrintMessagePrefix(log, message, format, args[0], args[1], args[2], args[3],
|
||
|
args[4], args[5], args[6], args[7], args[8], args[9]);
|
||
|
break;
|
||
|
|
||
|
case 11:
|
||
|
WLog_PrintMessagePrefix(log, message, format, args[0], args[1], args[2], args[3],
|
||
|
args[4], args[5], args[6], args[7], args[8], args[9], args[10]);
|
||
|
break;
|
||
|
|
||
|
case 12:
|
||
|
WLog_PrintMessagePrefix(log, message, format, args[0], args[1], args[2], args[3],
|
||
|
args[4], args[5], args[6], args[7], args[8], args[9], args[10],
|
||
|
args[11]);
|
||
|
break;
|
||
|
|
||
|
case 13:
|
||
|
WLog_PrintMessagePrefix(log, message, format, args[0], args[1], args[2], args[3],
|
||
|
args[4], args[5], args[6], args[7], args[8], args[9], args[10],
|
||
|
args[11], args[12]);
|
||
|
break;
|
||
|
|
||
|
case 14:
|
||
|
WLog_PrintMessagePrefix(log, message, format, args[0], args[1], args[2], args[3],
|
||
|
args[4], args[5], args[6], args[7], args[8], args[9], args[10],
|
||
|
args[11], args[12], args[13]);
|
||
|
break;
|
||
|
|
||
|
case 15:
|
||
|
WLog_PrintMessagePrefix(log, message, format, args[0], args[1], args[2], args[3],
|
||
|
args[4], args[5], args[6], args[7], args[8], args[9], args[10],
|
||
|
args[11], args[12], args[13], args[14]);
|
||
|
break;
|
||
|
|
||
|
case 16:
|
||
|
WLog_PrintMessagePrefix(log, message, format, args[0], args[1], args[2], args[3],
|
||
|
args[4], args[5], args[6], args[7], args[8], args[9], args[10],
|
||
|
args[11], args[12], args[13], args[14], args[15]);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
wLogLayout* WLog_GetLogLayout(wLog* log)
|
||
|
{
|
||
|
wLogAppender* appender;
|
||
|
appender = WLog_GetLogAppender(log);
|
||
|
return appender->Layout;
|
||
|
}
|
||
|
|
||
|
BOOL WLog_Layout_SetPrefixFormat(wLog* log, wLogLayout* layout, const char* format)
|
||
|
{
|
||
|
free(layout->FormatString);
|
||
|
layout->FormatString = NULL;
|
||
|
|
||
|
if (format)
|
||
|
{
|
||
|
layout->FormatString = _strdup(format);
|
||
|
|
||
|
if (!layout->FormatString)
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
wLogLayout* WLog_Layout_New(wLog* log)
|
||
|
{
|
||
|
LPCSTR prefix = "WLOG_PREFIX";
|
||
|
DWORD nSize;
|
||
|
char* env = NULL;
|
||
|
wLogLayout* layout;
|
||
|
layout = (wLogLayout*)calloc(1, sizeof(wLogLayout));
|
||
|
|
||
|
if (!layout)
|
||
|
return NULL;
|
||
|
|
||
|
nSize = GetEnvironmentVariableA(prefix, NULL, 0);
|
||
|
|
||
|
if (nSize)
|
||
|
{
|
||
|
env = (LPSTR)malloc(nSize);
|
||
|
|
||
|
if (!env)
|
||
|
{
|
||
|
free(layout);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (GetEnvironmentVariableA(prefix, env, nSize) != nSize - 1)
|
||
|
{
|
||
|
free(env);
|
||
|
free(layout);
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (env)
|
||
|
layout->FormatString = env;
|
||
|
else
|
||
|
{
|
||
|
#ifdef ANDROID
|
||
|
layout->FormatString = _strdup("[pid=%pid:tid=%tid] - ");
|
||
|
#else
|
||
|
layout->FormatString = _strdup("[%hr:%mi:%se:%ml] [%pid:%tid] [%lv][%mn] - ");
|
||
|
#endif
|
||
|
|
||
|
if (!layout->FormatString)
|
||
|
{
|
||
|
free(layout);
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return layout;
|
||
|
}
|
||
|
|
||
|
void WLog_Layout_Free(wLog* log, wLogLayout* layout)
|
||
|
{
|
||
|
if (layout)
|
||
|
{
|
||
|
if (layout->FormatString)
|
||
|
{
|
||
|
free(layout->FormatString);
|
||
|
layout->FormatString = NULL;
|
||
|
}
|
||
|
|
||
|
free(layout);
|
||
|
}
|
||
|
}
|