-
-
Notifications
You must be signed in to change notification settings - Fork 975
/
faq.html
executable file
·1615 lines (1260 loc) · 60.4 KB
/
faq.html
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
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<title>SLF4J FAQ</title>
<link rel="stylesheet" type="text/css" media="screen" href="css/site.css" />
<link rel="stylesheet" type="text/css" href="css/prettify.css" />
</head>
<body onload="prettyPrint(); decorate();">
<script type="text/javascript" src="js/prettify.js"></script>
<script type="text/javascript">prefix='';</script>
<script type="text/javascript" src="templates/header.js"></script>
<script type="text/javascript" src="js/jquery-min.js"></script>
<script type="text/javascript" src="js/decorator.js"></script>
<div id="left">
<script src="templates/left.js" type="text/javascript"></script>
</div>
<div id="content">
<h2><a name="top">Frequently Asked Questions about SLF4J</a></h2>
<p><b>Generalities</b></p>
<ol type="1">
<li><a href="#what_is">What is SLF4J?</a></li>
<li><a href="#when">When should SLF4J be used?</a></li>
<li><a href="#yet_another_facade"> Is SLF4J yet another loggingfacade?</a></li>
<li><a href="#why_new_project"> If SLF4J fixes JCL, then why
wasn't the fix made in JCL instead of creating a new project?
</a>
</li>
<li><a href="#need_to_recompile"> When using SLF4J, do I have to
recompile my application to switch to a different logging
system?
</a>
</li>
<li><a href="#requirements">What are SLF4J's requirements?</a></li>
<li><a href="#compatibility">Are SLF4J versions backward
compatible?</a></li>
<li><a href="#IllegalAccessError">I am getting
<code>IllegalAccessError</code> exceptions when using SLF4J. Why
is that?</a></li>
<li>
<a href="#license">Why is SLF4J licensed under X11 type
license instead of the Apache Software License?
</a>
</li>
<li>
<a href="#where_is_binding">Where can I get a particular
SLF4J binding?
</a>
</li>
<li>
<a href="#configure_logging">Should my library attempt to
configure logging?
</a>
</li>
<li>
<a href="#optional_dependency">In order to reduce the number of
dependencies of our software we would like to make SLF4J an
optional dependency. Is that a good idea?
</a>
</li>
<li>
<a href="#maven2">What about Maven transitive
dependencies?
</a>
</li>
<li>
<a href="#excludingJCL">How do I exclude commons-logging as a
Maven dependency?
</a>
</li>
</ol>
<b>About the SLF4J API</b>
<ol type="1">
<li>
<a href="#string_or_object"> Why don't the printing methods
in the Logger interface accept message of type Object, but only
messages of type String?
</a>
</li>
<li>
<a href="#exception_message">
Can I log an exception without an accompanying message?
</a>
</li>
<li>
<a href="#logging_performance"> What is the fastest way of
(not) logging?
</a>
</li>
<li>
<a href="#string_contents"> How can I log the string contents
of a single (possibly complex) object?
</a>
</li>
<li><a href="#fatal"> Why doesn't the
<code>org.slf4j.Logger</code> interface have methods for the
FATAL level? </a></li>
<li><a href="#trace">Why was the TRACE level introduced only in
SLF4J version 1.4.0? </a></li>
<li><a href="#i18n">Does the SLF4J logging API support I18N
(internationalization)? </a></li>
<li><a href="#noLoggerFactory">Is it possible to retrieve loggers
without going through the static methods in
<code>LoggerFactory</code>? </a></li>
<li><a href="#paramException">In the presence of an
exception/throwable, is it possible to parameterize a logging
statement?</a></li>
</ol>
<b>Implementing the SLF4J API</b>
<ol type="1">
<li><a href="#slf4j_compatible">How do I make my logging
framework SLF4J compatible? </a></li>
<li><a href="#marker_interface">How can my logging system add
support for the <code>Marker</code> interface? </a></li>
<li><a href="#version_checks">How does SLF4J's version check
mechanism work? </a></li>
</ol>
<b>General questions about logging</b>
<ol type="1">
<li><a href="#declared_static"> Should Logger members of a class
be declared as static? </a></li>
<li><a href="#declaration_pattern">Is there a recommended idiom
for declaring a loggers in a class?</a></li>
</ol>
<h2>Generalities</h2>
<dl>
<dt class="doAnchor" name="what_is">What is SLF4J?</dt>
<dd>
<p>SLF4J is a simple facade for logging systems allowing the
end-user to plug-in the desired logging system at deployment
time.
</p>
</dd>
<dt class="doAnchor" name="when">When should SLF4J be used?</dt>
<dd>
<p>In short, libraries and other embedded components should
consider SLF4J for their logging needs because libraries cannot
afford to impose their choice of logging framework on the
end-user. On the other hand, it does not necessarily make sense
for stand-alone applications to use SLF4J. Stand-alone
applications can invoke the logging framework of their choice
directly. In the case of logback, the question is moot because
logback exposes its logger API via SLF4J.
</p>
<p>SLF4J is only a facade, meaning that it does not provide a
complete logging solution. Operations such as configuring
appenders or setting logging levels cannot be performed with
SLF4J. Thus, at some point in time, any non-trivial
application will need to directly invoke the underlying
logging system. In other words, complete independence from the
API underlying logging system is not possible for a
stand-alone application. Nevertheless, SLF4J reduces the
impact of this dependence to near-painless levels.
</p>
<p>Suppose that your CRM application uses log4j for its
logging. However, one of your important clients request that
logging be performed through JDK 1.4 logging. If your
application is riddled with thousands of direct log4j calls,
migration to JDK 1.4 would be a relatively lengthy and
error-prone process. Even worse, you would potentially need to
maintain two versions of your CRM software. Had you been
invoking SLF4J API instead of log4j, the migration could be
completed in a matter of minutes by replacing one jar file with
another.
</p>
<p>SLF4J lets component developers to defer the choice of the
logging system to the end-user but eventually a choice needs
to be made.
</p>
</dd>
<dt class="doAnchor" name="yet_another_facade">Is SLF4J yet
another logging facade?</dt>
<dd>
<p>SLF4J is conceptually very similar to JCL. As such, it can
be thought of as yet another logging facade. However, SLF4J is
much simpler in design and arguably more robust. In a
nutshell, SLF4J avoid the class loader issues that plague JCL.
</p>
</dd>
<dt class="doAnchor" name="why_new_project">If SLF4J fixes JCL,
then why wasn't the fix made in JCL instead of creating a new
project?
</dt>
<dd>
<p>This is a very good question. First, SLF4J static binding
approach is very simple, perhaps even laughably so. It was
not easy to convince developers of the validity of that
approach. It is only after SLF4J was released and started to
become accepted did it gain respectability in the relevant
community.
</p>
<p>Second, SLF4J offers two enhancements which tend to be
underestimated. Parameterized log messages solve an important
problem associated with logging performance, in a pragmatic
way. Marker objects, which are supported by the
<code>org.slf4j.Logger</code> interface, pave the way for
adoption of advanced logging systems and still leave the door
open to switching back to more traditional logging systems if
need be.
</p>
</dd>
<dt class="doAnchor" name="need_to_recompile">When using SLF4J, do
I have to recompile my application to switch to a different
logging system?
</dt>
<dd>
<p>No, you do not need to recompile your application. You can
switch to a different logging system by removing the previous
SLF4J binding and replacing it with the binding of your choice.
</p>
<p>For example, if you were using the NOP implementation and
would like to switch to log4j version 1.2, simply replace
<em>slf4j-nop.jar</em> with <em>slf4j-log4j12.jar</em> on
your class path but do not forget to add log4j-1.2.x.jar as
well. Want to switch to JDK 1.4 logging? Just replace
<em>slf4j-log4j12.jar</em> with <em>slf4j-jdk14.jar</em>.
</p>
</dd>
<dt class="doAnchor" name="requirements">What are SLF4J's
requirements?
</dt>
<dd>
<p>As of version 1.7.0, SLF4J requires JDK 1.5 or later. Earlier
SLF4J versions, namely SLF4J 1.4, 1.5. and 1.6, required JDK
1.4.
</p>
<p> </p>
<table class="bodyTable striped">
<tr align="left">
<th>Binding</th>
<th>Requirements</th>
</tr>
<tr>
<td>slf4j-nop</td>
<td>JDK 1.5</td>
</tr>
<tr>
<td>slf4j-simple</td>
<td>JDK 1.5</td>
</tr>
<tr>
<td>slf4j-log4j12</td>
<td align="left">JDK 1.5, plus any other library
dependencies required by the log4j appenders in use</td>
</tr>
<tr>
<td>slf4j-jdk14</td>
<td>JDK 1.5 or later</td>
</tr>
<tr>
<td>logback-classic</td>
<td>JDK 1.5 or later, plus any other library dependencies
required by the logback appenders in use</td>
</tr>
</table>
</dd>
<!-- ==================================================== -->
<!-- entry has order dependees -->
<dt class="doAnchor" name="compatibility">Are SLF4J versions
backward compatible?
</dt>
<dd>
<p>From the clients perspective, the SLF4J API is backward
compatible for all versions. This means than you can upgrade
from SLF4J version 1.0 to any later version without
problems. Code compiled with <em>slf4j-api-versionN.jar</em>
will work with <em>slf4j-api-versionM.jar</em> for any versionN
and any versionM. <b>To date, binary compatibility in slf4j-api
has never been broken.</b></p>
<p>However, while the SLF4J API is very stable from the client's
perspective, SLF4J bindings, e.g. slf4j-simple.jar or
slf4j-log4j12.jar, may require a specific version of slf4j-api.
Mixing different versions of slf4j artifacts can be problematic
and is strongly discouraged. For instance, if you are using
slf4j-api-1.5.6.jar, then you should also use
slf4j-simple-1.5.6.jar, using slf4j-simple-1.4.2.jar will not
work.
</p>
<p>At initialization time, if SLF4J suspects that there may be a
version mismatch problem, it emits a warning about the said
mismatch.
</p>
</dd>
<!-- ==================================================== -->
<dt class="doAnchor" name="IllegalAccessError">I am getting
<code>IllegalAccessError</code> exceptions when using SLF4J. Why
is that?
</dt>
<dd>
<p>Here are the exception details.</p>
<pre class="source">Exception in thread "main" java.lang.IllegalAccessError: tried to access field
org.slf4j.impl.StaticLoggerBinder.SINGLETON from class org.slf4j.LoggerFactory
at org.slf4j.LoggerFactory.<clinit>(LoggerFactory.java:60)</pre>
<p>This error is caused by the static initializer of the
<code>LoggerFactory</code> class attempting to directly access
the SINGLETON field of
<code>org.slf4j.impl.StaticLoggerBinder</code>. While this was
allowed in SLF4J 1.5.5 and earlier, in 1.5.6 and later the
SINGLETON field has been marked as private access.
</p>
<p>If you get the exception shown above, then you are using an
older version of slf4j-api, e.g. 1.4.3, with a new version of a
slf4j binding, e.g. 1.5.6. Typically, this occurs when your
Maven <em>pom.ml</em> file incorporates hibernate 3.3.0 which
declares a dependency on slf4j-api version 1.4.2. If your
<em>pom.xml</em> declares a dependency on an slf4j binding, say
slf4j-log4j12 version 1.5.6, then you will get illegal access
errors.
</p>
<p>To see which version of slf4j-api is pulled in by Maven, use
the maven dependency plugin as follows.</p>
<p class="source">mvn dependency:tree</p>
<p>If you are using Eclipse, please do not rely on the dependency
tree shown by <a
href="http://m2eclipse.codehaus.org/">m2eclipse</a>.</p>
<p>In your <em>pom.xml</em> file, explicitly declaring a
dependency on slf4j-api matching the version of the declared
binding will make the problem go away.
</p>
<p>Please also read the FAQ entry on <a
href="#compatibility">backward compatibility</a> for a more
general explanation.</p>
</dd>
<!-- ==================================================== -->
<dt class="doAnchor" name="license">Why is SLF4J licensed under
X11 type license instead of the Apache Software License?
</dt>
<dd>
<p>SLF4J is licensed under a permissive X11 type license
instead of the <a
href="http://www.apache.org/licenses/">ASL</a> or the <a
href="http://www.gnu.org/copyleft/lesser.html">LGPL</a>
because the X11 license is deemed by both the Apache Software
Foundation as well as the Free Software Foundation as
compatible with their respective licenses.
</p>
</dd>
<!-- ==================================================== -->
<dt class="doAnchor" name="where_is_binding">Where can I get a
particular SLF4J binding?
</dt>
<dd>
<p>SLF4J bindings for <a
href="api/org/slf4j/impl/SimpleLogger.html">SimpleLogger</a>,
<a href="api/org/slf4j/impl/NOPLogger.html">NOPLogger</a>, <a
href="api/org/slf4j/impl/Log4jLoggerAdapter.html">Log4jLoggerAdapter</a>
and <a
href="api/org/slf4j/impl/JDK14LoggerAdapter.html">JDK14LoggerAdapter</a>
are contained within the files <em>slf4j-nop.jar</em>,
<em>slf4j-simple.jar</em>, <em>slf4j-log4j12.jar</em>, and
<em>slf4j-jdk14.jar</em>. These files ship with the <a
href="download.html">official SLF4J distribution</a>. Please
note that all bindings depend on <em>slf4j-api.jar</em>.
</p>
<p>The binding for logback-classic ships with the <a
href="http://logback.qos.ch/download.html">logback
distribution</a>. However, as with all other bindings, the
logback-classic binding requires <em>slf4j-api.jar</em>.
</p>
</dd>
<dt class="doAnchor" name="configure_logging">Should my library
attempt to configure logging?
</dt>
<dd>
<p><b>Embedded components such as libraries not only do not need
to configure the underlying logging framework, they really
should not do so</b>. They should invoke SLF4J to log but should
let the end-user configure the logging environment. When
embedded components try to configure logging on their own, they
often override the end-user's wishes. At the end of the day, it
is the end-user who has to read the logs and process them. She
should be the person to decide how she wants her logging
configured.
</p>
</dd>
<!-- ======================================================= -->
<dt class="doAnchor" name="optional_dependency">In order to reduce
the number of dependencies of our software we would like to make
SLF4J an optional dependency. Is that a good idea?
</dt>
<dd>
<p><a
href="http://stackoverflow.com/questions/978670/is-it-worth-wrapping-a-logging-framework-in-an-additional-layer">This
question pops up</a> whenever a software project reaches a point
where it needs to devise a logging strategy.
</p>
<p>Let Wombat be a software library with very few
dependencies. If SLF4J is chosen as Wombat's logging API, then a
new dependency on <em>slf4j-api.jar</em> will be added to
Wombat's list of dependencies. Given that writing a logging
wrapper does not seem that hard, some developers will be tempted
to wrap SLF4J and link with it only if it is already present on
the classpath, making SLF4J an optional dependency of Wombat. In
addition to solving the dependency problem, the wrapper will
isolate Wombat from SLF4J's API ensuring that logging in Wombat
is future-proof.
</p>
<p>On the other hand, any SLF4J-wrapper by definition depends on
SLF4J. It is bound to have the same general API. If in the
future a new and significantly different logging API comes
along, code that uses the wrapper will be equally difficult to
migrate to the new API as code that used SLF4J directly. Thus,
the wrapper is not likely to future-proof your code, but to make
it more complex by adding an additional indirection on top of
SLF4J, which is an indirection in itself.
</p>
<p><span class="label">increased vulnerability</span> It is
actually worse than that. Wrappers will need to depend on
certain internal SLF4J interfaces which change from time to
time, contrary to the client-facing API which never
changes. Thus, wrappers are usually dependent on the major
version they were compiled with. A wrapper compiled against
SLF4J version 1.5.x will not work with SLF4J 1.6 whereas client
code using <code>org.slf4j.Logger</code>,
<code>LoggerFactory</code>, <code>MarkerFactory</code>,
<code>org.slf4j.Marker</code>, and <code>MDC</code> will work
fine with any SLF4J version from version 1.0 and onwards.
</p>
<p>It is reasonable to assume that in most projects Wombat will
be one dependency among many. If each library had its own
logging wrapper, then each wrapper would presumably need to be
configured separately. Thus, instead of having to deal with one
logging framework, namely SLF4J, the user of Wombat would have
to detail with Wombat's logging wrapper as well. The problem
will be compounded by each framework that comes up with its own
wrapper in order to make SLF4J optional. (Configuring or
dealing with the intricacies of five different logging wrappers
is not exactly exciting nor endearing.)
</p>
<p>The <a
href="http://velocity.apache.org/engine/devel/developer-guide.html#Configuring_Logging">logging
strategy adopted by the Velocity project</a> is a good example
of the "custom logging abstraction" anti-pattern. By adopting an
independent logging abstraction strategy, Velocity developers
have made life harder for themselves, but more importantly, they
made life harder for their users.
</p>
<p>Some projects try to detect the presence of SLF4J on the
class path and switch to it if present. While this approach
seems transparent enough, it will result in erroneous location
information. Underlying logging frameworks will print the
location (class name and line number) of the wrapper instead of
the real caller. Then there is the question of API coverage as
SLF4J support MDC and markers in addition to parameterized
logging. While one can come up with a seemingly working
SLF4J-wrapper within hours, many technical issues will emerge
over time which Wombat developers will have to deal with. Note
that SLF4J has evolved over several years and has 260 bug
reports filed against it.</p>
<p>For the above reasons, developers of frameworks should resist
the temptation to write their own logging wrapper. Not only is
it a waste of time of the developer, it will actually make life
more difficult for the users of said frameworks and make logging
code paradoxically more vulnerable to change.
</p>
</dd>
<!-- ======================================================= -->
<dt class="doAnchor" name="maven2">What about Maven transitive
dependencies?
</dt>
<dd>
<p>As an author of a library built with Maven, you might want to
test your application using a binding, say slf4j-log4j12 or
logback-classic, without forcing log4j or logback-classic as a
dependency upon your users. This is rather easy to accomplish.
</p>
<p>Given that your library's code depends on the SLF4J API, you
will need to declare slf4j-api as a compile-time (default scope)
dependency.
</p>
<pre class="prettyprint source"><dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${project.version}</version>
</dependency></pre>
<p>Limiting the transitivity of the SLF4J binding used in your
tests can be accomplished by declaring the scope of the
SLF4J-binding dependency as "test". Here is an example:</p>
<pre class="prettyprint source"><dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${project.version}</version>
<b><scope>test</scope></b>
</dependency></pre>
<p>Thus, as far as your users are concerned you are exporting
slf4j-api as a transitive dependency of your library, but not
any SLF4J-binding or any underlying logging system.
</p>
<p>Note that as of SLF4J version 1.6, in the absence of an SLF4J
binding, slf4j-api will default to a no-operation
implementation.
</p>
</dd>
<!-- ====================================================== -->
<dt class="doAnchor" name="excludingJCL">How do I exclude
commons-logging as a Maven dependency?
</dt>
<dd>
<p><b>alternative 1) explicit exclusion</b></p>
<p>Many software projects using Maven declare commons-logging as
a dependency. Therefore, if you wish to migrate to SLF4J or use
jcl-over-slf4j, you would need to exclude commons-logging in all
of your project's dependencies which transitively depend on
commons-logging. <a
href="http://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html">Dependency
exclusion</a> is described in the Maven documentation. Excluding
commons-logging explicitly for multiple dependencies distributed
on several <em>pom.xml</em> files can be a cumbersome and a
relatively error prone process.
</p>
<p><b>alternative 2) provided scope</b></p>
<p>Commons-logging can be rather simply and conveniently
excluded as a dependency by declaring it in the
<em>provided</em> scope within the pom.xml file of your
project. The actual commons-logging classes would be provided by
jcl-over-slf4j. This translates into the following pom file
snippet:</p>
<pre class="prettyprint source"><dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${project.version}</version>
</dependency></pre>
<p>The first dependency declaration essentially states that
commons-logging will be "somehow" provided by your
environment. The second declaration includes jcl-over-slf4j into
your project. As jcl-over-slf4j is a perfect binary-compatible
replacement for commons-logging, the first assertion becomes
true.
</p>
<p>Unfortunately, while declaring commons-logging in the
provided scope gets the job done, your IDE, e.g. Eclipse, will
still place <em>commons-logging.jar</em> on your project's class
path as seen by your IDE. You would need to make sure that
<em>jcl-over-slf4j.jar</em> is visible before
<em>commons-logging.jar</em> by your IDE.
</p>
<p><b>alternative 3) empty artifacts</b></p>
<p>An alternative approach is to depend on an <b>empty</b>
<em>commons-logging.jar</em> artifact. This clever <a
href="http://day-to-day-stuff.blogspot.com/2007/10/announcement-version-99-does-not-exist.html">approach
first was imagined</a> and initially supported by Erik van
Oosten.
</p>
<p>The empty artifact is available from a <a
href="http://version99.qos.ch">http://version99.qos.ch</a> a
high-availability Maven repository, replicated on several hosts
located in different geographical regions.</p>
<p>The following declaration adds the version99 repository to
the set of remote repositories searched by Maven. This
repository contains empty artifacts for commons-logging and
log4j. By the way, if you use the version99 repository, please
drop us a line at <version99 AT qos.ch>.
</p>
<pre class="prettyprint source"><repositories>
<repository>
<id>version99</id>
<!-- highly available repository serving empty artifacts -->
<url>http://version99.qos.ch/</url>
</repository>
</repositories></pre>
<p>Declaring version 99-empty of commons-logging in the
<code><dependencyManagement></code> section of your project
will direct all transitive dependencies for commons-logging to
import version 99-empty, thus nicely addressing the
commons-logging exclusion problem. The classes for commons-logging
will be provided by jcl-over-slf4j. The following lines declare
commons-logging version 99-empty (in the dependency management
section) and declare jcl-over-slf4j as a dependency.
</p>
<pre class="prettyprint source"><dependencyManagement>
<dependencies>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version><b>99-empty</b></version>
</dependency>
... other declarations...
</dependencies>
</dependencyManagement>
<!-- Do not forget to declare a dependency on jcl-over-slf4j in the -->
<!-- dependencies section. Note that the dependency on commons-logging -->
<!-- will be imported transitively. You don't have to declare it yourself. -->
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${project.version}</version>
</dependency>
... other dependency declarations
</dependencies>
</pre>
</dd>
</dl>
<h2>About the SLF4J API</h2>
<dl>
<dt class="doAnchor" name="string_or_object">Why don't the
printing methods in the Logger interface accept message of type
Object, but only messages of type String?
</dt>
<dd>
<p>In SLF4J 1.0beta4, the printing methods such as debug(),
info(), warn(), error() in the <a
href="api/org/slf4j/Logger.html">Logger interface</a> were
modified so as to accept only messages of type String
instead of Object.
</p>
<p>Thus, the set of printing methods for the DEBUG level
became:</p>
<pre class="prettyprint source">debug(String msg);
debug(String format, Object arg);
debug(String format, Object arg1, Object arg2);
debug(String msg, Throwable t);</pre>
<p>Previously, the first argument in the above methods was of
type <code>Object</code>.</p>
<p>This change enforces the notion that logging systems are
about decorating and handling messages of type String, and not
any arbitrary type (Object).
</p>
<p>Just as importantly, the new set of method signatures offer
a clearer differentiation between the overloaded methods
whereas previously the choice of the invoked method due to
Java overloading rules were not always easy to follow.</p>
<p>It was also easy to make mistakes. For example, previously
it was legal to write:</p>
<pre class="prettyprint source">logger.debug(new Exception("some error"));</pre>
<p>Unfortunately, the above call did not print the stack trace
of the exception. Thus, a potentially crucial piece of
information could be lost. When the first parameter is
restricted to be of type String, then only the method
</p>
<pre class="prettyprint source">debug(String msg, Throwable t);</pre>
<p>can be used to log exceptions. Note that this method
ensures that every logged exception is accompanied with a
descriptive message.</p>
</dd>
<!-- ====================================================== -->
<dt class="doAnchor" name="exception_message">Can I log an
exception without an accompanying message?
</dt>
<dd>
<p>In short, no.</p>
<p>If <code>e</code> is an <code>Exception</code>, and you
would like to log an exception at the ERROR level, you must
add an accompanying message. For example,</p>
<pre class="prettyprint source">logger.error("some accompanying message", e);</pre>
<p>You might legitimately argue that not all exceptions have a
meaningful message to accompany them. Moreover, a good exception
should already contain a self explanatory description. The
accompanying message may therefore be considered redundant.
</p>
<p>While these are valid arguments, there are three opposing
arguments also worth considering. First, on many, albeit not
all occasions, the accompanying message can convey useful
information nicely complementing the description contained
in the exception. Frequently, at the point where the
exception is logged, the developer has access to more
contextual information than at the point where the exception
is thrown. Second, it is not difficult to imagine more or
less generic messages, e.g. "Exception caught", "Exception
follows", that can be used as the first argument for
<code>error(String msg, Throwable t)</code> invocations.
Third, most log output formats display the message on a
line, followed by the exception on a separate line. Thus,
the message line would look inconsistent without a message.
</p>
<p>In short, if the user were allowed to log an exception
without an accompanying message, it would be the job of the
logging system to invent a message. This is actually what
the <a href="http://tinyurl.com/cr9kg">throwing(String
sourceClass, String sourceMethod, Throwable thrown)</a>
method in java.util.logging package does. (It decides on its
own that accompanying message is the string "THROW".)
</p>
<p>It may initially appear strange to require an accompanying
message to log an exception. Nevertheless, this is common
practice in <em>all</em> log4j derived systems such as
java.util.logging, logkit, etc. and of course log4j itself. It
seems that the current consensus considers requiring an
accompanying message as a good a thing (TM).
</p>
</dd>
<!-- ====================================================== -->
<dt class="doAnchor" name="logging_performance">What is the
fastest way of (not) logging?
</dt>
<dd>
<p>SLF4J supports an advanced feature called parameterized
logging which can significantly boost logging performance for
<em>disabled</em> logging statement.</p>
<p> For some Logger <code>logger</code>, writing,</p>
<pre class="prettyprint source">logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));</pre>
<p>incurs the cost of constructing the message parameter, that
is converting both integer <code>i</code> and
<code>entry[i]</code> to a String, and concatenating
intermediate strings. This, regardless of whether the message
will be logged or not.
</p>
<p>One possible way to avoid the cost of parameter
construction is by surrounding the log statement with a
test. Here is an example.</p>
<pre class="prettyprint source">if(logger.isDebugEnabled()) {
logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
}</pre>
<p>This way you will not incur the cost of parameter
construction if debugging is disabled for
<code>logger</code>. On the other hand, if the logger is
enabled for the DEBUG level, you will incur the cost of
evaluating whether the logger is enabled or not, twice: once in
<code>debugEnabled</code> and once in <code>debug</code>. This
is an insignificant overhead because evaluating a logger takes
less than 1% of the time it takes to actually log a statement.
</p>
<p><b>Better yet, use parameterized messages</b></p>
<p>There exists a very convenient alternative based on message
formats. Assuming <code>entry</code> is an object, you can write:
</p>
<pre class="prettyprint source">Object entry = new SomeObject();
logger.debug("The entry is {}.", entry);</pre>
<p>After evaluating whether to log or not, and only if the
decision is affirmative, will the logger implementation format
the message and replace the '{}' pair with the string value of
<code>entry</code>. In other words, this form does not incur
the cost of parameter construction in case the log statement is
disabled.
</p>
<p>The following two lines will yield the exact same
output. However, the second form will outperform the first
form by a factor of at least 30, in case of a
<em>disabled</em> logging statement.
</p>
<pre class="prettyprint source">logger.debug("The new entry is "+entry+".");
logger.debug("The new entry is {}.", entry);</pre>
<p>A <a
href="apidocs/org/slf4j/Logger.html#debug(java.lang.String,%20java.lang.Object%2C%20java.lang.Object)">two
argument</a> variant is also available. For example, you can
write:</p>
<pre class="prettyprint source">logger.debug("The new entry is {}. It replaces {}.", entry, oldEntry);</pre>
<p>If three or more arguments need to be passed, you can make
use of the <a
href="apidocs/org/slf4j/Logger.html#debug(java.lang.String%2C%20java.lang.Object...)"><code>Object...</code>
variant</a> of the printing methods. For example, you can
write:</p>
<pre class="prettyprint source">logger.debug("Value {} was inserted between {} and {}.", newVal, below, above);</pre>
<p>This form incurs the hidden cost of construction of an
Object[] (object array) which is usually very small. The one and
two argument variants do not incur this hidden cost and exist
solely for this reason (efficiency). The slf4j-api would be
smaller/cleaner with only the Object... variant.</p>
<p>Array type arguments, including multi-dimensional arrays,
are also supported.</p>
<p>SLF4J uses its own message formatting implementation which
differs from that of the Java platform. This is justified by
the fact that SLF4J's implementation performs about 10 times
faster but at the cost of being non-standard and less
flexible.
</p>
<p><b>Escaping the "{}" pair</b></p>
<p>The "{}" pair is called the <em>formatting anchor</em>. It
serves to designate the location where arguments need to be
substituted within the message pattern.
</p>
<p>SLF4J only cares about the <em>formatting anchor</em>, that
is the '{' character immediately followed by '}'. Thus, in