blob: c9a60c2440cab5f961cd312727d951f49d5079d3 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% L OOO GGGG %
7% L O O G %
8% L O O G GG %
9% L O O G G %
10% LLLLL OOO GGG %
11% %
12% %
13% MagickCore Log Events %
14% %
15% Software Design %
16% John Cristy %
17% September 2002 %
18% %
19% %
20% Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization %
21% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37*/
38
39/*
40 Include declarations.
41*/
42#include "magick/studio.h"
43#include "magick/blob.h"
44#include "magick/client.h"
45#include "magick/configure.h"
46#include "magick/exception.h"
47#include "magick/exception-private.h"
48#include "magick/hashmap.h"
49#include "magick/log.h"
50#include "magick/memory_.h"
51#include "magick/option.h"
52#include "magick/semaphore.h"
53#include "magick/timer.h"
54#include "magick/string_.h"
55#include "magick/token.h"
56#include "magick/thread_.h"
57#include "magick/thread-private.h"
58#include "magick/utility.h"
59#include "magick/version.h"
60#include "magick/xml-tree.h"
61
62/*
63 Define declarations.
64*/
65#define LogFilename "log.xml"
66
67/*
68 Typedef declarations.
69*/
70typedef enum
71{
72 UndefinedHandler = 0x0000,
73 NoHandler = 0x0000,
74 ConsoleHandler = 0x0001,
75 StdoutHandler = 0x0002,
76 StderrHandler = 0x0004,
77 FileHandler = 0x0008,
78 DebugHandler = 0x0010,
79 EventHandler = 0x0020
80} LogHandlerType;
81
82typedef struct _EventInfo
83{
84 char
85 *name;
86
87 LogEventType
88 event;
89} EventInfo;
90
91typedef struct _HandlerInfo
92{
93 const char
94 *name;
95
96 LogHandlerType
97 handler;
98} HandlerInfo;
99
100struct _LogInfo
101{
102 LogEventType
103 event_mask;
104
105 LogHandlerType
106 handler_mask;
107
108 char
109 *path,
110 *name,
111 *filename,
112 *format;
113
114 unsigned long
115 generations,
116 limit;
117
118 FILE
119 *file;
120
121 unsigned long
122 generation;
123
124 MagickBooleanType
125 append,
cristy85340292009-10-21 19:32:19 +0000126 exempt,
cristy3ed852e2009-09-05 21:47:34 +0000127 stealth;
128
129 TimerInfo
130 timer;
131
132 unsigned long
133 signature;
134};
cristy85340292009-10-21 19:32:19 +0000135
136typedef struct _LogMapInfo
137{
138 const LogEventType
139 event_mask;
140
141 const LogHandlerType
142 handler_mask;
143
144 const char
145 *filename,
146 *format;
147} LogMapInfo;
cristy3ed852e2009-09-05 21:47:34 +0000148
149/*
cristy85340292009-10-21 19:32:19 +0000150 Static declarations.
cristy3ed852e2009-09-05 21:47:34 +0000151*/
152static const HandlerInfo
153 LogHandlers[] =
154 {
155 { "console", ConsoleHandler },
156 { "debug", DebugHandler },
157 { "event", EventHandler },
158 { "file", FileHandler },
159 { "none", NoHandler },
160 { "stderr", StderrHandler },
161 { "stdout", StdoutHandler },
162 { (char *) NULL, UndefinedHandler }
163 };
164
cristy85340292009-10-21 19:32:19 +0000165static const LogMapInfo
166 LogMap[] =
167 {
168 { NoEvents, ConsoleHandler, "Magick-%d.log",
169 "%t %r %u %v %d %c[%p]: %m/%f/%l/%d\n %e" }
170 };
171
cristy3ed852e2009-09-05 21:47:34 +0000172static char
173 log_name[MaxTextExtent] = "Magick";
174
175static LinkedListInfo
176 *log_list = (LinkedListInfo *) NULL;
177
178static SemaphoreInfo
179 *log_semaphore = (SemaphoreInfo *) NULL;
180
181static volatile MagickBooleanType
182 instantiate_log = MagickFalse;
183
184/*
185 Forward declarations.
186*/
187static LogHandlerType
188 ParseLogHandlers(const char *);
189
190static LogInfo
191 *GetLogInfo(const char *,ExceptionInfo *);
192
193static MagickBooleanType
194 InitializeLogList(ExceptionInfo *),
195 LoadLogLists(const char *,ExceptionInfo *);
196
197/*
198%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
199% %
200% %
201% %
202% C l o s e M a g i c k L o g %
203% %
204% %
205% %
206%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
207%
208% CloseMagickLog() closes the Magick log.
209%
210% The format of the CloseMagickLog method is:
211%
212% CloseMagickLog(void)
213%
214*/
215MagickExport void CloseMagickLog(void)
216{
217 ExceptionInfo
218 *exception;
219
220 LogInfo
221 *log_info;
222
223 if (IsEventLogging() == MagickFalse)
224 return;
225 exception=AcquireExceptionInfo();
226 log_info=GetLogInfo("*",exception);
227 exception=DestroyExceptionInfo(exception);
228 AcquireSemaphoreInfo(&log_semaphore);
229 if (log_info->file != (FILE *) NULL)
230 {
231 if (log_info->append == MagickFalse)
232 (void) fprintf(log_info->file,"</log>\n");
233 (void) fclose(log_info->file);
234 log_info->file=(FILE *) NULL;
235 }
236 RelinquishSemaphoreInfo(log_semaphore);
237}
238
239/*
240%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
241% %
242% %
243% %
cristydf1cc5f2009-10-19 16:02:33 +0000244+ D e s t r o y L o g C o m p o n e n t %
cristy3ed852e2009-09-05 21:47:34 +0000245% %
246% %
247% %
248%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
249%
cristydf1cc5f2009-10-19 16:02:33 +0000250% DestroyLogComponent() destroys the logging component.
cristy3ed852e2009-09-05 21:47:34 +0000251%
cristydf1cc5f2009-10-19 16:02:33 +0000252% The format of the DestroyLogComponent method is:
cristy3ed852e2009-09-05 21:47:34 +0000253%
cristydf1cc5f2009-10-19 16:02:33 +0000254% DestroyLogComponent(void)
cristy3ed852e2009-09-05 21:47:34 +0000255%
256*/
257
258static void *DestroyLogElement(void *log_info)
259{
260 register LogInfo
261 *p;
262
263 p=(LogInfo *) log_info;
264 if (p->file != (FILE *) NULL)
265 {
266 if (p->append == MagickFalse)
267 (void) fprintf(p->file,"</log>\n");
268 (void) fclose(p->file);
269 p->file=(FILE *) NULL;
270 }
cristy85340292009-10-21 19:32:19 +0000271 if (p->exempt == MagickFalse)
272 {
273 if (p->format != (char *) NULL)
274 p->format=DestroyString(p->format);
275 if (p->path != (char *) NULL)
276 p->path=DestroyString(p->path);
277 if (p->filename != (char *) NULL)
278 p->filename=DestroyString(p->filename);
279 }
cristy3ed852e2009-09-05 21:47:34 +0000280 p=(LogInfo *) RelinquishMagickMemory(p);
281 return((void *) NULL);
282}
283
cristydf1cc5f2009-10-19 16:02:33 +0000284MagickExport void DestroyLogComponent(void)
cristy3ed852e2009-09-05 21:47:34 +0000285{
286 AcquireSemaphoreInfo(&log_semaphore);
287 if (log_list != (LinkedListInfo *) NULL)
288 log_list=DestroyLinkedList(log_list,DestroyLogElement);
289 instantiate_log=MagickFalse;
290 RelinquishSemaphoreInfo(log_semaphore);
291 DestroySemaphoreInfo(&log_semaphore);
292}
293
294/*
295%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
296% %
297% %
298% %
299+ G e t L o g I n f o %
300% %
301% %
302% %
303%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
304%
305% GetLogInfo() searches the log list for the specified name and if found
306% returns attributes for that log.
307%
308% The format of the GetLogInfo method is:
309%
310% LogInfo *GetLogInfo(const char *name,ExceptionInfo *exception)
311%
312% A description of each parameter follows:
313%
314% o name: the log name.
315%
316% o exception: return any errors or warnings in this structure.
317%
318*/
319static LogInfo *GetLogInfo(const char *name,ExceptionInfo *exception)
320{
321 register LogInfo
322 *p;
323
324 assert(exception != (ExceptionInfo *) NULL);
325 if ((log_list == (LinkedListInfo *) NULL) || (instantiate_log == MagickFalse))
326 if (InitializeLogList(exception) == MagickFalse)
327 return((LogInfo *) NULL);
328 if ((log_list == (LinkedListInfo *) NULL) ||
329 (IsLinkedListEmpty(log_list) != MagickFalse))
330 return((LogInfo *) NULL);
331 if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
332 return((LogInfo *) GetValueFromLinkedList(log_list,0));
333 /*
334 Search for log tag.
335 */
336 AcquireSemaphoreInfo(&log_semaphore);
337 ResetLinkedListIterator(log_list);
338 p=(LogInfo *) GetNextValueInLinkedList(log_list);
339 while (p != (LogInfo *) NULL)
340 {
341 if (LocaleCompare(name,p->name) == 0)
342 break;
343 p=(LogInfo *) GetNextValueInLinkedList(log_list);
344 }
345 if (p != (LogInfo *) NULL)
346 (void) InsertValueInLinkedList(log_list,0,
347 RemoveElementByValueFromLinkedList(log_list,p));
348 RelinquishSemaphoreInfo(log_semaphore);
349 return(p);
350}
351
352/*
353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
354% %
355% %
356% %
357% G e t L o g I n f o L i s t %
358% %
359% %
360% %
361%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
362%
363% GetLogInfoList() returns any logs that match the specified pattern.
364%
365% The format of the GetLogInfoList function is:
366%
367% const LogInfo **GetLogInfoList(const char *pattern,
368% unsigned long *number_preferences,ExceptionInfo *exception)
369%
370% A description of each parameter follows:
371%
372% o pattern: Specifies a pointer to a text string containing a pattern.
373%
374% o number_preferences: This integer returns the number of logs in the list.
375%
376% o exception: return any errors or warnings in this structure.
377%
378*/
379#if defined(__cplusplus) || defined(c_plusplus)
380extern "C" {
381#endif
382
383static int LogInfoCompare(const void *x,const void *y)
384{
385 const LogInfo
386 **p,
387 **q;
388
389 p=(const LogInfo **) x,
390 q=(const LogInfo **) y;
391 if (LocaleCompare((*p)->path,(*q)->path) == 0)
392 return(LocaleCompare((*p)->name,(*q)->name));
393 return(LocaleCompare((*p)->path,(*q)->path));
394}
395
396#if defined(__cplusplus) || defined(c_plusplus)
397}
398#endif
399
400MagickExport const LogInfo **GetLogInfoList(const char *pattern,
401 unsigned long *number_preferences,ExceptionInfo *exception)
402{
403 const LogInfo
404 **preferences;
405
406 register const LogInfo
407 *p;
408
409 register long
410 i;
411
412 /*
413 Allocate log list.
414 */
415 assert(pattern != (char *) NULL);
416 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
417 assert(number_preferences != (unsigned long *) NULL);
418 *number_preferences=0;
419 p=GetLogInfo("*",exception);
420 if (p == (const LogInfo *) NULL)
421 return((const LogInfo **) NULL);
422 preferences=(const LogInfo **) AcquireQuantumMemory((size_t)
423 GetNumberOfElementsInLinkedList(log_list)+1UL,sizeof(*preferences));
424 if (preferences == (const LogInfo **) NULL)
425 return((const LogInfo **) NULL);
426 /*
427 Generate log list.
428 */
429 AcquireSemaphoreInfo(&log_semaphore);
430 ResetLinkedListIterator(log_list);
431 p=(const LogInfo *) GetNextValueInLinkedList(log_list);
432 for (i=0; p != (const LogInfo *) NULL; )
433 {
434 if ((p->stealth == MagickFalse) &&
435 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
436 preferences[i++]=p;
437 p=(const LogInfo *) GetNextValueInLinkedList(log_list);
438 }
439 RelinquishSemaphoreInfo(log_semaphore);
440 qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogInfoCompare);
441 preferences[i]=(LogInfo *) NULL;
442 *number_preferences=(unsigned long) i;
443 return(preferences);
444}
445
446/*
447%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
448% %
449% %
450% %
451% G e t L o g L i s t %
452% %
453% %
454% %
455%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
456%
457% GetLogList() returns any logs that match the specified pattern.
458%
459% The format of the GetLogList function is:
460%
461% char **GetLogList(const char *pattern,unsigned long *number_preferences,
462% ExceptionInfo *exception)
463%
464% A description of each parameter follows:
465%
466% o pattern: Specifies a pointer to a text string containing a pattern.
467%
468% o number_preferences: This integer returns the number of logs in the list.
469%
470% o exception: return any errors or warnings in this structure.
471%
472*/
473
474#if defined(__cplusplus) || defined(c_plusplus)
475extern "C" {
476#endif
477
478static int LogCompare(const void *x,const void *y)
479{
480 register const char
481 **p,
482 **q;
483
484 p=(const char **) x;
485 q=(const char **) y;
486 return(LocaleCompare(*p,*q));
487}
488
489#if defined(__cplusplus) || defined(c_plusplus)
490}
491#endif
492
493MagickExport char **GetLogList(const char *pattern,
494 unsigned long *number_preferences,ExceptionInfo *exception)
495{
496 char
497 **preferences;
498
499 register const LogInfo
500 *p;
501
502 register long
503 i;
504
505 /*
506 Allocate log list.
507 */
508 assert(pattern != (char *) NULL);
509 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
510 assert(number_preferences != (unsigned long *) NULL);
511 *number_preferences=0;
512 p=GetLogInfo("*",exception);
513 if (p == (const LogInfo *) NULL)
514 return((char **) NULL);
515 preferences=(char **) AcquireQuantumMemory((size_t)
516 GetNumberOfElementsInLinkedList(log_list)+1UL,sizeof(*preferences));
517 if (preferences == (char **) NULL)
518 return((char **) NULL);
519 /*
520 Generate log list.
521 */
522 AcquireSemaphoreInfo(&log_semaphore);
523 ResetLinkedListIterator(log_list);
524 p=(const LogInfo *) GetNextValueInLinkedList(log_list);
525 for (i=0; p != (const LogInfo *) NULL; )
526 {
527 if ((p->stealth == MagickFalse) &&
528 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
529 preferences[i++]=ConstantString(p->name);
530 p=(const LogInfo *) GetNextValueInLinkedList(log_list);
531 }
532 RelinquishSemaphoreInfo(log_semaphore);
533 qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogCompare);
534 preferences[i]=(char *) NULL;
535 *number_preferences=(unsigned long) i;
536 return(preferences);
537}
538
539/*
540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
541% %
542% %
543% %
544% G e t L o g N a m e %
545% %
546% %
547% %
548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
549%
550% GetLogName() returns the current log name.
551%
552% The format of the GetLogName method is:
553%
554% const char *GetLogName(void)
555%
556*/
557MagickExport const char *GetLogName(void)
558{
559 return(log_name);
560}
561
562/*
563%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
564% %
565% %
566% %
567+ I n i t i a l i z e L o g L i s t %
568% %
569% %
570% %
571%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
572%
573% InitializeLogList() initialize the log list.
574%
575% The format of the InitializeLogList method is:
576%
577% MagickBooleanType InitializeLogList(ExceptionInfo *exception)
578%
579% A description of each parameter follows.
580%
581% o exception: return any errors or warnings in this structure.
582%
583*/
584static MagickBooleanType InitializeLogList(ExceptionInfo *exception)
585{
586 if ((log_list == (LinkedListInfo *) NULL) && (instantiate_log == MagickFalse))
587 {
588 AcquireSemaphoreInfo(&log_semaphore);
589 if ((log_list == (LinkedListInfo *) NULL) &&
590 (instantiate_log == MagickFalse))
591 {
592 (void) LoadLogLists(LogFilename,exception);
593 instantiate_log=MagickTrue;
594 }
595 RelinquishSemaphoreInfo(log_semaphore);
596 }
597 return(log_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
598}
599
600/*
601%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
602% %
603% %
604% %
cristydf1cc5f2009-10-19 16:02:33 +0000605+ I n s t a n t i a t e L o g C o m p o n e n t %
cristy41c3c772009-10-19 02:17:37 +0000606% %
607% %
608% %
609%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
610%
cristydf1cc5f2009-10-19 16:02:33 +0000611% InstantiateLogComponent() instantiates the log component.
cristy41c3c772009-10-19 02:17:37 +0000612%
cristydf1cc5f2009-10-19 16:02:33 +0000613% The format of the InstantiateLogComponent method is:
cristy41c3c772009-10-19 02:17:37 +0000614%
cristydf1cc5f2009-10-19 16:02:33 +0000615% MagickBooleanType InstantiateLogComponent(void)
cristy41c3c772009-10-19 02:17:37 +0000616%
617*/
cristydf1cc5f2009-10-19 16:02:33 +0000618MagickExport MagickBooleanType InstantiateLogComponent(void)
cristy41c3c772009-10-19 02:17:37 +0000619{
620 AcquireSemaphoreInfo(&log_semaphore);
621 RelinquishSemaphoreInfo(log_semaphore);
622 return(MagickFalse);
623}
624
625/*
626%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
627% %
628% %
629% %
cristy3ed852e2009-09-05 21:47:34 +0000630% I s E v e n t L o g g i n g %
631% %
632% %
633% %
634%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
635%
636% IsEventLogging() returns MagickTrue if debug of events is enabled otherwise
637% MagickFalse.
638%
639% The format of the IsEventLogging method is:
640%
641% MagickBooleanType IsEventLogging(void)
642%
643*/
644MagickExport MagickBooleanType IsEventLogging(void)
645{
646 const LogInfo
647 *log_info;
648
649 ExceptionInfo
650 *exception;
651
652 if ((log_list == (LinkedListInfo *) NULL) ||
653 (IsLinkedListEmpty(log_list) != MagickFalse))
654 return(MagickFalse);
655 exception=AcquireExceptionInfo();
656 log_info=GetLogInfo("*",exception);
657 exception=DestroyExceptionInfo(exception);
658 return(log_info->event_mask != NoEvents ? MagickTrue : MagickFalse);
659}
660/*
661%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
662% %
663% %
664% %
665% L i s t L o g I n f o %
666% %
667% %
668% %
669%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
670%
671% ListLogInfo() lists the log info to a file.
672%
673% The format of the ListLogInfo method is:
674%
675% MagickBooleanType ListLogInfo(FILE *file,ExceptionInfo *exception)
676%
677% A description of each parameter follows.
678%
679% o file: An pointer to a FILE.
680%
681% o exception: return any errors or warnings in this structure.
682%
683*/
684MagickExport MagickBooleanType ListLogInfo(FILE *file,ExceptionInfo *exception)
685{
686#define MegabytesToBytes(value) ((MagickSizeType) (value)*1024*1024)
687
688 char
689 limit[MaxTextExtent];
690
691 const char
692 *path;
693
694 const LogInfo
695 **log_info;
696
697 long
698 j;
699
700 register long
701 i;
702
703 unsigned long
704 number_aliases;
705
706 if (file == (const FILE *) NULL)
707 file=stdout;
708 log_info=GetLogInfoList("*",&number_aliases,exception);
709 if (log_info == (const LogInfo **) NULL)
710 return(MagickFalse);
711 j=0;
712 path=(const char *) NULL;
713 for (i=0; i < (long) number_aliases; i++)
714 {
715 if (log_info[i]->stealth != MagickFalse)
716 continue;
717 if ((path == (const char *) NULL) ||
718 (LocaleCompare(path,log_info[i]->path) != 0))
719 {
720 if (log_info[i]->path != (char *) NULL)
721 (void) fprintf(file,"\nPath: %s\n\n",log_info[i]->path);
722 (void) fprintf(file,"Filename Generations Limit Format\n");
723 (void) fprintf(file,"-------------------------------------------------"
724 "------------------------------\n");
725 }
726 path=log_info[i]->path;
727 if (log_info[i]->filename != (char *) NULL)
728 {
729 (void) fprintf(file,"%s",log_info[i]->filename);
730 for (j=(long) strlen(log_info[i]->filename); j <= 16; j++)
731 (void) fprintf(file," ");
732 }
733 (void) fprintf(file,"%9lu ",log_info[i]->generations);
734 (void) FormatMagickSize(MegabytesToBytes(log_info[i]->limit),limit);
735 (void) fprintf(file,"%8s ",limit);
736 if (log_info[i]->format != (char *) NULL)
737 (void) fprintf(file,"%s",log_info[i]->format);
738 (void) fprintf(file,"\n");
739 }
740 (void) fflush(file);
741 log_info=(const LogInfo **) RelinquishMagickMemory((void *) log_info);
742 return(MagickTrue);
743}
744
745/*
746%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
747% %
748% %
749% %
750% L o g M a g i c k E v e n t %
751% %
752% %
753% %
754%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
755%
756% LogMagickEvent() logs an event as determined by the log configuration file.
757% If an error occurs, MagickFalse is returned otherwise MagickTrue.
758%
759% The format of the LogMagickEvent method is:
760%
761% MagickBooleanType LogMagickEvent(const LogEventType type,
762% const char *module,const char *function,const unsigned long line,
763% const char *format,...)
764%
765% A description of each parameter follows:
766%
767% o type: the event type.
768%
769% o filename: the source module filename.
770%
771% o function: the function name.
772%
773% o line: the line number of the source module.
774%
775% o format: the output format.
776%
777*/
778static char *TranslateEvent(const LogEventType magick_unused(type),
779 const char *module,const char *function,const unsigned long line,
780 const char *domain,const char *event)
781{
782 char
783 *text;
784
785 double
786 elapsed_time,
787 user_time;
788
789 ExceptionInfo
790 *exception;
791
792 LogInfo
793 *log_info;
794
795 register char
796 *q;
797
798 register const char
799 *p;
800
801 size_t
802 extent;
803
804 time_t
805 seconds;
806
807 exception=AcquireExceptionInfo();
808 log_info=(LogInfo *) GetLogInfo("*",exception);
809 exception=DestroyExceptionInfo(exception);
810 seconds=time((time_t *) NULL);
811 elapsed_time=GetElapsedTime(&log_info->timer);
812 user_time=GetUserTime(&log_info->timer);
813 text=AcquireString(event);
814 if (log_info->format == (char *) NULL)
815 return(text);
816 extent=strlen(event)+MaxTextExtent;
817 if (LocaleCompare(log_info->format,"xml") == 0)
818 {
819 char
820 timestamp[MaxTextExtent];
821
822 /*
823 Translate event in "XML" format.
824 */
825 (void) FormatMagickTime(seconds,extent,timestamp);
826 (void) FormatMagickString(text,extent,
827 "<entry>\n"
828 " <timestamp>%s</timestamp>\n"
cristy8b76e552009-09-28 18:20:20 +0000829 " <elapsed-time>%ld:%02ld.%03ld</elapsed-time>\n"
cristy3ed852e2009-09-05 21:47:34 +0000830 " <user-time>%0.3f</user-time>\n"
831 " <process-id>%ld</process-id>\n"
832 " <thread-id>%lu</thread-id>\n"
833 " <module>%s</module>\n"
834 " <function>%s</function>\n"
835 " <line>%lu</line>\n"
836 " <domain>%s</domain>\n"
837 " <event>%s</event>\n"
cristy8b76e552009-09-28 18:20:20 +0000838 "</entry>",timestamp,(long) (elapsed_time/60.0),(long)
839 floor(fmod(elapsed_time,60.0)),(long) (1000.0*(elapsed_time-
840 floor(elapsed_time))+0.5),user_time,(long) getpid(),
cristy3ed852e2009-09-05 21:47:34 +0000841 GetMagickThreadSignature(),module,function,line,domain,event);
842 return(text);
843 }
844 /*
845 Translate event in "human readable" format.
846 */
847 q=text;
848 for (p=log_info->format; *p != '\0'; p++)
849 {
850 *q='\0';
851 if ((size_t) (q-text+MaxTextExtent) >= extent)
852 {
853 extent+=MaxTextExtent;
854 text=(char *) ResizeQuantumMemory(text,extent+MaxTextExtent,
855 sizeof(*text));
856 if (text == (char *) NULL)
857 return((char *) NULL);
858 q=text+strlen(text);
859 }
860 /*
861 The format of the log is defined by embedding special format characters:
862
863 %c client name
864 %d domain
865 %e event
866 %f function
867 %g generation
868 %l line
869 %m module
870 %n log name
871 %p process id
872 %r real CPU time
873 %t wall clock time
874 %u user CPU time
875 %v version
876 %% percent sign
877 \n newline
878 \r carriage return
879 */
880 if ((*p == '\\') && (*(p+1) == 'r'))
881 {
882 *q++='\r';
883 p++;
884 continue;
885 }
886 if ((*p == '\\') && (*(p+1) == 'n'))
887 {
888 *q++='\n';
889 p++;
890 continue;
891 }
892 if (*p != '%')
893 {
894 *q++=(*p);
895 continue;
896 }
897 p++;
898 switch (*p)
899 {
900 case 'c':
901 {
902 q+=CopyMagickString(q,GetClientName(),extent);
903 break;
904 }
905 case 'd':
906 {
907 q+=CopyMagickString(q,domain,extent);
908 break;
909 }
910 case 'e':
911 {
912 q+=CopyMagickString(q,event,extent);
913 break;
914 }
915 case 'f':
916 {
917 q+=CopyMagickString(q,function,extent);
918 break;
919 }
920 case 'g':
921 {
922 if (log_info->generations == 0)
923 {
924 (void) CopyMagickString(q,"0",extent);
925 q++;
926 break;
927 }
928 q+=FormatMagickString(q,extent,"%lu",log_info->generation %
929 log_info->generations);
930 break;
931 }
932 case 'l':
933 {
934 q+=FormatMagickString(q,extent,"%lu",line);
935 break;
936 }
937 case 'm':
938 {
939 register const char
940 *p;
941
942 for (p=module+strlen(module)-1; p > module; p--)
943 if (*p == *DirectorySeparator)
944 {
945 p++;
946 break;
947 }
948 q+=CopyMagickString(q,p,extent);
949 break;
950 }
951 case 'n':
952 {
953 q+=CopyMagickString(q,GetLogName(),extent);
954 break;
955 }
956 case 'p':
957 {
958 q+=FormatMagickString(q,extent,"%ld",(long) getpid());
959 break;
960 }
961 case 'r':
962 {
cristy8b76e552009-09-28 18:20:20 +0000963 q+=FormatMagickString(q,extent,"%ld:%02ld.%03ld",(long)
964 (elapsed_time/60.0),(long) floor(fmod(elapsed_time,60.0)),
965 (long) (1000.0*(elapsed_time-floor(elapsed_time))+0.5));
cristy3ed852e2009-09-05 21:47:34 +0000966 break;
967 }
968 case 't':
969 {
970 q+=FormatMagickTime(seconds,extent,q);
971 break;
972 }
973 case 'u':
974 {
975 q+=FormatMagickString(q,extent,"%0.3fu",user_time);
976 break;
977 }
978 case 'v':
979 {
980 q+=CopyMagickString(q,MagickLibVersionText,extent);
981 break;
982 }
983 case '%':
984 {
985 *q++=(*p);
986 break;
987 }
988 default:
989 {
990 *q++='%';
991 *q++=(*p);
992 break;
993 }
994 }
995 }
996 *q='\0';
997 return(text);
998}
999
1000static char *TranslateFilename(const LogInfo *log_info)
1001{
1002 char
1003 *filename;
1004
1005 register char
1006 *q;
1007
1008 register const char
1009 *p;
1010
1011 size_t
1012 extent;
1013
1014 /*
1015 Translate event in "human readable" format.
1016 */
1017 assert(log_info != (LogInfo *) NULL);
1018 assert(log_info->filename != (char *) NULL);
1019 filename=AcquireString((char *) NULL);
1020 extent=MaxTextExtent;
1021 q=filename;
1022 for (p=log_info->filename; *p != '\0'; p++)
1023 {
1024 *q='\0';
1025 if ((size_t) (q-filename+MaxTextExtent) >= extent)
1026 {
1027 extent+=MaxTextExtent;
1028 filename=(char *) ResizeQuantumMemory(filename,extent+MaxTextExtent,
1029 sizeof(*filename));
1030 if (filename == (char *) NULL)
1031 return((char *) NULL);
1032 q=filename+strlen(filename);
1033 }
1034 /*
1035 The format of the filename is defined by embedding special format
1036 characters:
1037
1038 %c client name
1039 %n log name
1040 %p process id
1041 %v version
1042 %% percent sign
1043 */
1044 if (*p != '%')
1045 {
1046 *q++=(*p);
1047 continue;
1048 }
1049 p++;
1050 switch (*p)
1051 {
1052 case 'c':
1053 {
1054 q+=CopyMagickString(q,GetClientName(),extent);
1055 break;
1056 }
1057 case 'g':
1058 {
1059 if (log_info->generations == 0)
1060 {
1061 (void) CopyMagickString(q,"0",extent);
1062 q++;
1063 break;
1064 }
1065 q+=FormatMagickString(q,extent,"%lu",log_info->generation %
1066 log_info->generations);
1067 break;
1068 }
1069 case 'n':
1070 {
1071 q+=CopyMagickString(q,GetLogName(),extent);
1072 break;
1073 }
1074 case 'p':
1075 {
1076 q+=FormatMagickString(q,extent,"%ld",(long) getpid());
1077 break;
1078 }
1079 case 'v':
1080 {
1081 q+=CopyMagickString(q,MagickLibVersionText,extent);
1082 break;
1083 }
1084 case '%':
1085 {
1086 *q++=(*p);
1087 break;
1088 }
1089 default:
1090 {
1091 *q++='%';
1092 *q++=(*p);
1093 break;
1094 }
1095 }
1096 }
1097 *q='\0';
1098 return(filename);
1099}
1100
1101MagickBooleanType LogMagickEventList(const LogEventType type,const char *module,
1102 const char *function,const unsigned long line,const char *format,
1103 va_list operands)
1104{
1105 char
1106 event[MaxTextExtent],
1107 *text;
1108
1109 const char
1110 *domain;
1111
1112 ExceptionInfo
1113 *exception;
1114
1115 int
1116 n;
1117
1118 LogInfo
1119 *log_info;
1120
1121 if (IsEventLogging() == MagickFalse)
1122 return(MagickFalse);
1123 exception=AcquireExceptionInfo();
1124 log_info=(LogInfo *) GetLogInfo("*",exception);
1125 exception=DestroyExceptionInfo(exception);
1126 AcquireSemaphoreInfo(&log_semaphore);
1127 if ((log_info->event_mask & type) == 0)
1128 {
1129 RelinquishSemaphoreInfo(log_semaphore);
1130 return(MagickTrue);
1131 }
1132 domain=MagickOptionToMnemonic(MagickLogEventOptions,type);
1133#if defined(MAGICKCORE_HAVE_VSNPRINTF)
1134 n=vsnprintf(event,MaxTextExtent,format,operands);
1135#else
1136 n=vsprintf(event,format,operands);
1137#endif
1138 if (n < 0)
1139 event[MaxTextExtent-1]='\0';
1140 text=TranslateEvent(type,module,function,line,domain,event);
1141 if (text == (char *) NULL)
1142 {
1143 (void) ContinueTimer((TimerInfo *) &log_info->timer);
1144 RelinquishSemaphoreInfo(log_semaphore);
1145 return(MagickFalse);
1146 }
1147 if ((log_info->handler_mask & ConsoleHandler) != 0)
1148 {
1149 (void) fprintf(stderr,"%s\n",text);
1150 (void) fflush(stderr);
1151 }
1152 if ((log_info->handler_mask & DebugHandler) != 0)
1153 {
1154#if defined(__WINDOWS__)
1155 OutputDebugString(text);
1156#endif
1157 }
1158 if ((log_info->handler_mask & EventHandler) != 0)
1159 {
1160#if defined(__WINDOWS__)
1161 (void) NTReportEvent(text,MagickFalse);
1162#endif
1163 }
1164 if ((log_info->handler_mask & FileHandler) != 0)
1165 {
1166 struct stat
1167 file_info;
1168
1169 file_info.st_size=0;
1170 if (log_info->file != (FILE *) NULL)
1171 (void) fstat(fileno(log_info->file),&file_info);
1172 if (file_info.st_size > (off_t) (1024*1024*log_info->limit))
1173 {
1174 (void) fprintf(log_info->file,"</log>\n");
1175 (void) fclose(log_info->file);
1176 log_info->file=(FILE *) NULL;
1177 }
1178 if (log_info->file == (FILE *) NULL)
1179 {
1180 char
1181 *filename;
1182
1183 filename=TranslateFilename(log_info);
1184 if (filename == (char *) NULL)
1185 {
1186 (void) ContinueTimer((TimerInfo *) &log_info->timer);
1187 RelinquishSemaphoreInfo(log_semaphore);
1188 return(MagickFalse);
1189 }
1190 log_info->append=IsPathAccessible(filename);
1191 log_info->file=OpenMagickStream(filename,"ab");
1192 filename=(char *) RelinquishMagickMemory(filename);
1193 if (log_info->file == (FILE *) NULL)
1194 {
1195 RelinquishSemaphoreInfo(log_semaphore);
1196 return(MagickFalse);
1197 }
1198 log_info->generation++;
1199 if (log_info->append == MagickFalse)
1200 {
1201 (void) fprintf(log_info->file,"<?xml version=\"1.0\" "
1202 "encoding=\"UTF-8\" standalone=\"yes\"?>\n");
1203 (void) fprintf(log_info->file,"<log>\n");
1204 }
1205 }
1206 (void) fprintf(log_info->file,"%s\n",text);
1207 (void) fflush(log_info->file);
1208 }
1209 if ((log_info->handler_mask & StdoutHandler) != 0)
1210 {
1211 (void) fprintf(stdout,"%s\n",text);
1212 (void) fflush(stdout);
1213 }
1214 if ((log_info->handler_mask & StderrHandler) != 0)
1215 {
1216 (void) fprintf(stderr,"%s\n",text);
1217 (void) fflush(stderr);
1218 }
1219 text=(char *) RelinquishMagickMemory(text);
1220 (void) ContinueTimer((TimerInfo *) &log_info->timer);
1221 RelinquishSemaphoreInfo(log_semaphore);
1222 return(MagickTrue);
1223}
1224
1225MagickBooleanType LogMagickEvent(const LogEventType type,const char *module,
1226 const char *function,const unsigned long line,const char *format,...)
1227{
1228 va_list
1229 operands;
1230
1231 MagickBooleanType
1232 status;
1233
1234 va_start(operands,format);
1235 status=LogMagickEventList(type,module,function,line,format,operands);
1236 va_end(operands);
1237 return(status);
1238}
1239
1240/*
1241%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1242% %
1243% %
1244% %
1245+ L o a d L o g L i s t %
1246% %
1247% %
1248% %
1249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1250%
1251% LoadLogList() loads the log configuration file which provides a
1252% mapping between log attributes and log name.
1253%
1254% The format of the LoadLogList method is:
1255%
1256% MagickBooleanType LoadLogList(const char *xml,const char *filename,
1257% const unsigned long depth,ExceptionInfo *exception)
1258%
1259% A description of each parameter follows:
1260%
1261% o xml: The log list in XML format.
1262%
1263% o filename: The log list filename.
1264%
1265% o depth: depth of <include /> statements.
1266%
1267% o exception: return any errors or warnings in this structure.
1268%
1269*/
1270static MagickBooleanType LoadLogList(const char *xml,const char *filename,
1271 const unsigned long depth,ExceptionInfo *exception)
1272{
1273 char
1274 keyword[MaxTextExtent],
1275 *token;
1276
1277 const char
1278 *q;
1279
1280 LogInfo
1281 *log_info = (LogInfo *) NULL;
1282
1283 MagickStatusType
1284 status;
1285
1286 /*
1287 Load the log map file.
1288 */
1289 if (xml == (const char *) NULL)
1290 return(MagickFalse);
1291 if (log_list == (LinkedListInfo *) NULL)
1292 {
1293 log_list=NewLinkedList(0);
1294 if (log_list == (LinkedListInfo *) NULL)
1295 {
1296 ThrowFileException(exception,ResourceLimitError,
1297 "MemoryAllocationFailed",filename);
1298 return(MagickFalse);
1299 }
1300 }
1301 status=MagickTrue;
1302 token=AcquireString((const char *) xml);
1303 for (q=(const char *) xml; *q != '\0'; )
1304 {
1305 /*
1306 Interpret XML.
1307 */
1308 GetMagickToken(q,&q,token);
1309 if (*token == '\0')
1310 break;
1311 (void) CopyMagickString(keyword,token,MaxTextExtent);
1312 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1313 {
1314 /*
1315 Doctype element.
1316 */
1317 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1318 GetMagickToken(q,&q,token);
1319 continue;
1320 }
1321 if (LocaleNCompare(keyword,"<!--",4) == 0)
1322 {
1323 /*
1324 Comment element.
1325 */
1326 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1327 GetMagickToken(q,&q,token);
1328 continue;
1329 }
1330 if (LocaleCompare(keyword,"<include") == 0)
1331 {
1332 /*
1333 Include element.
1334 */
1335 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1336 {
1337 (void) CopyMagickString(keyword,token,MaxTextExtent);
1338 GetMagickToken(q,&q,token);
1339 if (*token != '=')
1340 continue;
1341 GetMagickToken(q,&q,token);
1342 if (LocaleCompare(keyword,"file") == 0)
1343 {
1344 if (depth > 200)
1345 (void) ThrowMagickException(exception,GetMagickModule(),
1346 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
1347 else
1348 {
1349 char
1350 path[MaxTextExtent],
1351 *xml;
1352
1353 GetPathComponent(filename,HeadPath,path);
1354 if (*path != '\0')
1355 (void) ConcatenateMagickString(path,DirectorySeparator,
1356 MaxTextExtent);
1357 if (*token == *DirectorySeparator)
1358 (void) CopyMagickString(path,token,MaxTextExtent);
1359 else
1360 (void) ConcatenateMagickString(path,token,MaxTextExtent);
1361 xml=FileToString(path,~0,exception);
1362 if (xml != (char *) NULL)
1363 {
1364 status|=LoadLogList(xml,path,depth+1,exception);
1365 xml=DestroyString(xml);
1366 }
1367 }
1368 }
1369 }
1370 continue;
1371 }
1372 if (LocaleCompare(keyword,"<logmap>") == 0)
1373 {
1374 /*
1375 Allocate memory for the log list.
1376 */
1377 log_info=(LogInfo *) AcquireMagickMemory(sizeof(*log_info));
1378 if (log_info == (LogInfo *) NULL)
1379 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1380 (void) ResetMagickMemory(log_info,0,sizeof(*log_info));
1381 log_info->path=ConstantString(filename);
1382 GetTimerInfo((TimerInfo *) &log_info->timer);
cristy85340292009-10-21 19:32:19 +00001383 log_info->exempt=MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +00001384 log_info->signature=MagickSignature;
1385 continue;
1386 }
1387 if (log_info == (LogInfo *) NULL)
1388 continue;
1389 if (LocaleCompare(keyword,"</logmap>") == 0)
1390 {
1391 status=AppendValueToLinkedList(log_list,log_info);
1392 if (status == MagickFalse)
1393 (void) ThrowMagickException(exception,GetMagickModule(),
1394 ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
1395 log_info=(LogInfo *) NULL;
1396 }
1397 GetMagickToken(q,(const char **) NULL,token);
1398 if (*token != '=')
1399 continue;
1400 GetMagickToken(q,&q,token);
1401 GetMagickToken(q,&q,token);
1402 switch (*keyword)
1403 {
1404 case 'E':
1405 case 'e':
1406 {
1407 if (LocaleCompare((char *) keyword,"events") == 0)
1408 {
1409 log_info->event_mask=(LogEventType) (log_info->event_mask |
1410 ParseMagickOption(MagickLogEventOptions,MagickTrue,token));
1411 break;
1412 }
1413 break;
1414 }
1415 case 'F':
1416 case 'f':
1417 {
1418 if (LocaleCompare((char *) keyword,"filename") == 0)
1419 {
1420 if (log_info->filename != (char *) NULL)
1421 log_info->filename=(char *)
1422 RelinquishMagickMemory(log_info->filename);
1423 log_info->filename=ConstantString(token);
1424 break;
1425 }
1426 if (LocaleCompare((char *) keyword,"format") == 0)
1427 {
1428 if (log_info->format != (char *) NULL)
1429 log_info->format=(char *)
1430 RelinquishMagickMemory(log_info->format);
1431 log_info->format=ConstantString(token);
1432 break;
1433 }
1434 break;
1435 }
1436 case 'G':
1437 case 'g':
1438 {
1439 if (LocaleCompare((char *) keyword,"generations") == 0)
1440 {
1441 if (LocaleCompare(token,"unlimited") == 0)
1442 {
1443 log_info->generations=(~0UL);
1444 break;
1445 }
1446 log_info->generations=(unsigned long) atol(token);
1447 break;
1448 }
1449 break;
1450 }
1451 case 'L':
1452 case 'l':
1453 {
1454 if (LocaleCompare((char *) keyword,"limit") == 0)
1455 {
1456 if (LocaleCompare(token,"unlimited") == 0)
1457 {
1458 log_info->limit=(~0UL);
1459 break;
1460 }
1461 log_info->limit=(unsigned long) atol(token);
1462 break;
1463 }
1464 break;
1465 }
1466 case 'O':
1467 case 'o':
1468 {
1469 if (LocaleCompare((char *) keyword,"output") == 0)
1470 {
1471 log_info->handler_mask=(LogHandlerType)
1472 (log_info->handler_mask | ParseLogHandlers(token));
1473 break;
1474 }
1475 break;
1476 }
1477 default:
1478 break;
1479 }
1480 }
1481 token=DestroyString(token);
1482 if (log_list == (LinkedListInfo *) NULL)
1483 return(MagickFalse);
1484 return(status != 0 ? MagickTrue : MagickFalse);
1485}
1486
1487/*
1488%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1489% %
1490% %
1491% %
1492% L o a d L o g L i s t s %
1493% %
1494% %
1495% %
1496%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1497%
1498% LoadLogLists() loads one or more log configuration file which provides a
1499% mapping between log attributes and log name.
1500%
1501% The format of the LoadLogLists method is:
1502%
1503% MagickBooleanType LoadLogLists(const char *filename,
1504% ExceptionInfo *exception)
1505%
1506% A description of each parameter follows:
1507%
1508% o filename: the log configuration filename.
1509%
1510% o exception: return any errors or warnings in this structure.
1511%
1512*/
1513static MagickBooleanType LoadLogLists(const char *filename,
1514 ExceptionInfo *exception)
1515{
cristy3ed852e2009-09-05 21:47:34 +00001516 const StringInfo
1517 *option;
1518
1519 LinkedListInfo
1520 *options;
1521
1522 MagickStatusType
1523 status;
1524
cristy85340292009-10-21 19:32:19 +00001525 register long
1526 i;
1527
1528 /*
1529 Load built-in log map.
1530 */
cristy3ed852e2009-09-05 21:47:34 +00001531 status=MagickFalse;
cristy85340292009-10-21 19:32:19 +00001532 if (log_list == (LinkedListInfo *) NULL)
1533 {
1534 log_list=NewLinkedList(0);
1535 if (log_list == (LinkedListInfo *) NULL)
1536 {
1537 ThrowFileException(exception,ResourceLimitError,
1538 "MemoryAllocationFailed",filename);
1539 return(MagickFalse);
1540 }
1541 }
1542 for (i=0; i < (long) (sizeof(LogMap)/sizeof(*LogMap)); i++)
1543 {
1544 LogInfo
1545 *log_info;
1546
1547 register const LogMapInfo
1548 *p;
1549
1550 p=LogMap+i;
1551 log_info=(LogInfo *) AcquireMagickMemory(sizeof(*log_info));
1552 if (log_info == (LogInfo *) NULL)
1553 {
1554 (void) ThrowMagickException(exception,GetMagickModule(),
1555 ResourceLimitError,"MemoryAllocationFailed","`%s'",log_info->name);
1556 continue;
1557 }
1558 (void) ResetMagickMemory(log_info,0,sizeof(*log_info));
1559 log_info->path=(char *) "[built-in]";
1560 GetTimerInfo((TimerInfo *) &log_info->timer);
1561 log_info->event_mask=p->event_mask;
1562 log_info->handler_mask=p->handler_mask;
1563 log_info->filename=(char *) p->filename;
1564 log_info->format=(char *) p->format;
1565 log_info->exempt=MagickTrue;
1566 log_info->signature=MagickSignature;
1567 status=AppendValueToLinkedList(log_list,log_info);
1568 if (status == MagickFalse)
1569 (void) ThrowMagickException(exception,GetMagickModule(),
1570 ResourceLimitError,"MemoryAllocationFailed","`%s'",log_info->name);
1571 }
1572 /*
1573 Load external log map.
1574 */
cristy3ed852e2009-09-05 21:47:34 +00001575 options=GetConfigureOptions(filename,exception);
1576 option=(const StringInfo *) GetNextValueInLinkedList(options);
1577 while (option != (const StringInfo *) NULL)
1578 {
1579 status|=LoadLogList((const char *) GetStringInfoDatum(option),
1580 GetStringInfoPath(option),0,exception);
1581 option=(const StringInfo *) GetNextValueInLinkedList(options);
1582 }
1583 options=DestroyConfigureOptions(options);
cristy3ed852e2009-09-05 21:47:34 +00001584 return(status != 0 ? MagickTrue : MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00001585}
1586
1587/*
1588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1589% %
1590% %
1591% %
1592+ P a r s e L o g H a n d l e r s %
1593% %
1594% %
1595% %
1596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1597%
1598% ParseLogHandlers() parses a string defining which handlers takes a log
1599% message and exports them.
1600%
1601% The format of the ParseLogHandlers method is:
1602%
1603% LogHandlerType ParseLogHandlers(const char *handlers)
1604%
1605% A description of each parameter follows:
1606%
1607% o handlers: one or more handlers separated by commas.
1608%
1609*/
1610static LogHandlerType ParseLogHandlers(const char *handlers)
1611{
1612 LogHandlerType
1613 handler_mask;
1614
1615 register const char
1616 *p;
1617
1618 register long
1619 i;
1620
1621 size_t
1622 length;
1623
1624 handler_mask=NoHandler;
1625 for (p=handlers; p != (char *) NULL; p=strchr(p,','))
1626 {
1627 while ((*p != '\0') && ((isspace((int) ((unsigned char) *p)) != 0) ||
1628 (*p == ',')))
1629 p++;
1630 for (i=0; LogHandlers[i].name != (char *) NULL; i++)
1631 {
1632 length=strlen(LogHandlers[i].name);
1633 if (LocaleNCompare(p,LogHandlers[i].name,length) == 0)
1634 {
1635 handler_mask=(LogHandlerType) (handler_mask | LogHandlers[i].handler);
1636 break;
1637 }
1638 }
1639 if (LogHandlers[i].name == (char *) NULL)
1640 return(UndefinedHandler);
1641 }
1642 return(handler_mask);
1643}
1644
1645/*
1646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1647% %
1648% %
1649% %
1650% S e t L o g E v e n t M a s k %
1651% %
1652% %
1653% %
1654%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1655%
1656% SetLogEventMask() accepts a list that determines which events to log. All
1657% other events are ignored. By default, no debug is enabled. This method
1658% returns the previous log event mask.
1659%
1660% The format of the SetLogEventMask method is:
1661%
1662% LogEventType SetLogEventMask(const char *events)
1663%
1664% A description of each parameter follows:
1665%
1666% o events: log these events.
1667%
1668*/
1669MagickExport LogEventType SetLogEventMask(const char *events)
1670{
1671 ExceptionInfo
1672 *exception;
1673
1674 LogInfo
1675 *log_info;
1676
1677 long
1678 option;
1679
1680 exception=AcquireExceptionInfo();
1681 log_info=(LogInfo *) GetLogInfo("*",exception);
1682 exception=DestroyExceptionInfo(exception);
1683 option=ParseMagickOption(MagickLogEventOptions,MagickTrue,events);
1684 AcquireSemaphoreInfo(&log_semaphore);
1685 log_info=(LogInfo *) GetValueFromLinkedList(log_list,0);
1686 log_info->event_mask=(LogEventType) option;
1687 if (option == -1)
1688 log_info->event_mask=UndefinedEvents;
1689 RelinquishSemaphoreInfo(log_semaphore);
1690 return(log_info->event_mask);
1691}
1692
1693/*
1694%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1695% %
1696% %
1697% %
1698% S e t L o g F o r m a t %
1699% %
1700% %
1701% %
1702%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1703%
1704% SetLogFormat() sets the format for the "human readable" log record.
1705%
1706% The format of the LogMagickFormat method is:
1707%
1708% SetLogFormat(const char *format)
1709%
1710% A description of each parameter follows:
1711%
1712% o format: the log record format.
1713%
1714*/
1715MagickExport void SetLogFormat(const char *format)
1716{
1717 LogInfo
1718 *log_info;
1719
1720 ExceptionInfo
1721 *exception;
1722
1723 exception=AcquireExceptionInfo();
1724 log_info=(LogInfo *) GetLogInfo("*",exception);
1725 exception=DestroyExceptionInfo(exception);
1726 AcquireSemaphoreInfo(&log_semaphore);
1727 if (log_info->format != (char *) NULL)
1728 log_info->format=DestroyString(log_info->format);
1729 log_info->format=ConstantString(format);
1730 RelinquishSemaphoreInfo(log_semaphore);
1731}
1732
1733/*
1734%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1735% %
1736% %
1737% %
1738% S e t L o g N a m e %
1739% %
1740% %
1741% %
1742%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1743%
1744% SetLogName() sets the log name and returns it.
1745%
1746% The format of the SetLogName method is:
1747%
1748% const char *SetLogName(const char *name)
1749%
1750% A description of each parameter follows:
1751%
1752% o log_name: SetLogName() returns the current client name.
1753%
1754% o name: Specifies the new client name.
1755%
1756*/
1757MagickExport const char *SetLogName(const char *name)
1758{
1759 if ((name != (char *) NULL) && (*name != '\0'))
1760 (void) CopyMagickString(log_name,name,MaxTextExtent);
1761 return(log_name);
1762}