MagickCore 7.1.1
Convert, Edit, Or Compose Bitmap Images
Loading...
Searching...
No Matches
log.c
1/*
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% Cristy %
17% September 2002 %
18% %
19% %
20% Copyright @ 1999 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% https://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 "MagickCore/studio.h"
43#include "MagickCore/blob.h"
44#include "MagickCore/client.h"
45#include "MagickCore/configure.h"
46#include "MagickCore/configure-private.h"
47#include "MagickCore/exception.h"
48#include "MagickCore/exception-private.h"
49#include "MagickCore/linked-list.h"
50#include "MagickCore/linked-list-private.h"
51#include "MagickCore/log.h"
52#include "MagickCore/log-private.h"
53#include "MagickCore/memory_.h"
54#include "MagickCore/nt-base-private.h"
55#include "MagickCore/option.h"
56#include "MagickCore/semaphore.h"
57#include "MagickCore/timer.h"
58#include "MagickCore/string_.h"
59#include "MagickCore/string-private.h"
60#include "MagickCore/thread_.h"
61#include "MagickCore/thread-private.h"
62#include "MagickCore/timer-private.h"
63#include "MagickCore/token.h"
64#include "MagickCore/utility.h"
65#include "MagickCore/utility-private.h"
66#include "MagickCore/version.h"
67#include "MagickCore/xml-tree.h"
68#include "MagickCore/xml-tree-private.h"
69
70/*
71 Define declarations.
72*/
73#define LogFilename "log.xml"
74
75/*
76 Typedef declarations.
77*/
78typedef enum
79{
80 UndefinedHandler = 0x0000,
81 NoHandler = 0x0000,
82 ConsoleHandler = 0x0001,
83 StdoutHandler = 0x0002,
84 StderrHandler = 0x0004,
85 FileHandler = 0x0008,
86 DebugHandler = 0x0010,
87 EventHandler = 0x0020,
88 MethodHandler = 0x0040
89} LogHandlerType;
90
91typedef struct _EventInfo
92{
93 char
94 *name;
95
96 LogEventType
97 event;
98} EventInfo;
99
100typedef struct _HandlerInfo
101{
102 const char
103 name[10];
104
105 LogHandlerType
106 handler;
108
110{
111 LogEventType
112 event_mask;
113
114 LogHandlerType
115 handler_mask;
116
117 char
118 *path,
119 *name,
120 *filename,
121 *format;
122
123 size_t
124 generations,
125 limit;
126
127 FILE
128 *file;
129
130 size_t
131 generation;
132
133 MagickBooleanType
134 append,
135 stealth;
136
138 timer;
139
140 MagickLogMethod
141 method;
142
144 *event_semaphore;
145
146 size_t
147 signature;
148};
149
150typedef struct _LogMapInfo
151{
152 const LogEventType
153 event_mask;
154
155 const LogHandlerType
156 handler_mask;
157
158 const char
159 *filename,
160 *format;
161} LogMapInfo;
162
163/*
164 Static declarations.
165*/
166static const HandlerInfo
167 LogHandlers[32] =
168 {
169 { "Console", ConsoleHandler },
170 { "Debug", DebugHandler },
171 { "Event", EventHandler },
172 { "File", FileHandler },
173 { "None", NoHandler },
174 { "Stderr", StderrHandler },
175 { "Stdout", StdoutHandler },
176 { "", UndefinedHandler },
177 { "", UndefinedHandler },
178 { "", UndefinedHandler },
179 { "", UndefinedHandler },
180 { "", UndefinedHandler },
181 { "", UndefinedHandler },
182 { "", UndefinedHandler },
183 { "", UndefinedHandler },
184 { "", UndefinedHandler },
185 { "", UndefinedHandler },
186 { "", UndefinedHandler },
187 { "", UndefinedHandler },
188 { "", UndefinedHandler },
189 { "", UndefinedHandler },
190 { "", UndefinedHandler },
191 { "", UndefinedHandler },
192 { "", UndefinedHandler },
193 { "", UndefinedHandler },
194 { "", UndefinedHandler },
195 { "", UndefinedHandler },
196 { "", UndefinedHandler },
197 { "", UndefinedHandler },
198 { "", UndefinedHandler },
199 { "", UndefinedHandler },
200 { "", UndefinedHandler }
201 };
202
203static const LogMapInfo
204 LogMap[] =
205 {
206 { NoEvents, ConsoleHandler, "Magick-%g.log",
207 "%t %r %u %v %d %c[%p]: %m/%f/%l/%d\\n %e" }
208 };
209
210static char
211 log_name[MagickPathExtent] = "Magick";
212
213static LinkedListInfo
214 *log_cache = (LinkedListInfo *) NULL;
215
216static MagickBooleanType
217 event_logging = MagickFalse;
218
219static SemaphoreInfo
220 *log_semaphore = (SemaphoreInfo *) NULL;
221
222/*
223 Forward declarations.
224*/
225#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
226static LogHandlerType
227 ParseLogHandlers(const char *) magick_attribute((__pure__));
228#endif
229
230static LogInfo
231 *GetLogInfo(const char *,ExceptionInfo *);
232
233static MagickBooleanType
234 IsLogCacheInstantiated(ExceptionInfo *) magick_attribute((__pure__));
235
236#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
237static MagickBooleanType
238 LoadLogCache(LinkedListInfo *,const char *,const char *,const size_t,
239 ExceptionInfo *);
240#endif
241
242/*
243%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
244% %
245% %
246% %
247% A c q u i r e L o g C a c h e %
248% %
249% %
250% %
251%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
252%
253% AcquireLogCache() caches one or more log configurations which provides a
254% mapping between log attributes and log name.
255%
256% The format of the AcquireLogCache method is:
257%
258% LinkedListInfo *AcquireLogCache(const char *filename,
259% ExceptionInfo *exception)
260%
261% A description of each parameter follows:
262%
263% o filename: the log configuration filename.
264%
265% o exception: return any errors or warnings in this structure.
266%
267*/
268static LinkedListInfo *AcquireLogCache(const char *filename,
269 ExceptionInfo *exception)
270{
272 *cache;
273
274 MagickStatusType
275 status;
276
277 ssize_t
278 i;
279
280 /*
281 Load external log map.
282 */
283 cache=NewLinkedList(0);
284 status=MagickTrue;
285#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
286 {
287 const StringInfo
288 *option;
289
291 *options;
292
293 options=GetConfigureOptions(filename,exception);
294 option=(const StringInfo *) GetNextValueInLinkedList(options);
295 while (option != (const StringInfo *) NULL)
296 {
297 status&=(MagickStatusType) LoadLogCache(cache,(const char *)
298 GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
299 option=(const StringInfo *) GetNextValueInLinkedList(options);
300 }
301 options=DestroyConfigureOptions(options);
302 }
303#else
304 magick_unreferenced(filename);
305#endif
306 /*
307 Load built-in log map.
308 */
309 for (i=0; i < (ssize_t) (sizeof(LogMap)/sizeof(*LogMap)); i++)
310 {
311 LogInfo
312 *log_info;
313
314 const LogMapInfo
315 *p;
316
317 p=LogMap+i;
318 log_info=(LogInfo *) AcquireMagickMemory(sizeof(*log_info));
319 if (log_info == (LogInfo *) NULL)
320 {
321 (void) ThrowMagickException(exception,GetMagickModule(),
322 ResourceLimitError,"MemoryAllocationFailed","`%s'",p->filename);
323 continue;
324 }
325 (void) memset(log_info,0,sizeof(*log_info));
326 log_info->path=ConstantString("[built-in]");
327 GetTimerInfo((TimerInfo *) &log_info->timer);
328 log_info->event_mask=p->event_mask;
329 log_info->handler_mask=p->handler_mask;
330 log_info->filename=ConstantString(p->filename);
331 log_info->format=ConstantString(p->format);
332 log_info->signature=MagickCoreSignature;
333 status&=(MagickStatusType) AppendValueToLinkedList(cache,log_info);
334 if (status == MagickFalse)
335 (void) ThrowMagickException(exception,GetMagickModule(),
336 ResourceLimitError,"MemoryAllocationFailed","`%s'",log_info->name);
337 }
338 return(cache);
339}
340
341/*
342%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
343% %
344% %
345% %
346% C l o s e M a g i c k L o g %
347% %
348% %
349% %
350%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
351%
352% CloseMagickLog() closes the Magick log.
353%
354% The format of the CloseMagickLog method is:
355%
356% CloseMagickLog(void)
357%
358*/
359MagickExport void CloseMagickLog(void)
360{
362 *exception;
363
364 LogInfo
365 *log_info;
366
367 if (IsEventLogging() == MagickFalse)
368 return;
369 exception=AcquireExceptionInfo();
370 log_info=GetLogInfo("*",exception);
371 exception=DestroyExceptionInfo(exception);
372 LockSemaphoreInfo(log_semaphore);
373 if (log_info->file != (FILE *) NULL)
374 {
375 (void) FormatLocaleFile(log_info->file,"</log>\n");
376 (void) fclose(log_info->file);
377 log_info->file=(FILE *) NULL;
378 }
379 UnlockSemaphoreInfo(log_semaphore);
380}
381
382/*
383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
384% %
385% %
386% %
387% G e t L o g E v e n t M a s k %
388% %
389% %
390% %
391%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
392%
393% GetLogEventMask() returns the current log event mask.
394%
395% The format of the GetLogEventMask method is:
396%
397% LogEventType GetLogEventMask(void)
398%
399*/
400MagickExport LogEventType GetLogEventMask(void)
401{
403 *exception;
404
405 LogInfo
406 *log_info;
407
408 exception=AcquireExceptionInfo();
409 log_info=GetLogInfo("*",exception);
410 exception=DestroyExceptionInfo(exception);
411 if (log_info == (const LogInfo *) NULL)
412 return(NoEvents);
413 return(log_info->event_mask);
414}
415
416/*
417%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
418% %
419% %
420% %
421+ G e t L o g I n f o %
422% %
423% %
424% %
425%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
426%
427% GetLogInfo() searches the log list for the specified name and if found
428% returns attributes for that log.
429%
430% The format of the GetLogInfo method is:
431%
432% LogInfo *GetLogInfo(const char *name,ExceptionInfo *exception)
433%
434% A description of each parameter follows:
435%
436% o name: the log name.
437%
438% o exception: return any errors or warnings in this structure.
439%
440*/
441static LogInfo *GetLogInfo(const char *name,ExceptionInfo *exception)
442{
443 LogInfo
444 *log_info;
445
447 *p;
448
449 assert(exception != (ExceptionInfo *) NULL);
450 if (IsLogCacheInstantiated(exception) == MagickFalse)
451 return((LogInfo *) NULL);
452 /*
453 Search for log tag.
454 */
455 log_info=(LogInfo *) NULL;
456 LockSemaphoreInfo(log_semaphore);
457 p=GetHeadElementInLinkedList(log_cache);
458 if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
459 {
460 if (p != (ElementInfo *) NULL)
461 log_info=(LogInfo *) p->value;
462 UnlockSemaphoreInfo(log_semaphore);
463 return(log_info);
464 }
465 while (p != (ElementInfo *) NULL)
466 {
467 log_info=(LogInfo* ) p->value;
468 if (LocaleCompare(name,log_info->name) == 0)
469 break;
470 p=p->next;
471 }
472 if (p == (ElementInfo *) NULL)
473 log_info=(LogInfo *) NULL;
474 else
475 SetHeadElementInLinkedList(log_cache,p);
476 UnlockSemaphoreInfo(log_semaphore);
477 return(log_info);
478}
479
480/*
481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
482% %
483% %
484% %
485% G e t L o g I n f o L i s t %
486% %
487% %
488% %
489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
490%
491% GetLogInfoList() returns any logs that match the specified pattern.
492%
493% The format of the GetLogInfoList function is:
494%
495% const LogInfo **GetLogInfoList(const char *pattern,
496% size_t *number_preferences,ExceptionInfo *exception)
497%
498% A description of each parameter follows:
499%
500% o pattern: Specifies a pointer to a text string containing a pattern.
501%
502% o number_preferences: This integer returns the number of logs in the list.
503%
504% o exception: return any errors or warnings in this structure.
505%
506*/
507#if defined(__cplusplus) || defined(c_plusplus)
508extern "C" {
509#endif
510
511static int LogInfoCompare(const void *x,const void *y)
512{
513 const LogInfo
514 **p,
515 **q;
516
517 p=(const LogInfo **) x,
518 q=(const LogInfo **) y;
519 if (LocaleCompare((*p)->path,(*q)->path) == 0)
520 return(LocaleCompare((*p)->name,(*q)->name));
521 return(LocaleCompare((*p)->path,(*q)->path));
522}
523
524#if defined(__cplusplus) || defined(c_plusplus)
525}
526#endif
527
528MagickExport const LogInfo **GetLogInfoList(const char *pattern,
529 size_t *number_preferences,ExceptionInfo *exception)
530{
531 const LogInfo
532 **preferences;
533
535 *p;
536
537 ssize_t
538 i;
539
540 assert(pattern != (char *) NULL);
541 assert(number_preferences != (size_t *) NULL);
542 if (IsEventLogging() != MagickFalse)
543 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
544 *number_preferences=0;
545 if (IsLogCacheInstantiated(exception) == MagickFalse)
546 return((const LogInfo **) NULL);
547 preferences=(const LogInfo **) AcquireQuantumMemory((size_t)
548 GetNumberOfElementsInLinkedList(log_cache)+1UL,sizeof(*preferences));
549 if (preferences == (const LogInfo **) NULL)
550 return((const LogInfo **) NULL);
551 LockSemaphoreInfo(log_semaphore);
552 p=GetHeadElementInLinkedList(log_cache);
553 for (i=0; p != (ElementInfo *) NULL; )
554 {
555 const LogInfo
556 *log_info;
557
558 log_info=(const LogInfo *) p->value;
559 if ((log_info->stealth == MagickFalse) &&
560 (GlobExpression(log_info->name,pattern,MagickFalse) != MagickFalse))
561 preferences[i++]=log_info;
562 p=p->next;
563 }
564 UnlockSemaphoreInfo(log_semaphore);
565 if (i == 0)
566 preferences=(const LogInfo **) RelinquishMagickMemory((void*) preferences);
567 else
568 {
569 qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogInfoCompare);
570 preferences[i]=(LogInfo *) NULL;
571 }
572 *number_preferences=(size_t) i;
573 return(preferences);
574}
575
576/*
577%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
578% %
579% %
580% %
581% G e t L o g L i s t %
582% %
583% %
584% %
585%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
586%
587% GetLogList() returns any logs that match the specified pattern.
588%
589% The format of the GetLogList function is:
590%
591% char **GetLogList(const char *pattern,size_t *number_preferences,
592% ExceptionInfo *exception)
593%
594% A description of each parameter follows:
595%
596% o pattern: Specifies a pointer to a text string containing a pattern.
597%
598% o number_preferences: This integer returns the number of logs in the list.
599%
600% o exception: return any errors or warnings in this structure.
601%
602*/
603
604#if defined(__cplusplus) || defined(c_plusplus)
605extern "C" {
606#endif
607
608static int LogCompare(const void *x,const void *y)
609{
610 const char
611 **p,
612 **q;
613
614 p=(const char **) x;
615 q=(const char **) y;
616 return(LocaleCompare(*p,*q));
617}
618
619#if defined(__cplusplus) || defined(c_plusplus)
620}
621#endif
622
623MagickExport char **GetLogList(const char *pattern,size_t *number_preferences,
624 ExceptionInfo *exception)
625{
626 char
627 **preferences;
628
630 *p;
631
632 ssize_t
633 i;
634
635 assert(pattern != (char *) NULL);
636 assert(number_preferences != (size_t *) NULL);
637 if (IsEventLogging() != MagickFalse)
638 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
639 *number_preferences=0;
640 if (IsLogCacheInstantiated(exception) == MagickFalse)
641 return((char **) NULL);
642 preferences=(char **) AcquireQuantumMemory((size_t)
643 GetNumberOfElementsInLinkedList(log_cache)+1UL,sizeof(*preferences));
644 if (preferences == (char **) NULL)
645 return((char **) NULL);
646 LockSemaphoreInfo(log_semaphore);
647 p=GetHeadElementInLinkedList(log_cache);
648 for (i=0; p != (ElementInfo *) NULL; )
649 {
650 const LogInfo
651 *log_info;
652
653 log_info=(const LogInfo *) p->value;
654 if ((log_info->stealth == MagickFalse) &&
655 (GlobExpression(log_info->name,pattern,MagickFalse) != MagickFalse))
656 preferences[i++]=ConstantString(log_info->name);
657 p=p->next;
658 }
659 UnlockSemaphoreInfo(log_semaphore);
660 if (i == 0)
661 preferences=(char **) RelinquishMagickMemory(preferences);
662 else
663 {
664 qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogCompare);
665 preferences[i]=(char *) NULL;
666 }
667 *number_preferences=(size_t) i;
668 return(preferences);
669}
670
671/*
672%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
673% %
674% %
675% %
676% G e t L o g N a m e %
677% %
678% %
679% %
680%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
681%
682% GetLogName() returns the current log name.
683%
684% The format of the GetLogName method is:
685%
686% const char *GetLogName(void)
687%
688*/
689MagickExport const char *GetLogName(void)
690{
691 return(log_name);
692}
693
694/*
695%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
696% %
697% %
698% %
699+ I s L o g C a c h e I n s t a n t i a t e d %
700% %
701% %
702% %
703%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
704%
705% IsLogCacheInstantiated() determines if the log list is instantiated. If
706% not, it instantiates the list and returns it.
707%
708% The format of the IsLogInstantiated method is:
709%
710% MagickBooleanType IsLogCacheInstantiated(ExceptionInfo *exception)
711%
712% A description of each parameter follows.
713%
714% o exception: return any errors or warnings in this structure.
715%
716*/
717
718static inline void CheckEventLogging(void)
719{
720 /*
721 Are we logging events?
722 */
723 if (IsLinkedListEmpty(log_cache) != MagickFalse)
724 event_logging=MagickFalse;
725 else
726 {
728 *p;
729
730 p=GetHeadElementInLinkedList(log_cache);
731 event_logging=(p != (ElementInfo *) NULL) &&
732 (((LogInfo *) p->value)->event_mask != NoEvents) ?
733 MagickTrue: MagickFalse;
734 }
735}
736
737static MagickBooleanType IsLogCacheInstantiated(ExceptionInfo *exception)
738{
739 if (log_cache == (LinkedListInfo *) NULL)
740 {
741 if (log_semaphore == (SemaphoreInfo *) NULL)
742 ActivateSemaphoreInfo(&log_semaphore);
743 LockSemaphoreInfo(log_semaphore);
744 if (log_cache == (LinkedListInfo *) NULL)
745 {
746 log_cache=AcquireLogCache(LogFilename,exception);
747 CheckEventLogging();
748 }
749 UnlockSemaphoreInfo(log_semaphore);
750 }
751 return(log_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
752}
753
754/*
755%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
756% %
757% %
758% %
759% I s E v e n t L o g g i n g %
760% %
761% %
762% %
763%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
764%
765% IsEventLogging() returns MagickTrue if debug of events is enabled otherwise
766% MagickFalse.
767%
768% The format of the IsEventLogging method is:
769%
770% MagickBooleanType IsEventLogging(void)
771%
772*/
773MagickExport MagickBooleanType IsEventLogging(void)
774{
775 return(event_logging);
776}
777
778/*
779%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
780% %
781% %
782% %
783% L i s t L o g I n f o %
784% %
785% %
786% %
787%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
788%
789% ListLogInfo() lists the log info to a file.
790%
791% The format of the ListLogInfo method is:
792%
793% MagickBooleanType ListLogInfo(FILE *file,ExceptionInfo *exception)
794%
795% A description of each parameter follows.
796%
797% o file: An pointer to a FILE.
798%
799% o exception: return any errors or warnings in this structure.
800%
801*/
802MagickExport MagickBooleanType ListLogInfo(FILE *file,ExceptionInfo *exception)
803{
804#define MegabytesToBytes(value) ((MagickSizeType) (value)*1024*1024)
805
806 const char
807 *path;
808
809 const LogInfo
810 **log_info;
811
812 ssize_t
813 i;
814
815 size_t
816 number_aliases;
817
818 ssize_t
819 j;
820
821 if (file == (const FILE *) NULL)
822 file=stdout;
823 log_info=GetLogInfoList("*",&number_aliases,exception);
824 if (log_info == (const LogInfo **) NULL)
825 return(MagickFalse);
826 j=0;
827 path=(const char *) NULL;
828 for (i=0; i < (ssize_t) number_aliases; i++)
829 {
830 if (log_info[i]->stealth != MagickFalse)
831 continue;
832 if ((path == (const char *) NULL) ||
833 (LocaleCompare(path,log_info[i]->path) != 0))
834 {
835 size_t
836 length;
837
838 if (log_info[i]->path != (char *) NULL)
839 (void) FormatLocaleFile(file,"\nPath: %s\n\n",log_info[i]->path);
840 length=0;
841 for (j=0; j < (ssize_t) (8*sizeof(LogHandlerType)); j++)
842 {
843 size_t
844 mask;
845
846 if (*LogHandlers[j].name == '\0')
847 break;
848 mask=1;
849 mask<<=j;
850 if (((size_t) log_info[i]->handler_mask & mask) != 0)
851 {
852 (void) FormatLocaleFile(file,"%s ",LogHandlers[j].name);
853 length+=strlen(LogHandlers[j].name);
854 }
855 }
856 for (j=(ssize_t) length; j <= 12; j++)
857 (void) FormatLocaleFile(file," ");
858 (void) FormatLocaleFile(file," Generations Limit Format\n");
859 (void) FormatLocaleFile(file,"-----------------------------------------"
860 "--------------------------------------\n");
861 }
862 path=log_info[i]->path;
863 if (log_info[i]->filename != (char *) NULL)
864 {
865 (void) FormatLocaleFile(file,"%s",log_info[i]->filename);
866 for (j=(ssize_t) strlen(log_info[i]->filename); j <= 16; j++)
867 (void) FormatLocaleFile(file," ");
868 }
869 (void) FormatLocaleFile(file,"%9g ",(double) log_info[i]->generations);
870 (void) FormatLocaleFile(file,"%8g ",(double) log_info[i]->limit);
871 if (log_info[i]->format != (char *) NULL)
872 (void) FormatLocaleFile(file,"%s",log_info[i]->format);
873 (void) FormatLocaleFile(file,"\n");
874 }
875 (void) fflush(file);
876 log_info=(const LogInfo **) RelinquishMagickMemory((void *) log_info);
877 return(MagickTrue);
878}
879
880#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
881/*
882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
883% %
884% %
885% %
886% L o a d L o g C a c h e %
887% %
888% %
889% %
890%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
891%
892% LoadLogCache() loads the log configurations which provides a
893% mapping between log attributes and log name.
894%
895% The format of the LoadLogCache method is:
896%
897% MagickBooleanType LoadLogCache(LinkedListInfo *cache,const char *xml,
898% const char *filename,const size_t depth,ExceptionInfo *exception)
899%
900% A description of each parameter follows:
901%
902% o xml: The log list in XML format.
903%
904% o filename: The log list filename.
905%
906% o depth: depth of <include /> statements.
907%
908% o exception: return any errors or warnings in this structure.
909%
910*/
911static MagickBooleanType LoadLogCache(LinkedListInfo *cache,const char *xml,
912 const char *filename,const size_t depth,ExceptionInfo *exception)
913{
914 char
915 keyword[MagickPathExtent],
916 *token;
917
918 const char
919 *q;
920
921 LogInfo
922 *log_info = (LogInfo *) NULL;
923
924 MagickStatusType
925 status;
926
927 size_t
928 extent;
929
930 /*
931 Load the log map file.
932 */
933 if (xml == (const char *) NULL)
934 return(MagickFalse);
935 status=MagickTrue;
936 token=AcquireString(xml);
937 extent=strlen(token)+MagickPathExtent;
938 for (q=(const char *) xml; *q != '\0'; )
939 {
940 /*
941 Interpret XML.
942 */
943 (void) GetNextToken(q,&q,extent,token);
944 if (*token == '\0')
945 break;
946 (void) CopyMagickString(keyword,token,MagickPathExtent);
947 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
948 {
949 /*
950 Doctype element.
951 */
952 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
953 (void) GetNextToken(q,&q,extent,token);
954 continue;
955 }
956 if (LocaleNCompare(keyword,"<!--",4) == 0)
957 {
958 /*
959 Comment element.
960 */
961 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
962 (void) GetNextToken(q,&q,extent,token);
963 continue;
964 }
965 if (LocaleCompare(keyword,"<include") == 0)
966 {
967 /*
968 Include element.
969 */
970 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
971 {
972 (void) CopyMagickString(keyword,token,MagickPathExtent);
973 (void) GetNextToken(q,&q,extent,token);
974 if (*token != '=')
975 continue;
976 (void) GetNextToken(q,&q,extent,token);
977 if (LocaleCompare(keyword,"file") == 0)
978 {
979 if (depth > MagickMaxRecursionDepth)
980 (void) ThrowMagickException(exception,GetMagickModule(),
981 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
982 else
983 {
984 char
985 path[MagickPathExtent],
986 *file_xml;
987
988 GetPathComponent(filename,HeadPath,path);
989 if (*path != '\0')
990 (void) ConcatenateMagickString(path,DirectorySeparator,
991 MagickPathExtent);
992 if (*token == *DirectorySeparator)
993 (void) CopyMagickString(path,token,MagickPathExtent);
994 else
995 (void) ConcatenateMagickString(path,token,MagickPathExtent);
996 file_xml=FileToXML(path,~0UL);
997 if (file_xml != (char *) NULL)
998 {
999 status&=(MagickStatusType) LoadLogCache(cache,file_xml,
1000 path,depth+1,exception);
1001 file_xml=DestroyString(file_xml);
1002 }
1003 }
1004 }
1005 }
1006 continue;
1007 }
1008 if (LocaleCompare(keyword,"<logmap>") == 0)
1009 {
1010 /*
1011 Allocate memory for the log list.
1012 */
1013 log_info=(LogInfo *) AcquireCriticalMemory(sizeof(*log_info));
1014 (void) memset(log_info,0,sizeof(*log_info));
1015 log_info->path=ConstantString(filename);
1016 GetTimerInfo((TimerInfo *) &log_info->timer);
1017 log_info->signature=MagickCoreSignature;
1018 continue;
1019 }
1020 if (log_info == (LogInfo *) NULL)
1021 continue;
1022 if (LocaleCompare(keyword,"</logmap>") == 0)
1023 {
1024 status=AppendValueToLinkedList(cache,log_info);
1025 if (status == MagickFalse)
1026 (void) ThrowMagickException(exception,GetMagickModule(),
1027 ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
1028 log_info=(LogInfo *) NULL;
1029 continue;
1030 }
1031 (void) GetNextToken(q,(const char **) NULL,extent,token);
1032 if (*token != '=')
1033 continue;
1034 (void) GetNextToken(q,&q,extent,token);
1035 (void) GetNextToken(q,&q,extent,token);
1036 switch (*keyword)
1037 {
1038 case 'E':
1039 case 'e':
1040 {
1041 if (LocaleCompare((char *) keyword,"events") == 0)
1042 {
1043 log_info->event_mask=(LogEventType) (log_info->event_mask |
1044 ParseCommandOption(MagickLogEventOptions,MagickTrue,token));
1045 break;
1046 }
1047 break;
1048 }
1049 case 'F':
1050 case 'f':
1051 {
1052 if (LocaleCompare((char *) keyword,"filename") == 0)
1053 {
1054 if (log_info->filename != (char *) NULL)
1055 log_info->filename=(char *)
1056 RelinquishMagickMemory(log_info->filename);
1057 log_info->filename=ConstantString(token);
1058 break;
1059 }
1060 if (LocaleCompare((char *) keyword,"format") == 0)
1061 {
1062 if (log_info->format != (char *) NULL)
1063 log_info->format=(char *)
1064 RelinquishMagickMemory(log_info->format);
1065 log_info->format=ConstantString(token);
1066 break;
1067 }
1068 break;
1069 }
1070 case 'G':
1071 case 'g':
1072 {
1073 if (LocaleCompare((char *) keyword,"generations") == 0)
1074 {
1075 if (LocaleCompare(token,"unlimited") == 0)
1076 {
1077 log_info->generations=(~0UL);
1078 break;
1079 }
1080 log_info->generations=StringToUnsignedLong(token);
1081 break;
1082 }
1083 break;
1084 }
1085 case 'L':
1086 case 'l':
1087 {
1088 if (LocaleCompare((char *) keyword,"limit") == 0)
1089 {
1090 if (LocaleCompare(token,"unlimited") == 0)
1091 {
1092 log_info->limit=(~0UL);
1093 break;
1094 }
1095 log_info->limit=StringToUnsignedLong(token);
1096 break;
1097 }
1098 break;
1099 }
1100 case 'O':
1101 case 'o':
1102 {
1103 if (LocaleCompare((char *) keyword,"output") == 0)
1104 {
1105 log_info->handler_mask=(LogHandlerType)
1106 (log_info->handler_mask | ParseLogHandlers(token));
1107 break;
1108 }
1109 break;
1110 }
1111 default:
1112 break;
1113 }
1114 }
1115 token=DestroyString(token);
1116 if (cache == (LinkedListInfo *) NULL)
1117 return(MagickFalse);
1118 return(status != 0 ? MagickTrue : MagickFalse);
1119}
1120#endif
1121
1122/*
1123%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1124% %
1125% %
1126% %
1127+ L o g C o m p o n e n t G e n e s i s %
1128% %
1129% %
1130% %
1131%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1132%
1133% LogComponentGenesis() instantiates the log component.
1134%
1135% The format of the LogComponentGenesis method is:
1136%
1137% MagickBooleanType LogComponentGenesis(void)
1138%
1139*/
1140MagickPrivate MagickBooleanType LogComponentGenesis(void)
1141{
1143 *exception;
1144
1145 if (log_semaphore == (SemaphoreInfo *) NULL)
1146 log_semaphore=AcquireSemaphoreInfo();
1147 exception=AcquireExceptionInfo();
1148 (void) GetLogInfo("*",exception);
1149 exception=DestroyExceptionInfo(exception);
1150 return(MagickTrue);
1151}
1152
1153/*
1154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1155% %
1156% %
1157% %
1158+ L o g C o m p o n e n t T e r m i n u s %
1159% %
1160% %
1161% %
1162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1163%
1164% LogComponentTerminus() destroys the logging component.
1165%
1166% The format of the LogComponentTerminus method is:
1167%
1168% LogComponentTerminus(void)
1169%
1170*/
1171
1172static void *DestroyLogElement(void *log_info)
1173{
1174 LogInfo
1175 *p;
1176
1177 p=(LogInfo *) log_info;
1178 if (p->file != (FILE *) NULL)
1179 {
1180 (void) FormatLocaleFile(p->file,"</log>\n");
1181 (void) fclose(p->file);
1182 p->file=(FILE *) NULL;
1183 }
1184 if (p->format != (char *) NULL)
1185 p->format=DestroyString(p->format);
1186 if (p->path != (char *) NULL)
1187 p->path=DestroyString(p->path);
1188 if (p->filename != (char *) NULL)
1189 p->filename=DestroyString(p->filename);
1190 if (p->event_semaphore != (SemaphoreInfo *) NULL)
1191 RelinquishSemaphoreInfo(&p->event_semaphore);
1192 p=(LogInfo *) RelinquishMagickMemory(p);
1193 return((void *) NULL);
1194}
1195
1196MagickPrivate void LogComponentTerminus(void)
1197{
1198 if (log_semaphore == (SemaphoreInfo *) NULL)
1199 ActivateSemaphoreInfo(&log_semaphore);
1200 LockSemaphoreInfo(log_semaphore);
1201 if (log_cache != (LinkedListInfo *) NULL)
1202 log_cache=DestroyLinkedList(log_cache,DestroyLogElement);
1203 event_logging=MagickFalse;
1204 UnlockSemaphoreInfo(log_semaphore);
1205 RelinquishSemaphoreInfo(&log_semaphore);
1206}
1207
1208/*
1209%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1210% %
1211% %
1212% %
1213% L o g M a g i c k E v e n t %
1214% %
1215% %
1216% %
1217%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1218%
1219% LogMagickEvent() logs an event as determined by the log configuration file.
1220% If an error occurs, MagickFalse is returned otherwise MagickTrue.
1221%
1222% The format of the LogMagickEvent method is:
1223%
1224% MagickBooleanType LogMagickEvent(const LogEventType type,
1225% const char *module,const char *function,const size_t line,
1226% const char *format,...)
1227%
1228% A description of each parameter follows:
1229%
1230% o type: the event type.
1231%
1232% o filename: the source module filename.
1233%
1234% o function: the function name.
1235%
1236% o line: the line number of the source module.
1237%
1238% o format: the output format.
1239%
1240*/
1241
1242static char *TranslateEvent(const char *module,const char *function,
1243 const size_t line,const char *domain,const char *event)
1244{
1245 char
1246 *text;
1247
1248 double
1249 elapsed_time,
1250 user_time;
1251
1253 *exception;
1254
1255 LogInfo
1256 *log_info;
1257
1258 char
1259 *q;
1260
1261 const char
1262 *p;
1263
1264 size_t
1265 extent;
1266
1267 time_t
1268 seconds;
1269
1270 exception=AcquireExceptionInfo();
1271 log_info=GetLogInfo("*",exception);
1272 exception=DestroyExceptionInfo(exception);
1273 seconds=GetMagickTime();
1274 elapsed_time=GetElapsedTime(&log_info->timer);
1275 user_time=GetUserTime(&log_info->timer);
1276 text=AcquireString(event);
1277 if (log_info->format == (char *) NULL)
1278 return(text);
1279 extent=strlen(event)+MagickPathExtent;
1280 if (LocaleCompare(log_info->format,"xml") == 0)
1281 {
1282 char
1283 timestamp[MagickTimeExtent];
1284
1285 /*
1286 Translate event in "XML" format.
1287 */
1288 (void) FormatMagickTime(seconds,sizeof(timestamp),timestamp);
1289 (void) FormatLocaleString(text,extent,
1290 "<entry>\n"
1291 " <timestamp>%s</timestamp>\n"
1292 " <elapsed-time>%lu:%02lu.%06lu</elapsed-time>\n"
1293 " <user-time>%0.3f</user-time>\n"
1294 " <process-id>%.20g</process-id>\n"
1295 " <thread-id>%.20g</thread-id>\n"
1296 " <module>%s</module>\n"
1297 " <function>%s</function>\n"
1298 " <line>%.20g</line>\n"
1299 " <domain>%s</domain>\n"
1300 " <event>%s</event>\n"
1301 "</entry>",timestamp,(unsigned long) (elapsed_time/60.0),
1302 (unsigned long) floor(fmod(elapsed_time,60.0)),(unsigned long)
1303 (1000000.0*(elapsed_time-floor(elapsed_time))+0.5),user_time,
1304 (double) getpid(),(double) GetMagickThreadSignature(),module,function,
1305 (double) line,domain,event);
1306 return(text);
1307 }
1308 /*
1309 Translate event in "human readable" format.
1310 */
1311 q=text;
1312 for (p=log_info->format; *p != '\0'; p++)
1313 {
1314 *q='\0';
1315 if ((size_t) (q-text+MagickPathExtent) >= extent)
1316 {
1317 extent+=MagickPathExtent;
1318 text=(char *) ResizeQuantumMemory(text,extent+MagickPathExtent,
1319 sizeof(*text));
1320 if (text == (char *) NULL)
1321 return((char *) NULL);
1322 q=text+strlen(text);
1323 }
1324 /*
1325 The format of the log is defined by embedding special format characters:
1326
1327 %c client name
1328 %d domain
1329 %e event
1330 %f function
1331 %g generation
1332 %i thread id
1333 %l line
1334 %m module
1335 %n log name
1336 %p process id
1337 %r real CPU time
1338 %t wall clock time
1339 %u user CPU time
1340 %v version
1341 %% percent sign
1342 \n newline
1343 \r carriage return
1344 */
1345 if ((*p == '\\') && (*(p+1) == 'r'))
1346 {
1347 *q++='\r';
1348 p++;
1349 continue;
1350 }
1351 if ((*p == '\\') && (*(p+1) == 'n'))
1352 {
1353 *q++='\n';
1354 p++;
1355 continue;
1356 }
1357 if (*p != '%')
1358 {
1359 *q++=(*p);
1360 continue;
1361 }
1362 p++;
1363 if (*p == '\0')
1364 break;
1365 switch (*p)
1366 {
1367 case 'c':
1368 {
1369 q+=(ptrdiff_t) CopyMagickString(q,GetClientName(),extent);
1370 break;
1371 }
1372 case 'd':
1373 {
1374 q+=(ptrdiff_t) CopyMagickString(q,domain,extent);
1375 break;
1376 }
1377 case 'e':
1378 {
1379 q+=(ptrdiff_t) CopyMagickString(q,event,extent);
1380 break;
1381 }
1382 case 'f':
1383 {
1384 q+=(ptrdiff_t) CopyMagickString(q,function,extent);
1385 break;
1386 }
1387 case 'g':
1388 {
1389 if (log_info->generations == 0)
1390 {
1391 (void) CopyMagickString(q,"0",extent);
1392 q++;
1393 break;
1394 }
1395 q+=(ptrdiff_t) FormatLocaleString(q,extent,"%.20g",(double) (log_info->generation %
1396 log_info->generations));
1397 break;
1398 }
1399 case 'i':
1400 {
1401 q+=(ptrdiff_t) FormatLocaleString(q,extent,"%.20g",(double)
1402 GetMagickThreadSignature());
1403 break;
1404 }
1405 case 'l':
1406 {
1407 q+=(ptrdiff_t) FormatLocaleString(q,extent,"%.20g",(double) line);
1408 break;
1409 }
1410 case 'm':
1411 {
1412 const char
1413 *r;
1414
1415 for (r=module+strlen(module)-1; r > module; r--)
1416 if (*r == *DirectorySeparator)
1417 {
1418 r++;
1419 break;
1420 }
1421 q+=(ptrdiff_t) CopyMagickString(q,r,extent);
1422 break;
1423 }
1424 case 'n':
1425 {
1426 q+=(ptrdiff_t) CopyMagickString(q,GetLogName(),extent);
1427 break;
1428 }
1429 case 'p':
1430 {
1431 q+=(ptrdiff_t) FormatLocaleString(q,extent,"%.20g",(double) getpid());
1432 break;
1433 }
1434 case 'r':
1435 {
1436 q+=(ptrdiff_t) FormatLocaleString(q,extent,"%lu:%02lu.%03lu",(unsigned long)
1437 (elapsed_time/60.0),(unsigned long) floor(fmod(elapsed_time,60.0)),
1438 (unsigned long) (1000.0*(elapsed_time-floor(elapsed_time))+0.5));
1439 break;
1440 }
1441 case 't':
1442 {
1443 q+=(ptrdiff_t) FormatMagickTime(seconds,extent,q);
1444 break;
1445 }
1446 case 'u':
1447 {
1448 q+=(ptrdiff_t) FormatLocaleString(q,extent,"%0.3fu",user_time);
1449 break;
1450 }
1451 case 'v':
1452 {
1453 q+=(ptrdiff_t) CopyMagickString(q,MagickLibVersionText,extent);
1454 break;
1455 }
1456 case '%':
1457 {
1458 *q++=(*p);
1459 break;
1460 }
1461 default:
1462 {
1463 *q++='%';
1464 *q++=(*p);
1465 break;
1466 }
1467 }
1468 }
1469 *q='\0';
1470 return(text);
1471}
1472
1473static char *TranslateFilename(const LogInfo *log_info)
1474{
1475 char
1476 *filename;
1477
1478 char
1479 *q;
1480
1481 const char
1482 *p;
1483
1484 size_t
1485 extent;
1486
1487 /*
1488 Translate event in "human readable" format.
1489 */
1490 assert(log_info != (LogInfo *) NULL);
1491 assert(log_info->filename != (char *) NULL);
1492 filename=AcquireString((char *) NULL);
1493 extent=MagickPathExtent;
1494 q=filename;
1495 for (p=log_info->filename; *p != '\0'; p++)
1496 {
1497 *q='\0';
1498 if ((size_t) (q-filename+MagickPathExtent) >= extent)
1499 {
1500 extent+=MagickPathExtent;
1501 filename=(char *) ResizeQuantumMemory(filename,extent+MagickPathExtent,
1502 sizeof(*filename));
1503 if (filename == (char *) NULL)
1504 return((char *) NULL);
1505 q=filename+strlen(filename);
1506 }
1507 /*
1508 The format of the filename is defined by embedding special format
1509 characters:
1510
1511 %c client name
1512 %n log name
1513 %p process id
1514 %v version
1515 %% percent sign
1516 */
1517 if (*p != '%')
1518 {
1519 *q++=(*p);
1520 continue;
1521 }
1522 p++;
1523 if (*p == '\0')
1524 break;
1525 switch (*p)
1526 {
1527 case '\0':
1528 {
1529 p--;
1530 break;
1531 }
1532 case 'c':
1533 {
1534 q+=(ptrdiff_t) CopyMagickString(q,GetClientName(),extent);
1535 break;
1536 }
1537 case 'g':
1538 {
1539 if (log_info->generations == 0)
1540 {
1541 (void) CopyMagickString(q,"0",extent);
1542 q++;
1543 break;
1544 }
1545 q+=(ptrdiff_t) FormatLocaleString(q,extent,"%.20g",(double) (log_info->generation %
1546 log_info->generations));
1547 break;
1548 }
1549 case 'n':
1550 {
1551 q+=(ptrdiff_t) CopyMagickString(q,GetLogName(),extent);
1552 break;
1553 }
1554 case 'p':
1555 {
1556 q+=(ptrdiff_t) FormatLocaleString(q,extent,"%.20g",(double) getpid());
1557 break;
1558 }
1559 case 'v':
1560 {
1561 q+=(ptrdiff_t) CopyMagickString(q,MagickLibVersionText,extent);
1562 break;
1563 }
1564 case '%':
1565 {
1566 *q++=(*p);
1567 break;
1568 }
1569 default:
1570 {
1571 *q++='%';
1572 *q++=(*p);
1573 break;
1574 }
1575 }
1576 }
1577 *q='\0';
1578 return(filename);
1579}
1580
1581MagickExport MagickBooleanType LogMagickEventList(const LogEventType type,
1582 const char *module,const char *function,const size_t line,const char *format,
1583 va_list operands)
1584{
1585 char
1586 event[MagickPathExtent],
1587 *text;
1588
1589 const char
1590 *domain;
1591
1593 *exception;
1594
1595 int
1596 n;
1597
1598 LogInfo
1599 *log_info;
1600
1601 exception=AcquireExceptionInfo();
1602 log_info=(LogInfo *) GetLogInfo("*",exception);
1603 exception=DestroyExceptionInfo(exception);
1604 if (log_info->event_semaphore == (SemaphoreInfo *) NULL)
1605 ActivateSemaphoreInfo(&log_info->event_semaphore);
1606 LockSemaphoreInfo(log_info->event_semaphore);
1607 if ((log_info->event_mask & type) == 0)
1608 {
1609 UnlockSemaphoreInfo(log_info->event_semaphore);
1610 return(MagickTrue);
1611 }
1612 domain=CommandOptionToMnemonic(MagickLogEventOptions,type);
1613#if defined(MAGICKCORE_HAVE_VSNPRINTF)
1614 n=vsnprintf(event,MagickPathExtent,format,operands);
1615#else
1616 n=vsprintf(event,format,operands);
1617#endif
1618 if (n < 0)
1619 event[MagickPathExtent-1]='\0';
1620 text=TranslateEvent(module,function,line,domain,event);
1621 if (text == (char *) NULL)
1622 {
1623 (void) ContinueTimer((TimerInfo *) &log_info->timer);
1624 UnlockSemaphoreInfo(log_info->event_semaphore);
1625 return(MagickFalse);
1626 }
1627 if ((log_info->handler_mask & ConsoleHandler) != 0)
1628 {
1629 (void) FormatLocaleFile(stderr,"%s\n",text);
1630 (void) fflush(stderr);
1631 }
1632 if ((log_info->handler_mask & DebugHandler) != 0)
1633 {
1634#if defined(MAGICKCORE_WINDOWS_SUPPORT)
1635 OutputDebugString(text);
1636 OutputDebugString("\n");
1637#endif
1638 }
1639 if ((log_info->handler_mask & EventHandler) != 0)
1640 {
1641#if defined(MAGICKCORE_WINDOWS_SUPPORT)
1642 (void) NTReportEvent(text,MagickFalse);
1643#endif
1644 }
1645 if ((log_info->handler_mask & FileHandler) != 0)
1646 {
1647 struct stat
1648 file_info;
1649
1650 file_info.st_size=0;
1651 if (log_info->file != (FILE *) NULL)
1652 (void) fstat(fileno(log_info->file),&file_info);
1653 if (file_info.st_size > (MagickOffsetType) (1024*1024*log_info->limit))
1654 {
1655 (void) FormatLocaleFile(log_info->file,"</log>\n");
1656 (void) fclose(log_info->file);
1657 log_info->file=(FILE *) NULL;
1658 }
1659 if (log_info->file == (FILE *) NULL)
1660 {
1661 char
1662 *filename;
1663
1664 filename=TranslateFilename(log_info);
1665 if (filename == (char *) NULL)
1666 {
1667 (void) ContinueTimer((TimerInfo *) &log_info->timer);
1668 UnlockSemaphoreInfo(log_info->event_semaphore);
1669 return(MagickFalse);
1670 }
1671 log_info->append=IsPathAccessible(filename);
1672 log_info->file=fopen_utf8(filename,"ab");
1673 filename=(char *) RelinquishMagickMemory(filename);
1674 if (log_info->file == (FILE *) NULL)
1675 {
1676 UnlockSemaphoreInfo(log_info->event_semaphore);
1677 return(MagickFalse);
1678 }
1679 log_info->generation++;
1680 if (log_info->append == MagickFalse)
1681 (void) FormatLocaleFile(log_info->file,"<?xml version=\"1.0\" "
1682 "encoding=\"UTF-8\" standalone=\"yes\"?>\n");
1683 (void) FormatLocaleFile(log_info->file,"<log>\n");
1684 }
1685 (void) FormatLocaleFile(log_info->file," <event>%s</event>\n",text);
1686 (void) fflush(log_info->file);
1687 }
1688 if ((log_info->handler_mask & MethodHandler) != 0)
1689 {
1690 if (log_info->method != (MagickLogMethod) NULL)
1691 log_info->method(type,text);
1692 }
1693 if ((log_info->handler_mask & StdoutHandler) != 0)
1694 {
1695 (void) FormatLocaleFile(stdout,"%s\n",text);
1696 (void) fflush(stdout);
1697 }
1698 if ((log_info->handler_mask & StderrHandler) != 0)
1699 {
1700 (void) FormatLocaleFile(stderr,"%s\n",text);
1701 (void) fflush(stderr);
1702 }
1703 text=(char *) RelinquishMagickMemory(text);
1704 (void) ContinueTimer((TimerInfo *) &log_info->timer);
1705 UnlockSemaphoreInfo(log_info->event_semaphore);
1706 return(MagickTrue);
1707}
1708
1709MagickExport MagickBooleanType LogMagickEvent(const LogEventType type,
1710 const char *module,const char *function,const size_t line,
1711 const char *format,...)
1712{
1713 va_list
1714 operands;
1715
1716 MagickBooleanType
1717 status;
1718
1719 if (IsEventLogging() == MagickFalse)
1720 return(MagickFalse);
1721 va_start(operands,format);
1722 status=LogMagickEventList(type,module,function,line,format,operands);
1723 va_end(operands);
1724 return(status);
1725}
1726
1727#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
1728/*
1729%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1730% %
1731% %
1732% %
1733% P a r s e L o g H a n d l e r s %
1734% %
1735% %
1736% %
1737%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1738%
1739% ParseLogHandlers() parses a string defining which handlers takes a log
1740% message and exports them.
1741%
1742% The format of the ParseLogHandlers method is:
1743%
1744% LogHandlerType ParseLogHandlers(const char *handlers)
1745%
1746% A description of each parameter follows:
1747%
1748% o handlers: one or more handlers separated by commas.
1749%
1750*/
1751static LogHandlerType ParseLogHandlers(const char *handlers)
1752{
1753 LogHandlerType
1754 handler_mask;
1755
1756 const char
1757 *p;
1758
1759 ssize_t
1760 i;
1761
1762 size_t
1763 length;
1764
1765 handler_mask=NoHandler;
1766 for (p=handlers; p != (char *) NULL; p=strchr(p,','))
1767 {
1768 while ((*p != '\0') && ((isspace((int) ((unsigned char) *p)) != 0) ||
1769 (*p == ',')))
1770 p++;
1771 for (i=0; *LogHandlers[i].name != '\0'; i++)
1772 {
1773 length=strlen(LogHandlers[i].name);
1774 if (LocaleNCompare(p,LogHandlers[i].name,length) == 0)
1775 {
1776 handler_mask=(LogHandlerType) (handler_mask | LogHandlers[i].handler);
1777 break;
1778 }
1779 }
1780 if (*LogHandlers[i].name == '\0')
1781 return(UndefinedHandler);
1782 }
1783 return(handler_mask);
1784}
1785#endif
1786
1787/*
1788%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1789% %
1790% %
1791% %
1792% S e t L o g E v e n t M a s k %
1793% %
1794% %
1795% %
1796%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1797%
1798% SetLogEventMask() accepts a list that determines which events to log. All
1799% other events are ignored. By default, no debug is enabled. This method
1800% returns the previous log event mask.
1801%
1802% The format of the SetLogEventMask method is:
1803%
1804% LogEventType SetLogEventMask(const char *events)
1805%
1806% A description of each parameter follows:
1807%
1808% o events: log these events.
1809%
1810*/
1811MagickExport LogEventType SetLogEventMask(const char *events)
1812{
1814 *exception;
1815
1816 LogEventType
1817 event_mask;
1818
1819 LogInfo
1820 *log_info;
1821
1822 ssize_t
1823 option;
1824
1825 event_mask=UndefinedEvents;
1826 exception=AcquireExceptionInfo();
1827 log_info=GetLogInfo("*",exception);
1828 exception=DestroyExceptionInfo(exception);
1829 if (log_info == (LogInfo *) NULL)
1830 return(event_mask);
1831 option=ParseCommandOption(MagickLogEventOptions,MagickTrue,events);
1832 LockSemaphoreInfo(log_semaphore);
1833 event_mask=log_info->event_mask;
1834 if (option == -1)
1835 log_info->event_mask=UndefinedEvents;
1836 else
1837 log_info->event_mask=(LogEventType) option;
1838 CheckEventLogging();
1839 UnlockSemaphoreInfo(log_semaphore);
1840 return(event_mask);
1841}
1842
1843/*
1844%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1845% %
1846% %
1847% %
1848% S e t L o g F o r m a t %
1849% %
1850% %
1851% %
1852%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1853%
1854% SetLogFormat() sets the format for the "human readable" log record.
1855%
1856% The format of the LogMagickFormat method is:
1857%
1858% SetLogFormat(const char *format)
1859%
1860% A description of each parameter follows:
1861%
1862% o format: the log record format.
1863%
1864*/
1865MagickExport void SetLogFormat(const char *format)
1866{
1867 LogInfo
1868 *log_info;
1869
1871 *exception;
1872
1873 exception=AcquireExceptionInfo();
1874 log_info=(LogInfo *) GetLogInfo("*",exception);
1875 exception=DestroyExceptionInfo(exception);
1876 if (log_info == (LogInfo *) NULL)
1877 return;
1878 LockSemaphoreInfo(log_semaphore);
1879 if (log_info->format != (char *) NULL)
1880 log_info->format=DestroyString(log_info->format);
1881 log_info->format=ConstantString(format);
1882 UnlockSemaphoreInfo(log_semaphore);
1883}
1884
1885/*
1886%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1887% %
1888% %
1889% %
1890% S e t L o g M e t h o d %
1891% %
1892% %
1893% %
1894%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1895%
1896% SetLogMethod() sets the method that will be called when an event is logged.
1897%
1898% The format of the SetLogMethod method is:
1899%
1900% void SetLogMethod(MagickLogMethod method)
1901%
1902% A description of each parameter follows:
1903%
1904% o method: pointer to a method that will be called when LogMagickEvent is
1905% being called.
1906%
1907*/
1908MagickExport void SetLogMethod(MagickLogMethod method)
1909{
1911 *exception;
1912
1913 LogInfo
1914 *log_info;
1915
1916 exception=AcquireExceptionInfo();
1917 log_info=(LogInfo *) GetLogInfo("*",exception);
1918 exception=DestroyExceptionInfo(exception);
1919 LockSemaphoreInfo(log_semaphore);
1920 log_info=(LogInfo *) GetValueFromLinkedList(log_cache,0);
1921 log_info->handler_mask=(LogHandlerType) (log_info->handler_mask |
1922 MethodHandler);
1923 log_info->method=method;
1924 UnlockSemaphoreInfo(log_semaphore);
1925}
1926
1927/*
1928%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1929% %
1930% %
1931% %
1932% S e t L o g N a m e %
1933% %
1934% %
1935% %
1936%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1937%
1938% SetLogName() sets the log name and returns it.
1939%
1940% The format of the SetLogName method is:
1941%
1942% const char *SetLogName(const char *name)
1943%
1944% A description of each parameter follows:
1945%
1946% o log_name: SetLogName() returns the current client name.
1947%
1948% o name: Specifies the new client name.
1949%
1950*/
1951MagickExport const char *SetLogName(const char *name)
1952{
1953 if ((name != (char *) NULL) && (*name != '\0'))
1954 (void) CopyMagickString(log_name,name,MagickPathExtent);
1955 return(log_name);
1956}