aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/doc/src/logger.xml
blob: 239b9553b1809c9426d20b7d69e2916efea470ba (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">

<erlref>
  <header>
    <copyright>
      <year>2017</year>
      <holder>Ericsson AB. All Rights Reserved.</holder>
    </copyright>
    <legalnotice>
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      See the License for the specific language governing permissions and
      limitations under the License.

    </legalnotice>

    <title>logger</title>
    <prepared></prepared>
    <responsible></responsible>
    <docno></docno>
    <approved></approved>
    <checked></checked>
    <date></date>
    <rev>A</rev>
    <file>logger.xml</file>
  </header>
  <module>logger</module>
  <modulesummary>API module for the logger.</modulesummary>

  <description>
    <p>
      This module is the main logger API. It contains functions that allow
      application to use a single log API and the system to manage those log
      events independently. To log events the logger
      <seealso marker="#macros">macros</seealso> should be used. For instance,
      to log a new error log event:</p>
      <code>
?LOG_ERROR("error happened because: ~p",[Reason]). %% With macro
logger:error("error happened because: ~p",[Reason]). %% Without macro
      </code>
      <p>This log event will then be sent to the configured log handlers which
      by default means that it will be printed to the console. If you want
      your systems logs to be printed to a file instead of the console you
      have to configure the default handler to do so. The simplest way is
      to include the following in your <seealso marker="config"><c>sys.config</c></seealso>.</p>
      <code>
[{kernel,
  [{logger,
    [{handler,default,logger_std_h,
      #{logger_std_h=>#{type=>{file,"path/to/file.log"}}}}]}]}].
      </code>
    <p>
      For more information about:
    </p>
    <list type="bulleted">
      <item>how to use the API,
        see <seealso marker="logger_chapter">the User's Guide</seealso>.</item>
      <item>how to configure logger,
        see the <seealso marker="logger_chapter#configuration">Configuration</seealso>
        section in the User's Guide.</item>
      <item>the convinience macros in logger.hrl,
        see <seealso marker="#macros">the macro section</seealso>.</item>
      <item>what the builtin formatter can do,
        see <seealso marker="logger_formatter">logger_formatter</seealso>.</item>
      <item>what the builtin handlers can do,
        see <seealso marker="logger_std_h">logger_std_h</seealso> and
        <seealso marker="logger_disk_log_h">logger_disk_log_h</seealso>.</item>
      <item>what builtin filters are available,
      see <seealso marker="logger_filters">logger_filters</seealso>.</item>
    </list>
  </description>

  <datatypes>
    <datatype>
      <name name="level"/>
      <desc>
	<p>The severity level for the message to be logged.</p>
      </desc>
    </datatype>
    <datatype>
      <name name="log"/>
      <desc>
	<p></p>
      </desc>
    </datatype>
    <datatype>
      <name name="report"/>
      <desc>
	<p></p>
      </desc>
    </datatype>
    <datatype>
      <name name="msg_fun"/>
      <desc>
	<p></p>
      </desc>
    </datatype>
    <datatype>
      <name name="metadata"/>
      <desc>
	<p>Metadata for the log event.</p>
	<p>Logger adds the following metadata to each log event:</p>
	<list>
	  <item><c>pid  => self()</c></item>
	  <item><c>gl   => group_leader()</c></item>
	  <item><c>time => erlang:monotonic_time(microsecond)</c></item>
	</list>
	<p>When a log macro is used, Logger also inserts location
	  information:</p>
	<list>
	  <item><c>mfa  => {?MODULE,?FUNCTION_NAME,?FUNCTION_ARITY}</c></item>
	  <item><c>file => ?FILE</c></item>
	  <item><c>line => ?LINE</c></item>
	</list>
	<p>You can add custom metadata, either by specifying a map as
	  the last parameter to any of the log macros or the API
	  functions, or by setting process metadata
	  with <seealso marker="#set_process_metadata-1">
	    <c>set_process_metadata/1</c></seealso>
	  or <seealso marker="#update_process_metadata-1">
	    <c>update_process_metadata/1</c></seealso>.</p>
	<p>Logger merges all the metadata maps before forwarding the
	  log event to the handlers. If the same keys occur, values
	  from the log call overwrites process metadata, which in turn
	  overwrites values set by Logger.</p>
      </desc>
    </datatype>
    <datatype>
      <name name="config"/>
      <desc>
	<p>Configuration data for the logger part of Logger, or for a handler.</p>
	<p>The following default values apply:</p>
	<list>
	  <item><c>level => info</c></item>
	  <item><c>filter_default => log</c></item>
	  <item><c>filters => []</c></item>
	  <item><c>formatter => {logger_formatter,DefaultFormatterConfig</c>}</item>
	</list>
	<p>See the <seealso marker="logger_formatter#configuration">
	    <c>logger_formatter(3)</c></seealso> manual page for
	  information about the default configuration for this
	  formatter.</p>
      </desc>
    </datatype>
    <datatype>
      <name name="handler_id"/>
      <desc>
	<p>A unique identifier for a handler instance.</p>
      </desc>
    </datatype>
    <datatype>
      <name name="filter_id"/>
      <desc>
	<p>A unique identifier for a filter.</p>
      </desc>
    </datatype>
    <datatype>
      <name name="filter"/>
      <desc>
	<p>A filter which can be installed for logger or for a handler.</p>
      </desc>
    </datatype>
    <datatype>
      <name name="filter_arg"/>
      <desc>
	<p>The second argument to the filter fun.</p>
      </desc>
    </datatype>
    <datatype>
      <name name="filter_return"/>
      <desc>
	<p>The return value from the filter fun.</p>
      </desc>
    </datatype>
    <datatype>
      <name name="timestamp"/>
      <desc>
	<p>A timestamp produced
	  with <seealso marker="erts:erlang#monotonic_time-1">
	    <c>erlang:monotonic_time(microsecond)</c></seealso>.</p>
      </desc>
    </datatype>
  </datatypes>

  <section>
    <title>Macros</title>
    <p>The following macros are defined:</p>

    <list>
      <item><c>?LOG_EMERGENCY(StringOrReport[,Metadata])</c></item>
      <item><c>?LOG_EMERGENCY(FunOrFormat,Args[,Metadata])</c></item>
      <item><c>?LOG_ALERT(StringOrReport[,Metadata])</c></item>
      <item><c>?LOG_ALERT(FunOrFormat,Args[,Metadata])</c></item>
      <item><c>?LOG_CRITICAL(StringOrReport[,Metadata])</c></item>
      <item><c>?LOG_CRITICAL(FunOrFormat,Args[,Metadata])</c></item>
      <item><c>?LOG_ERROR(StringOrReport[,Metadata])</c></item>
      <item><c>?LOG_ERROR(FunOrFormat,Args[,Metadata])</c></item>
      <item><c>?LOG_WARNING(StringOrReport[,Metadata])</c></item>
      <item><c>?LOG_WARNING(FunOrFormat,Args[,Metadata])</c></item>
      <item><c>?LOG_NOTICE(StringOrReport[,Metadata])</c></item>
      <item><c>?LOG_NOTICE(FunOrFormat,Args[,Metadata])</c></item>
      <item><c>?LOG_INFO(StringOrReport[,Metadata])</c></item>
      <item><c>?LOG_INFO(FunOrFormat,Args[,Metadata])</c></item>
      <item><c>?LOG_DEBUG(StringOrReport[,Metadata])</c></item>
      <item><c>?LOG_DEBUG(FunOrFormat,Args[,Metadata])</c></item>
    </list>

    <p>All macros expand to a call to logger, where <c>Level</c> is
      taken from the macro name, and location data is added. See the
      description of
      the <seealso marker="#type-metadata"><c>metadata()</c></seealso>
      type for more information about the location data.</p>

    <p>The call is wrapped in a case statement and will be evaluated
      only if <c>Level</c> is equal to or below the configured log
      level.</p>
  </section>

  <funcs>
    <func>
      <name>emergency(StringOrReport[,Metadata])</name>
      <name>emergency(Format,Args[,Metadata])</name>
      <name>emergency(Fun,FunArgs[,Metadata])</name>
      <fsummary>Logs the given message as level <c>emergency</c>.</fsummary>
      <desc>
        <p>Equivalent to
	<seealso marker="#log-2"><c>log(emergency,...)</c></seealso>.</p>
      </desc>
    </func>

    <func>
      <name>alert(StringOrReport[,Metadata])</name>
      <name>alert(Format,Args[,Metadata])</name>
      <name>alert(Fun,FunArgs[,Metadata])</name>
      <fsummary>Logs the given message as level <c>alert</c>.</fsummary>
      <desc>
        <p>Equivalent to
	<seealso marker="#log-2"><c>log(alert,...)</c></seealso>.</p>
      </desc>
    </func>

    <func>
      <name>critical(StringOrReport[,Metadata])</name>
      <name>critical(Format,Args[,Metadata])</name>
      <name>critical(Fun,FunArgs[,Metadata])</name>
      <fsummary>Logs the given message as level <c>critical</c>.</fsummary>
      <desc>
        <p>Equivalent to
	<seealso marker="#log-2"><c>log(critical,...)</c></seealso>.</p>
      </desc>
    </func>

    <func>
      <name>error(StringOrReport[,Metadata])</name>
      <name>error(Format,Args[,Metadata])</name>
      <name>error(Fun,FunArgs[,Metadata])</name>
      <fsummary>Logs the given message as level <c>error</c>.</fsummary>
      <desc>
        <p>Equivalent to
	<seealso marker="#log-2"><c>log(error,...)</c></seealso>.</p>
      </desc>
    </func>

    <func>
      <name>warning(StringOrReport[,Metadata])</name>
      <name>warning(Format,Args[,Metadata])</name>
      <name>warning(Fun,FunArgs[,Metadata])</name>
      <fsummary>Logs the given message as level <c>warning</c>.</fsummary>
      <desc>
        <p>Equivalent to
	<seealso marker="#log-2"><c>log(warning,...)</c></seealso>.</p>
      </desc>
    </func>

    <func>
      <name>notice(StringOrReport[,Metadata])</name>
      <name>notice(Format,Args[,Metadata])</name>
      <name>notice(Fun,FunArgs[,Metadata])</name>
      <fsummary>Logs the given message as level <c>notice</c>.</fsummary>
      <desc>
        <p>Equivalent to
	<seealso marker="#log-2"><c>log(notice,...)</c></seealso>.</p>
      </desc>
    </func>

    <func>
      <name>info(StringOrReport[,Metadata])</name>
      <name>info(Format,Args[,Metadata])</name>
      <name>info(Fun,FunArgs[,Metadata])</name>
      <fsummary>Logs the given message as level <c>info</c>.</fsummary>
      <desc>
        <p>Equivalent to
	<seealso marker="#log-2"><c>log(info,...)</c></seealso>.</p>
      </desc>
    </func>

    <func>
      <name>debug(StringOrReport[,Metadata])</name>
      <name>debug(Format,Args[,Metadata])</name>
      <name>debug(Fun,FunArgs[,Metadata])</name>
      <fsummary>Logs the given message as level <c>debug</c>.</fsummary>
      <desc>
        <p>Equivalent to
	<seealso marker="#log-2"><c>log(debug,...)</c></seealso>.</p>
      </desc>
    </func>

    <func>
      <name name="log" arity="2"/>
      <name name="log" arity="3" clause_i="1"/>
      <name name="log" arity="3" clause_i="2"/>
      <name name="log" arity="3" clause_i="3"/>
      <name name="log" arity="4" clause_i="1"/>
      <name name="log" arity="4" clause_i="2"/>
      <fsummary>Logs the given message.</fsummary>
      <type variable="Level"/>
      <type variable="StringOrReport" name_i="1"/>
      <type variable="Format" name_i="3"/>
      <type variable="Args" name_i="3"/>
      <type variable="Fun" name_i="4"/>
      <type variable="FunArgs" name_i="4"/>
      <type variable="Metadata"/>
      <desc>
        <p>Log the given message.</p>
      </desc>
    </func>

    <func>
      <name name="get_logger_config" arity="0"/>
      <fsummary>Lookup the current configuration for logger.</fsummary>
      <desc>
        <p>Lookup the current configuration for logger.</p>
      </desc>
    </func>

    <func>
      <name name="get_handler_config" arity="1"/>
      <fsummary>Lookup the current configuration for the given handler.</fsummary>
      <desc>
        <p>Lookup the current configuration for the given handler.</p>
      </desc>
    </func>

    <func>
      <name name="i" arity="0"/>
      <fsummary>Get all logger configurations</fsummary>
      <desc>
        <p>Same as <seealso marker="#i/1"><c>logger:i(term)</c></seealso></p>
      </desc>
    </func>

    <func>
      <name name="i" arity="1" clause_i="1"/>
      <name name="i" arity="1" clause_i="2"/>
      <name name="i" arity="1" clause_i="3"/>
      <fsummary>Get all logger configurations</fsummary>
      <desc>
        <p>Display or return all current logger configuration.</p>
        <taglist>
          <tag><c><anno>Action</anno> = string</c></tag>
          <item>
	    <p>Return the pretty printed current logger configuration
              as iodata.</p>
	  </item>
          <tag><c><anno>Action</anno> = term</c></tag>
          <item>
	    <p>Return the current logger configuration as a term. The
              format of this term may change inbetween releases. For a
              stable format use <seealso marker="#get_handler_config/1">
	      <c>logger:get_handler_config/1</c></seealso>
              and <seealso marker="#get_logger_config/0">
	      <c>logger:get_logger_config/0</c></seealso>.
              The same as calling <c>logger:i()</c>.</p>
	  </item>
	  <tag><c><anno>Action</anno> = print</c></tag>
          <item>
	    <p>Pretty print all the current logger configuration to
              standard out. Example:</p>
            <code><![CDATA[1> logger:i(print).
Current logger configuration:
  Level: info
  Filter Default: log
  Filters:
  Handlers:
    Id: default
      Module:    logger_std_h
      Level:     info
      Formatter:
        Module: logger_formatter
        Config: #{legacy_header => true,single_line => false,
                  template => [{logger_formatter,header},"\n",msg,"\n"]}
      Filter Default: stop
      Filters:
        Id: stop_progress
          Fun:    fun logger_filters:progress/2
          Config: stop
        Id: remote_gl
          Fun:    fun logger_filters:remote_gl/2
          Config: stop
        Id: domain
          Fun:    fun logger_filters:domain/2
          Config: {log,prefix_of,[beam,erlang,otp,sasl]}
        Id: no_domain
          Fun:    fun logger_filters:domain/2
          Config: {log,no_domain,[]}
      Handler Config:
        logger_std_h: #{type => standard_io}
  Level set per module:
    Module: my_module
      Level:    debug]]></code>
          </item>
        </taglist>
      </desc>
    </func>

    <func>
      <name name="add_logger_filter" arity="2"/>
      <fsummary>Add a filter to the logger.</fsummary>
      <desc>
        <p>Add a filter to the logger.</p>
	<p>The filter fun is called with the log event as the first
	  parameter, and the specified <c>filter_args()</c> as the
	  second parameter.</p>
	<p>The return value of the fun specifies if a log event is to
	  be discarded or forwarded to the handlers:</p>
	<taglist>
	  <tag><c>log()</c></tag>
	  <item>
	    <p>The filter <em>passed</em>. The next logger filter, if
	      any, is applied. If no more logger filters exist, the
	      log event is forwarded to the handler part of the
	      logger, where handler filters are applied.</p>
	  </item>
	  <tag><c>stop</c></tag>
	  <item>
	    <p>The filter <em>did not pass</em>, and the log event is
	      immediately discarded.</p>
	  </item>
	  <tag><c>ignore</c></tag>
	  <item>
	    <p>The filter has no knowledge of the log event. The next
	      logger filter, if any, is applied. If no more logger
	      filters exist, the value of the <c>filter_default</c>
	      configuration parameter for the logger specifies if the
	      log event shall be discarded or forwarded to the handler
	      part.</p>
	  </item>
	</taglist>
	<p>See section <seealso marker="logger_chapter#Filter">
	    Filter</seealso> in the User's Guide for more information
	    about filters.</p>
	<p>Some built-in filters exist. These are defined
	  in <seealso marker="logger_filters"><c>logger_filters</c></seealso>.</p>
      </desc>
    </func>

    <func>
      <name name="add_handler_filter" arity="3"/>
      <fsummary>Add a filter to the specified handler.</fsummary>
      <desc>
        <p>Add a filter to the specified handler.</p>
	<p>The filter fun is called with the log event as the first
	  parameter, and the specified <c>filter_args()</c> as the
	  second parameter.</p>
	<p>The return value of the fun specifies if a log event is to
	  be discarded or forwarded to the handler callback:</p>
	<taglist>
	  <tag><c>log()</c></tag>
	  <item>
	    <p>The filter <em>passed</em>. The next handler filter, if
	      any, is applied. If no more filters exist for this
	      handler, the log event is forwarded to the handler
	      callback.</p>
	  </item>
	  <tag><c>stop</c></tag>
	  <item>
	    <p>The filter <em>did not pass</em>, and the log event is
	      immediately discarded.</p>
	  </item>
	  <tag><c>ignore</c></tag>
	  <item>
	    <p>The filter has no knowledge of the log event. The next
	      handler filter, if any, is applied. If no more filters
	      exist for this handler, the value of
	      the <c>filter_default</c> configuration parameter for
	      the handler specifies if the log event shall be
	      discarded or forwarded to the handler callback.</p>
	  </item>
	</taglist>
	<p>See
	  section <seealso marker="logger_chapter#Filter">Filter</seealso>
	  in the User's Guide for more information about filters.</p>
	<p>Some built-in filters exist. These are defined in
	  <seealso marker="logger_filters"><c>logger_filters</c></seealso>.</p>
      </desc>
    </func>

    <func>
      <name name="remove_logger_filter" arity="1"/>
      <fsummary>Remove a filter from the logger.</fsummary>
      <desc>
        <p>Remove the filter identified
          by <c><anno>FilterId</anno></c> from the logger.</p>
      </desc>
    </func>

    <func>
      <name name="remove_handler_filter" arity="2"/>
      <fsummary>Remove a filter from the specified handler.</fsummary>
      <desc>
        <p>Remove the filter identified
          by <c><anno>FilterId</anno></c> from the handler identified
          by <c><anno>HandlerId</anno></c>.</p>
      </desc>
    </func>

    <func>
      <name name="add_handler" arity="3"/>
      <fsummary>Add a handler with the given configuration.</fsummary>
      <desc>
        <p>Add a handler with the given configuration.</p>
	<p><c><anno>HandlerId</anno></c> is a unique identifier which
	  must be used in all subsequent calls reffering to this
	  handler.</p>
      </desc>
    </func>

    <func>
      <name name="remove_handler" arity="1"/>
      <fsummary>Remove the handler with the specified identity.</fsummary>
      <desc>
        <p>Remove the handler identified by <c><anno>HandlerId</anno></c>.</p>
      </desc>
    </func>

    <func>
      <name name="set_module_level" arity="2"/>
      <fsummary>Set the log level for the specified module.</fsummary>
      <desc>
        <p>Set the log level for the
          specified <c><anno>Module</anno></c>.</p>
	<p>The log level for a module overrides the global log level
	  of the logger for log event originating from the module in
	  question. Notice, however, that it does not override the
	  level configuration for any handler.</p>
	<p>For example: Assume that the global log level for the
	  logger is <c>info</c>, and there is one handler, <c>h1</c>,
	  with level <c>info</c> and one handler, <c>h2</c>, with
	  level <c>debug</c>.</p>
	<p>With this configuration, no debug messages will be logged,
	  since they are all stopped by the global log level.</p>
	<p>If the level for <c>mymodule</c> is set now set
	  to <c>debug</c>, then debug events from this module will be
	  logged by the handler <c>h2</c>, but not by
	  handler <c>h1</c>.</p>
	<p>Debug events from other modules are still not logged.</p>
        <p>To change the global log level for the logger, use
          <seealso marker="#set_logger_config/2">
	    <c>logger:set_logger_config(level,Level)</c></seealso>.</p>
        <p>To change the log level for a handler, use
          <seealso marker="#set_handler_config/3">
	    <c>logger:set_handler_config(HandlerId,level,Level)</c></seealso>.</p>
	<note>
	  <p>The originating module for a log event is only detected
	    if <c>mfa=>{Module,Function,Arity}</c> exists in the
	    metadata. When log macros are used, this association is
	    automatically added to all log events. If the logger API
	    is called directly, without using a macro, the logging
	    client must explicitly add this information.</p>
	</note>
      </desc>
    </func>

    <func>
      <name name="reset_module_level" arity="1"/>
      <fsummary>Remove a module specific log setting.</fsummary>
      <desc>
        <p>Remove a module specific log setting. After this, the
          global log level is used for the specified module.</p>
      </desc>
    </func>

    <func>
      <name name="add_handlers" arity="1" clause_i="1"/>
      <fsummary>Setup logger handlers from the applications configuration parameters.</fsummary>
      <desc>
        <p>Reads the application configuration parameter <c>logger</c> and
          calls <c>logger:add_handlers/1</c> with it contents.</p>
      </desc>
    </func>

    <func>
      <name name="add_handlers" arity="1" clause_i="2"/>
      <fsummary>Setup logger handlers.</fsummary>
      <type name="config_handler"/>
      <desc>
        <p>This function should be used by custom logger handlers to make
        configuration consistent no matter which handler the system uses.
        Normal usage to to add a call to <c>logger:add_handlers/1</c>
        just after the processes that the handler needs are started
        and pass the applications logger config as an argument. Eg.</p>
        <code>
-behaviour(application).
start(_, []) ->
    case supervisor:start_link({local, my_sup}, my_sup, []) of
        {ok, Pid} ->
            ok = logger:add_handlers(my_app),
            {ok, Pid, []};
        Error -> Error
     end.</code>
       <p>This will read the <c>logger</c> configuration parameter from
         the handler application and start the configured handlers. The contents
         of the configuration use the same rules as the
         <seealso marker="logger_chapter#handler-configuration">logger handler configuration</seealso>.
       </p>
       <p>If the handler is meant to replace the default handler the kernels
         default handlers have to be disabled before the new handler is added.
         A <c>sys.config</c> file that disables the kernel handler and adds
         a custom handler could looks like this:</p>
         <code>
[{kernel,
  [{logger,
    %% Disable the default kernel handler
    [{handler,default,undefined}]}]},
 {my_app,
  [{logger,
    %% Enable this handler as the default
    [{handler,default,my_handler,#{}}]}]}].
         </code>
      </desc>
    </func>

    <func>
      <name name="set_logger_config" arity="1"/>
      <fsummary>Set configuration data for the logger.</fsummary>
      <desc>
        <p>Set configuration data for the logger. This overwrites the
          current logger configuration.</p>
	<p>To modify the existing configuration,
	  use <seealso marker="#set_logger_config-2"><c>set_logger_config/2</c>
	  </seealso>, or read the current configuration
	  with <seealso marker="#get_logger_config-0"><c>get_logger_config/0</c>
	  </seealso>, then merge in your added or updated
	  associations before writing it back.</p>
	<p>If a key is removed compared to the current configuration,
	  the default value is used.</p>
      </desc>
    </func>

    <func>
      <name name="set_logger_config" arity="2"/>
      <fsummary>Add or update configuration data for the logger.</fsummary>
      <desc>
        <p>Add or update configuration data for the logger. If the
          given <c><anno>Key</anno></c> already exists, its associated
          value will be changed to <c><anno>Value</anno></c>. If it
          doesn't exist, it will be added.</p>
      </desc>
    </func>

    <func>
      <name name="set_handler_config" arity="2"/>
      <fsummary>Set configuration data for the specified handler.</fsummary>
      <desc>
        <p>Set configuration data for the specified handler. This
          overwrites the current handler configuration.</p>
	<p>To modify the existing configuration,
	  use <seealso marker="#set_handler_config-3"><c>set_handler_config/3</c>
	  </seealso>, or read the current configuration
	  with <seealso marker="#get_handler_config-1"><c>get_handler_config/1</c>
	  </seealso>, then merge in your added or updated
	  associations before writing it back.</p>
	<p>If a key is removed compared to the current configuration,
	  and the key is know by Logger, the default value is used. If
	  it is a custom key, then it is up to the handler
	  implementation if the value is removed or a default value is
	  inserted.</p>
      </desc>
    </func>

    <func>
      <name name="set_handler_config" arity="3"/>
      <fsummary>Add or update configuration data for the specified
        handler.</fsummary>
      <desc>
        <p>Add or update configuration data for the specified
          handler. If the given <c><anno>Key</anno></c> already
          exists, its associated value will be changed
          to <c><anno>Value</anno></c>. If it doesn't exist, it will
          be added.</p>
      </desc>
    </func>

    <func>
      <name name="compare_levels" arity="2"/>
      <fsummary>Compare the severity of two log levels.</fsummary>
      <desc>
        <p>Compare the severity of two log levels. Returns <c>gt</c>
          if <c>Level1</c> is more severe than
          <c>Level2</c>, <c>lt</c> if <c>Level1</c> is less severe,
          and <c>eq</c> if the levels are equal.</p>
      </desc>
    </func>

    <func>
      <name name="set_process_metadata" arity="1"/>
      <fsummary>Set metadata to use when logging from current process.</fsummary>
      <desc>
        <p>Set metadata which Logger shall automatically insert in
          all log events produced on the current process.</p>
	<p>Location data produced by the log macros, and/or metadata
	  given as argument to the log call (API function or macro),
	  are merged with the process metadata. If the same keys
	  occur, values from the metadata argument to the log call
	  overwrite values from the process metadata, which in turn
	  overwrite values from the location data.</p>
	<p>Subsequent calls to this function overwrites previous data
          set. To update existing data instead of overwriting it,
          see <seealso marker="#update_process_metadata-1">
	    <c>update_process_metadata/1</c></seealso>.</p>
      </desc>
    </func>

    <func>
      <name name="update_process_metadata" arity="1"/>
      <fsummary>Set or update metadata to use when logging from
	current process.</fsummary>
      <desc>
	<p>Set or update metadata to use when logging from current
	  process</p>
	<p>If process metadata exists for the current process, this
	  function behaves as if it was implemented as follows:</p>
	<code type="erl">
logger:set_process_metadata(maps:merge(logger:get_process_metadata(),Meta)).
	</code>
	<p>If no process metadata exists, the function behaves as
	  <seealso marker="#set_process_metadata-1">
	    <c>set_process_metadata/1</c>
	  </seealso>.</p>
      </desc>
    </func>

    <func>
      <name name="get_process_metadata" arity="0"/>
      <fsummary>Retrieve data set with set_process_metadata/1.</fsummary>
      <desc>
        <p>Retrieve data set
          with <seealso marker="#set_process_metadata-1">
	    <c>set_process_metadata/1</c></seealso> or
	  <seealso marker="#update_process_metadata-1">
	    <c>update_process_metadata/1</c></seealso>.</p>
      </desc>
    </func>

    <func>
      <name name="unset_process_metadata" arity="0"/>
      <fsummary>Delete data set with set_process_metadata/1.</fsummary>
      <desc>
        <p>Delete data set
          with <seealso marker="#set_process_metadata-1">
	    <c>set_process_metadata/1</c></seealso> or
	  <seealso marker="#update_process_metadata-1">
	    <c>update_process_metadata/1</c></seealso>.</p>
      </desc>
    </func>

    <func>
      <name name="format_report" arity="1"/>
      <fsummary>Convert a log message on report form to {Format,Args}.</fsummary>
      <desc>
        <p>Convert a log message on report form to <c>{Format,Args}</c>.</p>
	<p>This is the default report callback used
	  by <seealso marker="logger_formatter">
	    <c>logger_formatter</c></seealso> when no custom report
	    callback is found.</p>
	<p>The function produces lines of <c>Key: Value</c> from
	  key-value lists. Strings are printed with <c>~ts</c> and
	  other terms with <c>~tp</c>.</p>
	<p>If the <c><anno>Report</anno></c> is a map, it is
	  converted to a key-value list before formatting as such.</p>
      </desc>
    </func>

  </funcs>

  <section>
    <title>Callback Functions</title>
    <p>The following functions are to be exported from a handler
      callback module.</p>
  </section>

  <funcs>
    <func>
      <name>Module:adding_handler(HandlerId,Config1) -> {ok,Config2} | {error,Reason}</name>
      <fsummary>An instance of this handler is about to be added.</fsummary>
      <type>
	<v>HandlerId =
	  <seealso marker="#type-handler_id">handler_id()</seealso></v>
	<v>Config1 = Config2 =
	  <seealso marker="#type-config">config()</seealso></v>
	<v>Reason = term()</v>
      </type>
      <desc>
	<p>This callback function is optional.</p>
	<p>The function is called when an new handler is about to be
	  added, and the purpose is to verify the configuration and
	  initiate all resourced needed by the handler.</p>
	<p>If everything succeeds, the callback function can add
	  possible default values or internal state values to the
	  configuration, and return the adjusted map
	  in <c>{ok,Config2}</c>.</p>
	<p>If the configuration is faulty, or if the initiation fails,
	  the callback function must return <c>{error,Reason}</c>.</p>
      </desc>
    </func>

    <func>
      <name>Module:removing_handler(HandlerId,Config) -> ok</name>
      <fsummary>The given handler is about to be removed.</fsummary>
      <type>
	<v>HandlerId =
	  <seealso marker="#type-handler_id">handler_id()</seealso></v>
	<v>Config =
	  <seealso marker="#type-config">config()</seealso></v>
      </type>
      <desc>
	<p>This callback function is optional.</p>
	<p>The function is called when a handler is about to be
	  removed, and the purpose is to release all resources used by
	  the handler. The return value is ignored by Logger.</p>
      </desc>
    </func>

    <func>
      <name>Module:changing_config(HandlerId,Config1,Config2) -> {ok,Config3} | {error,Reason}</name>
      <fsummary>The configuration for this handler is about to change.</fsummary>
      <type>
	<v>HandlerId =
	  <seealso marker="#type-handler_id">handler_id()</seealso></v>
	<v>Config1 = Config2 = Config3 =
	  <seealso marker="#type-config">config()</seealso></v>
	<v>Reason = term()</v>
      </type>
      <desc>
	<p>This callback function is optional.</p>
	<p>The function is called when the configuration for a handler
	  is about to change, and the purpose is to verify and act on
	  the new configuration.</p>
	<p><c>Config1</c> is the existing configuration
	  and <c>Config2</c> is the new configuration.</p>
	<p>If everything succeeds, the callback function must return a
	  possibly adjusted configuration in <c>{ok,Config3}</c>.</p>
	<p>If the configuration is faulty, the callback function must
	  return <c>{error,Reason}</c>.</p>
      </desc>
    </func>
  </funcs>
</erlref>