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