2 * WinPR: Windows Portable Runtime
5 * Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
27 #include <winpr/crt.h>
28 #include <winpr/print.h>
29 #include <winpr/debug.h>
30 #include <winpr/environment.h>
33 #include <android/log.h>
36 #include <winpr/wlog.h>
38 #include "wlog/wlog.h"
40 #include "../../log.h"
43 * References for general logging concepts:
45 * Short introduction to log4j:
46 * http://logging.apache.org/log4j/1.2/manual.html
48 * logging - Logging facility for Python:
49 * http://docs.python.org/2/library/logging.html
52 const char* WLOG_LEVELS[7] =
63 static DWORD g_FilterCount = 0;
64 static wLogFilter* g_Filters = NULL;
66 static void log_recursion(const char* file, const char* fkt, int line)
69 void* bt = winpr_backtrace(20);
70 char** msg = winpr_backtrace_symbols(bt, &used);
72 const char* tag = WINPR_TAG("utils.wlog");
73 __android_log_print(ANDROID_LOG_FATAL, tag, "Recursion detected!!!");
74 __android_log_print(ANDROID_LOG_FATAL, tag, "Check %s [%s:%d]", fkt, file, line);
76 for (i=0; i<used; i++)
77 __android_log_print(ANDROID_LOG_FATAL, tag, "%d: %s", i, msg[i]);
80 fprintf(stderr, "[%s]: Recursion detected!\n", fkt);
81 fprintf(stderr, "[%s]: Check %s:%d\n", fkt, file, line);
83 for (i=0; i<used; i++)
84 fprintf(stderr, "%s: %zd: %s\n", fkt, i, msg[i]);
90 winpr_backtrace_free(bt);
93 int WLog_Write(wLog* log, wLogMessage* message)
96 wLogAppender* appender;
97 appender = WLog_GetLogAppender(log);
102 if (!appender->State)
103 WLog_OpenAppender(log);
105 if (!appender->WriteMessage)
108 EnterCriticalSection(&appender->lock);
110 if (appender->recursive)
111 log_recursion(message->FileName, message->FunctionName, message->LineNumber);
114 appender->recursive = TRUE;
115 status = appender->WriteMessage(log, appender, message);
116 appender->recursive = FALSE;
119 LeaveCriticalSection(&appender->lock);
123 int WLog_WriteData(wLog* log, wLogMessage* message)
126 wLogAppender* appender;
127 appender = WLog_GetLogAppender(log);
132 if (!appender->State)
133 WLog_OpenAppender(log);
135 if (!appender->WriteDataMessage)
138 EnterCriticalSection(&appender->lock);
140 if (appender->recursive)
141 log_recursion(message->FileName, message->FunctionName, message->LineNumber);
144 appender->recursive = TRUE;
145 status = appender->WriteDataMessage(log, appender, message);
146 appender->recursive = FALSE;
149 LeaveCriticalSection(&appender->lock);
153 int WLog_WriteImage(wLog* log, wLogMessage* message)
156 wLogAppender* appender;
157 appender = WLog_GetLogAppender(log);
162 if (!appender->State)
163 WLog_OpenAppender(log);
165 if (!appender->WriteImageMessage)
168 EnterCriticalSection(&appender->lock);
170 if (appender->recursive)
171 log_recursion(message->FileName, message->FunctionName, message->LineNumber);
174 appender->recursive = TRUE;
175 status = appender->WriteImageMessage(log, appender, message);
176 appender->recursive = FALSE;
179 LeaveCriticalSection(&appender->lock);
183 int WLog_WritePacket(wLog* log, wLogMessage* message)
186 wLogAppender* appender;
187 appender = WLog_GetLogAppender(log);
192 if (!appender->State)
193 WLog_OpenAppender(log);
195 if (!appender->WritePacketMessage)
198 EnterCriticalSection(&appender->lock);
200 if (appender->recursive)
201 log_recursion(message->FileName, message->FunctionName, message->LineNumber);
204 appender->recursive = TRUE;
205 status = appender->WritePacketMessage(log, appender, message);
206 appender->recursive = FALSE;
209 LeaveCriticalSection(&appender->lock);
213 int WLog_PrintMessageVA(wLog* log, wLogMessage* message, va_list args)
217 if (message->Type == WLOG_MESSAGE_TEXT)
219 if (!strchr(message->FormatString, '%'))
221 message->TextString = (LPSTR) message->FormatString;
222 status = WLog_Write(log, message);
226 char formattedLogMessage[WLOG_MAX_STRING_SIZE];
227 wvsnprintfx(formattedLogMessage, WLOG_MAX_STRING_SIZE - 1, message->FormatString, args);
228 message->TextString = formattedLogMessage;
229 status = WLog_Write(log, message);
232 else if (message->Type == WLOG_MESSAGE_DATA)
234 message->Data = va_arg(args, void*);
235 message->Length = va_arg(args, int);
236 status = WLog_WriteData(log, message);
238 else if (message->Type == WLOG_MESSAGE_IMAGE)
240 message->ImageData = va_arg(args, void*);
241 message->ImageWidth = va_arg(args, int);
242 message->ImageHeight = va_arg(args, int);
243 message->ImageBpp = va_arg(args, int);
244 status = WLog_WriteImage(log, message);
246 else if (message->Type == WLOG_MESSAGE_PACKET)
248 message->PacketData = va_arg(args, void*);
249 message->PacketLength = va_arg(args, int);
250 message->PacketFlags = va_arg(args, int);
251 status = WLog_WritePacket(log, message);
257 void WLog_PrintMessage(wLog* log, wLogMessage* message, ...)
261 va_start(args, message);
262 status = WLog_PrintMessageVA(log, message, args);
266 DWORD WLog_GetLogLevel(wLog* log)
268 if (log->Level == WLOG_LEVEL_INHERIT)
270 return WLog_GetLogLevel(log->Parent);
278 void WLog_SetLogLevel(wLog* log, DWORD logLevel)
280 if ((logLevel > WLOG_OFF) && (logLevel != WLOG_LEVEL_INHERIT))
285 log->Level = logLevel;
288 int WLog_ParseLogLevel(const char* level)
295 if (_stricmp(level, "TRACE") == 0)
297 else if (_stricmp(level, "DEBUG") == 0)
299 else if (_stricmp(level, "INFO") == 0)
301 else if (_stricmp(level, "WARN") == 0)
303 else if (_stricmp(level, "ERROR") == 0)
305 else if (_stricmp(level, "FATAL") == 0)
307 else if (_stricmp(level, "OFF") == 0)
313 int WLog_ParseFilter(wLogFilter* filter, LPCSTR name)
329 while ((p = strchr(p, '.')) != NULL)
336 names = _strdup(name);
339 filter->NameCount = count;
340 filter->Names = (LPSTR*) calloc((count + 1UL), sizeof(LPSTR));
344 filter->NameCount = 0;
347 filter->Names[count] = NULL;
350 filter->Names[count++] = p;
357 filter->Names = NULL;
358 filter->NameCount = 0;
364 iLevel = WLog_ParseLogLevel(q);
370 filter->Names = NULL;
371 filter->NameCount = 0;
375 filter->Level = (DWORD) iLevel;
377 while ((p = strchr(p, '.')) != NULL)
379 if (count < filter->NameCount)
380 filter->Names[count++] = p + 1;
388 int WLog_ParseFilters()
397 nSize = GetEnvironmentVariableA("WLOG_FILTER", NULL, 0);
402 env = (LPSTR) malloc(nSize);
407 if (!GetEnvironmentVariableA("WLOG_FILTER", env, nSize))
413 while ((p = strchr(p, ',')) != NULL)
419 g_FilterCount = count;
423 strs = (LPCSTR*) calloc(g_FilterCount, sizeof(LPCSTR));
433 while ((p = strchr(p, ',')) != NULL)
435 if (count < g_FilterCount)
436 strs[count++] = p + 1;
441 g_Filters = calloc(g_FilterCount, sizeof(wLogFilter));
450 for (count = 0; count < g_FilterCount; count++)
452 status = WLog_ParseFilter(&g_Filters[count], strs[count]);
468 int WLog_GetFilterLogLevel(wLog* log)
474 for (i = 0; i < g_FilterCount; i++)
476 for (j = 0; j < g_Filters[i].NameCount; j++)
478 if (j >= log->NameCount)
481 if (_stricmp(g_Filters[i].Names[j], "*") == 0)
487 if (_stricmp(g_Filters[i].Names[j], log->Names[j]) != 0)
490 if (j == (log->NameCount - 1))
503 iLevel = (int) g_Filters[i].Level;
509 int WLog_ParseName(wLog* log, LPCSTR name)
517 while ((p = strchr(p, '.')) != NULL)
523 names = _strdup(name);
526 log->NameCount = count;
527 log->Names = (LPSTR*) calloc((count + 1UL), sizeof(LPSTR));
533 log->Names[count] = NULL;
536 log->Names[count++] = p;
538 while ((p = strchr(p, '.')) != NULL)
540 if (count < log->NameCount)
541 log->Names[count++] = p + 1;
549 wLog* WLog_New(LPCSTR name, wLog* rootLogger)
555 log = (wLog*) calloc(1, sizeof(wLog));
560 log->Name = _strdup(name);
565 if (WLog_ParseName(log, name) != 0)
568 log->Parent = rootLogger;
569 log->ChildrenCount = 0;
570 log->ChildrenSize = 16;
572 if (!(log->Children = (wLog**) calloc(log->ChildrenSize, sizeof(wLog*))))
575 log->Appender = NULL;
579 log->Level = WLOG_LEVEL_INHERIT;
583 log->Level = WLOG_INFO;
584 nSize = GetEnvironmentVariableA("WLOG_LEVEL", NULL, 0);
588 env = (LPSTR) malloc(nSize);
591 if (GetEnvironmentVariableA("WLOG_LEVEL", env, nSize))
593 iLevel = WLog_ParseLogLevel(env);
596 log->Level = (DWORD) iLevel;
604 iLevel = WLog_GetFilterLogLevel(log);
607 log->Level = (DWORD) iLevel;
612 free (log->Children);
618 void WLog_Free(wLog* log)
624 WLog_Appender_Free(log, log->Appender);
625 log->Appender = NULL;
636 static wLog* g_RootLog = NULL;
642 DWORD logAppenderType;
646 if (!(g_RootLog = WLog_New("", NULL)))
649 g_RootLog->IsRoot = TRUE;
651 logAppenderType = WLOG_APPENDER_CONSOLE;
652 nSize = GetEnvironmentVariableA("WLOG_APPENDER", NULL, 0);
656 env = (LPSTR) malloc(nSize);
659 if (GetEnvironmentVariableA("WLOG_APPENDER", env, nSize))
661 if (_stricmp(env, "CONSOLE") == 0)
662 logAppenderType = WLOG_APPENDER_CONSOLE;
663 else if (_stricmp(env, "FILE") == 0)
664 logAppenderType = WLOG_APPENDER_FILE;
665 else if (_stricmp(env, "BINARY") == 0)
666 logAppenderType = WLOG_APPENDER_BINARY;
672 WLog_SetLogAppenderType(g_RootLog, logAppenderType);
678 int WLog_AddChild(wLog* parent, wLog* child)
680 if (parent->ChildrenCount >= parent->ChildrenSize)
683 parent->ChildrenSize *= 2;
684 if (!parent->ChildrenSize)
686 if (parent->Children)
687 free (parent->Children);
688 parent->Children = NULL;
693 tmp = (wLog**) realloc(parent->Children, sizeof(wLog*) * parent->ChildrenSize);
696 if (parent->Children)
697 free (parent->Children);
698 parent->Children = NULL;
701 parent->Children = tmp;
705 if (!parent->Children)
708 parent->Children[parent->ChildrenCount++] = child;
709 child->Parent = parent;
713 wLog* WLog_FindChild(LPCSTR name)
719 root = WLog_GetRoot();
721 for (index = 0; index < root->ChildrenCount; index++)
723 child = root->Children[index];
725 if (strcmp(child->Name, name) == 0)
732 return (found) ? child : NULL;
735 wLog* WLog_Get(LPCSTR name)
738 if (!(log = WLog_FindChild(name)))
740 wLog* root = WLog_GetRoot();
743 if (!(log = WLog_New(name, root)))
745 WLog_AddChild(root, log);
759 wLog* root = g_RootLog;
764 for (index = 0; index < root->ChildrenCount; index++)
766 child = root->Children[index];