aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/doc/src/logger.xml
blob: 13d3e182d43c7eedace5d4787fd745d2f9577892 (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
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
<?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 logging in Erlang/OTP.</modulesummary>

  <description>

<!-- From old error_logger ref man:
 Errors, warnings, and info events
      are sent to the error logger from the Erlang runtime system and
      the different Erlang/OTP applications. The events are, by default,
      logged to the terminal. Notice that an event from a process <c>P</c> is
      logged at the node of the group leader of <c>P</c>. This means
      that log output is directed to the node from which a process was
      created, which not necessarily is the same node as where it is
      executing.</p>
    <p>Initially, <c>error_logger</c> has only a primitive event
      handler, which buffers and prints the raw event messages. During
      system startup, the Kernel application replaces this with a
      <em>standard event handler</em>, by default one that writes
      nicely formatted output to the terminal. Kernel can also be
      configured so that events are logged to a file instead, or not logged at all,
      see <seealso marker="kernel_app"><c>kernel(6)</c></seealso>.</p>
    <p>Also the SASL application, if started, adds its own event
      handler, which by default writes supervisor, crash, and progress
      reports to the terminal. See
      <seealso marker="sasl:sasl_app"><c>sasl(6)</c></seealso>.</p>
    <p>It is recommended that user-defined applications report
      errors through the error logger to get uniform reports.
-->



    <p>
      This module is the main API for logging in Erlang/OTP. It
      contains functions that allow applications to use a single log
      API and the system to manage those log events independently. Use
      the <seealso marker="#emergency-1">API functions</seealso> or the log
      <seealso marker="#macros">macros</seealso> to log events. For instance,
      to log a new error 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 is then sent to the configured log handlers which
      by default means that it is be printed to the console. If you want
      your systems logs to be printed to a file instead of the console you
      must 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:system_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 overwrite process metadata, which in turn
	  overwrite 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 the logger part of
	  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#system_time-1">
	    <c>erlang:system_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 to the
      metadata. 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>Look up the current configuration for the logger part
	of Logger.</fsummary>
      <desc>
        <p>Look up the current configuration for the logger part of
          Logger.</p>
      </desc>
    </func>

    <func>
      <name name="get_handler_config" arity="1"/>
      <fsummary>Look up the current configuration for the given
	handler.</fsummary>
      <desc>
        <p>Look up 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 configurations.</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 between 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>.</p>
            <p>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 part of Logger.</fsummary>
      <desc>
        <p>Add a filter to the logger part of 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 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 part 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 part of Logger.</fsummary>
      <desc>
        <p>Remove the filter identified
          by <c><anno>FilterId</anno></c> from the logger part of 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 Logger for log events 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 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 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 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 an API function
	    is called directly, without using a macro, the logging
	    client must explicitly add this information if module
	    levels shall have any effect.</p>
	</note>
      </desc>
    </func>

    <func>
      <name name="unset_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>Set up log handlers from the application's
	configuration parameters.</fsummary>
      <desc>
        <p>Reads the application configuration parameter <c>logger</c> and
          calls <c>logger:add_handlers/1</c> with its 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 is to add a call to <c>logger:add_handlers/1</c>
        just after the processes that the handler needs are started,
        and pass the application's <c>logger</c> configuration as the argument.
	For example:</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 reads the <c>logger</c> configuration parameter from
         the <c>my_all</c> application and starts 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 Kernel's
         default handler 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 look 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 part of Logger.</fsummary>
      <desc>
        <p>Set configuration data for the logger part of Logger. This
          overwrites the current logger configuration.</p>
	<p>To modify the existing configuration,
	  use <seealso marker="#update_logger_config-1">
	    <c>update_logger_config/1</c></seealso>, or, if a more
	  complex merge is needed, read the current configuration
	  with <seealso marker="#get_logger_config-0"><c>get_logger_config/0</c>
	  </seealso>, then do the merge before writing the new
	  configuration back with this function.</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 part
	of Logger.</fsummary>
      <desc>
        <p>Add or update configuration data for the logger part of
          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 does not exist, it will
          be added.</p>
      </desc>
    </func>

    <func>
      <name name="update_logger_config" arity="1"/>
      <fsummary>Update configuration data for the logger part of
	Logger.</fsummary>
      <desc>
        <p>Update configuration data for the logger part of
          Logger. This function behaves as if it was implemented as
          follows:</p>
	<code type="erl">
{ok,Old} = logger:get_logger_config(),
logger:set_logger_config(maps:merge(Old,Config)).
	</code>
	<p>To overwrite the existing configuration without any merge,
	  use <seealso marker="#set_logger_config-1"><c>set_logger_config/1</c>
	  </seealso>.</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="#update_handler_config-2">
	    <c>update_handler_config/2</c></seealso>, or, if a more
	  complex merge is needed, read the current configuration
	  with <seealso marker="#get_handler_config-1"><c>get_handler_config/1</c>
	  </seealso>, then do the merge before writing the new
	  configuration back with this function.</p>
	<p>If a key is removed compared to the current configuration,
	  and the key is known 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 does not exist, it will
          be added.</p>
      </desc>
    </func>

    <func>
      <name name="update_handler_config" arity="2"/>
      <fsummary>Update configuration data for the specified handler.</fsummary>
      <desc>
        <p>Update configuration data for the specified handler. This function
          behaves as if it was implemented as follows:</p>
	<code type="erl">
{ok,{_,Old}} = logger:get_handler_config(HandlerId),
logger:set_handler_config(HandlerId,maps:merge(Old,Config)).
	</code>
	<p>To overwrite the existing configuration without any merge,
	  use <seealso marker="#set_handler_config-2"><c>set_handler_config/2</c>
	  </seealso>.</p>
      </desc>
    </func>

    <func>
      <name name="update_formatter_config" arity="2"/>
      <fsummary>Update the formatter configuration for the specified handler.</fsummary>
      <desc>
        <p>Update the formatter configuration for the specified handler.</p>
	<p>The new configuration is merged with the existing formatter
	  configuration.</p>
	<p>To overwrite the existing configuration without any merge,
	  use <seealso marker="#set_handler_config-3">
	    <c>set_handler_config(HandlerId,formatter,
	      {FormatterModule,FormatterConfig})</c></seealso>.</p>
      </desc>
    </func>

    <func>
      <name name="update_formatter_config" arity="3"/>
      <fsummary>Update the formatter configuration for the specified handler.</fsummary>
      <desc>
        <p>Update the formatter configuration for the specified handler.</p>
	<p>This is equivalent
	  to <br/><seealso marker="#update_formatter_config-2">
	    <c>update_formatter_config(<anno>HandlerId</anno>,#{<anno>Key</anno>=><anno>Value</anno>})</c></seealso></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>