Coverage Report

Created: 2026-06-16 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}