MagickCore 7.1.2
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/resource-private.h"
57#include "MagickCore/semaphore.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.h"
63#include "MagickCore/timer-private.h"
64#include "MagickCore/token.h"
65#include "MagickCore/utility.h"
66#include "MagickCore/utility-private.h"
67#include "MagickCore/version.h"
68#include "MagickCore/xml-tree.h"
69#include "MagickCore/xml-tree-private.h"
70
71/*
72 Define declarations.
73*/
74#define LogFilename "log.xml"
75
76/*
77 Typedef declarations.
78*/
79typedef enum
80{
81 UndefinedHandler = 0x0000,
82 NoHandler = 0x0000,
83 ConsoleHandler = 0x0001,
84 StdoutHandler = 0x0002,
85 StderrHandler = 0x0004,
86 FileHandler = 0x0008,
87 DebugHandler = 0x0010,
88 EventHandler = 0x0020,
89 MethodHandler = 0x0040
90} LogHandlerType;
91
92typedef struct _EventInfo
93{
94 char
95 *name;
96
97 LogEventType
98 event;
99} EventInfo;
100
101typedef struct _HandlerInfo
102{
103 const char
104 name[10];
105
106 LogHandlerType
107 handler;
108} HandlerInfo;
109
111{
112 LogEventType
113 event_mask;
114
115 LogHandlerType
116 handler_mask;
117
118 char
119 *path,
120 *name,
121 *filename,
122 *format;
123
124 size_t
125 generations;
126
127 FILE
128 *file;
129
130 MagickBooleanType
131 append,
132 stealth;
133
134 MagickSizeType
135 limit;
136
137 TimerInfo
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{
271 LinkedListInfo
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
290 LinkedListInfo
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{
361 ExceptionInfo
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{
402 ExceptionInfo
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
446 ElementInfo
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
534 ElementInfo
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
629 ElementInfo
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 {
727 ElementInfo
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 char
831 limit[MagickPathExtent];
832
833 if (log_info[i]->stealth != MagickFalse)
834 continue;
835 if ((path == (const char *) NULL) ||
836 (LocaleCompare(path,log_info[i]->path) != 0))
837 {
838 if (log_info[i]->path != (char *) NULL)
839 (void) FormatLocaleFile(file,"\nPath: %s\nHandler: ",
840 log_info[i]->path);
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 (void) FormatLocaleFile(file,"%s ",LogHandlers[j].name);
852 }
853 (void) FormatLocaleFile(file,"\n\n");
854 }
855 (void) FormatLocaleFile(file,
856 "Generations Limit Filename\n");
857 (void) FormatLocaleFile(file,"---------------------------------------------"
858 "----------------------------------\n");
859 (void) FormatLocaleFile(file,"%g ",(double) log_info[i]->generations);
860 (void) CopyMagickString(limit,"unlimited",MagickPathExtent);
861 if (log_info[i]->limit > 0)
862 (void) FormatMagickSize(log_info[i]->limit,MagickTrue,"B",
863 MagickFormatExtent,limit);
864 (void) FormatLocaleFile(file," %9s",limit);
865 if (log_info[i]->filename != (char *) NULL)
866 (void) FormatLocaleFile(file," %s",log_info[i]->filename);
867 (void) FormatLocaleFile(file,"\n");
868 if (log_info[i]->format != (char *) NULL)
869 (void) FormatLocaleFile(file," Format: %s\n",log_info[i]->format);
870 (void) FormatLocaleFile(file,"\n");
871 path=log_info[i]->path;
872 }
873 (void) fflush(file);
874 log_info=(const LogInfo **) RelinquishMagickMemory((void *) log_info);
875 return(MagickTrue);
876}
877
878#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
879/*
880%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
881% %
882% %
883% %
884% L o a d L o g C a c h e %
885% %
886% %
887% %
888%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
889%
890% LoadLogCache() loads the log configurations which provides a
891% mapping between log attributes and log name.
892%
893% The format of the LoadLogCache method is:
894%
895% MagickBooleanType LoadLogCache(LinkedListInfo *cache,const char *xml,
896% const char *filename,const size_t depth,ExceptionInfo *exception)
897%
898% A description of each parameter follows:
899%
900% o xml: The log list in XML format.
901%
902% o filename: The log list filename.
903%
904% o depth: depth of <include /> statements.
905%
906% o exception: return any errors or warnings in this structure.
907%
908*/
909static MagickBooleanType LoadLogCache(LinkedListInfo *cache,const char *xml,
910 const char *filename,const size_t depth,ExceptionInfo *exception)
911{
912 char
913 keyword[MagickPathExtent],
914 *token;
915
916 const char
917 *q;
918
919 LogInfo
920 *log_info = (LogInfo *) NULL;
921
922 MagickStatusType
923 status;
924
925 size_t
926 extent;
927
928 /*
929 Load the log map file.
930 */
931 if (xml == (const char *) NULL)
932 return(MagickFalse);
933 status=MagickTrue;
934 token=AcquireString(xml);
935 extent=strlen(token)+MagickPathExtent;
936 for (q=(const char *) xml; *q != '\0'; )
937 {
938 /*
939 Interpret XML.
940 */
941 (void) GetNextToken(q,&q,extent,token);
942 if (*token == '\0')
943 break;
944 (void) CopyMagickString(keyword,token,MagickPathExtent);
945 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
946 {
947 /*
948 Doctype element.
949 */
950 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
951 (void) GetNextToken(q,&q,extent,token);
952 continue;
953 }
954 if (LocaleNCompare(keyword,"<!--",4) == 0)
955 {
956 /*
957 Comment element.
958 */
959 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
960 (void) GetNextToken(q,&q,extent,token);
961 continue;
962 }
963 if (LocaleCompare(keyword,"<include") == 0)
964 {
965 /*
966 Include element.
967 */
968 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
969 {
970 (void) CopyMagickString(keyword,token,MagickPathExtent);
971 (void) GetNextToken(q,&q,extent,token);
972 if (*token != '=')
973 continue;
974 (void) GetNextToken(q,&q,extent,token);
975 if (LocaleCompare(keyword,"file") == 0)
976 {
977 if (depth > MagickMaxRecursionDepth)
978 (void) ThrowMagickException(exception,GetMagickModule(),
979 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
980 else
981 {
982 char
983 path[MagickPathExtent],
984 *file_xml;
985
986 GetPathComponent(filename,HeadPath,path);
987 if (*path != '\0')
988 (void) ConcatenateMagickString(path,DirectorySeparator,
989 MagickPathExtent);
990 if (*token == *DirectorySeparator)
991 (void) CopyMagickString(path,token,MagickPathExtent);
992 else
993 (void) ConcatenateMagickString(path,token,MagickPathExtent);
994 file_xml=FileToXML(path,~0UL);
995 if (file_xml != (char *) NULL)
996 {
997 status&=(MagickStatusType) LoadLogCache(cache,file_xml,
998 path,depth+1,exception);
999 file_xml=DestroyString(file_xml);
1000 }
1001 }
1002 }
1003 }
1004 continue;
1005 }
1006 if (LocaleCompare(keyword,"<logmap>") == 0)
1007 {
1008 /*
1009 Allocate memory for the log list.
1010 */
1011 log_info=(LogInfo *) AcquireCriticalMemory(sizeof(*log_info));
1012 (void) memset(log_info,0,sizeof(*log_info));
1013 log_info->path=ConstantString(filename);
1014 GetTimerInfo((TimerInfo *) &log_info->timer);
1015 log_info->signature=MagickCoreSignature;
1016 continue;
1017 }
1018 if (log_info == (LogInfo *) NULL)
1019 continue;
1020 if (LocaleCompare(keyword,"</logmap>") == 0)
1021 {
1022 status=AppendValueToLinkedList(cache,log_info);
1023 if (status == MagickFalse)
1024 (void) ThrowMagickException(exception,GetMagickModule(),
1025 ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
1026 log_info=(LogInfo *) NULL;
1027 continue;
1028 }
1029 (void) GetNextToken(q,(const char **) NULL,extent,token);
1030 if (*token != '=')
1031 continue;
1032 (void) GetNextToken(q,&q,extent,token);
1033 (void) GetNextToken(q,&q,extent,token);
1034 switch (*keyword)
1035 {
1036 case 'E':
1037 case 'e':
1038 {
1039 if (LocaleCompare((char *) keyword,"events") == 0)
1040 {
1041 log_info->event_mask=(LogEventType) (log_info->event_mask |
1042 ParseCommandOption(MagickLogEventOptions,MagickTrue,token));
1043 break;
1044 }
1045 break;
1046 }
1047 case 'F':
1048 case 'f':
1049 {
1050 if (LocaleCompare((char *) keyword,"filename") == 0)
1051 {
1052 if (log_info->filename != (char *) NULL)
1053 log_info->filename=(char *)
1054 RelinquishMagickMemory(log_info->filename);
1055 log_info->filename=ConstantString(token);
1056 break;
1057 }
1058 if (LocaleCompare((char *) keyword,"format") == 0)
1059 {
1060 if (log_info->format != (char *) NULL)
1061 log_info->format=(char *)
1062 RelinquishMagickMemory(log_info->format);
1063 log_info->format=ConstantString(token);
1064 break;
1065 }
1066 break;
1067 }
1068 case 'G':
1069 case 'g':
1070 {
1071 if (LocaleCompare((char *) keyword,"generations") == 0)
1072 {
1073 if (LocaleCompare(token,"unlimited") == 0)
1074 {
1075 log_info->generations=(~0UL);
1076 break;
1077 }
1078 log_info->generations=StringToUnsignedLong(token);
1079 break;
1080 }
1081 break;
1082 }
1083 case 'L':
1084 case 'l':
1085 {
1086 if (LocaleCompare((char *) keyword,"limit") == 0)
1087 {
1088 if (LocaleCompare(token,"unlimited") == 0)
1089 {
1090 log_info->limit=(~0UL);
1091 break;
1092 }
1093 log_info->limit=StringToMagickSizeType(token,100.0);
1094 if (log_info->limit < 1024)
1095 log_info->limit=1024*1024*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{
1142 ExceptionInfo
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 void FormatLogFilename(const LogInfo *log_info,const ssize_t generation,
1243 char *filename)
1244{
1245 char
1246 *q;
1247
1248 const char
1249 *p;
1250
1251 /*
1252 Translate event in "human readable" format.
1253 */
1254 assert(log_info != (LogInfo *) NULL);
1255 q=filename;
1256 for (p=log_info->filename; *p != '\0'; p++)
1257 {
1258 /*
1259 The format of the filename is defined by embedding special format
1260 characters:
1261
1262 %c client name
1263 %n log name
1264 %p process id
1265 %v version
1266 %% percent sign
1267 */
1268 if (*p != '%')
1269 {
1270 *q++=(*p);
1271 continue;
1272 }
1273 p++;
1274 if (*p == '\0')
1275 break;
1276 switch (*p)
1277 {
1278 case '\0':
1279 {
1280 p--;
1281 break;
1282 }
1283 case 'c':
1284 {
1285 q+=(ptrdiff_t) CopyMagickString(q,GetClientName(),MagickPathExtent);
1286 break;
1287 }
1288 case 'g':
1289 {
1290 if (log_info->generations == 0)
1291 {
1292 (void) CopyMagickString(q,"0",MagickPathExtent);
1293 q++;
1294 break;
1295 }
1296 q+=(ptrdiff_t) FormatLocaleString(q,MagickPathExtent,"%.20g",(double)
1297 (generation % log_info->generations));
1298 break;
1299 }
1300 case 'n':
1301 {
1302 q+=(ptrdiff_t) CopyMagickString(q,GetLogName(),MagickPathExtent);
1303 break;
1304 }
1305 case 'p':
1306 {
1307 q+=(ptrdiff_t) FormatLocaleString(q,MagickPathExtent,"%.20g",(double)
1308 getpid());
1309 break;
1310 }
1311 case 'v':
1312 {
1313 q+=(ptrdiff_t) CopyMagickString(q,MagickLibVersionText,
1314 MagickPathExtent);
1315 break;
1316 }
1317 case '%':
1318 {
1319 *q++=(*p);
1320 break;
1321 }
1322 default:
1323 {
1324 *q++='%';
1325 *q++=(*p);
1326 break;
1327 }
1328 }
1329 }
1330 *q='\0';
1331}
1332
1333static char *TranslateEvent(const char *module,const char *function,
1334 const size_t line,const char *domain,const char *event)
1335{
1336 char
1337 *text;
1338
1339 double
1340 elapsed_time,
1341 user_time;
1342
1343 ExceptionInfo
1344 *exception;
1345
1346 LogInfo
1347 *log_info;
1348
1349 char
1350 *q;
1351
1352 const char
1353 *p;
1354
1355 size_t
1356 extent;
1357
1358 time_t
1359 seconds;
1360
1361 exception=AcquireExceptionInfo();
1362 log_info=GetLogInfo("*",exception);
1363 exception=DestroyExceptionInfo(exception);
1364 seconds=GetMagickTime();
1365 elapsed_time=GetElapsedTime(&log_info->timer);
1366 user_time=GetUserTime(&log_info->timer);
1367 text=AcquireString(event);
1368 if (log_info->format == (char *) NULL)
1369 return(text);
1370 extent=strlen(event)+MagickPathExtent;
1371 if (LocaleCompare(log_info->format,"xml") == 0)
1372 {
1373 char
1374 timestamp[MagickTimeExtent];
1375
1376 /*
1377 Translate event in "XML" format.
1378 */
1379 (void) FormatMagickTime(seconds,sizeof(timestamp),timestamp);
1380 (void) FormatLocaleString(text,extent,
1381 "<entry>\n"
1382 " <timestamp>%s</timestamp>\n"
1383 " <elapsed-time>%lu:%02lu.%06lu</elapsed-time>\n"
1384 " <user-time>%0.3f</user-time>\n"
1385 " <process-id>%.20g</process-id>\n"
1386 " <thread-id>%.20g</thread-id>\n"
1387 " <module>%s</module>\n"
1388 " <function>%s</function>\n"
1389 " <line>%.20g</line>\n"
1390 " <domain>%s</domain>\n"
1391 " <event>%s</event>\n"
1392 "</entry>",timestamp,(unsigned long) (elapsed_time/60.0),
1393 (unsigned long) floor(fmod(elapsed_time,60.0)),(unsigned long)
1394 (1000000.0*(elapsed_time-floor(elapsed_time))+0.5),user_time,
1395 (double) getpid(),(double) GetMagickThreadSignature(),module,function,
1396 (double) line,domain,event);
1397 return(text);
1398 }
1399 /*
1400 Translate event in "human readable" format.
1401 */
1402 q=text;
1403 for (p=log_info->format; *p != '\0'; p++)
1404 {
1405 *q='\0';
1406 if ((size_t) (q-text+MagickPathExtent) >= extent)
1407 {
1408 extent<<=1;
1409 text=(char *) ResizeQuantumMemory(text,extent,sizeof(*text));
1410 if (text == (char *) NULL)
1411 return((char *) NULL);
1412 q=text+strlen(text);
1413 }
1414 /*
1415 The format of the log is defined by embedding special format characters:
1416
1417 %c client name
1418 %d domain
1419 %e event
1420 %f function
1421 %i thread id
1422 %l line
1423 %m module
1424 %n log name
1425 %p process id
1426 %r real CPU time
1427 %t wall clock time
1428 %u user CPU time
1429 %v version
1430 %% percent sign
1431 \n newline
1432 \r carriage return
1433 */
1434 if ((*p == '\\') && (*(p+1) == 'r'))
1435 {
1436 *q++='\r';
1437 p++;
1438 continue;
1439 }
1440 if ((*p == '\\') && (*(p+1) == 'n'))
1441 {
1442 *q++='\n';
1443 p++;
1444 continue;
1445 }
1446 if (*p != '%')
1447 {
1448 *q++=(*p);
1449 continue;
1450 }
1451 p++;
1452 if (*p == '\0')
1453 break;
1454 switch (*p)
1455 {
1456 case 'c':
1457 {
1458 q+=(ptrdiff_t) CopyMagickString(q,GetClientName(),extent-(q-text));
1459 break;
1460 }
1461 case 'd':
1462 {
1463 q+=(ptrdiff_t) CopyMagickString(q,domain,extent-(q-text));
1464 break;
1465 }
1466 case 'e':
1467 {
1468 q+=(ptrdiff_t) CopyMagickString(q,event,extent-(q-text));
1469 break;
1470 }
1471 case 'f':
1472 {
1473 q+=(ptrdiff_t) CopyMagickString(q,function,extent-(q-text));
1474 break;
1475 }
1476 case 'i':
1477 {
1478 q+=(ptrdiff_t) FormatLocaleString(q,extent-(q-text),"%.20g",(double)
1479 GetMagickThreadSignature());
1480 break;
1481 }
1482 case 'l':
1483 {
1484 q+=(ptrdiff_t) FormatLocaleString(q,extent-(q-text),"%.20g",(double)
1485 line);
1486 break;
1487 }
1488 case 'm':
1489 {
1490 const char
1491 *r;
1492
1493 for (r=module+strlen(module)-1; r > module; r--)
1494 if (*r == *DirectorySeparator)
1495 {
1496 r++;
1497 break;
1498 }
1499 q+=(ptrdiff_t) CopyMagickString(q,r,extent-(q-text));
1500 break;
1501 }
1502 case 'n':
1503 {
1504 q+=(ptrdiff_t) CopyMagickString(q,GetLogName(),extent-(q-text));
1505 break;
1506 }
1507 case 'p':
1508 {
1509 q+=(ptrdiff_t) FormatLocaleString(q,extent-(q-text),"%.20g",(double)
1510 getpid());
1511 break;
1512 }
1513 case 'r':
1514 {
1515 q+=(ptrdiff_t) FormatLocaleString(q,extent-(q-text),"%lu:%02lu.%03lu",
1516 (unsigned long) (elapsed_time/60.0),(unsigned long) floor(fmod(
1517 elapsed_time,60.0)),(unsigned long) (1000.0*(elapsed_time-floor(
1518 elapsed_time))+0.5));
1519 break;
1520 }
1521 case 't':
1522 {
1523 q+=(ptrdiff_t) FormatMagickTime(seconds,extent-(q-text),q);
1524 break;
1525 }
1526 case 'u':
1527 {
1528 q+=(ptrdiff_t) FormatLocaleString(q,extent-(q-text),"%0.3fu",user_time);
1529 break;
1530 }
1531 case 'v':
1532 {
1533 q+=(ptrdiff_t) CopyMagickString(q,MagickLibVersionText,extent-(q-text));
1534 break;
1535 }
1536 case '%':
1537 {
1538 *q++=(*p);
1539 break;
1540 }
1541 default:
1542 {
1543 *q++='%';
1544 *q++=(*p);
1545 break;
1546 }
1547 }
1548 }
1549 *q='\0';
1550 return(text);
1551}
1552
1553MagickExport MagickBooleanType LogMagickEventList(const LogEventType type,
1554 const char *module,const char *function,const size_t line,const char *format,
1555 va_list operands)
1556{
1557 char
1558 event[MagickPathExtent],
1559 *text;
1560
1561 const char
1562 *domain;
1563
1564 ExceptionInfo
1565 *exception;
1566
1567 int
1568 n;
1569
1570 LogInfo
1571 *log_info;
1572
1573 exception=AcquireExceptionInfo();
1574 log_info=(LogInfo *) GetLogInfo("*",exception);
1575 exception=DestroyExceptionInfo(exception);
1576 if (log_info->event_semaphore == (SemaphoreInfo *) NULL)
1577 ActivateSemaphoreInfo(&log_info->event_semaphore);
1578 LockSemaphoreInfo(log_info->event_semaphore);
1579 if ((log_info->event_mask & type) == 0)
1580 {
1581 UnlockSemaphoreInfo(log_info->event_semaphore);
1582 return(MagickTrue);
1583 }
1584 domain=CommandOptionToMnemonic(MagickLogEventOptions,type);
1585#if defined(MAGICKCORE_HAVE_VSNPRINTF)
1586 n=vsnprintf(event,MagickPathExtent,format,operands);
1587#else
1588 n=vsprintf(event,format,operands);
1589#endif
1590 if (n < 0)
1591 event[MagickPathExtent-1]='\0';
1592 text=TranslateEvent(module,function,line,domain,event);
1593 if (text == (char *) NULL)
1594 {
1595 (void) ContinueTimer((TimerInfo *) &log_info->timer);
1596 UnlockSemaphoreInfo(log_info->event_semaphore);
1597 return(MagickFalse);
1598 }
1599 if ((log_info->handler_mask & ConsoleHandler) != 0)
1600 {
1601 (void) FormatLocaleFile(stderr,"%s\n",text);
1602 (void) fflush(stderr);
1603 }
1604 if ((log_info->handler_mask & DebugHandler) != 0)
1605 {
1606#if defined(MAGICKCORE_WINDOWS_SUPPORT)
1607 OutputDebugString(text);
1608 OutputDebugString("\n");
1609#endif
1610 }
1611 if ((log_info->handler_mask & EventHandler) != 0)
1612 {
1613#if defined(MAGICKCORE_WINDOWS_SUPPORT)
1614 (void) NTReportEvent(text,MagickFalse);
1615#endif
1616 }
1617 if ((log_info->handler_mask & FileHandler) != 0)
1618 {
1619 struct stat
1620 file_info;
1621
1622 file_info.st_size=0;
1623 if (log_info->file != (FILE *) NULL)
1624 (void) fstat(fileno(log_info->file),&file_info);
1625 if (file_info.st_size > (MagickOffsetType) log_info->limit)
1626 {
1627 ssize_t
1628 i;
1629
1630 /*
1631 Close log.
1632 */
1633 (void) FormatLocaleFile(log_info->file,"</log>\n");
1634 (void) FormatLocaleFile(log_info->file,"</logEntries>\n");
1635 (void) fclose(log_info->file);
1636 for (i=(ssize_t) log_info->generations-1; i > 0; i--)
1637 {
1638 char
1639 new_filename[MagickPathExtent],
1640 old_filename[MagickPathExtent];
1641
1642 /*
1643 Rotate logs.
1644 */
1645 FormatLogFilename(log_info,i-1,old_filename);
1646 FormatLogFilename(log_info,i,new_filename);
1647 (void) rename_utf8(old_filename,new_filename);
1648 }
1649 log_info->file=(FILE *) NULL;
1650 }
1651 if (log_info->file == (FILE *) NULL)
1652 {
1653 char
1654 log_filename[MagickPathExtent];
1655
1656 FormatLogFilename(log_info,0,log_filename);
1657 log_info->append=IsPathAccessible(log_filename);
1658 log_info->file=fopen_utf8(log_filename,"ab");
1659 if (log_info->file == (FILE *) NULL)
1660 {
1661 UnlockSemaphoreInfo(log_info->event_semaphore);
1662 return(MagickFalse);
1663 }
1664 if (log_info->append == MagickFalse)
1665 {
1666 (void) FormatLocaleFile(log_info->file,"<?xml version=\"1.0\" "
1667 "encoding=\"UTF-8\" standalone=\"yes\"?>\n");
1668 (void) FormatLocaleFile(log_info->file,"<logEntries>\n");
1669 }
1670 (void) FormatLocaleFile(log_info->file,"<log>\n");
1671 }
1672 (void) FormatLocaleFile(log_info->file," <event>%s</event>\n",text);
1673 (void) fflush(log_info->file);
1674 }
1675 if ((log_info->handler_mask & MethodHandler) != 0)
1676 {
1677 if (log_info->method != (MagickLogMethod) NULL)
1678 log_info->method(type,text);
1679 }
1680 if ((log_info->handler_mask & StdoutHandler) != 0)
1681 {
1682 (void) FormatLocaleFile(stdout,"%s\n",text);
1683 (void) fflush(stdout);
1684 }
1685 if ((log_info->handler_mask & StderrHandler) != 0)
1686 {
1687 (void) FormatLocaleFile(stderr,"%s\n",text);
1688 (void) fflush(stderr);
1689 }
1690 text=(char *) RelinquishMagickMemory(text);
1691 (void) ContinueTimer((TimerInfo *) &log_info->timer);
1692 UnlockSemaphoreInfo(log_info->event_semaphore);
1693 return(MagickTrue);
1694}
1695
1696MagickExport MagickBooleanType LogMagickEvent(const LogEventType type,
1697 const char *module,const char *function,const size_t line,
1698 const char *format,...)
1699{
1700 va_list
1701 operands;
1702
1703 MagickBooleanType
1704 status;
1705
1706 if (IsEventLogging() == MagickFalse)
1707 return(MagickFalse);
1708 va_start(operands,format);
1709 status=LogMagickEventList(type,module,function,line,format,operands);
1710 va_end(operands);
1711 return(status);
1712}
1713
1714#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
1715/*
1716%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1717% %
1718% %
1719% %
1720% P a r s e L o g H a n d l e r s %
1721% %
1722% %
1723% %
1724%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1725%
1726% ParseLogHandlers() parses a string defining which handlers takes a log
1727% message and exports them.
1728%
1729% The format of the ParseLogHandlers method is:
1730%
1731% LogHandlerType ParseLogHandlers(const char *handlers)
1732%
1733% A description of each parameter follows:
1734%
1735% o handlers: one or more handlers separated by commas.
1736%
1737*/
1738static LogHandlerType ParseLogHandlers(const char *handlers)
1739{
1740 LogHandlerType
1741 handler_mask;
1742
1743 const char
1744 *p;
1745
1746 ssize_t
1747 i;
1748
1749 size_t
1750 length;
1751
1752 handler_mask=NoHandler;
1753 for (p=handlers; p != (char *) NULL; p=strchr(p,','))
1754 {
1755 while ((*p != '\0') && ((isspace((int) ((unsigned char) *p)) != 0) ||
1756 (*p == ',')))
1757 p++;
1758 for (i=0; *LogHandlers[i].name != '\0'; i++)
1759 {
1760 length=strlen(LogHandlers[i].name);
1761 if (LocaleNCompare(p,LogHandlers[i].name,length) == 0)
1762 {
1763 handler_mask=(LogHandlerType) (handler_mask | LogHandlers[i].handler);
1764 break;
1765 }
1766 }
1767 if (*LogHandlers[i].name == '\0')
1768 return(UndefinedHandler);
1769 }
1770 return(handler_mask);
1771}
1772#endif
1773
1774/*
1775%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1776% %
1777% %
1778% %
1779% S e t L o g E v e n t M a s k %
1780% %
1781% %
1782% %
1783%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1784%
1785% SetLogEventMask() accepts a list that determines which events to log. All
1786% other events are ignored. By default, no debug is enabled. This method
1787% returns the previous log event mask.
1788%
1789% The format of the SetLogEventMask method is:
1790%
1791% LogEventType SetLogEventMask(const char *events)
1792%
1793% A description of each parameter follows:
1794%
1795% o events: log these events.
1796%
1797*/
1798MagickExport LogEventType SetLogEventMask(const char *events)
1799{
1800 ExceptionInfo
1801 *exception;
1802
1803 LogEventType
1804 event_mask;
1805
1806 LogInfo
1807 *log_info;
1808
1809 ssize_t
1810 option;
1811
1812 event_mask=UndefinedEvents;
1813 exception=AcquireExceptionInfo();
1814 log_info=GetLogInfo("*",exception);
1815 exception=DestroyExceptionInfo(exception);
1816 if (log_info == (LogInfo *) NULL)
1817 return(event_mask);
1818 option=ParseCommandOption(MagickLogEventOptions,MagickTrue,events);
1819 LockSemaphoreInfo(log_semaphore);
1820 event_mask=log_info->event_mask;
1821 if (option == -1)
1822 log_info->event_mask=UndefinedEvents;
1823 else
1824 log_info->event_mask=(LogEventType) option;
1825 CheckEventLogging();
1826 UnlockSemaphoreInfo(log_semaphore);
1827 return(event_mask);
1828}
1829
1830/*
1831%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1832% %
1833% %
1834% %
1835% S e t L o g F o r m a t %
1836% %
1837% %
1838% %
1839%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1840%
1841% SetLogFormat() sets the format for the "human readable" log record.
1842%
1843% The format of the LogMagickFormat method is:
1844%
1845% SetLogFormat(const char *format)
1846%
1847% A description of each parameter follows:
1848%
1849% o format: the log record format.
1850%
1851*/
1852MagickExport void SetLogFormat(const char *format)
1853{
1854 LogInfo
1855 *log_info;
1856
1857 ExceptionInfo
1858 *exception;
1859
1860 exception=AcquireExceptionInfo();
1861 log_info=(LogInfo *) GetLogInfo("*",exception);
1862 exception=DestroyExceptionInfo(exception);
1863 if (log_info == (LogInfo *) NULL)
1864 return;
1865 LockSemaphoreInfo(log_semaphore);
1866 if (log_info->format != (char *) NULL)
1867 log_info->format=DestroyString(log_info->format);
1868 log_info->format=ConstantString(format);
1869 UnlockSemaphoreInfo(log_semaphore);
1870}
1871
1872/*
1873%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1874% %
1875% %
1876% %
1877% S e t L o g M e t h o d %
1878% %
1879% %
1880% %
1881%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1882%
1883% SetLogMethod() sets the method that will be called when an event is logged.
1884%
1885% The format of the SetLogMethod method is:
1886%
1887% void SetLogMethod(MagickLogMethod method)
1888%
1889% A description of each parameter follows:
1890%
1891% o method: pointer to a method that will be called when LogMagickEvent is
1892% being called.
1893%
1894*/
1895MagickExport void SetLogMethod(MagickLogMethod method)
1896{
1897 ExceptionInfo
1898 *exception;
1899
1900 LogInfo
1901 *log_info;
1902
1903 exception=AcquireExceptionInfo();
1904 log_info=(LogInfo *) GetLogInfo("*",exception);
1905 exception=DestroyExceptionInfo(exception);
1906 LockSemaphoreInfo(log_semaphore);
1907 log_info=(LogInfo *) GetValueFromLinkedList(log_cache,0);
1908 log_info->handler_mask=(LogHandlerType) (log_info->handler_mask |
1909 MethodHandler);
1910 log_info->method=method;
1911 UnlockSemaphoreInfo(log_semaphore);
1912}
1913
1914/*
1915%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1916% %
1917% %
1918% %
1919% S e t L o g N a m e %
1920% %
1921% %
1922% %
1923%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1924%
1925% SetLogName() sets the log name and returns it.
1926%
1927% The format of the SetLogName method is:
1928%
1929% const char *SetLogName(const char *name)
1930%
1931% A description of each parameter follows:
1932%
1933% o log_name: SetLogName() returns the current client name.
1934%
1935% o name: Specifies the new client name.
1936%
1937*/
1938MagickExport const char *SetLogName(const char *name)
1939{
1940 if ((name != (char *) NULL) && (*name != '\0'))
1941 (void) CopyMagickString(log_name,name,MagickPathExtent);
1942 return(log_name);
1943}