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