/src/graphicsmagick/magick/log.c
Line | Count | Source |
1 | | /* |
2 | | % Copyright (C) 2003 - 2022 GraphicsMagick Group |
3 | | % Copyright (C) 2002 ImageMagick Studio |
4 | | % |
5 | | % This program is covered by multiple licenses, which are described in |
6 | | % Copyright.txt. You should have received a copy of Copyright.txt with this |
7 | | % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html. |
8 | | % |
9 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
10 | | % % |
11 | | % % |
12 | | % % |
13 | | % L OOO GGGG % |
14 | | % L O O G % |
15 | | % L O O G GG % |
16 | | % L O O G G % |
17 | | % LLLLL OOO GGG % |
18 | | % % |
19 | | % % |
20 | | % Log GraphicsMagick Events % |
21 | | % % |
22 | | % % |
23 | | % Software Design % |
24 | | % John Cristy % |
25 | | % September 2002 % |
26 | | % % |
27 | | % % |
28 | | % % |
29 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
30 | | % |
31 | | % |
32 | | */ |
33 | | |
34 | | /* |
35 | | Include declarations. |
36 | | */ |
37 | | #include "magick/studio.h" |
38 | | #if defined(MSWINDOWS) || defined(__CYGWIN__) |
39 | | # include "magick/nt_feature.h" |
40 | | #endif |
41 | | #include "magick/blob.h" |
42 | | #include "magick/log.h" |
43 | | #include "magick/semaphore.h" |
44 | | #include "magick/utility.h" |
45 | | #include "magick/version.h" |
46 | | |
47 | | /* |
48 | | Define declarations. |
49 | | */ |
50 | 254 | #define MagickLogFilename "log.mgk" |
51 | | |
52 | | /* |
53 | | Run-time Logger Info |
54 | | */ |
55 | | typedef struct _LogInfo |
56 | | { |
57 | | SemaphoreInfo |
58 | | *log_semaphore; |
59 | | |
60 | | FILE |
61 | | *file; |
62 | | |
63 | | TimerInfo |
64 | | timer; |
65 | | |
66 | | unsigned long |
67 | | generations, |
68 | | limit, |
69 | | generation, |
70 | | count; |
71 | | |
72 | | LogEventType |
73 | | events; |
74 | | |
75 | | LogOutputType |
76 | | output_type; |
77 | | |
78 | | LogMethod |
79 | | method; /* Logger callback function */ |
80 | | |
81 | | MagickBool |
82 | | log_configured; |
83 | | |
84 | | char |
85 | | path[256], |
86 | | filename[256], |
87 | | format[200]; |
88 | | |
89 | | time_t |
90 | | last_seconds; |
91 | | |
92 | | struct tm |
93 | | last_tm; |
94 | | |
95 | | } LogInfo; |
96 | | |
97 | | /* |
98 | | Static Logger Defaults |
99 | | */ |
100 | | typedef struct _LogInfoDefaults |
101 | | { |
102 | | unsigned long |
103 | | generations, /* 3 */ |
104 | | limit; /* 2000 */ |
105 | | |
106 | | LogEventType |
107 | | events; /* NoEventsMask */ |
108 | | |
109 | | LogOutputType |
110 | | output_type; /* StderrOutput */ |
111 | | |
112 | | LogMethod |
113 | | method; /* (LogMethod) 0 */ |
114 | | |
115 | | char |
116 | | filename[256], /* "Magick-%d.log" */ |
117 | | format[200]; /* "%t %r %u %p %m/%f/%l/%d:\n %e" */ |
118 | | |
119 | | } LogInfoDefaults; |
120 | | |
121 | | /* |
122 | | This table maps between masks and the various event id's that can occur |
123 | | This following id's are not represented in this table yet, since each of |
124 | | them would require a bit in the bitmask and none of these are actually |
125 | | used in the code at this point. |
126 | | |
127 | | DelegateBase |
128 | | MissingDelegateBase |
129 | | CorruptImageBase |
130 | | FileOpenBase |
131 | | StreamBase |
132 | | ModuleBase |
133 | | ImageBase |
134 | | MonitorBase |
135 | | RegistryBase |
136 | | |
137 | | */ |
138 | | static const struct |
139 | | { |
140 | | const char name[14]; |
141 | | unsigned int name_len; |
142 | | LogEventType mask; |
143 | | int start_type; |
144 | | int end_type; |
145 | | } eventmask_map[] = |
146 | | { |
147 | | #define STATIC_EVMASK(name,mask,start_type,end_type) {name,sizeof(name)-1,mask,start_type,end_type} |
148 | | STATIC_EVMASK( "none", NoEventsMask, 0, 0 ), |
149 | | STATIC_EVMASK( "information", InformationEventMask, EventException, EventException+99 ), |
150 | | STATIC_EVMASK( "warning", WarningEventMask, WarningException, WarningException+99 ), |
151 | | STATIC_EVMASK( "error", ErrorEventMask, ErrorException, ErrorException+99 ), |
152 | | STATIC_EVMASK( "fatalerror", FatalErrorEventMask, FatalErrorException, FatalErrorException+99 ), |
153 | | STATIC_EVMASK( "configure", ConfigureEventMask, ConfigureBase, ConfigureBase ), |
154 | | STATIC_EVMASK( "annotate", AnnotateEventMask, AnnotateBase, AnnotateBase ), |
155 | | STATIC_EVMASK( "render", RenderEventMask, RenderBase, RenderBase ), |
156 | | STATIC_EVMASK( "transform", TransformEventMask, TransformBase, TransformBase ), |
157 | | STATIC_EVMASK( "locale", LocaleEventMask, LocaleBase, LocaleBase ), |
158 | | STATIC_EVMASK( "coder", CoderEventMask, CoderBase, CoderBase ), |
159 | | STATIC_EVMASK( "x11", X11EventMask, X11Base, UserBase ), |
160 | | STATIC_EVMASK( "cache", CacheEventMask, CacheBase, CacheBase ), |
161 | | STATIC_EVMASK( "blob", BlobEventMask, BlobBase, BlobBase ), |
162 | | STATIC_EVMASK( "deprecate", DeprecateEventMask, DeprecateBase, DeprecateBase ), |
163 | | STATIC_EVMASK( "user", UserEventMask, UserBase, UserBase ), |
164 | | STATIC_EVMASK( "resource", ResourceEventMask, ResourceBase, ResourceBase ), |
165 | | STATIC_EVMASK( "temporaryfile", TemporaryFileEventMask, TemporaryFileBase, TemporaryFileBase ), |
166 | | /* this one is actually not used anymore */ |
167 | | STATIC_EVMASK( "exception", ExceptionEventMask, ExceptionBase, ExceptionBase ), |
168 | | STATIC_EVMASK( "option", OptionEventMask, OptionBase, OptionBase ), |
169 | | STATIC_EVMASK( "all", AllEventsMask, 0, 0 ) |
170 | | }; |
171 | | |
172 | | static const struct |
173 | | { |
174 | | const char name[14]; |
175 | | unsigned int name_len; |
176 | | LogOutputType mask; |
177 | | } output_map[] = |
178 | | { |
179 | | #define STATIC_OMAP(name,mask) {name,sizeof(name)-1,mask} |
180 | | STATIC_OMAP( "none", UndefinedOutput ), |
181 | | STATIC_OMAP( "disabled", DisabledOutput ), |
182 | | STATIC_OMAP( "stdout", StdoutOutput ), |
183 | | STATIC_OMAP( "stderr", StderrOutput ), |
184 | | STATIC_OMAP( "xmlfile", XMLFileOutput ), |
185 | | STATIC_OMAP( "txtfile", TXTFileOutput ), |
186 | | STATIC_OMAP( "win32debug", Win32DebugOutput ), |
187 | | STATIC_OMAP( "win32eventlog", Win32EventlogOutput ) |
188 | | }; |
189 | | |
190 | | /* |
191 | | Static declarations. |
192 | | */ |
193 | | static LogInfo |
194 | | *log_info = (LogInfo *) NULL; |
195 | | |
196 | | static LogInfoDefaults log_info_defaults = |
197 | | { |
198 | | 3, /* unsigned long generations */ |
199 | | 2000, /* unsigned long limit */ |
200 | | NoEventsMask, /* LogEventType events */ |
201 | | StderrOutput, /* LogOutputType output_type */ |
202 | | (LogMethod) 0, /* LogMethod */ |
203 | | "Magick-%d.log", /* char filename[256] */ |
204 | | "%t %r %u %p %m/%f/%l/%d:\n %e", /* char format[200] */ |
205 | | }; |
206 | | |
207 | | /* |
208 | | Forward declarations. |
209 | | */ |
210 | | static MagickPassFail |
211 | | ReadLogConfigureFile(const char *,const unsigned int,ExceptionInfo *); |
212 | | |
213 | | static LogEventType |
214 | | ParseEvents(const char *event_string) MAGICK_FUNC_PURE; |
215 | | |
216 | | /* |
217 | | Parse an event specification string and return the equivalent bits. |
218 | | */ |
219 | | static LogEventType ParseEvents(const char *event_string) |
220 | 254 | { |
221 | 254 | const char |
222 | 254 | *p; |
223 | | |
224 | 254 | unsigned int |
225 | 254 | i; |
226 | | |
227 | 254 | LogEventType |
228 | 254 | events=NoEventsMask; |
229 | | |
230 | 508 | for (p=event_string; p != 0; p=strchr(p,',')) |
231 | 254 | { |
232 | 254 | while ((*p != 0) && (isspace((int)(*p)) || *p == ',')) |
233 | 0 | p++; |
234 | | |
235 | 4.82k | for (i=0; i < ArraySize(eventmask_map); i++) |
236 | 4.82k | { |
237 | 4.82k | if (LocaleNCompare(p,eventmask_map[i].name, |
238 | 4.82k | eventmask_map[i].name_len) == 0) |
239 | 254 | { |
240 | 254 | events = (LogEventType) ((unsigned int) events | |
241 | 254 | (unsigned int) eventmask_map[i].mask); |
242 | 254 | break; |
243 | 254 | } |
244 | 4.82k | } |
245 | 254 | } |
246 | | |
247 | 254 | return events; |
248 | 254 | } |
249 | | |
250 | | /* |
251 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
252 | | % % |
253 | | % % |
254 | | % % |
255 | | + D e s t r o y L o g I n f o % |
256 | | % % |
257 | | % % |
258 | | % % |
259 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
260 | | % |
261 | | % Method DestroyLogInfo deallocates memory associated with the log list. |
262 | | % |
263 | | % The format of the DestroyLogInfo method is: |
264 | | % |
265 | | % DestroyLogInfo(void) |
266 | | % |
267 | | % |
268 | | */ |
269 | | void DestroyLogInfo(void) |
270 | 0 | { |
271 | 0 | if (log_info->file != (FILE *) NULL) |
272 | 0 | if ((log_info->file != stdout) && (log_info->file != stderr)) |
273 | 0 | { |
274 | 0 | if (log_info->output_type == XMLFileOutput) |
275 | 0 | (void) fprintf(log_info->file,"</log>\n"); |
276 | 0 | (void) fclose(log_info->file); |
277 | 0 | log_info->file=(FILE *) NULL; |
278 | 0 | } |
279 | 0 | log_info->log_configured=False; |
280 | 0 | DestroySemaphoreInfo(&log_info->log_semaphore); |
281 | 0 | MagickFreeMemory(log_info); |
282 | 0 | } |
283 | | |
284 | | /* |
285 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
286 | | % % |
287 | | % % |
288 | | % % |
289 | | + I n i t i a l i z e L o g I n f o % |
290 | | % % |
291 | | % % |
292 | | % % |
293 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
294 | | % |
295 | | % Method InitializeLogInfo initializes the logging facility. This function |
296 | | % is invoked by InitializeMagick(), which must be invoked before using any |
297 | | % other APIs. A memory-allocation failure in this function results in a |
298 | | % fatal error for the whole program. All of the allocations performed by |
299 | | % this function are released by DestroyLogInfo(). |
300 | | % |
301 | | % Normally this function will search for a "log.mgk" file from which to |
302 | | % obtain logging defaults, and use compiled-in defaults if the "log.mgk" |
303 | | % file is not found. The search for "log.mgk" is skipped if the default |
304 | | % logging method is MethodOutput and a logging call-back has been |
305 | | % registered. |
306 | | % |
307 | | % The format of the InitializeLogInfo method is: |
308 | | % |
309 | | % MagickPassFail InitializeLogInfo(void) |
310 | | % |
311 | | % |
312 | | */ |
313 | | MagickPassFail |
314 | | InitializeLogInfo(void) |
315 | 254 | { |
316 | 254 | const char |
317 | 254 | *p; |
318 | | |
319 | 254 | assert(log_info == (LogInfo *) NULL); |
320 | | |
321 | | /* |
322 | | Initialize LogInfo |
323 | | */ |
324 | 254 | log_info=MagickAllocateClearedMemory(LogInfo *,sizeof(LogInfo)); |
325 | 254 | if (log_info == (LogInfo *) NULL) |
326 | 0 | MagickFatalError3(ResourceLimitFatalError,MemoryAllocationFailed, |
327 | 254 | UnableToAllocateLogInfo); |
328 | | |
329 | | /* |
330 | | Initialize logging semaphore |
331 | | */ |
332 | 254 | log_info->log_semaphore=AllocateSemaphoreInfo(); |
333 | | |
334 | | /* |
335 | | Lock for access (to make Coverity happy) |
336 | | */ |
337 | | #if defined(__COVERITY__) |
338 | | LockSemaphoreInfo(log_info->log_semaphore); |
339 | | #endif /* defined(__COVERITY__) */ |
340 | | |
341 | 254 | log_info->file=(FILE *) NULL; |
342 | 254 | GetTimerInfo(&log_info->timer); |
343 | 254 | log_info->generations=log_info_defaults.generations; |
344 | 254 | log_info->limit=log_info_defaults.limit; |
345 | 254 | log_info->generation=0; |
346 | 254 | log_info->count=0; |
347 | 254 | log_info->events=log_info_defaults.events; |
348 | 254 | log_info->output_type=log_info_defaults.output_type; |
349 | 254 | log_info->method=log_info_defaults.method; |
350 | 254 | log_info->log_configured=MagickFalse; |
351 | 254 | log_info->last_seconds=0; |
352 | | |
353 | 254 | (void) strlcpy(log_info->path,"(default)",sizeof(log_info->path)); |
354 | 254 | (void) strlcpy(log_info->filename,log_info_defaults.filename,sizeof(log_info->filename)); |
355 | 254 | (void) strlcpy(log_info->format,log_info_defaults.format, |
356 | 254 | sizeof(log_info->format)); |
357 | | |
358 | | #if defined(__COVERITY__) |
359 | | UnlockSemaphoreInfo(log_info->log_semaphore); |
360 | | #endif /* defined(__COVERITY__) */ |
361 | | |
362 | | /* |
363 | | Set initial logging flags using the value of MAGICK_DEBUG if it is |
364 | | set in the environment. We do this here so it is possible to |
365 | | debug the loading of the log configuration file. |
366 | | */ |
367 | 254 | if ((p=getenv("MAGICK_DEBUG")) != (const char *) NULL) |
368 | 0 | (void) SetLogEventMask(p); |
369 | | |
370 | | #if UseInstalledMagick |
371 | | /* |
372 | | Try to read the log configuration file if not using call-back |
373 | | method. |
374 | | */ |
375 | | if (!((log_info->output_type & MethodOutput) && |
376 | | (log_info->method != (LogMethod) NULL))) |
377 | | { |
378 | | ExceptionInfo |
379 | | exception; |
380 | | |
381 | | GetExceptionInfo(&exception); |
382 | | (void) ReadLogConfigureFile(MagickLogFilename,0,&exception); |
383 | | DestroyExceptionInfo(&exception); |
384 | | } |
385 | | |
386 | | /* |
387 | | Set override logging flags using the value of MAGICK_DEBUG if it |
388 | | is set in the environment. |
389 | | */ |
390 | | if ((p=getenv("MAGICK_DEBUG")) != (const char *) NULL) |
391 | | (void) SetLogEventMask(p); |
392 | | #endif /* UseInstalledMagick */ |
393 | | |
394 | 254 | return MagickPass; |
395 | 254 | } |
396 | | |
397 | | /* |
398 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
399 | | % % |
400 | | % % |
401 | | % % |
402 | | + I n i t i a l i z e L o g I n f o P o s t % |
403 | | % % |
404 | | % % |
405 | | % % |
406 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
407 | | % |
408 | | % Method InitializeLogInfoPost finishes initialization of the logging |
409 | | % facility after the installation path is known. This function |
410 | | % is invoked by InitializeMagick(), which must be invoked before using any |
411 | | % other APIs. All of the allocations performed by this function are |
412 | | % released by DestroyLogInfo(). |
413 | | % |
414 | | % The format of the InitializeLogInfoPost method is: |
415 | | % |
416 | | % MagickPassFail InitializeLogInfoPost(void) |
417 | | % |
418 | | % |
419 | | */ |
420 | | MagickPassFail |
421 | | InitializeLogInfoPost(void) |
422 | 254 | { |
423 | 254 | const char |
424 | 254 | *p; |
425 | | |
426 | | /* |
427 | | Try to read the log configuration file if not using call-back |
428 | | method. |
429 | | */ |
430 | 254 | if (!log_info->log_configured) |
431 | 254 | { |
432 | 254 | if (!((log_info->output_type & MethodOutput) && |
433 | 0 | (log_info->method != (LogMethod) NULL))) |
434 | 254 | { |
435 | 254 | ExceptionInfo |
436 | 254 | exception; |
437 | | |
438 | 254 | GetExceptionInfo(&exception); |
439 | 254 | (void) ReadLogConfigureFile(MagickLogFilename,0,&exception); |
440 | 254 | DestroyExceptionInfo(&exception); |
441 | 254 | } |
442 | | |
443 | | /* |
444 | | Set override logging flags using the value of MAGICK_DEBUG if it |
445 | | is set in the environment. |
446 | | */ |
447 | 254 | if ((p=getenv("MAGICK_DEBUG")) != (const char *) NULL) |
448 | 0 | (void) SetLogEventMask(p); |
449 | | |
450 | | /* |
451 | | Claim that logging was successfully configured |
452 | | */ |
453 | 254 | log_info->log_configured=MagickTrue; |
454 | 254 | } |
455 | | |
456 | 254 | return MagickPass; |
457 | 254 | } |
458 | | |
459 | | /* |
460 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
461 | | % % |
462 | | % % |
463 | | % % |
464 | | % I s E v e n t L o g g i n g % |
465 | | % % |
466 | | % % |
467 | | % % |
468 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
469 | | % |
470 | | % IsEventLogging() returns MagickTrue if logging of events is enabled, |
471 | | % otherwise MagickFalse. This can be used to enable logging code which |
472 | | % is otherwise not needed. |
473 | | % |
474 | | % The format of the IsEventLogging method is: |
475 | | % |
476 | | % MagickBool IsEventLogging(void) |
477 | | % |
478 | | % |
479 | | */ |
480 | | MagickExport MagickBool IsEventLogging(void) |
481 | 16.9M | { |
482 | 16.9M | return (log_info->events != NoEventsMask); |
483 | 16.9M | } |
484 | | |
485 | | /* |
486 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
487 | | % % |
488 | | % % |
489 | | % % |
490 | | % I s E v e n t L o g g e d % |
491 | | % % |
492 | | % % |
493 | | % % |
494 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
495 | | % |
496 | | % IsEventLogged() returns MagickTrue if logging of events for the specified |
497 | | % exception type is enabled, otherwise MagickFalse. This can be used to |
498 | | % enable logging code which is otherwise not needed. |
499 | | % |
500 | | % The format of the IsEventLogging method is: |
501 | | % |
502 | | % MagickBool IsEventLogged(const ExceptionType type) |
503 | | % |
504 | | % |
505 | | */ |
506 | | MagickExport MagickBool IsEventLogged(const ExceptionType type) |
507 | 1.38G | { |
508 | 1.38G | unsigned int |
509 | 1.38G | i; |
510 | | |
511 | 1.38G | MagickBool |
512 | 1.38G | enabled = MagickFalse; |
513 | | |
514 | | /* Short-circuit for when not logging at all */ |
515 | 1.38G | if (log_info->events == NoEventsMask) |
516 | 6.60k | return MagickFalse; |
517 | | |
518 | 1.38G | if (log_info->events == AllEventsMask) |
519 | 0 | return MagickTrue; |
520 | | |
521 | | /* first translate the base type of the event to a mask */ |
522 | 30.2G | for (i=0; i < ArraySize(eventmask_map); i++) |
523 | 28.9G | { |
524 | | /* if the range in the table is above 100 it represents raw |
525 | | event id's. These entry types are to look for specific |
526 | | severity codes. |
527 | | */ |
528 | 28.9G | if (eventmask_map[i].start_type > 99) |
529 | 5.53G | { |
530 | 5.53G | if (((int) type >= eventmask_map[i].start_type) && |
531 | 1.41G | ((int) type <= eventmask_map[i].end_type)) |
532 | 1.38G | { |
533 | 1.38G | if (((unsigned int) log_info->events) & |
534 | 1.38G | ((unsigned int) eventmask_map[i].mask)) |
535 | 12.9M | { |
536 | 12.9M | enabled=MagickTrue; |
537 | 12.9M | break; |
538 | 12.9M | } |
539 | 1.38G | } |
540 | 5.53G | } |
541 | 23.3G | else |
542 | 23.3G | { |
543 | | /* these ranges are for id's with the severity stripped |
544 | | off and represent a category instead. |
545 | | */ |
546 | 23.3G | if ((((int) type % 100) >= eventmask_map[i].start_type) && |
547 | 6.64G | (((int) type % 100) <= eventmask_map[i].end_type)) |
548 | 1.37G | { |
549 | 1.37G | if (((unsigned int) log_info->events) & |
550 | 1.37G | ((unsigned int) eventmask_map[i].mask)) |
551 | 0 | { |
552 | 0 | enabled=MagickTrue; |
553 | 0 | break; |
554 | 0 | } |
555 | 1.37G | } |
556 | 23.3G | } |
557 | 28.9G | } |
558 | | |
559 | 1.38G | return enabled; |
560 | 1.38G | } |
561 | | |
562 | | /* |
563 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
564 | | % % |
565 | | % % |
566 | | % % |
567 | | % L o g M a g i c k E v e n t % |
568 | | % % |
569 | | % % |
570 | | % % |
571 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
572 | | % |
573 | | % LogMagickEvent() logs an event as determined by the current logging |
574 | | % configuration. If an error occurs, MagickFail is returned otherwise |
575 | | % MagickPass. |
576 | | % |
577 | | % The format of the LogMagickEvent method is: |
578 | | % |
579 | | % MagickPassFail LogMagickEvent(const LogEventType type,const char *module, |
580 | | % const char *function,const unsigned long line,const char *format,...) |
581 | | % |
582 | | % A description of each parameter follows: |
583 | | % |
584 | | % o type: The event type. |
585 | | % |
586 | | % o filename: The source module filename. |
587 | | % |
588 | | % o function: The function name. |
589 | | % |
590 | | % o line: The line number of the source module. |
591 | | % |
592 | | % o format: The output format. |
593 | | % |
594 | | % |
595 | | */ |
596 | | MagickExport MagickPassFail |
597 | | LogMagickEventList(const ExceptionType type, |
598 | | const char *module,const char *function, |
599 | | const unsigned long line, |
600 | | const char *format,va_list operands) |
601 | 221M | { |
602 | 221M | const char |
603 | 221M | *domain, |
604 | 221M | *modulebase, |
605 | 221M | *severity; |
606 | | |
607 | 221M | register const char |
608 | 221M | *p; |
609 | | |
610 | 221M | size_t |
611 | 221M | message_len=0; |
612 | | |
613 | 221M | char |
614 | 221M | message[MaxTextExtent], |
615 | 221M | event[MaxTextExtent], |
616 | 221M | timestamp[16]; |
617 | | |
618 | | #if defined(MSWINDOWS) |
619 | | char |
620 | | nteventtype; |
621 | | #endif |
622 | | |
623 | 221M | double |
624 | 221M | elapsed_time, |
625 | 221M | user_time; |
626 | | |
627 | 221M | struct tm |
628 | 221M | *time_meridian; |
629 | | |
630 | 221M | time_t |
631 | 221M | seconds; |
632 | | |
633 | 221M | if (!IsEventLogged(type)) |
634 | 208M | return MagickFalse; |
635 | | |
636 | 12.9M | event[0]='\0'; |
637 | 12.9M | message[0]='\0'; |
638 | 12.9M | timestamp[0]='\0'; |
639 | | |
640 | | /* fixup module info to just include the filename - and not the |
641 | | whole path to the file. This makes the log huge for no good |
642 | | reason */ |
643 | 96.9M | for (modulebase=module+strlen(module)-1; modulebase > module; modulebase--) |
644 | 96.9M | if (IsBasenameSeparator(*modulebase)) |
645 | 12.9M | { |
646 | 12.9M | modulebase++; |
647 | 12.9M | break; |
648 | 12.9M | } |
649 | | |
650 | 12.9M | switch (((unsigned int) type) % 100) |
651 | 12.9M | { |
652 | 0 | case UndefinedException: domain="Undefined"; break; |
653 | 0 | case ExceptionBase: domain="Exception"; break; |
654 | 1.57M | case ResourceBase: domain="Resource"; break; |
655 | | /* case ResourceLimitBase: domain="ResourceLimit"; break; */ |
656 | 25.0k | case TypeBase: domain="Type"; break; |
657 | | /* case AnnotateBase: domain="Annotate"; break; */ |
658 | 31.1k | case OptionBase: domain="Option"; break; |
659 | 64.4k | case DelegateBase: domain="Delegate"; break; |
660 | 458 | case MissingDelegateBase: domain="MissingDelegate"; break; |
661 | 7.56M | case CorruptImageBase: domain="CorruptImage"; break; |
662 | 461k | case FileOpenBase: domain="FileOpen"; break; |
663 | 15.0k | case BlobBase: domain="Blob"; break; |
664 | 0 | case StreamBase: domain="Stream"; break; |
665 | 9.76k | case CacheBase: domain="Cache"; break; |
666 | 3.16M | case CoderBase: domain="Coder"; break; |
667 | 0 | case ModuleBase: domain="Module"; break; |
668 | 36.6k | case DrawBase: domain="Draw"; break; |
669 | | /* case RenderBase: domain="Render"; break; */ |
670 | 5 | case ImageBase: domain="image"; break; |
671 | 0 | case TemporaryFileBase: domain="TemporaryFile"; break; |
672 | 0 | case TransformBase: domain="Transform"; break; |
673 | 0 | case XServerBase: domain="XServer"; break; |
674 | 0 | case X11Base: domain="X11"; break; |
675 | 0 | case UserBase: domain="User"; break; |
676 | 0 | case MonitorBase: domain="Monitor"; break; |
677 | 0 | case LocaleBase: domain="Locale"; break; |
678 | 0 | case DeprecateBase: domain="Deprecate"; break; |
679 | 0 | case RegistryBase: domain="Registry"; break; |
680 | 48 | case ConfigureBase: domain="Configure"; break; |
681 | 0 | default: domain="UnknownEvent"; break; |
682 | 12.9M | } |
683 | 12.9M | switch ((((unsigned int) type) / 100) * 100) |
684 | 12.9M | { |
685 | 0 | case EventException: severity="Event"; break; |
686 | 2.97M | case WarningException: severity="Warning"; break; |
687 | 9.98M | case ErrorException: severity="Error"; break; |
688 | 0 | case FatalErrorException: severity="FatalError"; break; |
689 | 0 | default: severity="Unknown"; break; |
690 | 12.9M | } |
691 | | #if defined(MSWINDOWS) |
692 | | switch ((type / 100) * 100) |
693 | | { |
694 | | case EventException: nteventtype=EVENTLOG_INFORMATION_TYPE; break; |
695 | | case WarningException: nteventtype=EVENTLOG_WARNING_TYPE; break; |
696 | | case ErrorException: nteventtype=EVENTLOG_ERROR_TYPE; break; |
697 | | case FatalErrorException: nteventtype=EVENTLOG_ERROR_TYPE; break; |
698 | | default: nteventtype=EVENTLOG_INFORMATION_TYPE; break; |
699 | | } |
700 | | #endif |
701 | 12.9M | MagickFormatStringList(event,sizeof(event),format,operands); |
702 | 12.9M | LockSemaphoreInfo(log_info->log_semaphore); |
703 | 12.9M | seconds=time((time_t *) NULL); |
704 | 12.9M | if (seconds == log_info->last_seconds) |
705 | 12.9M | { |
706 | 12.9M | time_meridian=&log_info->last_tm; |
707 | 12.9M | } |
708 | 4.13k | else |
709 | 4.13k | { |
710 | 4.13k | log_info->last_seconds=seconds; |
711 | 4.13k | #if defined(HAVE_LOCALTIME_R) |
712 | 4.13k | time_meridian=localtime_r(&seconds, &log_info->last_tm); |
713 | | #else |
714 | | time_meridian=localtime(&seconds); /* Possibly thread-unsafe version */ |
715 | | (void) memcpy(&log_info->last_tm,time_meridian,sizeof(log_info->last_tm)); |
716 | | #endif /* if defined(HAVE_LOCALTIME_R) */ |
717 | 4.13k | } |
718 | 12.9M | elapsed_time=GetElapsedTime(&log_info->timer); |
719 | 12.9M | user_time=GetUserTime(&log_info->timer); |
720 | 12.9M | (void) ContinueTimer((TimerInfo *) &log_info->timer); |
721 | 12.9M | (void) MagickFormatString(timestamp,sizeof(timestamp),"%04d%02d%02d%02d%02d%02d",time_meridian->tm_year+ |
722 | 12.9M | 1900,time_meridian->tm_mon+1,time_meridian->tm_mday, |
723 | 12.9M | time_meridian->tm_hour,time_meridian->tm_min,time_meridian->tm_sec); |
724 | | |
725 | 12.9M | if (!(((unsigned int) log_info->output_type) & XMLFileOutput)) |
726 | 12.9M | { |
727 | | /* |
728 | | Format message in a "human readable" format. |
729 | | */ |
730 | 272M | for (p=log_info->format; *p != '\0'; p++) |
731 | 259M | { |
732 | | /* |
733 | | Process formatting characters in text. |
734 | | */ |
735 | 259M | if ((*p == '\\') && (*(p+1) == 'r')) |
736 | 0 | { |
737 | 0 | message_len+=MagickFormatString(&message[message_len],sizeof(message)-message_len,"\r"); |
738 | 0 | p++; |
739 | 0 | continue; |
740 | 0 | } |
741 | 259M | if ((*p == '\\') && (*(p+1) == 'n')) |
742 | 0 | { |
743 | 0 | message_len+=MagickFormatString(&message[message_len],sizeof(message)-message_len,"\n"); |
744 | 0 | p++; |
745 | 0 | continue; |
746 | 0 | } |
747 | 259M | if (*p != '%') |
748 | 142M | { |
749 | 142M | message_len+=MagickFormatString(&message[message_len],sizeof(message)-message_len,"%c",*p); |
750 | 142M | continue; |
751 | 142M | } |
752 | 116M | p++; |
753 | 116M | switch (*p) |
754 | 116M | { |
755 | 12.9M | case 'd': |
756 | 12.9M | { |
757 | 12.9M | message_len+=MagickFormatString(&message[message_len],sizeof(message)-message_len,"%.1024s",domain); |
758 | 12.9M | break; |
759 | 0 | } |
760 | 12.9M | case 'e': |
761 | 12.9M | { |
762 | 12.9M | message_len+=MagickFormatString(&message[message_len],sizeof(message)-message_len,"%.1024s",event); |
763 | 12.9M | break; |
764 | 0 | } |
765 | 12.9M | case 'f': |
766 | 12.9M | { |
767 | 12.9M | message_len+=MagickFormatString(&message[message_len],sizeof(message)-message_len,"%.1024s",function); |
768 | 12.9M | break; |
769 | 0 | } |
770 | 12.9M | case 'l': |
771 | 12.9M | { |
772 | 12.9M | message_len+=MagickFormatString(&message[message_len],sizeof(message)-message_len,"%lu",line); |
773 | 12.9M | break; |
774 | 0 | } |
775 | 12.9M | case 'm': |
776 | 12.9M | { |
777 | 12.9M | message_len+=MagickFormatString(&message[message_len],sizeof(message)-message_len,"%.1024s",modulebase); |
778 | 12.9M | break; |
779 | 0 | } |
780 | 12.9M | case 'p': |
781 | 12.9M | { |
782 | 12.9M | message_len+=MagickFormatString(&message[message_len],sizeof(message)-message_len,"%ld",(long) getpid()); |
783 | 12.9M | break; |
784 | 0 | } |
785 | 12.9M | case 'r': |
786 | 12.9M | { |
787 | 12.9M | message_len+=MagickFormatString(&message[message_len],sizeof(message)-message_len,"%ld:%-9.6f",(long) (elapsed_time/60.0), |
788 | 12.9M | fmod(elapsed_time,60.0)); |
789 | 12.9M | break; |
790 | 0 | } |
791 | 0 | case 's': |
792 | 0 | { |
793 | 0 | message_len+=MagickFormatString(&message[message_len],sizeof(message)-message_len,"%.1024s",severity); |
794 | 0 | break; |
795 | 0 | } |
796 | 12.9M | case 't': |
797 | 12.9M | { |
798 | 12.9M | message_len+=MagickFormatString(&message[message_len],sizeof(message)-message_len,"%02d:%02d:%02d",time_meridian->tm_hour, |
799 | 12.9M | time_meridian->tm_min,time_meridian->tm_sec); |
800 | 12.9M | break; |
801 | 0 | } |
802 | 12.9M | case 'u': |
803 | 12.9M | { |
804 | 12.9M | message_len+=MagickFormatString(&message[message_len],sizeof(message)-message_len,"%0.3fu",user_time); |
805 | 12.9M | break; |
806 | 0 | } |
807 | 0 | default: |
808 | 0 | { |
809 | 0 | message_len+=MagickFormatString(&message[message_len],sizeof(message)-message_len,"%%"); |
810 | 0 | message_len+=MagickFormatString(&message[message_len],sizeof(message)-message_len,"%c",*p); |
811 | 0 | break; |
812 | 0 | } |
813 | 116M | } |
814 | 116M | } |
815 | | |
816 | | /* |
817 | | Add a new-line to message for messages which need it. This avoids buffering or I/O later. |
818 | | */ |
819 | 12.9M | if (((unsigned int) log_info->output_type) & |
820 | 12.9M | ((unsigned int) Win32DebugOutput|Win32EventlogOutput|StdoutOutput|StderrOutput)) |
821 | 12.9M | { |
822 | 12.9M | message_len+=MagickFormatString(&message[message_len],sizeof(message)-message_len,"\n"); |
823 | 12.9M | } |
824 | 12.9M | } |
825 | | |
826 | 12.9M | if ((log_info->output_type & MethodOutput) && |
827 | 0 | (log_info->method != (LogMethod) NULL)) |
828 | 0 | { |
829 | 0 | log_info->method(type,message); |
830 | 0 | UnlockSemaphoreInfo(log_info->log_semaphore); |
831 | 0 | return(MagickPass); |
832 | 0 | } |
833 | 12.9M | if (((unsigned int) log_info->output_type) & XMLFileOutput) |
834 | 0 | { |
835 | | /* |
836 | | Log to a file in the XML format. |
837 | | */ |
838 | 0 | log_info->count++; |
839 | 0 | if (log_info->count >= log_info->limit) |
840 | 0 | { |
841 | 0 | (void) fprintf(log_info->file,"</log>\n"); |
842 | 0 | (void) fclose(log_info->file); |
843 | 0 | log_info->file=(FILE *) NULL; |
844 | 0 | log_info->count=0; |
845 | 0 | } |
846 | 0 | if (log_info->file == (FILE *) NULL) |
847 | 0 | { |
848 | 0 | char |
849 | 0 | filename[MaxTextExtent]; |
850 | |
|
851 | 0 | (void) MagickSceneFileName(filename,log_info->filename,".%lu", |
852 | 0 | MagickFalse,log_info->generation); |
853 | 0 | log_info->file=fopen(filename,"w"); |
854 | 0 | if (log_info->file == (FILE *) NULL) |
855 | 0 | { |
856 | 0 | UnlockSemaphoreInfo(log_info->log_semaphore); |
857 | 0 | return(False); |
858 | 0 | } |
859 | 0 | (void) fprintf(log_info->file,"<?xml version=\"1.0\"?>\n"); |
860 | 0 | (void) fprintf(log_info->file,"<log>\n"); |
861 | 0 | log_info->generation++; |
862 | 0 | if (log_info->generation >= log_info->generations) |
863 | 0 | log_info->generation=0; |
864 | 0 | } |
865 | 0 | (void) fprintf(log_info->file,"<record>\n"); |
866 | 0 | (void) fprintf(log_info->file," <timestamp>%.1024s</timestamp>\n", |
867 | 0 | timestamp); |
868 | 0 | (void) fprintf(log_info->file, |
869 | 0 | " <elapsed-time>%ld:%-9.6f</elapsed-time>\n", |
870 | 0 | (long) (elapsed_time/60.0),fmod(elapsed_time,60.0)); |
871 | 0 | (void) fprintf(log_info->file," <user-time>%0.3f</user-time>\n", |
872 | 0 | user_time); |
873 | 0 | (void) fprintf(log_info->file," <pid>%ld</pid>\n",(long) getpid()); |
874 | 0 | (void) fprintf(log_info->file," <module>%.1024s</module>\n",modulebase); |
875 | 0 | (void) fprintf(log_info->file," <function>%.1024s</function>\n", |
876 | 0 | function); |
877 | 0 | (void) fprintf(log_info->file," <line>%lu</line>\n",line); |
878 | 0 | (void) fprintf(log_info->file," <domain>%.1024s</domain>\n",domain); |
879 | 0 | (void) fprintf(log_info->file," <severity>%.1024s</severity>\n",severity); |
880 | 0 | (void) fprintf(log_info->file," <event>%.1024s</event>\n",event); |
881 | 0 | (void) fprintf(log_info->file,"</record>\n"); |
882 | 0 | (void) fflush(log_info->file); |
883 | 0 | UnlockSemaphoreInfo(log_info->log_semaphore); |
884 | 0 | return(MagickPass); |
885 | 0 | } |
886 | 12.9M | if (((unsigned int) log_info->output_type) & TXTFileOutput) |
887 | 0 | { |
888 | | /* |
889 | | Log to a file in the TXT format. |
890 | | */ |
891 | 0 | log_info->count++; |
892 | 0 | if (log_info->count >= log_info->limit) |
893 | 0 | { |
894 | 0 | (void) fclose(log_info->file); |
895 | 0 | log_info->file=(FILE *) NULL; |
896 | 0 | log_info->count=0; |
897 | 0 | } |
898 | 0 | if (log_info->file == (FILE *) NULL) |
899 | 0 | { |
900 | 0 | char |
901 | 0 | filename[MaxTextExtent]; |
902 | |
|
903 | 0 | (void) MagickSceneFileName(filename,log_info->filename,".%lu", |
904 | 0 | MagickFalse,log_info->generation); |
905 | 0 | log_info->file=fopen(filename,"w"); |
906 | 0 | if (log_info->file == (FILE *) NULL) |
907 | 0 | { |
908 | 0 | UnlockSemaphoreInfo(log_info->log_semaphore); |
909 | 0 | return(False); |
910 | 0 | } |
911 | 0 | log_info->generation++; |
912 | 0 | if (log_info->generation >= log_info->generations) |
913 | 0 | log_info->generation=0; |
914 | 0 | } |
915 | 0 | (void) fprintf(log_info->file,"%s",message); |
916 | 0 | (void) fflush(log_info->file); |
917 | 0 | UnlockSemaphoreInfo(log_info->log_semaphore); |
918 | 0 | return(MagickPass); |
919 | 0 | } |
920 | | #if defined(MSWINDOWS) |
921 | | if (log_info->output_type & Win32DebugOutput) |
922 | | { |
923 | | OutputDebugString(message); |
924 | | } |
925 | | if (log_info->output_type & Win32EventlogOutput) |
926 | | { |
927 | | #define LOGGING_ERROR_CODE 0 |
928 | | LPCSTR |
929 | | szList[1]; |
930 | | |
931 | | HANDLE |
932 | | hSource; |
933 | | |
934 | | hSource = RegisterEventSource(NULL, MagickPackageName); |
935 | | if (hSource != NULL) |
936 | | { |
937 | | szList[0]=message; |
938 | | ReportEvent(hSource,nteventtype,0,LOGGING_ERROR_CODE,NULL,1,0,szList,NULL); |
939 | | DeregisterEventSource(hSource); |
940 | | } |
941 | | } |
942 | | #endif |
943 | 12.9M | if ((((unsigned int) log_info->output_type) & StdoutOutput) || |
944 | 12.9M | (((unsigned int) log_info->output_type) & StderrOutput)) |
945 | 12.9M | { |
946 | 12.9M | FILE |
947 | 12.9M | *file; |
948 | | |
949 | | /* |
950 | | Log to stdout/stderr in a "human readable" format. |
951 | | */ |
952 | 12.9M | file = stdout; |
953 | 12.9M | if (((unsigned int) log_info->output_type) & StderrOutput) |
954 | 12.9M | file = stderr; |
955 | 12.9M | (void) fprintf(file,"%s",message); |
956 | 12.9M | (void) fflush(file); |
957 | 12.9M | } |
958 | 12.9M | UnlockSemaphoreInfo(log_info->log_semaphore); |
959 | 12.9M | return(MagickPass); |
960 | 12.9M | } |
961 | | MagickExport MagickPassFail LogMagickEvent(const ExceptionType type, |
962 | | const char *module,const char *function,const unsigned long line, |
963 | | const char *format,...) |
964 | 221M | { |
965 | 221M | unsigned int |
966 | 221M | count; |
967 | | |
968 | 221M | va_list |
969 | 221M | operands; |
970 | | |
971 | 221M | va_start(operands,format); |
972 | 221M | count=LogMagickEventList(type, module, function, line, format, operands); |
973 | 221M | va_end(operands); |
974 | 221M | return (count); |
975 | 221M | } |
976 | | |
977 | | |
978 | | /* |
979 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
980 | | % % |
981 | | % % |
982 | | % % |
983 | | + R e a d L o g C o n f i g u r e F i l e % |
984 | | % % |
985 | | % % |
986 | | % % |
987 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
988 | | % |
989 | | % ReadLogConfigureFile() reads the log configuration file. |
990 | | % |
991 | | % The format of the ReadLogConfigureFile method is: |
992 | | % |
993 | | % MagickPassFail ReadLogConfigureFile(const char *basename, |
994 | | % const unsigned int depth,ExceptionInfo *exception) |
995 | | % |
996 | | % A description of each parameter follows: |
997 | | % |
998 | | % o status: ReadLogConfigureFile() returns MagickPass if at least one log entry |
999 | | % is defined otherwise False. |
1000 | | % |
1001 | | % o basename: The log configuration filename. |
1002 | | % |
1003 | | % o depth: depth of <include /> statements. |
1004 | | % |
1005 | | % o exception: Return any errors or warnings in this structure. |
1006 | | % |
1007 | | % |
1008 | | */ |
1009 | | static MagickPassFail ReadLogConfigureFile(const char *basename, |
1010 | | const unsigned int depth,ExceptionInfo *exception) |
1011 | 254 | { |
1012 | 254 | char |
1013 | 254 | keyword[MaxTextExtent], |
1014 | 254 | path[MaxTextExtent], |
1015 | 254 | token[MaxTextExtent], |
1016 | 254 | *q, |
1017 | 254 | *xml; |
1018 | | |
1019 | 254 | size_t |
1020 | 254 | blob_length=0, |
1021 | 254 | token_length; |
1022 | | |
1023 | 254 | MagickPassFail |
1024 | 254 | status=MagickPass; |
1025 | | |
1026 | | /* |
1027 | | Read the log configure file. |
1028 | | */ |
1029 | 254 | (void) strlcpy(path,basename,sizeof(path)); |
1030 | 254 | if (depth == 0) |
1031 | 254 | { |
1032 | | /* |
1033 | | Load top configuration file based on configure search path. |
1034 | | */ |
1035 | 254 | xml=(char *) GetConfigureBlob(basename,path,&blob_length,exception); |
1036 | 254 | } |
1037 | 0 | else |
1038 | 0 | { |
1039 | | /* |
1040 | | Load subordinate configuration file based on path specified |
1041 | | by parent configuration file. |
1042 | | */ |
1043 | 0 | xml=(char *) FileToBlob(basename,&blob_length,exception); |
1044 | 0 | } |
1045 | 254 | if (xml == (char *) NULL) |
1046 | 254 | return MagickFail; |
1047 | 0 | for (q=xml; *q != '\0'; ) |
1048 | 0 | { |
1049 | | /* |
1050 | | Interpret Coder. |
1051 | | */ |
1052 | 0 | token_length=MagickGetToken(q,&q,token,MaxTextExtent); |
1053 | 0 | if ((token_length == 0) || (*token == '\0')) |
1054 | 0 | break; |
1055 | 0 | (void) strlcpy(keyword,token,MaxTextExtent); |
1056 | 0 | if (LocaleNCompare(keyword,"<!--",4) == 0) |
1057 | 0 | { |
1058 | | /* |
1059 | | Comment element. |
1060 | | */ |
1061 | 0 | while ((token_length) && (LocaleNCompare(q,"->",2) != 0) && (*q != '\0')) |
1062 | 0 | token_length=MagickGetToken(q,&q,token,MaxTextExtent); |
1063 | 0 | continue; |
1064 | 0 | } |
1065 | 0 | if (LocaleCompare(keyword,"<include") == 0) |
1066 | 0 | { |
1067 | | /* |
1068 | | Include element. |
1069 | | */ |
1070 | 0 | while ((token_length) && (*token != '>') && (*q != '\0')) |
1071 | 0 | { |
1072 | 0 | (void) strlcpy(keyword,token,MaxTextExtent); |
1073 | 0 | token_length=MagickGetToken(q,&q,token,MaxTextExtent); |
1074 | 0 | if ((token_length) && (*token != '=')) |
1075 | 0 | continue; |
1076 | 0 | (void) MagickGetToken(q,&q,token,MaxTextExtent); |
1077 | 0 | if (LocaleCompare(keyword,"file") == 0) |
1078 | 0 | { |
1079 | 0 | if (depth > 200) |
1080 | 0 | (void) fprintf(stderr,"%.1024s: <include /> nested too deeply", |
1081 | 0 | path); |
1082 | 0 | else |
1083 | 0 | { |
1084 | 0 | char |
1085 | 0 | filename[MaxTextExtent]; |
1086 | |
|
1087 | 0 | GetPathComponent(path,HeadPath,filename); |
1088 | 0 | if (*filename != '\0') |
1089 | 0 | (void) strlcat(filename,DirectorySeparator,MaxTextExtent); |
1090 | 0 | (void) strlcat(filename,token,MaxTextExtent); |
1091 | 0 | status &= ReadLogConfigureFile(filename,depth+1,exception); |
1092 | 0 | if (status != MagickPass) |
1093 | 0 | { |
1094 | 0 | MagickFreeMemory(xml); |
1095 | 0 | return (status); |
1096 | 0 | } |
1097 | 0 | } |
1098 | 0 | } |
1099 | 0 | } |
1100 | 0 | continue; |
1101 | 0 | } |
1102 | 0 | if (LocaleCompare(keyword,"<magicklog>") == 0) |
1103 | 0 | { |
1104 | 0 | (void) strlcpy(log_info->path,path,sizeof(log_info->path)); |
1105 | 0 | continue; |
1106 | 0 | } |
1107 | 0 | token_length=MagickGetToken(q,(char **) NULL,token,MaxTextExtent); |
1108 | 0 | if ((token_length) && (*token != '=')) |
1109 | 0 | continue; |
1110 | 0 | (void) MagickGetToken(q,&q,token,MaxTextExtent); |
1111 | 0 | (void) MagickGetToken(q,&q,token,MaxTextExtent); |
1112 | 0 | switch (*keyword) |
1113 | 0 | { |
1114 | 0 | case 'E': |
1115 | 0 | case 'e': |
1116 | 0 | { |
1117 | 0 | if (LocaleCompare((char *) keyword,"events") == 0) |
1118 | 0 | log_info->events = (LogEventType) ((unsigned int) log_info->events | |
1119 | 0 | (unsigned int) ParseEvents(token)); |
1120 | 0 | break; |
1121 | 0 | } |
1122 | 0 | case 'F': |
1123 | 0 | case 'f': |
1124 | 0 | { |
1125 | 0 | if (LocaleCompare((char *) keyword,"filename") == 0) |
1126 | 0 | { |
1127 | 0 | (void) strlcpy(log_info->filename,token,sizeof(log_info->filename)); |
1128 | 0 | break; |
1129 | 0 | } |
1130 | 0 | if (LocaleCompare((char *) keyword,"format") == 0) |
1131 | 0 | { |
1132 | 0 | (void) strlcpy(log_info->format,token,sizeof(log_info->format)); |
1133 | 0 | break; |
1134 | 0 | } |
1135 | 0 | break; |
1136 | 0 | } |
1137 | 0 | case 'G': |
1138 | 0 | case 'g': |
1139 | 0 | { |
1140 | 0 | if (LocaleCompare((char *) keyword,"generations") == 0) |
1141 | 0 | { |
1142 | 0 | log_info->generations=MagickAtoL(token); |
1143 | 0 | break; |
1144 | 0 | } |
1145 | 0 | break; |
1146 | 0 | } |
1147 | 0 | case 'L': |
1148 | 0 | case 'l': |
1149 | 0 | { |
1150 | 0 | if (LocaleCompare((char *) keyword,"limit") == 0) |
1151 | 0 | { |
1152 | 0 | log_info->limit=MagickAtoL(token); |
1153 | 0 | break; |
1154 | 0 | } |
1155 | 0 | break; |
1156 | 0 | } |
1157 | 0 | case 'O': |
1158 | 0 | case 'o': |
1159 | 0 | { |
1160 | 0 | if (LocaleCompare((char *) keyword,"output") == 0) |
1161 | 0 | { |
1162 | 0 | unsigned int i; |
1163 | |
|
1164 | 0 | for (i=0; i < ArraySize(output_map); i++) |
1165 | 0 | { |
1166 | 0 | if (LocaleNCompare(token,output_map[i].name, |
1167 | 0 | output_map[i].name_len) == 0) |
1168 | 0 | { |
1169 | | /* We do not OR these flags despite the fact that |
1170 | | they are bit masks because they are still |
1171 | | mutually exclusive implementations. Asking for |
1172 | | XML and TXT format files each use the file handle |
1173 | | field and others to do their work, so they can |
1174 | | not be used together */ |
1175 | |
|
1176 | 0 | LockSemaphoreInfo(log_info->log_semaphore); |
1177 | |
|
1178 | 0 | log_info->output_type=output_map[i].mask; |
1179 | |
|
1180 | 0 | UnlockSemaphoreInfo(log_info->log_semaphore); |
1181 | |
|
1182 | 0 | break; |
1183 | 0 | } |
1184 | 0 | } |
1185 | 0 | break; |
1186 | 0 | } |
1187 | 0 | break; |
1188 | 0 | } |
1189 | 0 | default: |
1190 | 0 | break; |
1191 | 0 | } |
1192 | 0 | } |
1193 | | |
1194 | 0 | MagickFreeMemory(xml); |
1195 | |
|
1196 | 0 | if ((depth == 0) && (status == MagickPass)) |
1197 | 0 | log_info->log_configured=MagickTrue; |
1198 | |
|
1199 | 0 | return(status); |
1200 | 0 | } |
1201 | | |
1202 | | /* |
1203 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1204 | | % % |
1205 | | % % |
1206 | | % % |
1207 | | % S e t L o g D e f a u l t E v e n t T y p e % |
1208 | | % % |
1209 | | % % |
1210 | | % % |
1211 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1212 | | % |
1213 | | % SetLogDefaultEventType() accepts a comma-delimited list (Annotate, Blob, |
1214 | | % Cache, Coder, Configure, Deprecate, Error, Exception, FatalError, |
1215 | | % Information, Locale, Option, Render, Resource, TemporaryFile, Transform, |
1216 | | % User, Warning, or X11) that determines the default set of events to log. |
1217 | | % All other events are ignored. By default, no logging is enabled. |
1218 | | % |
1219 | | % This function should be called prior to InitializeMagick() since it |
1220 | | % provides defaults used by InitializeMagick() while the logging system |
1221 | | % is initialized. The events may be modified later after |
1222 | | % InitializeMagick() has been called using the SetLogEventMask() function. |
1223 | | % |
1224 | | % The format of SetLogDefaultEventType method is: |
1225 | | % |
1226 | | % void SetLogDefaultEventType( const char *events ) |
1227 | | % |
1228 | | % A description of each parameter follows: |
1229 | | % |
1230 | | % o events: Comma-separated list of events to report. |
1231 | | % |
1232 | | % |
1233 | | */ |
1234 | | MagickExport void SetLogDefaultEventType(const char *events) |
1235 | 0 | { |
1236 | 0 | if (events != NULL) |
1237 | 0 | { |
1238 | 0 | LogEventType event_flags=ParseEvents(events); |
1239 | 0 | log_info_defaults.events=event_flags; |
1240 | 0 | } |
1241 | 0 | } |
1242 | | |
1243 | | /* |
1244 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1245 | | % % |
1246 | | % % |
1247 | | % % |
1248 | | % S e t L o g D e f a u l t G e n e r a t i o n s % |
1249 | | % % |
1250 | | % % |
1251 | | % % |
1252 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1253 | | % |
1254 | | % SetLogDefaultGenerations() specifies the maximum number of log files |
1255 | | % to maintain before circulating back to overwrite the first name. |
1256 | | % |
1257 | | % This function should be called prior to InitializeMagick() since it |
1258 | | % provides defaults used by InitializeMagick() while the logging system |
1259 | | % is initialized. |
1260 | | % |
1261 | | % The format of SetLogDefaultGenerations method is: |
1262 | | % |
1263 | | % void SetLogDefaultGenerations(const unsigned long generations) |
1264 | | % |
1265 | | % A description of each parameter follows: |
1266 | | % |
1267 | | % o generations: Number of log files to maintain before circulating back to |
1268 | | % the first name. |
1269 | | % |
1270 | | % |
1271 | | */ |
1272 | | MagickExport void SetLogDefaultGenerations(const unsigned long generations) |
1273 | 0 | { |
1274 | 0 | log_info_defaults.generations=generations; |
1275 | 0 | } |
1276 | | |
1277 | | /* |
1278 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1279 | | % % |
1280 | | % % |
1281 | | % % |
1282 | | % S e t L o g D e f a u l t L i m i t % |
1283 | | % % |
1284 | | % % |
1285 | | % % |
1286 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1287 | | % |
1288 | | % SetLogDefaultLimit() specifies the maximum number of logging events which |
1289 | | % may occur before creating a new log file. |
1290 | | % |
1291 | | % This function should be called prior to InitializeMagick() since it |
1292 | | % provides defaults used by InitializeMagick() while the logging system |
1293 | | % is initialized. |
1294 | | % |
1295 | | % The format of SetLogDefaultLimit method is: |
1296 | | % |
1297 | | % void SetLogDefaultLimit(const unsigned long limit) |
1298 | | % |
1299 | | % A description of each parameter follows: |
1300 | | % |
1301 | | % o limit: Maximum number of logging events before creating a new log file. |
1302 | | % |
1303 | | % |
1304 | | */ |
1305 | | MagickExport void SetLogDefaultLimit(const unsigned long limit) |
1306 | 0 | { |
1307 | 0 | log_info_defaults.limit=limit; |
1308 | 0 | } |
1309 | | |
1310 | | /* |
1311 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1312 | | % % |
1313 | | % % |
1314 | | % % |
1315 | | % S e t L o g D e f a u l t L o g M e t h o d % |
1316 | | % % |
1317 | | % % |
1318 | | % % |
1319 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1320 | | % |
1321 | | % SetLogDefaultLogMethod() provides a call-back function to be invoked |
1322 | | % for each log event when the logging method type is MethodOutput. |
1323 | | % This call-back function is supported when MethodOutput is enabled |
1324 | | % in the log output type. MethodOutput is automatically enabled if |
1325 | | % a call-back function is provided, and disabled if the call-back |
1326 | | % function is NULL. |
1327 | | % |
1328 | | % This function should be called prior to InitializeMagick() since it |
1329 | | % provides defaults used by InitializeMagick() while the logging system |
1330 | | % is initialized. |
1331 | | % |
1332 | | % The format of SetLogDefaultLogMethod method is: |
1333 | | % |
1334 | | % void SetLogDefaultLogMethod( const LogMethod method ) |
1335 | | % |
1336 | | % A description of each parameter follows: |
1337 | | % |
1338 | | % o method: Call-back function to be invoked for each log event. |
1339 | | % |
1340 | | % |
1341 | | */ |
1342 | | MagickExport void SetLogDefaultLogMethod(const LogMethod method) |
1343 | 0 | { |
1344 | 0 | if (method == (LogMethod) NULL) |
1345 | 0 | { |
1346 | 0 | log_info_defaults.output_type=(LogOutputType) |
1347 | 0 | (log_info_defaults.output_type & ~MethodOutput); |
1348 | 0 | } |
1349 | 0 | else |
1350 | 0 | { |
1351 | 0 | log_info_defaults.output_type=(LogOutputType) |
1352 | 0 | (log_info_defaults.output_type | MethodOutput); |
1353 | 0 | } |
1354 | |
|
1355 | 0 | log_info_defaults.method=method; |
1356 | 0 | } |
1357 | | |
1358 | | /* |
1359 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1360 | | % % |
1361 | | % % |
1362 | | % % |
1363 | | % S e t L o g D e f a u l t O u t p u t T y p e % |
1364 | | % % |
1365 | | % % |
1366 | | % % |
1367 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1368 | | % |
1369 | | % SetLogDefaultOutputType() sets the logging output destination. |
1370 | | % |
1371 | | % This function should be called prior to InitializeMagick() since it |
1372 | | % provides defaults used by InitializeMagick() while the logging system |
1373 | | % is initialized. |
1374 | | % |
1375 | | % The format of SetLogDefaultOutputType method is: |
1376 | | % |
1377 | | % void SetLogDefaultOutputType( const LogOutputType output_type ) |
1378 | | % |
1379 | | % A description of each parameter follows: |
1380 | | % |
1381 | | % o output_type: The logging output destination. One of the enumerated |
1382 | | % values of LogOutputType. |
1383 | | % |
1384 | | % |
1385 | | */ |
1386 | | MagickExport void SetLogDefaultOutputType(const LogOutputType output_type) |
1387 | 0 | { |
1388 | 0 | log_info_defaults.output_type=output_type; |
1389 | 0 | } |
1390 | | |
1391 | | /* |
1392 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1393 | | % % |
1394 | | % % |
1395 | | % % |
1396 | | % S e t L o g D e f a u l t F o r ma t % |
1397 | | % % |
1398 | | % % |
1399 | | % % |
1400 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1401 | | % |
1402 | | % SetLogDefaultFormat() provides the format of the logging output. |
1403 | | % The specification supports these special format characters: |
1404 | | % |
1405 | | % %d domain |
1406 | | % %e event |
1407 | | % %f function |
1408 | | % %l line |
1409 | | % %m module |
1410 | | % %p process ID |
1411 | | % %r real CPU time |
1412 | | % %t wall clock time |
1413 | | % %u user CPU time |
1414 | | % %% percent sign |
1415 | | % \n newline |
1416 | | % \r carriage return |
1417 | | % |
1418 | | % This function should be called prior to InitializeMagick() since it |
1419 | | % provides defaults used by InitializeMagick() while the logging system |
1420 | | % is initialized. |
1421 | | % |
1422 | | % The format of SetLogDefaultFormat method is: |
1423 | | % |
1424 | | % void SetLogDefaultFormat( const char *format ) |
1425 | | % |
1426 | | % A description of each parameter follows: |
1427 | | % |
1428 | | % o format: The format of the logging output. |
1429 | | % |
1430 | | % |
1431 | | */ |
1432 | | MagickExport void SetLogDefaultFormat( const char *format ) |
1433 | 0 | { |
1434 | 0 | (void) strlcpy(log_info_defaults.format,format,sizeof(log_info_defaults.format)); |
1435 | 0 | } |
1436 | | |
1437 | | /* |
1438 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1439 | | % % |
1440 | | % % |
1441 | | % % |
1442 | | % S e t L o g D e f a u l t F i l e N a m e % |
1443 | | % % |
1444 | | % % |
1445 | | % % |
1446 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1447 | | % |
1448 | | % SetLogDefaultFileName() provides the file name, or file path, to be |
1449 | | % written to for each log event. Place a %d in the file name in order to |
1450 | | % support multiple log generations. This setting is only used when the |
1451 | | % log output type uses an output file. |
1452 | | % |
1453 | | % This function should be called prior to InitializeMagick() since it |
1454 | | % provides defaults used by InitializeMagick() while the logging system |
1455 | | % is initialized. |
1456 | | % |
1457 | | % The format of SetLogDefaultFileName method is: |
1458 | | % |
1459 | | % void SetLogDefaultFileName( const char *filename ) |
1460 | | % |
1461 | | % A description of each parameter follows: |
1462 | | % |
1463 | | % o filename: File name, or file path to write log output to. |
1464 | | % |
1465 | | % |
1466 | | */ |
1467 | | MagickExport void SetLogDefaultFileName( const char *filename ) |
1468 | 0 | { |
1469 | 0 | (void) strlcpy(log_info_defaults.filename,filename,sizeof(log_info_defaults.filename)); |
1470 | 0 | } |
1471 | | |
1472 | | /* |
1473 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1474 | | % % |
1475 | | % % |
1476 | | % % |
1477 | | % S e t L o g E v e n t M a s k % |
1478 | | % % |
1479 | | % % |
1480 | | % % |
1481 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1482 | | % |
1483 | | % SetLogEventMask() accepts a comma-delimited list (Annotate, Blob, Cache, |
1484 | | % Coder, Configure, Deprecate, Error, Exception, FatalError, Information, |
1485 | | % Locale, Option, Render, Resource, TemporaryFile, Transform, User, |
1486 | | % Warning, or X11) that determines which events to log. All other events |
1487 | | % are ignored. By default, no logging is enabled. This method returns |
1488 | | % the updated log event mask. |
1489 | | % |
1490 | | % The format of the SetLogEventMask method is: |
1491 | | % |
1492 | | % unsigned long SetLogEventMask(const char *events) |
1493 | | % |
1494 | | % A description of each parameter follows: |
1495 | | % |
1496 | | % o events: log these events. |
1497 | | % |
1498 | | % |
1499 | | */ |
1500 | | MagickExport unsigned long SetLogEventMask(const char *events) |
1501 | 508 | { |
1502 | 508 | LogEventType |
1503 | 508 | event_flags=NoEventsMask; |
1504 | | |
1505 | 508 | LockSemaphoreInfo(log_info->log_semaphore); |
1506 | | |
1507 | 508 | if (events != NULL) |
1508 | 254 | { |
1509 | 254 | event_flags=ParseEvents(events); |
1510 | 254 | log_info->events=event_flags; |
1511 | 254 | } |
1512 | | |
1513 | 508 | event_flags=log_info->events; |
1514 | | |
1515 | 508 | UnlockSemaphoreInfo(log_info->log_semaphore); |
1516 | | |
1517 | 508 | (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), |
1518 | 508 | "Set log event mask: %s", events ? events : "None"); |
1519 | | |
1520 | 508 | return (event_flags); |
1521 | 508 | } |
1522 | | |
1523 | | /* |
1524 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1525 | | % % |
1526 | | % % |
1527 | | % % |
1528 | | % S e t L o g F o r m a t % |
1529 | | % % |
1530 | | % % |
1531 | | % % |
1532 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1533 | | % |
1534 | | % SetLogFormat() sets the format for the "human readable" log record. |
1535 | | % The format specification supports these special format characters: |
1536 | | % |
1537 | | % %d domain, |
1538 | | % %e event, |
1539 | | % %f function, |
1540 | | % %l line, |
1541 | | % %m module, |
1542 | | % %p process ID, |
1543 | | % %r real CPU time, |
1544 | | % %t wall clock time, |
1545 | | % %u user CPU time, |
1546 | | % %% percent sign, |
1547 | | % \n newline, |
1548 | | % \r carriage return |
1549 | | % |
1550 | | % The format of the LogMagickFormat method is: |
1551 | | % |
1552 | | % void SetLogFormat(const char *format) |
1553 | | % |
1554 | | % A description of each parameter follows: |
1555 | | % |
1556 | | % o format: The log record format. |
1557 | | % |
1558 | | % |
1559 | | */ |
1560 | | MagickExport void SetLogFormat(const char *format) |
1561 | 0 | { |
1562 | 0 | LockSemaphoreInfo(log_info->log_semaphore); |
1563 | |
|
1564 | 0 | (void) strlcpy(log_info->format,format,sizeof(log_info->format)); |
1565 | |
|
1566 | 0 | UnlockSemaphoreInfo(log_info->log_semaphore); |
1567 | 0 | } |
1568 | | |
1569 | | /* |
1570 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1571 | | % % |
1572 | | % % |
1573 | | % % |
1574 | | % S e t L o g M e t h o d % |
1575 | | % % |
1576 | | % % |
1577 | | % % |
1578 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1579 | | % |
1580 | | % SetLogMethod() sets the method to be called when logging. |
1581 | | % |
1582 | | % The format of the SetLogMethod method is: |
1583 | | % |
1584 | | % void SetLogMethod(LogMethod method) |
1585 | | % |
1586 | | % A description of each parameter follows: |
1587 | | % |
1588 | | % o method: pointer to a method of type LogMethod that will be called when LogMagickEvent |
1589 | | % is called. Pass a null pointer to remove a registered method. |
1590 | | % |
1591 | | % |
1592 | | */ |
1593 | | MagickExport void SetLogMethod(LogMethod method) |
1594 | 0 | { |
1595 | 0 | LockSemaphoreInfo(log_info->log_semaphore); |
1596 | |
|
1597 | 0 | if (method == (LogMethod) NULL) |
1598 | 0 | { |
1599 | 0 | log_info->output_type=(LogOutputType) |
1600 | 0 | (log_info->output_type & ~MethodOutput); |
1601 | 0 | } |
1602 | 0 | else |
1603 | 0 | { |
1604 | 0 | log_info->output_type=(LogOutputType) |
1605 | 0 | (log_info->output_type | MethodOutput); |
1606 | 0 | } |
1607 | |
|
1608 | 0 | log_info->method=method; |
1609 | |
|
1610 | 0 | UnlockSemaphoreInfo(log_info->log_semaphore); |
1611 | 0 | } |