MagickCore  7.1.1-43
Convert, Edit, Or Compose Bitmap Images
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 */
78 typedef 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 
91 typedef struct _EventInfo
92 {
93  char
94  *name;
95 
96  LogEventType
97  event;
98 } EventInfo;
99 
100 typedef struct _HandlerInfo
101 {
102  const char
103  name[10];
104 
105  LogHandlerType
106  handler;
107 } HandlerInfo;
108 
109 struct _LogInfo
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 
137  TimerInfo
138  timer;
139 
140  MagickLogMethod
141  method;
142 
144  *event_semaphore;
145 
146  size_t
147  signature;
148 };
149 
150 typedef 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 */
166 static 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 
203 static 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 
210 static char
211  log_name[MagickPathExtent] = "Magick";
212 
213 static LinkedListInfo
214  *log_cache = (LinkedListInfo *) NULL;
215 
216 static MagickBooleanType
217  event_logging = MagickFalse;
218 
219 static SemaphoreInfo
220  *log_semaphore = (SemaphoreInfo *) NULL;
221 
222 /*
223  Forward declarations.
224 */
225 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
226 static LogHandlerType
227  ParseLogHandlers(const char *) magick_attribute((__pure__));
228 #endif
229 
230 static LogInfo
231  *GetLogInfo(const char *,ExceptionInfo *);
232 
233 static MagickBooleanType
234  IsLogCacheInstantiated(ExceptionInfo *) magick_attribute((__pure__));
235 
236 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
237 static 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 */
268 static 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 */
359 MagickExport 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 */
400 MagickExport 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 */
441 static 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)
508 extern "C" {
509 #endif
510 
511 static 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 
528 MagickExport 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)
605 extern "C" {
606 #endif
607 
608 static 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 
623 MagickExport 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 */
689 MagickExport 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 
718 static 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 
737 static 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 */
773 MagickExport 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 */
802 MagickExport 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 */
911 static 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 */
1140 MagickPrivate 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 
1172 static 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 
1196 MagickPrivate 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 
1242 static 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 
1473 static 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 
1581 MagickExport 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 
1709 MagickExport 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 */
1751 static 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 */
1811 MagickExport 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 */
1865 MagickExport 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 */
1908 MagickExport 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 */
1951 MagickExport 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 }
_EventInfo
Definition: log.c:91
SemaphoreInfo
Definition: semaphore.c:60
_LinkedListInfo
Definition: linked-list.c:60
_ElementInfo
Definition: draw.c:132
_HandlerInfo
Definition: log.c:100
_TimerInfo
Definition: timer.h:40
_ExceptionInfo
Definition: exception.h:101
_LogMapInfo
Definition: log.c:150
_LogInfo
Definition: log.c:109
_StringInfo
Definition: string_.h:27