07417599ce
* only expose necessary functions and types in header * don't expose appender internals * add generic function WLog_ConfigureAppender to have the possibility to configure appender specific settings * detect appender availability if WLog_SetLogAppenderType or WLog_Appender_New return FALSE or NULL respectively the appender isn't available or the initialization failed. This is very useful for the use with optional appenders. * add Free to the appender interface. At the time of the Free the appender is known and available so it can be called directly (instead of calling the right function according to the type) * make all appender internal function static * all appenders return the generic wLogAppender type now. Typecasts are internally done where necessary this abstracts the appenders more cleanly
411 lines
9.5 KiB
C
411 lines
9.5 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
|
|
*/
|
|
|
|
void WLog_PrintMessagePrefixVA(wLog* log, wLogMessage* message, const char* format, va_list args)
|
|
{
|
|
if (!strchr(format, '%'))
|
|
{
|
|
message->PrefixString = (LPSTR) format;
|
|
}
|
|
else
|
|
{
|
|
wvsnprintfx(message->PrefixString, WLOG_MAX_PREFIX_SIZE - 1, format, args);
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
DWORD nSize;
|
|
char* env = NULL;
|
|
wLogLayout* layout;
|
|
|
|
layout = (wLogLayout*) calloc(1, sizeof(wLogLayout));
|
|
if (!layout)
|
|
return NULL;
|
|
|
|
nSize = GetEnvironmentVariableA("WLOG_PREFIX", NULL, 0);
|
|
if (nSize)
|
|
{
|
|
env = (LPSTR) malloc(nSize);
|
|
if (!env)
|
|
{
|
|
free(layout);
|
|
return NULL;
|
|
}
|
|
nSize = GetEnvironmentVariableA("WLOG_PREFIX", env, nSize);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|