Codebase list apache-log4j2 / 41c572e
Merge tag 'upstream/2.4' Upstream version 2.4 Emmanuel Bourg 8 years ago
738 changed file(s) with 36263 addition(s) and 12489 deletion(s). Raw diff Collapse all Expand all
00
1 Apache Log4j 2.2 RELEASE NOTES
1 Apache Log4j 2.4 RELEASE NOTES
22
3 The Apache Log4j 2 team is pleased to announce the Log4j 2.2 release!
3 The Apache Log4j 2 team is pleased to announce the Log4j 2.4 release!
44
55 Apache log4j is a well known framework for logging application behavior. Log4j 2 is an upgrade to
66 Log4j that provides significant improvements over its predecessor, Log4j 1.x, and provides
77 many other modern features such as support for Markers, property substitution using Lookups, and asynchronous
88 Loggers. In addition, Log4j 2 will not lose events while reconfiguring.
99
10 This is the fifth GA release. It contains several bugfixes and new features.
10 This is the eighth GA release. It contains several bugfixes and new features. As of this release
11 Log4j now requires a minimum of Java 7.
1112
12 GA Release 2.2
13 GA Release 2.4
1314
1415 Changes in this version include:
1516
1617 New features:
17 o LOG4J2-941: Allow JSON layout to create one compact log record per line. Thanks to Konstantinos Liakos.
18 o LOG4J2-933: HTML layout should not use attribute minimalization for hr noshade. Thanks to ppiman at gmail.com.
19 o LOG4J2-895: Specify the SyslogAppender connect timeout value as part of the configuration.
20 The SyslogAppender takes a new parameter connectTimeoutMillis.
21 o LOG4J2-899: Specify the SocketAppender connect timeout value as part of the configuration.
22 The SyslogAppender takes a new parameter connectTimeoutMillis.
18 o LOG4J2-635: Add support for configuration via Properties.
19 o LOG4J2-952: Add ConfigurationBuilder.
20 o LOG4J2-599: Added support for Java 8 lambda expressions to lazily construct a log message only if
21 the requested log level is enabled.
22 o LOG4J2-1118: Updated Logger wrapper generator tool to add Java 8 lambda support for custom log levels.
23 o LOG4J2-1107: New Appender for Apache Kafka. Thanks to Mikael Ståldal.
24 o LOG4J2-1113: New publisher Appender for ZeroMQ (using JeroMQ). Thanks to Gary Gregory.
25 o LOG4J2-1088: Add Comma Separated Value (CSV) layouts for parameter and event logging. Thanks to Gary Gregory.
26 o LOG4J2-1090: Add Core Configurator APIs to change a logger's level.
27 o LOG4J2-1105: Add API org.apache.logging.log4j.Level.isInRange(Level, Level). Thanks to Gary Gregory.
28 o LOG4J2-1106: Add a LevelRangeFilter class. Thanks to Gary Gregory.
29 o LOG4J2-1076: Added support for system nanosecond time in pattern layout.
30 o LOG4J2-1075: Added support for compressing to bzip2 format on file rollover.
31 o LOG4J2-1077: Support additional Apache Commons Compress compression formats on rollover: Deflate, Pack200, XY.
32 o LOG4J2-767: New module for Liquibase integration. Thanks to Mikael Ståldal.
33 o LOG4J2-1023: New RewritePolicy for changing level of a log event. Thanks to Mikael Ståldal.
34 o LOG4J2-1015: Add a way to route messages based on the %marker in Layout for RoutingAppender. Thanks to Daniel Marcotte.
35 o LOG4J2-1050: Add a Log4jLookup class to help write log files relative to log4j2.xml. Thanks to Adam Retter.
36 o LOG4J2-1057: Add API org.apache.logging.log4j.LogManager.getFormatterLogger().
37 o LOG4J2-1066: Expose Log4jContextFactory's ShutdownCallbackRegistry. Thanks to Charles Allen.
2338
2439 Fixed Bugs:
25 o LOG4J2-938: (JMX) To avoid memory leaks when web applications are restarted, JMX notifications are sent from
26 the caller thread in web applications. For non-web applications notifications are sent from a background thread
27 as before. Thanks to Mauro Molinari.
28 o LOG4J2-957: Missing toUpperCase("Locale.ENGLISH"). Thanks to fatih guleryuz.
29 o LOG4J2-956: Manual refers to Route "AppenderRef" attribute, should be "ref". Thanks to David Kellerman.
30 o LOG4J2-944: Log4j Flume appender is not adding millisecond to the event headers when the event is logged at 000 milliseconds. Thanks to Vinayaka Ramachandra.
31 o LOG4J2-924: Log4j 1.2 Bridge doesn't map level ALL correctly in Category.getEffectiveLevel(). Thanks to Ryan Rupp.
32 o LOG4J2-931: ConsoleAppender is missing @PluginFactory annotation at createAppender method. Thanks to Robert Gacki.
33 o LOG4J2-919: Logging system fails to initialize if XInclude API is not available. Thanks to David Johle.
34 o LOG4J2-914: ThrowableProxy.getExtendedStackTraceAsString causes NullpointerException. Thanks to Kaj Bjurman.
35 o LOG4J2-912: XML configuration does not report full error message for XInclude parser configuration problems.
36 o LOG4J2-903: ClassLoaderContextSelector uses ClassLoader.toString() as a key Thanks to Mauro Molinari.
37 o LOG4J2-834: ThrowableProxy throws NoClassDefFoundError. Thanks to Nikita Koval, Leonard Broman, Thiago Kronig.
38 o LOG4J2-893: NullPointerException on filter when mapping JUL to Log4j2.
39 o LOG4J2-892: JUL adapter does not map Log4j'2 FATAL level to a JUL level.
40 o LOG4J2-881: AbstractLifecycle should not implement equals() and hashCode(). Thanks to Mariano Gonzalez.
41 o LOG4J2-897: Javadoc for org.apache.log4j.BasicConfigurator.configure() is incorrect.
42 o LOG4J2-891: AbstractLifecycle should not implement equals() and hashCode().
43 o LOG4J2-946: [docs] Using Log4j 2 in Web Applications: Update example (Log4jWebLifeCycle is not visible). Thanks to artemonster.
40 o LOG4J2-1121: Fixed potential race condition on reconfiguration. Introduced ReliabilityStrategy to facilitate
41 switching between different mechanisms for preventing log events from being dropped on reconfiguration.
42 o LOG4J2-1123: Core Configurator.initialize(String, ClassLoader, String) fails to work when config location is a file path. Thanks to Gary Gregory.
43 o LOG4J2-1117: OutputStreamManager in ConsoleAppender leaking managers. Thanks to Marcus Thiesen.
44 o LOG4J2-1044: Write pending events to Flume when the appender is stopped.
45 o LOG4J2-1108: NullPointerException when passing null to java.util.logging.Logger.setLevel(). Thanks to Mikael Ståldal.
46 o LOG4J2-1110: org.apache.logging.log4j.jul.CoreLogger.setLevel() checks for security permission too late.
47 o LOG4J2-1084: Misleading StatusLogger WARN event in LogManager with java.util.Map. Thanks to Philipp Schneider.
48 o LOG4J2-1051: NoClassDefFoundError when starting app on Google App Engine. Thanks to Lukasz Lenart.
49 o LOG4J2-684: ExtendedThrowablePatternConverter does not print suppressed exceptions. Thanks to Joern Huxhorn, Mauro Molinari.
50 o LOG4J2-1069: Improper handling of JSON escape chars when deserializing JSON log events. Thanks to Sam Braam.
51 o LOG4J2-1068: Exceptions not logged when using TcpSocketServer + SerializedLayout. Thanks to Andy McMullan.
52 o LOG4J2-1067: ThrowableProxy getExtendedStackTraceAsString throws NPE on deserialized nested exceptions. Thanks to Sam Braam.
53 o LOG4J2-1049: AsyncAppender now resets the thread interrupted flag after catching InterruptedException. Thanks to Robert Schaft.
54 o LOG4J2-1048: FileConfigurationMonitor unnecessarily calls System.currentTimeMillis() causing high CPU usage. Thanks to Nikhil.
55 o LOG4J2-1037: Backward compatibility issue in log4j-1.2-api NDC pop() and peek(). Thanks to Marc Dergacz.
56 o LOG4J2-1025: Custom java.util.logging.Level gives null Log4j Level and causes NPE. Thanks to Mikael Ståldal.
57 o LOG4J2-1033: SimpleLogger creates unnecessary Map objects by calling ThreadContext.getContext() instead of getImmutableContext(). Thanks to Mikael Ståldal.
58 o LOG4J2-1026: HighlightConverter does not obey noConsoleNoAnsi.
59 o LOG4J2-1019: ZipCompressAction leaves files open until GC when an IO error takes place.
60 o LOG4J2-1020: GzCompressAction leaves files open until GC when an IO error takes place.
61 o LOG4J2-1038: Incorrect documentation for layout default charset. Thanks to Gili.
62 o LOG4J2-1042: Socket and Syslog appenders don't take timeout into account at startup. Thanks to Guillaume Turri.
63 o LOG4J2-934: Circular suppressed Exception throws StackOverflowError. Thanks to Kenneth Gendron.
64 o LOG4J2-1046: Circular Exception cause throws StackOverflowError. Thanks to Kenneth Gendron.
65 o LOG4J2-982: Use System.nanoTime() to measure time intervals. Thanks to Mikhail Mazurskiy.
66 o LOG4J2-1045: Externalize log4j2.xml via URL resource. Thanks to Günter Albrecht.
67 o LOG4J2-1058: Log4jMarker#contains(String) does not respect org.slf4j.Marker contract. Thanks to Daniel Branzea.
68 o LOG4J2-1060: Log4jMarker#contains(Marker) does not respect org.slf4j.Marker contract.
69 o LOG4J2-1061: Log4jMarker#remove(Marker) does not respect org.slf4j.Marker contract.
70 o LOG4J2-1062: Log4jMarker#add(Marker) does not respect org.slf4j.Marker contract.
71 o LOG4J2-1064: org.apache.logging.slf4j.Log4jMarker does not implement org.slf4j.Marker.equals(Object) org.slf4j.Marker.hashCode().
72 o LOG4J2-889: Header in layout should not be written on application startup if appending to an existing file. Fixes LOG4J2-1030. Thanks to Maciej Karaś, Kenneth Leider.
73 o LOG4J2-918: Clarify documentation for combining async with sync loggers.
74 o LOG4J2-1078: GelfLayout throws exception if some log event fields are null. Thanks to Mikael Ståldal.
4475
4576 Changes:
46 o LOG4J2-955: Documentation: clarify system properties to control status logger, improve troubleshooting FAQ entry.
47 o LOG4J2-950: Incorrect attribute name in PropertiesRewritePolicy example. Thanks to Joel Edwards.
48 o LOG4J2-901: Update docs for SyslogAppender: "No structured id name was supplied" Thanks to Tihomir Meščić, Siegfried Greisinger.
49 o LOG4J2-958: Update from Jackson 2.5.0 to 2.5.1.
50 o LOG4J2-925: Update from Jackson 2.4.4 to 2.5.0.
51 o LOG4J2-910: Update Jackson from 2.4.3 to 2.4.4.
52 o LOG4J2-881: Update Jackson from 2.4.2 to 2.4.3.
53 o LOG4J2-882: Update maven-core from 3.1.0 to 3.2.3.
54 o LOG4J2-883: Update tests from org.apache.felix.framework 4.2.1 to 4.4.1.
55 o LOG4J2-884: Update org.eclipse.osgi from 3.6.0 to 3.7.1.
56 o LOG4J2-900: Update Apache Flume from 1.5.0.1 to 1.5.2.
77 o LOG4J2-1017: Update Java platform from Java 6 to 7. From this version onwards, log4j 2 requires Java 7.
78 o LOG4J2-812: PatternLayout timestamp formatting performance improvement: replaced synchronized SimpleDateFormat with
79 Apache Commons FastDateFormat. This and better caching resulted in a ~3-30X faster timestamp formatting.
80 o LOG4J2-1097: PatternLayout timestamp formatting performance improvement: predefined date formats (and variants using
81 a period '.' millisecond separator instead of ',') are now formatted ~2-10X faster than other date formats.
82 o LOG4J2-1096: Improved performance of ParameterizedMessage::getFormattedMessage by ~2X.
83 o LOG4J2-1120: LoggerConfig performance improvements: avoid unnecessary lock acquisition, use more efficient data structure.
84 o LOG4J2-1125: PatternLayout performance improvement by caching and reusing a ThreadLocal StringBuilder.
85 o LOG4J2-1114: Add thread name to status logger layout.
86 o LOG4J2-1010: Pass log event when interpolating logger properties.
87 o LOG4J2-1044: Support batchSize in FlumeAvroManager.
88 o LOG4J2-1065: Define org.apache.logging.log4j.Marker.equals(Object) and org.apache.logging.log4j.Marker.hashCode().
89 o LOG4J2-1063: Avoid creating temporary array object in org.apache.logging.slf4j.Log4jMarker.iterator().
90 o LOG4J2-890: log4j-web-2.1 should workaround a bug in JBOSS EAP 6.2. Thanks to Hassan Kalaldeh, Robert Andersson, Remko Popma.
91 o LOG4J2-403: MongoDB appender, username and password should be optional. Thanks to Poorna Subhash P, Jeremy Lautman.
92 o LOG4J2-1035: Log4j2 tries to SystemClassLoader when running on Google AppEngine.
93 o LOG4J2-1022: Allow a list of keys to be specified in the MDC pattern converter.
94 o LOG4J2-959: Fix FindBugs DM_DEFAULT_ENCODING bug in SimpleLogger.logMessage() and simplify code.
95 o LOG4J2-1036: Update Apache Flume from 1.5.2 to 1.6.0.
96 o LOG4J2-1041: Update MongoDB driver from 2.11.2 to 2.13.2.
97 o LOG4J2-1018: Update database tests from H2 1.3.175 to 1.3.176.
98 o LOG4J2-1070: Update Java Mail from 1.5.2 to 1.5.4.
99 o LOG4J2-1079: Update Jackson from 2.5.3 to 2.5.4.
100 o LOG4J2-1879: Update Jackson from 2.5.4 to 2.6.0.
101 o LOG4J2-1092: Update Jackson from 2.6.0 to 2.6.1.
102 o LOG4J2-1104: Update Apache Commons Compress from 1.9 to 1.10.
57103
104 Removed:
105 o Removed experimental interface LevelLogger which got committed to master by mistake.
58106
59 Apache Log4j 2.2 requires a minimum of Java 6 to build and run. Future releases may require a minimum
60 of Java 7.
107 Apache Log4j 2.4 requires a minimum of Java 7 to build and run. Log4j 2.4 and greater requires Java 7,
108 version 2.3 required Java 6.
61109
62110 Basic compatibility with Log4j 1.x is provided through the log4j-1.2-api component, however it does not implement some of the
63111 very implementation specific classes and methods. The package names and Maven groupId have been changed to
0 # -*- mode: ruby -*-
1 # vi: set ft=ruby :
2
3 # Licensed to the Apache Software Foundation (ASF) under one or more
4 # contributor license agreements. See the NOTICE file distributed with
5 # this work for additional information regarding copyright ownership.
6 # The ASF licenses this file to You under the Apache License, Version 2.0
7 # (the "License"); you may not use this file except in compliance with
8 # the License. You may obtain a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17
18 $script = <<SCRIPT
19 apt-get install --quiet --yes openjdk-6-jdk maven
20 SCRIPT
21
22 # Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
23 VAGRANTFILE_API_VERSION = "2"
24
25 Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
26 # All Vagrant configuration is done here. The most common configuration
27 # options are documented and commented below. For a complete reference,
28 # please see the online documentation at vagrantup.com.
29
30 # Every Vagrant virtual environment requires a box to build off of.
31 config.vm.box = "ubuntu/trusty64"
32
33 # Provision script
34 config.vm.provision "shell", inline: $script
35
36 # Disable automatic box update checking. If you disable this, then
37 # boxes will only be checked for updates when the user runs
38 # `vagrant box outdated`. This is not recommended.
39 # config.vm.box_check_update = false
40
41 # Create a forwarded port mapping which allows access to a specific port
42 # within the machine from a port on the host machine. In the example below,
43 # accessing "localhost:8080" will access port 80 on the guest machine.
44 # config.vm.network "forwarded_port", guest: 80, host: 8080
45
46 # Create a private network, which allows host-only access to the machine
47 # using a specific IP.
48 # config.vm.network "private_network", ip: "192.168.33.10"
49
50 # Create a public network, which generally matched to bridged network.
51 # Bridged networks make the machine appear as another physical device on
52 # your network.
53 # config.vm.network "public_network"
54
55 # If true, then any SSH connections made will enable agent forwarding.
56 # Default value: false
57 # config.ssh.forward_agent = true
58
59 # Provider-specific configuration so you can fine-tune various
60 # backing providers for Vagrant. These expose provider-specific options.
61 # Example for VirtualBox:
62 #
63 # config.vm.provider "virtualbox" do |vb|
64 # # Don't boot with headless mode
65 # vb.gui = true
66 #
67 # # Use VBoxManage to customize the VM. For example to change memory:
68 # vb.customize ["modifyvm", :id, "--memory", "1024"]
69 # end
70 #
71 # View the documentation for the provider you're using for more
72 # information on available options.
73
74 end
0 <?xml version="1.0" encoding="UTF-8"?>
10 <!DOCTYPE module PUBLIC
21 "-//Puppy Crawl//DTD Check Configuration 1.1//EN"
32 "http://www.puppycrawl.com/dtds/configuration_1_1.dtd">
6665 <!--<module name="SuppressionFilter">
6766 <property name="file" value="conf/checkstyle-suppressions.xml"/>
6867 </module> -->
68 <module name="SuppressionCommentFilter">
69 <property name="offCommentFormat" value="Check\:OFF\: ([\w\|]+)"/>
70 <property name="onCommentFormat" value="Check\:ON\: ([\w\|]+)"/>
71 <property name="checkFormat" value="$1"/>
72 </module>
6973
7074 <module name="TreeWalker">
7175
144148 <!--<module name="FileLength"/>-->
145149 <module name="LineLength">
146150 <property name="max" value="120"/>
151 <!-- Ignore import statements -->
152 <property name="ignorePattern" value="^import\s.*$"/>
147153 </module>
148154 <module name="MethodLength"/>
149155 <module name="ParameterNumber">
199205 <!-- <module name="InnerAssignment"/> -->
200206 <module name="MagicNumber">
201207 <property name="ignoreNumbers" value="-1,0,1,2,3,4,5,6,7"/>
202 </module>
203 <module name="RedundantThrows">
204 <property name="allowUnchecked" value="true"/>
205208 </module>
206209 <module name="SimplifyBooleanExpression"/>
207210 <module name="SimplifyBooleanReturn"/>
225228 </module>
226229
227230
228
229231 <!-- Miscellaneous other checks. -->
230232 <!-- See http://checkstyle.sf.net/config_misc.html -->
231233 <module name="ArrayTypeStyle"/>
234236 </module>
235237 <module name="UpperEll"/>
236238
239 <module name="HiddenField">
240 <property name="ignoreConstructorParameter" value="true"/>
241 <property name="ignoreSetter" value="true"/>
242 </module>
243
237244 </module>
238245
239246 </module>
0 <?xml version="1.0"?>
1 <?xml-stylesheet type="text/xsl"?>
2 <rdf:RDF xml:lang="en"
3 xmlns="http://usefulinc.com/ns/doap#"
4 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
5 xmlns:asfext="http://projects.apache.org/ns/asfext#"
6 xmlns:foaf="http://xmlns.com/foaf/0.1/">
7 <!--
8 Licensed to the Apache Software Foundation (ASF) under one or more
9 contributor license agreements. See the NOTICE file distributed with
10 this work for additional information regarding copyright ownership.
11 The ASF licenses this file to You under the Apache License, Version 2.0
12 (the "License"); you may not use this file except in compliance with
13 the License. You may obtain a copy of the License at
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22
23 -->
24 <Project rdf:about="http://logging.apache.org/log4j/2.x">
25 <created>2010-05-12</created>
26 <license rdf:resource="http://usefulinc.com/doap/licenses/asl20" />
27 <name>Apache log4j</name>
28 <homepage rdf:resource="http://logging.apache.org/log4j/2.x" />
29 <asfext:pmc rdf:resource="http://logging.apache.org" />
30 <shortdesc>Apache log4j provides logging services for Java.</shortdesc>
31 <bug-database rdf:resource="http://issues.apache.org/jira" />
32 <mailing-list rdf:resource="http://logging.apache.org/log4j/2.x/mail-lists.html" />
33 <download-page rdf:resource="http://logging.apache.org/log4j/2.x/download.html" />
34 <programming-language>Java</programming-language>
35 <category rdf:resource="http://projects.apache.org/category/library" />
36 <release>
37 <Version>
38 <name>Apache log4j 2</name>
39 <created>2015-05-09</created>
40 <revision>2.3</revision>
41 </Version>
42 <Version>
43 <name>Apache log4j 2</name>
44 <created>2015-02-26</created>
45 <revision>2.2</revision>
46 </Version>
47 <Version>
48 <name>Apache log4j 2</name>
49 <created>2014-10-24</created>
50 <revision>2.1</revision>
51 </Version>
52 <Version>
53 <name>Apache log4j 2</name>
54 <created>2014-07-17</created>
55 <revision>2.0</revision>
56 </Version>
57 </release>
58 <repository>
59 <SVNRepository>
60 <location rdf:resource="http://git-wip-us.apache.org/repos/asf/logging-log4j2.git"/>
61 <browse rdf:resource="https://git-wip-us.apache.org/repos/asf?p=logging-log4j2.git;a=tree"/>
62 </SVNRepository>
63 </repository>
64 </Project>
65 </rdf:RDF>
1919 <parent>
2020 <groupId>org.apache.logging.log4j</groupId>
2121 <artifactId>log4j</artifactId>
22 <version>2.2</version>
22 <version>2.4</version>
2323 <relativePath>../</relativePath>
2424 </parent>
2525 <artifactId>log4j-1.2-api</artifactId>
7474 <version>1.7</version>
7575 <scope>test</scope>
7676 </dependency>
77 <dependency>
78 <groupId>commons-io</groupId>
79 <artifactId>commons-io</artifactId>
80 <scope>test</scope>
81 </dependency>
7782 </dependencies>
7883 <build>
7984 <plugins>
4141 private static LoggerFactory loggerFactory = new PrivateFactory();
4242
4343 private static final Map<LoggerContext, ConcurrentMap<String, Logger>> CONTEXT_MAP =
44 new WeakHashMap<LoggerContext, ConcurrentMap<String, Logger>>();
44 new WeakHashMap<>();
4545
4646 private static final String FQCN = Category.class.getName();
4747
6666 * @param name The name of the Logger.
6767 */
6868 protected Category(final String name) {
69 this((LoggerContext) PrivateManager.getContext(), name);
69 this(PrivateManager.getContext(), name);
7070 }
7171
7272 private Category(final org.apache.logging.log4j.core.Logger logger) {
7474 }
7575
7676 public static Category getInstance(final String name) {
77 return getInstance((LoggerContext) PrivateManager.getContext(), name, loggerFactory);
78 }
79
80 static Category getInstance(final LoggerContext context, final String name) {
77 return getInstance(PrivateManager.getContext(), name, loggerFactory);
78 }
79
80 static Logger getInstance(final LoggerContext context, final String name) {
8181 return getInstance(context, name, loggerFactory);
8282 }
8383
84 static Category getInstance(final LoggerContext context, final String name, final LoggerFactory factory) {
84 static Logger getInstance(final LoggerContext context, final String name, final LoggerFactory factory) {
8585 final ConcurrentMap<String, Logger> loggers = getLoggersMap(context);
8686 Logger logger = loggers.get(name);
8787 if (logger != null) {
9696 return getInstance(clazz.getName());
9797 }
9898
99 static Category getInstance(final LoggerContext context, @SuppressWarnings("rawtypes") final Class clazz) {
99 static Logger getInstance(final LoggerContext context, @SuppressWarnings("rawtypes") final Class clazz) {
100100 return getInstance(context, clazz.getName());
101101 }
102102
122122 return getInstance(Strings.EMPTY);
123123 }
124124
125
126 static Category getRoot(final LoggerContext context) {
125 static Logger getRoot(final LoggerContext context) {
127126 return getInstance(context, Strings.EMPTY);
128127 }
129128
131130 synchronized (CONTEXT_MAP) {
132131 ConcurrentMap<String, Logger> map = CONTEXT_MAP.get(context);
133132 if (map == null) {
134 map = new ConcurrentHashMap<String, Logger>();
133 map = new ConcurrentHashMap<>();
135134 CONTEXT_MAP.put(context, map);
136135 }
137136 return map;
368367 String name = logger.getName();
369368 final ConcurrentMap<String, Logger> loggers = getLoggersMap(logger.getContext());
370369 while ((name = NameUtil.getSubName(name)) != null) {
371 if (loggers.containsKey(name)) {
372 final ResourceBundle rb = loggers.get(name).bundle;
370 final Logger subLogger = loggers.get(name);
371 if (subLogger != null) {
372 final ResourceBundle rb = subLogger.bundle;
373373 if (rb != null) {
374374 return rb;
375375 }
457457 private static class PrivateManager extends org.apache.logging.log4j.LogManager {
458458 private static final String FQCN = Category.class.getName();
459459
460 public static org.apache.logging.log4j.spi.LoggerContext getContext() {
461 return getContext(FQCN, false);
460 public static LoggerContext getContext() {
461 return (LoggerContext) getContext(FQCN, false);
462462 }
463463
464464 public static org.apache.logging.log4j.Logger getLogger(final String name) {
2020 import java.io.ObjectOutputStream;
2121 import java.io.ObjectStreamException;
2222 import java.io.Serializable;
23 import java.util.Locale;
2324
2425 import org.apache.logging.log4j.util.Strings;
2526
173174 if (sArg == null) {
174175 return defaultLevel;
175176 }
176
177 final String s = sArg.toUpperCase();
178
179 if (s.equals("ALL")) {
177 final String s = sArg.toUpperCase(Locale.ROOT);
178 switch (s) {
179 case "ALL":
180180 return Level.ALL;
181 }
182 if (s.equals("DEBUG")) {
181 case "DEBUG":
183182 return Level.DEBUG;
184 }
185 if (s.equals("INFO")) {
183 case "INFO":
186184 return Level.INFO;
187 }
188 if (s.equals("WARN")) {
185 case "WARN":
189186 return Level.WARN;
190 }
191 if (s.equals("ERROR")) {
187 case "ERROR":
192188 return Level.ERROR;
193 }
194 if (s.equals("FATAL")) {
189 case "FATAL":
195190 return Level.FATAL;
196 }
197 if (s.equals("OFF")) {
191 case "OFF":
198192 return Level.OFF;
199 }
200 if (s.equals("TRACE")) {
193 case "TRACE":
201194 return Level.TRACE;
202 }
203 //
204 // For Turkish i problem, see bug 40937
205 //
206 if (s.equals("\u0130NFO")) {
207 return Level.INFO;
208 }
209 return defaultLevel;
195 default:
196 return defaultLevel;
197 }
210198 }
211199
212200 /**
6666 }
6767
6868 public static Logger getRootLogger() {
69 return (Logger) Category.getInstance((LoggerContext) PrivateManager.getContext(), Strings.EMPTY);
69 return Category.getInstance(PrivateManager.getContext(), Strings.EMPTY);
7070 }
7171
7272 public static Logger getLogger(final String name) {
73 return (Logger) Category.getInstance((LoggerContext) PrivateManager.getContext(), name);
73 return Category.getInstance(PrivateManager.getContext(), name);
7474 }
7575
7676 public static Logger getLogger(@SuppressWarnings("rawtypes") final Class clazz) {
77 return (Logger) Category.getInstance((LoggerContext) PrivateManager.getContext(), clazz.getName());
77 return Category.getInstance(PrivateManager.getContext(), clazz.getName());
7878 }
7979
8080 public static Logger getLogger(final String name, final LoggerFactory factory) {
81 return (Logger) Category.getInstance((LoggerContext) PrivateManager.getContext(), name);
81 return Category.getInstance(PrivateManager.getContext(), name);
8282 }
8383
8484 public static Logger exists(final String name) {
85 final LoggerContext ctx = (LoggerContext) PrivateManager.getContext();
85 final LoggerContext ctx = PrivateManager.getContext();
8686 if (!ctx.hasLogger(name)) {
8787 return null;
8888 }
9595 }
9696
9797 static void reconfigure() {
98 final LoggerContext ctx = (LoggerContext) PrivateManager.getContext();
98 final LoggerContext ctx = PrivateManager.getContext();
9999 ctx.reconfigure();
100100 }
101101
161161
162162 @Override
163163 public Logger getLogger(final String name) {
164 return (Logger) Category.getInstance((LoggerContext) PrivateManager.getContext(), name);
164 return Category.getInstance(PrivateManager.getContext(), name);
165165 }
166166
167167 @Override
168168 public Logger getLogger(final String name, final LoggerFactory factory) {
169 return (Logger) Category.getInstance((LoggerContext) PrivateManager.getContext(), name);
169 return Category.getInstance(PrivateManager.getContext(), name);
170170 }
171171
172172 @Override
173173 public Logger getRootLogger() {
174 return (Logger) Category.getRoot((LoggerContext) PrivateManager.getContext());
174 return Category.getRoot(PrivateManager.getContext());
175175 }
176176
177177 @Override
210210 private static class PrivateManager extends org.apache.logging.log4j.LogManager {
211211 private static final String FQCN = LogManager.class.getName();
212212
213
214 public static org.apache.logging.log4j.spi.LoggerContext getContext() {
215 return getContext(FQCN, false);
213 public static LoggerContext getContext() {
214 return (LoggerContext) getContext(FQCN, false);
216215 }
217216
218217 public static org.apache.logging.log4j.Logger getLogger(final String name) {
2525 public class Logger extends Category {
2626
2727 protected Logger(final String name) {
28 super((LoggerContext) PrivateManager.getContext(), name);
28 super(PrivateManager.getContext(), name);
2929 }
3030
3131 Logger(final LoggerContext context, final String name) {
3333 }
3434
3535 public static Logger getLogger(final String name) {
36 return (Logger) Category.getInstance((LoggerContext) PrivateManager.getContext(), name);
36 return Category.getInstance(PrivateManager.getContext(), name);
3737 }
3838
3939 public static Logger getLogger(final Class<?> clazz) {
40 return (Logger) Category.getInstance((LoggerContext) PrivateManager.getContext(), clazz);
40 return Category.getInstance(PrivateManager.getContext(), clazz);
4141 }
4242
4343 public static Logger getRootLogger() {
44 return (Logger) Category.getRoot((LoggerContext) PrivateManager.getContext());
44 return Category.getRoot(PrivateManager.getContext());
4545 }
4646
4747 public static Logger getLogger(final String name, final LoggerFactory factory) {
48 return (Logger) Category.getInstance((LoggerContext) PrivateManager.getContext(), name, factory);
48 return Category.getInstance(PrivateManager.getContext(), name, factory);
4949 }
5050
5151 /**
5454 private static class PrivateManager extends org.apache.logging.log4j.LogManager {
5555 private static final String FQCN = Logger.class.getName();
5656
57 public static org.apache.logging.log4j.spi.LoggerContext getContext() {
58 return getContext(FQCN, false);
57 public static LoggerContext getContext() {
58 return (LoggerContext) getContext(FQCN, false);
5959 }
6060
6161 public static org.apache.logging.log4j.Logger getLogger(final String name) {
3232 new InheritableThreadLocal<Map<String, Object>>() {
3333 @Override
3434 protected Map<String, Object> initialValue() {
35 return new HashMap<String, Object>();
35 return new HashMap<>();
3636 }
3737
3838 @Override
3939 protected Map<String, Object> childValue(final Map<String, Object> parentValue) {
40 return parentValue == null ? new HashMap<String, Object>() : new HashMap<String, Object>(parentValue);
40 return parentValue == null ? new HashMap<String, Object>() : new HashMap<>(parentValue);
4141 }
4242 };
4343
7171 }
7272
7373 public static Hashtable<String, Object> getContext() {
74 return new Hashtable<String, Object>(localMap.get());
74 return new Hashtable<>(localMap.get());
7575 }
7676 }
5555 */
5656 @SuppressWarnings("rawtypes")
5757 public static Stack cloneStack() {
58 final Stack<String> stack = new Stack<String>();
58 final Stack<String> stack = new Stack<>();
5959 for (final String element : org.apache.logging.log4j.ThreadContext.cloneStack().asList()) {
6060 stack.push(element);
6161 }
3333
3434 <section name="Requirements">
3535 <p>
36 The Log4j 1.2 bridge requires at least Java 6 and is dependent on the Log4j 2 API and implementation.
36 The Log4j 1.2 bridge is dependent on the Log4j 2 API and implementation.
3737 </p>
3838 </section>
3939
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.log4j;
17
18 import java.util.List;
19
20 import org.apache.logging.log4j.junit.InitialLoggerContext;
21 import org.apache.logging.log4j.test.appender.ListAppender;
22 import org.junit.Rule;
23 import org.junit.Test;
24
25 import static org.junit.Assert.assertEquals;
26
27 public class CallerInformationTest {
28
29 // config from log4j-core test-jar
30 private static final String CONFIG = "log4j2-calling-class.xml";
31
32 @Rule
33 public final InitialLoggerContext ctx = new InitialLoggerContext(CONFIG);
34
35 @Test
36 public void testClassLogger() throws Exception {
37 final ListAppender app = ctx.getListAppender("Class").clear();
38 final Logger logger = Logger.getLogger("ClassLogger");
39 logger.info("Ignored message contents.");
40 logger.warn("Verifying the caller class is still correct.");
41 logger.error("Hopefully nobody breaks me!");
42 final List<String> messages = app.getMessages();
43 assertEquals("Incorrect number of messages.", 3, messages.size());
44 for (final String message : messages) {
45 assertEquals("Incorrect caller class name.", this.getClass().getName(), message);
46 }
47 }
48
49 @Test
50 public void testMethodLogger() throws Exception {
51 final ListAppender app = ctx.getListAppender("Method").clear();
52 final Logger logger = Logger.getLogger("MethodLogger");
53 logger.info("More messages.");
54 logger.warn("CATASTROPHE INCOMING!");
55 logger.error("ZOMBIES!!!");
56 logger.warn("brains~~~");
57 logger.info("Itchy. Tasty.");
58 final List<String> messages = app.getMessages();
59 assertEquals("Incorrect number of messages.", 5, messages.size());
60 for (final String message : messages) {
61 assertEquals("Incorrect caller method name.", "testMethodLogger", message);
62 }
63 }
64 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.log4j;
17
18 import static org.junit.Assert.assertEquals;
19
20 import java.util.List;
21
22 import org.apache.logging.log4j.junit.LoggerContextRule;
23 import org.apache.logging.log4j.test.appender.ListAppender;
24 import org.junit.ClassRule;
25 import org.junit.Test;
26
27 public class CallerInformationTest {
28
29 // config from log4j-core test-jar
30 private static final String CONFIG = "log4j2-calling-class.xml";
31
32 @ClassRule
33 public static final LoggerContextRule ctx = new LoggerContextRule(CONFIG);
34
35 @Test
36 public void testClassLogger() throws Exception {
37 final ListAppender app = ctx.getListAppender("Class").clear();
38 final Logger logger = Logger.getLogger("ClassLogger");
39 logger.info("Ignored message contents.");
40 logger.warn("Verifying the caller class is still correct.");
41 logger.error("Hopefully nobody breaks me!");
42 final List<String> messages = app.getMessages();
43 assertEquals("Incorrect number of messages.", 3, messages.size());
44 for (final String message : messages) {
45 assertEquals("Incorrect caller class name.", this.getClass().getName(), message);
46 }
47 }
48
49 @Test
50 public void testMethodLogger() throws Exception {
51 final ListAppender app = ctx.getListAppender("Method").clear();
52 final Logger logger = Logger.getLogger("MethodLogger");
53 logger.info("More messages.");
54 logger.warn("CATASTROPHE INCOMING!");
55 logger.error("ZOMBIES!!!");
56 logger.warn("brains~~~");
57 logger.info("Itchy. Tasty.");
58 final List<String> messages = app.getMessages();
59 assertEquals("Incorrect number of messages.", 5, messages.size());
60 for (final String message : messages) {
61 assertEquals("Incorrect caller method name.", "testMethodLogger", message);
62 }
63 }
64 }
1616
1717 package org.apache.log4j;
1818
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.assertTrue;
22
1923 import java.lang.reflect.Method;
2024 import java.util.List;
2125
2832 import org.apache.logging.log4j.message.Message;
2933 import org.apache.logging.log4j.message.ObjectMessage;
3034 import org.apache.logging.log4j.test.appender.ListAppender;
35 import org.apache.logging.log4j.util.Strings;
3136 import org.junit.AfterClass;
3237 import org.junit.Before;
3338 import org.junit.BeforeClass;
3439 import org.junit.Test;
3540
36 import static org.junit.Assert.*;
37
3841
3942 /**
4043 * Tests of Category.
4952 public static void setupClass() {
5053 appender.start();
5154 ConfigurationFactory.setConfigurationFactory(cf);
52 final LoggerContext ctx = (LoggerContext) org.apache.logging.log4j.LogManager.getContext();
53 ctx.reconfigure();
55 LoggerContext.getContext().reconfigure();
5456 }
5557
5658 @AfterClass
178180 appender.clear();
179181 final String threadName = Thread.currentThread().getName();
180182 final String expected = "ERROR o.a.l.CategoryTest [" + threadName + "] Test Message" + Constants.LINE_SEPARATOR;
181 assertTrue("Incorrect message \"" + msg + '"' + " expected \"" + expected + '"', msg.endsWith(expected));
183 assertTrue("Incorrect message " + Strings.dquote(msg) + " expected " + Strings.dquote(expected), msg.endsWith(expected));
182184 }
183185
184186 /**
214214 */
215215 @Test
216216 public void testIntToAll() {
217 final Level level = Level.toLevel(Level.ALL_INT);
217 final Level level = Level.toLevel(Priority.ALL_INT);
218218 assertEquals("ALL", level.toString());
219219 }
220220
223223 */
224224 @Test
225225 public void testIntToFatal() {
226 final Level level = Level.toLevel(Level.FATAL_INT);
226 final Level level = Level.toLevel(Priority.FATAL_INT);
227227 assertEquals("FATAL", level.toString());
228228 }
229229
233233 */
234234 @Test
235235 public void testIntToOff() {
236 final Level level = Level.toLevel(Level.OFF_INT);
236 final Level level = Level.toLevel(Priority.OFF_INT);
237237 assertEquals("OFF", level.toString());
238238 }
239239
7272
7373 @After
7474 public void tearDown() {
75 final LoggerContext ctx = (LoggerContext) org.apache.logging.log4j.LogManager.getContext();
76 ctx.reconfigure();
75 LoggerContext.getContext().reconfigure();
7776 a1 = null;
7877 a2 = null;
7978 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.log4j;
17
18 import org.apache.logging.log4j.junit.InitialLoggerContext;
19 import org.junit.ClassRule;
20 import org.junit.Test;
21
22 import static org.junit.Assert.*;
23
24 /**
25 *
26 */
27 public class LoggingTest {
28
29 private static final String CONFIG = "log4j2-config.xml";
30
31 @ClassRule
32 public static final InitialLoggerContext CTX = new InitialLoggerContext(CONFIG);
33
34 @Test
35 public void testParent() {
36 final Logger logger = Logger.getLogger("org.apache.test.logging.Test");
37 final Category parent = logger.getParent();
38 assertNotNull("No parent Logger", parent);
39 assertEquals("Incorrect parent logger", "org.apache.test.logging", parent.getName());
40 }
41
42 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.log4j;
17
18 import org.apache.logging.log4j.junit.LoggerContextRule;
19 import org.junit.ClassRule;
20 import org.junit.Test;
21
22 import static org.junit.Assert.*;
23
24 /**
25 *
26 */
27 public class LoggingTest {
28
29 private static final String CONFIG = "log4j2-config.xml";
30
31 @ClassRule
32 public static final LoggerContextRule CTX = new LoggerContextRule(CONFIG);
33
34 @Test
35 public void testParent() {
36 final Logger logger = Logger.getLogger("org.apache.test.logging.Test");
37 final Category parent = logger.getParent();
38 assertNotNull("No parent Logger", parent);
39 assertEquals("Incorrect parent logger", "org.apache.test.logging", parent.getName());
40 }
41
42 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.log4j;
17
18 import org.junit.After;
19 import org.junit.Assert;
20 import org.junit.Before;
21 import org.junit.Test;
22
23 public class MDCTestCase {
24
25 @Before
26 public void setUp() {
27 MDC.clear();
28 }
29
30 @After
31 public void tearDown() {
32 MDC.clear();
33 }
34
35 @Test
36 public void testPut() throws Exception {
37 MDC.put("key", "some value");
38 Assert.assertEquals("some value", MDC.get("key"));
39 Assert.assertEquals(1, MDC.getContext().size());
40 }
41
42 @Test
43 public void testRemoveLastKey() throws Exception {
44 MDC.put("key", "some value");
45 MDC.remove("key");
46 }
47
48 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.log4j;
17
18 import org.apache.logging.log4j.util.Strings;
19 import org.junit.Assert;
20 import org.junit.Test;
21
22 public class NDCTest {
23
24 @Test
25 public void testPopEmpty() {
26 NDC.clear();
27 Assert.assertEquals(Strings.EMPTY, NDC.pop());
28 }
29
30 @Test
31 public void testPeekEmpty() {
32 NDC.clear();
33 Assert.assertEquals(Strings.EMPTY, NDC.peek());
34 }
35 }
1717
1818 import java.io.StringWriter;
1919
20 import org.apache.logging.log4j.LogManager;
2120 import org.apache.logging.log4j.core.LoggerContext;
2221 import org.apache.logging.log4j.core.config.Configurator;
2322 import org.apache.logging.log4j.status.StatusLogger;
3736
3837 @BeforeClass
3938 public static void setupClass() {
40 context = (LoggerContext) LogManager.getContext(false);
39 context = LoggerContext.getContext(false);
4140 }
4241
4342 @AfterClass
1616
1717 package org.apache.log4j.util;
1818
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.fail;
21
1922 import java.io.ByteArrayInputStream;
2023 import java.io.ByteArrayOutputStream;
2124 import java.io.File;
2225 import java.io.FileInputStream;
23 import java.io.FileOutputStream;
2426 import java.io.IOException;
2527 import java.io.ObjectInputStream;
2628 import java.io.ObjectOutputStream;
2729
28 import static org.junit.Assert.*;
30 import org.apache.commons.io.FileUtils;
2931
3032
3133 /**
5052 public static Object serializeClone(final Object obj)
5153 throws IOException, ClassNotFoundException {
5254 final ByteArrayOutputStream memOut = new ByteArrayOutputStream();
53 final ObjectOutputStream objOut = new ObjectOutputStream(memOut);
54 objOut.writeObject(obj);
55 objOut.close();
55 try (final ObjectOutputStream objOut = new ObjectOutputStream(memOut)) {
56 objOut.writeObject(obj);
57 }
5658
5759 final ByteArrayInputStream src = new ByteArrayInputStream(memOut.toByteArray());
5860 final ObjectInputStream objIs = new ObjectInputStream(src);
6870 * @throws Exception thrown on IO or deserialization exception.
6971 */
7072 public static Object deserializeStream(final String witness) throws Exception {
71 final FileInputStream fileIs = new FileInputStream(witness);
72 final ObjectInputStream objIs = new ObjectInputStream(fileIs);
73 try {
73 try (final ObjectInputStream objIs = new ObjectInputStream(new FileInputStream(witness))) {
7474 return objIs.readObject();
75 } finally {
76 objIs.close();
7775 }
7876 }
7977
9189 final String witness, final Object obj, final int[] skip,
9290 final int endCompare) throws Exception {
9391 final ByteArrayOutputStream memOut = new ByteArrayOutputStream();
94 final ObjectOutputStream objOut = new ObjectOutputStream(memOut);
95 objOut.writeObject(obj);
96 objOut.close();
92 try (final ObjectOutputStream objOut = new ObjectOutputStream(memOut)) {
93 objOut.writeObject(obj);
94 }
9795
9896 assertStreamEquals(witness, memOut.toByteArray(), skip, endCompare);
9997 }
114112
115113 if (witnessFile.exists()) {
116114 int skipIndex = 0;
117 final byte[] expected = new byte[actual.length];
118 final FileInputStream is = new FileInputStream(witnessFile);
119 final int bytesRead = is.read(expected);
120 is.close();
115 final byte[] expected = FileUtils.readFileToByteArray(witnessFile);
116 final int bytesRead = expected.length;
121117
122118 if (bytesRead < endCompare) {
123119 assertEquals(bytesRead, actual.length);
143139 //
144140 // if the file doesn't exist then
145141 // assume that we are setting up and need to write it
146 final FileOutputStream os = new FileOutputStream(witnessFile);
147 os.write(actual);
148 os.close();
142 FileUtils.writeByteArrayToFile(witnessFile, actual);
149143 fail("Writing witness file " + witness);
150144 }
151145 }
1919 <parent>
2020 <groupId>org.apache.logging.log4j</groupId>
2121 <artifactId>log4j</artifactId>
22 <version>2.2</version>
22 <version>2.4</version>
2323 <relativePath>../</relativePath>
2424 </parent>
2525 <artifactId>log4j-api</artifactId>
1919 import org.apache.logging.log4j.spi.ExtendedLogger;
2020
2121 /**
22 * Logs "Events" that are represented as StructuredDataMessages.
22 * Logs "Events" that are represented as {@link StructuredDataMessage}.
2323 */
2424 public final class EventLogger {
2525
2626 private static final String NAME = "EventLogger";
2727
2828 /**
29 * Define the Event Marker.
29 * Defines the Event Marker.
3030 */
3131 public static final Marker EVENT_MARKER = MarkerManager.getMarker("EVENT");
3232
3535 private static final ExtendedLogger LOGGER = LogManager.getContext(false).getLogger(NAME);
3636
3737 private EventLogger() {
38 // empty
3839 }
3940
4041 /**
41 * Log events with a level of ALL.
42 * Logs events with a level of ALL.
4243 * @param msg The event StructuredDataMessage.
4344 */
4445 public static void logEvent(final StructuredDataMessage msg) {
4647 }
4748
4849 /**
49 * Log events and specify the logging level.
50 * Logs events and specify the logging level.
5051 * @param msg The event StructuredDataMessage.
5152 * @param level The logging Level.
5253 */
1818 import java.io.Serializable;
1919 import java.util.Collection;
2020 import java.util.Locale;
21 import java.util.Objects;
2122 import java.util.concurrent.ConcurrentHashMap;
2223 import java.util.concurrent.ConcurrentMap;
2324
4344 public final class Level implements Comparable<Level>, Serializable {
4445
4546 private static final long serialVersionUID = 1581082L;
46 private static final ConcurrentMap<String, Level> levels = new ConcurrentHashMap<String, Level>();
47 private static final ConcurrentMap<String, Level> levels = new ConcurrentHashMap<>();
4748
4849 /**
4950 * No events will be logged.
139140 }
140141
141142 /**
143 * Compares this level against the levels passed as arguments and returns true if this level is in between the given levels.
144 *
145 * @param minLevel
146 * The minimum level to test.
147 * @param maxLevel
148 * The maximum level to test.
149 * @return True true if this level is in between the given levels
150 * @since 2.4
151 */
152 public boolean isInRange(final Level minLevel, final Level maxLevel) {
153 return this.intLevel >= minLevel.intLevel && this.intLevel <= maxLevel.intLevel;
154 }
155
156 /**
142157 * Compares this level against the level passed as an argument and returns true if this level is the same or is less
143158 * specific.T
144159 *
275290 * @throws java.lang.IllegalArgumentException if the Level name is not registered.
276291 */
277292 public static Level valueOf(final String name) {
278 if (name == null) {
279 throw new NullPointerException("No level name given.");
280 }
293 Objects.requireNonNull(name, "No level name given.");
281294 final String levelName = name.toUpperCase(Locale.ENGLISH);
282 if (levels.containsKey(levelName)) {
283 return levels.get(levelName);
295 final Level level = levels.get(levelName);
296 if (level != null) {
297 return level;
284298 }
285299 throw new IllegalArgumentException("Unknown level constant [" + levelName + "].");
286300 }
8484 }
8585
8686 if (factory == null) {
87 final SortedMap<Integer, LoggerContextFactory> factories = new TreeMap<Integer, LoggerContextFactory>();
87 final SortedMap<Integer, LoggerContextFactory> factories = new TreeMap<>();
8888 // note that the following initial call to ProviderUtil may block until a Provider has been installed when
8989 // running in an OSGi environment
9090 if (ProviderUtil.hasProviders()) {
103103 if (factories.isEmpty()) {
104104 LOGGER.error("Log4j2 could not find a logging implementation. Please add log4j-core to the classpath. Using SimpleLogger to log to the console...");
105105 factory = new SimpleLoggerContextFactory();
106 } else if (factories.size() == 1) {
107 factory = factories.get(factories.lastKey());
106108 } else {
107109 final StringBuilder sb = new StringBuilder("Multiple logging implementations found: \n");
108110 for (final Map.Entry<Integer, LoggerContextFactory> entry : factories.entrySet()) {
302304 public static void setFactory(final LoggerContextFactory factory) {
303305 LogManager.factory = factory;
304306 }
307
308 /**
309 * Returns a formatter Logger using the fully qualified name of the calling Class as the Logger name.
310 * <p>
311 * This logger lets you use a {@link java.util.Formatter} string in the message to format parameters.
312 * </p>
313 * @return The Logger for the calling class.
314 * @throws UnsupportedOperationException if the calling class cannot be determined.
315 * @since 2.4
316 */
317 public static Logger getFormatterLogger() {
318 return getFormatterLogger(ReflectionUtil.getCallerClass(2));
319 }
320
305321
306322 /**
307323 * Returns a formatter Logger using the fully qualified name of the Class as the Logger name.
398414 StringFormatterMessageFactory.INSTANCE);
399415 }
400416
417 private static Class<?> callerClass(final Class<?> clazz) {
418 if (clazz != null) {
419 return clazz;
420 }
421 final Class<?> candidate = ReflectionUtil.getCallerClass(3);
422 if (candidate == null) {
423 throw new UnsupportedOperationException("No class provided, and an appropriate one cannot be found.");
424 }
425 return candidate;
426 }
427
401428 /**
402429 * Returns a Logger with the name of the calling class.
403430 * @return The Logger for the calling class.
415442 * @throws UnsupportedOperationException if {@code clazz} is {@code null} and the calling class cannot be determined.
416443 */
417444 public static Logger getLogger(final Class<?> clazz) {
418 if (clazz == null) {
419 final Class<?> candidate = ReflectionUtil.getCallerClass(2);
420 if (candidate == null) {
421 throw new UnsupportedOperationException("No class provided, and an appropriate one cannot be found.");
422 }
423 return getLogger(candidate);
424 }
425 return getContext(clazz.getClassLoader(), false).getLogger(clazz.getName());
445 final Class<?> cls = callerClass(clazz);
446 return getContext(cls.getClassLoader(), false).getLogger(cls.getName());
426447 }
427448
428449 /**
435456 * @throws UnsupportedOperationException if {@code clazz} is {@code null} and the calling class cannot be determined.
436457 */
437458 public static Logger getLogger(final Class<?> clazz, final MessageFactory messageFactory) {
438 if (clazz == null) {
439 final Class<?> candidate = ReflectionUtil.getCallerClass(2);
440 if (candidate == null) {
441 throw new UnsupportedOperationException("No class provided, and an appropriate one cannot be found.");
442 }
443 return getLogger(candidate, messageFactory);
444 }
445 return getContext(clazz.getClassLoader(), false).getLogger(clazz.getName(), messageFactory);
459 final Class<?> cls = callerClass(clazz);
460 return getContext(cls.getClassLoader(), false).getLogger(cls.getName(), messageFactory);
446461 }
447462
448463 /**
1717
1818 import org.apache.logging.log4j.message.Message;
1919 import org.apache.logging.log4j.message.MessageFactory;
20 import org.apache.logging.log4j.util.MessageSupplier;
21 import org.apache.logging.log4j.util.Supplier;
2022
2123 /**
2224 * This is the central interface in the log4j package. Most logging operations, except configuration, are done through
4143 * For service provider implementations, it is recommended to extend the
4244 * {@link org.apache.logging.log4j.spi.AbstractLogger} class rather than implementing this interface directly.
4345 * </p>
46 *
47 * Since 2.4, methods have been added to the {@code Logger} interface to support lambda expressions.
48 * The new methods allow client code to lazily log messages without explicitly checking if the requested log level is
49 * enabled. For example, previously one would write:
50 *
51 * <pre>
52 * // pre-Java 8 style optimization: explicitly check the log level
53 * // to make sure the expensiveOperation() method is only called if necessary
54 * if (logger.isTraceEnabled()) {
55 * logger.trace(&quot;Some long-running operation returned {}&quot;, expensiveOperation());
56 * }</pre>
57 * <p>
58 * With Java 8, the same effect can be achieved with a lambda expression:
59 *
60 * <pre>
61 * // Java-8 style optimization: no need to explicitly check the log level:
62 * // the lambda expression is not evaluated if the TRACE level is not enabled
63 * logger.trace(&quot;Some long-running operation returned {}&quot;, () -&gt; expensiveOperation());
64 * </pre>
4465 */
4566 public interface Logger {
4667
80101 void debug(Marker marker, Message msg, Throwable t);
81102
82103 /**
104 * Logs a message which is only to be constructed if the logging level is the {@link Level#DEBUG DEBUG} level with
105 * the specified Marker. The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the
106 * {@code Message}.
107 *
108 * @param marker the marker data specific to this log statement
109 * @param msgSupplier A function, which when called, produces the desired log message.
110 * @since 2.4
111 */
112 void debug(Marker marker, MessageSupplier msgSupplier);
113
114 /**
115 * Logs a message (only to be constructed if the logging level is the {@link Level#DEBUG DEBUG} level) with the
116 * specified Marker and including the stack trace of the {@link Throwable} <code>t</code> passed as parameter. The
117 * {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
118 *
119 * @param marker the marker data specific to this log statement
120 * @param msgSupplier A function, which when called, produces the desired log message.
121 * @param t A Throwable or null.
122 * @since 2.4
123 */
124 void debug(Marker marker, MessageSupplier msgSupplier, Throwable t);
125
126 /**
83127 * Logs a message object with the {@link Level#DEBUG DEBUG} level.
84128 *
85129 * @param marker the marker data specific to this log statement
116160 void debug(Marker marker, String message, Object... params);
117161
118162 /**
163 * Logs a message with parameters which are only to be constructed if the logging level is the {@link Level#DEBUG
164 * DEBUG} level.
165 *
166 * @param marker the marker data specific to this log statement
167 * @param message the message to log; the format depends on the message factory.
168 * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
169 * @since 2.4
170 */
171 void debug(Marker marker, String message, Supplier<?>... paramSuppliers);
172
173 /**
119174 * Logs a message at the {@link Level#DEBUG DEBUG} level including the stack trace of the {@link Throwable}
120175 * <code>t</code> passed as parameter.
121176 *
126181 void debug(Marker marker, String message, Throwable t);
127182
128183 /**
184 * Logs a message which is only to be constructed if the logging level is the {@link Level#DEBUG DEBUG} level with
185 * the specified Marker.
186 *
187 * @param marker the marker data specific to this log statement
188 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
189 * message factory.
190 * @since 2.4
191 */
192 void debug(Marker marker, Supplier<?> msgSupplier);
193
194 /**
195 * Logs a message (only to be constructed if the logging level is the {@link Level#DEBUG DEBUG} level) with the
196 * specified Marker and including the stack trace of the {@link Throwable} <code>t</code> passed as parameter.
197 *
198 * @param marker the marker data specific to this log statement
199 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
200 * message factory.
201 * @param t A Throwable or null.
202 * @since 2.4
203 */
204 void debug(Marker marker, Supplier<?> msgSupplier, Throwable t);
205
206 /**
129207 * Logs a message with the specific Marker at the {@link Level#DEBUG DEBUG} level.
130208 *
131209 * @param msg the message string to be logged
139217 * @param t A Throwable or null.
140218 */
141219 void debug(Message msg, Throwable t);
220
221 /**
222 * Logs a message which is only to be constructed if the logging level is the {@link Level#DEBUG DEBUG} level. The
223 * {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
224 *
225 * @param msgSupplier A function, which when called, produces the desired log message.
226 * @since 2.4
227 */
228 void debug(MessageSupplier msgSupplier);
229
230 /**
231 * Logs a message (only to be constructed if the logging level is the {@link Level#DEBUG DEBUG} level) including the
232 * stack trace of the {@link Throwable} <code>t</code> passed as parameter. The {@code MessageSupplier} may or may
233 * not use the {@link MessageFactory} to construct the {@code Message}.
234 *
235 * @param msgSupplier A function, which when called, produces the desired log message.
236 * @param t the exception to log, including its stack trace.
237 * @since 2.4
238 */
239 void debug(MessageSupplier msgSupplier, Throwable t);
142240
143241 /**
144242 * Logs a message object with the {@link Level#DEBUG DEBUG} level.
173271 void debug(String message, Object... params);
174272
175273 /**
274 * Logs a message with parameters which are only to be constructed if the logging level is the {@link Level#DEBUG
275 * DEBUG} level.
276 *
277 * @param message the message to log; the format depends on the message factory.
278 * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
279 * @since 2.4
280 */
281 void debug(String message, Supplier<?>... paramSuppliers);
282
283 /**
176284 * Logs a message at the {@link Level#DEBUG DEBUG} level including the stack trace of the {@link Throwable}
177285 * <code>t</code> passed as parameter.
178286 *
180288 * @param t the exception to log, including its stack trace.
181289 */
182290 void debug(String message, Throwable t);
291
292 /**
293 * Logs a message which is only to be constructed if the logging level is the {@link Level#DEBUG DEBUG} level.
294 *
295 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
296 * message factory.
297 * @since 2.4
298 */
299 void debug(Supplier<?> msgSupplier);
300
301 /**
302 * Logs a message (only to be constructed if the logging level is the {@link Level#DEBUG DEBUG} level) including the
303 * stack trace of the {@link Throwable} <code>t</code> passed as parameter.
304 *
305 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
306 * message factory.
307 * @param t the exception to log, including its stack trace.
308 * @since 2.4
309 */
310 void debug(Supplier<?> msgSupplier, Throwable t);
183311
184312 /**
185313 * Logs entry to a method. Used when the method in question has no parameters or when the parameters should not be
224352 void error(Marker marker, Message msg, Throwable t);
225353
226354 /**
355 * Logs a message which is only to be constructed if the logging level is the {@link Level#ERROR ERROR} level with
356 * the specified Marker.
357 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
358 *
359 * @param marker the marker data specific to this log statement
360 * @param msgSupplier A function, which when called, produces the desired log message.
361 * @since 2.4
362 */
363 void error(Marker marker, MessageSupplier msgSupplier);
364
365 /**
366 * Logs a message (only to be constructed if the logging level is the {@link Level#ERROR ERROR} level) with the
367 * specified Marker and including the stack trace of the {@link Throwable} <code>t</code> passed as parameter.
368 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
369 *
370 * @param marker the marker data specific to this log statement
371 * @param msgSupplier A function, which when called, produces the desired log message.
372 * @param t A Throwable or null.
373 * @since 2.4
374 */
375 void error(Marker marker, MessageSupplier msgSupplier, Throwable t);
376
377 /**
227378 * Logs a message object with the {@link Level#ERROR ERROR} level.
228379 *
229380 * @param marker the marker data specific to this log statement.
265416 void error(Marker marker, String message, Object... params);
266417
267418 /**
419 * Logs a message with parameters which are only to be constructed if the logging level is the {@link Level#ERROR
420 * ERROR} level.
421 *
422 * @param marker the marker data specific to this log statement
423 * @param message the message to log; the format depends on the message factory.
424 * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
425 * @since 2.4
426 */
427 void error(Marker marker, String message, Supplier<?>... paramSuppliers);
428
429 /**
268430 * Logs a message at the {@link Level#ERROR ERROR} level including the stack trace of the {@link Throwable}
269431 * <code>t</code> passed as parameter.
270432 *
275437 void error(Marker marker, String message, Throwable t);
276438
277439 /**
440 * Logs a message which is only to be constructed if the logging level is the {@link Level#ERROR ERROR} level with
441 * the specified Marker.
442 *
443 * @param marker the marker data specific to this log statement
444 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
445 * message factory.
446 * @since 2.4
447 */
448 void error(Marker marker, Supplier<?> msgSupplier);
449
450 /**
451 * Logs a message (only to be constructed if the logging level is the {@link Level#ERROR ERROR} level) with the
452 * specified Marker and including the stack trace of the {@link Throwable} <code>t</code> passed as parameter.
453 *
454 * @param marker the marker data specific to this log statement
455 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
456 * message factory.
457 * @param t A Throwable or null.
458 * @since 2.4
459 */
460 void error(Marker marker, Supplier<?> msgSupplier, Throwable t);
461
462 /**
278463 * Logs a message with the specific Marker at the {@link Level#ERROR ERROR} level.
279464 *
280465 * @param msg the message string to be logged
288473 * @param t A Throwable or null.
289474 */
290475 void error(Message msg, Throwable t);
476
477 /**
478 * Logs a message which is only to be constructed if the logging level is the {@link Level#ERROR ERROR} level.
479 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
480 *
481 * @param msgSupplier A function, which when called, produces the desired log message.
482 * @since 2.4
483 */
484 void error(MessageSupplier msgSupplier);
485
486 /**
487 * Logs a message (only to be constructed if the logging level is the {@link Level#ERROR ERROR} level) including the
488 * stack trace of the {@link Throwable} <code>t</code> passed as parameter.
489 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
490 *
491 * @param msgSupplier A function, which when called, produces the desired log message.
492 * @param t the exception to log, including its stack trace.
493 * @since 2.4
494 */
495 void error(MessageSupplier msgSupplier, Throwable t);
291496
292497 /**
293498 * Logs a message object with the {@link Level#ERROR ERROR} level.
327532 void error(String message, Object... params);
328533
329534 /**
535 * Logs a message with parameters which are only to be constructed if the logging level is the {@link Level#ERROR
536 * ERROR} level.
537 *
538 * @param message the message to log; the format depends on the message factory.
539 * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
540 * @since 2.4
541 */
542 void error(String message, Supplier<?>... paramSuppliers);
543
544 /**
330545 * Logs a message at the {@link Level#ERROR ERROR} level including the stack trace of the {@link Throwable}
331546 * <code>t</code> passed as parameter.
332547 *
334549 * @param t the exception to log, including its stack trace.
335550 */
336551 void error(String message, Throwable t);
552
553 /**
554 * Logs a message which is only to be constructed if the logging level is the {@link Level#ERROR ERROR} level.
555 *
556 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
557 * message factory.
558 * @since 2.4
559 */
560 void error(Supplier<?> msgSupplier);
561
562 /**
563 * Logs a message (only to be constructed if the logging level is the {@link Level#ERROR ERROR} level) including the
564 * stack trace of the {@link Throwable} <code>t</code> passed as parameter.
565 *
566 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
567 * message factory.
568 * @param t the exception to log, including its stack trace.
569 * @since 2.4
570 */
571 void error(Supplier<?> msgSupplier, Throwable t);
337572
338573 /**
339574 * Logs exit from a method. Used for methods that do not return anything.
370605 void fatal(Marker marker, Message msg, Throwable t);
371606
372607 /**
608 * Logs a message which is only to be constructed if the logging level is the {@link Level#FATAL FATAL} level with
609 * the specified Marker.
610 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
611 *
612 * @param marker the marker data specific to this log statement
613 * @param msgSupplier A function, which when called, produces the desired log message.
614 * @since 2.4
615 */
616 void fatal(Marker marker, MessageSupplier msgSupplier);
617
618 /**
619 * Logs a message (only to be constructed if the logging level is the {@link Level#FATAL FATAL} level) with the
620 * specified Marker and including the stack trace of the {@link Throwable} <code>t</code> passed as parameter.
621 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
622 *
623 * @param marker the marker data specific to this log statement
624 * @param msgSupplier A function, which when called, produces the desired log message.
625 * @param t A Throwable or null.
626 * @since 2.4
627 */
628 void fatal(Marker marker, MessageSupplier msgSupplier, Throwable t);
629
630 /**
373631 * Logs a message object with the {@link Level#FATAL FATAL} level.
374632 *
375633 * @param marker The marker data specific to this log statement.
411669 void fatal(Marker marker, String message, Object... params);
412670
413671 /**
672 * Logs a message with parameters which are only to be constructed if the logging level is the {@link Level#FATAL
673 * FATAL} level.
674 *
675 * @param marker the marker data specific to this log statement
676 * @param message the message to log; the format depends on the message factory.
677 * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
678 * @since 2.4
679 */
680 void fatal(Marker marker, String message, Supplier<?>... paramSuppliers);
681
682 /**
414683 * Logs a message at the {@link Level#FATAL FATAL} level including the stack trace of the {@link Throwable}
415684 * <code>t</code> passed as parameter.
416685 *
421690 void fatal(Marker marker, String message, Throwable t);
422691
423692 /**
693 * Logs a message which is only to be constructed if the logging level is the {@link Level#FATAL FATAL} level with
694 * the specified Marker.
695 *
696 * @param marker the marker data specific to this log statement
697 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
698 * message factory.
699 * @since 2.4
700 */
701 void fatal(Marker marker, Supplier<?> msgSupplier);
702
703 /**
704 * Logs a message (only to be constructed if the logging level is the {@link Level#FATAL FATAL} level) with the
705 * specified Marker and including the stack trace of the {@link Throwable} <code>t</code> passed as parameter.
706 *
707 * @param marker the marker data specific to this log statement
708 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
709 * message factory.
710 * @param t A Throwable or null.
711 * @since 2.4
712 */
713 void fatal(Marker marker, Supplier<?> msgSupplier, Throwable t);
714
715 /**
424716 * Logs a message with the specific Marker at the {@link Level#FATAL FATAL} level.
425717 *
426718 * @param msg the message string to be logged
434726 * @param t A Throwable or null.
435727 */
436728 void fatal(Message msg, Throwable t);
729
730 /**
731 * Logs a message which is only to be constructed if the logging level is the {@link Level#FATAL FATAL} level.
732 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
733 *
734 * @param msgSupplier A function, which when called, produces the desired log message.
735 * @since 2.4
736 */
737 void fatal(MessageSupplier msgSupplier);
738
739 /**
740 * Logs a message (only to be constructed if the logging level is the {@link Level#FATAL FATAL} level) including the
741 * stack trace of the {@link Throwable} <code>t</code> passed as parameter.
742 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
743 *
744 * @param msgSupplier A function, which when called, produces the desired log message.
745 * @param t the exception to log, including its stack trace.
746 * @since 2.4
747 */
748 void fatal(MessageSupplier msgSupplier, Throwable t);
437749
438750 /**
439751 * Logs a message object with the {@link Level#FATAL FATAL} level.
473785 void fatal(String message, Object... params);
474786
475787 /**
788 * Logs a message with parameters which are only to be constructed if the logging level is the {@link Level#FATAL
789 * FATAL} level.
790 *
791 * @param message the message to log; the format depends on the message factory.
792 * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
793 * @since 2.4
794 */
795 void fatal(String message, Supplier<?>... paramSuppliers);
796
797 /**
476798 * Logs a message at the {@link Level#FATAL FATAL} level including the stack trace of the {@link Throwable}
477799 * <code>t</code> passed as parameter.
478800 *
482804 void fatal(String message, Throwable t);
483805
484806 /**
807 * Logs a message which is only to be constructed if the logging level is the {@link Level#FATAL FATAL} level.
808 *
809 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
810 * message factory.
811 * @since 2.4
812 */
813 void fatal(Supplier<?> msgSupplier);
814
815 /**
816 * Logs a message (only to be constructed if the logging level is the {@link Level#FATAL FATAL} level) including the
817 * stack trace of the {@link Throwable} <code>t</code> passed as parameter.
818 *
819 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
820 * message factory.
821 * @param t the exception to log, including its stack trace.
822 * @since 2.4
823 */
824 void fatal(Supplier<?> msgSupplier, Throwable t);
825
826 /**
485827 * Gets the Level associated with the Logger.
486828 *
487829 * @return the Level associate with the Logger.
518860 * @param t A Throwable or null.
519861 */
520862 void info(Marker marker, Message msg, Throwable t);
863
864 /**
865 * Logs a message which is only to be constructed if the logging level is the {@link Level#INFO INFO} level with
866 * the specified Marker.
867 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
868 *
869 * @param marker the marker data specific to this log statement
870 * @param msgSupplier A function, which when called, produces the desired log message.
871 * @since 2.4
872 */
873 void info(Marker marker, MessageSupplier msgSupplier);
874
875 /**
876 * Logs a message (only to be constructed if the logging level is the {@link Level#INFO INFO} level) with the
877 * specified Marker and including the stack trace of the {@link Throwable} <code>t</code> passed as parameter.
878 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
879 *
880 * @param marker the marker data specific to this log statement
881 * @param msgSupplier A function, which when called, produces the desired log message.
882 * @param t A Throwable or null.
883 * @since 2.4
884 */
885 void info(Marker marker, MessageSupplier msgSupplier, Throwable t);
521886
522887 /**
523888 * Logs a message object with the {@link Level#INFO INFO} level.
560925 void info(Marker marker, String message, Object... params);
561926
562927 /**
928 * Logs a message with parameters which are only to be constructed if the logging level is the {@link Level#INFO
929 * INFO} level.
930 *
931 * @param marker the marker data specific to this log statement
932 * @param message the message to log; the format depends on the message factory.
933 * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
934 * @since 2.4
935 */
936 void info(Marker marker, String message, Supplier<?>... paramSuppliers);
937
938 /**
563939 * Logs a message at the {@link Level#INFO INFO} level including the stack trace of the {@link Throwable}
564940 * <code>t</code> passed as parameter.
565941 *
570946 void info(Marker marker, String message, Throwable t);
571947
572948 /**
949 * Logs a message which is only to be constructed if the logging level is the {@link Level#INFO INFO} level with the
950 * specified Marker.
951 *
952 * @param marker the marker data specific to this log statement
953 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
954 * message factory.
955 * @since 2.4
956 */
957 void info(Marker marker, Supplier<?> msgSupplier);
958
959 /**
960 * Logs a message (only to be constructed if the logging level is the {@link Level#INFO INFO} level) with the
961 * specified Marker and including the stack trace of the {@link Throwable} <code>t</code> passed as parameter.
962 *
963 * @param marker the marker data specific to this log statement
964 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
965 * message factory.
966 * @param t A Throwable or null.
967 * @since 2.4
968 */
969 void info(Marker marker, Supplier<?> msgSupplier, Throwable t);
970
971 /**
573972 * Logs a message with the specific Marker at the {@link Level#INFO INFO} level.
574973 *
575974 * @param msg the message string to be logged
583982 * @param t A Throwable or null.
584983 */
585984 void info(Message msg, Throwable t);
985
986 /**
987 * Logs a message which is only to be constructed if the logging level is the {@link Level#INFO INFO} level.
988 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
989 *
990 * @param msgSupplier A function, which when called, produces the desired log message.
991 * @since 2.4
992 */
993 void info(MessageSupplier msgSupplier);
994
995 /**
996 * Logs a message (only to be constructed if the logging level is the {@link Level#INFO INFO} level) including the
997 * stack trace of the {@link Throwable} <code>t</code> passed as parameter.
998 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
999 *
1000 * @param msgSupplier A function, which when called, produces the desired log message.
1001 * @param t the exception to log, including its stack trace.
1002 * @since 2.4
1003 */
1004 void info(MessageSupplier msgSupplier, Throwable t);
5861005
5871006 /**
5881007 * Logs a message object with the {@link Level#INFO INFO} level.
6211040 void info(String message, Object... params);
6221041
6231042 /**
1043 * Logs a message with parameters which are only to be constructed if the logging level is the {@link Level#INFO
1044 * INFO} level.
1045 *
1046 * @param message the message to log; the format depends on the message factory.
1047 * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
1048 * @since 2.4
1049 */
1050 void info(String message, Supplier<?>... paramSuppliers);
1051
1052 /**
6241053 * Logs a message at the {@link Level#INFO INFO} level including the stack trace of the {@link Throwable}
6251054 * <code>t</code> passed as parameter.
6261055 *
6281057 * @param t the exception to log, including its stack trace.
6291058 */
6301059 void info(String message, Throwable t);
1060
1061 /**
1062 * Logs a message which is only to be constructed if the logging level is the {@link Level#INFO INFO} level.
1063 *
1064 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
1065 * message factory.
1066 * @since 2.4
1067 */
1068 void info(Supplier<?> msgSupplier);
1069
1070 /**
1071 * Logs a message (only to be constructed if the logging level is the {@link Level#INFO INFO} level) including the
1072 * stack trace of the {@link Throwable} <code>t</code> passed as parameter.
1073 *
1074 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
1075 * message factory.
1076 * @param t the exception to log, including its stack trace.
1077 * @since 2.4
1078 */
1079 void info(Supplier<?> msgSupplier, Throwable t);
6311080
6321081 /**
6331082 * Checks whether this Logger is enabled for the {@link Level#DEBUG DEBUG} Level.
7661215 void log(Level level, Marker marker, Message msg, Throwable t);
7671216
7681217 /**
1218 * Logs a message which is only to be constructed if the logging level is the specified level with
1219 * the specified Marker.
1220 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
1221 *
1222 * @param level the logging level
1223 * @param marker the marker data specific to this log statement
1224 * @param msgSupplier A function, which when called, produces the desired log message.
1225 * @since 2.4
1226 */
1227 void log(Level level, Marker marker, MessageSupplier msgSupplier);
1228
1229 /**
1230 * Logs a message (only to be constructed if the logging level is the specified level) with the
1231 * specified Marker and including the stack log of the {@link Throwable} <code>t</code> passed as parameter.
1232 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
1233 *
1234 * @param level the logging level
1235 * @param marker the marker data specific to this log statement
1236 * @param msgSupplier A function, which when called, produces the desired log message.
1237 * @param t A Throwable or null.
1238 * @since 2.4
1239 */
1240 void log(Level level, Marker marker, MessageSupplier msgSupplier, Throwable t);
1241
1242 /**
7691243 * Logs a message object with the given level.
7701244 *
7711245 * @param level the logging level
7851259 */
7861260 void log(Level level, Marker marker, Object message, Throwable t);
7871261
1262
7881263 /**
7891264 * Logs a message object with the given level.
7901265 *
8061281 void log(Level level, Marker marker, String message, Object... params);
8071282
8081283 /**
1284 * Logs a message with parameters which are only to be constructed if the logging level is the specified level.
1285 *
1286 * @param level the logging level
1287 * @param marker the marker data specific to this log statement
1288 * @param message the message to log; the format depends on the message factory.
1289 * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
1290 * @since 2.4
1291 */
1292 void log(Level level, Marker marker, String message, Supplier<?>... paramSuppliers);
1293
1294 /**
8091295 * Logs a message at the given level including the stack trace of the {@link Throwable} <code>t</code> passed as
8101296 * parameter.
8111297 *
8171303 void log(Level level, Marker marker, String message, Throwable t);
8181304
8191305 /**
1306 * Logs a message (only to be constructed if the logging level is the specified level) with the specified Marker.
1307 *
1308 * @param level the logging level
1309 * @param marker the marker data specific to this log statement
1310 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
1311 * message factory.
1312 * @since 2.4
1313 */
1314 void log(Level level, Marker marker, Supplier<?> msgSupplier);
1315
1316 /**
1317 * Logs a message (only to be constructed if the logging level is the specified level) with the specified Marker and
1318 * including the stack log of the {@link Throwable} <code>t</code> passed as parameter.
1319 *
1320 * @param level the logging level
1321 * @param marker the marker data specific to this log statement
1322 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
1323 * message factory.
1324 * @param t A Throwable or null.
1325 * @since 2.4
1326 */
1327 void log(Level level, Marker marker, Supplier<?> msgSupplier, Throwable t);
1328
1329 /**
8201330 * Logs a message with the specific Marker at the given level.
8211331 *
8221332 * @param level the logging level
8321342 * @param t A Throwable or null.
8331343 */
8341344 void log(Level level, Message msg, Throwable t);
1345
1346 /**
1347 * Logs a message which is only to be constructed if the logging level is the specified level.
1348 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
1349 *
1350 * @param level the logging level
1351 * @param msgSupplier A function, which when called, produces the desired log message.
1352 * @since 2.4
1353 */
1354 void log(Level level, MessageSupplier msgSupplier);
1355
1356 /**
1357 * Logs a message (only to be constructed if the logging level is the specified level) including the
1358 * stack log of the {@link Throwable} <code>t</code> passed as parameter.
1359 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
1360 *
1361 * @param level the logging level
1362 * @param msgSupplier A function, which when called, produces the desired log message.
1363 * @param t the exception to log, including its stack log.
1364 * @since 2.4
1365 */
1366 void log(Level level, MessageSupplier msgSupplier, Throwable t);
8351367
8361368 /**
8371369 * Logs a message object with the given level.
8701402 void log(Level level, String message, Object... params);
8711403
8721404 /**
1405 * Logs a message with parameters which are only to be constructed if the logging level is the specified level.
1406 *
1407 * @param level the logging level
1408 * @param message the message to log; the format depends on the message factory.
1409 * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
1410 * @since 2.4
1411 */
1412 void log(Level level, String message, Supplier<?>... paramSuppliers);
1413
1414 /**
8731415 * Logs a message at the given level including the stack trace of the {@link Throwable} <code>t</code> passed as
8741416 * parameter.
8751417 *
8781420 * @param t the exception to log, including its stack trace.
8791421 */
8801422 void log(Level level, String message, Throwable t);
1423
1424 /**
1425 * Logs a message which is only to be constructed if the logging level is the specified level.
1426 *
1427 * @param level the logging level
1428 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
1429 * message factory.
1430 * @since 2.4
1431 */
1432 void log(Level level, Supplier<?> msgSupplier);
1433
1434 /**
1435 * Logs a message (only to be constructed if the logging level is the specified level) including the stack log of
1436 * the {@link Throwable} <code>t</code> passed as parameter.
1437 *
1438 * @param level the logging level
1439 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
1440 * message factory.
1441 * @param t the exception to log, including its stack log.
1442 * @since 2.4
1443 */
1444 void log(Level level, Supplier<?> msgSupplier, Throwable t);
8811445
8821446 /**
8831447 * Logs a formatted message using the specified format string and arguments.
9411505 void trace(Marker marker, Message msg, Throwable t);
9421506
9431507 /**
1508 * Logs a message which is only to be constructed if the logging level is the {@link Level#TRACE TRACE} level with
1509 * the specified Marker.
1510 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
1511 *
1512 * @param marker the marker data specific to this log statement
1513 * @param msgSupplier A function, which when called, produces the desired log message.
1514 * @since 2.4
1515 */
1516 void trace(Marker marker, MessageSupplier msgSupplier);
1517
1518 /**
1519 * Logs a message (only to be constructed if the logging level is the {@link Level#TRACE TRACE} level) with the
1520 * specified Marker and including the stack trace of the {@link Throwable} <code>t</code> passed as parameter.
1521 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
1522 *
1523 * @param marker the marker data specific to this log statement
1524 * @param msgSupplier A function, which when called, produces the desired log message.
1525 * @param t A Throwable or null.
1526 * @since 2.4
1527 */
1528 void trace(Marker marker, MessageSupplier msgSupplier, Throwable t);
1529
1530 /**
9441531 * Logs a message object with the {@link Level#TRACE TRACE} level.
9451532 *
9461533 * @param marker the marker data specific to this log statement
9781565 void trace(Marker marker, String message, Object... params);
9791566
9801567 /**
1568 * Logs a message with parameters which are only to be constructed if the logging level is the {@link Level#TRACE
1569 * TRACE} level.
1570 *
1571 * @param marker the marker data specific to this log statement
1572 * @param message the message to log; the format depends on the message factory.
1573 * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
1574 * @since 2.4
1575 */
1576 void trace(Marker marker, String message, Supplier<?>... paramSuppliers);
1577
1578 /**
9811579 * Logs a message at the {@link Level#TRACE TRACE} level including the stack trace of the {@link Throwable}
9821580 * <code>t</code> passed as parameter.
9831581 *
9891587 void trace(Marker marker, String message, Throwable t);
9901588
9911589 /**
1590 * Logs a message which is only to be constructed if the logging level is the {@link Level#TRACE TRACE} level with
1591 * the specified Marker.
1592 *
1593 * @param marker the marker data specific to this log statement
1594 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
1595 * message factory.
1596 * @since 2.4
1597 */
1598 void trace(Marker marker, Supplier<?> msgSupplier);
1599
1600 /**
1601 * Logs a message (only to be constructed if the logging level is the {@link Level#TRACE TRACE} level) with the
1602 * specified Marker and including the stack trace of the {@link Throwable} <code>t</code> passed as parameter.
1603 *
1604 * @param marker the marker data specific to this log statement
1605 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
1606 * message factory.
1607 * @param t A Throwable or null.
1608 * @since 2.4
1609 */
1610 void trace(Marker marker, Supplier<?> msgSupplier, Throwable t);
1611
1612 /**
9921613 * Logs a message with the specific Marker at the {@link Level#TRACE TRACE} level.
9931614 *
9941615 * @param msg the message string to be logged
10021623 * @param t A Throwable or null.
10031624 */
10041625 void trace(Message msg, Throwable t);
1626
1627 /**
1628 * Logs a message which is only to be constructed if the logging level is the {@link Level#TRACE TRACE} level.
1629 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
1630 *
1631 * @param msgSupplier A function, which when called, produces the desired log message.
1632 * @since 2.4
1633 */
1634 void trace(MessageSupplier msgSupplier);
1635
1636 /**
1637 * Logs a message (only to be constructed if the logging level is the {@link Level#TRACE TRACE} level) including the
1638 * stack trace of the {@link Throwable} <code>t</code> passed as parameter.
1639 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
1640 *
1641 * @param msgSupplier A function, which when called, produces the desired log message.
1642 * @param t the exception to log, including its stack trace.
1643 * @since 2.4
1644 */
1645 void trace(MessageSupplier msgSupplier, Throwable t);
10051646
10061647 /**
10071648 * Logs a message object with the {@link Level#TRACE TRACE} level.
10371678 void trace(String message, Object... params);
10381679
10391680 /**
1681 * Logs a message with parameters which are only to be constructed if the logging level is the {@link Level#TRACE
1682 * TRACE} level.
1683 *
1684 * @param message the message to log; the format depends on the message factory.
1685 * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
1686 * @since 2.4
1687 */
1688 void trace(String message, Supplier<?>... paramSuppliers);
1689
1690 /**
10401691 * Logs a message at the {@link Level#TRACE TRACE} level including the stack trace of the {@link Throwable}
10411692 * <code>t</code> passed as parameter.
10421693 *
10471698 void trace(String message, Throwable t);
10481699
10491700 /**
1701 * Logs a message which is only to be constructed if the logging level is the {@link Level#TRACE TRACE} level.
1702 *
1703 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
1704 * message factory.
1705 * @since 2.4
1706 */
1707 void trace(Supplier<?> msgSupplier);
1708
1709 /**
1710 * Logs a message (only to be constructed if the logging level is the {@link Level#TRACE TRACE} level) including the
1711 * stack trace of the {@link Throwable} <code>t</code> passed as parameter.
1712 *
1713 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
1714 * message factory.
1715 * @param t the exception to log, including its stack trace.
1716 * @since 2.4
1717 */
1718 void trace(Supplier<?> msgSupplier, Throwable t);
1719
1720 /**
10501721 * Logs a message with the specific Marker at the {@link Level#WARN WARN} level.
10511722 *
10521723 * @param marker the marker data specific to this log statement
10621733 * @param t A Throwable or null.
10631734 */
10641735 void warn(Marker marker, Message msg, Throwable t);
1736
1737 /**
1738 * Logs a message which is only to be constructed if the logging level is the {@link Level#WARN WARN} level with
1739 * the specified Marker.
1740 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
1741 *
1742 * @param marker the marker data specific to this log statement
1743 * @param msgSupplier A function, which when called, produces the desired log message.
1744 * @since 2.4
1745 */
1746 void warn(Marker marker, MessageSupplier msgSupplier);
1747
1748 /**
1749 * Logs a message (only to be constructed if the logging level is the {@link Level#WARN WARN} level) with the
1750 * specified Marker and including the stack warn of the {@link Throwable} <code>t</code> passed as parameter.
1751 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
1752 *
1753 * @param marker the marker data specific to this log statement
1754 * @param msgSupplier A function, which when called, produces the desired log message.
1755 * @param t A Throwable or null.
1756 * @since 2.4
1757 */
1758 void warn(Marker marker, MessageSupplier msgSupplier, Throwable t);
10651759
10661760 /**
10671761 * Logs a message object with the {@link Level#WARN WARN} level.
11051799 void warn(Marker marker, String message, Object... params);
11061800
11071801 /**
1802 * Logs a message with parameters which are only to be constructed if the logging level is the {@link Level#WARN
1803 * WARN} level.
1804 *
1805 * @param marker the marker data specific to this log statement
1806 * @param message the message to log; the format depends on the message factory.
1807 * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
1808 * @since 2.4
1809 */
1810 void warn(Marker marker, String message, Supplier<?>... paramSuppliers);
1811
1812 /**
11081813 * Logs a message at the {@link Level#WARN WARN} level including the stack trace of the {@link Throwable}
11091814 * <code>t</code> passed as parameter.
11101815 *
11151820 void warn(Marker marker, String message, Throwable t);
11161821
11171822 /**
1823 * Logs a message which is only to be constructed if the logging level is the {@link Level#WARN WARN} level with the
1824 * specified Marker.
1825 *
1826 * @param marker the marker data specific to this log statement
1827 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
1828 * message factory.
1829 * @since 2.4
1830 */
1831 void warn(Marker marker, Supplier<?> msgSupplier);
1832
1833 /**
1834 * Logs a message (only to be constructed if the logging level is the {@link Level#WARN WARN} level) with the
1835 * specified Marker and including the stack warn of the {@link Throwable} <code>t</code> passed as parameter.
1836 *
1837 * @param marker the marker data specific to this log statement
1838 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
1839 * message factory.
1840 * @param t A Throwable or null.
1841 * @since 2.4
1842 */
1843 void warn(Marker marker, Supplier<?> msgSupplier, Throwable t);
1844
1845 /**
11181846 * Logs a message with the specific Marker at the {@link Level#WARN WARN} level.
11191847 *
11201848 * @param msg the message string to be logged
11281856 * @param t A Throwable or null.
11291857 */
11301858 void warn(Message msg, Throwable t);
1859
1860 /**
1861 * Logs a message which is only to be constructed if the logging level is the {@link Level#WARN WARN} level.
1862 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
1863 *
1864 * @param msgSupplier A function, which when called, produces the desired log message.
1865 * @since 2.4
1866 */
1867 void warn(MessageSupplier msgSupplier);
1868
1869 /**
1870 * Logs a message (only to be constructed if the logging level is the {@link Level#WARN WARN} level) including the
1871 * stack warn of the {@link Throwable} <code>t</code> passed as parameter.
1872 * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the {@code Message}.
1873 *
1874 * @param msgSupplier A function, which when called, produces the desired log message.
1875 * @param t the exception to log, including its stack warn.
1876 * @since 2.4
1877 */
1878 void warn(MessageSupplier msgSupplier, Throwable t);
11311879
11321880 /**
11331881 * Logs a message object with the {@link Level#WARN WARN} level.
11671915 void warn(String message, Object... params);
11681916
11691917 /**
1918 * Logs a message with parameters which are only to be constructed if the logging level is the {@link Level#WARN
1919 * WARN} level.
1920 *
1921 * @param message the message to log; the format depends on the message factory.
1922 * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
1923 * @since 2.4
1924 */
1925 void warn(String message, Supplier<?>... paramSuppliers);
1926
1927 /**
11701928 * Logs a message at the {@link Level#WARN WARN} level including the stack trace of the {@link Throwable}
11711929 * <code>t</code> passed as parameter.
11721930 *
11741932 * @param t the exception to log, including its stack trace.
11751933 */
11761934 void warn(String message, Throwable t);
1935
1936 /**
1937 * Logs a message which is only to be constructed if the logging level is the {@link Level#WARN WARN} level.
1938 *
1939 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
1940 * message factory.
1941 * @since 2.4
1942 */
1943 void warn(Supplier<?> msgSupplier);
1944
1945 /**
1946 * Logs a message (only to be constructed if the logging level is the {@link Level#WARN WARN} level) including the
1947 * stack warn of the {@link Throwable} <code>t</code> passed as parameter.
1948 *
1949 * @param msgSupplier A function, which when called, produces the desired log message; the format depends on the
1950 * message factory.
1951 * @param t the exception to log, including its stack warn.
1952 * @since 2.4
1953 */
1954 void warn(Supplier<?> msgSupplier, Throwable t);
1955
11771956 }
2626 */
2727 public interface Marker extends Serializable {
2828
29 /**
30 * Adds a Marker as a parent to this Marker.
31 * @param markers The parent markers to add.
32 * @return The current Marker object, thus allowing multiple adds to be concatenated.
33 * @throws IllegalArgumentException if the argument is {@code null}
34 */
35 Marker addParents(Marker... markers);
36
37 /**
38 * Returns true if the given marker has the same name as this marker.
39 *
40 * @param obj the reference object with which to compare.
41 * @return true if the given marker has the same name as this marker.
42 * @since 2.4
43 */
44 @Override
45 public boolean equals(Object obj);
46
2947 /**
3048 * Returns the name of this Marker.
3149 * @return The name of the Marker.
3755 * @return The parent Markers or {@code null} if this Marker has no parents.
3856 */
3957 Marker[] getParents();
58
59 /**
60 * Returns a hash code value based on the name of this marker.
61 * Markers are equal if they have the same name.
62 * @return the computed hash code
63 * @since 2.4
64 */
65 @Override
66 public int hashCode();
4067
4168 /**
4269 * Indicates whether this Marker has references to any other Markers.
6188 boolean isInstanceOf(String name);
6289
6390 /**
64 * Adds a Marker as a parent to this Marker.
65 * @param markers The parent markers to add.
66 * @return The current Marker object, thus allowing multiple adds to be concatenated.
91 * Removes the specified Marker as a parent of this Marker.
92 * @param marker The marker to remove.
93 * @return {@code true} if the marker was removed.
6794 * @throws IllegalArgumentException if the argument is {@code null}
6895 */
69 Marker addParents(Marker... markers);
96 boolean remove(Marker marker);
7097
7198 /**
7299 * Replaces the set of parent Markers with the provided Markers.
74101 * @return The current Marker object.
75102 */
76103 Marker setParents(Marker... markers);
77
78 /**
79 * Removes the specified Marker as a parent of this Marker.
80 * @param marker The marker to remove.
81 * @return {@code true} if the marker was removed.
82 * @throws IllegalArgumentException if the argument is {@code null}
83 */
84 boolean remove(Marker marker);
85104 }
2626 */
2727 public final class MarkerManager {
2828
29 private static final ConcurrentMap<String, Marker> MARKERS = new ConcurrentHashMap<String, Marker>();
29 private static final ConcurrentMap<String, Marker> MARKERS = new ConcurrentHashMap<>();
3030
3131 private MarkerManager() {
3232 // do nothing
4040 }
4141
4242 /**
43 * Retrieve a Marker or create a Marker that has no parent.
43 * Tests existence of the given marker.
44 * @param key the marker name
45 * @return true if the marker exists.
46 * @since 2.4
47 */
48 public static boolean exists(final String key) {
49 return MARKERS.containsKey(key);
50 }
51
52
53 /**
54 * Retrieves a Marker or create a Marker that has no parent.
4455 * @param name The name of the Marker.
4556 * @return The Marker with the specified name.
4657 * @throws IllegalArgumentException if the argument is {@code null}
379390 sb.append(" ]");
380391 }
381392 }
393
382394 }
5151
5252 private static final long serialVersionUID = 1L;
5353
54 private static final Iterator<String> EMPTY_ITERATOR = new EmptyIterator<String>();
54 private static final Iterator<String> EMPTY_ITERATOR = new EmptyIterator<>();
5555
5656 @Override
5757 public String pop() {
1414 * limitations under the license.
1515 */
1616 package org.apache.logging.log4j.message;
17
18 import org.apache.logging.log4j.util.Chars;
19 import org.apache.logging.log4j.util.StringBuilders;
1720
1821 /**
1922 * Generates information about the current Thread. Used internally by ThreadDumpMessage.
8083 */
8184 @Override
8285 public void printThreadInfo(final StringBuilder sb) {
83 sb.append('"').append(name).append("\" ");
86 StringBuilders.appendDqValue(sb, name).append(Chars.SPACE);
8487 if (isDaemon) {
8588 sb.append("daemon ");
8689 }
8790 sb.append("prio=").append(priority).append(" tid=").append(id).append(' ');
8891 if (threadGroupName != null) {
89 sb.append("group=\"").append(threadGroupName).append('"');
92 StringBuilders.appendKeyDqValue(sb, "group", threadGroupName);
9093 }
9194 sb.append('\n');
9295 sb.append("\tThread state: ").append(state.name()).append('\n');
1919 import java.lang.management.MonitorInfo;
2020 import java.lang.management.ThreadInfo;
2121
22 import org.apache.logging.log4j.util.StringBuilders;
23
2224 /**
2325 * Provides information on locks and monitors in the thread dump. This class requires Java 1.6 to compile and
2426 * run.
3436
3537 @Override
3638 public void printThreadInfo(final StringBuilder sb) {
37 sb.append('"').append(threadInfo.getThreadName()).append('"');
39 StringBuilders.appendDqValue(sb, threadInfo.getThreadName());
3840 sb.append(" Id=").append(threadInfo.getThreadId()).append(' ');
3941 formatState(sb, threadInfo);
4042 if (threadInfo.isSuspended()) {
2121 import java.util.TreeMap;
2222
2323 import org.apache.logging.log4j.util.EnglishEnums;
24 import org.apache.logging.log4j.util.StringBuilders;
2425 import org.apache.logging.log4j.util.Strings;
2526
2627 /**
5354 * Constructor.
5455 */
5556 public MapMessage() {
56 data = new TreeMap<String, String>();
57 data = new TreeMap<>();
5758 }
5859
5960 /**
6162 * @param map The Map.
6263 */
6364 public MapMessage(final Map<String, String> map) {
64 this.data = map instanceof SortedMap ? (SortedMap<String, String>) map : new TreeMap<String, String>(map);
65 this.data = map instanceof SortedMap ? (SortedMap<String, String>) map : new TreeMap<>(map);
6566 }
6667
6768 @Override
247248 sb.append(' ');
248249 }
249250 first = false;
250 sb.append(entry.getKey()).append("=\"").append(entry.getValue()).append('"');
251 StringBuilders.appendKeyDqValue(sb, entry);
251252 }
252253 }
253254
259260 sb.append(", ");
260261 }
261262 first = false;
262 sb.append('"').append(entry.getKey()).append("\":");
263 sb.append('"').append(entry.getValue()).append('"');
263 StringBuilders.appendDqValue(sb, entry.getKey()).append(':');
264 StringBuilders.appendDqValue(sb, entry.getValue());
264265 }
265266 sb.append('}');
266267 }
274275 sb.append(", ");
275276 }
276277 first = false;
277 sb.append(entry.getKey()).append("=\"").append(entry.getValue()).append('"');
278 StringBuilders.appendKeyDqValue(sb, entry);
278279 }
279280 sb.append('}');
280281 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.message;
17
18 import java.io.IOException;
19 import java.io.ObjectInputStream;
20 import java.io.ObjectOutputStream;
21 import java.util.Arrays;
22
23 /**
24 * Handles messages that contain an Object[].
25 * <p>
26 * Created for use with the CSV layout. For example:
27 * </p>
28 * <p>
29 * {@code logger.debug(new ObjectArrayMessage(1, 2, "Bob"));}
30 * </p>
31 *
32 * @since 2.4
33 */
34 public final class ObjectArrayMessage implements Message {
35
36 private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
37
38 private static final long serialVersionUID = -5903272448334166185L;
39
40 private transient Object[] array;
41 private transient String arrayString;
42
43 /**
44 * Creates the ObjectMessage.
45 *
46 * @param obj
47 * The Object to format.
48 */
49 public ObjectArrayMessage(final Object... obj) {
50 this.array = obj == null ? EMPTY_OBJECT_ARRAY : obj;
51 }
52
53 private boolean equalObjectsOrStrings(final Object[] left, final Object[] right) {
54 return left.equals(right) || String.valueOf(left).equals(String.valueOf(right));
55 }
56
57 @Override
58 public boolean equals(final Object o) {
59 if (this == o) {
60 return true;
61 }
62 if (o == null || getClass() != o.getClass()) {
63 return false;
64 }
65
66 final ObjectArrayMessage that = (ObjectArrayMessage) o;
67 return array == null ? that.array == null : equalObjectsOrStrings(array, that.array);
68 }
69
70 /**
71 * Returns the object formatted using its toString method.
72 *
73 * @return the String representation of the object.
74 */
75 @Override
76 public String getFormat() {
77 return getFormattedMessage();
78 }
79
80 /**
81 * Returns the formatted object message.
82 *
83 * @return the formatted object message.
84 */
85 @Override
86 public String getFormattedMessage() {
87 // LOG4J2-763: cache formatted string in case obj changes later
88 if (arrayString == null) {
89 arrayString = Arrays.toString(array);
90 }
91 return arrayString;
92 }
93
94 /**
95 * Returns the object as if it were a parameter.
96 *
97 * @return The object.
98 */
99 @Override
100 public Object[] getParameters() {
101 return array;
102 }
103
104 /**
105 * Returns null.
106 *
107 * @return null.
108 */
109 @Override
110 public Throwable getThrowable() {
111 return null;
112 }
113
114 @Override
115 public int hashCode() {
116 return array.hashCode();
117 }
118
119 private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
120 in.defaultReadObject();
121 array = (Object[]) in.readObject();
122 }
123
124 @Override
125 public String toString() {
126 return "ObjectArrayMessage[obj=" + getFormattedMessage() + ']';
127 }
128
129 private void writeObject(final ObjectOutputStream out) throws IOException {
130 out.defaultWriteObject();
131 out.writeObject(array);
132 }
133 }
3131 private transient String objectString;
3232
3333 /**
34 * Create the ObjectMessage.
34 * Creates the ObjectMessage.
3535 * @param obj The Object to format.
3636 */
3737 public ObjectMessage(final Object obj) {
209209 }
210210
211211 protected String formatMessage(final String msgPattern, final String[] sArgs) {
212 return format(msgPattern, sArgs);
212 return formatStringArgs(msgPattern, sArgs);
213213 }
214214
215215 @Override
252252 if (messagePattern == null || arguments == null || arguments.length == 0) {
253253 return messagePattern;
254254 }
255
256 final StringBuilder result = new StringBuilder();
255 if (arguments instanceof String[]) {
256 return formatStringArgs(messagePattern, (String[]) arguments);
257 }
258 final String[] stringArgs = new String[arguments.length];
259 for (int i = 0; i < arguments.length; i++) {
260 stringArgs[i] = String.valueOf(arguments[i]);
261 }
262 return formatStringArgs(messagePattern, stringArgs);
263 }
264
265 /**
266 * Replace placeholders in the given messagePattern with arguments.
267 * <p>
268 * Package protected for unit tests.
269 *
270 * @param messagePattern the message pattern containing placeholders.
271 * @param arguments the arguments to be used to replace placeholders.
272 * @return the formatted message.
273 */
274 // Profiling showed this method is important to log4j performance. Modify with care!
275 // 33 bytes (allows immediate JVM inlining: < 35 bytes) LOG4J2-1096
276 static String formatStringArgs(final String messagePattern, final String[] arguments) {
277 int len = 0;
278 if (messagePattern == null || (len = messagePattern.length()) == 0 || arguments == null
279 || arguments.length == 0) {
280 return messagePattern;
281 }
282
283 return formatStringArgs0(messagePattern, len, arguments);
284 }
285
286 // Profiling showed this method is important to log4j performance. Modify with care!
287 // 157 bytes (will be inlined when hot enough: < 325 bytes)
288 private static String formatStringArgs0(final String messagePattern, final int len, final String[] arguments) {
289 final char[] result = new char[len + sumStringLengths(arguments)];
290 int pos = 0;
257291 int escapeCounter = 0;
258292 int currentArgument = 0;
259 for (int i = 0; i < messagePattern.length(); i++) {
293 int i = 0;
294 for (; i < len - 1; i++) { // last char is excluded from the loop
260295 final char curChar = messagePattern.charAt(i);
261296 if (curChar == ESCAPE_CHAR) {
262297 escapeCounter++;
263298 } else {
264 if (curChar == DELIM_START && i < messagePattern.length() - 1
265 && messagePattern.charAt(i + 1) == DELIM_STOP) {
299 if (isDelimPair(curChar, messagePattern, i)) { // looks ahead one char
300 i++;
301
266302 // write escaped escape chars
267 final int escapedEscapes = escapeCounter / 2;
268 for (int j = 0; j < escapedEscapes; j++) {
269 result.append(ESCAPE_CHAR);
270 }
271
272 if (escapeCounter % 2 == 1) {
303 pos = writeEscapedEscapeChars(escapeCounter, result, pos);
304
305 if (isOdd(escapeCounter)) {
273306 // i.e. escaped
274307 // write escaped escape chars
275 result.append(DELIM_START);
276 result.append(DELIM_STOP);
308 pos = writeDelimPair(result, pos);
277309 } else {
278310 // unescaped
279 if (currentArgument < arguments.length) {
280 result.append(arguments[currentArgument]);
281 } else {
282 result.append(DELIM_START).append(DELIM_STOP);
283 }
311 pos = writeArgOrDelimPair(arguments, currentArgument, result, pos);
284312 currentArgument++;
285313 }
286 i++;
287 escapeCounter = 0;
288 continue;
314 } else {
315 pos = handleLiteralChar(result, pos, escapeCounter, curChar);
289316 }
290 // any other char beside ESCAPE or DELIM_START/STOP-combo
291 // write unescaped escape chars
292 if (escapeCounter > 0) {
293 for (int j = 0; j < escapeCounter; j++) {
294 result.append(ESCAPE_CHAR);
295 }
296 escapeCounter = 0;
297 }
298 result.append(curChar);
317 escapeCounter = 0;
299318 }
300319 }
301 return result.toString();
320 pos = handleRemainingCharIfAny(messagePattern, len, result, pos, escapeCounter, i);
321 return new String(result, 0, pos);
322 }
323
324 /**
325 * Returns the sum of the lengths of all Strings in the specified array.
326 */
327 // Profiling showed this method is important to log4j performance. Modify with care!
328 // 30 bytes (allows immediate JVM inlining: < 35 bytes) LOG4J2-1096
329 private static int sumStringLengths(final String[] arguments) {
330 int result = 0;
331 for (int i = 0; i < arguments.length; i++) {
332 result += String.valueOf(arguments[i]).length();
333 }
334 return result;
335 }
336
337 /**
338 * Returns {@code true} if the specified char and the char at {@code curCharIndex + 1} in the specified message
339 * pattern together form a "{}" delimiter pair, returns {@code false} otherwise.
340 */
341 // Profiling showed this method is important to log4j performance. Modify with care!
342 // 22 bytes (allows immediate JVM inlining: < 35 bytes) LOG4J2-1096
343 private static boolean isDelimPair(final char curChar, final String messagePattern, final int curCharIndex) {
344 return curChar == DELIM_START && messagePattern.charAt(curCharIndex + 1) == DELIM_STOP;
345 }
346
347 /**
348 * Detects whether the message pattern has been fully processed or if an unprocessed character remains and processes
349 * it if necessary, returning the resulting position in the result char array.
350 */
351 // Profiling showed this method is important to log4j performance. Modify with care!
352 // 28 bytes (allows immediate JVM inlining: < 35 bytes) LOG4J2-1096
353 private static int handleRemainingCharIfAny(final String messagePattern, final int len, final char[] result,
354 int pos, int escapeCounter, int i) {
355 if (i == len - 1) {
356 final char curChar = messagePattern.charAt(i);
357 pos = handleLastChar(result, pos, escapeCounter, curChar);
358 }
359 return pos;
360 }
361
362 /**
363 * Processes the last unprocessed character and returns the resulting position in the result char array.
364 */
365 // Profiling showed this method is important to log4j performance. Modify with care!
366 // 28 bytes (allows immediate JVM inlining: < 35 bytes) LOG4J2-1096
367 private static int handleLastChar(final char[] result, int pos, final int escapeCounter, final char curChar) {
368 if (curChar == ESCAPE_CHAR) {
369 pos = writeUnescapedEscapeChars(escapeCounter + 1, result, pos);
370 } else {
371 pos = handleLiteralChar(result, pos, escapeCounter, curChar);
372 }
373 return pos;
374 }
375
376 /**
377 * Processes a literal char (neither an '\' escape char nor a "{}" delimiter pair) and returns the resulting
378 * position.
379 */
380 // Profiling showed this method is important to log4j performance. Modify with care!
381 // 16 bytes (allows immediate JVM inlining: < 35 bytes) LOG4J2-1096
382 private static int handleLiteralChar(final char[] result, int pos, final int escapeCounter, final char curChar) {
383 // any other char beside ESCAPE or DELIM_START/STOP-combo
384 // write unescaped escape chars
385 pos = writeUnescapedEscapeChars(escapeCounter, result, pos);
386 result[pos++] = curChar;
387 return pos;
388 }
389
390 /**
391 * Writes "{}" to the specified result array at the specified position and returns the resulting position.
392 */
393 // Profiling showed this method is important to log4j performance. Modify with care!
394 // 18 bytes (allows immediate JVM inlining: < 35 bytes) LOG4J2-1096
395 private static int writeDelimPair(final char[] result, int pos) {
396 result[pos++] = DELIM_START;
397 result[pos++] = DELIM_STOP;
398 return pos;
399 }
400
401 /**
402 * Returns {@code true} if the specified parameter is odd.
403 */
404 // Profiling showed this method is important to log4j performance. Modify with care!
405 // 11 bytes (allows immediate JVM inlining: < 35 bytes) LOG4J2-1096
406 private static boolean isOdd(final int number) {
407 return (number & 1) == 1;
408 }
409
410 /**
411 * Writes a '\' char to the specified result array (starting at the specified position) for each <em>pair</em> of
412 * '\' escape chars encountered in the message format and returns the resulting position.
413 */
414 // Profiling showed this method is important to log4j performance. Modify with care!
415 // 11 bytes (allows immediate JVM inlining: < 35 bytes) LOG4J2-1096
416 private static int writeEscapedEscapeChars(final int escapeCounter, final char[] result, final int pos) {
417 final int escapedEscapes = escapeCounter >> 1; // divide by two
418 return writeUnescapedEscapeChars(escapedEscapes, result, pos);
419 }
420
421 /**
422 * Writes the specified number of '\' chars to the specified result array (starting at the specified position) and
423 * returns the resulting position.
424 */
425 // Profiling showed this method is important to log4j performance. Modify with care!
426 // 20 bytes (allows immediate JVM inlining: < 35 bytes) LOG4J2-1096
427 private static int writeUnescapedEscapeChars(int escapeCounter, char[] result, int pos) {
428 while (escapeCounter > 0) {
429 result[pos++] = ESCAPE_CHAR;
430 escapeCounter--;
431 }
432 return pos;
433 }
434
435 /**
436 * Appends the argument at the specified argument index (or, if no such argument exists, the "{}" delimiter pair) to
437 * the specified result char array at the specified position and returns the resulting position.
438 */
439 // Profiling showed this method is important to log4j performance. Modify with care!
440 // 25 bytes (allows immediate JVM inlining: < 35 bytes) LOG4J2-1096
441 private static int writeArgOrDelimPair(final String[] arguments, final int currentArgument, final char[] result,
442 int pos) {
443 if (currentArgument < arguments.length) {
444 pos = writeArgAt0(arguments, currentArgument, result, pos);
445 } else {
446 pos = writeDelimPair(result, pos);
447 }
448 return pos;
449 }
450
451 /**
452 * Appends the argument at the specified argument index to the specified result char array at the specified position
453 * and returns the resulting position.
454 */
455 // Profiling showed this method is important to log4j performance. Modify with care!
456 // 30 bytes (allows immediate JVM inlining: < 35 bytes) LOG4J2-1096
457 private static int writeArgAt0(final String[] arguments, final int currentArgument, final char[] result,
458 final int pos) {
459 final String arg = String.valueOf(arguments[currentArgument]);
460 int argLen = arg.length();
461 arg.getChars(0, argLen, result, pos);
462 return pos + argLen;
302463 }
303464
304465 /**
363524 return (String) o;
364525 }
365526 final StringBuilder str = new StringBuilder();
366 final Set<String> dejaVu = new HashSet<String>(); // that's actually a neat name ;)
527 final Set<String> dejaVu = new HashSet<>(); // that's actually a neat name ;)
367528 recursiveDeepToString(o, str, dejaVu);
368529 return str.toString();
369530 }
393554 * @param dejaVu a list of container identities that were already used.
394555 */
395556 private static void recursiveDeepToString(final Object o, final StringBuilder str, final Set<String> dejaVu) {
396 if (o == null) {
397 str.append("null");
557 if (appendStringDateOrNull(o, str)) {
398558 return;
399559 }
400 if (o instanceof String) {
401 str.append(o);
402 return;
403 }
404
560 if (isMaybeRecursive(o)) {
561 appendPotentiallyRecursiveValue(o, str, dejaVu);
562 } else {
563 tryObjectToString(o, str);
564 }
565 }
566
567 private static boolean appendStringDateOrNull(final Object o, final StringBuilder str) {
568 if (o == null || o instanceof String) {
569 str.append(String.valueOf(o));
570 return true;
571 }
572 return appendDate(o, str);
573 }
574
575 private static boolean appendDate(final Object o, final StringBuilder str) {
576 if (!(o instanceof Date)) {
577 return false;
578 }
579 final Date date = (Date) o;
580 final SimpleDateFormat format = getSimpleDateFormat();
581 str.append(format.format(date));
582 return true;
583 }
584
585 private static SimpleDateFormat getSimpleDateFormat() {
586 // I'll leave it like this for the moment... this could probably be optimized using ThreadLocal...
587 return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
588 }
589
590 /**
591 * Returns {@code true} if the specified object is an array, a Map or a Collection.
592 */
593 private static boolean isMaybeRecursive(final Object o) {
594 return o.getClass().isArray() || o instanceof Map || o instanceof Collection;
595 }
596
597 private static void appendPotentiallyRecursiveValue(final Object o, final StringBuilder str,
598 final Set<String> dejaVu) {
405599 final Class<?> oClass = o.getClass();
406600 if (oClass.isArray()) {
407 if (oClass == byte[].class) {
408 str.append(Arrays.toString((byte[]) o));
409 } else if (oClass == short[].class) {
410 str.append(Arrays.toString((short[]) o));
411 } else if (oClass == int[].class) {
412 str.append(Arrays.toString((int[]) o));
413 } else if (oClass == long[].class) {
414 str.append(Arrays.toString((long[]) o));
415 } else if (oClass == float[].class) {
416 str.append(Arrays.toString((float[]) o));
417 } else if (oClass == double[].class) {
418 str.append(Arrays.toString((double[]) o));
419 } else if (oClass == boolean[].class) {
420 str.append(Arrays.toString((boolean[]) o));
421 } else if (oClass == char[].class) {
422 str.append(Arrays.toString((char[]) o));
423 } else {
424 // special handling of container Object[]
425 final String id = identityToString(o);
426 if (dejaVu.contains(id)) {
427 str.append(RECURSION_PREFIX).append(id).append(RECURSION_SUFFIX);
428 } else {
429 dejaVu.add(id);
430 final Object[] oArray = (Object[]) o;
431 str.append('[');
432 boolean first = true;
433 for (final Object current : oArray) {
434 if (first) {
435 first = false;
436 } else {
437 str.append(", ");
438 }
439 recursiveDeepToString(current, str, new HashSet<String>(dejaVu));
440 }
441 str.append(']');
442 }
443 //str.append(Arrays.deepToString((Object[]) o));
444 }
601 appendArray(o, str, dejaVu, oClass);
445602 } else if (o instanceof Map) {
446 // special handling of container Map
603 appendMap(o, str, dejaVu);
604 } else if (o instanceof Collection) {
605 appendCollection(o, str, dejaVu);
606 }
607 }
608
609 private static void appendArray(final Object o, final StringBuilder str, final Set<String> dejaVu,
610 final Class<?> oClass) {
611 if (oClass == byte[].class) {
612 str.append(Arrays.toString((byte[]) o));
613 } else if (oClass == short[].class) {
614 str.append(Arrays.toString((short[]) o));
615 } else if (oClass == int[].class) {
616 str.append(Arrays.toString((int[]) o));
617 } else if (oClass == long[].class) {
618 str.append(Arrays.toString((long[]) o));
619 } else if (oClass == float[].class) {
620 str.append(Arrays.toString((float[]) o));
621 } else if (oClass == double[].class) {
622 str.append(Arrays.toString((double[]) o));
623 } else if (oClass == boolean[].class) {
624 str.append(Arrays.toString((boolean[]) o));
625 } else if (oClass == char[].class) {
626 str.append(Arrays.toString((char[]) o));
627 } else {
628 // special handling of container Object[]
447629 final String id = identityToString(o);
448630 if (dejaVu.contains(id)) {
449631 str.append(RECURSION_PREFIX).append(id).append(RECURSION_SUFFIX);
450632 } else {
451633 dejaVu.add(id);
452 final Map<?, ?> oMap = (Map<?, ?>) o;
453 str.append('{');
454 boolean isFirst = true;
455 for (final Object o1 : oMap.entrySet()) {
456 final Map.Entry<?, ?> current = (Map.Entry<?, ?>) o1;
457 if (isFirst) {
458 isFirst = false;
634 final Object[] oArray = (Object[]) o;
635 str.append('[');
636 boolean first = true;
637 for (final Object current : oArray) {
638 if (first) {
639 first = false;
459640 } else {
460641 str.append(", ");
461642 }
462 final Object key = current.getKey();
463 final Object value = current.getValue();
464 recursiveDeepToString(key, str, new HashSet<String>(dejaVu));
465 str.append('=');
466 recursiveDeepToString(value, str, new HashSet<String>(dejaVu));
467 }
468 str.append('}');
469 }
470 } else if (o instanceof Collection) {
471 // special handling of container Collection
472 final String id = identityToString(o);
473 if (dejaVu.contains(id)) {
474 str.append(RECURSION_PREFIX).append(id).append(RECURSION_SUFFIX);
475 } else {
476 dejaVu.add(id);
477 final Collection<?> oCol = (Collection<?>) o;
478 str.append('[');
479 boolean isFirst = true;
480 for (final Object anOCol : oCol) {
481 if (isFirst) {
482 isFirst = false;
483 } else {
484 str.append(", ");
485 }
486 recursiveDeepToString(anOCol, str, new HashSet<String>(dejaVu));
643 recursiveDeepToString(current, str, new HashSet<>(dejaVu));
487644 }
488645 str.append(']');
489646 }
490 } else if (o instanceof Date) {
491 final Date date = (Date) o;
492 final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
493 // I'll leave it like this for the moment... this could probably be optimized using ThreadLocal...
494 str.append(format.format(date));
647 //str.append(Arrays.deepToString((Object[]) o));
648 }
649 }
650
651 private static void appendMap(final Object o, final StringBuilder str, final Set<String> dejaVu) {
652 // special handling of container Map
653 final String id = identityToString(o);
654 if (dejaVu.contains(id)) {
655 str.append(RECURSION_PREFIX).append(id).append(RECURSION_SUFFIX);
495656 } else {
496 // it's just some other Object, we can only use toString().
497 try {
498 str.append(o.toString());
499 } catch (final Throwable t) {
500 str.append(ERROR_PREFIX);
501 str.append(identityToString(o));
502 str.append(ERROR_SEPARATOR);
503 final String msg = t.getMessage();
504 final String className = t.getClass().getName();
505 str.append(className);
506 if (!className.equals(msg)) {
507 str.append(ERROR_MSG_SEPARATOR);
508 str.append(msg);
657 dejaVu.add(id);
658 final Map<?, ?> oMap = (Map<?, ?>) o;
659 str.append('{');
660 boolean isFirst = true;
661 for (final Object o1 : oMap.entrySet()) {
662 final Map.Entry<?, ?> current = (Map.Entry<?, ?>) o1;
663 if (isFirst) {
664 isFirst = false;
665 } else {
666 str.append(", ");
509667 }
510 str.append(ERROR_SUFFIX);
668 final Object key = current.getKey();
669 final Object value = current.getValue();
670 recursiveDeepToString(key, str, new HashSet<>(dejaVu));
671 str.append('=');
672 recursiveDeepToString(value, str, new HashSet<>(dejaVu));
511673 }
512 }
674 str.append('}');
675 }
676 }
677
678 private static void appendCollection(final Object o, final StringBuilder str, final Set<String> dejaVu) {
679 // special handling of container Collection
680 final String id = identityToString(o);
681 if (dejaVu.contains(id)) {
682 str.append(RECURSION_PREFIX).append(id).append(RECURSION_SUFFIX);
683 } else {
684 dejaVu.add(id);
685 final Collection<?> oCol = (Collection<?>) o;
686 str.append('[');
687 boolean isFirst = true;
688 for (final Object anOCol : oCol) {
689 if (isFirst) {
690 isFirst = false;
691 } else {
692 str.append(", ");
693 }
694 recursiveDeepToString(anOCol, str, new HashSet<>(dejaVu));
695 }
696 str.append(']');
697 }
698 }
699
700 private static void tryObjectToString(final Object o, final StringBuilder str) {
701 // it's just some other Object, we can only use toString().
702 try {
703 str.append(o.toString());
704 } catch (final Throwable t) {
705 handleErrorInObjectToString(o, str, t);
706 }
707 }
708
709 private static void handleErrorInObjectToString(final Object o, final StringBuilder str, final Throwable t) {
710 str.append(ERROR_PREFIX);
711 str.append(identityToString(o));
712 str.append(ERROR_SEPARATOR);
713 final String msg = t.getMessage();
714 final String className = t.getClass().getName();
715 str.append(className);
716 if (!className.equals(msg)) {
717 str.append(ERROR_MSG_SEPARATOR);
718 str.append(msg);
719 }
720 str.append(ERROR_SUFFIX);
513721 }
514722
515723 /**
132132 stringArgs = new String[argArray.length];
133133 int i = 0;
134134 for (final Object obj : argArray) {
135 stringArgs[i] = obj.toString();
135 final String string = String.valueOf(obj);
136 stringArgs[i] = string;
137 out.writeUTF(string);
136138 ++i;
137139 }
138140 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.message;
17
18 import java.io.Serializable;
19
20 /**
21 * The StructuredData identifier.
22 */
23 public class StructuredDataId implements Serializable {
24
25 private static final String AT = "@";
26
27 /**
28 * RFC 5424 Time Quality.
29 */
30 public static final StructuredDataId TIME_QUALITY = new StructuredDataId("timeQuality", null,
31 new String[]{"tzKnown", "isSynced", "syncAccuracy"});
32
33 /**
34 * RFC 5424 Origin.
35 */
36 public static final StructuredDataId ORIGIN = new StructuredDataId("origin", null,
37 new String[]{"ip", "enterpriseId", "software", "swVersion"});
38
39 /**
40 * RFC 5424 Meta.
41 */
42 public static final StructuredDataId META = new StructuredDataId("meta", null,
43 new String[]{"sequenceId", "sysUpTime", "language"});
44
45 /**
46 * Reserved enterprise number.
47 */
48 public static final int RESERVED = -1;
49
50 private static final long serialVersionUID = 9031746276396249990L;
51 private static final int MAX_LENGTH = 32;
52
53 private final String name;
54 private final int enterpriseNumber;
55 private final String[] required;
56 private final String[] optional;
57
58
59 protected StructuredDataId(final String name, final String[] required, final String[] optional) {
60 int index = -1;
61 if (name != null) {
62 if (name.length() > MAX_LENGTH) {
63 throw new IllegalArgumentException(String.format("Length of id %s exceeds maximum of %d characters",
64 name, MAX_LENGTH));
65 }
66 index = name.indexOf(AT);
67 }
68
69 if (index > 0) {
70 this.name = name.substring(0, index);
71 this.enterpriseNumber = Integer.parseInt(name.substring(index + 1));
72 } else {
73 this.name = name;
74 this.enterpriseNumber = RESERVED;
75 }
76 this.required = required;
77 this.optional = optional;
78 }
79
80 /**
81 * A Constructor that helps conformance to RFC 5424.
82 *
83 * @param name The name portion of the id.
84 * @param enterpriseNumber The enterprise number.
85 * @param required The list of keys that are required for this id.
86 * @param optional The list of keys that are optional for this id.
87 */
88 public StructuredDataId(final String name, final int enterpriseNumber, final String[] required,
89 final String[] optional) {
90 if (name == null) {
91 throw new IllegalArgumentException("No structured id name was supplied");
92 }
93 if (name.contains(AT)) {
94 throw new IllegalArgumentException("Structured id name cannot contain an '" + AT + '\'');
95 }
96 if (enterpriseNumber <= 0) {
97 throw new IllegalArgumentException("No enterprise number was supplied");
98 }
99 this.name = name;
100 this.enterpriseNumber = enterpriseNumber;
101 final String id = enterpriseNumber < 0 ? name : name + AT + enterpriseNumber;
102 if (id.length() > MAX_LENGTH) {
103 throw new IllegalArgumentException("Length of id exceeds maximum of 32 characters: " + id);
104 }
105 this.required = required;
106 this.optional = optional;
107 }
108
109 /**
110 * Creates an id using another id to supply default values.
111 * @param id The original StructuredDataId.
112 * @return the new StructuredDataId.
113 */
114 public StructuredDataId makeId(final StructuredDataId id) {
115 if (id == null) {
116 return this;
117 }
118 return makeId(id.getName(), id.getEnterpriseNumber());
119 }
120
121 /**
122 * Creates an id based on the current id.
123 * @param defaultId The default id to use if this StructuredDataId doesn't have a name.
124 * @param enterpriseNumber The enterprise number.
125 * @return a StructuredDataId.
126 */
127 public StructuredDataId makeId(final String defaultId, final int enterpriseNumber) {
128 String id;
129 String[] req;
130 String[] opt;
131 if (enterpriseNumber <= 0) {
132 return this;
133 }
134 if (this.name != null) {
135 id = this.name;
136 req = this.required;
137 opt = this.optional;
138 } else {
139 id = defaultId;
140 req = null;
141 opt = null;
142 }
143
144 return new StructuredDataId(id, enterpriseNumber, req, opt);
145 }
146
147 /**
148 * Returns a list of required keys.
149 * @return a List of required keys or null if none have been provided.
150 */
151 public String[] getRequired() {
152 return required;
153 }
154
155 /**
156 * Returns a list of optional keys.
157 * @return a List of optional keys or null if none have been provided.
158 */
159 public String[] getOptional() {
160 return optional;
161 }
162
163 /**
164 * Returns the StructuredDataId name.
165 * @return the StructuredDataId name.
166 */
167 public String getName() {
168 return name;
169 }
170
171 /**
172 * Returns the enterprise number.
173 * @return the enterprise number.
174 */
175 public int getEnterpriseNumber() {
176 return enterpriseNumber;
177 }
178
179 /**
180 * Indicates if the id is reserved.
181 * @return true if the id uses the reserved enterprise number, false otherwise.
182 */
183 public boolean isReserved() {
184 return enterpriseNumber <= 0;
185 }
186
187 @Override
188 public String toString() {
189 return isReserved() ? name : name + AT + enterpriseNumber;
190 }
191 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.message;
17
18 import java.io.Serializable;
19
20 import org.apache.logging.log4j.util.Strings;
21
22 /**
23 * The StructuredData identifier.
24 */
25 public class StructuredDataId implements Serializable {
26
27 private static final String AT_SIGN = "@";
28
29 /**
30 * RFC 5424 Time Quality.
31 */
32 public static final StructuredDataId TIME_QUALITY = new StructuredDataId("timeQuality", null,
33 new String[]{"tzKnown", "isSynced", "syncAccuracy"});
34
35 /**
36 * RFC 5424 Origin.
37 */
38 public static final StructuredDataId ORIGIN = new StructuredDataId("origin", null,
39 new String[]{"ip", "enterpriseId", "software", "swVersion"});
40
41 /**
42 * RFC 5424 Meta.
43 */
44 public static final StructuredDataId META = new StructuredDataId("meta", null,
45 new String[]{"sequenceId", "sysUpTime", "language"});
46
47 /**
48 * Reserved enterprise number.
49 */
50 public static final int RESERVED = -1;
51
52 private static final long serialVersionUID = 9031746276396249990L;
53 private static final int MAX_LENGTH = 32;
54
55 private final String name;
56 private final int enterpriseNumber;
57 private final String[] required;
58 private final String[] optional;
59
60
61 protected StructuredDataId(final String name, final String[] required, final String[] optional) {
62 int index = -1;
63 if (name != null) {
64 if (name.length() > MAX_LENGTH) {
65 throw new IllegalArgumentException(String.format("Length of id %s exceeds maximum of %d characters",
66 name, MAX_LENGTH));
67 }
68 index = name.indexOf(AT_SIGN);
69 }
70
71 if (index > 0) {
72 this.name = name.substring(0, index);
73 this.enterpriseNumber = Integer.parseInt(name.substring(index + 1));
74 } else {
75 this.name = name;
76 this.enterpriseNumber = RESERVED;
77 }
78 this.required = required;
79 this.optional = optional;
80 }
81
82 /**
83 * A Constructor that helps conformance to RFC 5424.
84 *
85 * @param name The name portion of the id.
86 * @param enterpriseNumber The enterprise number.
87 * @param required The list of keys that are required for this id.
88 * @param optional The list of keys that are optional for this id.
89 */
90 public StructuredDataId(final String name, final int enterpriseNumber, final String[] required,
91 final String[] optional) {
92 if (name == null) {
93 throw new IllegalArgumentException("No structured id name was supplied");
94 }
95 if (name.contains(AT_SIGN)) {
96 throw new IllegalArgumentException("Structured id name cannot contain an " + Strings.quote(AT_SIGN));
97 }
98 if (enterpriseNumber <= 0) {
99 throw new IllegalArgumentException("No enterprise number was supplied");
100 }
101 this.name = name;
102 this.enterpriseNumber = enterpriseNumber;
103 final String id = name + AT_SIGN + enterpriseNumber;
104 if (id.length() > MAX_LENGTH) {
105 throw new IllegalArgumentException("Length of id exceeds maximum of 32 characters: " + id);
106 }
107 this.required = required;
108 this.optional = optional;
109 }
110
111 /**
112 * Creates an id using another id to supply default values.
113 * @param id The original StructuredDataId.
114 * @return the new StructuredDataId.
115 */
116 public StructuredDataId makeId(final StructuredDataId id) {
117 if (id == null) {
118 return this;
119 }
120 return makeId(id.getName(), id.getEnterpriseNumber());
121 }
122
123 /**
124 * Creates an id based on the current id.
125 * @param defaultId The default id to use if this StructuredDataId doesn't have a name.
126 * @param enterpriseNumber The enterprise number.
127 * @return a StructuredDataId.
128 */
129 public StructuredDataId makeId(final String defaultId, final int enterpriseNumber) {
130 String id;
131 String[] req;
132 String[] opt;
133 if (enterpriseNumber <= 0) {
134 return this;
135 }
136 if (this.name != null) {
137 id = this.name;
138 req = this.required;
139 opt = this.optional;
140 } else {
141 id = defaultId;
142 req = null;
143 opt = null;
144 }
145
146 return new StructuredDataId(id, enterpriseNumber, req, opt);
147 }
148
149 /**
150 * Returns a list of required keys.
151 * @return a List of required keys or null if none have been provided.
152 */
153 public String[] getRequired() {
154 return required;
155 }
156
157 /**
158 * Returns a list of optional keys.
159 * @return a List of optional keys or null if none have been provided.
160 */
161 public String[] getOptional() {
162 return optional;
163 }
164
165 /**
166 * Returns the StructuredDataId name.
167 * @return the StructuredDataId name.
168 */
169 public String getName() {
170 return name;
171 }
172
173 /**
174 * Returns the enterprise number.
175 * @return the enterprise number.
176 */
177 public int getEnterpriseNumber() {
178 return enterpriseNumber;
179 }
180
181 /**
182 * Indicates if the id is reserved.
183 * @return true if the id uses the reserved enterprise number, false otherwise.
184 */
185 public boolean isReserved() {
186 return enterpriseNumber <= 0;
187 }
188
189 @Override
190 public String toString() {
191 return isReserved() ? name : name + AT_SIGN + enterpriseNumber;
192 }
193 }
2525 import java.util.HashMap;
2626 import java.util.Map;
2727
28 import org.apache.logging.log4j.util.StringBuilders;
2829 import org.apache.logging.log4j.util.Strings;
2930
3031 /**
7273 public String toString() {
7374 final StringBuilder sb = new StringBuilder("ThreadDumpMessage[");
7475 if (this.title.length() > 0) {
75 sb.append("Title=\"").append(this.title).append('"');
76 StringBuilders.appendKeyDqValue(sb, "Title", this.title);
7677 }
7778 sb.append(']');
7879 return sb.toString();
170171 public Map<ThreadInformation, StackTraceElement[]> createThreadInfo() {
171172 final Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
172173 final Map<ThreadInformation, StackTraceElement[]> threads =
173 new HashMap<ThreadInformation, StackTraceElement[]>(map.size());
174 new HashMap<>(map.size());
174175 for (final Map.Entry<Thread, StackTraceElement[]> entry : map.entrySet()) {
175176 threads.put(new BasicThreadInformation(entry.getKey()), entry.getValue());
176177 }
188189 final ThreadInfo[] array = bean.dumpAllThreads(true, true);
189190
190191 final Map<ThreadInformation, StackTraceElement[]> threads =
191 new HashMap<ThreadInformation, StackTraceElement[]>(array.length);
192 new HashMap<>(array.length);
192193 for (final ThreadInfo info : array) {
193194 threads.put(new ExtendedThreadInformation(info), info.getStackTrace());
194195 }
1515 */
1616 package org.apache.logging.log4j.simple;
1717
18 import java.io.ByteArrayOutputStream;
1918 import java.io.PrintStream;
2019 import java.text.DateFormat;
2120 import java.text.SimpleDateFormat;
2928 import org.apache.logging.log4j.message.MessageFactory;
3029 import org.apache.logging.log4j.spi.AbstractLogger;
3130 import org.apache.logging.log4j.util.PropertiesUtil;
31 import org.apache.logging.log4j.util.Strings;
3232
3333 /**
3434 * This is the default logger that is used when no suitable logging implementation is available.
9797 }
9898
9999 @Override
100 public boolean isEnabled(final Level level, final Marker marker, final Message msg, final Throwable t) {
101 return this.level.intLevel() >= level.intLevel();
100 public boolean isEnabled(final Level testLevel, final Marker marker, final Message msg, final Throwable t) {
101 return this.level.intLevel() >= testLevel.intLevel();
102102 }
103103
104104 @Override
105 public boolean isEnabled(final Level level, final Marker marker, final Object msg, final Throwable t) {
106 return this.level.intLevel() >= level.intLevel();
105 public boolean isEnabled(final Level testLevel, final Marker marker, final Object msg, final Throwable t) {
106 return this.level.intLevel() >= testLevel.intLevel();
107107 }
108108
109109 @Override
110 public boolean isEnabled(final Level level, final Marker marker, final String msg) {
111 return this.level.intLevel() >= level.intLevel();
110 public boolean isEnabled(final Level testLevel, final Marker marker, final String msg) {
111 return this.level.intLevel() >= testLevel.intLevel();
112112 }
113113
114114 @Override
115 public boolean isEnabled(final Level level, final Marker marker, final String msg, final Object... p1) {
116 return this.level.intLevel() >= level.intLevel();
115 public boolean isEnabled(final Level testLevel, final Marker marker, final String msg, final Object... p1) {
116 return this.level.intLevel() >= testLevel.intLevel();
117117 }
118118
119119 @Override
120 public boolean isEnabled(final Level level, final Marker marker, final String msg, final Throwable t) {
121 return this.level.intLevel() >= level.intLevel();
120 public boolean isEnabled(final Level testLevel, final Marker marker, final String msg, final Throwable t) {
121 return this.level.intLevel() >= testLevel.intLevel();
122122 }
123123
124124 @Override
138138
139139 sb.append(level.toString());
140140 sb.append(SPACE);
141 if (logName != null && logName.length() > 0) {
141 if (Strings.isNotEmpty(logName)) {
142142 sb.append(logName);
143143 sb.append(SPACE);
144144 }
145145 sb.append(msg.getFormattedMessage());
146146 if (showContextMap) {
147 final Map<String, String> mdc = ThreadContext.getContext();
147 final Map<String, String> mdc = ThreadContext.getImmutableContext();
148148 if (mdc.size() > 0) {
149149 sb.append(SPACE);
150150 sb.append(mdc.toString());
158158 } else {
159159 t = throwable;
160160 }
161 stream.println(sb.toString());
161162 if (t != null) {
162 sb.append(SPACE);
163 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
164 t.printStackTrace(new PrintStream(baos));
165 sb.append(baos.toString());
163 stream.print(SPACE);
164 t.printStackTrace(stream);
166165 }
167 stream.println(sb.toString());
168166 }
169167
170168 public void setLevel(final Level level) {
5959
6060 private final PrintStream stream;
6161
62 private final ConcurrentMap<String, ExtendedLogger> loggers = new ConcurrentHashMap<String, ExtendedLogger>();
62 private final ConcurrentMap<String, ExtendedLogger> loggers = new ConcurrentHashMap<>();
6363
6464 public SimpleLoggerContext() {
6565 props = new PropertiesUtil("log4j2.simplelog.properties");
9898
9999 @Override
100100 public ExtendedLogger getLogger(final String name, final MessageFactory messageFactory) {
101 if (loggers.containsKey(name)) {
102 final ExtendedLogger logger = loggers.get(name);
103 AbstractLogger.checkMessageFactory(logger, messageFactory);
104 return logger;
101 final ExtendedLogger extendedLogger = loggers.get(name);
102 if (extendedLogger != null) {
103 AbstractLogger.checkMessageFactory(extendedLogger, messageFactory);
104 return extendedLogger;
105105 }
106
107106 loggers.putIfAbsent(name, new SimpleLogger(name, defaultLevel, showLogName, showShortName, showDateTime,
108107 showContextMap, dateTimeFormat, messageFactory, props, stream));
109108 return loggers.get(name);
2525 import org.apache.logging.log4j.message.ParameterizedMessageFactory;
2626 import org.apache.logging.log4j.message.StringFormattedMessage;
2727 import org.apache.logging.log4j.status.StatusLogger;
28 import org.apache.logging.log4j.util.LambdaUtil;
29 import org.apache.logging.log4j.util.MessageSupplier;
30 import org.apache.logging.log4j.util.Supplier;
2831
2932 /**
3033 * Base implementation of a Logger. It is highly recommended that any Logger implementation extend this class.
242245 }
243246
244247 @Override
248 public void debug(final Supplier<?> msgSupplier) {
249 logIfEnabled(FQCN, Level.DEBUG, null, msgSupplier, (Throwable) null);
250 }
251
252 @Override
253 public void debug(final Supplier<?> msgSupplier, final Throwable t) {
254 logIfEnabled(FQCN, Level.DEBUG, null, msgSupplier, t);
255 }
256
257 @Override
258 public void debug(final Marker marker, final Supplier<?> msgSupplier) {
259 logIfEnabled(FQCN, Level.DEBUG, marker, msgSupplier, (Throwable) null);
260 }
261
262 @Override
263 public void debug(final Marker marker, final String message, final Supplier<?>... paramSuppliers) {
264 logIfEnabled(FQCN, Level.DEBUG, marker, message, paramSuppliers);
265 }
266
267 @Override
268 public void debug(final Marker marker, final Supplier<?> msgSupplier, final Throwable t) {
269 logIfEnabled(FQCN, Level.DEBUG, marker, msgSupplier, t);
270 }
271
272 @Override
273 public void debug(final String message, final Supplier<?>... paramSuppliers) {
274 logIfEnabled(FQCN, Level.DEBUG, null, message, paramSuppliers);
275 }
276
277 @Override
278 public void debug(final Marker marker, final MessageSupplier msgSupplier) {
279 logIfEnabled(FQCN, Level.DEBUG, marker, msgSupplier, (Throwable) null);
280 }
281
282 @Override
283 public void debug(final Marker marker, final MessageSupplier msgSupplier, final Throwable t) {
284 logIfEnabled(FQCN, Level.DEBUG, marker, msgSupplier, t);
285 }
286
287 @Override
288 public void debug(final MessageSupplier msgSupplier) {
289 logIfEnabled(FQCN, Level.DEBUG, null, msgSupplier, (Throwable) null);
290 }
291
292 @Override
293 public void debug(final MessageSupplier msgSupplier, final Throwable t) {
294 logIfEnabled(FQCN, Level.DEBUG, null, msgSupplier, t);
295 }
296
297 @Override
245298 public void entry() {
246299 entry(FQCN);
247300 }
354407 }
355408
356409 @Override
410 public void error(final Supplier<?> msgSupplier) {
411 logIfEnabled(FQCN, Level.ERROR, null, msgSupplier, (Throwable) null);
412 }
413
414 @Override
415 public void error(final Supplier<?> msgSupplier, final Throwable t) {
416 logIfEnabled(FQCN, Level.ERROR, null, msgSupplier, t);
417 }
418
419 @Override
420 public void error(final Marker marker, final Supplier<?> msgSupplier) {
421 logIfEnabled(FQCN, Level.ERROR, marker, msgSupplier, (Throwable) null);
422 }
423
424 @Override
425 public void error(final Marker marker, final String message, final Supplier<?>... paramSuppliers) {
426 logIfEnabled(FQCN, Level.ERROR, marker, message, paramSuppliers);
427 }
428
429 @Override
430 public void error(final Marker marker, final Supplier<?> msgSupplier, final Throwable t) {
431 logIfEnabled(FQCN, Level.ERROR, marker, msgSupplier, t);
432 }
433
434 @Override
435 public void error(final String message, final Supplier<?>... paramSuppliers) {
436 logIfEnabled(FQCN, Level.ERROR, null, message, paramSuppliers);
437 }
438
439 @Override
440 public void error(final Marker marker, final MessageSupplier msgSupplier) {
441 logIfEnabled(FQCN, Level.ERROR, marker, msgSupplier, (Throwable) null);
442 }
443
444 @Override
445 public void error(final Marker marker, final MessageSupplier msgSupplier, final Throwable t) {
446 logIfEnabled(FQCN, Level.ERROR, marker, msgSupplier, t);
447 }
448
449 @Override
450 public void error(final MessageSupplier msgSupplier) {
451 logIfEnabled(FQCN, Level.ERROR, null, msgSupplier, (Throwable) null);
452 }
453
454 @Override
455 public void error(final MessageSupplier msgSupplier, final Throwable t) {
456 logIfEnabled(FQCN, Level.ERROR, null, msgSupplier, t);
457 }
458
459 @Override
357460 public void exit() {
358461 exit(FQCN, null);
359462 }
456559 }
457560
458561 @Override
562 public void fatal(final Supplier<?> msgSupplier) {
563 logIfEnabled(FQCN, Level.FATAL, null, msgSupplier, (Throwable) null);
564 }
565
566 @Override
567 public void fatal(final Supplier<?> msgSupplier, final Throwable t) {
568 logIfEnabled(FQCN, Level.FATAL, null, msgSupplier, t);
569 }
570
571 @Override
572 public void fatal(final Marker marker, final Supplier<?> msgSupplier) {
573 logIfEnabled(FQCN, Level.FATAL, marker, msgSupplier, (Throwable) null);
574 }
575
576 @Override
577 public void fatal(final Marker marker, final String message, final Supplier<?>... paramSuppliers) {
578 logIfEnabled(FQCN, Level.FATAL, marker, message, paramSuppliers);
579 }
580
581 @Override
582 public void fatal(final Marker marker, final Supplier<?> msgSupplier, final Throwable t) {
583 logIfEnabled(FQCN, Level.FATAL, marker, msgSupplier, t);
584 }
585
586 @Override
587 public void fatal(final String message, final Supplier<?>... paramSuppliers) {
588 logIfEnabled(FQCN, Level.FATAL, null, message, paramSuppliers);
589 }
590
591 @Override
592 public void fatal(final Marker marker, final MessageSupplier msgSupplier) {
593 logIfEnabled(FQCN, Level.FATAL, marker, msgSupplier, (Throwable) null);
594 }
595
596 @Override
597 public void fatal(final Marker marker, final MessageSupplier msgSupplier, final Throwable t) {
598 logIfEnabled(FQCN, Level.FATAL, marker, msgSupplier, t);
599 }
600
601 @Override
602 public void fatal(final MessageSupplier msgSupplier) {
603 logIfEnabled(FQCN, Level.FATAL, null, msgSupplier, (Throwable) null);
604 }
605
606 @Override
607 public void fatal(final MessageSupplier msgSupplier, final Throwable t) {
608 logIfEnabled(FQCN, Level.FATAL, null, msgSupplier, t);
609 }
610
611 @Override
459612 public MessageFactory getMessageFactory() {
460613 return messageFactory;
461614 }
533686 @Override
534687 public void info(final String message, final Throwable t) {
535688 logIfEnabled(FQCN, Level.INFO, null, message, t);
689 }
690
691 @Override
692 public void info(final Supplier<?> msgSupplier) {
693 logIfEnabled(FQCN, Level.INFO, null, msgSupplier, (Throwable) null);
694 }
695
696 @Override
697 public void info(final Supplier<?> msgSupplier, final Throwable t) {
698 logIfEnabled(FQCN, Level.INFO, null, msgSupplier, t);
699 }
700
701 @Override
702 public void info(final Marker marker, final Supplier<?> msgSupplier) {
703 logIfEnabled(FQCN, Level.INFO, marker, msgSupplier, (Throwable) null);
704 }
705
706 @Override
707 public void info(final Marker marker, final String message, final Supplier<?>... paramSuppliers) {
708 logIfEnabled(FQCN, Level.INFO, marker, message, paramSuppliers);
709 }
710
711 @Override
712 public void info(final Marker marker, final Supplier<?> msgSupplier, final Throwable t) {
713 logIfEnabled(FQCN, Level.INFO, marker, msgSupplier, t);
714 }
715
716 @Override
717 public void info(final String message, final Supplier<?>... paramSuppliers) {
718 logIfEnabled(FQCN, Level.INFO, null, message, paramSuppliers);
719 }
720
721 @Override
722 public void info(final Marker marker, final MessageSupplier msgSupplier) {
723 logIfEnabled(FQCN, Level.INFO, marker, msgSupplier, (Throwable) null);
724 }
725
726 @Override
727 public void info(final Marker marker, final MessageSupplier msgSupplier, final Throwable t) {
728 logIfEnabled(FQCN, Level.INFO, marker, msgSupplier, t);
729 }
730
731 @Override
732 public void info(final MessageSupplier msgSupplier) {
733 logIfEnabled(FQCN, Level.INFO, null, msgSupplier, (Throwable) null);
734 }
735
736 @Override
737 public void info(final MessageSupplier msgSupplier, final Throwable t) {
738 logIfEnabled(FQCN, Level.INFO, null, msgSupplier, t);
536739 }
537740
538741 @Override
675878 @Override
676879 public void log(final Level level, final String message, final Throwable t) {
677880 logIfEnabled(FQCN, level, null, message, t);
881 }
882
883 @Override
884 public void log(final Level level, final Supplier<?> msgSupplier) {
885 logIfEnabled(FQCN, level, null, msgSupplier, (Throwable) null);
886 }
887
888 @Override
889 public void log(final Level level, final Supplier<?> msgSupplier, final Throwable t) {
890 logIfEnabled(FQCN, level, null, msgSupplier, t);
891 }
892
893 @Override
894 public void log(final Level level, final Marker marker, final Supplier<?> msgSupplier) {
895 logIfEnabled(FQCN, level, marker, msgSupplier, (Throwable) null);
896 }
897
898 @Override
899 public void log(final Level level, final Marker marker, final String message, final Supplier<?>... paramSuppliers) {
900 logIfEnabled(FQCN, level, marker, message, paramSuppliers);
901 }
902
903 @Override
904 public void log(final Level level, final Marker marker, final Supplier<?> msgSupplier, final Throwable t) {
905 logIfEnabled(FQCN, level, marker, msgSupplier, t);
906 }
907
908 @Override
909 public void log(final Level level, final String message, final Supplier<?>... paramSuppliers) {
910 logIfEnabled(FQCN, level, null, message, paramSuppliers);
911 }
912
913 @Override
914 public void log(final Level level, final Marker marker, final MessageSupplier msgSupplier) {
915 logIfEnabled(FQCN, level, marker, msgSupplier, (Throwable) null);
916 }
917
918 @Override
919 public void log(final Level level, final Marker marker, final MessageSupplier msgSupplier, final Throwable t) {
920 logIfEnabled(FQCN, level, marker, msgSupplier, t);
921 }
922
923 @Override
924 public void log(final Level level, final MessageSupplier msgSupplier) {
925 logIfEnabled(FQCN, level, null, msgSupplier, (Throwable) null);
926 }
927
928 @Override
929 public void log(final Level level, final MessageSupplier msgSupplier, final Throwable t) {
930 logIfEnabled(FQCN, level, null, msgSupplier, t);
678931 }
679932
680933 @Override
686939 }
687940
688941 @Override
942 public void logIfEnabled(final String fqcn, final Level level, final Marker marker,
943 final MessageSupplier msgSupplier, final Throwable t) {
944 if (isEnabled(level, marker, msgSupplier, t)) {
945 logMessage(fqcn, level, marker, msgSupplier, t);
946 }
947 }
948
949 @Override
689950 public void logIfEnabled(final String fqcn, final Level level, final Marker marker, final Object message,
690951 final Throwable t) {
691952 if (isEnabled(level, marker, message, t)) {
694955 }
695956
696957 @Override
958 public void logIfEnabled(final String fqcn, final Level level, final Marker marker, final Supplier<?> msgSupplier,
959 final Throwable t) {
960 if (isEnabled(level, marker, msgSupplier, t)) {
961 logMessage(fqcn, level, marker, msgSupplier, t);
962 }
963 }
964
965 @Override
697966 public void logIfEnabled(final String fqcn, final Level level, final Marker marker, final String message) {
698967 if (isEnabled(level, marker, message)) {
699968 logMessage(fqcn, level, marker, message);
969 }
970 }
971
972 @Override
973 public void logIfEnabled(final String fqcn, final Level level, final Marker marker, final String message,
974 final Supplier<?>... paramSuppliers) {
975 if (isEnabled(level, marker, message)) {
976 logMessage(fqcn, level, marker, message, paramSuppliers);
700977 }
701978 }
702979
721998 logMessage(fqcn, level, marker, messageFactory.newMessage(message), t);
722999 }
7231000
1001 protected void logMessage(final String fqcn, final Level level, final Marker marker,
1002 final MessageSupplier msgSupplier, final Throwable t) {
1003 final Message message = LambdaUtil.get(msgSupplier);
1004 logMessage(fqcn, level, marker, message, t);
1005 }
1006
1007 protected void logMessage(final String fqcn, final Level level, final Marker marker, final Supplier<?> msgSupplier,
1008 final Throwable t) {
1009 final Object message = LambdaUtil.get(msgSupplier);
1010 logMessage(fqcn, level, marker, messageFactory.newMessage(message), t);
1011 }
1012
7241013 protected void logMessage(final String fqcn, final Level level, final Marker marker, final String message,
7251014 final Throwable t) {
7261015 logMessage(fqcn, level, marker, messageFactory.newMessage(message), t);
7341023 protected void logMessage(final String fqcn, final Level level, final Marker marker, final String message,
7351024 final Object... params) {
7361025 final Message msg = messageFactory.newMessage(message, params);
1026 logMessage(fqcn, level, marker, msg, msg.getThrowable());
1027 }
1028
1029 protected void logMessage(final String fqcn, final Level level, final Marker marker, final String message,
1030 final Supplier<?>... paramSuppliers) {
1031 final Message msg = messageFactory.newMessage(message, LambdaUtil.getAll(paramSuppliers));
7371032 logMessage(fqcn, level, marker, msg, msg.getThrowable());
7381033 }
7391034
8541149 }
8551150
8561151 @Override
1152 public void trace(final Supplier<?> msgSupplier) {
1153 logIfEnabled(FQCN, Level.TRACE, null, msgSupplier, (Throwable) null);
1154 }
1155
1156 @Override
1157 public void trace(final Supplier<?> msgSupplier, final Throwable t) {
1158 logIfEnabled(FQCN, Level.TRACE, null, msgSupplier, t);
1159 }
1160
1161 @Override
1162 public void trace(final Marker marker, final Supplier<?> msgSupplier) {
1163 logIfEnabled(FQCN, Level.TRACE, marker, msgSupplier, (Throwable) null);
1164 }
1165
1166 @Override
1167 public void trace(final Marker marker, final String message, final Supplier<?>... paramSuppliers) {
1168 logIfEnabled(FQCN, Level.TRACE, marker, message, paramSuppliers);
1169 }
1170
1171 @Override
1172 public void trace(final Marker marker, final Supplier<?> msgSupplier, final Throwable t) {
1173 logIfEnabled(FQCN, Level.TRACE, marker, msgSupplier, t);
1174 }
1175
1176 @Override
1177 public void trace(final String message, final Supplier<?>... paramSuppliers) {
1178 logIfEnabled(FQCN, Level.TRACE, null, message, paramSuppliers);
1179 }
1180
1181 @Override
1182 public void trace(final Marker marker, final MessageSupplier msgSupplier) {
1183 logIfEnabled(FQCN, Level.TRACE, marker, msgSupplier, (Throwable) null);
1184 }
1185
1186 @Override
1187 public void trace(final Marker marker, final MessageSupplier msgSupplier, final Throwable t) {
1188 logIfEnabled(FQCN, Level.TRACE, marker, msgSupplier, t);
1189 }
1190
1191 @Override
1192 public void trace(final MessageSupplier msgSupplier) {
1193 logIfEnabled(FQCN, Level.TRACE, null, msgSupplier, (Throwable) null);
1194 }
1195
1196 @Override
1197 public void trace(final MessageSupplier msgSupplier, final Throwable t) {
1198 logIfEnabled(FQCN, Level.TRACE, null, msgSupplier, t);
1199 }
1200
1201 @Override
8571202 public void warn(final Marker marker, final Message msg) {
8581203 logIfEnabled(FQCN, Level.WARN, marker, msg, null);
8591204 }
8681213 logIfEnabled(FQCN, Level.WARN, marker, message, null);
8691214 }
8701215
871 /* -- FIXME: this comment looks lost
872 * Instead of one single method with Object... declared the following methods explicitly specify parameters because
873 * they perform dramatically better than having the JVM convert them to an array.
874 */
875
8761216 @Override
8771217 public void warn(final Marker marker, final Object message, final Throwable t) {
8781218 logIfEnabled(FQCN, Level.WARN, marker, message, t);
9281268 logIfEnabled(FQCN, Level.WARN, null, message, t);
9291269 }
9301270
1271 @Override
1272 public void warn(final Supplier<?> msgSupplier) {
1273 logIfEnabled(FQCN, Level.WARN, null, msgSupplier, (Throwable) null);
1274 }
1275
1276 @Override
1277 public void warn(final Supplier<?> msgSupplier, final Throwable t) {
1278 logIfEnabled(FQCN, Level.WARN, null, msgSupplier, t);
1279 }
1280
1281 @Override
1282 public void warn(final Marker marker, final Supplier<?> msgSupplier) {
1283 logIfEnabled(FQCN, Level.WARN, marker, msgSupplier, (Throwable) null);
1284 }
1285
1286 @Override
1287 public void warn(final Marker marker, final String message, final Supplier<?>... paramSuppliers) {
1288 logIfEnabled(FQCN, Level.WARN, marker, message, paramSuppliers);
1289 }
1290
1291 @Override
1292 public void warn(final Marker marker, final Supplier<?> msgSupplier, final Throwable t) {
1293 logIfEnabled(FQCN, Level.WARN, marker, msgSupplier, t);
1294 }
1295
1296 @Override
1297 public void warn(final String message, final Supplier<?>... paramSuppliers) {
1298 logIfEnabled(FQCN, Level.WARN, null, message, paramSuppliers);
1299 }
1300
1301 @Override
1302 public void warn(final Marker marker, final MessageSupplier msgSupplier) {
1303 logIfEnabled(FQCN, Level.WARN, marker, msgSupplier, (Throwable) null);
1304 }
1305
1306 @Override
1307 public void warn(final Marker marker, final MessageSupplier msgSupplier, final Throwable t) {
1308 logIfEnabled(FQCN, Level.WARN, marker, msgSupplier, t);
1309 }
1310
1311 @Override
1312 public void warn(final MessageSupplier msgSupplier) {
1313 logIfEnabled(FQCN, Level.WARN, null, msgSupplier, (Throwable) null);
1314 }
1315
1316 @Override
1317 public void warn(final MessageSupplier msgSupplier, final Throwable t) {
1318 logIfEnabled(FQCN, Level.WARN, null, msgSupplier, t);
1319 }
9311320 }
3434 * A map to store loggers for their given LoggerContexts.
3535 */
3636 protected final Map<LoggerContext, ConcurrentMap<String, L>> registry =
37 new WeakHashMap<LoggerContext, ConcurrentMap<String, L>>();
37 new WeakHashMap<>();
3838
3939 @Override
4040 public L getLogger(final String name) {
4141 final LoggerContext context = getContext();
4242 final ConcurrentMap<String, L> loggers = getLoggersInContext(context);
43 if (loggers.containsKey(name)) {
44 return loggers.get(name);
43 final L logger = loggers.get(name);
44 if (logger != null) {
45 return logger;
4546 }
4647 loggers.putIfAbsent(name, newLogger(name, context));
4748 return loggers.get(name);
5758 synchronized (registry) {
5859 ConcurrentMap<String, L> loggers = registry.get(context);
5960 if (loggers == null) {
60 loggers = new ConcurrentHashMap<String, L>();
61 loggers = new ConcurrentHashMap<>();
6162 registry.put(context, loggers);
6263 }
6364 return loggers;
5252 @Override
5353 protected Map<String, String> childValue(final Map<String, String> parentValue) {
5454 return parentValue != null && isMapEnabled //
55 ? Collections.unmodifiableMap(new HashMap<String, String>(parentValue)) //
55 ? Collections.unmodifiableMap(new HashMap<>(parentValue)) //
5656 : null;
5757 }
5858 };
5959 }
6060 // if not inheritable, return plain ThreadLocal with null as initial value
61 return new ThreadLocal<Map<String, String>>();
61 return new ThreadLocal<>();
6262 }
6363
6464 @Override
6767 return;
6868 }
6969 Map<String, String> map = localMap.get();
70 map = map == null ? new HashMap<String, String>() : new HashMap<String, String>(map);
70 map = map == null ? new HashMap<String, String>() : new HashMap<>(map);
7171 map.put(key, value);
7272 localMap.set(Collections.unmodifiableMap(map));
7373 }
8282 public void remove(final String key) {
8383 final Map<String, String> map = localMap.get();
8484 if (map != null) {
85 final Map<String, String> copy = new HashMap<String, String>(map);
85 final Map<String, String> copy = new HashMap<>(map);
8686 copy.remove(key);
8787 localMap.set(Collections.unmodifiableMap(copy));
8888 }
102102 @Override
103103 public Map<String, String> getCopy() {
104104 final Map<String, String> map = localMap.get();
105 return map == null ? new HashMap<String, String>() : new HashMap<String, String>(map);
105 return map == null ? new HashMap<String, String>() : new HashMap<>(map);
106106 }
107107
108108 @Override
1919 import java.util.Collections;
2020 import java.util.Iterator;
2121 import java.util.List;
22 import java.util.NoSuchElementException;
2322
2423 import org.apache.logging.log4j.ThreadContext.ContextStack;
2524 import org.apache.logging.log4j.util.Strings;
3231
3332 private static final long serialVersionUID = 5050501L;
3433
35 private static final ThreadLocal<MutableThreadContextStack> stack = new ThreadLocal<MutableThreadContextStack>();
34 private static final ThreadLocal<MutableThreadContextStack> stack = new ThreadLocal<>();
3635
3736 private final boolean useStack;
3837
128127 final ThreadContextStack other = (ThreadContextStack) obj;
129128 final MutableThreadContextStack values = stack.get();
130129 if (values == null) {
131 return other == null;
130 return false;
132131 }
133132 return values.equals(other);
134133 }
169168 public String peek() {
170169 final MutableThreadContextStack values = stack.get();
171170 if (values == null || values.size() == 0) {
172 return null;
171 return Strings.EMPTY;
173172 }
174173 return values.peek();
175174 }
181180 }
182181 final MutableThreadContextStack values = stack.get();
183182 if (values == null || values.size() == 0) {
184 throw new NoSuchElementException("The ThreadContext stack is empty");
183 // Like version 1.2
184 return Strings.EMPTY;
185185 }
186186 final MutableThreadContextStack copy = (MutableThreadContextStack) values.copy();
187187 final String result = copy.pop();
1919 import org.apache.logging.log4j.Logger;
2020 import org.apache.logging.log4j.Marker;
2121 import org.apache.logging.log4j.message.Message;
22 import org.apache.logging.log4j.util.MessageSupplier;
23 import org.apache.logging.log4j.util.Supplier;
2224
2325 /**
2426 * Extends the {@code Logger} interface with methods that facilitate implementing or extending {@code Logger}s. Users
151153 * @param t the exception to log, including its stack trace.
152154 */
153155 void logMessage(String fqcn, Level level, Marker marker, Message message, Throwable t);
156
157 /**
158 * Logs a message which is only to be constructed if the specified level is active.
159 *
160 * @param fqcn The fully qualified class name of the logger entry point, used to determine the caller class and
161 * method when location information needs to be logged.
162 * @param level The logging Level to check.
163 * @param marker A Marker or null.
164 * @param msgSupplier A function, which when called, produces the desired log message.
165 * @param t the exception to log, including its stack trace.
166 */
167 void logIfEnabled(String fqcn, Level level, Marker marker, MessageSupplier msgSupplier, Throwable t);
168
169 /**
170 * Logs a message whose parameters are only to be constructed if the specified level is active.
171 *
172 * @param fqcn The fully qualified class name of the logger entry point, used to determine the caller class and
173 * method when location information needs to be logged.
174 * @param level The logging Level to check.
175 * @param marker A Marker or null.
176 * @param message The message format.
177 * @param paramSuppliers An array of functions, which when called, produce the desired log message parameters.
178 */
179 void logIfEnabled(String fqcn, Level level, Marker marker, String message, Supplier<?>... paramSuppliers);
180
181 /**
182 * Logs a message which is only to be constructed if the specified level is active.
183 *
184 * @param fqcn The fully qualified class name of the logger entry point, used to determine the caller class and
185 * method when location information needs to be logged.
186 * @param level The logging Level to check.
187 * @param marker A Marker or null.
188 * @param msgSupplier A function, which when called, produces the desired log message.
189 * @param t the exception to log, including its stack trace.
190 */
191 void logIfEnabled(String fqcn, Level level, Marker marker, Supplier<?> msgSupplier, Throwable t);
192
154193 }
2929 Object getExternalContext();
3030
3131 /**
32 * Returns a Logger.
32 * Returns an ExtendedLogger.
3333 * @param name The name of the Logger to return.
3434 * @return The logger with the specified name.
3535 */
3636 ExtendedLogger getLogger(String name);
3737
3838 /**
39 * Returns a Logger.
39 * Returns an ExtendedLogger.
4040 * @param name The name of the Logger to return.
4141 * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change
4242 * the logger but will log a warning if mismatched.
4343 }
4444
4545 public MutableThreadContextStack(final List<String> list) {
46 this.list = new ArrayList<String>(list);
46 this.list = new ArrayList<>(list);
4747 }
4848
4949 private MutableThreadContextStack(final MutableThreadContextStack stack) {
50 this.list = new ArrayList<String>(stack.list);
50 this.list = new ArrayList<>(stack.list);
5151 }
5252
5353 private void checkInvariants() {
101101 if (list == null) {
102102 return;
103103 }
104 final List<String> copy = new ArrayList<String>(list.size());
104 final List<String> copy = new ArrayList<>(list.size());
105105 final int count = Math.min(depth, list.size());
106106 for (int i = 0; i < count; i++) {
107107 copy.add(list.get(i));
1515 */
1616 package org.apache.logging.log4j.status;
1717
18 import static org.apache.logging.log4j.util.Chars.SPACE;
19
1820 import java.io.ByteArrayOutputStream;
1921 import java.io.PrintStream;
2022 import java.io.Serializable;
2830 * The Status data.
2931 */
3032 public class StatusData implements Serializable {
33
3134 private static final long serialVersionUID = -4341916115118014017L;
3235
3336 private final long timestamp;
3437 private final StackTraceElement caller;
3538 private final Level level;
3639 private final Message msg;
40 private String threadName;
3741 private final Throwable throwable;
3842
3943 /**
4246 * @param level The logging level.
4347 * @param msg The message String.
4448 * @param t The Error or Exception that occurred.
49 * @param threadName The thread name
4550 */
46 public StatusData(final StackTraceElement caller, final Level level, final Message msg, final Throwable t) {
51 public StatusData(final StackTraceElement caller, final Level level, final Message msg, final Throwable t, String threadName) {
4752 this.timestamp = System.currentTimeMillis();
4853 this.caller = caller;
4954 this.level = level;
5055 this.msg = msg;
5156 this.throwable = t;
57 this.threadName = threadName;
5258 }
5359
5460 /**
8389 return msg;
8490 }
8591
92 public String getThreadName() {
93 if (threadName == null) {
94 threadName = Thread.currentThread().getName();
95 }
96 return threadName;
97 }
98
8699 /**
87100 * Returns the Throwable associated with the event.
88101 * @return The Throwable associated with the event.
99112 final StringBuilder sb = new StringBuilder();
100113 final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS");
101114 sb.append(format.format(new Date(timestamp)));
102 sb.append(' ');
115 sb.append(SPACE);
116 sb.append(getThreadName());
117 sb.append(SPACE);
103118 sb.append(level.toString());
104 sb.append(' ');
119 sb.append(SPACE);
105120 sb.append(msg.getFormattedMessage());
106121 final Object[] params = msg.getParameters();
107122 Throwable t;
111126 t = throwable;
112127 }
113128 if (t != null) {
114 sb.append(' ');
129 sb.append(SPACE);
115130 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
116131 t.printStackTrace(new PrintStream(baos));
117132 sb.append(baos.toString());
3737 import org.apache.logging.log4j.util.Strings;
3838
3939 /**
40 * Mechanism to record events that occur in the logging system.
40 * Records events that occur in the logging system.
4141 */
4242 public final class StatusLogger extends AbstractLogger {
4343
6161
6262 private final SimpleLogger logger;
6363
64 private final Collection<StatusListener> listeners = new CopyOnWriteArrayList<StatusListener>();
64 private final Collection<StatusListener> listeners = new CopyOnWriteArrayList<>();
65
6566 @SuppressWarnings("NonSerializableFieldInSerializableClass") // ReentrantReadWriteLock is Serializable
6667 private final ReadWriteLock listenersLock = new ReentrantReadWriteLock();
6768
68 private final Queue<StatusData> messages = new BoundedQueue<StatusData>(MAX_ENTRIES);
69 private final Queue<StatusData> messages = new BoundedQueue<>(MAX_ENTRIES);
70
6971 @SuppressWarnings("NonSerializableFieldInSerializableClass") // ReentrantLock is Serializable
7072 private final Lock msgLock = new ReentrantLock();
7173
9092 }
9193
9294 /**
93 * Register a new listener.
95 * Registers a new listener.
9496 * @param listener The StatusListener to register.
9597 */
9698 public void registerListener(final StatusListener listener) {
107109 }
108110
109111 /**
110 * Remove a StatusListener.
112 * Removes a StatusListener.
111113 * @param listener The StatusListener to remove.
112114 */
113115 public void removeListener(final StatusListener listener) {
116118 try {
117119 listeners.remove(listener);
118120 int lowest = Level.toLevel(DEFAULT_STATUS_LEVEL, Level.WARN).intLevel();
119 for (final StatusListener l : listeners) {
120 final int level = l.getStatusLevel().intLevel();
121 for (final StatusListener statusListener : listeners) {
122 final int level = statusListener.getStatusLevel().intLevel();
121123 if (lowest < level) {
122124 lowest = level;
123125 }
167169 public List<StatusData> getStatusData() {
168170 msgLock.lock();
169171 try {
170 return new ArrayList<StatusData>(messages);
172 return new ArrayList<>(messages);
171173 } finally {
172174 msgLock.unlock();
173175 }
191193 }
192194
193195 /**
194 * Add an event.
196 * Adds an event.
195197 * @param marker The Marker
196198 * @param fqcn The fully qualified class name of the <b>caller</b>
197199 * @param level The logging level
204206 if (fqcn != null) {
205207 element = getStackTraceElement(fqcn, Thread.currentThread().getStackTrace());
206208 }
207 final StatusData data = new StatusData(element, level, msg, t);
209 final StatusData data = new StatusData(element, level, msg, t, null);
208210 msgLock.lock();
209211 try {
210212 messages.add(data);
275277 }
276278
277279 /**
278 * Queue for status events.
280 * Queues for status events.
279281 * @param <E> Object type to be stored in the queue.
280282 */
281283 private class BoundedQueue<E> extends ConcurrentLinkedQueue<E> {
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.util;
17
18 /**
19 * <em>Consider this class private.</em>
20 */
21 public class Chars {
22
23 public static final char CR = '\r';
24 public static final char DQUOTE = '\"';
25 public static final char EQ = '=';
26 public static final char LF = '\n';
27 public static final char QUOTE = '\'';
28 public static final char SPACE = ' ';
29 public static final char TAB = '\t';
30
31 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.util;
18
19 import org.apache.logging.log4j.message.Message;
20
21
22 /**
23 * Utility class for lambda support.
24 */
25 public class LambdaUtil {
26 /**
27 * Private constructor: this class is not intended to be instantiated.
28 */
29 private LambdaUtil() {
30 }
31
32 /**
33 * Converts an array of lambda expressions into an array of their evaluation results.
34 *
35 * @param suppliers an array of lambda expressions or {@code null}
36 * @return an array containing the results of evaluating the lambda expressions (or {@code null} if the suppliers
37 * array was {@code null}
38 */
39 public static Object[] getAll(final Supplier<?>... suppliers) {
40 if (suppliers == null) {
41 return null;
42 }
43 final Object[] result = new Object[suppliers.length];
44 for (int i = 0; i < result.length; i++) {
45 result[i] = get(suppliers[i]);
46 }
47 return result;
48 }
49
50 /**
51 * Returns the result of evaluating the specified function.
52 * @param supplier a lambda expression or {@code null}
53 * @return the results of evaluating the lambda expression (or {@code null} if the supplier
54 * was {@code null}
55 */
56 public static Object get(final Supplier<?> supplier) {
57 if (supplier == null) {
58 return null;
59 }
60 return supplier.get();
61 }
62
63 /**
64 * Returns the Message supplied by the specified function.
65 * @param supplier a lambda expression or {@code null}
66 * @return the Message resulting from evaluating the lambda expression (or {@code null} if the supplier was
67 * {@code null}
68 */
69 public static Message get(final MessageSupplier supplier) {
70 if (supplier == null) {
71 return null;
72 }
73 return supplier.get();
74 }
75 }
9393 return cl;
9494 }
9595 final ClassLoader ccl = LoaderUtil.class.getClassLoader();
96 return ccl == null ? ClassLoader.getSystemClassLoader() : ccl;
96 return ccl == null && !GET_CLASS_LOADER_DISABLED ? ClassLoader.getSystemClassLoader() : ccl;
9797 }
9898 }
9999
180180 */
181181 public static Collection<URL> findResources(final String resource) {
182182 final Collection<UrlResource> urlResources = findUrlResources(resource);
183 final Collection<URL> resources = new LinkedHashSet<URL>(urlResources.size());
183 final Collection<URL> resources = new LinkedHashSet<>(urlResources.size());
184184 for (final UrlResource urlResource : urlResources) {
185185 resources.add(urlResource.getUrl());
186186 }
191191 final ClassLoader[] candidates = {
192192 getThreadContextClassLoader(),
193193 LoaderUtil.class.getClassLoader(),
194 ClassLoader.getSystemClassLoader()
194 GET_CLASS_LOADER_DISABLED ? null : ClassLoader.getSystemClassLoader()
195195 };
196 final Collection<UrlResource> resources = new LinkedHashSet<UrlResource>();
196 final Collection<UrlResource> resources = new LinkedHashSet<>();
197197 for (final ClassLoader cl : candidates) {
198198 if (cl != null) {
199199 try {
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.util;
18
19 import org.apache.logging.log4j.message.Message;
20
21 /**
22 * Classes implementing this interface know how to supply {@link Message}s.
23 *
24 * <p>This is a <a href="https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html">functional
25 * interface</a> intended to support lambda expressions in log4j 2.
26 *
27 * <p>Implementors are free to cache values or return a new or distinct value each time the supplier is invoked.
28 *
29 * @since 2.4
30 */
31 public interface MessageSupplier {
32
33 /**
34 * Gets a Message.
35 *
36 * @return a Message
37 */
38 Message get();
39 }
1818 import java.io.IOException;
1919 import java.io.InputStream;
2020 import java.net.URL;
21 import java.util.ArrayList;
22 import java.util.List;
2123 import java.util.Properties;
2224
2325 import org.apache.logging.log4j.Logger;
236238 return new Properties();
237239 }
238240 }
241
242 /**
243 * Extracts properties that start with or are equals to the specific prefix and returns them in a
244 * new Properties object with the prefix removed.
245 * @param properties The Properties to evaluate.
246 * @param prefix The prefix to extract.
247 * @return The subset of properties.
248 */
249 public static Properties extractSubset(Properties properties, String prefix) {
250 Properties subset = new Properties();
251
252 if (prefix == null || prefix.length() == 0) {
253 return subset;
254 }
255
256 String prefixToMatch = prefix.charAt(prefix.length() - 1) != '.' ? prefix + '.' : prefix;
257
258 List<String> keys = new ArrayList<>();
259
260 for (String key : properties.stringPropertyNames()) {
261 if (key.startsWith(prefixToMatch)) {
262 subset.setProperty(key.substring(prefixToMatch.length()), properties.getProperty(key));
263 keys.add(key);
264 }
265 }
266 for (String key : keys) {
267 properties.remove(key);
268 }
269
270 return subset;
271 }
239272 }
4848
4949 private static final Logger LOGGER = StatusLogger.getLogger();
5050
51 protected static final Collection<Provider> PROVIDERS = new HashSet<Provider>();
51 protected static final Collection<Provider> PROVIDERS = new HashSet<>();
5252
5353 /**
5454 * Guards the ProviderUtil singleton instance from lazy initialization. This is primarily used for OSGi support.
116116 if (INSTANCE == null) {
117117 try {
118118 STARTUP_LOCK.lockInterruptibly();
119 if (INSTANCE == null) {
120 INSTANCE = new ProviderUtil();
119 try {
120 if (INSTANCE == null) {
121 INSTANCE = new ProviderUtil();
122 }
123 } finally {
124 STARTUP_LOCK.unlock();
121125 }
122126 } catch (final InterruptedException e) {
123127 LOGGER.fatal("Interrupted before Log4j Providers could be loaded.", e);
124128 Thread.currentThread().interrupt();
125 } finally {
126 STARTUP_LOCK.unlock();
127129 }
128130 }
129131 }
148148 if (isValid(element)) {
149149 if (i == depth) {
150150 return element;
151 } else {
152 ++i;
153 }
151 }
152 ++i;
154153 }
155154 }
156155 LOGGER.error("Could not find an appropriate StackTraceElement at index {}", depth);
269268 // benchmarks show that using the SecurityManager is much faster than looping through getCallerClass(int)
270269 if (SECURITY_MANAGER != null) {
271270 final Class<?>[] array = SECURITY_MANAGER.getClassContext();
272 final Stack<Class<?>> classes = new Stack<Class<?>>();
271 final Stack<Class<?>> classes = new Stack<>();
273272 classes.ensureCapacity(array.length);
274273 for (final Class<?> clazz : array) {
275274 classes.push(clazz);
278277 }
279278 // slower version using getCallerClass where we cannot use a SecurityManager
280279 if (supportsFastReflection()) {
281 final Stack<Class<?>> classes = new Stack<Class<?>>();
280 final Stack<Class<?>> classes = new Stack<>();
282281 Class<?> clazz;
283282 for (int i = 1; null != (clazz = getCallerClass(i)); i++) {
284283 classes.push(clazz);
285284 }
286285 return classes;
287286 }
288 return new Stack<Class<?>>();
287 return new Stack<>();
289288 }
290289
291290 static final class PrivateSecurityManager extends SecurityManager {
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.util;
17
18 import java.util.Map.Entry;
19
20 /**
21 * <em>Consider this class private.</em>
22 */
23 public class StringBuilders {
24
25 /**
26 * Appends in the following format: double quoted value.
27 *
28 * @param sb
29 * a string builder
30 * @param value
31 * a value
32 * @return {@code "value"}
33 */
34 public static StringBuilder appendDqValue(final StringBuilder sb, final Object value) {
35 return sb.append(Chars.DQUOTE).append(value).append(Chars.DQUOTE);
36 }
37
38 /**
39 * Appends in the following format: key=double quoted value.
40 *
41 * @param sb
42 * a string builder
43 * @param entry
44 * a map entry
45 * @return {@code key="value"}
46 */
47 public static StringBuilder appendKeyDqValue(final StringBuilder sb, final Entry<String, String> entry) {
48 return appendKeyDqValue(sb, entry.getKey(), entry.getValue());
49 }
50
51 /**
52 * Appends in the following format: key=double quoted value.
53 *
54 * @param sb
55 * a string builder
56 * @param key
57 * a key
58 * @param value
59 * a value
60 * @return {@code key="value"}
61 */
62 public static StringBuilder appendKeyDqValue(final StringBuilder sb, final String key, final Object value) {
63 return sb.append(key).append(Chars.EQ).append(Chars.DQUOTE).append(value).append(Chars.DQUOTE);
64 }
65
66 }
1717
1818 /**
1919 * <em>Consider this class private.</em>
20 *
2021 * @see <a href="http://commons.apache.org/proper/commons-lang/">Apache Commons Lang</a>
2122 */
2223 public final class Strings {
2627 */
2728 public static final String EMPTY = "";
2829
29 private Strings() {
30 /**
31 * Returns a double quoted string.
32 *
33 * @param str
34 * a String
35 * @return {@code "str"}
36 */
37 public static String dquote(final String str) {
38 return Chars.DQUOTE + str + Chars.DQUOTE;
3039 }
3140
3241 /**
33 * <p>Checks if a CharSequence is empty ("") or null.</p>
42 * Checks if a String is blank. A blank string is one that is {@code null}, empty, or when trimmed using
43 * {@link String#trim()} is empty.
44 *
45 * @param s
46 * the String to check, may be {@code null}
47 * @return {@code true} if the String is {@code null}, empty, or trims to empty.
48 */
49 public static boolean isBlank(final String s) {
50 return s == null || s.trim().isEmpty();
51 }
52
53 /**
54 * <p>
55 * Checks if a CharSequence is empty ("") or null.
56 * </p>
3457 *
3558 * <pre>
3659 * Strings.isEmpty(null) = true
4063 * Strings.isEmpty(" bob ") = false
4164 * </pre>
4265 *
43 * <p>NOTE: This method changed in Lang version 2.0.
44 * It no longer trims the CharSequence.
45 * That functionality is available in isBlank().</p>
66 * <p>
67 * NOTE: This method changed in Lang version 2.0. It no longer trims the CharSequence. That functionality is
68 * available in isBlank().
69 * </p>
4670 *
47 * <p>Copied from Apache Commons Lang org.apache.commons.lang3.StringUtils.isEmpty(CharSequence)</p>
71 * <p>
72 * Copied from Apache Commons Lang org.apache.commons.lang3.StringUtils.isEmpty(CharSequence)
73 * </p>
4874 *
49 * @param cs the CharSequence to check, may be null
75 * @param cs
76 * the CharSequence to check, may be null
5077 * @return {@code true} if the CharSequence is empty or null
5178 */
5279 public static boolean isEmpty(final CharSequence cs) {
5481 }
5582
5683 /**
57 * <p>Checks if a CharSequence is not empty ("") and not null.</p>
84 * Checks if a String is not blank. The opposite of {@link #isBlank(String)}.
85 *
86 * @param s
87 * the String to check, may be {@code null}
88 * @return {@code true} if the String is non-{@code null} and has content after being trimmed.
89 */
90 public static boolean isNotBlank(final String s) {
91 return !isBlank(s);
92 }
93
94 /**
95 * <p>
96 * Checks if a CharSequence is not empty ("") and not null.
97 * </p>
5898 *
5999 * <pre>
60100 * Strings.isNotEmpty(null) = false
64104 * Strings.isNotEmpty(" bob ") = true
65105 * </pre>
66106 *
67 * <p>Copied from Apache Commons Lang org.apache.commons.lang3.StringUtils.isNotEmpty(CharSequence)</p>
107 * <p>
108 * Copied from Apache Commons Lang org.apache.commons.lang3.StringUtils.isNotEmpty(CharSequence)
109 * </p>
68110 *
69 * @param cs the CharSequence to check, may be null
111 * @param cs
112 * the CharSequence to check, may be null
70113 * @return {@code true} if the CharSequence is not empty and not null
71114 */
72115 public static boolean isNotEmpty(final CharSequence cs) {
74117 }
75118
76119 /**
77 * Checks if a String is blank. A blank string is one that is {@code null}, empty, or when trimmed using
78 * {@link String#trim()} is empty.
79 *
80 * @param s the String to check, may be {@code null}
81 * @return {@code true} if the String is {@code null}, empty, or trims to empty.
120 * Returns a quoted string.
121 *
122 * @param str
123 * a String
124 * @return {@code 'str'}
82125 */
83 public static boolean isBlank(final String s) {
84 return s == null || s.trim().isEmpty();
126 public static String quote(final String str) {
127 return Chars.QUOTE + str + Chars.QUOTE;
85128 }
86129
87130 /**
88 * Checks if a String is not blank. The opposite of {@link #isBlank(String)}.
89 *
90 * @param s the String to check, may be {@code null}
91 * @return {@code true} if the String is non-{@code null} and has content after being trimmed.
92 */
93 public static boolean isNotBlank(final String s) {
94 return !isBlank(s);
95 }
96
97 /**
98 * <p>Removes control characters (char &lt;= 32) from both
99 * ends of this String returning {@code null} if the String is
131 * <p>
132 * Removes control characters (char &lt;= 32) from both ends of this String returning {@code null} if the String is
100133 * empty ("") after the trim or if it is {@code null}.
101134 *
102 * <p>The String is trimmed using {@link String#trim()}.
103 * Trim removes start and end characters &lt;= 32.</p>
135 * <p>
136 * The String is trimmed using {@link String#trim()}. Trim removes start and end characters &lt;= 32.
137 * </p>
104138 *
105139 * <pre>
106140 * Strings.trimToNull(null) = null
110144 * Strings.trimToNull(" abc ") = "abc"
111145 * </pre>
112146 *
113 * <p>Copied from Apache Commons Lang org.apache.commons.lang3.StringUtils.trimToNull(String)</p>
147 * <p>
148 * Copied from Apache Commons Lang org.apache.commons.lang3.StringUtils.trimToNull(String)
149 * </p>
114150 *
115 * @param str the String to be trimmed, may be null
116 * @return the trimmed String,
117 * {@code null} if only chars &lt;= 32, empty or null String input
151 * @param str
152 * the String to be trimmed, may be null
153 * @return the trimmed String, {@code null} if only chars &lt;= 32, empty or null String input
118154 */
119155 public static String trimToNull(final String str) {
120156 final String ts = str == null ? null : str.trim();
121157 return isEmpty(ts) ? null : ts;
122158 }
123159
160 private Strings() {
161 // empty
162 }
124163 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.util;
18
19 /**
20 * Classes implementing this interface know how to supply a value.
21 *
22 * <p>This is a <a href="https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html">functional
23 * interface</a> intended to support lambda expressions in log4j 2.
24 *
25 * <p>Implementors are free to cache values or return a new or distinct value each time the supplier is invoked.
26 *
27 * @param <T> the type of values returned by this supplier
28 *
29 * @since 2.4
30 */
31 public interface Supplier<T> {
32
33 /**
34 * Gets a value.
35 *
36 * @return a value
37 */
38 T get();
39 }
3333
3434 <section name="Requirements">
3535 <p>
36 The Log4j 2 API requires at least Java 6.
36 As of version 2.4, the Log4j 2 API requires Java 7. Versions 2.3 and earlier require Java 6.
3737 </p>
3838 </section>
3939
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j;
18
19 import java.util.ArrayList;
20 import java.util.List;
21
22 import org.apache.logging.log4j.message.Message;
23 import org.apache.logging.log4j.message.SimpleMessage;
24 import org.apache.logging.log4j.spi.AbstractLogger;
25 import org.apache.logging.log4j.util.MessageSupplier;
26 import org.apache.logging.log4j.util.Supplier;
27 import org.junit.Before;
28 import org.junit.Test;
29
30 import static org.junit.Assert.*;
31
32 /**
33 * Tests the AbstractLogger implementation of the Logger2 interface.
34 */
35 public class LambdaLoggerTest {
36
37 private static class LogEvent {
38 @SuppressWarnings("unused")
39 final String fqcn;
40 final Level level;
41 final Marker marker;
42 final Message message;
43 final Throwable throwable;
44
45 public LogEvent(final String fqcn, final Level level, final Marker marker, final Message message, final Throwable t) {
46 this.fqcn = fqcn;
47 this.level = level;
48 this.marker = marker;
49 this.message = message;
50 this.throwable = t;
51 }
52 }
53
54 private static class Logger2Impl extends AbstractLogger {
55 private static final long serialVersionUID = 1L;
56
57 boolean enabled = true;
58 final List<LambdaLoggerTest.LogEvent> list = new ArrayList<>();
59
60 @Override
61 public boolean isEnabled(final Level level, final Marker marker, final Message message, final Throwable t) {
62 return enabled;
63 }
64
65 @Override
66 public boolean isEnabled(final Level level, final Marker marker, final Object message, final Throwable t) {
67 return enabled;
68 }
69
70 @Override
71 public boolean isEnabled(final Level level, final Marker marker, final String message, final Throwable t) {
72 return enabled;
73 }
74
75 @Override
76 public boolean isEnabled(final Level level, final Marker marker, final String message) {
77 return enabled;
78 }
79
80 @Override
81 public boolean isEnabled(final Level level, final Marker marker, final String message, final Object... params) {
82 return enabled;
83 }
84
85 @Override
86 public void logMessage(final String fqcn, final Level level, final Marker marker, final Message message, final Throwable t) {
87 list.add(new LogEvent(fqcn, level, marker, message, t));
88 }
89
90 @Override
91 public Level getLevel() {
92 return null;
93 }
94
95 public AbstractLogger disable() {
96 enabled = false;
97 return this;
98 }
99
100 public AbstractLogger enable() {
101 enabled = true;
102 return this;
103 }
104 }
105
106 final Logger2Impl logger2 = new Logger2Impl();
107 final String stringMessage = "Hi";
108 final Message message = new SimpleMessage("HiMessage");
109 final Throwable throwable = new Error("I'm Bad");
110 final Marker marker = MarkerManager.getMarker("test");
111
112 private class MyMessageSupplier implements MessageSupplier {
113 public boolean invoked = false;
114
115 @Override
116 public Message get() {
117 invoked = true;
118 return message;
119 }
120 };
121
122 final MyMessageSupplier messageSupplier = new MyMessageSupplier();
123
124 private class MySupplier implements Supplier<String> {
125 public boolean invoked = false;
126
127 @Override
128 public String get() {
129 invoked = true;
130 return stringMessage;
131 }
132 }
133
134 final MySupplier supplier = new MySupplier();
135
136 @Before
137 public void beforeEachTest() {
138 logger2.list.clear();
139 supplier.invoked = false;
140 messageSupplier.invoked = false;
141 }
142
143 @Test
144 public void testDebugMarkerMessageSupplier() {
145 logger2.disable().debug(marker, messageSupplier);
146 assertTrue(logger2.list.isEmpty());
147 assertFalse(messageSupplier.invoked);
148
149 logger2.enable().debug(marker, messageSupplier);
150 assertEquals(1, logger2.list.size());
151 assertTrue(messageSupplier.invoked);
152
153 final LogEvent event = logger2.list.get(0);
154 assertEquals(Level.DEBUG, event.level);
155 assertSame(message, event.message);
156 assertSame(marker, event.marker);
157 }
158
159 @Test
160 public void testDebugMessageSupplier() {
161 logger2.disable().debug(messageSupplier);
162 assertTrue(logger2.list.isEmpty());
163 assertFalse(messageSupplier.invoked);
164
165 logger2.enable().debug(messageSupplier);
166 assertEquals(1, logger2.list.size());
167 assertTrue(messageSupplier.invoked);
168
169 final LogEvent event = logger2.list.get(0);
170 assertEquals(Level.DEBUG, event.level);
171 assertSame(message, event.message);
172 }
173
174 @Test
175 public void testDebugMarkerMessageSupplierThrowable() {
176 logger2.disable().debug(marker, messageSupplier, throwable);
177 assertTrue(logger2.list.isEmpty());
178 assertFalse(messageSupplier.invoked);
179
180 logger2.enable().debug(marker, messageSupplier, throwable);
181 assertEquals(1, logger2.list.size());
182 assertTrue(messageSupplier.invoked);
183
184 final LogEvent event = logger2.list.get(0);
185 assertEquals(Level.DEBUG, event.level);
186 assertSame(marker, event.marker);
187 assertSame(message, event.message);
188 assertSame(throwable, event.throwable);
189 }
190
191 @Test
192 public void testDebugMessageSupplierThrowable() {
193 logger2.disable().debug(messageSupplier, throwable);
194 assertTrue(logger2.list.isEmpty());
195 assertFalse(messageSupplier.invoked);
196
197 logger2.enable().debug(messageSupplier, throwable);
198 assertEquals(1, logger2.list.size());
199 assertTrue(messageSupplier.invoked);
200
201 final LogEvent event = logger2.list.get(0);
202 assertEquals(Level.DEBUG, event.level);
203 assertSame(message, event.message);
204 assertSame(throwable, event.throwable);
205 }
206
207 @Test
208 public void testDebugMarkerSupplier() {
209 logger2.disable().debug(marker, supplier);
210 assertTrue(logger2.list.isEmpty());
211 assertFalse(supplier.invoked);
212
213 logger2.enable().debug(marker, supplier);
214 assertEquals(1, logger2.list.size());
215 assertTrue(supplier.invoked);
216
217 final LogEvent event = logger2.list.get(0);
218 assertEquals(Level.DEBUG, event.level);
219 assertSame(stringMessage, event.message.getFormattedMessage());
220 assertSame(marker, event.marker);
221 }
222
223 @Test
224 public void testDebugSupplier() {
225 logger2.disable().debug(supplier);
226 assertTrue(logger2.list.isEmpty());
227 assertFalse(supplier.invoked);
228
229 logger2.enable().debug(supplier);
230 assertEquals(1, logger2.list.size());
231 assertTrue(supplier.invoked);
232
233 final LogEvent event = logger2.list.get(0);
234 assertEquals(Level.DEBUG, event.level);
235 assertSame(stringMessage, event.message.getFormattedMessage());
236 }
237
238 @Test
239 public void testDebugMarkerSupplierThrowable() {
240 logger2.disable().debug(marker, supplier, throwable);
241 assertTrue(logger2.list.isEmpty());
242 assertFalse(supplier.invoked);
243
244 logger2.enable().debug(marker, supplier, throwable);
245 assertEquals(1, logger2.list.size());
246 assertTrue(supplier.invoked);
247
248 final LogEvent event = logger2.list.get(0);
249 assertEquals(Level.DEBUG, event.level);
250 assertSame(marker, event.marker);
251 assertSame(stringMessage, event.message.getFormattedMessage());
252 assertSame(throwable, event.throwable);
253 }
254
255 @Test
256 public void testDebugSupplierThrowable() {
257 logger2.disable().debug(supplier, throwable);
258 assertTrue(logger2.list.isEmpty());
259 assertFalse(supplier.invoked);
260
261 logger2.enable().debug(supplier, throwable);
262 assertEquals(1, logger2.list.size());
263 assertTrue(supplier.invoked);
264
265 final LogEvent event = logger2.list.get(0);
266 assertEquals(Level.DEBUG, event.level);
267 assertSame(stringMessage, event.message.getFormattedMessage());
268 assertSame(throwable, event.throwable);
269 }
270
271 @Test
272 public void testDebugStringParamSupplier() {
273 logger2.disable().debug("abc {}", supplier);
274 assertTrue(logger2.list.isEmpty());
275 assertFalse(supplier.invoked);
276
277 logger2.enable().debug("abc {}", supplier);
278 assertEquals(1, logger2.list.size());
279 assertTrue(supplier.invoked);
280
281 final LogEvent event = logger2.list.get(0);
282 assertEquals(Level.DEBUG, event.level);
283 assertEquals("abc Hi", event.message.getFormattedMessage());
284 }
285
286 @Test
287 public void testDebugMarkerStringParamSupplier() {
288 logger2.disable().debug(marker, "abc {}", supplier);
289 assertTrue(logger2.list.isEmpty());
290 assertFalse(supplier.invoked);
291
292 logger2.enable().debug(marker, "abc {}", supplier);
293 assertEquals(1, logger2.list.size());
294 assertTrue(supplier.invoked);
295
296 final LogEvent event = logger2.list.get(0);
297 assertEquals(Level.DEBUG, event.level);
298 assertSame(marker, event.marker);
299 assertEquals("abc Hi", event.message.getFormattedMessage());
300 }
301
302 @Test
303 public void testErrorMarkerMessageSupplier() {
304 logger2.disable().error(marker, messageSupplier);
305 assertTrue(logger2.list.isEmpty());
306 assertFalse(messageSupplier.invoked);
307
308 logger2.enable().error(marker, messageSupplier);
309 assertEquals(1, logger2.list.size());
310 assertTrue(messageSupplier.invoked);
311
312 final LogEvent event = logger2.list.get(0);
313 assertEquals(Level.ERROR, event.level);
314 assertSame(message, event.message);
315 assertSame(marker, event.marker);
316 }
317
318 @Test
319 public void testErrorMessageSupplier() {
320 logger2.disable().error(messageSupplier);
321 assertTrue(logger2.list.isEmpty());
322 assertFalse(messageSupplier.invoked);
323
324 logger2.enable().error(messageSupplier);
325 assertEquals(1, logger2.list.size());
326 assertTrue(messageSupplier.invoked);
327
328 final LogEvent event = logger2.list.get(0);
329 assertEquals(Level.ERROR, event.level);
330 assertSame(message, event.message);
331 }
332
333 @Test
334 public void testErrorMarkerMessageSupplierThrowable() {
335 logger2.disable().error(marker, messageSupplier, throwable);
336 assertTrue(logger2.list.isEmpty());
337 assertFalse(messageSupplier.invoked);
338
339 logger2.enable().error(marker, messageSupplier, throwable);
340 assertEquals(1, logger2.list.size());
341 assertTrue(messageSupplier.invoked);
342
343 final LogEvent event = logger2.list.get(0);
344 assertEquals(Level.ERROR, event.level);
345 assertSame(marker, event.marker);
346 assertSame(message, event.message);
347 assertSame(throwable, event.throwable);
348 }
349
350 @Test
351 public void testErrorMessageSupplierThrowable() {
352 logger2.disable().error(messageSupplier, throwable);
353 assertTrue(logger2.list.isEmpty());
354 assertFalse(messageSupplier.invoked);
355
356 logger2.enable().error(messageSupplier, throwable);
357 assertEquals(1, logger2.list.size());
358 assertTrue(messageSupplier.invoked);
359
360 final LogEvent event = logger2.list.get(0);
361 assertEquals(Level.ERROR, event.level);
362 assertSame(message, event.message);
363 assertSame(throwable, event.throwable);
364 }
365
366 @Test
367 public void testErrorMarkerSupplier() {
368 logger2.disable().error(marker, supplier);
369 assertTrue(logger2.list.isEmpty());
370 assertFalse(supplier.invoked);
371
372 logger2.enable().error(marker, supplier);
373 assertEquals(1, logger2.list.size());
374 assertTrue(supplier.invoked);
375
376 final LogEvent event = logger2.list.get(0);
377 assertEquals(Level.ERROR, event.level);
378 assertSame(stringMessage, event.message.getFormattedMessage());
379 assertSame(marker, event.marker);
380 }
381
382 @Test
383 public void testErrorSupplier() {
384 logger2.disable().error(supplier);
385 assertTrue(logger2.list.isEmpty());
386 assertFalse(supplier.invoked);
387
388 logger2.enable().error(supplier);
389 assertEquals(1, logger2.list.size());
390 assertTrue(supplier.invoked);
391
392 final LogEvent event = logger2.list.get(0);
393 assertEquals(Level.ERROR, event.level);
394 assertSame(stringMessage, event.message.getFormattedMessage());
395 }
396
397 @Test
398 public void testErrorMarkerSupplierThrowable() {
399 logger2.disable().error(marker, supplier, throwable);
400 assertTrue(logger2.list.isEmpty());
401 assertFalse(supplier.invoked);
402
403 logger2.enable().error(marker, supplier, throwable);
404 assertEquals(1, logger2.list.size());
405 assertTrue(supplier.invoked);
406
407 final LogEvent event = logger2.list.get(0);
408 assertEquals(Level.ERROR, event.level);
409 assertSame(marker, event.marker);
410 assertSame(stringMessage, event.message.getFormattedMessage());
411 assertSame(throwable, event.throwable);
412 }
413
414 @Test
415 public void testErrorSupplierThrowable() {
416 logger2.disable().error(supplier, throwable);
417 assertTrue(logger2.list.isEmpty());
418 assertFalse(supplier.invoked);
419
420 logger2.enable().error(supplier, throwable);
421 assertEquals(1, logger2.list.size());
422 assertTrue(supplier.invoked);
423
424 final LogEvent event = logger2.list.get(0);
425 assertEquals(Level.ERROR, event.level);
426 assertSame(stringMessage, event.message.getFormattedMessage());
427 assertSame(throwable, event.throwable);
428 }
429
430 @Test
431 public void testErrorStringParamSupplier() {
432 logger2.disable().error("abc {}", supplier);
433 assertTrue(logger2.list.isEmpty());
434 assertFalse(supplier.invoked);
435
436 logger2.enable().error("abc {}", supplier);
437 assertEquals(1, logger2.list.size());
438 assertTrue(supplier.invoked);
439
440 final LogEvent event = logger2.list.get(0);
441 assertEquals(Level.ERROR, event.level);
442 assertEquals("abc Hi", event.message.getFormattedMessage());
443 }
444
445 @Test
446 public void testErrorMarkerStringParamSupplier() {
447 logger2.disable().error(marker, "abc {}", supplier);
448 assertTrue(logger2.list.isEmpty());
449 assertFalse(supplier.invoked);
450
451 logger2.enable().error(marker, "abc {}", supplier);
452 assertEquals(1, logger2.list.size());
453 assertTrue(supplier.invoked);
454
455 final LogEvent event = logger2.list.get(0);
456 assertEquals(Level.ERROR, event.level);
457 assertSame(marker, event.marker);
458 assertEquals("abc Hi", event.message.getFormattedMessage());
459 }
460
461 @Test
462 public void testFatalMarkerMessageSupplier() {
463 logger2.disable().fatal(marker, messageSupplier);
464 assertTrue(logger2.list.isEmpty());
465 assertFalse(messageSupplier.invoked);
466
467 logger2.enable().fatal(marker, messageSupplier);
468 assertEquals(1, logger2.list.size());
469 assertTrue(messageSupplier.invoked);
470
471 final LogEvent event = logger2.list.get(0);
472 assertEquals(Level.FATAL, event.level);
473 assertSame(message, event.message);
474 assertSame(marker, event.marker);
475 }
476
477 @Test
478 public void testFatalMessageSupplier() {
479 logger2.disable().fatal(messageSupplier);
480 assertTrue(logger2.list.isEmpty());
481 assertFalse(messageSupplier.invoked);
482
483 logger2.enable().fatal(messageSupplier);
484 assertEquals(1, logger2.list.size());
485 assertTrue(messageSupplier.invoked);
486
487 final LogEvent event = logger2.list.get(0);
488 assertEquals(Level.FATAL, event.level);
489 assertSame(message, event.message);
490 }
491
492 @Test
493 public void testFatalMarkerMessageSupplierThrowable() {
494 logger2.disable().fatal(marker, messageSupplier, throwable);
495 assertTrue(logger2.list.isEmpty());
496 assertFalse(messageSupplier.invoked);
497
498 logger2.enable().fatal(marker, messageSupplier, throwable);
499 assertEquals(1, logger2.list.size());
500 assertTrue(messageSupplier.invoked);
501
502 final LogEvent event = logger2.list.get(0);
503 assertEquals(Level.FATAL, event.level);
504 assertSame(marker, event.marker);
505 assertSame(message, event.message);
506 assertSame(throwable, event.throwable);
507 }
508
509 @Test
510 public void testFatalMessageSupplierThrowable() {
511 logger2.disable().fatal(messageSupplier, throwable);
512 assertTrue(logger2.list.isEmpty());
513 assertFalse(messageSupplier.invoked);
514
515 logger2.enable().fatal(messageSupplier, throwable);
516 assertEquals(1, logger2.list.size());
517 assertTrue(messageSupplier.invoked);
518
519 final LogEvent event = logger2.list.get(0);
520 assertEquals(Level.FATAL, event.level);
521 assertSame(message, event.message);
522 assertSame(throwable, event.throwable);
523 }
524
525 @Test
526 public void testFatalMarkerSupplier() {
527 logger2.disable().fatal(marker, supplier);
528 assertTrue(logger2.list.isEmpty());
529 assertFalse(supplier.invoked);
530
531 logger2.enable().fatal(marker, supplier);
532 assertEquals(1, logger2.list.size());
533 assertTrue(supplier.invoked);
534
535 final LogEvent event = logger2.list.get(0);
536 assertEquals(Level.FATAL, event.level);
537 assertSame(stringMessage, event.message.getFormattedMessage());
538 assertSame(marker, event.marker);
539 }
540
541 @Test
542 public void testFatalSupplier() {
543 logger2.disable().fatal(supplier);
544 assertTrue(logger2.list.isEmpty());
545 assertFalse(supplier.invoked);
546
547 logger2.enable().fatal(supplier);
548 assertEquals(1, logger2.list.size());
549 assertTrue(supplier.invoked);
550
551 final LogEvent event = logger2.list.get(0);
552 assertEquals(Level.FATAL, event.level);
553 assertSame(stringMessage, event.message.getFormattedMessage());
554 }
555
556 @Test
557 public void testFatalMarkerSupplierThrowable() {
558 logger2.disable().fatal(marker, supplier, throwable);
559 assertTrue(logger2.list.isEmpty());
560 assertFalse(supplier.invoked);
561
562 logger2.enable().fatal(marker, supplier, throwable);
563 assertEquals(1, logger2.list.size());
564 assertTrue(supplier.invoked);
565
566 final LogEvent event = logger2.list.get(0);
567 assertEquals(Level.FATAL, event.level);
568 assertSame(marker, event.marker);
569 assertSame(stringMessage, event.message.getFormattedMessage());
570 assertSame(throwable, event.throwable);
571 }
572
573 @Test
574 public void testFatalSupplierThrowable() {
575 logger2.disable().fatal(supplier, throwable);
576 assertTrue(logger2.list.isEmpty());
577 assertFalse(supplier.invoked);
578
579 logger2.enable().fatal(supplier, throwable);
580 assertEquals(1, logger2.list.size());
581 assertTrue(supplier.invoked);
582
583 final LogEvent event = logger2.list.get(0);
584 assertEquals(Level.FATAL, event.level);
585 assertSame(stringMessage, event.message.getFormattedMessage());
586 assertSame(throwable, event.throwable);
587 }
588
589 @Test
590 public void testFatalStringParamSupplier() {
591 logger2.disable().fatal("abc {}", supplier);
592 assertTrue(logger2.list.isEmpty());
593 assertFalse(supplier.invoked);
594
595 logger2.enable().fatal("abc {}", supplier);
596 assertEquals(1, logger2.list.size());
597 assertTrue(supplier.invoked);
598
599 final LogEvent event = logger2.list.get(0);
600 assertEquals(Level.FATAL, event.level);
601 assertEquals("abc Hi", event.message.getFormattedMessage());
602 }
603
604 @Test
605 public void testFatalMarkerStringParamSupplier() {
606 logger2.disable().fatal(marker, "abc {}", supplier);
607 assertTrue(logger2.list.isEmpty());
608 assertFalse(supplier.invoked);
609
610 logger2.enable().fatal(marker, "abc {}", supplier);
611 assertEquals(1, logger2.list.size());
612 assertTrue(supplier.invoked);
613
614 final LogEvent event = logger2.list.get(0);
615 assertEquals(Level.FATAL, event.level);
616 assertSame(marker, event.marker);
617 assertEquals("abc Hi", event.message.getFormattedMessage());
618 }
619
620 @Test
621 public void testInfoMarkerMessageSupplier() {
622 logger2.disable().info(marker, messageSupplier);
623 assertTrue(logger2.list.isEmpty());
624 assertFalse(messageSupplier.invoked);
625
626 logger2.enable().info(marker, messageSupplier);
627 assertEquals(1, logger2.list.size());
628 assertTrue(messageSupplier.invoked);
629
630 final LogEvent event = logger2.list.get(0);
631 assertEquals(Level.INFO, event.level);
632 assertSame(message, event.message);
633 assertSame(marker, event.marker);
634 }
635
636 @Test
637 public void testInfoMessageSupplier() {
638 logger2.disable().info(messageSupplier);
639 assertTrue(logger2.list.isEmpty());
640 assertFalse(messageSupplier.invoked);
641
642 logger2.enable().info(messageSupplier);
643 assertEquals(1, logger2.list.size());
644 assertTrue(messageSupplier.invoked);
645
646 final LogEvent event = logger2.list.get(0);
647 assertEquals(Level.INFO, event.level);
648 assertSame(message, event.message);
649 }
650
651 @Test
652 public void testInfoMarkerMessageSupplierThrowable() {
653 logger2.disable().info(marker, messageSupplier, throwable);
654 assertTrue(logger2.list.isEmpty());
655 assertFalse(messageSupplier.invoked);
656
657 logger2.enable().info(marker, messageSupplier, throwable);
658 assertEquals(1, logger2.list.size());
659 assertTrue(messageSupplier.invoked);
660
661 final LogEvent event = logger2.list.get(0);
662 assertEquals(Level.INFO, event.level);
663 assertSame(marker, event.marker);
664 assertSame(message, event.message);
665 assertSame(throwable, event.throwable);
666 }
667
668 @Test
669 public void testInfoMessageSupplierThrowable() {
670 logger2.disable().info(messageSupplier, throwable);
671 assertTrue(logger2.list.isEmpty());
672 assertFalse(messageSupplier.invoked);
673
674 logger2.enable().info(messageSupplier, throwable);
675 assertEquals(1, logger2.list.size());
676 assertTrue(messageSupplier.invoked);
677
678 final LogEvent event = logger2.list.get(0);
679 assertEquals(Level.INFO, event.level);
680 assertSame(message, event.message);
681 assertSame(throwable, event.throwable);
682 }
683
684 @Test
685 public void testInfoMarkerSupplier() {
686 logger2.disable().info(marker, supplier);
687 assertTrue(logger2.list.isEmpty());
688 assertFalse(supplier.invoked);
689
690 logger2.enable().info(marker, supplier);
691 assertEquals(1, logger2.list.size());
692 assertTrue(supplier.invoked);
693
694 final LogEvent event = logger2.list.get(0);
695 assertEquals(Level.INFO, event.level);
696 assertSame(stringMessage, event.message.getFormattedMessage());
697 assertSame(marker, event.marker);
698 }
699
700 @Test
701 public void testInfoSupplier() {
702 logger2.disable().info(supplier);
703 assertTrue(logger2.list.isEmpty());
704 assertFalse(supplier.invoked);
705
706 logger2.enable().info(supplier);
707 assertEquals(1, logger2.list.size());
708 assertTrue(supplier.invoked);
709
710 final LogEvent event = logger2.list.get(0);
711 assertEquals(Level.INFO, event.level);
712 assertSame(stringMessage, event.message.getFormattedMessage());
713 }
714
715 @Test
716 public void testInfoMarkerSupplierThrowable() {
717 logger2.disable().info(marker, supplier, throwable);
718 assertTrue(logger2.list.isEmpty());
719 assertFalse(supplier.invoked);
720
721 logger2.enable().info(marker, supplier, throwable);
722 assertEquals(1, logger2.list.size());
723 assertTrue(supplier.invoked);
724
725 final LogEvent event = logger2.list.get(0);
726 assertEquals(Level.INFO, event.level);
727 assertSame(marker, event.marker);
728 assertSame(stringMessage, event.message.getFormattedMessage());
729 assertSame(throwable, event.throwable);
730 }
731
732 @Test
733 public void testInfoSupplierThrowable() {
734 logger2.disable().info(supplier, throwable);
735 assertTrue(logger2.list.isEmpty());
736 assertFalse(supplier.invoked);
737
738 logger2.enable().info(supplier, throwable);
739 assertEquals(1, logger2.list.size());
740 assertTrue(supplier.invoked);
741
742 final LogEvent event = logger2.list.get(0);
743 assertEquals(Level.INFO, event.level);
744 assertSame(stringMessage, event.message.getFormattedMessage());
745 assertSame(throwable, event.throwable);
746 }
747
748 @Test
749 public void testInfoStringParamSupplier() {
750 logger2.disable().info("abc {}", supplier);
751 assertTrue(logger2.list.isEmpty());
752 assertFalse(supplier.invoked);
753
754 logger2.enable().info("abc {}", supplier);
755 assertEquals(1, logger2.list.size());
756 assertTrue(supplier.invoked);
757
758 final LogEvent event = logger2.list.get(0);
759 assertEquals(Level.INFO, event.level);
760 assertEquals("abc Hi", event.message.getFormattedMessage());
761 }
762
763 @Test
764 public void testInfoMarkerStringParamSupplier() {
765 logger2.disable().info(marker, "abc {}", supplier);
766 assertTrue(logger2.list.isEmpty());
767 assertFalse(supplier.invoked);
768
769 logger2.enable().info(marker, "abc {}", supplier);
770 assertEquals(1, logger2.list.size());
771 assertTrue(supplier.invoked);
772
773 final LogEvent event = logger2.list.get(0);
774 assertEquals(Level.INFO, event.level);
775 assertSame(marker, event.marker);
776 assertEquals("abc Hi", event.message.getFormattedMessage());
777 }
778
779 @Test
780 public void testTraceMarkerMessageSupplier() {
781 logger2.disable().trace(marker, messageSupplier);
782 assertTrue(logger2.list.isEmpty());
783 assertFalse(messageSupplier.invoked);
784
785 logger2.enable().trace(marker, messageSupplier);
786 assertEquals(1, logger2.list.size());
787 assertTrue(messageSupplier.invoked);
788
789 final LogEvent event = logger2.list.get(0);
790 assertEquals(Level.TRACE, event.level);
791 assertSame(message, event.message);
792 assertSame(marker, event.marker);
793 }
794
795 @Test
796 public void testTraceMessageSupplier() {
797 logger2.disable().trace(messageSupplier);
798 assertTrue(logger2.list.isEmpty());
799 assertFalse(messageSupplier.invoked);
800
801 logger2.enable().trace(messageSupplier);
802 assertEquals(1, logger2.list.size());
803 assertTrue(messageSupplier.invoked);
804
805 final LogEvent event = logger2.list.get(0);
806 assertEquals(Level.TRACE, event.level);
807 assertSame(message, event.message);
808 }
809
810 @Test
811 public void testTraceMarkerMessageSupplierThrowable() {
812 logger2.disable().trace(marker, messageSupplier, throwable);
813 assertTrue(logger2.list.isEmpty());
814 assertFalse(messageSupplier.invoked);
815
816 logger2.enable().trace(marker, messageSupplier, throwable);
817 assertEquals(1, logger2.list.size());
818 assertTrue(messageSupplier.invoked);
819
820 final LogEvent event = logger2.list.get(0);
821 assertEquals(Level.TRACE, event.level);
822 assertSame(marker, event.marker);
823 assertSame(message, event.message);
824 assertSame(throwable, event.throwable);
825 }
826
827 @Test
828 public void testTraceMessageSupplierThrowable() {
829 logger2.disable().trace(messageSupplier, throwable);
830 assertTrue(logger2.list.isEmpty());
831 assertFalse(messageSupplier.invoked);
832
833 logger2.enable().trace(messageSupplier, throwable);
834 assertEquals(1, logger2.list.size());
835 assertTrue(messageSupplier.invoked);
836
837 final LogEvent event = logger2.list.get(0);
838 assertEquals(Level.TRACE, event.level);
839 assertSame(message, event.message);
840 assertSame(throwable, event.throwable);
841 }
842
843 @Test
844 public void testTraceMarkerSupplier() {
845 logger2.disable().trace(marker, supplier);
846 assertTrue(logger2.list.isEmpty());
847 assertFalse(supplier.invoked);
848
849 logger2.enable().trace(marker, supplier);
850 assertEquals(1, logger2.list.size());
851 assertTrue(supplier.invoked);
852
853 final LogEvent event = logger2.list.get(0);
854 assertEquals(Level.TRACE, event.level);
855 assertSame(stringMessage, event.message.getFormattedMessage());
856 assertSame(marker, event.marker);
857 }
858
859 @Test
860 public void testTraceSupplier() {
861 logger2.disable().trace(supplier);
862 assertTrue(logger2.list.isEmpty());
863 assertFalse(supplier.invoked);
864
865 logger2.enable().trace(supplier);
866 assertEquals(1, logger2.list.size());
867 assertTrue(supplier.invoked);
868
869 final LogEvent event = logger2.list.get(0);
870 assertEquals(Level.TRACE, event.level);
871 assertSame(stringMessage, event.message.getFormattedMessage());
872 }
873
874 @Test
875 public void testTraceMarkerSupplierThrowable() {
876 logger2.disable().trace(marker, supplier, throwable);
877 assertTrue(logger2.list.isEmpty());
878 assertFalse(supplier.invoked);
879
880 logger2.enable().trace(marker, supplier, throwable);
881 assertEquals(1, logger2.list.size());
882 assertTrue(supplier.invoked);
883
884 final LogEvent event = logger2.list.get(0);
885 assertEquals(Level.TRACE, event.level);
886 assertSame(marker, event.marker);
887 assertSame(stringMessage, event.message.getFormattedMessage());
888 assertSame(throwable, event.throwable);
889 }
890
891 @Test
892 public void testTraceSupplierThrowable() {
893 logger2.disable().trace(supplier, throwable);
894 assertTrue(logger2.list.isEmpty());
895 assertFalse(supplier.invoked);
896
897 logger2.enable().trace(supplier, throwable);
898 assertEquals(1, logger2.list.size());
899 assertTrue(supplier.invoked);
900
901 final LogEvent event = logger2.list.get(0);
902 assertEquals(Level.TRACE, event.level);
903 assertSame(stringMessage, event.message.getFormattedMessage());
904 assertSame(throwable, event.throwable);
905 }
906
907 @Test
908 public void testTraceStringParamSupplier() {
909 logger2.disable().trace("abc {}", supplier);
910 assertTrue(logger2.list.isEmpty());
911 assertFalse(supplier.invoked);
912
913 logger2.enable().trace("abc {}", supplier);
914 assertEquals(1, logger2.list.size());
915 assertTrue(supplier.invoked);
916
917 final LogEvent event = logger2.list.get(0);
918 assertEquals(Level.TRACE, event.level);
919 assertEquals("abc Hi", event.message.getFormattedMessage());
920 }
921
922 @Test
923 public void testTraceMarkerStringParamSupplier() {
924 logger2.disable().trace(marker, "abc {}", supplier);
925 assertTrue(logger2.list.isEmpty());
926 assertFalse(supplier.invoked);
927
928 logger2.enable().trace(marker, "abc {}", supplier);
929 assertEquals(1, logger2.list.size());
930 assertTrue(supplier.invoked);
931
932 final LogEvent event = logger2.list.get(0);
933 assertEquals(Level.TRACE, event.level);
934 assertSame(marker, event.marker);
935 assertEquals("abc Hi", event.message.getFormattedMessage());
936 }
937
938 @Test
939 public void testWarnMarkerMessageSupplier() {
940 logger2.disable().warn(marker, messageSupplier);
941 assertTrue(logger2.list.isEmpty());
942 assertFalse(messageSupplier.invoked);
943
944 logger2.enable().warn(marker, messageSupplier);
945 assertEquals(1, logger2.list.size());
946 assertTrue(messageSupplier.invoked);
947
948 final LogEvent event = logger2.list.get(0);
949 assertEquals(Level.WARN, event.level);
950 assertSame(message, event.message);
951 assertSame(marker, event.marker);
952 }
953
954 @Test
955 public void testWarnMessageSupplier() {
956 logger2.disable().warn(messageSupplier);
957 assertTrue(logger2.list.isEmpty());
958 assertFalse(messageSupplier.invoked);
959
960 logger2.enable().warn(messageSupplier);
961 assertEquals(1, logger2.list.size());
962 assertTrue(messageSupplier.invoked);
963
964 final LogEvent event = logger2.list.get(0);
965 assertEquals(Level.WARN, event.level);
966 assertSame(message, event.message);
967 }
968
969 @Test
970 public void testWarnMarkerMessageSupplierThrowable() {
971 logger2.disable().warn(marker, messageSupplier, throwable);
972 assertTrue(logger2.list.isEmpty());
973 assertFalse(messageSupplier.invoked);
974
975 logger2.enable().warn(marker, messageSupplier, throwable);
976 assertEquals(1, logger2.list.size());
977 assertTrue(messageSupplier.invoked);
978
979 final LogEvent event = logger2.list.get(0);
980 assertEquals(Level.WARN, event.level);
981 assertSame(marker, event.marker);
982 assertSame(message, event.message);
983 assertSame(throwable, event.throwable);
984 }
985
986 @Test
987 public void testWarnMessageSupplierThrowable() {
988 logger2.disable().warn(messageSupplier, throwable);
989 assertTrue(logger2.list.isEmpty());
990 assertFalse(messageSupplier.invoked);
991
992 logger2.enable().warn(messageSupplier, throwable);
993 assertEquals(1, logger2.list.size());
994 assertTrue(messageSupplier.invoked);
995
996 final LogEvent event = logger2.list.get(0);
997 assertEquals(Level.WARN, event.level);
998 assertSame(message, event.message);
999 assertSame(throwable, event.throwable);
1000 }
1001
1002 @Test
1003 public void testWarnMarkerSupplier() {
1004 logger2.disable().warn(marker, supplier);
1005 assertTrue(logger2.list.isEmpty());
1006 assertFalse(supplier.invoked);
1007
1008 logger2.enable().warn(marker, supplier);
1009 assertEquals(1, logger2.list.size());
1010 assertTrue(supplier.invoked);
1011
1012 final LogEvent event = logger2.list.get(0);
1013 assertEquals(Level.WARN, event.level);
1014 assertSame(stringMessage, event.message.getFormattedMessage());
1015 assertSame(marker, event.marker);
1016 }
1017
1018 @Test
1019 public void testWarnSupplier() {
1020 logger2.disable().warn(supplier);
1021 assertTrue(logger2.list.isEmpty());
1022 assertFalse(supplier.invoked);
1023
1024 logger2.enable().warn(supplier);
1025 assertEquals(1, logger2.list.size());
1026 assertTrue(supplier.invoked);
1027
1028 final LogEvent event = logger2.list.get(0);
1029 assertEquals(Level.WARN, event.level);
1030 assertSame(stringMessage, event.message.getFormattedMessage());
1031 }
1032
1033 @Test
1034 public void testWarnMarkerSupplierThrowable() {
1035 logger2.disable().warn(marker, supplier, throwable);
1036 assertTrue(logger2.list.isEmpty());
1037 assertFalse(supplier.invoked);
1038
1039 logger2.enable().warn(marker, supplier, throwable);
1040 assertEquals(1, logger2.list.size());
1041 assertTrue(supplier.invoked);
1042
1043 final LogEvent event = logger2.list.get(0);
1044 assertEquals(Level.WARN, event.level);
1045 assertSame(marker, event.marker);
1046 assertSame(stringMessage, event.message.getFormattedMessage());
1047 assertSame(throwable, event.throwable);
1048 }
1049
1050 @Test
1051 public void testWarnSupplierThrowable() {
1052 logger2.disable().warn(supplier, throwable);
1053 assertTrue(logger2.list.isEmpty());
1054 assertFalse(supplier.invoked);
1055
1056 logger2.enable().warn(supplier, throwable);
1057 assertEquals(1, logger2.list.size());
1058 assertTrue(supplier.invoked);
1059
1060 final LogEvent event = logger2.list.get(0);
1061 assertEquals(Level.WARN, event.level);
1062 assertSame(stringMessage, event.message.getFormattedMessage());
1063 assertSame(throwable, event.throwable);
1064 }
1065
1066 @Test
1067 public void testWarnStringParamSupplier() {
1068 logger2.disable().warn("abc {}", supplier);
1069 assertTrue(logger2.list.isEmpty());
1070 assertFalse(supplier.invoked);
1071
1072 logger2.enable().warn("abc {}", supplier);
1073 assertEquals(1, logger2.list.size());
1074 assertTrue(supplier.invoked);
1075
1076 final LogEvent event = logger2.list.get(0);
1077 assertEquals(Level.WARN, event.level);
1078 assertEquals("abc Hi", event.message.getFormattedMessage());
1079 }
1080
1081 @Test
1082 public void testWarnMarkerStringParamSupplier() {
1083 logger2.disable().warn(marker, "abc {}", supplier);
1084 assertTrue(logger2.list.isEmpty());
1085 assertFalse(supplier.invoked);
1086
1087 logger2.enable().warn(marker, "abc {}", supplier);
1088 assertEquals(1, logger2.list.size());
1089 assertTrue(supplier.invoked);
1090
1091 final LogEvent event = logger2.list.get(0);
1092 assertEquals(Level.WARN, event.level);
1093 assertSame(marker, event.marker);
1094 assertEquals("abc Hi", event.message.getFormattedMessage());
1095 }
1096
1097 @Test
1098 public void testLogMarkerMessageSupplier() {
1099 logger2.disable().log(Level.WARN, marker, messageSupplier);
1100 assertTrue(logger2.list.isEmpty());
1101 assertFalse(messageSupplier.invoked);
1102
1103 logger2.enable().log(Level.WARN, marker, messageSupplier);
1104 assertEquals(1, logger2.list.size());
1105 assertTrue(messageSupplier.invoked);
1106
1107 final LogEvent event = logger2.list.get(0);
1108 assertEquals(Level.WARN, event.level);
1109 assertSame(message, event.message);
1110 assertSame(marker, event.marker);
1111 }
1112
1113 @Test
1114 public void testLogMessageSupplier() {
1115 logger2.disable().log(Level.WARN, messageSupplier);
1116 assertTrue(logger2.list.isEmpty());
1117 assertFalse(messageSupplier.invoked);
1118
1119 logger2.enable().log(Level.WARN, messageSupplier);
1120 assertEquals(1, logger2.list.size());
1121 assertTrue(messageSupplier.invoked);
1122
1123 final LogEvent event = logger2.list.get(0);
1124 assertEquals(Level.WARN, event.level);
1125 assertSame(message, event.message);
1126 }
1127
1128 @Test
1129 public void testLogMarkerMessageSupplierThrowable() {
1130 logger2.disable().log(Level.WARN, marker, messageSupplier, throwable);
1131 assertTrue(logger2.list.isEmpty());
1132 assertFalse(messageSupplier.invoked);
1133
1134 logger2.enable().log(Level.WARN, marker, messageSupplier, throwable);
1135 assertEquals(1, logger2.list.size());
1136 assertTrue(messageSupplier.invoked);
1137
1138 final LogEvent event = logger2.list.get(0);
1139 assertEquals(Level.WARN, event.level);
1140 assertSame(marker, event.marker);
1141 assertSame(message, event.message);
1142 assertSame(throwable, event.throwable);
1143 }
1144
1145 @Test
1146 public void testLogMessageSupplierThrowable() {
1147 logger2.disable().log(Level.WARN, messageSupplier, throwable);
1148 assertTrue(logger2.list.isEmpty());
1149 assertFalse(messageSupplier.invoked);
1150
1151 logger2.enable().log(Level.WARN, messageSupplier, throwable);
1152 assertEquals(1, logger2.list.size());
1153 assertTrue(messageSupplier.invoked);
1154
1155 final LogEvent event = logger2.list.get(0);
1156 assertEquals(Level.WARN, event.level);
1157 assertSame(message, event.message);
1158 assertSame(throwable, event.throwable);
1159 }
1160
1161 @Test
1162 public void testLogMarkerSupplier() {
1163 logger2.disable().log(Level.WARN, marker, supplier);
1164 assertTrue(logger2.list.isEmpty());
1165 assertFalse(supplier.invoked);
1166
1167 logger2.enable().log(Level.WARN, marker, supplier);
1168 assertEquals(1, logger2.list.size());
1169 assertTrue(supplier.invoked);
1170
1171 final LogEvent event = logger2.list.get(0);
1172 assertEquals(Level.WARN, event.level);
1173 assertSame(stringMessage, event.message.getFormattedMessage());
1174 assertSame(marker, event.marker);
1175 }
1176
1177 @Test
1178 public void testLogSupplier() {
1179 logger2.disable().log(Level.WARN, supplier);
1180 assertTrue(logger2.list.isEmpty());
1181 assertFalse(supplier.invoked);
1182
1183 logger2.enable().log(Level.WARN, supplier);
1184 assertEquals(1, logger2.list.size());
1185 assertTrue(supplier.invoked);
1186
1187 final LogEvent event = logger2.list.get(0);
1188 assertEquals(Level.WARN, event.level);
1189 assertSame(stringMessage, event.message.getFormattedMessage());
1190 }
1191
1192 @Test
1193 public void testLogMarkerSupplierThrowable() {
1194 logger2.disable().log(Level.WARN, marker, supplier, throwable);
1195 assertTrue(logger2.list.isEmpty());
1196 assertFalse(supplier.invoked);
1197
1198 logger2.enable().log(Level.WARN, marker, supplier, throwable);
1199 assertEquals(1, logger2.list.size());
1200 assertTrue(supplier.invoked);
1201
1202 final LogEvent event = logger2.list.get(0);
1203 assertEquals(Level.WARN, event.level);
1204 assertSame(marker, event.marker);
1205 assertSame(stringMessage, event.message.getFormattedMessage());
1206 assertSame(throwable, event.throwable);
1207 }
1208
1209 @Test
1210 public void testLogSupplierThrowable() {
1211 logger2.disable().log(Level.WARN, supplier, throwable);
1212 assertTrue(logger2.list.isEmpty());
1213 assertFalse(supplier.invoked);
1214
1215 logger2.enable().log(Level.WARN, supplier, throwable);
1216 assertEquals(1, logger2.list.size());
1217 assertTrue(supplier.invoked);
1218
1219 final LogEvent event = logger2.list.get(0);
1220 assertEquals(Level.WARN, event.level);
1221 assertSame(stringMessage, event.message.getFormattedMessage());
1222 assertSame(throwable, event.throwable);
1223 }
1224
1225 @Test
1226 public void testLogStringParamSupplier() {
1227 logger2.disable().log(Level.WARN, "abc {}", supplier);
1228 assertTrue(logger2.list.isEmpty());
1229 assertFalse(supplier.invoked);
1230
1231 logger2.enable().log(Level.WARN, "abc {}", supplier);
1232 assertEquals(1, logger2.list.size());
1233 assertTrue(supplier.invoked);
1234
1235 final LogEvent event = logger2.list.get(0);
1236 assertEquals(Level.WARN, event.level);
1237 assertEquals("abc Hi", event.message.getFormattedMessage());
1238 }
1239
1240 @Test
1241 public void testLogMarkerStringParamSupplier() {
1242 logger2.disable().log(Level.WARN, marker, "abc {}", supplier);
1243 assertTrue(logger2.list.isEmpty());
1244 assertFalse(supplier.invoked);
1245
1246 logger2.enable().log(Level.WARN, marker, "abc {}", supplier);
1247 assertEquals(1, logger2.list.size());
1248 assertTrue(supplier.invoked);
1249
1250 final LogEvent event = logger2.list.get(0);
1251 assertEquals(Level.WARN, event.level);
1252 assertSame(marker, event.marker);
1253 assertEquals("abc Hi", event.message.getFormattedMessage());
1254 }
1255
1256 }
1515 */
1616 package org.apache.logging.log4j;
1717
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertFalse;
20 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.assertTrue;
22
1823 import org.junit.Test;
19
20 import static org.junit.Assert.*;
2124
2225 /**
2326 *
2528 public class LevelTest {
2629
2730 @Test
31 public void testDefault() {
32 final Level level = Level.toLevel("Information", Level.ERROR);
33 assertNotNull(level);
34 assertEquals(Level.ERROR, level);
35 }
36
37 @Test
38 public void testForNameEquals() {
39 final String name = "Foo";
40 final int intValue = 1;
41 final Level level = Level.forName(name, intValue);
42 assertNotNull(level);
43 assertEquals(level, Level.forName(name, intValue));
44 assertEquals(level, Level.getLevel(name));
45 assertEquals(intValue, Level.getLevel(name).intLevel());
46 }
47
48 @Test
2849 public void testGoodLevels() {
2950 final Level level = Level.toLevel("INFO");
3051 assertNotNull(level);
3253 }
3354
3455 @Test
35 public void testDefault() {
36 final Level level = Level.toLevel("Information", Level.ERROR);
37 assertNotNull(level);
38 assertEquals(Level.ERROR, level);
56 public void testIsInRangeErrorToDebug() {
57 assertFalse(Level.OFF.isInRange(Level.ERROR, Level.DEBUG));
58 assertFalse(Level.FATAL.isInRange(Level.ERROR, Level.DEBUG));
59 assertTrue(Level.ERROR.isInRange(Level.ERROR, Level.DEBUG));
60 assertTrue(Level.WARN.isInRange(Level.ERROR, Level.DEBUG));
61 assertTrue(Level.INFO.isInRange(Level.ERROR, Level.DEBUG));
62 assertTrue(Level.DEBUG.isInRange(Level.ERROR, Level.DEBUG));
63 assertFalse(Level.TRACE.isInRange(Level.ERROR, Level.DEBUG));
64 assertFalse(Level.ALL.isInRange(Level.ERROR, Level.DEBUG));
65 }
66
67 @Test
68 public void testIsInRangeFatalToTrace() {
69 assertFalse(Level.OFF.isInRange(Level.FATAL, Level.TRACE));
70 assertTrue(Level.FATAL.isInRange(Level.FATAL, Level.TRACE));
71 assertTrue(Level.ERROR.isInRange(Level.FATAL, Level.TRACE));
72 assertTrue(Level.WARN.isInRange(Level.FATAL, Level.TRACE));
73 assertTrue(Level.INFO.isInRange(Level.FATAL, Level.TRACE));
74 assertTrue(Level.DEBUG.isInRange(Level.FATAL, Level.TRACE));
75 assertTrue(Level.TRACE.isInRange(Level.FATAL, Level.TRACE));
76 assertFalse(Level.ALL.isInRange(Level.FATAL, Level.TRACE));
77 }
78
79 @Test
80 public void testIsInRangeOffToAll() {
81 assertTrue(Level.OFF.isInRange(Level.OFF, Level.ALL));
82 assertTrue(Level.FATAL.isInRange(Level.OFF, Level.ALL));
83 assertTrue(Level.ERROR.isInRange(Level.OFF, Level.ALL));
84 assertTrue(Level.WARN.isInRange(Level.OFF, Level.ALL));
85 assertTrue(Level.INFO.isInRange(Level.OFF, Level.ALL));
86 assertTrue(Level.DEBUG.isInRange(Level.OFF, Level.ALL));
87 assertTrue(Level.TRACE.isInRange(Level.OFF, Level.ALL));
88 assertTrue(Level.ALL.isInRange(Level.OFF, Level.ALL));
89 }
90
91 @Test
92 public void testIsInRangeSameLevels() {
93 // Level.OFF
94 assertTrue(Level.OFF.isInRange(Level.OFF, Level.OFF));
95 assertFalse(Level.OFF.isInRange(Level.FATAL, Level.FATAL));
96 assertFalse(Level.OFF.isInRange(Level.ERROR, Level.ERROR));
97 assertFalse(Level.OFF.isInRange(Level.WARN, Level.WARN));
98 assertFalse(Level.OFF.isInRange(Level.INFO, Level.INFO));
99 assertFalse(Level.OFF.isInRange(Level.DEBUG, Level.DEBUG));
100 assertFalse(Level.OFF.isInRange(Level.TRACE, Level.TRACE));
101 assertFalse(Level.OFF.isInRange(Level.ALL, Level.ALL));
102 // Level.FATAL
103 assertFalse(Level.FATAL.isInRange(Level.OFF, Level.OFF));
104 assertTrue(Level.FATAL.isInRange(Level.FATAL, Level.FATAL));
105 assertFalse(Level.FATAL.isInRange(Level.ERROR, Level.ERROR));
106 assertFalse(Level.FATAL.isInRange(Level.WARN, Level.WARN));
107 assertFalse(Level.FATAL.isInRange(Level.INFO, Level.INFO));
108 assertFalse(Level.FATAL.isInRange(Level.DEBUG, Level.DEBUG));
109 assertFalse(Level.FATAL.isInRange(Level.TRACE, Level.TRACE));
110 assertFalse(Level.FATAL.isInRange(Level.ALL, Level.ALL));
111 // Level.ERROR
112 assertFalse(Level.ERROR.isInRange(Level.OFF, Level.OFF));
113 assertFalse(Level.ERROR.isInRange(Level.FATAL, Level.FATAL));
114 assertTrue(Level.ERROR.isInRange(Level.ERROR, Level.ERROR));
115 assertFalse(Level.ERROR.isInRange(Level.WARN, Level.WARN));
116 assertFalse(Level.ERROR.isInRange(Level.INFO, Level.INFO));
117 assertFalse(Level.ERROR.isInRange(Level.DEBUG, Level.DEBUG));
118 assertFalse(Level.ERROR.isInRange(Level.TRACE, Level.TRACE));
119 assertFalse(Level.ERROR.isInRange(Level.ALL, Level.ALL));
120 // Level.WARN
121 assertFalse(Level.WARN.isInRange(Level.OFF, Level.OFF));
122 assertFalse(Level.WARN.isInRange(Level.FATAL, Level.FATAL));
123 assertFalse(Level.WARN.isInRange(Level.ERROR, Level.ERROR));
124 assertTrue(Level.WARN.isInRange(Level.WARN, Level.WARN));
125 assertFalse(Level.WARN.isInRange(Level.INFO, Level.INFO));
126 assertFalse(Level.WARN.isInRange(Level.DEBUG, Level.DEBUG));
127 assertFalse(Level.WARN.isInRange(Level.TRACE, Level.TRACE));
128 assertFalse(Level.WARN.isInRange(Level.ALL, Level.ALL));
129 // Level.INFO
130 assertFalse(Level.INFO.isInRange(Level.OFF, Level.OFF));
131 assertFalse(Level.INFO.isInRange(Level.FATAL, Level.FATAL));
132 assertFalse(Level.INFO.isInRange(Level.ERROR, Level.ERROR));
133 assertFalse(Level.INFO.isInRange(Level.WARN, Level.WARN));
134 assertTrue(Level.INFO.isInRange(Level.INFO, Level.INFO));
135 assertFalse(Level.INFO.isInRange(Level.DEBUG, Level.DEBUG));
136 assertFalse(Level.INFO.isInRange(Level.TRACE, Level.TRACE));
137 assertFalse(Level.INFO.isInRange(Level.ALL, Level.ALL));
138 // Level.DEBUG
139 assertFalse(Level.DEBUG.isInRange(Level.OFF, Level.OFF));
140 assertFalse(Level.DEBUG.isInRange(Level.FATAL, Level.FATAL));
141 assertFalse(Level.DEBUG.isInRange(Level.ERROR, Level.ERROR));
142 assertFalse(Level.DEBUG.isInRange(Level.WARN, Level.WARN));
143 assertFalse(Level.DEBUG.isInRange(Level.INFO, Level.INFO));
144 assertTrue(Level.DEBUG.isInRange(Level.DEBUG, Level.DEBUG));
145 assertFalse(Level.DEBUG.isInRange(Level.TRACE, Level.TRACE));
146 assertFalse(Level.DEBUG.isInRange(Level.ALL, Level.ALL));
147 // Level.TRACE
148 assertFalse(Level.TRACE.isInRange(Level.OFF, Level.OFF));
149 assertFalse(Level.TRACE.isInRange(Level.FATAL, Level.FATAL));
150 assertFalse(Level.TRACE.isInRange(Level.ERROR, Level.ERROR));
151 assertFalse(Level.TRACE.isInRange(Level.WARN, Level.WARN));
152 assertFalse(Level.TRACE.isInRange(Level.INFO, Level.INFO));
153 assertFalse(Level.TRACE.isInRange(Level.DEBUG, Level.DEBUG));
154 assertTrue(Level.TRACE.isInRange(Level.TRACE, Level.TRACE));
155 assertFalse(Level.TRACE.isInRange(Level.ALL, Level.ALL));
156 // Level.ALL
157 assertFalse(Level.ALL.isInRange(Level.OFF, Level.OFF));
158 assertFalse(Level.ALL.isInRange(Level.FATAL, Level.FATAL));
159 assertFalse(Level.ALL.isInRange(Level.ERROR, Level.ERROR));
160 assertFalse(Level.ALL.isInRange(Level.WARN, Level.WARN));
161 assertFalse(Level.ALL.isInRange(Level.INFO, Level.INFO));
162 assertFalse(Level.ALL.isInRange(Level.DEBUG, Level.DEBUG));
163 assertFalse(Level.ALL.isInRange(Level.TRACE, Level.TRACE));
164 assertTrue(Level.ALL.isInRange(Level.ALL, Level.ALL));
165 }
166
167 @Test
168 public void testIsInRangeWarnToInfo() {
169 assertFalse(Level.OFF.isInRange(Level.WARN, Level.INFO));
170 assertFalse(Level.FATAL.isInRange(Level.WARN, Level.INFO));
171 assertFalse(Level.ERROR.isInRange(Level.WARN, Level.INFO));
172 assertTrue(Level.WARN.isInRange(Level.WARN, Level.INFO));
173 assertTrue(Level.INFO.isInRange(Level.WARN, Level.INFO));
174 assertFalse(Level.DEBUG.isInRange(Level.WARN, Level.INFO));
175 assertFalse(Level.TRACE.isInRange(Level.WARN, Level.INFO));
176 assertFalse(Level.ALL.isInRange(Level.WARN, Level.INFO));
39177 }
40178
41179 @Test
123261 assertTrue(Level.ALL.isLessSpecificThan(Level.ALL));
124262 }
125263
126 @Test
127 public void testIsMoreSpecificThan() {
128 // Level.OFF
129 assertTrue(Level.OFF.isMoreSpecificThan(Level.OFF));
130 assertTrue(Level.OFF.isMoreSpecificThan(Level.FATAL));
131 assertTrue(Level.OFF.isMoreSpecificThan(Level.ERROR));
132 assertTrue(Level.OFF.isMoreSpecificThan(Level.WARN));
133 assertTrue(Level.OFF.isMoreSpecificThan(Level.INFO));
134 assertTrue(Level.OFF.isMoreSpecificThan(Level.DEBUG));
135 assertTrue(Level.OFF.isMoreSpecificThan(Level.TRACE));
136 assertTrue(Level.OFF.isMoreSpecificThan(Level.ALL));
137 // Level.FATAL
138 assertFalse(Level.FATAL.isMoreSpecificThan(Level.OFF));
139 assertTrue(Level.FATAL.isMoreSpecificThan(Level.FATAL));
140 assertTrue(Level.FATAL.isMoreSpecificThan(Level.ERROR));
141 assertTrue(Level.FATAL.isMoreSpecificThan(Level.WARN));
142 assertTrue(Level.FATAL.isMoreSpecificThan(Level.INFO));
143 assertTrue(Level.FATAL.isMoreSpecificThan(Level.DEBUG));
144 assertTrue(Level.FATAL.isMoreSpecificThan(Level.TRACE));
145 assertTrue(Level.FATAL.isMoreSpecificThan(Level.ALL));
146 // Level.ERROR
147 assertFalse(Level.ERROR.isMoreSpecificThan(Level.OFF));
148 assertFalse(Level.ERROR.isMoreSpecificThan(Level.FATAL));
149 assertTrue(Level.ERROR.isMoreSpecificThan(Level.ERROR));
150 assertTrue(Level.ERROR.isMoreSpecificThan(Level.WARN));
151 assertTrue(Level.ERROR.isMoreSpecificThan(Level.INFO));
152 assertTrue(Level.ERROR.isMoreSpecificThan(Level.DEBUG));
153 assertTrue(Level.ERROR.isMoreSpecificThan(Level.TRACE));
154 assertTrue(Level.ERROR.isMoreSpecificThan(Level.ALL));
155 // Level.WARN
156 assertFalse(Level.WARN.isMoreSpecificThan(Level.OFF));
157 assertFalse(Level.WARN.isMoreSpecificThan(Level.FATAL));
158 assertFalse(Level.WARN.isMoreSpecificThan(Level.ERROR));
159 assertTrue(Level.WARN.isMoreSpecificThan(Level.WARN));
160 assertTrue(Level.WARN.isMoreSpecificThan(Level.INFO));
161 assertTrue(Level.WARN.isMoreSpecificThan(Level.DEBUG));
162 assertTrue(Level.WARN.isMoreSpecificThan(Level.TRACE));
163 assertTrue(Level.WARN.isMoreSpecificThan(Level.ALL));
164 // Level.INFO
165 assertFalse(Level.INFO.isMoreSpecificThan(Level.OFF));
166 assertFalse(Level.INFO.isMoreSpecificThan(Level.FATAL));
167 assertFalse(Level.INFO.isMoreSpecificThan(Level.ERROR));
168 assertFalse(Level.INFO.isMoreSpecificThan(Level.WARN));
169 assertTrue(Level.INFO.isMoreSpecificThan(Level.INFO));
170 assertTrue(Level.INFO.isMoreSpecificThan(Level.DEBUG));
171 assertTrue(Level.INFO.isMoreSpecificThan(Level.TRACE));
172 assertTrue(Level.INFO.isMoreSpecificThan(Level.ALL));
173 // Level.DEBUG
174 assertFalse(Level.DEBUG.isMoreSpecificThan(Level.OFF));
175 assertFalse(Level.DEBUG.isMoreSpecificThan(Level.FATAL));
176 assertFalse(Level.DEBUG.isMoreSpecificThan(Level.ERROR));
177 assertFalse(Level.DEBUG.isMoreSpecificThan(Level.WARN));
178 assertFalse(Level.DEBUG.isMoreSpecificThan(Level.INFO));
179 assertTrue(Level.DEBUG.isMoreSpecificThan(Level.DEBUG));
180 assertTrue(Level.DEBUG.isMoreSpecificThan(Level.TRACE));
181 assertTrue(Level.DEBUG.isMoreSpecificThan(Level.ALL));
182 // Level.TRACE
183 assertFalse(Level.TRACE.isMoreSpecificThan(Level.OFF));
184 assertFalse(Level.TRACE.isMoreSpecificThan(Level.FATAL));
185 assertFalse(Level.TRACE.isMoreSpecificThan(Level.ERROR));
186 assertFalse(Level.TRACE.isMoreSpecificThan(Level.WARN));
187 assertFalse(Level.TRACE.isMoreSpecificThan(Level.INFO));
188 assertFalse(Level.TRACE.isMoreSpecificThan(Level.DEBUG));
189 assertTrue(Level.TRACE.isMoreSpecificThan(Level.TRACE));
190 assertTrue(Level.TRACE.isMoreSpecificThan(Level.ALL));
191 // Level.ALL
192 assertFalse(Level.ALL.isMoreSpecificThan(Level.OFF));
193 assertFalse(Level.ALL.isMoreSpecificThan(Level.FATAL));
194 assertFalse(Level.ALL.isMoreSpecificThan(Level.ERROR));
195 assertFalse(Level.ALL.isMoreSpecificThan(Level.WARN));
196 assertFalse(Level.ALL.isMoreSpecificThan(Level.INFO));
197 assertFalse(Level.ALL.isMoreSpecificThan(Level.DEBUG));
198 assertFalse(Level.ALL.isMoreSpecificThan(Level.TRACE));
199 assertTrue(Level.ALL.isMoreSpecificThan(Level.ALL));
200 }
201
202264 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j;
17
18 import java.util.Date;
19 import java.util.List;
20 import java.util.Locale;
21
22 import org.apache.logging.log4j.message.ParameterizedMessageFactory;
23 import org.apache.logging.log4j.message.StringFormatterMessageFactory;
24 import org.apache.logging.log4j.message.StructuredDataMessage;
25 import org.apache.logging.log4j.util.Strings;
26 import org.junit.Before;
27 import org.junit.Test;
28
29 import static org.hamcrest.CoreMatchers.*;
30
31 import static org.junit.Assert.*;
32
33 /**
34 *
35 */
36 public class LoggerTest {
37
38 private static class TestParameterizedMessageFactory {
39 // empty
40 }
41
42 private static class TestStringFormatterMessageFactory {
43 // empty
44 }
45
46 TestLogger logger = (TestLogger) LogManager.getLogger("LoggerTest");
47 List<String> results = logger.getEntries();
48
49 @Test
50 public void basicFlow() {
51 logger.entry();
52 logger.exit();
53 assertEquals(2, results.size());
54 assertThat("Incorrect Entry", results.get(0), startsWith("ENTRY[ FLOW ] TRACE entry"));
55 assertThat("incorrect Exit", results.get(1), startsWith("EXIT[ FLOW ] TRACE exit"));
56
57 }
58
59 @Test
60 public void catching() {
61 try {
62 throw new NullPointerException();
63 } catch (final Exception e) {
64 logger.catching(e);
65 assertEquals(1, results.size());
66 assertThat("Incorrect Catching",
67 results.get(0), startsWith("CATCHING[ EXCEPTION ] ERROR catching java.lang.NullPointerException"));
68 }
69 }
70
71 @Test
72 public void debug() {
73 logger.debug("Debug message");
74 assertEquals(1, results.size());
75 assertTrue("Incorrect message", results.get(0).startsWith(" DEBUG Debug message"));
76 }
77
78 @Test
79 public void debugObject() {
80 logger.debug(new Date());
81 assertEquals(1, results.size());
82 assertTrue("Invalid length", results.get(0).length() > 7);
83 }
84
85 @Test
86 public void debugWithParms() {
87 logger.debug("Hello, {}", "World");
88 assertEquals(1, results.size());
89 assertTrue("Incorrect substitution", results.get(0).startsWith(" DEBUG Hello, World"));
90 }
91
92 @Test
93 public void debugWithParmsAndThrowable() {
94 logger.debug("Hello, {}", "World", new RuntimeException("Test Exception"));
95 assertEquals(1, results.size());
96 assertTrue("Unexpected results: " + results.get(0),
97 results.get(0).startsWith(" DEBUG Hello, World java.lang.RuntimeException: Test Exception"));
98 }
99
100 @Test
101 public void getFormatterLogger_Class() {
102 // The TestLogger logger was already created in an instance variable for this class.
103 // The message factory is only used when the logger is created.
104 final TestLogger testLogger = (TestLogger) LogManager.getFormatterLogger(TestStringFormatterMessageFactory.class);
105 assertNotNull(testLogger);
106 assertTrue(testLogger.getMessageFactory() instanceof StringFormatterMessageFactory);
107 assertEquals(StringFormatterMessageFactory.INSTANCE, testLogger.getMessageFactory());
108 testLogger.debug("%,d", Integer.MAX_VALUE);
109 assertEquals(1, testLogger.getEntries().size());
110 assertEquals(String.format(" DEBUG %,d", Integer.MAX_VALUE), testLogger.getEntries().get(0));
111 }
112
113 @Test
114 public void getFormatterLogger_Object() {
115 // The TestLogger logger was already created in an instance variable for this class.
116 // The message factory is only used when the logger is created.
117 final TestLogger testLogger = (TestLogger) LogManager.getFormatterLogger(new TestStringFormatterMessageFactory());
118 assertNotNull(testLogger);
119 assertTrue(testLogger.getMessageFactory() instanceof StringFormatterMessageFactory);
120 assertEquals(StringFormatterMessageFactory.INSTANCE, testLogger.getMessageFactory());
121 testLogger.debug("%,d", Integer.MAX_VALUE);
122 assertEquals(1, testLogger.getEntries().size());
123 assertEquals(String.format(" DEBUG %,d", Integer.MAX_VALUE), testLogger.getEntries().get(0));
124 }
125
126 @Test
127 public void getFormatterLogger_String() {
128 final StringFormatterMessageFactory messageFactory = StringFormatterMessageFactory.INSTANCE;
129 final TestLogger testLogger = (TestLogger) LogManager.getFormatterLogger("getLogger_String_StringFormatterMessageFactory");
130 assertNotNull(testLogger);
131 assertTrue(testLogger.getMessageFactory() instanceof StringFormatterMessageFactory);
132 assertEquals(messageFactory, testLogger.getMessageFactory());
133 testLogger.debug("%,d", Integer.MAX_VALUE);
134 assertEquals(1, testLogger.getEntries().size());
135 assertEquals(String.format(" DEBUG %,d", Integer.MAX_VALUE), testLogger.getEntries().get(0));
136 }
137
138 @Test
139 public void getLogger_Class_ParameterizedMessageFactory() {
140 // The TestLogger logger was already created in an instance variable for this class.
141 // The message factory is only used when the logger is created.
142 final ParameterizedMessageFactory messageFactory = ParameterizedMessageFactory.INSTANCE;
143 final TestLogger testLogger = (TestLogger) LogManager.getLogger(TestParameterizedMessageFactory.class,
144 messageFactory);
145 assertNotNull(testLogger);
146 assertEquals(messageFactory, testLogger.getMessageFactory());
147 testLogger.debug("{}", Integer.MAX_VALUE);
148 assertEquals(1, testLogger.getEntries().size());
149 assertEquals(" DEBUG " + Integer.MAX_VALUE, testLogger.getEntries().get(0));
150 }
151
152 @Test
153 public void getLogger_Class_StringFormatterMessageFactory() {
154 // The TestLogger logger was already created in an instance variable for this class.
155 // The message factory is only used when the logger is created.
156 final TestLogger testLogger = (TestLogger) LogManager.getLogger(TestStringFormatterMessageFactory.class,
157 StringFormatterMessageFactory.INSTANCE);
158 assertNotNull(testLogger);
159 assertEquals(StringFormatterMessageFactory.INSTANCE, testLogger.getMessageFactory());
160 testLogger.debug("%,d", Integer.MAX_VALUE);
161 assertEquals(1, testLogger.getEntries().size());
162 assertEquals(String.format(" DEBUG %,d", Integer.MAX_VALUE), testLogger.getEntries().get(0));
163 }
164
165 @Test
166 public void getLogger_Object_ParameterizedMessageFactory() {
167 // The TestLogger logger was already created in an instance variable for this class.
168 // The message factory is only used when the logger is created.
169 final ParameterizedMessageFactory messageFactory = ParameterizedMessageFactory.INSTANCE;
170 final TestLogger testLogger = (TestLogger) LogManager.getLogger(new TestParameterizedMessageFactory(),
171 messageFactory);
172 assertNotNull(testLogger);
173 assertEquals(messageFactory, testLogger.getMessageFactory());
174 testLogger.debug("{}", Integer.MAX_VALUE);
175 assertEquals(1, testLogger.getEntries().size());
176 assertEquals(" DEBUG " + Integer.MAX_VALUE, testLogger.getEntries().get(0));
177 }
178
179 @Test
180 public void getLogger_Object_StringFormatterMessageFactory() {
181 // The TestLogger logger was already created in an instance variable for this class.
182 // The message factory is only used when the logger is created.
183 final StringFormatterMessageFactory messageFactory = StringFormatterMessageFactory.INSTANCE;
184 final TestLogger testLogger = (TestLogger) LogManager.getLogger(new TestStringFormatterMessageFactory(),
185 messageFactory);
186 assertNotNull(testLogger);
187 assertEquals(messageFactory, testLogger.getMessageFactory());
188 testLogger.debug("%,d", Integer.MAX_VALUE);
189 assertEquals(1, testLogger.getEntries().size());
190 assertEquals(String.format(" DEBUG %,d", Integer.MAX_VALUE), testLogger.getEntries().get(0));
191 }
192
193 @Test
194 public void getLogger_String_MessageFactoryMismatch() {
195 final StringFormatterMessageFactory messageFactory = StringFormatterMessageFactory.INSTANCE;
196 final TestLogger testLogger = (TestLogger) LogManager.getLogger("getLogger_String_MessageFactoryMismatch",
197 messageFactory);
198 assertNotNull(testLogger);
199 assertEquals(messageFactory, testLogger.getMessageFactory());
200 final TestLogger testLogger2 = (TestLogger) LogManager.getLogger("getLogger_String_MessageFactoryMismatch",
201 ParameterizedMessageFactory.INSTANCE);
202 //TODO: How to test?
203 //This test context always creates new loggers, other test context impls I tried fail other tests.
204 //assertEquals(messageFactory, testLogger2.getMessageFactory());
205 testLogger.debug("%,d", Integer.MAX_VALUE);
206 assertEquals(1, testLogger.getEntries().size());
207 assertEquals(String.format(" DEBUG %,d", Integer.MAX_VALUE), testLogger.getEntries().get(0));
208 }
209
210 @Test
211 public void getLogger_String_ParameterizedMessageFactory() {
212 final ParameterizedMessageFactory messageFactory = ParameterizedMessageFactory.INSTANCE;
213 final TestLogger testLogger = (TestLogger) LogManager.getLogger("getLogger_String_ParameterizedMessageFactory",
214 messageFactory);
215 assertNotNull(testLogger);
216 assertEquals(messageFactory, testLogger.getMessageFactory());
217 testLogger.debug("{}", Integer.MAX_VALUE);
218 assertEquals(1, testLogger.getEntries().size());
219 assertEquals(" DEBUG " + Integer.MAX_VALUE, testLogger.getEntries().get(0));
220 }
221
222 @Test
223 public void getLogger_String_StringFormatterMessageFactory() {
224 final StringFormatterMessageFactory messageFactory = StringFormatterMessageFactory.INSTANCE;
225 final TestLogger testLogger = (TestLogger) LogManager.getLogger("getLogger_String_StringFormatterMessageFactory",
226 messageFactory);
227 assertNotNull(testLogger);
228 assertEquals(messageFactory, testLogger.getMessageFactory());
229 testLogger.debug("%,d", Integer.MAX_VALUE);
230 assertEquals(1, testLogger.getEntries().size());
231 assertEquals(String.format(" DEBUG %,d", Integer.MAX_VALUE), testLogger.getEntries().get(0));
232 }
233
234 @Test
235 public void getLoggerByClass() {
236 final Logger classLogger = LogManager.getLogger(LoggerTest.class);
237 assertNotNull(classLogger);
238 }
239
240 @Test
241 public void getLoggerByNullClass() {
242 // Returns a SimpleLogger
243 assertNotNull(LogManager.getLogger((Class<?>) null));
244 }
245
246 @Test
247 public void getLoggerByNullObject() {
248 // Returns a SimpleLogger
249 assertNotNull(LogManager.getLogger((Object) null));
250 }
251
252 @Test
253 public void getLoggerByNullString() {
254 // Returns a SimpleLogger
255 assertNotNull(LogManager.getLogger((String) null));
256 }
257
258 @Test
259 public void getLoggerByObject() {
260 final Logger classLogger = LogManager.getLogger(this);
261 assertNotNull(classLogger);
262 assertEquals(classLogger, LogManager.getLogger(LoggerTest.class));
263 }
264
265 @Test
266 public void getRootLogger() {
267 assertNotNull(LogManager.getRootLogger());
268 assertNotNull(LogManager.getLogger(Strings.EMPTY));
269 assertNotNull(LogManager.getLogger(LogManager.ROOT_LOGGER_NAME));
270 assertEquals(LogManager.getRootLogger(), LogManager.getLogger(Strings.EMPTY));
271 assertEquals(LogManager.getRootLogger(), LogManager.getLogger(LogManager.ROOT_LOGGER_NAME));
272 }
273
274 @Test
275 public void isAllEnabled() {
276 assertTrue("Incorrect level", logger.isEnabled(Level.ALL));
277 }
278
279 @Test
280 public void isDebugEnabled() {
281 assertTrue("Incorrect level", logger.isDebugEnabled());
282 assertTrue("Incorrect level", logger.isEnabled(Level.DEBUG));
283 }
284
285 @Test
286 public void isErrorEnabled() {
287 assertTrue("Incorrect level", logger.isErrorEnabled());
288 assertTrue("Incorrect level", logger.isEnabled(Level.ERROR));
289 }
290
291 @Test
292 public void isFatalEnabled() {
293 assertTrue("Incorrect level", logger.isFatalEnabled());
294 assertTrue("Incorrect level", logger.isEnabled(Level.FATAL));
295 }
296
297 @Test
298 public void isInfoEnabled() {
299 assertTrue("Incorrect level", logger.isInfoEnabled());
300 assertTrue("Incorrect level", logger.isEnabled(Level.INFO));
301 }
302
303 @Test
304 public void isOffEnabled() {
305 assertTrue("Incorrect level", logger.isEnabled(Level.OFF));
306 }
307
308 @Test
309 public void isTraceEnabled() {
310 assertTrue("Incorrect level", logger.isTraceEnabled());
311 assertTrue("Incorrect level", logger.isEnabled(Level.TRACE));
312 }
313
314 @Test
315 public void isWarnEnabled() {
316 assertTrue("Incorrect level", logger.isWarnEnabled());
317 assertTrue("Incorrect level", logger.isEnabled(Level.WARN));
318 }
319
320 @Test
321 public void mdc() {
322
323 ThreadContext.put("TestYear", new Integer(2010).toString());
324 logger.debug("Debug message");
325 ThreadContext.clearMap();
326 logger.debug("Debug message");
327 assertEquals(2, results.size());
328 assertTrue("Incorrect MDC: " + results.get(0),
329 results.get(0).startsWith(" DEBUG Debug message {TestYear=2010}"));
330 assertTrue("MDC not cleared?: " + results.get(1),
331 results.get(1).startsWith(" DEBUG Debug message"));
332 }
333
334 @Test
335 public void printf() {
336 logger.printf(Level.DEBUG, "Debug message %d", 1);
337 logger.printf(Level.DEBUG, MarkerManager.getMarker("Test"), "Debug message %d", 2);
338 assertEquals(2, results.size());
339 assertThat("Incorrect message", results.get(0), startsWith(" DEBUG Debug message 1"));
340 assertThat("Incorrect message", results.get(1), startsWith("Test DEBUG Debug message 2"));
341 }
342
343 @Before
344 public void setup() {
345 results.clear();
346 }
347
348 @Test
349 public void structuredData() {
350 ThreadContext.put("loginId", "JohnDoe");
351 ThreadContext.put("ipAddress", "192.168.0.120");
352 ThreadContext.put("locale", Locale.US.getDisplayName());
353 final StructuredDataMessage msg = new StructuredDataMessage("Audit@18060", "Transfer Complete", "Transfer");
354 msg.put("ToAccount", "123456");
355 msg.put("FromAccount", "123457");
356 msg.put("Amount", "200.00");
357 logger.info(MarkerManager.getMarker("EVENT"), msg);
358 ThreadContext.clearMap();
359 assertEquals(1, results.size());
360 assertThat("Incorrect structured data: ", results.get(0), startsWith(
361 "EVENT INFO Transfer [Audit@18060 Amount=\"200.00\" FromAccount=\"123457\" ToAccount=\"123456\"] Transfer Complete"));
362 }
363
364 @Test
365 public void throwing() {
366 logger.throwing(new IllegalArgumentException("Test Exception"));
367 assertEquals(1, results.size());
368 assertThat("Incorrect Throwing",
369 results.get(0), startsWith("THROWING[ EXCEPTION ] ERROR throwing java.lang.IllegalArgumentException: Test Exception"));
370 }
371 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j;
17
18 import java.util.Date;
19 import java.util.List;
20 import java.util.Locale;
21
22 import org.apache.logging.log4j.message.ParameterizedMessageFactory;
23 import org.apache.logging.log4j.message.StringFormatterMessageFactory;
24 import org.apache.logging.log4j.message.StructuredDataMessage;
25 import org.apache.logging.log4j.util.Strings;
26 import org.junit.Before;
27 import org.junit.Test;
28
29 import static org.hamcrest.CoreMatchers.*;
30
31 import static org.junit.Assert.*;
32
33 /**
34 *
35 */
36 public class LoggerTest {
37
38 private static class TestParameterizedMessageFactory {
39 // empty
40 }
41
42 private static class TestStringFormatterMessageFactory {
43 // empty
44 }
45
46 TestLogger logger = (TestLogger) LogManager.getLogger("LoggerTest");
47 List<String> results = logger.getEntries();
48
49 @Test
50 public void basicFlow() {
51 logger.entry();
52 logger.exit();
53 assertEquals(2, results.size());
54 assertThat("Incorrect Entry", results.get(0), startsWith("ENTRY[ FLOW ] TRACE entry"));
55 assertThat("incorrect Exit", results.get(1), startsWith("EXIT[ FLOW ] TRACE exit"));
56
57 }
58
59 @Test
60 public void catching() {
61 try {
62 throw new NullPointerException();
63 } catch (final Exception e) {
64 logger.catching(e);
65 assertEquals(1, results.size());
66 assertThat("Incorrect Catching",
67 results.get(0), startsWith("CATCHING[ EXCEPTION ] ERROR catching java.lang.NullPointerException"));
68 }
69 }
70
71 @Test
72 public void debug() {
73 logger.debug("Debug message");
74 assertEquals(1, results.size());
75 assertTrue("Incorrect message", results.get(0).startsWith(" DEBUG Debug message"));
76 }
77
78 @Test
79 public void debugObject() {
80 logger.debug(new Date());
81 assertEquals(1, results.size());
82 assertTrue("Invalid length", results.get(0).length() > 7);
83 }
84
85 @Test
86 public void debugWithParms() {
87 logger.debug("Hello, {}", "World");
88 assertEquals(1, results.size());
89 assertTrue("Incorrect substitution", results.get(0).startsWith(" DEBUG Hello, World"));
90 }
91
92 @Test
93 public void debugWithParmsAndThrowable() {
94 logger.debug("Hello, {}", "World", new RuntimeException("Test Exception"));
95 assertEquals(1, results.size());
96 assertTrue("Unexpected results: " + results.get(0),
97 results.get(0).startsWith(" DEBUG Hello, World java.lang.RuntimeException: Test Exception"));
98 }
99
100 @Test
101 public void getFormatterLogger() {
102 // The TestLogger logger was already created in an instance variable for this class.
103 // The message factory is only used when the logger is created.
104 final TestLogger testLogger = (TestLogger) LogManager.getFormatterLogger();
105 final TestLogger altLogger = (TestLogger) LogManager.getFormatterLogger(getClass());
106 assertEquals(testLogger.getName(), altLogger.getName());
107 assertNotNull(testLogger);
108 assertTrue(testLogger.getMessageFactory() instanceof StringFormatterMessageFactory);
109 assertEquals(StringFormatterMessageFactory.INSTANCE, testLogger.getMessageFactory());
110 testLogger.debug("%,d", Integer.MAX_VALUE);
111 assertEquals(1, testLogger.getEntries().size());
112 assertEquals(String.format(" DEBUG %,d", Integer.MAX_VALUE), testLogger.getEntries().get(0));
113 }
114
115 @Test
116 public void getFormatterLogger_Class() {
117 // The TestLogger logger was already created in an instance variable for this class.
118 // The message factory is only used when the logger is created.
119 final TestLogger testLogger = (TestLogger) LogManager.getFormatterLogger(TestStringFormatterMessageFactory.class);
120 assertNotNull(testLogger);
121 assertTrue(testLogger.getMessageFactory() instanceof StringFormatterMessageFactory);
122 assertEquals(StringFormatterMessageFactory.INSTANCE, testLogger.getMessageFactory());
123 testLogger.debug("%,d", Integer.MAX_VALUE);
124 assertEquals(1, testLogger.getEntries().size());
125 assertEquals(String.format(" DEBUG %,d", Integer.MAX_VALUE), testLogger.getEntries().get(0));
126 }
127
128 @Test
129 public void getFormatterLogger_Object() {
130 // The TestLogger logger was already created in an instance variable for this class.
131 // The message factory is only used when the logger is created.
132 final TestLogger testLogger = (TestLogger) LogManager.getFormatterLogger(new TestStringFormatterMessageFactory());
133 assertNotNull(testLogger);
134 assertTrue(testLogger.getMessageFactory() instanceof StringFormatterMessageFactory);
135 assertEquals(StringFormatterMessageFactory.INSTANCE, testLogger.getMessageFactory());
136 testLogger.debug("%,d", Integer.MAX_VALUE);
137 assertEquals(1, testLogger.getEntries().size());
138 assertEquals(String.format(" DEBUG %,d", Integer.MAX_VALUE), testLogger.getEntries().get(0));
139 }
140
141 @Test
142 public void getFormatterLogger_String() {
143 final StringFormatterMessageFactory messageFactory = StringFormatterMessageFactory.INSTANCE;
144 final TestLogger testLogger = (TestLogger) LogManager.getFormatterLogger("getLogger_String_StringFormatterMessageFactory");
145 assertNotNull(testLogger);
146 assertTrue(testLogger.getMessageFactory() instanceof StringFormatterMessageFactory);
147 assertEquals(messageFactory, testLogger.getMessageFactory());
148 testLogger.debug("%,d", Integer.MAX_VALUE);
149 assertEquals(1, testLogger.getEntries().size());
150 assertEquals(String.format(" DEBUG %,d", Integer.MAX_VALUE), testLogger.getEntries().get(0));
151 }
152
153 @Test
154 public void getLogger_Class_ParameterizedMessageFactory() {
155 // The TestLogger logger was already created in an instance variable for this class.
156 // The message factory is only used when the logger is created.
157 final ParameterizedMessageFactory messageFactory = ParameterizedMessageFactory.INSTANCE;
158 final TestLogger testLogger = (TestLogger) LogManager.getLogger(TestParameterizedMessageFactory.class,
159 messageFactory);
160 assertNotNull(testLogger);
161 assertEquals(messageFactory, testLogger.getMessageFactory());
162 testLogger.debug("{}", Integer.MAX_VALUE);
163 assertEquals(1, testLogger.getEntries().size());
164 assertEquals(" DEBUG " + Integer.MAX_VALUE, testLogger.getEntries().get(0));
165 }
166
167 @Test
168 public void getLogger_Class_StringFormatterMessageFactory() {
169 // The TestLogger logger was already created in an instance variable for this class.
170 // The message factory is only used when the logger is created.
171 final TestLogger testLogger = (TestLogger) LogManager.getLogger(TestStringFormatterMessageFactory.class,
172 StringFormatterMessageFactory.INSTANCE);
173 assertNotNull(testLogger);
174 assertEquals(StringFormatterMessageFactory.INSTANCE, testLogger.getMessageFactory());
175 testLogger.debug("%,d", Integer.MAX_VALUE);
176 assertEquals(1, testLogger.getEntries().size());
177 assertEquals(String.format(" DEBUG %,d", Integer.MAX_VALUE), testLogger.getEntries().get(0));
178 }
179
180 @Test
181 public void getLogger_Object_ParameterizedMessageFactory() {
182 // The TestLogger logger was already created in an instance variable for this class.
183 // The message factory is only used when the logger is created.
184 final ParameterizedMessageFactory messageFactory = ParameterizedMessageFactory.INSTANCE;
185 final TestLogger testLogger = (TestLogger) LogManager.getLogger(new TestParameterizedMessageFactory(),
186 messageFactory);
187 assertNotNull(testLogger);
188 assertEquals(messageFactory, testLogger.getMessageFactory());
189 testLogger.debug("{}", Integer.MAX_VALUE);
190 assertEquals(1, testLogger.getEntries().size());
191 assertEquals(" DEBUG " + Integer.MAX_VALUE, testLogger.getEntries().get(0));
192 }
193
194 @Test
195 public void getLogger_Object_StringFormatterMessageFactory() {
196 // The TestLogger logger was already created in an instance variable for this class.
197 // The message factory is only used when the logger is created.
198 final StringFormatterMessageFactory messageFactory = StringFormatterMessageFactory.INSTANCE;
199 final TestLogger testLogger = (TestLogger) LogManager.getLogger(new TestStringFormatterMessageFactory(),
200 messageFactory);
201 assertNotNull(testLogger);
202 assertEquals(messageFactory, testLogger.getMessageFactory());
203 testLogger.debug("%,d", Integer.MAX_VALUE);
204 assertEquals(1, testLogger.getEntries().size());
205 assertEquals(String.format(" DEBUG %,d", Integer.MAX_VALUE), testLogger.getEntries().get(0));
206 }
207
208 @Test
209 public void getLogger_String_MessageFactoryMismatch() {
210 final StringFormatterMessageFactory messageFactory = StringFormatterMessageFactory.INSTANCE;
211 final TestLogger testLogger = (TestLogger) LogManager.getLogger("getLogger_String_MessageFactoryMismatch",
212 messageFactory);
213 assertNotNull(testLogger);
214 assertEquals(messageFactory, testLogger.getMessageFactory());
215 final TestLogger testLogger2 = (TestLogger) LogManager.getLogger("getLogger_String_MessageFactoryMismatch",
216 ParameterizedMessageFactory.INSTANCE);
217 //TODO: How to test?
218 //This test context always creates new loggers, other test context impls I tried fail other tests.
219 //assertEquals(messageFactory, testLogger2.getMessageFactory());
220 testLogger.debug("%,d", Integer.MAX_VALUE);
221 assertEquals(1, testLogger.getEntries().size());
222 assertEquals(String.format(" DEBUG %,d", Integer.MAX_VALUE), testLogger.getEntries().get(0));
223 }
224
225 @Test
226 public void getLogger_String_ParameterizedMessageFactory() {
227 final ParameterizedMessageFactory messageFactory = ParameterizedMessageFactory.INSTANCE;
228 final TestLogger testLogger = (TestLogger) LogManager.getLogger("getLogger_String_ParameterizedMessageFactory",
229 messageFactory);
230 assertNotNull(testLogger);
231 assertEquals(messageFactory, testLogger.getMessageFactory());
232 testLogger.debug("{}", Integer.MAX_VALUE);
233 assertEquals(1, testLogger.getEntries().size());
234 assertEquals(" DEBUG " + Integer.MAX_VALUE, testLogger.getEntries().get(0));
235 }
236
237 @Test
238 public void getLogger_String_StringFormatterMessageFactory() {
239 final StringFormatterMessageFactory messageFactory = StringFormatterMessageFactory.INSTANCE;
240 final TestLogger testLogger = (TestLogger) LogManager.getLogger("getLogger_String_StringFormatterMessageFactory",
241 messageFactory);
242 assertNotNull(testLogger);
243 assertEquals(messageFactory, testLogger.getMessageFactory());
244 testLogger.debug("%,d", Integer.MAX_VALUE);
245 assertEquals(1, testLogger.getEntries().size());
246 assertEquals(String.format(" DEBUG %,d", Integer.MAX_VALUE), testLogger.getEntries().get(0));
247 }
248
249 @Test
250 public void getLoggerByClass() {
251 final Logger classLogger = LogManager.getLogger(LoggerTest.class);
252 assertNotNull(classLogger);
253 }
254
255 @Test
256 public void getLoggerByNullClass() {
257 // Returns a SimpleLogger
258 assertNotNull(LogManager.getLogger((Class<?>) null));
259 }
260
261 @Test
262 public void getLoggerByNullObject() {
263 // Returns a SimpleLogger
264 assertNotNull(LogManager.getLogger((Object) null));
265 }
266
267 @Test
268 public void getLoggerByNullString() {
269 // Returns a SimpleLogger
270 assertNotNull(LogManager.getLogger((String) null));
271 }
272
273 @Test
274 public void getLoggerByObject() {
275 final Logger classLogger = LogManager.getLogger(this);
276 assertNotNull(classLogger);
277 assertEquals(classLogger, LogManager.getLogger(LoggerTest.class));
278 }
279
280 @Test
281 public void getRootLogger() {
282 assertNotNull(LogManager.getRootLogger());
283 assertNotNull(LogManager.getLogger(Strings.EMPTY));
284 assertNotNull(LogManager.getLogger(LogManager.ROOT_LOGGER_NAME));
285 assertEquals(LogManager.getRootLogger(), LogManager.getLogger(Strings.EMPTY));
286 assertEquals(LogManager.getRootLogger(), LogManager.getLogger(LogManager.ROOT_LOGGER_NAME));
287 }
288
289 @Test
290 public void isAllEnabled() {
291 assertTrue("Incorrect level", logger.isEnabled(Level.ALL));
292 }
293
294 @Test
295 public void isDebugEnabled() {
296 assertTrue("Incorrect level", logger.isDebugEnabled());
297 assertTrue("Incorrect level", logger.isEnabled(Level.DEBUG));
298 }
299
300 @Test
301 public void isErrorEnabled() {
302 assertTrue("Incorrect level", logger.isErrorEnabled());
303 assertTrue("Incorrect level", logger.isEnabled(Level.ERROR));
304 }
305
306 @Test
307 public void isFatalEnabled() {
308 assertTrue("Incorrect level", logger.isFatalEnabled());
309 assertTrue("Incorrect level", logger.isEnabled(Level.FATAL));
310 }
311
312 @Test
313 public void isInfoEnabled() {
314 assertTrue("Incorrect level", logger.isInfoEnabled());
315 assertTrue("Incorrect level", logger.isEnabled(Level.INFO));
316 }
317
318 @Test
319 public void isOffEnabled() {
320 assertTrue("Incorrect level", logger.isEnabled(Level.OFF));
321 }
322
323 @Test
324 public void isTraceEnabled() {
325 assertTrue("Incorrect level", logger.isTraceEnabled());
326 assertTrue("Incorrect level", logger.isEnabled(Level.TRACE));
327 }
328
329 @Test
330 public void isWarnEnabled() {
331 assertTrue("Incorrect level", logger.isWarnEnabled());
332 assertTrue("Incorrect level", logger.isEnabled(Level.WARN));
333 }
334
335 @Test
336 public void mdc() {
337
338 ThreadContext.put("TestYear", Integer.valueOf(2010).toString());
339 logger.debug("Debug message");
340 ThreadContext.clearMap();
341 logger.debug("Debug message");
342 assertEquals(2, results.size());
343 assertTrue("Incorrect MDC: " + results.get(0),
344 results.get(0).startsWith(" DEBUG Debug message {TestYear=2010}"));
345 assertTrue("MDC not cleared?: " + results.get(1),
346 results.get(1).startsWith(" DEBUG Debug message"));
347 }
348
349 @Test
350 public void printf() {
351 logger.printf(Level.DEBUG, "Debug message %d", 1);
352 logger.printf(Level.DEBUG, MarkerManager.getMarker("Test"), "Debug message %d", 2);
353 assertEquals(2, results.size());
354 assertThat("Incorrect message", results.get(0), startsWith(" DEBUG Debug message 1"));
355 assertThat("Incorrect message", results.get(1), startsWith("Test DEBUG Debug message 2"));
356 }
357
358 @Before
359 public void setup() {
360 results.clear();
361 }
362
363 @Test
364 public void structuredData() {
365 ThreadContext.put("loginId", "JohnDoe");
366 ThreadContext.put("ipAddress", "192.168.0.120");
367 ThreadContext.put("locale", Locale.US.getDisplayName());
368 final StructuredDataMessage msg = new StructuredDataMessage("Audit@18060", "Transfer Complete", "Transfer");
369 msg.put("ToAccount", "123456");
370 msg.put("FromAccount", "123457");
371 msg.put("Amount", "200.00");
372 logger.info(MarkerManager.getMarker("EVENT"), msg);
373 ThreadContext.clearMap();
374 assertEquals(1, results.size());
375 assertThat("Incorrect structured data: ", results.get(0), startsWith(
376 "EVENT INFO Transfer [Audit@18060 Amount=\"200.00\" FromAccount=\"123457\" ToAccount=\"123456\"] Transfer Complete"));
377 }
378
379 @Test
380 public void throwing() {
381 logger.throwing(new IllegalArgumentException("Test Exception"));
382 assertEquals(1, results.size());
383 assertThat("Incorrect Throwing",
384 results.get(0), startsWith("THROWING[ EXCEPTION ] ERROR throwing java.lang.IllegalArgumentException: Test Exception"));
385 }
386 }
4444 super(name);
4545 }
4646
47 private final List<String> list = new ArrayList<String>();
47 private final List<String> list = new ArrayList<>();
4848
4949 public List<String> getEntries() {
5050 return list;
6060 sb.append(level.toString());
6161 sb.append(' ');
6262 sb.append(msg.getFormattedMessage());
63 final Map<String, String> mdc = ThreadContext.getContext();
63 final Map<String, String> mdc = ThreadContext.getImmutableContext();
6464 if (mdc.size() > 0) {
6565 sb.append(' ');
6666 sb.append(mdc.toString());
2626 *
2727 */
2828 public class TestLoggerContext implements LoggerContext {
29 private final Map<String, ExtendedLogger> map = new HashMap<String, ExtendedLogger>();
29 private final Map<String, ExtendedLogger> map = new HashMap<>();
3030
3131 @Override
3232 public ExtendedLogger getLogger(final String name) {
33 if (map.containsKey(name)) {
34 return map.get(name);
33 final ExtendedLogger extendedLogger = map.get(name);
34 if (extendedLogger != null) {
35 return extendedLogger;
3536 }
3637 final ExtendedLogger logger = new TestLogger(name);
3738 map.put(name, logger);
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.message;
17
18 import org.junit.Assert;
19 import org.junit.Test;
20
21 /**
22 * @since 2.4
23 */
24 public class ObjectArrayMessageTest {
25
26 private static final Object[] ARRAY = { "A", "B", "C" };
27 private static final ObjectArrayMessage OBJECT_ARRAY_MESSAGE = new ObjectArrayMessage(ARRAY);
28
29 @Test
30 public void testGetParameters() {
31 Assert.assertArrayEquals(ARRAY, OBJECT_ARRAY_MESSAGE.getParameters());
32 }
33
34 @Test
35 public void testGetThrowable() {
36 Assert.assertEquals(null, OBJECT_ARRAY_MESSAGE.getThrowable());
37 }
38
39 }
3737 }
3838
3939 @Test
40 public void testFormat3StringArgs() {
41 final String testMsg = "Test message {}{} {}";
42 final String[] args = { "a", "b", "c" };
43 final String result = ParameterizedMessage.formatStringArgs(testMsg, args);
44 assertEquals("Test message ab c", result);
45 }
46
47 @Test
48 public void testFormatNullArgs() {
49 final String testMsg = "Test message {} {} {} {} {} {}";
50 final String[] args = { "a", null, "c", null, null, null };
51 final String result = ParameterizedMessage.formatStringArgs(testMsg, args);
52 assertEquals("Test message a null c null null null", result);
53 }
54
55 @Test
56 public void testFormatStringArgsIgnoresSuperfluousArgs() {
57 final String testMsg = "Test message {}{} {}";
58 final String[] args = { "a", "b", "c", "unnecessary", "superfluous" };
59 final String result = ParameterizedMessage.formatStringArgs(testMsg, args);
60 assertEquals("Test message ab c", result);
61 }
62
63 @Test
64 public void testFormatStringArgsWithEscape() {
65 final String testMsg = "Test message \\{}{} {}";
66 final String[] args = { "a", "b", "c" };
67 final String result = ParameterizedMessage.formatStringArgs(testMsg, args);
68 assertEquals("Test message {}a b", result);
69 }
70
71 @Test
72 public void testFormatStringArgsWithTrailingEscape() {
73 final String testMsg = "Test message {}{} {}\\";
74 final String[] args = { "a", "b", "c" };
75 final String result = ParameterizedMessage.formatStringArgs(testMsg, args);
76 assertEquals("Test message ab c\\", result);
77 }
78
79 @Test
80 public void testFormatStringArgsWithTrailingEscapedEscape() {
81 final String testMsg = "Test message {}{} {}\\\\";
82 final String[] args = { "a", "b", "c" };
83 final String result = ParameterizedMessage.formatStringArgs(testMsg, args);
84 assertEquals("Test message ab c\\\\", result);
85 }
86
87 @Test
88 public void testFormatStringArgsWithEscapedEscape() {
89 final String testMsg = "Test message \\\\{}{} {}";
90 final String[] args = { "a", "b", "c" };
91 final String result = ParameterizedMessage.formatStringArgs(testMsg, args);
92 assertEquals("Test message \\ab c", result);
93 }
94
95 @Test
4096 public void testSafeWithMutableParams() { // LOG4J2-763
4197 final String testMsg = "Test message {}";
4298 final Mutable param = new Mutable().set("abc");
1515 */
1616 package org.apache.logging.log4j.message;
1717
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertNotNull;
20
21 import java.io.ByteArrayInputStream;
22 import java.io.ByteArrayOutputStream;
23 import java.io.IOException;
24 import java.io.ObjectInputStream;
25 import java.io.ObjectOutputStream;
26
27 import org.junit.Assert;
1828 import org.junit.Test;
19
20 import static org.junit.Assert.*;
2129
2230 /**
2331 *
8492 final String actual = msg.getFormattedMessage();
8593 assertEquals("Should use initial param value", "Test message abc", actual);
8694 }
95
96 @Test
97 public void testSerialization() throws IOException, ClassNotFoundException {
98 final StringFormattedMessage expected = new StringFormattedMessage("Msg", "a", "b", "c");
99 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
100 try (final ObjectOutputStream out = new ObjectOutputStream(baos)) {
101 out.writeObject(expected);
102 }
103 final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
104 final ObjectInputStream in = new ObjectInputStream(bais);
105 final StringFormattedMessage actual = (StringFormattedMessage) in.readObject();
106 Assert.assertEquals(expected, actual);
107 Assert.assertEquals(expected.getFormat(), actual.getFormat());
108 Assert.assertEquals(expected.getFormattedMessage(), actual.getFormattedMessage());
109 Assert.assertArrayEquals(expected.getParameters(), actual.getParameters());
110 }
87111 }
4343
4444 @Override
4545 protected void before() throws Throwable {
46 final Map<String, String> configMap = new HashMap<String, String>(2);
46 final Map<String, String> configMap = new HashMap<>(2);
4747 // Cleans framework before first init. Subsequent init invocations do not clean framework.
4848 configMap.put("org.osgi.framework.storage.clean", "onFirstInit");
4949 // Delegates loading of endorsed libraries to JVM classloader
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.util;
18
19 import org.apache.logging.log4j.message.Message;
20 import org.apache.logging.log4j.message.SimpleMessage;
21 import org.junit.Test;
22
23 import static org.junit.Assert.*;
24
25 /**
26 * Tests the LambdaUtil class.
27 */
28 public class LambdaUtilTest {
29
30 @Test
31 public void testGetSupplierResultOfSupplier() {
32 final String expected = "result";
33 final Object actual = LambdaUtil.get(new Supplier<String>() {
34 @Override
35 public String get() {
36 return expected;
37 }
38 });
39 assertSame(expected, actual);
40 }
41
42 @Test
43 public void testGetMessageSupplierResultOfSupplier() {
44 final Message expected = new SimpleMessage("hi");
45 final Message actual = LambdaUtil.get(new MessageSupplier() {
46 @Override
47 public Message get() {
48 return expected;
49 }
50 });
51 assertSame(expected, actual);
52 }
53
54 @Test
55 public void testGetSupplierReturnsNullIfSupplierNull() {
56 final Object actual = LambdaUtil.get((Supplier<?>) null);
57 assertNull(actual);
58 }
59
60 @Test
61 public void testGetMessageSupplierReturnsNullIfSupplierNull() {
62 final Object actual = LambdaUtil.get((MessageSupplier) null);
63 assertNull(actual);
64 }
65
66 @Test(expected = RuntimeException.class)
67 public void testGetSupplierExceptionIfSupplierThrowsException() {
68 LambdaUtil.get(new Supplier<String>() {
69 @Override
70 public String get() {
71 throw new RuntimeException();
72 }
73 });
74 }
75
76 @Test(expected = RuntimeException.class)
77 public void testGetMessageSupplierExceptionIfSupplierThrowsException() {
78 LambdaUtil.get(new MessageSupplier() {
79 @Override
80 public Message get() {
81 throw new RuntimeException();
82 }
83 });
84 }
85
86 @Test
87 public void testGetAllReturnsResultOfSuppliers() {
88 final String expected1 = "result1";
89 final Supplier<String> function1 = new Supplier<String>() {
90 @Override
91 public String get() {
92 return expected1;
93 }
94 };
95 final String expected2 = "result2";
96 final Supplier<String> function2 = new Supplier<String>() {
97 @Override
98 public String get() {
99 return expected2;
100 }
101 };
102
103 final Supplier<?>[] functions = { function1, function2 };
104 final Object[] actual = LambdaUtil.getAll(functions);
105 assertEquals(actual.length, functions.length);
106 assertSame(expected1, actual[0]);
107 assertSame(expected2, actual[1]);
108 }
109
110 @Test
111 public void testGetAllReturnsNullArrayIfSupplierArrayNull() {
112 final Object[] actual = LambdaUtil.getAll((Supplier<?>[]) null);
113 assertNull(actual);
114 }
115
116 @Test
117 public void testGetAllReturnsNullElementsIfSupplierArrayContainsNulls() {
118 final Supplier<?>[] functions = new Supplier[3];
119 final Object[] actual = LambdaUtil.getAll(functions);
120 assertEquals(actual.length, functions.length);
121 for (final Object object : actual) {
122 assertNull(object);
123 }
124 }
125
126 @Test(expected = RuntimeException.class)
127 public void testGetAllThrowsExceptionIfAnyOfTheSuppliersThrowsException() {
128 final Supplier<String> function1 = new Supplier<String>() {
129 @Override
130 public String get() {
131 return "abc";
132 }
133 };
134 final Supplier<String> function2 = new Supplier<String>() {
135 @Override
136 public String get() {
137 throw new RuntimeException();
138 }
139 };
140
141 final Supplier<?>[] functions = { function1, function2 };
142 LambdaUtil.getAll(functions);
143 }
144 }
7373 @Test
7474 public void testGetCurrentStackTrace() throws Exception {
7575 final Stack<Class<?>> classes = ReflectionUtil.getCurrentStackTrace();
76 final Stack<Class<?>> reversed = new Stack<Class<?>>();
76 final Stack<Class<?>> reversed = new Stack<>();
7777 reversed.ensureCapacity(classes.size());
7878 while (!classes.empty()) {
7979 reversed.push(classes.pop());
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.util;
18
19 import org.junit.Assert;
20 import org.junit.Test;
21
22 public class StringsTest {
23
24 @Test
25 public void testQuote() {
26 Assert.assertEquals("'Q'", Strings.quote("Q"));
27 }
28
29 }
2525 <description>Apache Log4j Bill of Materials</description>
2626 <groupId>org.apache.logging.log4j</groupId>
2727 <artifactId>log4j-bom</artifactId>
28 <version>2.2</version>
28 <version>2.4</version>
2929 <packaging>pom</packaging>
3030 <dependencyManagement>
3131 <dependencies>
124124 </build>
125125
126126 <scm>
127 <tag>log4j-2.2</tag>
127 <tag>log4j-2.4</tag>
128128 </scm>
129129 </project>
11 /target/
22 /.classpath
33 /.project
4 /bin/
2020 <parent>
2121 <groupId>org.apache.logging.log4j</groupId>
2222 <artifactId>log4j</artifactId>
23 <version>2.2</version>
23 <version>2.4</version>
2424 <relativePath>../</relativePath>
2525 </parent>
2626 <artifactId>log4j-core</artifactId>
7474 <artifactId>jackson-dataformat-xml</artifactId>
7575 <optional>true</optional>
7676 </dependency>
77 <!-- POM for jackson-dataformat-xml 2.5.4 depends on woodstox-core-asl 4.3.0 -->
7778 <dependency>
7879 <groupId>org.codehaus.woodstox</groupId>
7980 <artifactId>woodstox-core-asl</artifactId>
104105 <groupId>org.jboss.spec.javax.jms</groupId>
105106 <artifactId>jboss-jms-api_1.1_spec</artifactId>
106107 <scope>provided</scope>
108 <optional>true</optional>
109 </dependency>
110 <!-- Used for Kafka appender -->
111 <dependency>
112 <groupId>org.apache.kafka</groupId>
113 <artifactId>kafka-clients</artifactId>
114 <optional>true</optional>
115 </dependency>
116 <!-- Used for ZeroMQ JeroMQ appender -->
117 <dependency>
118 <groupId>org.zeromq</groupId>
119 <artifactId>jeromq</artifactId>
120 <optional>true</optional>
121 </dependency>
122 <!-- Used for compressing to formats other than zip and gz -->
123 <dependency>
124 <groupId>org.apache.commons</groupId>
125 <artifactId>commons-compress</artifactId>
126 <optional>true</optional>
127 </dependency>
128 <!-- Used for the CSV layout -->
129 <dependency>
130 <groupId>org.apache.commons</groupId>
131 <artifactId>commons-csv</artifactId>
107132 <optional>true</optional>
108133 </dependency>
109134
366391 <links>
367392 <link>http://docs.oracle.com/javaee/6/api/</link>
368393 <link>http://www.osgi.org/javadoc/r4v43/core/</link>
394 <link>https://commons.apache.org/proper/commons-lang/javadocs/api-release/</link>
369395 </links>
370396 <groups>
371397 <group>
9898 protected void setState(final LifeCycle.State newState) {
9999 this.state = newState;
100100 // Need a better string than this.toString() for the message
101 // LOGGER.debug("{} {}", this.state, this);
101 // LOGGER.trace("{} {}", this.state, this);
102102 }
103103
104104 protected void setStopped() {
107107
108108 protected void setStopping() {
109109 this.setState(LifeCycle.State.STOPPING);
110 }
111
112 @Override
113 public void initialize() {
114 this.state = State.INITIALIZED;
110115 }
111116
112117 @Override
116116 // do nothing
117117 }
118118
119 @Override
120 public long getNanoTime() {
121 return 0;
122 }
119123 }
3232 * Status of a life cycle like a {@link LoggerContext}.
3333 */
3434 public enum State {
35 /** Object is in its initial state and not yet initialized. */
36 INITIALIZING,
3537 /** Initialized but not yet started. */
3638 INITIALIZED,
3739 /** In the process of starting. */
4547 }
4648
4749 /**
48 * Gets the life-cycle state
50 * Gets the life-cycle state.
4951 *
5052 * @return the life-cycle state
5153 */
5254 State getState();
55
56 void initialize();
5357
5458 void start();
5559
169169 */
170170 void setIncludeLocation(boolean locationRequired);
171171
172 /**
173 * Returns the value of the running Java Virtual Machine's high-resolution time source when this event was created,
174 * or a dummy value if it is known that this value will not be used downstream.
175 * @return The value of the running Java Virtual Machine's high-resolution time source when this event was created.
176 * @since Log4J 2.4
177 */
178 long getNanoTime();
172179 }
1717
1818 import java.util.EventListener;
1919
20 import org.apache.logging.log4j.LogManager;
21
2220 /**
2321 * Base class for server classes that listen to {@link LogEvent}s.
2422 * TODO (MS) How is this class any different from Appender?
2826 private final LoggerContext context;
2927
3028 protected LogEventListener() {
31 context = (LoggerContext) LogManager.getContext(false);
29 context = LoggerContext.getContext(false);
3230 }
3331
3432 public void log(final LogEvent event) {
3634 return;
3735 }
3836 final Logger logger = context.getLogger(event.getLoggerName());
39 if (logger.config.filter(event.getLevel(), event.getMarker(), event.getMessage(), event.getThrown())) {
40 logger.config.logEvent(event);
37 if (logger.privateConfig.filter(event.getLevel(), event.getMarker(), event.getMessage(), event.getThrown())) {
38 logger.privateConfig.logEvent(event);
4139 }
4240 }
4341 }
2525 import org.apache.logging.log4j.Marker;
2626 import org.apache.logging.log4j.core.config.Configuration;
2727 import org.apache.logging.log4j.core.config.LoggerConfig;
28 import org.apache.logging.log4j.core.config.ReliabilityStrategy;
2829 import org.apache.logging.log4j.core.filter.CompositeFilter;
2930 import org.apache.logging.log4j.message.Message;
3031 import org.apache.logging.log4j.message.MessageFactory;
3132 import org.apache.logging.log4j.message.SimpleMessage;
3233 import org.apache.logging.log4j.spi.AbstractLogger;
3334 import org.apache.logging.log4j.util.Strings;
35 import org.apache.logging.log4j.util.Supplier;
3436
3537 /**
3638 * The core implementation of the {@link org.apache.logging.log4j.Logger} interface. Besides providing an
4547 * Logger noticeably impacts performance. The message pattern and parameters are required so that they can be
4648 * used in global filters.
4749 */
48 public class Logger extends AbstractLogger {
50 public class Logger extends AbstractLogger implements Supplier<LoggerConfig> {
4951
5052 private static final long serialVersionUID = 1L;
5153
5254 /**
5355 * Config should be consistent across threads.
5456 */
55 protected volatile PrivateConfig config;
57 protected volatile PrivateConfig privateConfig;
5658
5759 // FIXME: ditto to the above
5860 private final LoggerContext context;
6668 protected Logger(final LoggerContext context, final String name, final MessageFactory messageFactory) {
6769 super(name, messageFactory);
6870 this.context = context;
69 config = new PrivateConfig(context.getConfiguration(), this);
71 privateConfig = new PrivateConfig(context.getConfiguration(), this);
7072 }
7173
7274 /**
7577 * @return The parent Logger.
7678 */
7779 public Logger getParent() {
78 final LoggerConfig lc = config.loggerConfig.getName().equals(getName()) ? config.loggerConfig.getParent() :
79 config.loggerConfig;
80 final LoggerConfig lc = privateConfig.loggerConfig.getName().equals(getName()) ? privateConfig.loggerConfig.getParent() :
81 privateConfig.loggerConfig;
8082 if (lc == null) {
8183 return null;
8284 }
9698
9799 /**
98100 * This method is not exposed through the public API and is provided primarily for unit testing.
99 * @param level The Level to use on this Logger.
101 * <p>
102 * If the new level is null, this logger inherits the level from its parent.
103 * </p>
104 *
105 * @param level The Level to use on this Logger, may be null.
100106 */
101107 public synchronized void setLevel(final Level level) {
108 if (level == getLevel()) {
109 return;
110 }
111 Level actualLevel;
102112 if (level != null) {
103 config = new PrivateConfig(config, level);
104 }
113 actualLevel = level;
114 } else {
115 final Logger parent = getParent();
116 actualLevel = parent != null ? parent.getLevel() : privateConfig.level;
117 }
118 privateConfig = new PrivateConfig(privateConfig, actualLevel);
119 }
120
121 /*
122 * (non-Javadoc)
123 * @see org.apache.logging.log4j.util.Supplier#get()
124 */
125 public LoggerConfig get() {
126 return privateConfig.loggerConfig;
105127 }
106128
107129 @Override
108130 public void logMessage(final String fqcn, final Level level, final Marker marker, final Message message, final Throwable t) {
109131 final Message msg = message == null ? new SimpleMessage(Strings.EMPTY) : message;
110 config.config.getConfigurationMonitor().checkConfiguration();
111 config.loggerConfig.log(getName(), fqcn, marker, level, msg, t);
132
133 // check if we need to reconfigure
134 privateConfig.config.getConfigurationMonitor().checkConfiguration();
135
136 final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy();
137 strategy.log(this, getName(), fqcn, marker, level, msg, t);
112138 }
113139
114140 @Override
115141 public boolean isEnabled(final Level level, final Marker marker, final String message, final Throwable t) {
116 return config.filter(level, marker, message, t);
142 return privateConfig.filter(level, marker, message, t);
117143 }
118144
119145 @Override
120146 public boolean isEnabled(final Level level, final Marker marker, final String message) {
121 return config.filter(level, marker, message);
147 return privateConfig.filter(level, marker, message);
122148 }
123149
124150 @Override
125151 public boolean isEnabled(final Level level, final Marker marker, final String message, final Object... params) {
126 return config.filter(level, marker, message, params);
152 return privateConfig.filter(level, marker, message, params);
127153 }
128154
129155 @Override
130156 public boolean isEnabled(final Level level, final Marker marker, final Object message, final Throwable t) {
131 return config.filter(level, marker, message, t);
157 return privateConfig.filter(level, marker, message, t);
132158 }
133159
134160 @Override
135161 public boolean isEnabled(final Level level, final Marker marker, final Message message, final Throwable t) {
136 return config.filter(level, marker, message, t);
162 return privateConfig.filter(level, marker, message, t);
137163 }
138164
139165 /**
141167 * @param appender The Appender to add to the Logger.
142168 */
143169 public void addAppender(final Appender appender) {
144 config.config.addLoggerAppender(this, appender);
170 privateConfig.config.addLoggerAppender(this, appender);
145171 }
146172
147173 /**
149175 * @param appender The Appender to remove from the Logger.
150176 */
151177 public void removeAppender(final Appender appender) {
152 config.loggerConfig.removeAppender(appender.getName());
178 privateConfig.loggerConfig.removeAppender(appender.getName());
153179 }
154180
155181 /**
157183 * @return A Map containing the Appender's name as the key and the Appender as the value.
158184 */
159185 public Map<String, Appender> getAppenders() {
160 return config.loggerConfig.getAppenders();
186 return privateConfig.loggerConfig.getAppenders();
161187 }
162188
163189 /**
166192 */
167193 // FIXME: this really ought to be an Iterable instead of an Iterator
168194 public Iterator<Filter> getFilters() {
169 final Filter filter = config.loggerConfig.getFilter();
195 final Filter filter = privateConfig.loggerConfig.getFilter();
170196 if (filter == null) {
171197 return new ArrayList<Filter>().iterator();
172198 } else if (filter instanceof CompositeFilter) {
173199 return ((CompositeFilter) filter).iterator();
174200 } else {
175 final List<Filter> filters = new ArrayList<Filter>();
201 final List<Filter> filters = new ArrayList<>();
176202 filters.add(filter);
177203 return filters.iterator();
178204 }
185211 */
186212 @Override
187213 public Level getLevel() {
188 return config.level;
214 return privateConfig.level;
189215 }
190216
191217 /**
193219 * @return The number of Filters associated with the Logger.
194220 */
195221 public int filterCount() {
196 final Filter filter = config.loggerConfig.getFilter();
222 final Filter filter = privateConfig.loggerConfig.getFilter();
197223 if (filter == null) {
198224 return 0;
199225 } else if (filter instanceof CompositeFilter) {
207233 * @param filter The Filter to add.
208234 */
209235 public void addFilter(final Filter filter) {
210 config.config.addLoggerFilter(this, filter);
236 privateConfig.config.addLoggerFilter(this, filter);
211237 }
212238
213239 /**
216242 * @return true if the associated LoggerConfig is additive, false otherwise.
217243 */
218244 public boolean isAdditive() {
219 return config.loggerConfig.isAdditive();
245 return privateConfig.loggerConfig.isAdditive();
220246 }
221247
222248 /**
225251 * @param additive Boolean value to indicate whether the Logger is additive or not.
226252 */
227253 public void setAdditive(final boolean additive) {
228 config.config.setLoggerAdditive(this, additive);
254 privateConfig.config.setLoggerAdditive(this, additive);
229255 }
230256
231257 /**
238264 * volatile. Option 2 is used here as the performance cost is very low and it does a better
239265 * job at documenting how it is used.
240266 *
241 * @param config The new Configuration.
242 */
243 void updateConfiguration(final Configuration config) {
244 this.config = new PrivateConfig(config, this);
267 * @param newConfig The new Configuration.
268 */
269 protected void updateConfiguration(final Configuration newConfig) {
270 this.privateConfig = new PrivateConfig(newConfig, this);
245271 }
246272
247273 /**
2020 import java.io.File;
2121 import java.net.URI;
2222 import java.util.Collection;
23 import java.util.Objects;
2324 import java.util.concurrent.ConcurrentHashMap;
2425 import java.util.concurrent.ConcurrentMap;
2526 import java.util.concurrent.CopyOnWriteArrayList;
2728 import java.util.concurrent.locks.ReentrantLock;
2829
2930 import org.apache.logging.log4j.LogManager;
31 import org.apache.logging.log4j.core.async.AsyncLogger;
3032 import org.apache.logging.log4j.core.config.Configuration;
3133 import org.apache.logging.log4j.core.config.ConfigurationFactory;
3234 import org.apache.logging.log4j.core.config.ConfigurationListener;
3436 import org.apache.logging.log4j.core.config.DefaultConfiguration;
3537 import org.apache.logging.log4j.core.config.NullConfiguration;
3638 import org.apache.logging.log4j.core.config.Reconfigurable;
39 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
3740 import org.apache.logging.log4j.core.jmx.Server;
38 import org.apache.logging.log4j.core.util.Assert;
3941 import org.apache.logging.log4j.core.util.Cancellable;
42 import org.apache.logging.log4j.core.util.NanoClockFactory;
4043 import org.apache.logging.log4j.core.util.NetUtils;
4144 import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry;
4245 import org.apache.logging.log4j.message.MessageFactory;
4346 import org.apache.logging.log4j.spi.AbstractLogger;
4447 import org.apache.logging.log4j.spi.LoggerContextFactory;
4548
46 import static org.apache.logging.log4j.core.util.ShutdownCallbackRegistry.SHUTDOWN_HOOK_MARKER;
49 import static org.apache.logging.log4j.core.util.ShutdownCallbackRegistry.*;
4750
4851 /**
4952 * The LoggerContext is the anchor for the logging system. It maintains a list
5962 public static final String PROPERTY_CONFIG = "config";
6063 private static final Configuration NULL_CONFIGURATION = new NullConfiguration();
6164
62 private final ConcurrentMap<String, Logger> loggers = new ConcurrentHashMap<String, Logger>();
63 private final CopyOnWriteArrayList<PropertyChangeListener> propertyChangeListeners = new CopyOnWriteArrayList<PropertyChangeListener>();
65 /**
66 * Returns the current LoggerContext.
67 * <p>
68 * Avoids the type cast for:
69 *</p>
70 *<pre>(LoggerContext) LogManager.getContext();</pre>
71 *
72 * <p>
73 * WARNING - The LoggerContext returned by this method may not be the LoggerContext used to create a Logger
74 * for the calling class.
75 * </p>
76 * @return The current LoggerContext.
77 * @see LogManager#getContext()
78 */
79 public static LoggerContext getContext() {
80 return (LoggerContext) LogManager.getContext();
81 }
82
83 /**
84 * Returns a LoggerContext.
85 * <p>
86 * Avoids the type cast for:
87 *</p>
88 *<pre>(LoggerContext) LogManager.getContext(currentContext);</pre>
89 *
90 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
91 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
92 * returned and if the caller is a class in the container's classpath then a different LoggerContext may be
93 * returned. If true then only a single LoggerContext will be returned.
94 * @return a LoggerContext.
95 * @see LogManager#getContext(boolean)
96 */
97 public static LoggerContext getContext(final boolean currentContext) {
98 return (LoggerContext) LogManager.getContext(currentContext);
99 }
100
101 /**
102 * Returns a LoggerContext.
103 * <p>
104 * Avoids the type cast for:
105 *</p>
106 *<pre>(LoggerContext) LogManager.getContext(loader, currentContext, configLocation);</pre>
107 *
108 * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate
109 * ClassLoader.
110 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
111 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
112 * returned and if the caller is a class in the container's classpath then a different LoggerContext may be
113 * returned. If true then only a single LoggerContext will be returned.
114 * @param configLocation The URI for the configuration to use.
115 * @return a LoggerContext.
116 * @see LogManager#getContext(ClassLoader, boolean, URI)
117 */
118 public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext,
119 final URI configLocation) {
120 return (LoggerContext) LogManager.getContext(loader, currentContext, configLocation);
121 }
122
123 private final ConcurrentMap<String, Logger> loggers = new ConcurrentHashMap<>();
124 private final CopyOnWriteArrayList<PropertyChangeListener> propertyChangeListeners = new CopyOnWriteArrayList<>();
64125
65126 /**
66127 * The Configuration is volatile to guarantee that initialization of the
69130 private volatile Configuration config = new DefaultConfiguration();
70131 private Object externalContext;
71132 private final String name;
72 private URI configLocation;
133 private volatile URI configLocation;
73134 private Cancellable shutdownCallback;
74135
75136 private final Lock configLock = new ReentrantLock();
148209 }
149210
150211 /**
151 * Start with a specific configuration.
212 * Starts with a specific configuration.
152213 * @param config The new Configuration.
153214 */
154215 public void start(final Configuration config) {
189250 return "Shutdown callback for LoggerContext[name=" + LoggerContext.this.getName() + ']';
190251 }
191252 });
192 } catch (final IllegalStateException ise) {
193 LOGGER.fatal(SHUTDOWN_HOOK_MARKER, "Unable to register shutdown hook because JVM is shutting down.");
194 } catch (final SecurityException se) {
195 LOGGER.error(SHUTDOWN_HOOK_MARKER, "Unable to register shutdown hook due to security restrictions");
253 } catch (final IllegalStateException e) {
254 LOGGER.fatal(SHUTDOWN_HOOK_MARKER, "Unable to register shutdown hook because JVM is shutting down.", e);
255 } catch (final SecurityException e) {
256 LOGGER.error(SHUTDOWN_HOOK_MARKER, "Unable to register shutdown hook due to security restrictions", e);
196257 }
197258 }
198259 }
240301 }
241302
242303 /**
243 * Set the external context.
304 * Sets the external context.
244305 * @param context The external context.
245306 */
246307 public void setExternalContext(final Object context) {
257318 }
258319
259320 /**
260 * Obtain a Logger from the Context.
321 * Obtains a Logger from the Context.
261322 * @param name The name of the Logger to return.
262323 * @return The Logger.
263324 */
280341 }
281342
282343 /**
283 * Obtain a Logger from the Context.
344 * Obtains a Logger from the Context.
284345 * @param name The name of the Logger to return.
285346 * @param messageFactory The message factory is used only when creating a
286347 * logger, subsequent use does not change the logger but will log
301362 }
302363
303364 /**
304 * Determine if the specified Logger exists.
365 * Determines if the specified Logger exists.
305366 * @param name The Logger name to search for.
306367 * @return True if the Logger exists, false otherwise.
307368 */
321382 }
322383
323384 /**
324 * Add a Filter to the Configuration. Filters that are added through the API will be lost
385 * Adds a Filter to the Configuration. Filters that are added through the API will be lost
325386 * when a reconfigure occurs.
326387 * @param filter The Filter to add.
327388 */
338399 }
339400
340401 /**
341 * Set the Configuration to be used.
402 * Sets the Configuration to be used.
342403 * @param config The new Configuration.
343404 * @return The previous Configuration.
344405 */
345 private synchronized Configuration setConfiguration(final Configuration config) {
346 Assert.requireNonNull(config, "No Configuration was provided");
347 final Configuration prev = this.config;
348 config.addListener(this);
349 final ConcurrentMap<String, String> map = config.getComponent(Configuration.CONTEXT_PROPERTIES);
350
351 try { // LOG4J2-719 network access may throw android.os.NetworkOnMainThreadException
352 map.putIfAbsent("hostName", NetUtils.getLocalHostname());
353 } catch (final Exception ex) {
354 LOGGER.debug("Ignoring {}, setting hostName to 'unknown'", ex.toString());
355 map.putIfAbsent("hostName", "unknown");
356 }
357 map.putIfAbsent("contextName", name);
358 config.start();
359 this.config = config;
360 updateLoggers();
361 if (prev != null) {
362 prev.removeListener(this);
363 prev.stop();
364 }
365
366 firePropertyChangeEvent(new PropertyChangeEvent(this, PROPERTY_CONFIG, prev, config));
367
406 private Configuration setConfiguration(final Configuration config) {
407 Objects.requireNonNull(config, "No Configuration was provided");
408 configLock.lock();
368409 try {
369 Server.reregisterMBeansAfterReconfigure();
370 } catch (final Throwable t) {
371 // LOG4J2-716: Android has no java.lang.management
372 LOGGER.error("Could not reconfigure JMX", t);
373 }
374 return prev;
410 final Configuration prev = this.config;
411 config.addListener(this);
412 final ConcurrentMap<String, String> map = config.getComponent(Configuration.CONTEXT_PROPERTIES);
413
414 try { // LOG4J2-719 network access may throw android.os.NetworkOnMainThreadException
415 map.putIfAbsent("hostName", NetUtils.getLocalHostname());
416 } catch (final Exception ex) {
417 LOGGER.debug("Ignoring {}, setting hostName to 'unknown'", ex.toString());
418 map.putIfAbsent("hostName", "unknown");
419 }
420 map.putIfAbsent("contextName", name);
421 config.start();
422 this.config = config;
423 updateLoggers();
424 if (prev != null) {
425 prev.removeListener(this);
426 prev.stop();
427 }
428
429 firePropertyChangeEvent(new PropertyChangeEvent(this, PROPERTY_CONFIG, prev, config));
430
431 try {
432 Server.reregisterMBeansAfterReconfigure();
433 } catch (final Throwable t) {
434 // LOG4J2-716: Android has no java.lang.management
435 LOGGER.error("Could not reconfigure JMX", t);
436 }
437 Log4jLogEvent.setNanoClock(NanoClockFactory.createNanoClock());
438 try {
439 AsyncLogger.setNanoClock(NanoClockFactory.createNanoClock());
440 } catch (Throwable ignored) {
441 // LMAX Disruptor jar may not be in the classpath. Ignore this.
442 LOGGER.debug("Could not set AsyncLogger NanoClock. Ignoring: " + ignored.toString());
443 }
444 return prev;
445 } finally {
446 configLock.unlock();
447 }
375448 }
376449
377450 private void firePropertyChangeEvent(final PropertyChangeEvent event) {
381454 }
382455
383456 public void addPropertyChangeListener(final PropertyChangeListener listener) {
384 propertyChangeListeners.add(Assert.requireNonNull(listener, "listener"));
457 propertyChangeListeners.add(Objects.requireNonNull(listener, "listener"));
385458 }
386459
387460 public void removePropertyChangeListener(final PropertyChangeListener listener) {
395468 * ConfigurationSource#getLocation() getLocation()} to get the actual source of the current configuration.
396469 * @return the initial configuration location or {@code null}
397470 */
398 public synchronized URI getConfigLocation() {
471 public URI getConfigLocation() {
399472 return configLocation;
400473 }
401474
403476 * Sets the configLocation to the specified value and reconfigures this context.
404477 * @param configLocation the location of the new configuration
405478 */
406 public synchronized void setConfigLocation(final URI configLocation) {
479 public void setConfigLocation(final URI configLocation) {
407480 this.configLocation = configLocation;
408 reconfigure();
481
482 reconfigure(configLocation);
409483 }
410484
411485 /**
412486 * Reconfigure the context.
413487 */
414 public synchronized void reconfigure() {
488 private void reconfigure(final URI configURI) {
415489 final ClassLoader cl = ClassLoader.class.isInstance(externalContext) ? (ClassLoader) externalContext : null;
416 LOGGER.debug("Reconfiguration started for context[name={}] at {} ({}) with optional ClassLoader: {}", name,
417 configLocation, this, cl);
418 final Configuration instance = ConfigurationFactory.getInstance().getConfiguration(name, configLocation, cl);
490 LOGGER.debug("Reconfiguration started for context[name={}] at URI {} ({}) with optional ClassLoader: {}", name,
491 configURI, this, cl);
492 final Configuration instance = ConfigurationFactory.getInstance().getConfiguration(name, configURI, cl);
419493 setConfiguration(instance);
420494 /*
421495 * instance.start(); Configuration old = setConfiguration(instance);
422496 * updateLoggers(); if (old != null) { old.stop(); }
423497 */
424498
425 LOGGER.debug("Reconfiguration complete for context[name={}] at {} ({}) with optional ClassLoader: {}", name,
426 configLocation, this, cl);
427 }
428
429 /**
430 * Cause all Loggers to be updated against the current Configuration.
499 LOGGER.debug("Reconfiguration complete for context[name={}] at URI {} ({}) with optional ClassLoader: {}", name,
500 configURI, this, cl);
501 }
502
503 /**
504 * Reconfigure the context. Log4j does not remove Loggers during a reconfiguration. Log4j will create new
505 * LoggerConfig objects and Log4j will point the Loggers at the new LoggerConfigs. Log4j will free the old
506 * LoggerConfig, along with old Appenders and Filters.
507 */
508 public void reconfigure() {
509 reconfigure(configLocation);
510 }
511
512 /**
513 * Causes all Loggers to be updated against the current Configuration.
431514 */
432515 public void updateLoggers() {
433516 updateLoggers(this.config);
434517 }
435518
436519 /**
437 * Cause all Logger to be updated against the specified Configuration.
520 * Causes all Logger to be updated against the specified Configuration.
438521 * @param config The Configuration.
439522 */
440523 public void updateLoggers(final Configuration config) {
444527 }
445528
446529 /**
447 * Cause a reconfiguration to take place when the underlying configuration
530 * Causes a reconfiguration to take place when the underlying configuration
448531 * file changes.
449532 *
450533 * @param reconfigurable The Configuration that can be reconfigured.
3535
3636 // Need to lock that map instead of using a ConcurrentMap due to stop removing the
3737 // manager from the map and closing the stream, requiring the whole stop method to be locked.
38 private static final Map<String, AbstractManager> MAP = new HashMap<String, AbstractManager>();
38 private static final Map<String, AbstractManager> MAP = new HashMap<>();
3939
4040 private static final Lock LOCK = new ReentrantLock();
4141
6969 if (manager == null) {
7070 manager = factory.createManager(name, data);
7171 if (manager == null) {
72 throw new IllegalStateException("Unable to create a manager");
72 throw new IllegalStateException("ManagerFactory [" + factory + "] unable to create manager for ["
73 + name + "] with data [" + data + "]");
7374 }
7475 MAP.put(name, manager);
7576 }
138139 * format descriptors are specified.
139140 */
140141 public Map<String, String> getContentFormat() {
141 return new HashMap<String, String>();
142 return new HashMap<>();
142143 }
143144 }
6262 private AppenderControl errorAppender;
6363 private AsyncThread thread;
6464 private static final AtomicLong threadSequence = new AtomicLong(1);
65 private static ThreadLocal<Boolean> isAppenderThread = new ThreadLocal<Boolean>();
65 private static ThreadLocal<Boolean> isAppenderThread = new ThreadLocal<>();
6666
6767
6868 private AsyncAppender(final String name, final Filter filter, final AppenderRef[] appenderRefs,
7070 final boolean ignoreExceptions, final Configuration config,
7171 final boolean includeLocation) {
7272 super(name, filter, null, ignoreExceptions);
73 this.queue = new ArrayBlockingQueue<Serializable>(queueSize);
73 this.queue = new ArrayBlockingQueue<>(queueSize);
7474 this.queueSize = queueSize;
7575 this.blocking = blocking;
7676 this.config = config;
8282 @Override
8383 public void start() {
8484 final Map<String, Appender> map = config.getAppenders();
85 final List<AppenderControl> appenders = new ArrayList<AppenderControl>();
85 final List<AppenderControl> appenders = new ArrayList<>();
8686 for (final AppenderRef appenderRef : appenderRefs) {
87 if (map.containsKey(appenderRef.getRef())) {
88 appenders.add(new AppenderControl(map.get(appenderRef.getRef()), appenderRef.getLevel(),
89 appenderRef.getFilter()));
87 final Appender appender = map.get(appenderRef.getRef());
88 if (appender != null) {
89 appenders.add(new AppenderControl(appender, appenderRef.getLevel(), appenderRef.getFilter()));
9090 } else {
9191 LOGGER.error("No appender named {} was configured", appenderRef);
9292 }
9393 }
9494 if (errorRef != null) {
95 if (map.containsKey(errorRef)) {
96 errorAppender = new AppenderControl(map.get(errorRef), null, null);
95 final Appender appender = map.get(errorRef);
96 if (appender != null) {
97 errorAppender = new AppenderControl(appender, null, null);
9798 } else {
9899 LOGGER.error("Unable to set up error Appender. No appender named {} was configured", errorRef);
99100 }
149150 coreEvent.setEndOfBatch(false); // queue is definitely not empty!
150151 appendSuccessful = thread.callAppenders(coreEvent);
151152 } else {
153 final Serializable serialized = Log4jLogEvent.serialize(coreEvent, includeLocation);
152154 try {
153155 // wait for free slots in the queue
154 queue.put(Log4jLogEvent.serialize(coreEvent, includeLocation));
156 queue.put(serialized);
155157 appendSuccessful = true;
156158 } catch (final InterruptedException e) {
157 LOGGER.warn("Interrupted while waiting for a free slot in the AsyncAppender LogEvent-queue {}",
158 getName());
159 // LOG4J2-1049: Some applications use Thread.interrupt() to send
160 // messages between application threads. This does not necessarily
161 // mean that the queue is full. To prevent dropping a log message,
162 // quickly try to offer the event to the queue again.
163 // (Yes, this means there is a possibility the same event is logged twice.)
164 //
165 // Finally, catching the InterruptedException means the
166 // interrupted flag has been cleared on the current thread.
167 // This may interfere with the application's expectation of
168 // being interrupted, so when we are done, we set the interrupted
169 // flag again.
170 appendSuccessful = queue.offer(serialized);
171 if (!appendSuccessful) {
172 LOGGER.warn("Interrupted while waiting for a free slot in the AsyncAppender LogEvent-queue {}",
173 getName());
174 }
175 // set the interrupted flag again.
176 Thread.currentThread().interrupt();
159177 }
160178 }
161179 } else {
3838 import org.apache.logging.log4j.util.PropertiesUtil;
3939
4040 /**
41 * ConsoleAppender appends log events to <code>System.out</code> or
41 * Appends log events to <code>System.out</code> or
4242 * <code>System.err</code> using a layout specified by the user. The
4343 * default target is <code>System.out</code>.
4444 * TODO accessing System.out or .err as a byte stream instead of a writer
5353 private static final long serialVersionUID = 1L;
5454 private static final String JANSI_CLASS = "org.fusesource.jansi.WindowsAnsiOutputStream";
5555 private static ConsoleManagerFactory factory = new ConsoleManagerFactory();
56 private static final Target DEFAULT_TARGET = Target.SYSTEM_OUT;
5657
5758 /**
5859 * Enumeration of console destinations.
7172 }
7273
7374 /**
74 * Create a Console Appender.
75 * Creates a Console Appender.
7576 * @param layout The layout to use (required).
7677 * @param filter The Filter or null.
7778 * @param targetStr The target ("SYSTEM_OUT" or "SYSTEM_ERR"). The default is "SYSTEM_OUT".
9899 }
99100 final boolean isFollow = Boolean.parseBoolean(follow);
100101 final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
101 final Target target = targetStr == null ? Target.SYSTEM_OUT : Target.valueOf(targetStr);
102 return new ConsoleAppender(name, layout, filter, getManager(isFollow, target, layout), ignoreExceptions);
102 final Target target = targetStr == null ? DEFAULT_TARGET : Target.valueOf(targetStr);
103 return new ConsoleAppender(name, layout, filter, getManager(target, isFollow, layout), ignoreExceptions);
103104 }
104105
105106 public static ConsoleAppender createDefaultAppenderForLayout(final Layout<? extends Serializable> layout) {
106107 // this method cannot use the builder class without introducing an infinite loop due to DefaultConfiguration
107 return new ConsoleAppender("Console", layout, null, getManager(false, Target.SYSTEM_OUT, layout), true);
108 return new ConsoleAppender("Console", layout, null, getManager(DEFAULT_TARGET, false, layout), true);
108109 }
109110
110111 @PluginBuilderFactory
123124
124125 @PluginBuilderAttribute
125126 @Required
126 private Target target = Target.SYSTEM_OUT;
127 private Target target = DEFAULT_TARGET;
127128
128129 @PluginBuilderAttribute
129130 @Required
167168
168169 @Override
169170 public ConsoleAppender build() {
170 return new ConsoleAppender(name, layout, filter, getManager(follow, target, layout), ignoreExceptions);
171 }
172 }
173
174 private static OutputStreamManager getManager(final boolean follow, final Target target, final Layout<? extends Serializable> layout) {
175 final String type = target.name();
171 return new ConsoleAppender(name, layout, filter, getManager(target, follow, layout), ignoreExceptions);
172 }
173 }
174
175 private static OutputStreamManager getManager(final Target target, final boolean follow, final Layout<? extends Serializable> layout) {
176176 final OutputStream os = getOutputStream(follow, target);
177 return OutputStreamManager.getManager(target.name() + '.' + follow, new FactoryData(os, type, layout), factory);
177 final String managerName = target.name() + '.' + follow;
178 return OutputStreamManager.getManager(managerName, new FactoryData(os, managerName, layout), factory);
178179 }
179180
180181 private static OutputStream getOutputStream(final boolean follow, final Target target) {
181182 final String enc = Charset.defaultCharset().name();
182 PrintStream printStream = null;
183 OutputStream outputStream = null;
183184 try {
184 printStream = target == Target.SYSTEM_OUT ?
185 follow ? new PrintStream(new SystemOutStream(), true, enc) : System.out :
186 follow ? new PrintStream(new SystemErrStream(), true, enc) : System.err;
185 // @formatter:off
186 outputStream = target == Target.SYSTEM_OUT ?
187 follow ? new PrintStream(new SystemOutStream(), true, enc) : System.out :
188 follow ? new PrintStream(new SystemErrStream(), true, enc) : System.err;
189 // @formatter:on
190 outputStream = new CloseShieldOutputStream(outputStream);
187191 } catch (final UnsupportedEncodingException ex) { // should never happen
188192 throw new IllegalStateException("Unsupported default encoding " + enc, ex);
189193 }
190194 final PropertiesUtil propsUtil = PropertiesUtil.getProperties();
191 if (!propsUtil.getStringProperty("os.name").startsWith("Windows") ||
192 propsUtil.getBooleanProperty("log4j.skipJansi")) {
193 return printStream;
195 if (!propsUtil.getStringProperty("os.name").startsWith("Windows")
196 || propsUtil.getBooleanProperty("log4j.skipJansi")) {
197 return outputStream;
194198 }
195199 try {
196200 // We type the parameter as a wildcard to avoid a hard reference to Jansi.
197201 final Class<?> clazz = Loader.loadClass(JANSI_CLASS);
198202 final Constructor<?> constructor = clazz.getConstructor(OutputStream.class);
199 return (OutputStream) constructor.newInstance(printStream);
203 return new CloseShieldOutputStream((OutputStream) constructor.newInstance(outputStream));
200204 } catch (final ClassNotFoundException cnfe) {
201205 LOGGER.debug("Jansi is not installed, cannot find {}", JANSI_CLASS);
202206 } catch (final NoSuchMethodException nsme) {
204208 } catch (final Exception ex) {
205209 LOGGER.warn("Unable to instantiate {}", JANSI_CLASS);
206210 }
207 return printStream;
211 return outputStream;
208212 }
209213
210214 /**
272276 @Override
273277 public void write(final int b) throws IOException {
274278 System.out.write(b);
279 }
280 }
281
282 /**
283 * A delegating OutputStream that does not close its delegate.
284 */
285 private static class CloseShieldOutputStream extends OutputStream {
286
287 private final OutputStream delegate;
288
289 public CloseShieldOutputStream(final OutputStream delegate) {
290 this.delegate = delegate;
291 }
292
293 @Override
294 public void close() {
295 // do not close delegate
296 }
297
298 @Override
299 public void flush() throws IOException {
300 delegate.flush();
301 }
302
303 @Override
304 public void write(final byte[] b) throws IOException {
305 delegate.write(b);
306 }
307
308 @Override
309 public void write(final byte[] b, final int off, final int len)
310 throws IOException {
311 delegate.write(b, off, len);
312 }
313
314 @Override
315 public void write(final int b) throws IOException {
316 delegate.write(b);
275317 }
276318 }
277319
309351 */
310352 @Override
311353 public OutputStreamManager createManager(final String name, final FactoryData data) {
312 return new OutputStreamManager(data.os, data.type, data.layout);
354 return new OutputStreamManager(data.os, data.type, data.layout, true);
313355 }
314356 }
315357
1616 package org.apache.logging.log4j.core.appender;
1717
1818 import java.io.Serializable;
19 import java.util.concurrent.TimeUnit;
1920
2021 import org.apache.logging.log4j.Logger;
2122 import org.apache.logging.log4j.core.Appender;
3435
3536 private static final int MAX_EXCEPTIONS = 3;
3637
37 private static final int EXCEPTION_INTERVAL = 300000;
38 private static final long EXCEPTION_INTERVAL = TimeUnit.MINUTES.toNanos(5);
3839
3940 private int exceptionCount = 0;
4041
41 private long lastException;
42 private long lastException = System.nanoTime() - EXCEPTION_INTERVAL - 1;
4243
4344 private final Appender appender;
4445
5354 */
5455 @Override
5556 public void error(final String msg) {
56 final long current = System.currentTimeMillis();
57 if (lastException + EXCEPTION_INTERVAL < current || exceptionCount++ < MAX_EXCEPTIONS) {
57 final long current = System.nanoTime();
58 if (current - lastException > EXCEPTION_INTERVAL || exceptionCount++ < MAX_EXCEPTIONS) {
5859 LOGGER.error(msg);
5960 }
6061 lastException = current;
6768 */
6869 @Override
6970 public void error(final String msg, final Throwable t) {
70 final long current = System.currentTimeMillis();
71 if (lastException + EXCEPTION_INTERVAL < current || exceptionCount++ < MAX_EXCEPTIONS) {
71 final long current = System.nanoTime();
72 if (current - lastException > EXCEPTION_INTERVAL || exceptionCount++ < MAX_EXCEPTIONS) {
7273 LOGGER.error(msg, t);
7374 }
7475 lastException = current;
8586 */
8687 @Override
8788 public void error(final String msg, final LogEvent event, final Throwable t) {
88 final long current = System.currentTimeMillis();
89 if (lastException + EXCEPTION_INTERVAL < current || exceptionCount++ < MAX_EXCEPTIONS) {
89 final long current = System.nanoTime();
90 if (current - lastException > EXCEPTION_INTERVAL || exceptionCount++ < MAX_EXCEPTIONS) {
9091 LOGGER.error(msg, t);
9192 }
9293 lastException = current;
1818 import java.util.ArrayList;
1919 import java.util.List;
2020 import java.util.Map;
21 import java.util.concurrent.TimeUnit;
2122
2223 import org.apache.logging.log4j.LoggingException;
2324 import org.apache.logging.log4j.core.Appender;
5455
5556 private AppenderControl primary;
5657
57 private final List<AppenderControl> failoverAppenders = new ArrayList<AppenderControl>();
58
59 private final long intervalMillis;
60
61 private volatile long nextCheckMillis = 0;
58 private final List<AppenderControl> failoverAppenders = new ArrayList<>();
59
60 private final long intervalNanos;
61
62 private volatile long nextCheckNanos = 0;
6263
6364 private FailoverAppender(final String name, final Filter filter, final String primary, final String[] failovers,
6465 final int intervalMillis, final Configuration config, final boolean ignoreExceptions) {
6667 this.primaryRef = primary;
6768 this.failovers = failovers;
6869 this.config = config;
69 this.intervalMillis = intervalMillis;
70 this.intervalNanos = TimeUnit.MILLISECONDS.toNanos(intervalMillis);
7071 }
7172
7273
7475 public void start() {
7576 final Map<String, Appender> map = config.getAppenders();
7677 int errors = 0;
77 if (map.containsKey(primaryRef)) {
78 primary = new AppenderControl(map.get(primaryRef), null, null);
78 final Appender appender = map.get(primaryRef);
79 if (appender != null) {
80 primary = new AppenderControl(appender, null, null);
7981 } else {
8082 LOGGER.error("Unable to locate primary Appender " + primaryRef);
8183 ++errors;
8284 }
8385 for (final String name : failovers) {
84 if (map.containsKey(name)) {
85 failoverAppenders.add(new AppenderControl(map.get(name), null, null));
86 final Appender foAppender = map.get(name);
87 if (foAppender != null) {
88 failoverAppenders.add(new AppenderControl(foAppender, null, null));
8689 } else {
8790 LOGGER.error("Failover appender " + name + " is not configured");
8891 }
106109 error("FailoverAppender " + getName() + " did not start successfully");
107110 return;
108111 }
109 final long localCheckMillis = nextCheckMillis;
110 if (localCheckMillis == 0 || System.currentTimeMillis() > localCheckMillis) {
112 final long localCheckNanos = nextCheckNanos;
113 if (localCheckNanos == 0 || System.nanoTime() - localCheckNanos > 0) {
111114 callAppender(event);
112115 } else {
113116 failover(event, null);
117120 private void callAppender(final LogEvent event) {
118121 try {
119122 primary.callAppender(event);
120 nextCheckMillis = 0;
123 nextCheckNanos = 0;
121124 } catch (final Exception ex) {
122 nextCheckMillis = System.currentTimeMillis() + intervalMillis;
125 nextCheckNanos = System.nanoTime() + intervalNanos;
123126 failover(event, ex);
124127 }
125128 }
126129
127130 private void failover(final LogEvent event, final Exception ex) {
128131 final RuntimeException re = ex != null ?
129 (ex instanceof LoggingException ? (LoggingException)ex : new LoggingException(ex)) : null;
132 (ex instanceof LoggingException ? (LoggingException) ex : new LoggingException(ex)) : null;
130133 boolean written = false;
131134 Exception failoverException = null;
132135 for (final AppenderControl control : failoverAppenders) {
4444 private final Advertiser advertiser;
4545 private Object advertisement;
4646
47 private FileAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter, final FileManager manager,
48 final String filename, final boolean ignoreExceptions, final boolean immediateFlush,
49 final Advertiser advertiser) {
47 private FileAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
48 final FileManager manager, final String filename, final boolean ignoreExceptions,
49 final boolean immediateFlush, final Advertiser advertiser) {
50
5051 super(name, layout, filter, ignoreExceptions, immediateFlush, manager);
5152 if (advertiser != null) {
52 final Map<String, String> configuration = new HashMap<String, String>(layout.getContentFormat());
53 final Map<String, String> configuration = new HashMap<>(layout.getContentFormat());
5354 configuration.putAll(manager.getContentFormat());
5455 configuration.put("contentType", layout.getContentType());
5556 configuration.put("name", name);
4343 private final int bufferSize;
4444
4545 protected FileManager(final String fileName, final OutputStream os, final boolean append, final boolean locking,
46 final String advertiseURI, final Layout<? extends Serializable> layout, final int bufferSize) {
47 super(os, fileName, layout);
46 final String advertiseURI, final Layout<? extends Serializable> layout, final int bufferSize,
47 final boolean writeHeader) {
48 super(os, fileName, layout, writeHeader);
4849 this.isAppend = append;
4950 this.isLocking = locking;
5051 this.advertiseURI = advertiseURI;
141142 */
142143 @Override
143144 public Map<String, String> getContentFormat() {
144 final Map<String, String> result = new HashMap<String, String>(super.getContentFormat());
145 final Map<String, String> result = new HashMap<>(super.getContentFormat());
145146 result.put("fileURI", advertiseURI);
146147 return result;
147148 }
195196 parent.mkdirs();
196197 }
197198
199 final boolean writeHeader = !data.append || !file.exists();
198200 OutputStream os;
199201 try {
200202 os = new FileOutputStream(name, data.append);
204206 } else {
205207 bufferSize = -1; // signals to RollingFileManager not to use BufferedOutputStream
206208 }
207 return new FileManager(name, os, data.append, data.locking, data.advertiseURI, data.layout, bufferSize);
209 return new FileManager(name, os, data.append, data.locking, data.advertiseURI, data.layout, bufferSize,
210 writeHeader);
208211 } catch (final FileNotFoundException ex) {
209212 LOGGER.error("FileManager (" + name + ") " + ex);
210213 }
5555 final boolean ignoreExceptions, final boolean immediateFlush, final Advertiser advertiser) {
5656 super(name, layout, filter, ignoreExceptions, immediateFlush, manager);
5757 if (advertiser != null) {
58 final Map<String, String> configuration = new HashMap<String, String>(layout.getContentFormat());
58 final Map<String, String> configuration = new HashMap<>(layout.getContentFormat());
5959 configuration.putAll(manager.getContentFormat());
6060 configuration.put("contentType", layout.getContentType());
6161 configuration.put("name", name);
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.appender;
17
18 import java.io.File;
19 import java.io.IOException;
20 import java.io.OutputStream;
21 import java.io.RandomAccessFile;
22 import java.io.Serializable;
23 import java.lang.reflect.Method;
24 import java.nio.ByteOrder;
25 import java.nio.MappedByteBuffer;
26 import java.nio.channels.FileChannel;
27 import java.security.AccessController;
28 import java.security.PrivilegedActionException;
29 import java.security.PrivilegedExceptionAction;
30 import java.util.HashMap;
31 import java.util.Map;
32
33 import org.apache.logging.log4j.core.Layout;
34 import org.apache.logging.log4j.core.util.Assert;
35 import org.apache.logging.log4j.core.util.Closer;
36
37 /**
38 * Extends OutputStreamManager but instead of using a buffered output stream, this class maps a region of a file into
39 * memory and writes to this memory region.
40 * <p>
41 *
42 * @see <a
43 * href="http://www.codeproject.com/Tips/683614/Things-to-Know-about-Memory-Mapped-File-in-Java">http://www.codeproject.com/Tips/683614/Things-to-Know-about-Memory-Mapped-File-in-Java</a>
44 * @see <a href="http://bugs.java.com/view_bug.do?bug_id=6893654">http://bugs.java.com/view_bug.do?bug_id=6893654</a>
45 * @see <a href="http://bugs.java.com/view_bug.do?bug_id=4724038">http://bugs.java.com/view_bug.do?bug_id=4724038</a>
46 * @see <a
47 * href="http://stackoverflow.com/questions/9261316/memory-mapped-mappedbytebuffer-or-direct-bytebuffer-for-db-implementation">http://stackoverflow.com/questions/9261316/memory-mapped-mappedbytebuffer-or-direct-bytebuffer-for-db-implementation</a>
48 *
49 * @since 2.1
50 */
51 public class MemoryMappedFileManager extends OutputStreamManager {
52 static final int DEFAULT_REGION_LENGTH = 32 * 1024 * 1024;
53 private static final MemoryMappedFileManagerFactory FACTORY = new MemoryMappedFileManagerFactory();
54
55 private final boolean isForce;
56 private final int regionLength;
57 private final String advertiseURI;
58 private final RandomAccessFile randomAccessFile;
59 private final ThreadLocal<Boolean> isEndOfBatch = new ThreadLocal<Boolean>();
60 private MappedByteBuffer mappedBuffer;
61 private long mappingOffset;
62
63 protected MemoryMappedFileManager(final RandomAccessFile file, final String fileName, final OutputStream os,
64 final boolean force, final long position, final int regionLength, final String advertiseURI,
65 final Layout<? extends Serializable> layout) throws IOException {
66 super(os, fileName, layout);
67 this.isForce = force;
68 this.randomAccessFile = Assert.requireNonNull(file, "RandomAccessFile");
69 this.regionLength = regionLength;
70 this.advertiseURI = advertiseURI;
71 this.isEndOfBatch.set(Boolean.FALSE);
72 this.mappedBuffer = mmap(randomAccessFile.getChannel(), getFileName(), position, regionLength);
73 this.mappingOffset = position;
74 }
75
76 /**
77 * Returns the MemoryMappedFileManager.
78 *
79 * @param fileName The name of the file to manage.
80 * @param append true if the file should be appended to, false if it should be overwritten.
81 * @param isForce true if the contents should be flushed to disk on every write
82 * @param regionLength The mapped region length.
83 * @param advertiseURI the URI to use when advertising the file
84 * @param layout The layout.
85 * @return A MemoryMappedFileManager for the File.
86 */
87 public static MemoryMappedFileManager getFileManager(final String fileName, final boolean append,
88 final boolean isForce, final int regionLength, final String advertiseURI,
89 final Layout<? extends Serializable> layout) {
90 return (MemoryMappedFileManager) getManager(fileName, new FactoryData(append, isForce, regionLength,
91 advertiseURI, layout), FACTORY);
92 }
93
94 public Boolean isEndOfBatch() {
95 return isEndOfBatch.get();
96 }
97
98 public void setEndOfBatch(final boolean isEndOfBatch) {
99 this.isEndOfBatch.set(Boolean.valueOf(isEndOfBatch));
100 }
101
102 @Override
103 protected synchronized void write(final byte[] bytes, int offset, int length) {
104 super.write(bytes, offset, length); // writes to dummy output stream
105
106 while (length > mappedBuffer.remaining()) {
107 final int chunk = mappedBuffer.remaining();
108 mappedBuffer.put(bytes, offset, chunk);
109 offset += chunk;
110 length -= chunk;
111 remap();
112 }
113 mappedBuffer.put(bytes, offset, length);
114
115 // no need to call flush() if force is true,
116 // already done in AbstractOutputStreamAppender.append
117 }
118
119 private synchronized void remap() {
120 final long offset = this.mappingOffset + mappedBuffer.position();
121 final int length = mappedBuffer.remaining() + regionLength;
122 try {
123 unsafeUnmap(mappedBuffer);
124 final long fileLength = randomAccessFile.length() + regionLength;
125 LOGGER.debug("MMapAppender extending {} by {} bytes to {}", getFileName(), regionLength, fileLength);
126
127 long startNanos = System.nanoTime();
128 randomAccessFile.setLength(fileLength);
129 final float millis = (float) ((System.nanoTime() - startNanos) / (1000.0 * 1000.0));
130 LOGGER.debug("MMapAppender extended {} OK in {} millis", getFileName(), millis);
131
132 mappedBuffer = mmap(randomAccessFile.getChannel(), getFileName(), offset, length);
133 mappingOffset = offset;
134 } catch (final Exception ex) {
135 LOGGER.error("Unable to remap " + getName() + ". " + ex);
136 }
137 }
138
139 @Override
140 public synchronized void flush() {
141 mappedBuffer.force();
142 }
143
144 @Override
145 public synchronized void close() {
146 final long position = mappedBuffer.position();
147 final long length = mappingOffset + position;
148 try {
149 unsafeUnmap(mappedBuffer);
150 } catch (final Exception ex) {
151 LOGGER.error("Unable to unmap MappedBuffer " + getName() + ". " + ex);
152 }
153 try {
154 LOGGER.debug("MMapAppender closing. Setting {} length to {} (offset {} + position {})", getFileName(),
155 length, mappingOffset, position);
156 randomAccessFile.setLength(length);
157 randomAccessFile.close();
158 } catch (final IOException ex) {
159 LOGGER.error("Unable to close MemoryMappedFile " + getName() + ". " + ex);
160 }
161 }
162
163 public static MappedByteBuffer mmap(final FileChannel fileChannel, final String fileName, final long start,
164 final int size) throws IOException {
165 for (int i = 1;; i++) {
166 try {
167 LOGGER.debug("MMapAppender remapping {} start={}, size={}", fileName, start, size);
168
169 final long startNanos = System.nanoTime();
170 final MappedByteBuffer map = fileChannel.map(FileChannel.MapMode.READ_WRITE, start, size);
171 map.order(ByteOrder.nativeOrder());
172
173 final float millis = (float) ((System.nanoTime() - startNanos) / (1000.0 * 1000.0));
174 LOGGER.debug("MMapAppender remapped {} OK in {} millis", fileName, millis);
175
176 return map;
177 } catch (final IOException e) {
178 if (e.getMessage() == null || !e.getMessage().endsWith("user-mapped section open")) {
179 throw e;
180 }
181 LOGGER.debug("Remap attempt {}/10 failed. Retrying...", i, e);
182 if (i < 10) {
183 Thread.yield();
184 } else {
185 try {
186 Thread.sleep(1);
187 } catch (final InterruptedException ignored) {
188 Thread.currentThread().interrupt();
189 throw e;
190 }
191 }
192 }
193 }
194 }
195
196 private static void unsafeUnmap(final MappedByteBuffer mbb) throws PrivilegedActionException {
197 LOGGER.debug("MMapAppender unmapping old buffer...");
198 final long startNanos = System.nanoTime();
199 AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
200 @Override
201 public Object run() throws Exception {
202 final Method getCleanerMethod = mbb.getClass().getMethod("cleaner");
203 getCleanerMethod.setAccessible(true);
204 final Object cleaner = getCleanerMethod.invoke(mbb); // sun.misc.Cleaner instance
205 final Method cleanMethod = cleaner.getClass().getMethod("clean");
206 cleanMethod.invoke(cleaner);
207 return null;
208 }
209 });
210 final float millis = (float) ((System.nanoTime() - startNanos) / (1000.0 * 1000.0));
211 LOGGER.debug("MMapAppender unmapped buffer OK in {} millis", millis);
212 }
213
214 /**
215 * Returns the name of the File being managed.
216 *
217 * @return The name of the File being managed.
218 */
219 public String getFileName() {
220 return getName();
221 }
222
223 /**
224 * Returns the length of the memory mapped region.
225 *
226 * @return the length of the mapped region
227 */
228 public int getRegionLength() {
229 return regionLength;
230 }
231
232 /**
233 * Returns {@code true} if the content of the buffer should be forced to the storage device on every write,
234 * {@code false} otherwise.
235 *
236 * @return whether each write should be force-sync'ed
237 */
238 public boolean isImmediateFlush() {
239 return isForce;
240 }
241
242 /** {@code OutputStream} subclass that does not write anything. */
243 static class DummyOutputStream extends OutputStream {
244 @Override
245 public void write(final int b) throws IOException {
246 }
247
248 @Override
249 public void write(final byte[] b, final int off, final int len) throws IOException {
250 }
251 }
252
253 /**
254 * Gets this FileManager's content format specified by:
255 * <p>
256 * Key: "fileURI" Value: provided "advertiseURI" param.
257 * </p>
258 *
259 * @return Map of content format keys supporting FileManager
260 */
261 @Override
262 public Map<String, String> getContentFormat() {
263 final Map<String, String> result = new HashMap<String, String>(super.getContentFormat());
264 result.put("fileURI", advertiseURI);
265 return result;
266 }
267
268 /**
269 * Factory Data.
270 */
271 private static class FactoryData {
272 private final boolean append;
273 private final boolean force;
274 private final int regionLength;
275 private final String advertiseURI;
276 private final Layout<? extends Serializable> layout;
277
278 /**
279 * Constructor.
280 *
281 * @param append Append to existing file or truncate.
282 * @param force forces the memory content to be written to the storage device on every event
283 * @param regionLength length of the mapped region
284 */
285 public FactoryData(final boolean append, final boolean force, final int regionLength,
286 final String advertiseURI, final Layout<? extends Serializable> layout) {
287 this.append = append;
288 this.force = force;
289 this.regionLength = regionLength;
290 this.advertiseURI = advertiseURI;
291 this.layout = layout;
292 }
293 }
294
295 /**
296 * Factory to create a MemoryMappedFileManager.
297 */
298 private static class MemoryMappedFileManagerFactory implements ManagerFactory<MemoryMappedFileManager, FactoryData> {
299
300 /**
301 * Create a MemoryMappedFileManager.
302 *
303 * @param name The name of the File.
304 * @param data The FactoryData
305 * @return The MemoryMappedFileManager for the File.
306 */
307 @SuppressWarnings("resource")
308 @Override
309 public MemoryMappedFileManager createManager(final String name, final FactoryData data) {
310 final File file = new File(name);
311 final File parent = file.getParentFile();
312 if (null != parent && !parent.exists()) {
313 parent.mkdirs();
314 }
315 if (!data.append) {
316 file.delete();
317 }
318
319 final OutputStream os = new DummyOutputStream();
320 RandomAccessFile raf = null;
321 try {
322 raf = new RandomAccessFile(name, "rw");
323 final long position = (data.append) ? raf.length() : 0;
324 raf.setLength(position + data.regionLength);
325 return new MemoryMappedFileManager(raf, name, os, data.force, position, data.regionLength,
326 data.advertiseURI, data.layout);
327 } catch (final Exception ex) {
328 LOGGER.error("MemoryMappedFileManager (" + name + ") " + ex);
329 Closer.closeSilently(raf);
330 }
331 return null;
332 }
333 }
334 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.appender;
17
18 import java.io.File;
19 import java.io.IOException;
20 import java.io.OutputStream;
21 import java.io.RandomAccessFile;
22 import java.io.Serializable;
23 import java.lang.reflect.Method;
24 import java.nio.ByteOrder;
25 import java.nio.MappedByteBuffer;
26 import java.nio.channels.FileChannel;
27 import java.security.AccessController;
28 import java.security.PrivilegedActionException;
29 import java.security.PrivilegedExceptionAction;
30 import java.util.HashMap;
31 import java.util.Map;
32 import java.util.Objects;
33
34 import org.apache.logging.log4j.core.Layout;
35 import org.apache.logging.log4j.core.util.Closer;
36 import org.apache.logging.log4j.core.util.NullOutputStream;
37
38 /**
39 * Extends OutputStreamManager but instead of using a buffered output stream, this class maps a region of a file into
40 * memory and writes to this memory region.
41 * <p>
42 *
43 * @see <a
44 * href="http://www.codeproject.com/Tips/683614/Things-to-Know-about-Memory-Mapped-File-in-Java">
45 * http://www.codeproject.com/Tips/683614/Things-to-Know-about-Memory-Mapped-File-in-Java</a>
46 * @see <a href="http://bugs.java.com/view_bug.do?bug_id=6893654">http://bugs.java.com/view_bug.do?bug_id=6893654</a>
47 * @see <a href="http://bugs.java.com/view_bug.do?bug_id=4724038">http://bugs.java.com/view_bug.do?bug_id=4724038</a>
48 * @see <a
49 * href="http://stackoverflow.com/questions/9261316/memory-mapped-mappedbytebuffer-or-direct-bytebuffer-for-db-implementation">
50 * http://stackoverflow.com/questions/9261316/memory-mapped-mappedbytebuffer-or-direct-bytebuffer-for-db-implementation</a>
51 *
52 * @since 2.1
53 */
54 public class MemoryMappedFileManager extends OutputStreamManager {
55 /**
56 *
57 */
58 private static final int MAX_REMAP_COUNT = 10;
59 static final int DEFAULT_REGION_LENGTH = 32 * 1024 * 1024;
60 private static final MemoryMappedFileManagerFactory FACTORY = new MemoryMappedFileManagerFactory();
61 private static final double NANOS_PER_MILLISEC = 1000.0 * 1000.0;
62
63 private final boolean isForce;
64 private final int regionLength;
65 private final String advertiseURI;
66 private final RandomAccessFile randomAccessFile;
67 private final ThreadLocal<Boolean> isEndOfBatch = new ThreadLocal<>();
68 private MappedByteBuffer mappedBuffer;
69 private long mappingOffset;
70
71 protected MemoryMappedFileManager(final RandomAccessFile file, final String fileName, final OutputStream os,
72 final boolean force, final long position, final int regionLength, final String advertiseURI,
73 final Layout<? extends Serializable> layout, final boolean writeHeader) throws IOException {
74 super(os, fileName, layout, writeHeader);
75 this.isForce = force;
76 this.randomAccessFile = Objects.requireNonNull(file, "RandomAccessFile");
77 this.regionLength = regionLength;
78 this.advertiseURI = advertiseURI;
79 this.isEndOfBatch.set(Boolean.FALSE);
80 this.mappedBuffer = mmap(randomAccessFile.getChannel(), getFileName(), position, regionLength);
81 this.mappingOffset = position;
82 }
83
84 /**
85 * Returns the MemoryMappedFileManager.
86 *
87 * @param fileName The name of the file to manage.
88 * @param append true if the file should be appended to, false if it should be overwritten.
89 * @param isForce true if the contents should be flushed to disk on every write
90 * @param regionLength The mapped region length.
91 * @param advertiseURI the URI to use when advertising the file
92 * @param layout The layout.
93 * @return A MemoryMappedFileManager for the File.
94 */
95 public static MemoryMappedFileManager getFileManager(final String fileName, final boolean append,
96 final boolean isForce, final int regionLength, final String advertiseURI,
97 final Layout<? extends Serializable> layout) {
98 return (MemoryMappedFileManager) getManager(fileName, new FactoryData(append, isForce, regionLength,
99 advertiseURI, layout), FACTORY);
100 }
101
102 public Boolean isEndOfBatch() {
103 return isEndOfBatch.get();
104 }
105
106 public void setEndOfBatch(final boolean isEndOfBatch) {
107 this.isEndOfBatch.set(Boolean.valueOf(isEndOfBatch));
108 }
109
110 @Override
111 protected synchronized void write(final byte[] bytes, int offset, int length) {
112 super.write(bytes, offset, length); // writes to dummy output stream
113
114 while (length > mappedBuffer.remaining()) {
115 final int chunk = mappedBuffer.remaining();
116 mappedBuffer.put(bytes, offset, chunk);
117 offset += chunk;
118 length -= chunk;
119 remap();
120 }
121 mappedBuffer.put(bytes, offset, length);
122
123 // no need to call flush() if force is true,
124 // already done in AbstractOutputStreamAppender.append
125 }
126
127 private synchronized void remap() {
128 final long offset = this.mappingOffset + mappedBuffer.position();
129 final int length = mappedBuffer.remaining() + regionLength;
130 try {
131 unsafeUnmap(mappedBuffer);
132 final long fileLength = randomAccessFile.length() + regionLength;
133 LOGGER.debug("MMapAppender extending {} by {} bytes to {}", getFileName(), regionLength, fileLength);
134
135 final long startNanos = System.nanoTime();
136 randomAccessFile.setLength(fileLength);
137 final float millis = (float) ((System.nanoTime() - startNanos) / NANOS_PER_MILLISEC);
138 LOGGER.debug("MMapAppender extended {} OK in {} millis", getFileName(), millis);
139
140 mappedBuffer = mmap(randomAccessFile.getChannel(), getFileName(), offset, length);
141 mappingOffset = offset;
142 } catch (final Exception ex) {
143 LOGGER.error("Unable to remap " + getName() + ". " + ex);
144 }
145 }
146
147 @Override
148 public synchronized void flush() {
149 mappedBuffer.force();
150 }
151
152 @Override
153 public synchronized void close() {
154 final long position = mappedBuffer.position();
155 final long length = mappingOffset + position;
156 try {
157 unsafeUnmap(mappedBuffer);
158 } catch (final Exception ex) {
159 LOGGER.error("Unable to unmap MappedBuffer " + getName() + ". " + ex);
160 }
161 try {
162 LOGGER.debug("MMapAppender closing. Setting {} length to {} (offset {} + position {})", getFileName(),
163 length, mappingOffset, position);
164 randomAccessFile.setLength(length);
165 randomAccessFile.close();
166 } catch (final IOException ex) {
167 LOGGER.error("Unable to close MemoryMappedFile " + getName() + ". " + ex);
168 }
169 }
170
171 public static MappedByteBuffer mmap(final FileChannel fileChannel, final String fileName, final long start,
172 final int size) throws IOException {
173 for (int i = 1;; i++) {
174 try {
175 LOGGER.debug("MMapAppender remapping {} start={}, size={}", fileName, start, size);
176
177 final long startNanos = System.nanoTime();
178 final MappedByteBuffer map = fileChannel.map(FileChannel.MapMode.READ_WRITE, start, size);
179 map.order(ByteOrder.nativeOrder());
180
181 final float millis = (float) ((System.nanoTime() - startNanos) / NANOS_PER_MILLISEC);
182 LOGGER.debug("MMapAppender remapped {} OK in {} millis", fileName, millis);
183
184 return map;
185 } catch (final IOException e) {
186 if (e.getMessage() == null || !e.getMessage().endsWith("user-mapped section open")) {
187 throw e;
188 }
189 LOGGER.debug("Remap attempt {}/{} failed. Retrying...", i, MAX_REMAP_COUNT, e);
190 if (i < MAX_REMAP_COUNT) {
191 Thread.yield();
192 } else {
193 try {
194 Thread.sleep(1);
195 } catch (final InterruptedException ignored) {
196 Thread.currentThread().interrupt();
197 throw e;
198 }
199 }
200 }
201 }
202 }
203
204 private static void unsafeUnmap(final MappedByteBuffer mbb) throws PrivilegedActionException {
205 LOGGER.debug("MMapAppender unmapping old buffer...");
206 final long startNanos = System.nanoTime();
207 AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
208 @Override
209 public Object run() throws Exception {
210 final Method getCleanerMethod = mbb.getClass().getMethod("cleaner");
211 getCleanerMethod.setAccessible(true);
212 final Object cleaner = getCleanerMethod.invoke(mbb); // sun.misc.Cleaner instance
213 final Method cleanMethod = cleaner.getClass().getMethod("clean");
214 cleanMethod.invoke(cleaner);
215 return null;
216 }
217 });
218 final float millis = (float) ((System.nanoTime() - startNanos) / NANOS_PER_MILLISEC);
219 LOGGER.debug("MMapAppender unmapped buffer OK in {} millis", millis);
220 }
221
222 /**
223 * Returns the name of the File being managed.
224 *
225 * @return The name of the File being managed.
226 */
227 public String getFileName() {
228 return getName();
229 }
230
231 /**
232 * Returns the length of the memory mapped region.
233 *
234 * @return the length of the mapped region
235 */
236 public int getRegionLength() {
237 return regionLength;
238 }
239
240 /**
241 * Returns {@code true} if the content of the buffer should be forced to the storage device on every write,
242 * {@code false} otherwise.
243 *
244 * @return whether each write should be force-sync'ed
245 */
246 public boolean isImmediateFlush() {
247 return isForce;
248 }
249
250 /**
251 * Gets this FileManager's content format specified by:
252 * <p>
253 * Key: "fileURI" Value: provided "advertiseURI" param.
254 * </p>
255 *
256 * @return Map of content format keys supporting FileManager
257 */
258 @Override
259 public Map<String, String> getContentFormat() {
260 final Map<String, String> result = new HashMap<>(super.getContentFormat());
261 result.put("fileURI", advertiseURI);
262 return result;
263 }
264
265 /**
266 * Factory Data.
267 */
268 private static class FactoryData {
269 private final boolean append;
270 private final boolean force;
271 private final int regionLength;
272 private final String advertiseURI;
273 private final Layout<? extends Serializable> layout;
274
275 /**
276 * Constructor.
277 *
278 * @param append Append to existing file or truncate.
279 * @param force forces the memory content to be written to the storage device on every event
280 * @param regionLength length of the mapped region
281 */
282 public FactoryData(final boolean append, final boolean force, final int regionLength,
283 final String advertiseURI, final Layout<? extends Serializable> layout) {
284 this.append = append;
285 this.force = force;
286 this.regionLength = regionLength;
287 this.advertiseURI = advertiseURI;
288 this.layout = layout;
289 }
290 }
291
292 /**
293 * Factory to create a MemoryMappedFileManager.
294 */
295 private static class MemoryMappedFileManagerFactory
296 implements ManagerFactory<MemoryMappedFileManager, FactoryData> {
297
298 /**
299 * Create a MemoryMappedFileManager.
300 *
301 * @param name The name of the File.
302 * @param data The FactoryData
303 * @return The MemoryMappedFileManager for the File.
304 */
305 @SuppressWarnings("resource")
306 @Override
307 public MemoryMappedFileManager createManager(final String name, final FactoryData data) {
308 final File file = new File(name);
309 final File parent = file.getParentFile();
310 if (null != parent && !parent.exists()) {
311 parent.mkdirs();
312 }
313 if (!data.append) {
314 file.delete();
315 }
316
317 final boolean writeHeader = !data.append || !file.exists();
318 final OutputStream os = NullOutputStream.NULL_OUTPUT_STREAM;
319 RandomAccessFile raf = null;
320 try {
321 raf = new RandomAccessFile(name, "rw");
322 final long position = (data.append) ? raf.length() : 0;
323 raf.setLength(position + data.regionLength);
324 return new MemoryMappedFileManager(raf, name, os, data.force, position, data.regionLength,
325 data.advertiseURI, data.layout, writeHeader);
326 } catch (final Exception ex) {
327 LOGGER.error("MemoryMappedFileManager (" + name + ") " + ex);
328 Closer.closeSilently(raf);
329 }
330 return null;
331 }
332 }
333 }
2929 private volatile OutputStream os;
3030 protected final Layout<?> layout;
3131
32 protected OutputStreamManager(final OutputStream os, final String streamName, final Layout<?> layout) {
32 protected OutputStreamManager(final OutputStream os, final String streamName, final Layout<?> layout,
33 final boolean writeHeader) {
3334 super(streamName);
3435 this.os = os;
3536 this.layout = layout;
36 if (layout != null) {
37 if (writeHeader && layout != null) {
3738 final byte[] header = layout.getHeader();
3839 if (header != null) {
3940 try {
4545 private Object advertisement;
4646 private final Advertiser advertiser;
4747
48 private RandomAccessFileAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
49 final RandomAccessFileManager manager, final String filename, final boolean ignoreExceptions,
50 final boolean immediateFlush, final Advertiser advertiser) {
48 private RandomAccessFileAppender(final String name, final Layout<? extends Serializable> layout,
49 final Filter filter, final RandomAccessFileManager manager, final String filename,
50 final boolean ignoreExceptions, final boolean immediateFlush, final Advertiser advertiser) {
51
5152 super(name, layout, filter, ignoreExceptions, immediateFlush, manager);
5253 if (advertiser != null) {
53 final Map<String, String> configuration = new HashMap<String, String>(
54 final Map<String, String> configuration = new HashMap<>(
5455 layout.getContentFormat());
5556 configuration.putAll(manager.getContentFormat());
5657 configuration.put("contentType", layout.getContentType());
2525 import java.util.Map;
2626
2727 import org.apache.logging.log4j.core.Layout;
28 import org.apache.logging.log4j.core.util.NullOutputStream;
2829
2930 /**
3031 * Extends OutputStreamManager but instead of using a buffered output stream,
4041 private final String advertiseURI;
4142 private final RandomAccessFile randomAccessFile;
4243 private final ByteBuffer buffer;
43 private final ThreadLocal<Boolean> isEndOfBatch = new ThreadLocal<Boolean>();
44 private final ThreadLocal<Boolean> isEndOfBatch = new ThreadLocal<>();
4445
4546 protected RandomAccessFileManager(final RandomAccessFile file,
4647 final String fileName, final OutputStream os,
4748 final boolean immediateFlush, final int bufferSize,
48 final String advertiseURI, final Layout<? extends Serializable> layout) {
49 super(os, fileName, layout);
49 final String advertiseURI, final Layout<? extends Serializable> layout, final boolean writeHeader) {
50 super(os, fileName, layout, writeHeader);
5051 this.isImmediateFlush = immediateFlush;
5152 this.randomAccessFile = file;
5253 this.advertiseURI = advertiseURI;
142143 return buffer.capacity();
143144 }
144145
145 /** {@code OutputStream} subclass that does not write anything. */
146 static class DummyOutputStream extends OutputStream {
147 @Override
148 public void write(final int b) throws IOException {
149 }
150
151 @Override
152 public void write(final byte[] b, final int off, final int len) throws IOException {
153 }
154 }
155
156146 /**
157147 * Gets this FileManager's content format specified by:
158148 * <p>
163153 */
164154 @Override
165155 public Map<String, String> getContentFormat() {
166 final Map<String, String> result = new HashMap<String, String>(
156 final Map<String, String> result = new HashMap<>(
167157 super.getContentFormat());
168158 result.put("fileURI", advertiseURI);
169159 return result;
219209 file.delete();
220210 }
221211
222 final OutputStream os = new DummyOutputStream();
212 final boolean writeHeader = !data.append || !file.exists();
213 final OutputStream os = NullOutputStream.NULL_OUTPUT_STREAM;
223214 RandomAccessFile raf;
224215 try {
225216 raf = new RandomAccessFile(name, "rw");
229220 raf.setLength(0);
230221 }
231222 return new RandomAccessFileManager(raf, name, os, data.immediateFlush,
232 data.bufferSize, data.advertiseURI, data.layout);
223 data.bufferSize, data.advertiseURI, data.layout, writeHeader);
233224 } catch (final Exception ex) {
234225 LOGGER.error("RandomAccessFileManager (" + name + ") " + ex);
235226 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.appender;
17
18 import java.io.Serializable;
19 import java.util.HashMap;
20 import java.util.Map;
21 import java.util.zip.Deflater;
22
23 import org.apache.logging.log4j.core.Filter;
24 import org.apache.logging.log4j.core.Layout;
25 import org.apache.logging.log4j.core.LogEvent;
26 import org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy;
27 import org.apache.logging.log4j.core.appender.rolling.RollingFileManager;
28 import org.apache.logging.log4j.core.appender.rolling.RolloverStrategy;
29 import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
30 import org.apache.logging.log4j.core.config.Configuration;
31 import org.apache.logging.log4j.core.config.plugins.Plugin;
32 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
33 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
34 import org.apache.logging.log4j.core.config.plugins.PluginElement;
35 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
36 import org.apache.logging.log4j.core.layout.PatternLayout;
37 import org.apache.logging.log4j.core.net.Advertiser;
38 import org.apache.logging.log4j.core.util.Booleans;
39 import org.apache.logging.log4j.core.util.Integers;
40
41 /**
42 * An appender that writes to files and can roll over at intervals.
43 */
44 @Plugin(name = "RollingFile", category = "Core", elementType = "appender", printObject = true)
45 public final class RollingFileAppender extends AbstractOutputStreamAppender<RollingFileManager> {
46
47 private static final int DEFAULT_BUFFER_SIZE = 8192;
48 private static final long serialVersionUID = 1L;
49
50 private final String fileName;
51 private final String filePattern;
52 private Object advertisement;
53 private final Advertiser advertiser;
54
55
56 private RollingFileAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
57 final RollingFileManager manager, final String fileName, final String filePattern,
58 final boolean ignoreExceptions, final boolean immediateFlush, final Advertiser advertiser) {
59 super(name, layout, filter, ignoreExceptions, immediateFlush, manager);
60 if (advertiser != null) {
61 final Map<String, String> configuration = new HashMap<String, String>(layout.getContentFormat());
62 configuration.put("contentType", layout.getContentType());
63 configuration.put("name", name);
64 advertisement = advertiser.advertise(configuration);
65 }
66 this.fileName = fileName;
67 this.filePattern = filePattern;
68 this.advertiser = advertiser;
69 }
70
71 @Override
72 public void stop() {
73 super.stop();
74 if (advertiser != null) {
75 advertiser.unadvertise(advertisement);
76 }
77 }
78
79 /**
80 * Write the log entry rolling over the file when required.
81
82 * @param event The LogEvent.
83 */
84 @Override
85 public void append(final LogEvent event) {
86 getManager().checkRollover(event);
87 super.append(event);
88 }
89
90 /**
91 * Returns the File name for the Appender.
92 * @return The file name.
93 */
94 public String getFileName() {
95 return fileName;
96 }
97
98 /**
99 * Returns the file pattern used when rolling over.
100 * @return The file pattern.
101 */
102 public String getFilePattern() {
103 return filePattern;
104 }
105
106 /**
107 * Create a RollingFileAppender.
108 * @param fileName The name of the file that is actively written to. (required).
109 * @param filePattern The pattern of the file name to use on rollover. (required).
110 * @param append If true, events are appended to the file. If false, the file
111 * is overwritten when opened. Defaults to "true"
112 * @param name The name of the Appender (required).
113 * @param bufferedIO When true, I/O will be buffered. Defaults to "true".
114 * @param bufferSizeStr buffer size for buffered IO (default is 8192).
115 * @param immediateFlush When true, events are immediately flushed. Defaults to "true".
116 * @param policy The triggering policy. (required).
117 * @param strategy The rollover strategy. Defaults to DefaultRolloverStrategy.
118 * @param layout The layout to use (defaults to the default PatternLayout).
119 * @param filter The Filter or null.
120 * @param ignore If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise
121 * they are propagated to the caller.
122 * @param advertise "true" if the appender configuration should be advertised, "false" otherwise.
123 * @param advertiseURI The advertised URI which can be used to retrieve the file contents.
124 * @param config The Configuration.
125 * @return A RollingFileAppender.
126 */
127 @PluginFactory
128 public static RollingFileAppender createAppender(
129 @PluginAttribute("fileName") final String fileName,
130 @PluginAttribute("filePattern") final String filePattern,
131 @PluginAttribute("append") final String append,
132 @PluginAttribute("name") final String name,
133 @PluginAttribute("bufferedIO") final String bufferedIO,
134 @PluginAttribute("bufferSize") final String bufferSizeStr,
135 @PluginAttribute("immediateFlush") final String immediateFlush,
136 @PluginElement("Policy") final TriggeringPolicy policy,
137 @PluginElement("Strategy") RolloverStrategy strategy,
138 @PluginElement("Layout") Layout<? extends Serializable> layout,
139 @PluginElement("Filter") final Filter filter,
140 @PluginAttribute("ignoreExceptions") final String ignore,
141 @PluginAttribute("advertise") final String advertise,
142 @PluginAttribute("advertiseURI") final String advertiseURI,
143 @PluginConfiguration final Configuration config) {
144
145 final boolean isAppend = Booleans.parseBoolean(append, true);
146 final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
147 final boolean isBuffered = Booleans.parseBoolean(bufferedIO, true);
148 final boolean isFlush = Booleans.parseBoolean(immediateFlush, true);
149 final boolean isAdvertise = Boolean.parseBoolean(advertise);
150 final int bufferSize = Integers.parseInt(bufferSizeStr, DEFAULT_BUFFER_SIZE);
151 if (!isBuffered && bufferSize > 0) {
152 LOGGER.warn("The bufferSize is set to {} but bufferedIO is not true: {}", bufferSize, bufferedIO);
153 }
154 if (name == null) {
155 LOGGER.error("No name provided for FileAppender");
156 return null;
157 }
158
159 if (fileName == null) {
160 LOGGER.error("No filename was provided for FileAppender with name " + name);
161 return null;
162 }
163
164 if (filePattern == null) {
165 LOGGER.error("No filename pattern provided for FileAppender with name " + name);
166 return null;
167 }
168
169 if (policy == null) {
170 LOGGER.error("A TriggeringPolicy must be provided");
171 return null;
172 }
173
174 if (strategy == null) {
175 strategy = DefaultRolloverStrategy.createStrategy(null, null, null,
176 String.valueOf(Deflater.DEFAULT_COMPRESSION), config);
177 }
178
179 if (layout == null) {
180 layout = PatternLayout.createDefaultLayout();
181 }
182
183 final RollingFileManager manager = RollingFileManager.getFileManager(fileName, filePattern, isAppend,
184 isBuffered, policy, strategy, advertiseURI, layout, bufferSize);
185 if (manager == null) {
186 return null;
187 }
188
189 return new RollingFileAppender(name, layout, filter, manager, fileName, filePattern,
190 ignoreExceptions, isFlush, isAdvertise ? config.getAdvertiser() : null);
191 }
192 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.appender;
17
18 import java.io.Serializable;
19 import java.util.HashMap;
20 import java.util.Map;
21 import java.util.zip.Deflater;
22
23 import org.apache.logging.log4j.core.Filter;
24 import org.apache.logging.log4j.core.Layout;
25 import org.apache.logging.log4j.core.LogEvent;
26 import org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy;
27 import org.apache.logging.log4j.core.appender.rolling.RollingFileManager;
28 import org.apache.logging.log4j.core.appender.rolling.RolloverStrategy;
29 import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
30 import org.apache.logging.log4j.core.config.Configuration;
31 import org.apache.logging.log4j.core.config.plugins.Plugin;
32 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
33 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
34 import org.apache.logging.log4j.core.config.plugins.PluginElement;
35 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
36 import org.apache.logging.log4j.core.layout.PatternLayout;
37 import org.apache.logging.log4j.core.net.Advertiser;
38 import org.apache.logging.log4j.core.util.Booleans;
39 import org.apache.logging.log4j.core.util.Integers;
40
41 /**
42 * An appender that writes to files and can roll over at intervals.
43 */
44 @Plugin(name = "RollingFile", category = "Core", elementType = "appender", printObject = true)
45 public final class RollingFileAppender extends AbstractOutputStreamAppender<RollingFileManager> {
46
47 private static final int DEFAULT_BUFFER_SIZE = 8192;
48 private static final long serialVersionUID = 1L;
49
50 private final String fileName;
51 private final String filePattern;
52 private Object advertisement;
53 private final Advertiser advertiser;
54
55
56 private RollingFileAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
57 final RollingFileManager manager, final String fileName, final String filePattern,
58 final boolean ignoreExceptions, final boolean immediateFlush, final Advertiser advertiser) {
59 super(name, layout, filter, ignoreExceptions, immediateFlush, manager);
60 if (advertiser != null) {
61 final Map<String, String> configuration = new HashMap<>(layout.getContentFormat());
62 configuration.put("contentType", layout.getContentType());
63 configuration.put("name", name);
64 advertisement = advertiser.advertise(configuration);
65 }
66 this.fileName = fileName;
67 this.filePattern = filePattern;
68 this.advertiser = advertiser;
69 }
70
71 @Override
72 public void stop() {
73 super.stop();
74 if (advertiser != null) {
75 advertiser.unadvertise(advertisement);
76 }
77 }
78
79 /**
80 * Write the log entry rolling over the file when required.
81
82 * @param event The LogEvent.
83 */
84 @Override
85 public void append(final LogEvent event) {
86 getManager().checkRollover(event);
87 super.append(event);
88 }
89
90 /**
91 * Returns the File name for the Appender.
92 * @return The file name.
93 */
94 public String getFileName() {
95 return fileName;
96 }
97
98 /**
99 * Returns the file pattern used when rolling over.
100 * @return The file pattern.
101 */
102 public String getFilePattern() {
103 return filePattern;
104 }
105
106 /**
107 * Returns the triggering policy
108 * @return The TriggeringPolicy
109 */
110 public <T extends TriggeringPolicy> T getTriggeringPolicy() {
111 return getManager().getTriggeringPolicy();
112 }
113
114 /**
115 * Create a RollingFileAppender.
116 * @param fileName The name of the file that is actively written to. (required).
117 * @param filePattern The pattern of the file name to use on rollover. (required).
118 * @param append If true, events are appended to the file. If false, the file
119 * is overwritten when opened. Defaults to "true"
120 * @param name The name of the Appender (required).
121 * @param bufferedIO When true, I/O will be buffered. Defaults to "true".
122 * @param bufferSizeStr buffer size for buffered IO (default is 8192).
123 * @param immediateFlush When true, events are immediately flushed. Defaults to "true".
124 * @param policy The triggering policy. (required).
125 * @param strategy The rollover strategy. Defaults to DefaultRolloverStrategy.
126 * @param layout The layout to use (defaults to the default PatternLayout).
127 * @param filter The Filter or null.
128 * @param ignore If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise
129 * they are propagated to the caller.
130 * @param advertise "true" if the appender configuration should be advertised, "false" otherwise.
131 * @param advertiseURI The advertised URI which can be used to retrieve the file contents.
132 * @param config The Configuration.
133 * @return A RollingFileAppender.
134 */
135 @PluginFactory
136 public static RollingFileAppender createAppender(
137 @PluginAttribute("fileName") final String fileName,
138 @PluginAttribute("filePattern") final String filePattern,
139 @PluginAttribute("append") final String append,
140 @PluginAttribute("name") final String name,
141 @PluginAttribute("bufferedIO") final String bufferedIO,
142 @PluginAttribute("bufferSize") final String bufferSizeStr,
143 @PluginAttribute("immediateFlush") final String immediateFlush,
144 @PluginElement("Policy") final TriggeringPolicy policy,
145 @PluginElement("Strategy") RolloverStrategy strategy,
146 @PluginElement("Layout") Layout<? extends Serializable> layout,
147 @PluginElement("Filter") final Filter filter,
148 @PluginAttribute("ignoreExceptions") final String ignore,
149 @PluginAttribute("advertise") final String advertise,
150 @PluginAttribute("advertiseURI") final String advertiseURI,
151 @PluginConfiguration final Configuration config) {
152
153 final boolean isAppend = Booleans.parseBoolean(append, true);
154 final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
155 final boolean isBuffered = Booleans.parseBoolean(bufferedIO, true);
156 final boolean isFlush = Booleans.parseBoolean(immediateFlush, true);
157 final boolean isAdvertise = Boolean.parseBoolean(advertise);
158 final int bufferSize = Integers.parseInt(bufferSizeStr, DEFAULT_BUFFER_SIZE);
159 if (!isBuffered && bufferSize > 0) {
160 LOGGER.warn("The bufferSize is set to {} but bufferedIO is not true: {}", bufferSize, bufferedIO);
161 }
162 if (name == null) {
163 LOGGER.error("No name provided for FileAppender");
164 return null;
165 }
166
167 if (fileName == null) {
168 LOGGER.error("No filename was provided for FileAppender with name " + name);
169 return null;
170 }
171
172 if (filePattern == null) {
173 LOGGER.error("No filename pattern provided for FileAppender with name " + name);
174 return null;
175 }
176
177 if (policy == null) {
178 LOGGER.error("A TriggeringPolicy must be provided");
179 return null;
180 }
181
182 if (strategy == null) {
183 strategy = DefaultRolloverStrategy.createStrategy(null, null, null,
184 String.valueOf(Deflater.DEFAULT_COMPRESSION), config);
185 }
186
187 if (layout == null) {
188 layout = PatternLayout.createDefaultLayout();
189 }
190
191 final RollingFileManager manager = RollingFileManager.getFileManager(fileName, filePattern, isAppend,
192 isBuffered, policy, strategy, advertiseURI, layout, bufferSize);
193 if (manager == null) {
194 return null;
195 }
196
197 return new RollingFileAppender(name, layout, filter, manager, fileName, filePattern,
198 ignoreExceptions, isFlush, isAdvertise ? config.getAdvertiser() : null);
199 }
200 }
5959 final boolean immediateFlush, final int bufferSize, final Advertiser advertiser) {
6060 super(name, layout, filter, ignoreExceptions, immediateFlush, manager);
6161 if (advertiser != null) {
62 final Map<String, String> configuration = new HashMap<String, String>(layout.getContentFormat());
62 final Map<String, String> configuration = new HashMap<>(layout.getContentFormat());
6363 configuration.put("contentType", layout.getContentType());
6464 configuration.put("name", name);
6565 advertisement = advertiser.advertise(configuration);
5555 final Advertiser advertiser) {
5656 super(name, layout, filter, ignoreExceptions, immediateFlush, manager);
5757 if (advertiser != null) {
58 final Map<String, String> configuration = new HashMap<String, String>(layout.getContentFormat());
58 final Map<String, String> configuration = new HashMap<>(layout.getContentFormat());
5959 configuration.putAll(manager.getContentFormat());
6060 configuration.put("contentType", layout.getContentType());
6161 configuration.put("name", name);
158158 * if the protocol cannot be handled.
159159 */
160160 protected static AbstractSocketManager createSocketManager(final String name, Protocol protocol, final String host,
161 final int port, int connectTimeoutMillis, final SslConfiguration sslConfig, final int delayMillis,
161 final int port, final int connectTimeoutMillis, final SslConfiguration sslConfig, final int delayMillis,
162162 final boolean immediateFail, final Layout<? extends Serializable> layout) {
163163 if (protocol == Protocol.TCP && sslConfig != null) {
164164 // Upgrade TCP to SSL if an SSL config is specified.
1717
1818 import java.nio.charset.Charset;
1919
20 import org.apache.logging.log4j.util.Chars;
21
2022 /**
2123 * Wrapper for messages that are formatted according to RFC 5425.
2224 */
2325 public class TlsSyslogFrame {
24 public static final char SPACE = ' ';
25
2626 private String message;
2727 private int messageLengthInBytes;
2828
5151 @Override
5252 public String toString() {
5353 final String length = Integer.toString(messageLengthInBytes);
54 return length + SPACE + message;
55 }
56
57 @Override
58 public boolean equals(final Object frame) {
59 return super.equals(frame);
54 return length + Chars.SPACE + message;
6055 }
6156
6257 public boolean equals(final TlsSyslogFrame frame) {
4242 protected AbstractDatabaseManager(final String name, final int bufferSize) {
4343 super(name);
4444 this.bufferSize = bufferSize;
45 this.buffer = new ArrayList<LogEvent>(bufferSize + 1);
45 this.buffer = new ArrayList<>(bufferSize + 1);
4646 }
4747
4848 /**
9292 * @param eventTimestamp If {@code "true"}, indicates that this column is a date-time column in which the event
9393 * timestamp should be inserted. Mutually exclusive with {@code pattern!=null} and
9494 * {@code literalValue!=null}.
95 * @param unicode If {@code "true"}, indicates that the column is a unicode String.
95 * @param unicode If {@code "true"}, indicates that the column is a Unicode String.
9696 * @param clob If {@code "true"}, indicates that the column is a character LOB (CLOB).
9797 * @return the created column config.
9898 */
122122 throw new UnsupportedOperationException();
123123 }
124124
125 // method must be present to compile on Java 7!
126 // @Override must be absent to compile on Java 6!
125 @Override
127126 @SuppressWarnings("unused")
128127 public java.util.logging.Logger getParentLogger() {
129128 throw new UnsupportedOperationException();
207207 public JdbcDatabaseManager createManager(final String name, final FactoryData data) {
208208 final StringBuilder columnPart = new StringBuilder();
209209 final StringBuilder valuePart = new StringBuilder();
210 final List<Column> columns = new ArrayList<Column>();
210 final List<Column> columns = new ArrayList<>();
211211 int i = 0;
212212 for (final ColumnConfig config : data.columnConfigs) {
213213 if (i++ > 0) {
4848 * </p>
4949 * <p>
5050 * Many of the return types of {@link LogEvent} methods (e.g., {@link StackTraceElement}, {@link Message},
51 * {@link Marker}, {@link Throwable},
52 * {@link org.apache.logging.log4j.ThreadContext.ContextStack ThreadContext.ContextStack}, and
53 * {@link Map Map&lt;String, String&gt;}) will not be recognized by the JPA provider. In conjunction with
54 * {@link javax.persistence.Convert @Convert}, you can use the converters in the
51 * {@link Marker}, {@link Throwable},
52 * {@link org.apache.logging.log4j.ThreadContext.ContextStack ThreadContext.ContextStack}, and
53 * {@link Map Map&lt;String, String&gt;}) will not be recognized by the JPA provider. In conjunction with
54 * {@link javax.persistence.Convert @Convert}, you can use the converters in the
5555 * {@link org.apache.logging.log4j.core.appender.db.jpa.converter} package to convert these types to database columns.
56 * If you want to retrieve log events from the database, you can create a true POJO entity and also use these
56 * If you want to retrieve log events from the database, you can create a true POJO entity and also use these
5757 * converters for extracting persisted values.<br>
5858 * </p>
5959 * <p>
168168 /**
169169 * A no-op mutator to satisfy JPA requirements, as this entity is write-only.
170170 *
171 * @param nanoTime Ignored.
172 */
173 @SuppressWarnings("unused")
174 public void setNanoTime(final long nanoTime) {
175 // this entity is write-only
176 }
177
178 /**
179 * A no-op mutator to satisfy JPA requirements, as this entity is write-only.
180 *
171181 * @param millis Ignored.
172182 */
173183 @SuppressWarnings("unused")
256266 private static class NullLogEvent extends AbstractLogEvent {
257267
258268 private static final long serialVersionUID = 1L;
259 // Inherits everything
269 // Inherits everything
260270 }
261271 }
3939 /**
4040 * Users of the JPA appender may want to extend this class instead of {@link AbstractLogEventWrapperEntity}. This class
4141 * implements all of the required mutator methods but does not implement a mutable entity ID property. In order to
42 * create an entity based on this class, you need only create two constructors matching this class's
43 * constructors, annotate the class {@link javax.persistence.Entity @Entity} and {@link javax.persistence.Table @Table},
44 * and implement the fully mutable entity ID property annotated with {@link javax.persistence.Id @Id} and
42 * create an entity based on this class, you need only create two constructors matching this class's constructors,
43 * annotate the class {@link javax.persistence.Entity @Entity} and {@link javax.persistence.Table @Table}, and implement
44 * the fully mutable entity ID property annotated with {@link javax.persistence.Id @Id} and
4545 * {@link javax.persistence.GeneratedValue @GeneratedValue} to tell the JPA provider how to calculate an ID for new
4646 * events.<br>
4747 * <br>
7272 * signature. The no-argument constructor is required for a standards-compliant JPA provider to accept this as an
7373 * entity.
7474 */
75 @SuppressWarnings("unused")
7675 public BasicLogEventEntity() {
7776 super();
7877 }
169168 }
170169
171170 /**
171 * Returns the value of the running Java Virtual Machine's high-resolution time source when this event was created,
172 * or a dummy value if it is known that this value will not be used downstream.
173 *
174 * @return the JVM nano time
175 */
176 @Override
177 @Basic
178 public long getNanoTime() {
179 return this.getWrappedEvent().getNanoTime();
180 }
181
182 /**
172183 * Gets the exception logged. Annotated with {@code @Convert(converter = ThrowableAttributeConverter.class)}.
173184 *
174185 * @return the exception logged.
100100 throwableClassName = firstLine;
101101 }
102102
103 final List<StackTraceElement> stackTrace = new ArrayList<StackTraceElement>();
103 final List<StackTraceElement> stackTrace = new ArrayList<>();
104104 Throwable cause = null;
105105 while (lines.hasNext()) {
106106 final String line = lines.next();
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.appender.mom.jeromq;
18
19 import java.io.Serializable;
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.List;
23
24 import org.apache.logging.log4j.Logger;
25 import org.apache.logging.log4j.core.Filter;
26 import org.apache.logging.log4j.core.Layout;
27 import org.apache.logging.log4j.core.LogEvent;
28 import org.apache.logging.log4j.core.appender.AbstractAppender;
29 import org.apache.logging.log4j.core.config.Property;
30 import org.apache.logging.log4j.core.config.plugins.Plugin;
31 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
32 import org.apache.logging.log4j.core.config.plugins.PluginElement;
33 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
34 import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
35 import org.apache.logging.log4j.core.layout.PatternLayout;
36 import org.apache.logging.log4j.status.StatusLogger;
37 import org.apache.logging.log4j.util.PropertiesUtil;
38 import org.apache.logging.log4j.util.Strings;
39 import org.zeromq.ZMQ;
40 import org.zeromq.ZMQ.Socket;
41
42 /**
43 * Sends log events to one or more ZeroMQ (JeroMQ) endpoints.
44 * <p>
45 * Requires the JeroMQ jar (LGPL as of 0.3.5)
46 * </p>
47 */
48 // TODO
49 // Some methods are synchronized because a ZMQ.Socket is not thread-safe
50 // Using a ThreadLocal for the publisher hangs tests on shutdown. There must be
51 // some issue on threads owning certain resources as opposed to others.
52 @Plugin(name = "JeroMQ", category = "Core", elementType = "appender", printObject = true)
53 public final class JeroMqAppender extends AbstractAppender {
54
55 // Per ZMQ docs, there should usually only be one ZMQ context per process.
56 private static volatile ZMQ.Context context;
57
58 private static final int DEFAULT_BACKLOG = 100;
59
60 private static final int DEFAULT_IVL = 100;
61
62 private static final int DEFAULT_RCV_HWM = 1000;
63
64 private static final int DEFAULT_SND_HWM = 1000;
65
66 private static Logger logger;
67
68 // ZMQ sockets are not thread safe.
69 private static ZMQ.Socket publisher;
70
71 private static final long serialVersionUID = 1L;
72
73 private static final String SIMPLE_NAME = JeroMqAppender.class.getSimpleName();
74
75 static final String SYS_PROPERTY_ENABLE_SHUTDOWN_HOOK = "log4j.jeromq.enableShutdownHook";
76
77 static final String SYS_PROPERTY_IO_THREADS = "log4j.jeromq.ioThreads";
78
79 static {
80 logger = StatusLogger.getLogger();
81 final PropertiesUtil managerProps = PropertiesUtil.getProperties();
82 final Integer ioThreads = managerProps.getIntegerProperty(SYS_PROPERTY_IO_THREADS, 1);
83 final Boolean enableShutdownHook = managerProps.getBooleanProperty(SYS_PROPERTY_ENABLE_SHUTDOWN_HOOK, true);
84 final String simpleName = SIMPLE_NAME;
85 logger.trace("{} using ZMQ version {}", simpleName, ZMQ.getVersionString());
86 logger.trace("{} creating ZMQ context with ioThreads={}", simpleName, ioThreads);
87 context = ZMQ.context(ioThreads);
88 logger.trace("{} created ZMQ context {}", simpleName, context);
89 if (enableShutdownHook) {
90 final Thread hook = new Thread(simpleName + "-shutdown") {
91 @Override
92 public void run() {
93 shutdown();
94 }
95 };
96 logger.trace("{} adding shutdown hook {}", simpleName, hook);
97 Runtime.getRuntime().addShutdownHook(hook);
98 }
99 }
100
101 // The ZMQ.Socket class has other set methods that we do not cover because
102 // they throw unsupported operation exceptions.
103 @PluginFactory
104 public static JeroMqAppender createAppender(
105 // @formatter:off
106 @Required(message = "No name provided for JeroMqAppender") @PluginAttribute("name") final String name,
107 @PluginElement("Layout") Layout<?> layout,
108 @PluginElement("Filters") final Filter filter,
109 @PluginElement("Properties") final Property[] properties,
110 // Super attributes
111 @PluginAttribute("ignoreExceptions") final boolean ignoreExceptions,
112 // ZMQ attributes; defaults picked from zmq.Options.
113 @PluginAttribute(value = "affinity", defaultLong = 0) final long affinity,
114 @PluginAttribute(value = "backlog", defaultLong = DEFAULT_BACKLOG) final long backlog,
115 @PluginAttribute(value = "delayAttachOnConnect", defaultBoolean = false) final boolean delayAttachOnConnect,
116 @PluginAttribute(value = "identity") final byte[] identity,
117 @PluginAttribute(value = "ipv4Only", defaultBoolean = true) final boolean ipv4Only,
118 @PluginAttribute(value = "linger", defaultLong = -1) final long linger,
119 @PluginAttribute(value = "maxMsgSize", defaultLong = -1) final long maxMsgSize,
120 @PluginAttribute(value = "rcvHwm", defaultLong = DEFAULT_RCV_HWM) final long rcvHwm,
121 @PluginAttribute(value = "receiveBufferSize", defaultLong = 0) final long receiveBufferSize,
122 @PluginAttribute(value = "receiveTimeOut", defaultLong = -1) final int receiveTimeOut,
123 @PluginAttribute(value = "reconnectIVL", defaultLong = DEFAULT_IVL) final long reconnectIVL,
124 @PluginAttribute(value = "reconnectIVLMax", defaultLong = 0) final long reconnectIVLMax,
125 @PluginAttribute(value = "sendBufferSize", defaultLong = 0) final long sendBufferSize,
126 @PluginAttribute(value = "sendTimeOut", defaultLong = -1) final int sendTimeOut,
127 @PluginAttribute(value = "sndHwm", defaultLong = DEFAULT_SND_HWM) final long sndHwm,
128 @PluginAttribute(value = "tcpKeepAlive", defaultInt = -1) final int tcpKeepAlive,
129 @PluginAttribute(value = "tcpKeepAliveCount", defaultLong = -1) final long tcpKeepAliveCount,
130 @PluginAttribute(value = "tcpKeepAliveIdle", defaultLong = -1) final long tcpKeepAliveIdle,
131 @PluginAttribute(value = "tcpKeepAliveInterval", defaultLong = -1) final long tcpKeepAliveInterval,
132 @PluginAttribute(value = "xpubVerbose", defaultBoolean = false) final boolean xpubVerbose
133 // @formatter:on
134 ) {
135 if (layout == null) {
136 layout = PatternLayout.createDefaultLayout();
137 }
138 List<String> endpoints;
139 if (properties == null) {
140 endpoints = new ArrayList<>(0);
141 } else {
142 endpoints = new ArrayList<>(properties.length);
143 for (final Property property : properties) {
144 if ("endpoint".equalsIgnoreCase(property.getName())) {
145 final String value = property.getValue();
146 if (Strings.isNotEmpty(value)) {
147 endpoints.add(value);
148 }
149 }
150 }
151 }
152 logger.debug("Creating JeroMqAppender with name={}, filter={}, layout={}, ignoreExceptions={}, endpoints={}",
153 name, filter, layout, ignoreExceptions, endpoints);
154 return new JeroMqAppender(name, filter, layout, ignoreExceptions, endpoints, affinity, backlog,
155 delayAttachOnConnect, identity, ipv4Only, linger, maxMsgSize, rcvHwm, receiveBufferSize, receiveTimeOut,
156 reconnectIVL, reconnectIVLMax, sendBufferSize, sendTimeOut, sndHwm, tcpKeepAlive, tcpKeepAliveCount,
157 tcpKeepAliveIdle, tcpKeepAliveInterval, xpubVerbose);
158 }
159
160 static ZMQ.Context getContext() {
161 return context;
162 }
163
164 private static ZMQ.Socket getPublisher() {
165 return publisher;
166 }
167
168 private static ZMQ.Socket newPublisher() {
169 logger.trace("{} creating a new ZMQ PUB socket with context {}", SIMPLE_NAME, context);
170 final Socket socketPub = context.socket(ZMQ.PUB);
171 logger.trace("{} created new ZMQ PUB socket {}", SIMPLE_NAME, socketPub);
172 return socketPub;
173 }
174
175 static void shutdown() {
176 if (context != null) {
177 logger.trace("{} terminating JeroMQ context {}", SIMPLE_NAME, context);
178 context.term();
179 context = null;
180 }
181 }
182
183 private final long affinity;
184 private final long backlog;
185 private final boolean delayAttachOnConnect;
186 private final List<String> endpoints;
187 private final byte[] identity;
188 private final int ioThreads = 1;
189 private final boolean ipv4Only;
190 private final long linger;
191 private final long maxMsgSize;
192 private final long rcvHwm;
193 private final long receiveBufferSize;
194 private final int receiveTimeOut;
195 private final long reconnectIVL;
196 private final long reconnectIVLMax;
197 private final long sendBufferSize;
198 private int sendRcFalse;
199 private int sendRcTrue;
200 private final int sendTimeOut;
201 private final long sndHwm;
202 private final int tcpKeepAlive;
203 private final long tcpKeepAliveCount;
204 private final long tcpKeepAliveIdle;
205 private final long tcpKeepAliveInterval;
206 private final boolean xpubVerbose;
207
208 private JeroMqAppender(final String name, final Filter filter, final Layout<? extends Serializable> layout,
209 final boolean ignoreExceptions, final List<String> endpoints, final long affinity, final long backlog,
210 final boolean delayAttachOnConnect, final byte[] identity, final boolean ipv4Only, final long linger,
211 final long maxMsgSize, final long rcvHwm, final long receiveBufferSize, final int receiveTimeOut,
212 final long reconnectIVL, final long reconnectIVLMax, final long sendBufferSize, final int sendTimeOut,
213 final long sndHWM, final int tcpKeepAlive, final long tcpKeepAliveCount, final long tcpKeepAliveIdle,
214 final long tcpKeepAliveInterval, final boolean xpubVerbose) {
215 super(name, filter, layout, ignoreExceptions);
216 this.endpoints = endpoints;
217 this.affinity = affinity;
218 this.backlog = backlog;
219 this.delayAttachOnConnect = delayAttachOnConnect;
220 this.identity = identity;
221 this.ipv4Only = ipv4Only;
222 this.linger = linger;
223 this.maxMsgSize = maxMsgSize;
224 this.rcvHwm = rcvHwm;
225 this.receiveBufferSize = receiveBufferSize;
226 this.receiveTimeOut = receiveTimeOut;
227 this.reconnectIVL = reconnectIVL;
228 this.reconnectIVLMax = reconnectIVLMax;
229 this.sendBufferSize = sendBufferSize;
230 this.sendTimeOut = sendTimeOut;
231 this.sndHwm = sndHWM;
232 this.tcpKeepAlive = tcpKeepAlive;
233 this.tcpKeepAliveCount = tcpKeepAliveCount;
234 this.tcpKeepAliveIdle = tcpKeepAliveIdle;
235 this.tcpKeepAliveInterval = tcpKeepAliveInterval;
236 this.xpubVerbose = xpubVerbose;
237 }
238
239 @Override
240 public synchronized void append(final LogEvent event) {
241 final String formattedMessage = event.getMessage().getFormattedMessage();
242 if (getPublisher().send(formattedMessage, 0)) {
243 sendRcTrue++;
244 } else {
245 sendRcFalse++;
246 logger.error("Appender {} could not send message {} to JeroMQ {}", getName(), sendRcFalse,
247 formattedMessage);
248 }
249 }
250
251 // not public, handy for testing
252 int getSendRcFalse() {
253 return sendRcFalse;
254 }
255
256 // not public, handy for testing
257 int getSendRcTrue() {
258 return sendRcTrue;
259 }
260
261 // not public, handy for testing
262 void resetSendRcs() {
263 sendRcTrue = sendRcFalse = 0;
264 }
265
266 @Override
267 public synchronized void start() {
268 super.start();
269 publisher = newPublisher();
270 final String name = getName();
271 final String prefix = "JeroMQ Appender";
272 logger.debug("Starting {} {} using ZMQ version {}", prefix, name, ZMQ.getVersionString());
273 logger.debug("{} {} context {} with ioThreads={}", prefix, name, context, ioThreads);
274 //
275 final ZMQ.Socket socketPub = getPublisher();
276 logger.trace("{} {} setting {} publisher properties for instance {}", prefix, name,
277 socketPub.getClass().getName(), socketPub);
278 logger.trace("{} {} publisher setAffinity({})", prefix, name, affinity);
279 socketPub.setAffinity(affinity);
280 logger.trace("{} {} publisher setBacklog({})", prefix, name, backlog);
281 socketPub.setBacklog(backlog);
282 logger.trace("{} {} publisher setDelayAttachOnConnect({})", prefix, name, delayAttachOnConnect);
283 socketPub.setDelayAttachOnConnect(delayAttachOnConnect);
284 if (identity != null) {
285 logger.trace("{} {} publisher setIdentity({})", prefix, name, Arrays.toString(identity));
286 socketPub.setIdentity(identity);
287 }
288 logger.trace("{} {} publisher setIPv4Only({})", prefix, name, ipv4Only);
289 socketPub.setIPv4Only(ipv4Only);
290 logger.trace("{} {} publisher setLinger({})", prefix, name, linger);
291 socketPub.setLinger(linger);
292 logger.trace("{} {} publisher setMaxMsgSize({})", prefix, name, maxMsgSize);
293 socketPub.setMaxMsgSize(maxMsgSize);
294 logger.trace("{} {} publisher setRcvHWM({})", prefix, name, rcvHwm);
295 socketPub.setRcvHWM(rcvHwm);
296 logger.trace("{} {} publisher setReceiveBufferSize({})", prefix, name, receiveBufferSize);
297 socketPub.setReceiveBufferSize(receiveBufferSize);
298 logger.trace("{} {} publisher setReceiveTimeOut({})", prefix, name, receiveTimeOut);
299 socketPub.setReceiveTimeOut(receiveTimeOut);
300 logger.trace("{} {} publisher setReconnectIVL({})", prefix, name, reconnectIVL);
301 socketPub.setReconnectIVL(reconnectIVL);
302 logger.trace("{} {} publisher setReconnectIVLMax({})", prefix, name, reconnectIVLMax);
303 socketPub.setReconnectIVLMax(reconnectIVLMax);
304 logger.trace("{} {} publisher setSendBufferSize({})", prefix, name, sendBufferSize);
305 socketPub.setSendBufferSize(sendBufferSize);
306 logger.trace("{} {} publisher setSendTimeOut({})", prefix, name, sendTimeOut);
307 socketPub.setSendTimeOut(sendTimeOut);
308 logger.trace("{} {} publisher setSndHWM({})", prefix, name, sndHwm);
309 socketPub.setSndHWM(sndHwm);
310 logger.trace("{} {} publisher setTCPKeepAlive({})", prefix, name, tcpKeepAlive);
311 socketPub.setTCPKeepAlive(tcpKeepAlive);
312 logger.trace("{} {} publisher setTCPKeepAliveCount({})", prefix, name, tcpKeepAliveCount);
313 socketPub.setTCPKeepAliveCount(tcpKeepAliveCount);
314 logger.trace("{} {} publisher setTCPKeepAliveIdle({})", prefix, name, tcpKeepAliveIdle);
315 socketPub.setTCPKeepAliveIdle(tcpKeepAliveIdle);
316 logger.trace("{} {} publisher setTCPKeepAliveInterval({})", prefix, name, tcpKeepAliveInterval);
317 socketPub.setTCPKeepAliveInterval(tcpKeepAliveInterval);
318 logger.trace("{} {} publisher setXpubVerbose({})", prefix, name, xpubVerbose);
319 socketPub.setXpubVerbose(xpubVerbose);
320 //
321 if (logger.isDebugEnabled()) {
322 logger.debug(
323 "Created JeroMQ {} publisher {} type {}, affinity={}, backlog={}, delayAttachOnConnect={}, events={}, IPv4Only={}, linger={}, maxMsgSize={}, multicastHops={}, "
324 + "rate={}, rcvHWM={}, receiveBufferSize={}, receiveTimeOut={}, reconnectIVL={}, reconnectIVLMax={}, recoveryInterval={}, sendBufferSize={}, "
325 + "sendTimeOut={}, sndHWM={}, TCPKeepAlive={}, TCPKeepAliveCount={}, TCPKeepAliveIdle={}, TCPKeepAliveInterval={}, TCPKeepAliveSetting={}",
326 name, socketPub, socketPub.getType(), socketPub.getAffinity(), socketPub.getBacklog(),
327 socketPub.getDelayAttachOnConnect(), socketPub.getEvents(), socketPub.getIPv4Only(),
328 socketPub.getLinger(), socketPub.getMaxMsgSize(), socketPub.getMulticastHops(), socketPub.getRate(),
329 socketPub.getRcvHWM(), socketPub.getReceiveBufferSize(), socketPub.getReceiveTimeOut(),
330 socketPub.getReconnectIVL(), socketPub.getReconnectIVLMax(), socketPub.getRecoveryInterval(),
331 socketPub.getSendBufferSize(), socketPub.getSendTimeOut(), socketPub.getSndHWM(),
332 socketPub.getTCPKeepAlive(), socketPub.getTCPKeepAliveCount(), socketPub.getTCPKeepAliveIdle(),
333 socketPub.getTCPKeepAliveInterval(), socketPub.getTCPKeepAliveSetting());
334 }
335 for (final String endpoint : endpoints) {
336 logger.debug("Binding {} appender {} to endpoint {}", SIMPLE_NAME, name, endpoint);
337 socketPub.bind(endpoint);
338 }
339 }
340
341 @Override
342 public synchronized void stop() {
343 super.stop();
344 final Socket socketPub = getPublisher();
345 if (socketPub != null) {
346 logger.debug("Closing {} appender {} publisher {}", SIMPLE_NAME, getName(), socketPub);
347 socketPub.close();
348 publisher = null;
349 }
350 }
351
352 @Override
353 public String toString() {
354 return "JeroMqAppender [context=" + context + ", publisher=" + publisher + ", endpoints=" + endpoints + "]";
355 }
356
357 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.appender.mom.kafka;
18
19 import java.util.Properties;
20
21 import org.apache.kafka.clients.producer.KafkaProducer;
22 import org.apache.kafka.clients.producer.Producer;
23
24 public class DefaultKafkaProducerFactory implements KafkaProducerFactory {
25
26 @Override
27 public Producer<byte[], byte[]> newKafkaProducer(final Properties config) {
28 return new KafkaProducer<>(config);
29 }
30
31 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.appender.mom.kafka;
18
19 import java.io.Serializable;
20 import java.nio.charset.StandardCharsets;
21
22 import org.apache.logging.log4j.core.Filter;
23 import org.apache.logging.log4j.core.Layout;
24 import org.apache.logging.log4j.core.LogEvent;
25 import org.apache.logging.log4j.core.appender.AbstractAppender;
26 import org.apache.logging.log4j.core.appender.AppenderLoggingException;
27 import org.apache.logging.log4j.core.config.Property;
28 import org.apache.logging.log4j.core.config.plugins.Plugin;
29 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
30 import org.apache.logging.log4j.core.config.plugins.PluginElement;
31 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
32 import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
33
34 /**
35 * Sends log events to an Apache Kafka topic.
36 */
37 @Plugin(name = "Kafka", category = "Core", elementType = "appender", printObject = true)
38 public final class KafkaAppender extends AbstractAppender {
39
40 /**
41 *
42 */
43 private static final long serialVersionUID = 1L;
44 @PluginFactory
45 public static KafkaAppender createAppender(
46 @PluginElement("Layout") final Layout<? extends Serializable> layout,
47 @PluginElement("Filter") final Filter filter,
48 @Required(message = "No name provided for KafkaAppender") @PluginAttribute("name") final String name,
49 @PluginAttribute(value = "ignoreExceptions", defaultBoolean = true) final boolean ignoreExceptions,
50 @Required(message = "No topic provided for KafkaAppender") @PluginAttribute("topic") final String topic,
51 @PluginElement("Properties") final Property[] properties) {
52 final KafkaManager kafkaManager = new KafkaManager(name, topic, properties);
53 return new KafkaAppender(name, layout, filter, ignoreExceptions, kafkaManager);
54 }
55
56 private final KafkaManager manager;
57
58 private KafkaAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter, final boolean ignoreExceptions, final KafkaManager manager) {
59 super(name, filter, layout, ignoreExceptions);
60 this.manager = manager;
61 }
62
63 @Override
64 public void append(final LogEvent event) {
65 if (event.getLoggerName().startsWith("org.apache.kafka")) {
66 LOGGER.warn("Recursive logging from [{}] for appender [{}].", event.getLoggerName(), getName());
67 } else {
68 try {
69 if (getLayout() != null) {
70 manager.send(getLayout().toByteArray(event));
71 } else {
72 manager.send(event.getMessage().getFormattedMessage().getBytes(StandardCharsets.UTF_8));
73 }
74 } catch (final Exception e) {
75 LOGGER.error("Unable to write to Kafka [{}] for appender [{}].", manager.getName(), getName(), e);
76 throw new AppenderLoggingException("Unable to write to Kafka in appender: " + e.getMessage(), e);
77 }
78 }
79 }
80
81 @Override
82 public void start() {
83 super.start();
84 manager.startup();
85 }
86
87 @Override
88 public void stop() {
89 super.stop();
90 manager.release();
91 }
92
93 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.appender.mom.kafka;
18
19 import java.util.Properties;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.TimeUnit;
22 import java.util.concurrent.TimeoutException;
23
24 import org.apache.kafka.clients.producer.Producer;
25 import org.apache.kafka.clients.producer.ProducerRecord;
26 import org.apache.logging.log4j.core.appender.AbstractManager;
27 import org.apache.logging.log4j.core.config.Property;
28
29 public class KafkaManager extends AbstractManager {
30
31 public static final String DEFAULT_TIMEOUT_MILLIS = "30000";
32
33 /**
34 * package-private access for testing.
35 */
36 static KafkaProducerFactory producerFactory = new DefaultKafkaProducerFactory();
37
38 private final Properties config = new Properties();
39 private Producer<byte[], byte[]> producer = null;
40 private final int timeoutMillis;
41
42 private final String topic;
43
44 public KafkaManager(final String name, final String topic, final Property[] properties) {
45 super(name);
46 this.topic = topic;
47 config.setProperty("key.serializer", "org.apache.kafka.common.serialization.ByteArraySerializer");
48 config.setProperty("value.serializer", "org.apache.kafka.common.serialization.ByteArraySerializer");
49 config.setProperty("batch.size", "0");
50 for (final Property property : properties) {
51 config.setProperty(property.getName(), property.getValue());
52 }
53 this.timeoutMillis = Integer.parseInt(config.getProperty("timeout.ms", DEFAULT_TIMEOUT_MILLIS));
54 }
55
56 @Override
57 public void releaseSub() {
58 if (producer != null) {
59 // This thread is a workaround for this Kafka issue: https://issues.apache.org/jira/browse/KAFKA-1660
60 final Thread closeThread = new Thread(new Runnable() {
61 @Override
62 public void run() {
63 producer.close();
64 }
65 });
66 closeThread.setName("KafkaManager-CloseThread");
67 closeThread.setDaemon(true); // avoid blocking JVM shutdown
68 closeThread.start();
69 try {
70 closeThread.join(timeoutMillis);
71 } catch (final InterruptedException ignore) {
72 // ignore
73 }
74 }
75 }
76
77 public void send(final byte[] msg) throws ExecutionException, InterruptedException, TimeoutException {
78 if (producer != null) {
79 producer.send(new ProducerRecord<byte[], byte[]>(topic, msg)).get(timeoutMillis, TimeUnit.MILLISECONDS);
80 }
81 }
82
83 public void startup() {
84 producer = producerFactory.newKafkaProducer(config);
85 }
86
87 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.appender.mom.kafka;
18
19 import java.util.Properties;
20
21 import org.apache.kafka.clients.producer.Producer;
22
23 public interface KafkaProducerFactory {
24
25 Producer<byte[], byte[]> newKafkaProducer(Properties config);
26
27 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.appender.rewrite;
17
18 import java.util.HashMap;
19 import java.util.Locale;
20 import java.util.Map;
21
22 import org.apache.logging.log4j.Level;
23 import org.apache.logging.log4j.core.LogEvent;
24 import org.apache.logging.log4j.core.config.plugins.Plugin;
25 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
26 import org.apache.logging.log4j.core.config.plugins.PluginElement;
27 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
28 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
29 import org.apache.logging.log4j.core.util.KeyValuePair;
30
31 /**
32 * Rewrites log event levels for a given logger name.
33 *
34 * @since 2.4
35 */
36 @Plugin(name = "LoggerNameLevelRewritePolicy", category = "Core", elementType = "rewritePolicy", printObject = true)
37 public class LoggerNameLevelRewritePolicy implements RewritePolicy {
38
39 /**
40 * Creates a policy to rewrite levels for a given logger name.
41 *
42 * @param loggerNamePrefix
43 * The logger name prefix for events to rewrite; all event logger names that start with this string will be
44 * rewritten.
45 * @param levelPairs
46 * The levels to rewrite, the key is the source level, the value the target level.
47 * @return a new LoggerNameLevelRewritePolicy
48 */
49 @PluginFactory
50 public static LoggerNameLevelRewritePolicy createPolicy(
51 // @formatter:off
52 @PluginAttribute("logger") final String loggerNamePrefix,
53 @PluginElement("KeyValuePair") final KeyValuePair[] levelPairs) {
54 // @formatter:on
55 final Map<Level, Level> newMap = new HashMap<>(levelPairs.length);
56 for (final KeyValuePair keyValuePair : levelPairs) {
57 newMap.put(getLevel(keyValuePair.getKey()), getLevel(keyValuePair.getValue()));
58 }
59 return new LoggerNameLevelRewritePolicy(loggerNamePrefix, newMap);
60 }
61
62 private static Level getLevel(final String name) {
63 return Level.getLevel(name.toUpperCase(Locale.ROOT));
64 }
65
66 private final String loggerName;
67
68 private final Map<Level, Level> map;
69
70 private LoggerNameLevelRewritePolicy(final String loggerName, final Map<Level, Level> map) {
71 super();
72 this.loggerName = loggerName;
73 this.map = map;
74 }
75
76 @Override
77 public LogEvent rewrite(final LogEvent event) {
78 if (!event.getLoggerName().startsWith(loggerName)) {
79 return event;
80 }
81 final Level sourceLevel = event.getLevel();
82 final Level newLevel = map.get(sourceLevel);
83 if (newLevel == null || newLevel == sourceLevel) {
84 return event;
85 }
86 final LogEvent result = new Log4jLogEvent.Builder(event).setLevel(newLevel).build();
87 return result;
88 }
89
90 }
6262 return source;
6363 }
6464
65 final Map<String, String> newMap = new HashMap<String, String>(((MapMessage) msg).getData());
65 final Map<String, String> newMap = new HashMap<>(((MapMessage) msg).getData());
6666 switch (mode) {
6767 case Add: {
6868 newMap.putAll(map);
7777 }
7878 }
7979 final MapMessage message = ((MapMessage) msg).newInstance(newMap);
80 if (source instanceof Log4jLogEvent) {
81 final Log4jLogEvent event = (Log4jLogEvent) source;
82 return Log4jLogEvent.createEvent(event.getLoggerName(), event.getMarker(), event.getLoggerFqcn(),
83 event.getLevel(), message, event.getThrown(), event.getThrownProxy(), event.getContextMap(),
84 event.getContextStack(), event.getThreadName(), event.getSource(), event.getTimeMillis());
85 }
86 return new Log4jLogEvent(source.getLoggerName(), source.getMarker(), source.getLoggerFqcn(), source.getLevel(),
87 message, source.getThrown(), source.getContextMap(), source.getContextStack(), source.getThreadName(),
88 source.getSource(), source.getTimeMillis());
80 final LogEvent result = new Log4jLogEvent.Builder(source).setMessage(message).build();
81 return result;
8982 }
9083
9184 /**
130123 public static MapRewritePolicy createPolicy(
131124 @PluginAttribute("mode") final String mode,
132125 @PluginElement("KeyValuePair") final KeyValuePair[] pairs) {
133 Mode op;
134 if (mode == null) {
135 op = Mode.Add;
136 } else {
137 op = Mode.valueOf(mode);
138 if (op == null) {
139 LOGGER.error("Undefined mode " + mode);
140 return null;
141 }
142 }
126 Mode op = mode == null ? op = Mode.Add : Mode.valueOf(mode);
143127 if (pairs == null || pairs.length == 0) {
144128 LOGGER.error("keys and values must be specified for the MapRewritePolicy");
145129 return null;
146130 }
147 final Map<String, String> map = new HashMap<String, String>();
131 final Map<String, String> map = new HashMap<>();
148132 for (final KeyValuePair pair : pairs) {
149133 final String key = pair.getKey();
150134 if (key == null) {
4747
4848 private PropertiesRewritePolicy(final Configuration config, final List<Property> props) {
4949 this.config = config;
50 this.properties = new HashMap<Property, Boolean>(props.size());
50 this.properties = new HashMap<>(props.size());
5151 for (final Property property : props) {
5252 final Boolean interpolate = Boolean.valueOf(property.getValue().contains("${"));
5353 properties.put(property, interpolate);
6262 */
6363 @Override
6464 public LogEvent rewrite(final LogEvent source) {
65 final Map<String, String> props = new HashMap<String, String>(source.getContextMap());
65 final Map<String, String> props = new HashMap<>(source.getContextMap());
6666 for (final Map.Entry<Property, Boolean> entry : properties.entrySet()) {
6767 final Property prop = entry.getKey();
6868 props.put(prop.getName(), entry.getValue().booleanValue() ?
6969 config.getStrSubstitutor().replace(prop.getValue()) : prop.getValue());
7070 }
7171
72 return new Log4jLogEvent(source.getLoggerName(), source.getMarker(), source.getLoggerFqcn(), source.getLevel(),
73 source.getMessage(), source.getThrown(), props, source.getContextStack(), source.getThreadName(),
74 source.getSource(), source.getTimeMillis());
72 final LogEvent result = new Log4jLogEvent.Builder(source).setContextMap(props).build();
73 return result;
7574 }
7675
7776 @Override
4141 private static final long serialVersionUID = 1L;
4242
4343 private final Configuration config;
44 private final ConcurrentMap<String, AppenderControl> appenders = new ConcurrentHashMap<String, AppenderControl>();
44 private final ConcurrentMap<String, AppenderControl> appenders = new ConcurrentHashMap<>();
4545 private final RewritePolicy rewritePolicy;
4646 private final AppenderRef[] appenderRefs;
4747
7676 }
7777
7878 /**
79 * Modify the event and pass to the subordinate Appenders.
79 * Modifies the event and pass to the subordinate Appenders.
8080 * @param event The LogEvent.
8181 */
8282 @Override
9090 }
9191
9292 /**
93 * Create a RewriteAppender.
93 * Creates a RewriteAppender.
9494 * @param name The name of the Appender.
9595 * @param ignore If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise
9696 * they are propagated to the caller.
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.appender.rolling;
17
18 import org.apache.logging.log4j.core.LogEvent;
19 import org.apache.logging.log4j.core.config.plugins.Plugin;
20 import org.apache.logging.log4j.core.config.plugins.PluginElement;
21 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
22
23 /**
24 * Triggering policy that wraps other policies.
25 */
26 @Plugin(name = "Policies", category = "Core", printObject = true)
27 public final class CompositeTriggeringPolicy implements TriggeringPolicy {
28
29 private final TriggeringPolicy[] policies;
30
31 private CompositeTriggeringPolicy(final TriggeringPolicy... policies) {
32 this.policies = policies;
33 }
34
35 /**
36 * Initializes the policy.
37 * @param manager The RollingFileManager.
38 */
39 @Override
40 public void initialize(final RollingFileManager manager) {
41 for (final TriggeringPolicy policy : policies) {
42 policy.initialize(manager);
43 }
44 }
45
46 /**
47 * Determines if a rollover should occur.
48 * @param event A reference to the currently event.
49 * @return true if a rollover should occur, false otherwise.
50 */
51 @Override
52 public boolean isTriggeringEvent(final LogEvent event) {
53 for (final TriggeringPolicy policy : policies) {
54 if (policy.isTriggeringEvent(event)) {
55 return true;
56 }
57 }
58 return false;
59 }
60
61 @Override
62 public String toString() {
63 final StringBuilder sb = new StringBuilder("CompositeTriggeringPolicy{");
64 boolean first = true;
65 for (final TriggeringPolicy policy : policies) {
66 if (!first) {
67 sb.append(", ");
68 }
69 sb.append(policy.toString());
70 first = false;
71 }
72 sb.append('}');
73 return sb.toString();
74 }
75
76 /**
77 * Create a CompositeTriggeringPolicy.
78 * @param policies The triggering policies.
79 * @return A CompositeTriggeringPolicy.
80 */
81 @PluginFactory
82 public static CompositeTriggeringPolicy createPolicy(
83 @PluginElement("Policies") final TriggeringPolicy... policies) {
84 return new CompositeTriggeringPolicy(policies);
85 }
86 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.appender.rolling;
17
18 import java.util.Arrays;
19
20 import org.apache.logging.log4j.core.LogEvent;
21 import org.apache.logging.log4j.core.config.plugins.Plugin;
22 import org.apache.logging.log4j.core.config.plugins.PluginElement;
23 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
24
25 /**
26 * Triggering policy that wraps other policies.
27 */
28 @Plugin(name = "Policies", category = "Core", printObject = true)
29 public final class CompositeTriggeringPolicy implements TriggeringPolicy {
30
31 private final TriggeringPolicy[] policies;
32
33 private CompositeTriggeringPolicy(final TriggeringPolicy... policies) {
34 this.policies = policies;
35 }
36
37 public TriggeringPolicy[] getTriggeringPolicies() {
38 return policies;
39 }
40
41 /**
42 * Initializes the policy.
43 * @param manager The RollingFileManager.
44 */
45 @Override
46 public void initialize(final RollingFileManager manager) {
47 for (final TriggeringPolicy policy : policies) {
48 policy.initialize(manager);
49 }
50 }
51
52 /**
53 * Determines if a rollover should occur.
54 * @param event A reference to the currently event.
55 * @return true if a rollover should occur, false otherwise.
56 */
57 @Override
58 public boolean isTriggeringEvent(final LogEvent event) {
59 for (final TriggeringPolicy policy : policies) {
60 if (policy.isTriggeringEvent(event)) {
61 return true;
62 }
63 }
64 return false;
65 }
66
67 /**
68 * Create a CompositeTriggeringPolicy.
69 * @param policies The triggering policies.
70 * @return A CompositeTriggeringPolicy.
71 */
72 @PluginFactory
73 public static CompositeTriggeringPolicy createPolicy(
74 @PluginElement("Policies") final TriggeringPolicy... policies) {
75 return new CompositeTriggeringPolicy(policies);
76 }
77
78 @Override
79 public String toString() {
80 return "CompositeTriggeringPolicy(policies=" + Arrays.toString(policies) + ")";
81 }
82
83 }
1818 import java.io.File;
1919 import java.util.ArrayList;
2020 import java.util.List;
21 import java.util.Objects;
22 import java.util.concurrent.TimeUnit;
2123 import java.util.zip.Deflater;
2224
2325 import org.apache.logging.log4j.Logger;
2426 import org.apache.logging.log4j.core.appender.rolling.action.Action;
27 import org.apache.logging.log4j.core.appender.rolling.action.CommonsCompressAction;
2528 import org.apache.logging.log4j.core.appender.rolling.action.FileRenameAction;
2629 import org.apache.logging.log4j.core.appender.rolling.action.GzCompressAction;
2730 import org.apache.logging.log4j.core.appender.rolling.action.ZipCompressAction;
7679 @Plugin(name = "DefaultRolloverStrategy", category = "Core", printObject = true)
7780 public class DefaultRolloverStrategy implements RolloverStrategy {
7881
79 private static final String EXT_ZIP = ".zip";
80 private static final String EXT_GZIP = ".gz";
82 /**
83 * Enumerates over supported file extensions.
84 */
85 private enum FileExtensions {
86 ZIP(".zip") {
87 @Override
88 Action createCompressAction(final String renameTo, final String compressedName,
89 final boolean deleteSource, final int compressionLevel) {
90 return new ZipCompressAction(new File(baseName(renameTo)), new File(compressedName), deleteSource,
91 compressionLevel);
92 }
93 },
94 GZIP(".gz") {
95 @Override
96 Action createCompressAction(final String renameTo, final String compressedName,
97 final boolean deleteSource, final int compressionLevel) {
98 return new GzCompressAction(new File(baseName(renameTo)), new File(compressedName), deleteSource);
99 }
100 },
101 BZIP2(".bz2") {
102 @Override
103 Action createCompressAction(final String renameTo, final String compressedName,
104 final boolean deleteSource, final int compressionLevel) {
105 // One of "gz", "bzip2", "xz", "pack200", or "deflate".
106 return new CommonsCompressAction("bzip2", new File(baseName(renameTo)), new File(compressedName),
107 deleteSource);
108 }
109 },
110 DEFLATE(".deflate") {
111 @Override
112 Action createCompressAction(final String renameTo, final String compressedName,
113 final boolean deleteSource, final int compressionLevel) {
114 // One of "gz", "bzip2", "xz", "pack200", or "deflate".
115 return new CommonsCompressAction("deflate", new File(baseName(renameTo)), new File(compressedName),
116 deleteSource);
117 }
118 },
119 PACK200(".pack200") {
120 @Override
121 Action createCompressAction(final String renameTo, final String compressedName,
122 final boolean deleteSource, final int compressionLevel) {
123 // One of "gz", "bzip2", "xz", "pack200", or "deflate".
124 return new CommonsCompressAction("pack200", new File(baseName(renameTo)), new File(compressedName),
125 deleteSource);
126 }
127 },
128 XY(".xy") {
129 @Override
130 Action createCompressAction(final String renameTo, final String compressedName,
131 final boolean deleteSource, final int compressionLevel) {
132 // One of "gz", "bzip2", "xz", "pack200", or "deflate".
133 return new CommonsCompressAction("xy", new File(baseName(renameTo)), new File(compressedName),
134 deleteSource);
135 }
136 };
137
138 private final String extension;
139
140 private FileExtensions(final String extension) {
141 Objects.requireNonNull(extension, "extension");
142 this.extension = extension;
143 }
144
145 String getExtension() {
146 return extension;
147 }
148
149 boolean isExtensionFor(final String s) {
150 return s.endsWith(this.extension);
151 }
152
153 int length() {
154 return extension.length();
155 }
156
157 String baseName(final String name) {
158 return name.substring(0, name.length() - length());
159 }
160
161 abstract Action createCompressAction(String renameTo, String compressedName, boolean deleteSource,
162 int compressionLevel);
163 };
81164
82165 /**
83166 * Allow subclasses access to the status logger without creating another instance.
143226 * @param minIndex The minimum index.
144227 * @param maxIndex The maximum index.
145228 */
146 protected DefaultRolloverStrategy(final int minIndex, final int maxIndex, final boolean useMax, final int compressionLevel, final StrSubstitutor subst) {
229 protected DefaultRolloverStrategy(final int minIndex, final int maxIndex, final boolean useMax,
230 final int compressionLevel, final StrSubstitutor subst) {
147231 this.minIndex = minIndex;
148232 this.maxIndex = maxIndex;
149233 this.useMax = useMax;
178262 * @return true if purge was successful and rollover should be attempted.
179263 */
180264 private int purgeAscending(final int lowIndex, final int highIndex, final RollingFileManager manager) {
181 int suffixLength = 0;
182
183 final List<FileRenameAction> renames = new ArrayList<FileRenameAction>();
265 final List<FileRenameAction> renames = new ArrayList<>();
184266 final StringBuilder buf = new StringBuilder();
185267
186268 // LOG4J2-531: directory scan & rollover must use same format
187269 manager.getPatternProcessor().formatFileName(subst, buf, highIndex);
188
189270 String highFilename = subst.replace(buf);
190
191 if (highFilename.endsWith(EXT_GZIP)) {
192 suffixLength = EXT_GZIP.length();
193 } else if (highFilename.endsWith(EXT_ZIP)) {
194 suffixLength = EXT_ZIP.length();
195 }
196
271 final int suffixLength = suffixLength(highFilename);
197272 int maxIndex = 0;
198273
199274 for (int i = highIndex; i >= lowIndex; i--) {
295370 * @return true if purge was successful and rollover should be attempted.
296371 */
297372 private int purgeDescending(final int lowIndex, final int highIndex, final RollingFileManager manager) {
298 int suffixLength = 0;
299
300 final List<FileRenameAction> renames = new ArrayList<FileRenameAction>();
373 final List<FileRenameAction> renames = new ArrayList<>();
301374 final StringBuilder buf = new StringBuilder();
302375
303376 // LOG4J2-531: directory scan & rollover must use same format
304377 manager.getPatternProcessor().formatFileName(subst, buf, lowIndex);
305378
306379 String lowFilename = subst.replace(buf);
307
308 if (lowFilename.endsWith(EXT_GZIP)) {
309 suffixLength = EXT_GZIP.length();
310 } else if (lowFilename.endsWith(EXT_ZIP)) {
311 suffixLength = EXT_ZIP.length();
312 }
380 final int suffixLength = suffixLength(lowFilename);
313381
314382 for (int i = lowIndex; i <= highIndex; i++) {
315383 File toRename = new File(lowFilename);
387455 return lowIndex;
388456 }
389457
458 private int suffixLength(final String lowFilename) {
459 for (FileExtensions extension : FileExtensions.values()) {
460 if (extension.isExtensionFor(lowFilename)) {
461 return extension.length();
462 }
463 }
464 return 0;
465 }
466
390467 /**
391468 * Perform the rollover.
392469 * @param manager The RollingFileManager name for current active log file.
398475 if (maxIndex < 0) {
399476 return null;
400477 }
401 final long start = System.nanoTime();
478 final long startNanos = System.nanoTime();
402479 final int fileIndex = purge(minIndex, maxIndex, manager);
403480 if (fileIndex < 0) {
404481 return null;
405482 }
406483 if (LOGGER.isTraceEnabled()) {
407 final double duration = (System.nanoTime() - start) / (1000.0 * 1000.0 * 1000.0);
408 LOGGER.trace("DefaultRolloverStrategy.purge() took {} seconds", duration);
484 final double durationMillis = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNanos);
485 LOGGER.trace("DefaultRolloverStrategy.purge() took {} milliseconds", durationMillis);
409486 }
410487 final StringBuilder buf = new StringBuilder(255);
411488 manager.getPatternProcessor().formatFileName(subst, buf, fileIndex);
412489 final String currentFileName = manager.getFileName();
413490
414 String renameTo = buf.toString();
491 final String renameTo = buf.toString();
415492 final String compressedName = renameTo;
416493 Action compressAction = null;
417494
418 if (renameTo.endsWith(EXT_GZIP)) {
419 renameTo = renameTo.substring(0, renameTo.length() - EXT_GZIP.length());
420 compressAction = new GzCompressAction(new File(renameTo), new File(compressedName), true);
421 } else if (renameTo.endsWith(EXT_ZIP)) {
422 renameTo = renameTo.substring(0, renameTo.length() - EXT_ZIP.length());
423 compressAction = new ZipCompressAction(new File(renameTo), new File(compressedName), true,
424 compressionLevel);
495 if (FileExtensions.GZIP.isExtensionFor(renameTo)) {
496 compressAction = FileExtensions.GZIP.createCompressAction(renameTo, compressedName, true, compressionLevel);
497 } else if (FileExtensions.ZIP.isExtensionFor(renameTo)) {
498 compressAction = FileExtensions.ZIP.createCompressAction(renameTo, compressedName, true, compressionLevel);
499 } else if (FileExtensions.BZIP2.isExtensionFor(renameTo)) {
500 compressAction = FileExtensions.BZIP2.createCompressAction(renameTo, compressedName, true, compressionLevel);
425501 }
426502
427503 final FileRenameAction renameAction =
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.appender.rolling;
17
18 import java.text.SimpleDateFormat;
19 import java.util.ArrayList;
20 import java.util.Calendar;
21 import java.util.Date;
22 import java.util.List;
23
24 import org.apache.logging.log4j.Logger;
25 import org.apache.logging.log4j.core.LogEvent;
26 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
27 import org.apache.logging.log4j.core.lookup.StrSubstitutor;
28 import org.apache.logging.log4j.core.pattern.ArrayPatternConverter;
29 import org.apache.logging.log4j.core.pattern.DatePatternConverter;
30 import org.apache.logging.log4j.core.pattern.FormattingInfo;
31 import org.apache.logging.log4j.core.pattern.PatternConverter;
32 import org.apache.logging.log4j.core.pattern.PatternParser;
33 import org.apache.logging.log4j.status.StatusLogger;
34
35 /**
36 * Parse the rollover pattern.
37 */
38 public class PatternProcessor {
39
40 protected static final Logger LOGGER = StatusLogger.getLogger();
41 private static final String KEY = "FileConverter";
42
43 private static final char YEAR_CHAR = 'y';
44 private static final char MONTH_CHAR = 'M';
45 private static final char[] WEEK_CHARS = {'w', 'W'};
46 private static final char[] DAY_CHARS = {'D', 'd', 'F', 'E'};
47 private static final char[] HOUR_CHARS = {'H', 'K', 'h', 'k'};
48 private static final char MINUTE_CHAR = 'm';
49 private static final char SECOND_CHAR = 's';
50 private static final char MILLIS_CHAR = 'S';
51
52 private final ArrayPatternConverter[] patternConverters;
53 private final FormattingInfo[] patternFields;
54
55 private long prevFileTime = 0;
56 private long nextFileTime = 0;
57
58 private RolloverFrequency frequency = null;
59
60 /**
61 * Constructor.
62 * @param pattern The file pattern.
63 */
64 public PatternProcessor(final String pattern) {
65 final PatternParser parser = createPatternParser();
66 final List<PatternConverter> converters = new ArrayList<PatternConverter>();
67 final List<FormattingInfo> fields = new ArrayList<FormattingInfo>();
68 parser.parse(pattern, converters, fields, false, false);
69 final FormattingInfo[] infoArray = new FormattingInfo[fields.size()];
70 patternFields = fields.toArray(infoArray);
71 final ArrayPatternConverter[] converterArray = new ArrayPatternConverter[converters.size()];
72 patternConverters = converters.toArray(converterArray);
73
74 for (final ArrayPatternConverter converter : patternConverters) {
75 if (converter instanceof DatePatternConverter) {
76 final DatePatternConverter dateConverter = (DatePatternConverter) converter;
77 frequency = calculateFrequency(dateConverter.getPattern());
78 }
79 }
80 }
81
82 /**
83 * Returns the next potential rollover time.
84 * @param current The current time.
85 * @param increment The increment to the next time.
86 * @param modulus If true the time will be rounded to occur on a boundary aligned with the increment.
87 * @return the next potential rollover time and the timestamp for the target file.
88 */
89 public long getNextTime(final long current, final int increment, final boolean modulus) {
90 prevFileTime = nextFileTime;
91 long nextTime;
92
93 if (frequency == null) {
94 throw new IllegalStateException("Pattern does not contain a date");
95 }
96 final Calendar currentCal = Calendar.getInstance();
97 currentCal.setTimeInMillis(current);
98 final Calendar cal = Calendar.getInstance();
99 cal.set(currentCal.get(Calendar.YEAR), 0, 1, 0, 0, 0);
100 cal.set(Calendar.MILLISECOND, 0);
101 if (frequency == RolloverFrequency.ANNUALLY) {
102 increment(cal, Calendar.YEAR, increment, modulus);
103 nextTime = cal.getTimeInMillis();
104 cal.add(Calendar.YEAR, -1);
105 nextFileTime = cal.getTimeInMillis();
106 return debugGetNextTime(nextTime);
107 }
108 cal.set(Calendar.MONTH, currentCal.get(Calendar.MONTH));
109 if (frequency == RolloverFrequency.MONTHLY) {
110 increment(cal, Calendar.MONTH, increment, modulus);
111 nextTime = cal.getTimeInMillis();
112 cal.add(Calendar.MONTH, -1);
113 nextFileTime = cal.getTimeInMillis();
114 return debugGetNextTime(nextTime);
115 }
116 if (frequency == RolloverFrequency.WEEKLY) {
117 cal.set(Calendar.WEEK_OF_YEAR, currentCal.get(Calendar.WEEK_OF_YEAR));
118 increment(cal, Calendar.WEEK_OF_YEAR, increment, modulus);
119 cal.set(Calendar.DAY_OF_WEEK, currentCal.getFirstDayOfWeek());
120 nextTime = cal.getTimeInMillis();
121 cal.add(Calendar.WEEK_OF_YEAR, -1);
122 nextFileTime = cal.getTimeInMillis();
123 return debugGetNextTime(nextTime);
124 }
125 cal.set(Calendar.DAY_OF_YEAR, currentCal.get(Calendar.DAY_OF_YEAR));
126 if (frequency == RolloverFrequency.DAILY) {
127 increment(cal, Calendar.DAY_OF_YEAR, increment, modulus);
128 nextTime = cal.getTimeInMillis();
129 cal.add(Calendar.DAY_OF_YEAR, -1);
130 nextFileTime = cal.getTimeInMillis();
131 return debugGetNextTime(nextTime);
132 }
133 cal.set(Calendar.HOUR_OF_DAY, currentCal.get(Calendar.HOUR_OF_DAY));
134 if (frequency == RolloverFrequency.HOURLY) {
135 increment(cal, Calendar.HOUR_OF_DAY, increment, modulus);
136 nextTime = cal.getTimeInMillis();
137 cal.add(Calendar.HOUR_OF_DAY, -1);
138 nextFileTime = cal.getTimeInMillis();
139 return debugGetNextTime(nextTime);
140 }
141 cal.set(Calendar.MINUTE, currentCal.get(Calendar.MINUTE));
142 if (frequency == RolloverFrequency.EVERY_MINUTE) {
143 increment(cal, Calendar.MINUTE, increment, modulus);
144 nextTime = cal.getTimeInMillis();
145 cal.add(Calendar.MINUTE, -1);
146 nextFileTime = cal.getTimeInMillis();
147 return debugGetNextTime(nextTime);
148 }
149 cal.set(Calendar.SECOND, currentCal.get(Calendar.SECOND));
150 if (frequency == RolloverFrequency.EVERY_SECOND) {
151 increment(cal, Calendar.SECOND, increment, modulus);
152 nextTime = cal.getTimeInMillis();
153 cal.add(Calendar.SECOND, -1);
154 nextFileTime = cal.getTimeInMillis();
155 return debugGetNextTime(nextTime);
156 }
157 cal.set(Calendar.MILLISECOND, currentCal.get(Calendar.MILLISECOND));
158 increment(cal, Calendar.MILLISECOND, increment, modulus);
159 nextTime = cal.getTimeInMillis();
160 cal.add(Calendar.MILLISECOND, -1);
161 nextFileTime = cal.getTimeInMillis();
162 return debugGetNextTime(nextTime);
163 }
164
165 public void updateTime() {
166 prevFileTime = nextFileTime;
167 }
168
169 private long debugGetNextTime(final long nextTime) {
170 if (LOGGER.isTraceEnabled()) {
171 LOGGER.trace("PatternProcessor.getNextTime returning {}, nextFileTime={}, prevFileTime={}, current={}, freq={}", //
172 format(nextTime), format(nextFileTime), format(prevFileTime), format(System.currentTimeMillis()), frequency);
173 }
174 return nextTime;
175 }
176
177 private String format(final long time) {
178 return new SimpleDateFormat("yyyy/MM/dd-HH:mm:ss.SSS").format(new Date(time));
179 }
180
181 private void increment(final Calendar cal, final int type, final int increment, final boolean modulate) {
182 final int interval = modulate ? increment - (cal.get(type) % increment) : increment;
183 cal.add(type, interval);
184 }
185
186 /**
187 * Format file name.
188 * @param buf string buffer to which formatted file name is appended, may not be null.
189 * @param obj object to be evaluated in formatting, may not be null.
190 */
191 public final void formatFileName(final StringBuilder buf, final Object obj) {
192 final long time = prevFileTime == 0 ? System.currentTimeMillis() : prevFileTime;
193 formatFileName(buf, new Date(time), obj);
194 }
195
196 /**
197 * Format file name.
198 * @param subst The StrSubstitutor.
199 * @param buf string buffer to which formatted file name is appended, may not be null.
200 * @param obj object to be evaluated in formatting, may not be null.
201 */
202 public final void formatFileName(final StrSubstitutor subst, final StringBuilder buf, final Object obj) {
203 // LOG4J2-628: we deliberately use System time, not the log4j.Clock time
204 // for creating the file name of rolled-over files.
205 final long time = prevFileTime == 0 ? System.currentTimeMillis() : prevFileTime;
206 formatFileName(buf, new Date(time), obj);
207 final LogEvent event = new Log4jLogEvent(time);
208 final String fileName = subst.replace(event, buf);
209 buf.setLength(0);
210 buf.append(fileName);
211 }
212
213 /**
214 * Format file name.
215 * @param buf string buffer to which formatted file name is appended, may not be null.
216 * @param objects objects to be evaluated in formatting, may not be null.
217 */
218 protected final void formatFileName(final StringBuilder buf, final Object... objects) {
219 for (int i = 0; i < patternConverters.length; i++) {
220 final int fieldStart = buf.length();
221 patternConverters[i].format(buf, objects);
222
223 if (patternFields[i] != null) {
224 patternFields[i].format(fieldStart, buf);
225 }
226 }
227 }
228
229 private RolloverFrequency calculateFrequency(final String pattern) {
230 if (patternContains(pattern, MILLIS_CHAR)) {
231 return RolloverFrequency.EVERY_MILLISECOND;
232 }
233 if (patternContains(pattern, SECOND_CHAR)) {
234 return RolloverFrequency.EVERY_SECOND;
235 }
236 if (patternContains(pattern, MINUTE_CHAR)) {
237 return RolloverFrequency.EVERY_MINUTE;
238 }
239 if (patternContains(pattern, HOUR_CHARS)) {
240 return RolloverFrequency.HOURLY;
241 }
242 if (patternContains(pattern, DAY_CHARS)) {
243 return RolloverFrequency.DAILY;
244 }
245 if (patternContains(pattern, WEEK_CHARS)) {
246 return RolloverFrequency.WEEKLY;
247 }
248 if (patternContains(pattern, MONTH_CHAR)) {
249 return RolloverFrequency.MONTHLY;
250 }
251 if (patternContains(pattern, YEAR_CHAR)) {
252 return RolloverFrequency.ANNUALLY;
253 }
254 return null;
255 }
256
257 private PatternParser createPatternParser() {
258
259 return new PatternParser(null, KEY, null);
260 }
261
262 private boolean patternContains(final String pattern, final char... chars) {
263 for (final char character : chars) {
264 if (patternContains(pattern, character)) {
265 return true;
266 }
267 }
268 return false;
269 }
270
271 private boolean patternContains(final String pattern, final char character) {
272 return pattern.indexOf(character) >= 0;
273 }
274 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.appender.rolling;
17
18 import java.text.SimpleDateFormat;
19 import java.util.ArrayList;
20 import java.util.Calendar;
21 import java.util.Date;
22 import java.util.List;
23
24 import org.apache.logging.log4j.Logger;
25 import org.apache.logging.log4j.core.LogEvent;
26 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
27 import org.apache.logging.log4j.core.lookup.StrSubstitutor;
28 import org.apache.logging.log4j.core.pattern.ArrayPatternConverter;
29 import org.apache.logging.log4j.core.pattern.DatePatternConverter;
30 import org.apache.logging.log4j.core.pattern.FormattingInfo;
31 import org.apache.logging.log4j.core.pattern.PatternConverter;
32 import org.apache.logging.log4j.core.pattern.PatternParser;
33 import org.apache.logging.log4j.status.StatusLogger;
34
35 /**
36 * Parses the rollover pattern.
37 */
38 public class PatternProcessor {
39
40 protected static final Logger LOGGER = StatusLogger.getLogger();
41 private static final String KEY = "FileConverter";
42
43 private static final char YEAR_CHAR = 'y';
44 private static final char MONTH_CHAR = 'M';
45 private static final char[] WEEK_CHARS = {'w', 'W'};
46 private static final char[] DAY_CHARS = {'D', 'd', 'F', 'E'};
47 private static final char[] HOUR_CHARS = {'H', 'K', 'h', 'k'};
48 private static final char MINUTE_CHAR = 'm';
49 private static final char SECOND_CHAR = 's';
50 private static final char MILLIS_CHAR = 'S';
51
52 private final ArrayPatternConverter[] patternConverters;
53 private final FormattingInfo[] patternFields;
54
55 private long prevFileTime = 0;
56 private long nextFileTime = 0;
57
58 private RolloverFrequency frequency = null;
59
60 /**
61 * Constructor.
62 * @param pattern The file pattern.
63 */
64 public PatternProcessor(final String pattern) {
65 final PatternParser parser = createPatternParser();
66 final List<PatternConverter> converters = new ArrayList<>();
67 final List<FormattingInfo> fields = new ArrayList<>();
68 parser.parse(pattern, converters, fields, false, false);
69 final FormattingInfo[] infoArray = new FormattingInfo[fields.size()];
70 patternFields = fields.toArray(infoArray);
71 final ArrayPatternConverter[] converterArray = new ArrayPatternConverter[converters.size()];
72 patternConverters = converters.toArray(converterArray);
73
74 for (final ArrayPatternConverter converter : patternConverters) {
75 if (converter instanceof DatePatternConverter) {
76 final DatePatternConverter dateConverter = (DatePatternConverter) converter;
77 frequency = calculateFrequency(dateConverter.getPattern());
78 }
79 }
80 }
81
82 /**
83 * Returns the next potential rollover time.
84 * @param currentMillis The current time.
85 * @param increment The increment to the next time.
86 * @param modulus If true the time will be rounded to occur on a boundary aligned with the increment.
87 * @return the next potential rollover time and the timestamp for the target file.
88 */
89 public long getNextTime(final long currentMillis, final int increment, final boolean modulus) {
90 prevFileTime = nextFileTime;
91 long nextTime;
92
93 if (frequency == null) {
94 throw new IllegalStateException("Pattern does not contain a date");
95 }
96 final Calendar currentCal = Calendar.getInstance();
97 currentCal.setTimeInMillis(currentMillis);
98 final Calendar cal = Calendar.getInstance();
99 cal.set(currentCal.get(Calendar.YEAR), 0, 1, 0, 0, 0);
100 cal.set(Calendar.MILLISECOND, 0);
101 if (frequency == RolloverFrequency.ANNUALLY) {
102 increment(cal, Calendar.YEAR, increment, modulus);
103 nextTime = cal.getTimeInMillis();
104 cal.add(Calendar.YEAR, -1);
105 nextFileTime = cal.getTimeInMillis();
106 return debugGetNextTime(nextTime);
107 }
108 cal.set(Calendar.MONTH, currentCal.get(Calendar.MONTH));
109 if (frequency == RolloverFrequency.MONTHLY) {
110 increment(cal, Calendar.MONTH, increment, modulus);
111 nextTime = cal.getTimeInMillis();
112 cal.add(Calendar.MONTH, -1);
113 nextFileTime = cal.getTimeInMillis();
114 return debugGetNextTime(nextTime);
115 }
116 if (frequency == RolloverFrequency.WEEKLY) {
117 cal.set(Calendar.WEEK_OF_YEAR, currentCal.get(Calendar.WEEK_OF_YEAR));
118 increment(cal, Calendar.WEEK_OF_YEAR, increment, modulus);
119 cal.set(Calendar.DAY_OF_WEEK, currentCal.getFirstDayOfWeek());
120 nextTime = cal.getTimeInMillis();
121 cal.add(Calendar.WEEK_OF_YEAR, -1);
122 nextFileTime = cal.getTimeInMillis();
123 return debugGetNextTime(nextTime);
124 }
125 cal.set(Calendar.DAY_OF_YEAR, currentCal.get(Calendar.DAY_OF_YEAR));
126 if (frequency == RolloverFrequency.DAILY) {
127 increment(cal, Calendar.DAY_OF_YEAR, increment, modulus);
128 nextTime = cal.getTimeInMillis();
129 cal.add(Calendar.DAY_OF_YEAR, -1);
130 nextFileTime = cal.getTimeInMillis();
131 return debugGetNextTime(nextTime);
132 }
133 cal.set(Calendar.HOUR_OF_DAY, currentCal.get(Calendar.HOUR_OF_DAY));
134 if (frequency == RolloverFrequency.HOURLY) {
135 increment(cal, Calendar.HOUR_OF_DAY, increment, modulus);
136 nextTime = cal.getTimeInMillis();
137 cal.add(Calendar.HOUR_OF_DAY, -1);
138 nextFileTime = cal.getTimeInMillis();
139 return debugGetNextTime(nextTime);
140 }
141 cal.set(Calendar.MINUTE, currentCal.get(Calendar.MINUTE));
142 if (frequency == RolloverFrequency.EVERY_MINUTE) {
143 increment(cal, Calendar.MINUTE, increment, modulus);
144 nextTime = cal.getTimeInMillis();
145 cal.add(Calendar.MINUTE, -1);
146 nextFileTime = cal.getTimeInMillis();
147 return debugGetNextTime(nextTime);
148 }
149 cal.set(Calendar.SECOND, currentCal.get(Calendar.SECOND));
150 if (frequency == RolloverFrequency.EVERY_SECOND) {
151 increment(cal, Calendar.SECOND, increment, modulus);
152 nextTime = cal.getTimeInMillis();
153 cal.add(Calendar.SECOND, -1);
154 nextFileTime = cal.getTimeInMillis();
155 return debugGetNextTime(nextTime);
156 }
157 cal.set(Calendar.MILLISECOND, currentCal.get(Calendar.MILLISECOND));
158 increment(cal, Calendar.MILLISECOND, increment, modulus);
159 nextTime = cal.getTimeInMillis();
160 cal.add(Calendar.MILLISECOND, -1);
161 nextFileTime = cal.getTimeInMillis();
162 return debugGetNextTime(nextTime);
163 }
164
165 public void updateTime() {
166 prevFileTime = nextFileTime;
167 }
168
169 private long debugGetNextTime(final long nextTime) {
170 if (LOGGER.isTraceEnabled()) {
171 LOGGER.trace("PatternProcessor.getNextTime returning {}, nextFileTime={}, prevFileTime={}, current={}, freq={}", //
172 format(nextTime), format(nextFileTime), format(prevFileTime), format(System.currentTimeMillis()), frequency);
173 }
174 return nextTime;
175 }
176
177 private String format(final long time) {
178 return new SimpleDateFormat("yyyy/MM/dd-HH:mm:ss.SSS").format(new Date(time));
179 }
180
181 private void increment(final Calendar cal, final int type, final int increment, final boolean modulate) {
182 final int interval = modulate ? increment - (cal.get(type) % increment) : increment;
183 cal.add(type, interval);
184 }
185
186 /**
187 * Format file name.
188 * @param buf string buffer to which formatted file name is appended, may not be null.
189 * @param obj object to be evaluated in formatting, may not be null.
190 */
191 public final void formatFileName(final StringBuilder buf, final Object obj) {
192 final long time = prevFileTime == 0 ? System.currentTimeMillis() : prevFileTime;
193 formatFileName(buf, new Date(time), obj);
194 }
195
196 /**
197 * Formats file name.
198 * @param subst The StrSubstitutor.
199 * @param buf string buffer to which formatted file name is appended, may not be null.
200 * @param obj object to be evaluated in formatting, may not be null.
201 */
202 public final void formatFileName(final StrSubstitutor subst, final StringBuilder buf, final Object obj) {
203 // LOG4J2-628: we deliberately use System time, not the log4j.Clock time
204 // for creating the file name of rolled-over files.
205 final long time = prevFileTime == 0 ? System.currentTimeMillis() : prevFileTime;
206 formatFileName(buf, new Date(time), obj);
207 final LogEvent event = new Log4jLogEvent.Builder().setTimeMillis(time).build();
208 final String fileName = subst.replace(event, buf);
209 buf.setLength(0);
210 buf.append(fileName);
211 }
212
213 /**
214 * Formats file name.
215 * @param buf string buffer to which formatted file name is appended, may not be null.
216 * @param objects objects to be evaluated in formatting, may not be null.
217 */
218 protected final void formatFileName(final StringBuilder buf, final Object... objects) {
219 for (int i = 0; i < patternConverters.length; i++) {
220 final int fieldStart = buf.length();
221 patternConverters[i].format(buf, objects);
222
223 if (patternFields[i] != null) {
224 patternFields[i].format(fieldStart, buf);
225 }
226 }
227 }
228
229 private RolloverFrequency calculateFrequency(final String pattern) {
230 if (patternContains(pattern, MILLIS_CHAR)) {
231 return RolloverFrequency.EVERY_MILLISECOND;
232 }
233 if (patternContains(pattern, SECOND_CHAR)) {
234 return RolloverFrequency.EVERY_SECOND;
235 }
236 if (patternContains(pattern, MINUTE_CHAR)) {
237 return RolloverFrequency.EVERY_MINUTE;
238 }
239 if (patternContains(pattern, HOUR_CHARS)) {
240 return RolloverFrequency.HOURLY;
241 }
242 if (patternContains(pattern, DAY_CHARS)) {
243 return RolloverFrequency.DAILY;
244 }
245 if (patternContains(pattern, WEEK_CHARS)) {
246 return RolloverFrequency.WEEKLY;
247 }
248 if (patternContains(pattern, MONTH_CHAR)) {
249 return RolloverFrequency.MONTHLY;
250 }
251 if (patternContains(pattern, YEAR_CHAR)) {
252 return RolloverFrequency.ANNUALLY;
253 }
254 return null;
255 }
256
257 private PatternParser createPatternParser() {
258
259 return new PatternParser(null, KEY, null);
260 }
261
262 private boolean patternContains(final String pattern, final char... chars) {
263 for (final char character : chars) {
264 if (patternContains(pattern, character)) {
265 return true;
266 }
267 }
268 return false;
269 }
270
271 private boolean patternContains(final String pattern, final char character) {
272 return pattern.indexOf(character) >= 0;
273 }
274 }
4848 protected RollingFileManager(final String fileName, final String pattern, final OutputStream os,
4949 final boolean append, final long size, final long time, final TriggeringPolicy triggeringPolicy,
5050 final RolloverStrategy rolloverStrategy, final String advertiseURI,
51 final Layout<? extends Serializable> layout, final int bufferSize) {
52 super(fileName, os, append, false, advertiseURI, layout, bufferSize);
51 final Layout<? extends Serializable> layout, final int bufferSize, final boolean writeHeader) {
52 super(fileName, os, append, false, advertiseURI, layout, bufferSize, writeHeader);
5353 this.size = size;
5454 this.initialTime = time;
5555 this.triggeringPolicy = triggeringPolicy;
138138 * Returns the triggering policy
139139 * @return The TriggeringPolicy
140140 */
141 public TriggeringPolicy getTriggeringPolicy() {
142 return this.triggeringPolicy;
141 public <T extends TriggeringPolicy> T getTriggeringPolicy() {
142 // TODO We could parameterize this class with a TriggeringPolicy instead of type casting here.
143 return (T) this.triggeringPolicy;
143144 }
144145
145146 /**
309310 }
310311 final long size = data.append ? file.length() : 0;
311312
313 final boolean writeHeader = !data.append || !file.exists();
312314 OutputStream os;
313315 try {
314316 os = new FileOutputStream(name, data.append);
320322 }
321323 final long time = file.lastModified(); // LOG4J2-531 create file first so time has valid value
322324 return new RollingFileManager(name, data.pattern, os, data.append, size, time, data.policy,
323 data.strategy, data.advertiseURI, data.layout, bufferSize);
325 data.strategy, data.advertiseURI, data.layout, bufferSize, writeHeader);
324326 } catch (final FileNotFoundException ex) {
325327 LOGGER.error("FileManager (" + name + ") " + ex);
326328 }
2525 import org.apache.logging.log4j.core.Layout;
2626 import org.apache.logging.log4j.core.appender.AppenderLoggingException;
2727 import org.apache.logging.log4j.core.appender.ManagerFactory;
28 import org.apache.logging.log4j.core.util.NullOutputStream;
2829
2930 /**
3031 * Extends RollingFileManager but instead of using a buffered output stream,
4243 private final boolean isImmediateFlush;
4344 private RandomAccessFile randomAccessFile;
4445 private final ByteBuffer buffer;
45 private final ThreadLocal<Boolean> isEndOfBatch = new ThreadLocal<Boolean>();
46 private final ThreadLocal<Boolean> isEndOfBatch = new ThreadLocal<>();
4647
4748 public RollingRandomAccessFileManager(final RandomAccessFile raf, final String fileName,
4849 final String pattern, final OutputStream os, final boolean append,
4950 final boolean immediateFlush, final int bufferSize, final long size, final long time,
5051 final TriggeringPolicy policy, final RolloverStrategy strategy,
51 final String advertiseURI, final Layout<? extends Serializable> layout) {
52 super(fileName, pattern, os, append, size, time, policy, strategy, advertiseURI, layout, bufferSize);
52 final String advertiseURI, final Layout<? extends Serializable> layout, final boolean writeHeader) {
53 super(fileName, pattern, os, append, size, time, policy, strategy, advertiseURI, layout, bufferSize,
54 writeHeader);
5355 this.isImmediateFlush = immediateFlush;
5456 this.randomAccessFile = raf;
5557 isEndOfBatch.set(Boolean.FALSE);
179181 final long size = data.append ? file.length() : 0;
180182 final long time = file.exists() ? file.lastModified() : System.currentTimeMillis();
181183
184 final boolean writeHeader = !data.append || !file.exists();
182185 RandomAccessFile raf = null;
183186 try {
184187 raf = new RandomAccessFile(name, "rw");
190193 LOGGER.trace("RandomAccessFile {} set length to 0", name);
191194 raf.setLength(0);
192195 }
193 return new RollingRandomAccessFileManager(raf, name, data.pattern, new DummyOutputStream(), data.append,
194 data.immediateFlush, data.bufferSize, size, time, data.policy, data.strategy, data.advertiseURI,
195 data.layout);
196 return new RollingRandomAccessFileManager(raf, name, data.pattern, NullOutputStream.NULL_OUTPUT_STREAM,
197 data.append, data.immediateFlush, data.bufferSize, size, time, data.policy, data.strategy,
198 data.advertiseURI, data.layout, writeHeader);
196199 } catch (final IOException ex) {
197200 LOGGER.error("Cannot access RandomAccessFile {}) " + ex);
198201 if (raf != null) {
204207 }
205208 }
206209 return null;
207 }
208 }
209
210 /** {@code OutputStream} subclass that does not write anything. */
211 static class DummyOutputStream extends OutputStream {
212 @Override
213 public void write(final int b) throws IOException {
214 }
215
216 @Override
217 public void write(final byte[] b, final int off, final int len) throws IOException {
218210 }
219211 }
220212
1414 * limitations under the license.
1515 */
1616 package org.apache.logging.log4j.core.appender.rolling;
17
18 import java.util.Objects;
1719
1820 import org.apache.logging.log4j.core.appender.rolling.action.Action;
1921
5456 */
5557 public RolloverDescriptionImpl(final String activeFileName, final boolean append, final Action synchronous,
5658 final Action asynchronous) {
57 if (activeFileName == null) {
58 throw new NullPointerException("activeFileName");
59 }
59 Objects.requireNonNull(activeFileName, "activeFileName");
6060
6161 this.append = append;
6262 this.activeFileName = activeFileName;
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.appender.rolling;
17
18 import java.text.NumberFormat;
19 import java.text.ParseException;
20 import java.util.Locale;
21 import java.util.regex.Matcher;
22 import java.util.regex.Pattern;
23
24 import org.apache.logging.log4j.Logger;
25 import org.apache.logging.log4j.core.LogEvent;
26 import org.apache.logging.log4j.core.config.plugins.Plugin;
27 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
28 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
29 import org.apache.logging.log4j.status.StatusLogger;
30
31 /**
32 *
33 */
34 @Plugin(name = "SizeBasedTriggeringPolicy", category = "Core", printObject = true)
35 public class SizeBasedTriggeringPolicy implements TriggeringPolicy {
36 /**
37 * Allow subclasses access to the status logger without creating another instance.
38 */
39 protected static final Logger LOGGER = StatusLogger.getLogger();
40
41 private static final long KB = 1024;
42 private static final long MB = KB * KB;
43 private static final long GB = KB * MB;
44
45 /**
46 * Rollover threshold size in bytes.
47 */
48 private static final long MAX_FILE_SIZE = 10 * 1024 * 1024; // let 10 MB the default max size
49
50
51 /**
52 * Pattern for string parsing.
53 */
54 private static final Pattern VALUE_PATTERN =
55 Pattern.compile("([0-9]+([\\.,][0-9]+)?)\\s*(|K|M|G)B?", Pattern.CASE_INSENSITIVE);
56
57 private final long maxFileSize;
58
59 private RollingFileManager manager;
60
61 /**
62 * Constructs a new instance.
63 */
64 protected SizeBasedTriggeringPolicy() {
65 this.maxFileSize = MAX_FILE_SIZE;
66 }
67
68 /**
69 * Constructs a new instance.
70 *
71 * @param maxFileSize rollover threshold size in bytes.
72 */
73 protected SizeBasedTriggeringPolicy(final long maxFileSize) {
74 this.maxFileSize = maxFileSize;
75 }
76
77 /**
78 * Initialize the TriggeringPolicy.
79 * @param manager The RollingFileManager.
80 */
81 @Override
82 public void initialize(final RollingFileManager manager) {
83 this.manager = manager;
84 }
85
86
87 /**
88 * Returns true if a rollover should occur.
89 * @param event A reference to the currently event.
90 * @return true if a rollover should take place, false otherwise.
91 */
92 @Override
93 public boolean isTriggeringEvent(final LogEvent event) {
94 final boolean triggered = manager.getFileSize() > maxFileSize;
95 if (triggered) {
96 manager.getPatternProcessor().updateTime();
97 }
98 return triggered;
99 }
100
101 @Override
102 public String toString() {
103 return "SizeBasedTriggeringPolicy(size=" + maxFileSize + ')';
104 }
105
106 /**
107 * Create a SizeBasedTriggeringPolicy.
108 * @param size The size of the file before rollover is required.
109 * @return A SizeBasedTriggeringPolicy.
110 */
111 @PluginFactory
112 public static SizeBasedTriggeringPolicy createPolicy(@PluginAttribute("size") final String size) {
113
114 final long maxSize = size == null ? MAX_FILE_SIZE : valueOf(size);
115 return new SizeBasedTriggeringPolicy(maxSize);
116 }
117
118 /**
119 * Converts a string to a number of bytes. Strings consist of a floating point value followed by
120 * K, M, or G for kilobytes, megabytes, gigabytes, respectively. The
121 * abbreviations KB, MB, and GB are also accepted. Matching is case insensitive.
122 *
123 * @param string The string to convert
124 * @return The Bytes value for the string
125 */
126 private static long valueOf(final String string) {
127 final Matcher matcher = VALUE_PATTERN.matcher(string);
128
129 // Valid input?
130 if (matcher.matches()) {
131 try {
132 // Get double precision value
133 final long value = NumberFormat.getNumberInstance(Locale.getDefault()).parse(
134 matcher.group(1)).longValue();
135
136 // Get units specified
137 final String units = matcher.group(3);
138
139 if (units.isEmpty()) {
140 return value;
141 } else if (units.equalsIgnoreCase("K")) {
142 return value * KB;
143 } else if (units.equalsIgnoreCase("M")) {
144 return value * MB;
145 } else if (units.equalsIgnoreCase("G")) {
146 return value * GB;
147 } else {
148 LOGGER.error("Units not recognized: " + string);
149 return MAX_FILE_SIZE;
150 }
151 } catch (final ParseException e) {
152 LOGGER.error("Unable to parse numeric part: " + string, e);
153 return MAX_FILE_SIZE;
154 }
155 }
156 LOGGER.error("Unable to parse bytes: " + string);
157 return MAX_FILE_SIZE;
158 }
159 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.appender.rolling;
17
18 import java.text.NumberFormat;
19 import java.text.ParseException;
20 import java.util.Locale;
21 import java.util.regex.Matcher;
22 import java.util.regex.Pattern;
23
24 import org.apache.logging.log4j.Logger;
25 import org.apache.logging.log4j.core.LogEvent;
26 import org.apache.logging.log4j.core.config.plugins.Plugin;
27 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
28 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
29 import org.apache.logging.log4j.status.StatusLogger;
30
31 /**
32 *
33 */
34 @Plugin(name = "SizeBasedTriggeringPolicy", category = "Core", printObject = true)
35 public class SizeBasedTriggeringPolicy implements TriggeringPolicy {
36 /**
37 * Allow subclasses access to the status logger without creating another instance.
38 */
39 protected static final Logger LOGGER = StatusLogger.getLogger();
40
41 private static final long KB = 1024;
42 private static final long MB = KB * KB;
43 private static final long GB = KB * MB;
44
45 /**
46 * Rollover threshold size in bytes.
47 */
48 private static final long MAX_FILE_SIZE = 10 * 1024 * 1024; // let 10 MB the default max size
49
50
51 /**
52 * Pattern for string parsing.
53 */
54 private static final Pattern VALUE_PATTERN =
55 Pattern.compile("([0-9]+([\\.,][0-9]+)?)\\s*(|K|M|G)B?", Pattern.CASE_INSENSITIVE);
56
57 private final long maxFileSize;
58
59 private RollingFileManager manager;
60
61 /**
62 * Constructs a new instance.
63 */
64 protected SizeBasedTriggeringPolicy() {
65 this.maxFileSize = MAX_FILE_SIZE;
66 }
67
68 /**
69 * Constructs a new instance.
70 *
71 * @param maxFileSize rollover threshold size in bytes.
72 */
73 protected SizeBasedTriggeringPolicy(final long maxFileSize) {
74 this.maxFileSize = maxFileSize;
75 }
76
77 public long getMaxFileSize() {
78 return maxFileSize;
79 }
80
81 /**
82 * Initialize the TriggeringPolicy.
83 * @param manager The RollingFileManager.
84 */
85 @Override
86 public void initialize(final RollingFileManager manager) {
87 this.manager = manager;
88 }
89
90
91 /**
92 * Returns true if a rollover should occur.
93 * @param event A reference to the currently event.
94 * @return true if a rollover should take place, false otherwise.
95 */
96 @Override
97 public boolean isTriggeringEvent(final LogEvent event) {
98 final boolean triggered = manager.getFileSize() > maxFileSize;
99 if (triggered) {
100 manager.getPatternProcessor().updateTime();
101 }
102 return triggered;
103 }
104
105 @Override
106 public String toString() {
107 return "SizeBasedTriggeringPolicy(size=" + maxFileSize + ')';
108 }
109
110 /**
111 * Create a SizeBasedTriggeringPolicy.
112 * @param size The size of the file before rollover is required.
113 * @return A SizeBasedTriggeringPolicy.
114 */
115 @PluginFactory
116 public static SizeBasedTriggeringPolicy createPolicy(@PluginAttribute("size") final String size) {
117
118 final long maxSize = size == null ? MAX_FILE_SIZE : valueOf(size);
119 return new SizeBasedTriggeringPolicy(maxSize);
120 }
121
122 /**
123 * Converts a string to a number of bytes. Strings consist of a floating point value followed by
124 * K, M, or G for kilobytes, megabytes, gigabytes, respectively. The
125 * abbreviations KB, MB, and GB are also accepted. Matching is case insensitive.
126 *
127 * @param string The string to convert
128 * @return The Bytes value for the string
129 */
130 private static long valueOf(final String string) {
131 final Matcher matcher = VALUE_PATTERN.matcher(string);
132
133 // Valid input?
134 if (matcher.matches()) {
135 try {
136 // Get double precision value
137 final long value = NumberFormat.getNumberInstance(Locale.getDefault()).parse(
138 matcher.group(1)).longValue();
139
140 // Get units specified
141 final String units = matcher.group(3);
142
143 if (units.isEmpty()) {
144 return value;
145 } else if (units.equalsIgnoreCase("K")) {
146 return value * KB;
147 } else if (units.equalsIgnoreCase("M")) {
148 return value * MB;
149 } else if (units.equalsIgnoreCase("G")) {
150 return value * GB;
151 } else {
152 LOGGER.error("Units not recognized: " + string);
153 return MAX_FILE_SIZE;
154 }
155 } catch (final ParseException e) {
156 LOGGER.error("Unable to parse numeric part: " + string, e);
157 return MAX_FILE_SIZE;
158 }
159 }
160 LOGGER.error("Unable to parse bytes: " + string);
161 return MAX_FILE_SIZE;
162 }
163
164 }
2222 import org.apache.logging.log4j.core.util.Integers;
2323
2424 /**
25 * Triggering Policy that causes a rollover based on time.
25 * Rolls a file over based on time.
2626 */
2727 @Plugin(name = "TimeBasedTriggeringPolicy", category = "Core", printObject = true)
2828 public final class TimeBasedTriggeringPolicy implements TriggeringPolicy {
2929
30 private long nextRollover;
30 private long nextRolloverMillis;
3131 private final int interval;
3232 private final boolean modulate;
3333
3838 this.modulate = modulate;
3939 }
4040
41 public int getInterval() {
42 return interval;
43 }
44
45 public long getNextRolloverMillis() {
46 return nextRolloverMillis;
47 }
48
4149 /**
42 * Initialize the policy.
50 * Initializes the policy.
4351 * @param manager The RollingFileManager.
4452 */
4553 @Override
4957 // LOG4J2-531: call getNextTime twice to force initialization of both prevFileTime and nextFileTime
5058 manager.getPatternProcessor().getNextTime(manager.getFileTime(), interval, modulate);
5159
52 nextRollover = manager.getPatternProcessor().getNextTime(manager.getFileTime(), interval, modulate);
60 nextRolloverMillis = manager.getPatternProcessor().getNextTime(manager.getFileTime(), interval, modulate);
5361 }
5462
5563 /**
56 * Determine whether a rollover should occur.
64 * Determines whether a rollover should occur.
5765 * @param event A reference to the currently event.
5866 * @return true if a rollover should occur.
5967 */
6270 if (manager.getFileSize() == 0) {
6371 return false;
6472 }
65 final long now = event.getTimeMillis();
66 if (now > nextRollover) {
67 nextRollover = manager.getPatternProcessor().getNextTime(now, interval, modulate);
73 final long nowMillis = event.getTimeMillis();
74 if (nowMillis > nextRolloverMillis) {
75 nextRolloverMillis = manager.getPatternProcessor().getNextTime(nowMillis, interval, modulate);
6876 return true;
6977 }
7078 return false;
7179 }
7280
73 @Override
74 public String toString() {
75 return "TimeBasedTriggeringPolicy";
76 }
77
7881 /**
79 * Create a TimeBasedTriggeringPolicy.
82 * Creates a TimeBasedTriggeringPolicy.
8083 * @param interval The interval between rollovers.
8184 * @param modulate If true the time will be rounded to occur on a boundary aligned with the increment.
8285 * @return a TimeBasedTriggeringPolicy.
8992 final boolean mod = Boolean.parseBoolean(modulate);
9093 return new TimeBasedTriggeringPolicy(increment, mod);
9194 }
95
96 @Override
97 public String toString() {
98 return "TimeBasedTriggeringPolicy(nextRolloverMillis=" + nextRolloverMillis + ", interval=" + interval
99 + ", modulate=" + modulate + ")";
100 }
101
92102 }
2525 * Abstract base class for implementations of Action.
2626 */
2727 public abstract class AbstractAction implements Action {
28
2829 /**
29 * Allow subclasses access to the status logger without creating another instance.
30 * Allows subclasses access to the status logger without creating another instance.
3031 */
3132 protected static final Logger LOGGER = StatusLogger.getLogger();
3233 /**
4647 }
4748
4849 /**
49 * Perform action.
50 * Performs action.
5051 *
5152 * @return true if successful.
5253 * @throws IOException if IO error.
9091 }
9192
9293 /**
93 * Capture exception.
94 * Captures exception.
9495 *
9596 * @param ex exception.
9697 */
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.appender.rolling.action;
17
18 import java.io.BufferedOutputStream;
19 import java.io.File;
20 import java.io.FileInputStream;
21 import java.io.FileOutputStream;
22 import java.io.IOException;
23 import java.util.Objects;
24
25 import org.apache.commons.compress.compressors.CompressorException;
26 import org.apache.commons.compress.compressors.CompressorStreamFactory;
27 import org.apache.commons.compress.utils.IOUtils;
28
29 /**
30 * Compresses a file using bzip2 compression.
31 */
32 public final class CommonsCompressAction extends AbstractAction {
33
34 private static final int BUF_SIZE = 8102;
35
36 /**
37 * Compressor name. One of "gz", "bzip2", "xz", "pack200", or "deflate".
38 */
39 private final String name;
40
41 /**
42 * Source file.
43 */
44 private final File source;
45
46 /**
47 * Destination file.
48 */
49 private final File destination;
50
51 /**
52 * If true, attempt to delete file on completion.
53 */
54 private final boolean deleteSource;
55
56 /**
57 * Creates new instance of Bzip2CompressAction.
58 * @param name the compressor name. One of "gz", "bzip2", "xz", "pack200", or "deflate".
59 * @param source file to compress, may not be null.
60 * @param destination compressed file, may not be null.
61 * @param deleteSource if true, attempt to delete file on completion. Failure to delete does not cause an exception
62 * to be thrown or affect return value.
63 */
64 public CommonsCompressAction(final String name, final File source, final File destination, final boolean deleteSource) {
65 Objects.requireNonNull(source, "source");
66 Objects.requireNonNull(destination, "destination");
67 this.name = name;
68 this.source = source;
69 this.destination = destination;
70 this.deleteSource = deleteSource;
71 }
72
73 /**
74 * Compresses.
75 *
76 * @return true if successfully compressed.
77 * @throws IOException on IO exception.
78 */
79 @Override
80 public boolean execute() throws IOException {
81 return execute(name, source, destination, deleteSource);
82 }
83
84 /**
85 * Compresses a file.
86 * @param name the compressor name, i.e. "gz", "bzip2", "xz", "pack200", or "deflate".
87 * @param source file to compress, may not be null.
88 * @param destination compressed file, may not be null.
89 * @param deleteSource if true, attempt to delete file on completion. Failure to delete does not cause an exception
90 * to be thrown or affect return value.
91 *
92 * @return true if source file compressed.
93 * @throws IOException on IO exception.
94 */
95 public static boolean execute(final String name, final File source, final File destination, final boolean deleteSource)
96 throws IOException {
97 if (!source.exists()) {
98 return false;
99 }
100 try (final FileInputStream input = new FileInputStream(source);
101 final BufferedOutputStream output = new BufferedOutputStream(new CompressorStreamFactory()
102 .createCompressorOutputStream(name, new FileOutputStream(destination)))) {
103 IOUtils.copy(input, output, BUF_SIZE);
104 } catch (final CompressorException e) {
105 throw new IOException(e);
106 }
107
108 if (deleteSource && !source.delete()) {
109 LOGGER.warn("Unable to delete " + source.toString() + '.');
110 }
111 return true;
112 }
113
114 /**
115 * Reports exception.
116 *
117 * @param ex exception.
118 */
119 @Override
120 protected void reportException(final Exception ex) {
121 LOGGER.warn("Exception during " + name + " compression of '" + source.toString() + "'.", ex);
122 }
123
124 @Override
125 public String toString() {
126 return CommonsCompressAction.class.getSimpleName() + '[' + source + " to " + destination //
127 + ", deleteSource=" + deleteSource + ']';
128 }
129 }
1616 package org.apache.logging.log4j.core.appender.rolling.action;
1717
1818 import java.io.File;
19 import java.io.FileInputStream;
20 import java.io.FileOutputStream;
2119 import java.io.IOException;
22 import java.nio.channels.FileChannel;
20 import java.nio.file.Files;
2321
2422 /**
2523 * File rename action.
120118 if (!destination.exists()) {
121119 destination.createNewFile();
122120 }
123
124 FileChannel srcChannel = null;
125 FileChannel destChannel = null;
126 FileInputStream srcStream = null;
127 FileOutputStream destStream = null;
128 try {
129 srcStream = new FileInputStream(source);
130 destStream = new FileOutputStream(destination);
131 srcChannel = srcStream.getChannel();
132 destChannel = destStream.getChannel();
133 destChannel.transferFrom(srcChannel, 0, srcChannel.size());
134 } finally {
135 if (srcChannel != null) {
136 srcChannel.close();
137 }
138 if (srcStream != null) {
139 srcStream.close();
140 }
141 if (destChannel != null) {
142 destChannel.close();
143 }
144 if (destStream != null) {
145 destStream.close();
146 }
147 }
121 Files.copy(source.toPath(), destination.toPath());
148122 }
149123
150124 @Override
2020 import java.io.FileInputStream;
2121 import java.io.FileOutputStream;
2222 import java.io.IOException;
23 import java.util.Objects;
2324 import java.util.zip.GZIPOutputStream;
2425
2526 /**
5354 * does not cause an exception to be thrown or affect return value.
5455 */
5556 public GzCompressAction(final File source, final File destination, final boolean deleteSource) {
56 if (source == null) {
57 throw new NullPointerException("source");
58 }
59
60 if (destination == null) {
61 throw new NullPointerException("destination");
62 }
57 Objects.requireNonNull(source, "source");
58 Objects.requireNonNull(destination, "destination");
6359
6460 this.source = source;
6561 this.destination = destination;
8884 * @throws IOException on IO exception.
8985 */
9086 public static boolean execute(final File source, final File destination, final boolean deleteSource)
91 throws IOException {
87 throws IOException {
9288 if (source.exists()) {
93 final FileInputStream fis = new FileInputStream(source);
94 final FileOutputStream fos = new FileOutputStream(destination);
95 final GZIPOutputStream gzos = new GZIPOutputStream(fos);
96 final BufferedOutputStream os = new BufferedOutputStream(gzos);
97 final byte[] inbuf = new byte[BUF_SIZE];
98 int n;
89 try (final FileInputStream fis = new FileInputStream(source);
90 final BufferedOutputStream os = new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream(
91 destination)))) {
92 final byte[] inbuf = new byte[BUF_SIZE];
93 int n;
9994
100 while ((n = fis.read(inbuf)) != -1) {
101 os.write(inbuf, 0, n);
95 while ((n = fis.read(inbuf)) != -1) {
96 os.write(inbuf, 0, n);
97 }
10298 }
103
104 os.close();
105 fis.close();
10699
107100 if (deleteSource && !source.delete()) {
108101 LOGGER.warn("Unable to delete " + source.toString() + '.');
1919 import java.io.FileInputStream;
2020 import java.io.FileOutputStream;
2121 import java.io.IOException;
22 import java.util.Objects;
2223 import java.util.zip.ZipEntry;
2324 import java.util.zip.ZipOutputStream;
2425
4142 private final File destination;
4243
4344 /**
44 * If true, attempt to delete file on completion.
45 * If true, attempts to delete file on completion.
4546 */
4647 private final boolean deleteSource;
4748
5152 private final int level;
5253
5354 /**
54 * Create new instance of GzCompressAction.
55 * Creates new instance of GzCompressAction.
5556 *
5657 * @param source file to compress, may not be null.
5758 * @param destination compressed file, may not be null.
6061 * @param level TODO
6162 */
6263 public ZipCompressAction(final File source, final File destination, final boolean deleteSource, final int level) {
63 if (source == null) {
64 throw new NullPointerException("source");
65 }
66
67 if (destination == null) {
68 throw new NullPointerException("destination");
69 }
64 Objects.requireNonNull(source, "source");
65 Objects.requireNonNull(destination, "destination");
7066
7167 this.source = source;
7268 this.destination = destination;
7571 }
7672
7773 /**
78 * Compress.
74 * Compresses.
7975 *
8076 * @return true if successfully compressed.
8177 * @throws IOException on IO exception.
8682 }
8783
8884 /**
89 * Compress a file.
85 * Compresses a file.
9086 *
9187 * @param source file to compress, may not be null.
9288 * @param destination compressed file, may not be null.
9793 * @throws IOException on IO exception.
9894 */
9995 public static boolean execute(final File source, final File destination, final boolean deleteSource, final int level)
100 throws IOException {
96 throws IOException {
10197 if (source.exists()) {
102 final FileInputStream fis = new FileInputStream(source);
103 final FileOutputStream fos = new FileOutputStream(destination);
104 final ZipOutputStream zos = new ZipOutputStream(fos);
105 zos.setLevel(level);
98 try (final FileInputStream fis = new FileInputStream(source);
99 final ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(destination))) {
100 zos.setLevel(level);
106101
107 final ZipEntry zipEntry = new ZipEntry(source.getName());
108 zos.putNextEntry(zipEntry);
102 final ZipEntry zipEntry = new ZipEntry(source.getName());
103 zos.putNextEntry(zipEntry);
109104
110 final byte[] inbuf = new byte[BUF_SIZE];
111 int n;
105 final byte[] inbuf = new byte[BUF_SIZE];
106 int n;
112107
113 while ((n = fis.read(inbuf)) != -1) {
114 zos.write(inbuf, 0, n);
108 while ((n = fis.read(inbuf)) != -1) {
109 zos.write(inbuf, 0, n);
110 }
115111 }
116
117 zos.close();
118 fis.close();
119112
120113 if (deleteSource && !source.delete()) {
121114 LOGGER.warn("Unable to delete " + source.toString() + '.');
128121 }
129122
130123 /**
131 * Capture exception.
124 * Captures exception.
132125 *
133126 * @param ex exception.
134127 */
4949 private final Routes routes;
5050 private final Route defaultRoute;
5151 private final Configuration config;
52 private final ConcurrentMap<String, AppenderControl> appenders =
53 new ConcurrentHashMap<String, AppenderControl>();
52 private final ConcurrentMap<String, AppenderControl> appenders = new ConcurrentHashMap<>();
5453 private final RewritePolicy rewritePolicy;
5554
5655 private RoutingAppender(final String name, final Filter filter, final boolean ignoreExceptions, final Routes routes,
1616 package org.apache.logging.log4j.core.async;
1717
1818 import java.util.Map;
19 import java.util.Objects;
1920 import java.util.concurrent.ExecutorService;
2021 import java.util.concurrent.Executors;
2122
2526 import org.apache.logging.log4j.core.Logger;
2627 import org.apache.logging.log4j.core.LoggerContext;
2728 import org.apache.logging.log4j.core.config.Property;
29 import org.apache.logging.log4j.core.config.ReliabilityStrategy;
2830 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
2931 import org.apache.logging.log4j.core.jmx.RingBufferAdmin;
3032 import org.apache.logging.log4j.core.util.Clock;
3133 import org.apache.logging.log4j.core.util.ClockFactory;
34 import org.apache.logging.log4j.core.util.DummyNanoClock;
3235 import org.apache.logging.log4j.core.util.Integers;
3336 import org.apache.logging.log4j.core.util.Loader;
37 import org.apache.logging.log4j.core.util.NanoClock;
3438 import org.apache.logging.log4j.message.Message;
3539 import org.apache.logging.log4j.message.MessageFactory;
3640 import org.apache.logging.log4j.message.TimestampMessage;
3741 import org.apache.logging.log4j.status.StatusLogger;
42 import org.apache.logging.log4j.util.PropertiesUtil;
3843
3944 import com.lmax.disruptor.BlockingWaitStrategy;
4045 import com.lmax.disruptor.ExceptionHandler;
8186 private static final int RINGBUFFER_DEFAULT_SIZE = 256 * 1024;
8287 private static final StatusLogger LOGGER = StatusLogger.getLogger();
8388 private static final ThreadNameStrategy THREAD_NAME_STRATEGY = ThreadNameStrategy.create();
84 private static final ThreadLocal<Info> threadlocalInfo = new ThreadLocal<Info>();
8589
8690 static enum ThreadNameStrategy { // LOG4J2-467
8791 CACHED {
99103 abstract String getThreadName(Info info);
100104
101105 static ThreadNameStrategy create() {
102 final String name = System.getProperty("AsyncLogger.ThreadNameStrategy", CACHED.name());
106 final String name = PropertiesUtil.getProperties().getStringProperty("AsyncLogger.ThreadNameStrategy", CACHED.name());
103107 try {
104108 return ThreadNameStrategy.valueOf(name);
105109 } catch (final Exception ex) {
109113 }
110114 }
111115 private static volatile Disruptor<RingBufferLogEvent> disruptor;
112 private static final Clock clock = ClockFactory.getClock();
116 private static final Clock CLOCK = ClockFactory.getClock();
117 private static volatile NanoClock nanoClock = new DummyNanoClock();
113118
114119 private static final ExecutorService executor = Executors
115120 .newSingleThreadExecutor(new DaemonThreadFactory("AsyncLogger-"));
120125 final int ringBufferSize = calculateRingBufferSize();
121126
122127 final WaitStrategy waitStrategy = createWaitStrategy();
123 disruptor = new Disruptor<RingBufferLogEvent>(RingBufferLogEvent.FACTORY, ringBufferSize, executor,
124 ProducerType.MULTI, waitStrategy);
128 disruptor = new Disruptor<>(RingBufferLogEvent.FACTORY, ringBufferSize, executor, ProducerType.MULTI,
129 waitStrategy);
125130 disruptor.handleExceptionsWith(getExceptionHandler());
126131 disruptor.handleEventsWith(new RingBufferLogEventHandler());
127132
132137
133138 private static int calculateRingBufferSize() {
134139 int ringBufferSize = RINGBUFFER_DEFAULT_SIZE;
135 final String userPreferredRBSize = System.getProperty("AsyncLogger.RingBufferSize",
140 final String userPreferredRBSize = PropertiesUtil.getProperties().getStringProperty("AsyncLogger.RingBufferSize",
136141 String.valueOf(ringBufferSize));
137142 try {
138143 int size = Integer.parseInt(userPreferredRBSize);
162167 final boolean isAppenderThread = true;
163168 final Info info = new Info(new RingBufferLogEventTranslator(), //
164169 Thread.currentThread().getName(), isAppenderThread);
165 threadlocalInfo.set(info);
170 Info.threadlocalInfo.set(info);
166171 }
167172 });
168173 }
169174
170175 private static WaitStrategy createWaitStrategy() {
171 final String strategy = System.getProperty("AsyncLogger.WaitStrategy");
176 final String strategy = PropertiesUtil.getProperties().getStringProperty("AsyncLogger.WaitStrategy");
172177 LOGGER.debug("property AsyncLogger.WaitStrategy={}", strategy);
173178 if ("Sleep".equals(strategy)) {
174179 return new SleepingWaitStrategy();
181186 return new BlockingWaitStrategy();
182187 }
183188
184 private static ExceptionHandler getExceptionHandler() {
185 final String cls = System.getProperty("AsyncLogger.ExceptionHandler");
189 private static ExceptionHandler<RingBufferLogEvent> getExceptionHandler() {
190 final String cls = PropertiesUtil.getProperties().getStringProperty("AsyncLogger.ExceptionHandler");
186191 if (cls == null) {
187192 LOGGER.debug("No AsyncLogger.ExceptionHandler specified");
188193 return null;
189194 }
190195 try {
191 final ExceptionHandler result = Loader.newCheckedInstanceOf(cls, ExceptionHandler.class);
196 @SuppressWarnings("unchecked")
197 final ExceptionHandler<RingBufferLogEvent> result = Loader.newCheckedInstanceOf(cls, ExceptionHandler.class);
192198 LOGGER.debug("AsyncLogger.ExceptionHandler={}", result);
193199 return result;
194200 } catch (final Exception ignored) {
213219 * Tuple with the event translator and thread name for a thread.
214220 */
215221 static class Info {
222 private static final ThreadLocal<Info> threadlocalInfo = new ThreadLocal<Info>() {
223 @Override
224 protected Info initialValue() {
225 // by default, set isAppenderThread to false
226 return new Info(new RingBufferLogEventTranslator(), Thread.currentThread().getName(), false);
227 }
228 };
216229 private final RingBufferLogEventTranslator translator;
217230 private final String cachedThreadName;
218231 private final boolean isAppenderThread;
232
219233 public Info(final RingBufferLogEventTranslator translator, final String threadName, final boolean appenderThread) {
220234 this.translator = translator;
221235 this.cachedThreadName = threadName;
222236 this.isAppenderThread = appenderThread;
223237 }
238
239 // LOG4J2-467
240 private String threadName() {
241 return THREAD_NAME_STRATEGY.getThreadName(this);
242 }
224243 }
225244
226245 @Override
227 public void logMessage(final String fqcn, final Level level, final Marker marker, final Message message, final Throwable thrown) {
228 // TODO refactor to reduce size to <= 35 bytecodes to allow JVM to inline it
229 Info info = threadlocalInfo.get();
230 if (info == null) {
231 info = new Info(new RingBufferLogEventTranslator(), Thread.currentThread().getName(), false);
232 threadlocalInfo.set(info);
233 }
246 public void logMessage(final String fqcn, final Level level, final Marker marker, final Message message,
247 final Throwable thrown) {
234248
235249 final Disruptor<RingBufferLogEvent> temp = disruptor;
236250 if (temp == null) { // LOG4J2-639
237251 LOGGER.fatal("Ignoring log event after log4j was shut down");
238 return;
239 }
240
241 // LOG4J2-471: prevent deadlock when RingBuffer is full and object
242 // being logged calls Logger.log() from its toString() method
243 if (info.isAppenderThread && temp.getRingBuffer().remainingCapacity() == 0) {
252 } else {
253 logMessage0(temp, fqcn, level, marker, message, thrown);
254 }
255 }
256
257 private void logMessage0(final Disruptor<RingBufferLogEvent> theDisruptor, final String fqcn, final Level level,
258 final Marker marker, final Message message, final Throwable thrown) {
259 final Info info = Info.threadlocalInfo.get();
260 logMessageInAppropriateThread(info, theDisruptor, fqcn, level, marker, message, thrown);
261 }
262
263 private void logMessageInAppropriateThread(final Info info, final Disruptor<RingBufferLogEvent> theDisruptor,
264 final String fqcn, final Level level, final Marker marker, final Message message, final Throwable thrown) {
265 if (!logMessageInCurrentThread(info, theDisruptor, fqcn, level, marker, message, thrown)) {
266 logMessageInBackgroundThread(info, fqcn, level, marker, message, thrown);
267 }
268 }
269
270 /**
271 * LOG4J2-471: prevent deadlock when RingBuffer is full and object
272 * being logged calls Logger.log() from its toString() method
273 *
274 * @param info threadlocal information - used to determine if the current thread is the background appender thread
275 * @param theDisruptor used to check if the buffer is full
276 * @param fqcn fully qualified caller name
277 * @param level log level
278 * @param marker optional marker
279 * @param message log message
280 * @param thrown optional exception
281 * @return {@code true} if the event has been logged in the current thread, {@code false} if it should be passed to
282 * the background thread
283 */
284 private boolean logMessageInCurrentThread(Info info, final Disruptor<RingBufferLogEvent> theDisruptor,
285 final String fqcn, final Level level, final Marker marker, final Message message, final Throwable thrown) {
286 if (info.isAppenderThread && theDisruptor.getRingBuffer().remainingCapacity() == 0) {
244287 // bypass RingBuffer and invoke Appender directly
245 config.loggerConfig.log(getName(), fqcn, marker, level, message, thrown);
246 return;
247 }
288 final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy();
289 strategy.log(this, getName(), fqcn, marker, level, message, thrown);
290 return true;
291 }
292 return false;
293 }
294
295 /**
296 * Enqueues the specified message to be logged in the background thread.
297 *
298 * @param info holds some cached information
299 * @param fqcn fully qualified caller name
300 * @param level log level
301 * @param marker optional marker
302 * @param message log message
303 * @param thrown optional exception
304 */
305 private void logMessageInBackgroundThread(Info info, final String fqcn, final Level level, final Marker marker,
306 final Message message, final Throwable thrown) {
307
248308 message.getFormattedMessage(); // LOG4J2-763: ask message to freeze parameters
249 final boolean includeLocation = config.loggerConfig.isIncludeLocation();
309
310 initLogMessageInfo(info, fqcn, level, marker, message, thrown);
311 enqueueLogMessageInfo(info);
312 }
313
314 private void initLogMessageInfo(Info info, final String fqcn, final Level level, final Marker marker,
315 final Message message, final Throwable thrown) {
250316 info.translator.setValues(this, getName(), marker, fqcn, level, message, //
251317 // don't construct ThrowableProxy until required
252318 thrown, //
262328
263329 // Thread.currentThread().getName(), //
264330 // info.cachedThreadName, //
265 THREAD_NAME_STRATEGY.getThreadName(info), // LOG4J2-467
331 info.threadName(), //
266332
267333 // location: very expensive operation. LOG4J2-153:
268334 // Only include if "includeLocation=true" is specified,
269335 // exclude if not specified or if "false" was specified.
270 includeLocation ? location(fqcn) : null,
336 calcLocationIfRequested(fqcn),
271337
272338 // System.currentTimeMillis());
273339 // CoarseCachedClock: 20% faster than system clock, 16ms gaps
274340 // CachedClock: 10% faster than system clock, smaller gaps
275341 // LOG4J2-744 avoid calling clock altogether if message has the timestamp
276 message instanceof TimestampMessage ? ((TimestampMessage) message).getTimestamp() :
277 clock.currentTimeMillis());
278
342 eventTimeMillis(message), //
343 nanoClock.nanoTime() //
344 );
345 }
346
347 private long eventTimeMillis(final Message message) {
348 return message instanceof TimestampMessage ? ((TimestampMessage) message).getTimestamp() :
349 CLOCK.currentTimeMillis();
350 }
351
352 /**
353 * Returns the caller location if requested, {@code null} otherwise.
354 * @param fqcn fully qualified caller name.
355 * @return the caller location if requested, {@code null} otherwise.
356 */
357 private StackTraceElement calcLocationIfRequested(String fqcn) {
358 final boolean includeLocation = privateConfig.loggerConfig.isIncludeLocation();
359 return includeLocation ? location(fqcn) : null;
360 }
361
362 private void enqueueLogMessageInfo(Info info) {
279363 // LOG4J2-639: catch NPE if disruptor field was set to null after our check above
280364 try {
281365 // Note: do NOT use the temp variable above!
298382 * @param event the event to log
299383 */
300384 public void actualAsyncLog(final RingBufferLogEvent event) {
301 final Map<Property, Boolean> properties = config.loggerConfig.getProperties();
302 event.mergePropertiesIntoContextMap(properties, config.config.getStrSubstitutor());
303 config.logEvent(event);
385 final Map<Property, Boolean> properties = privateConfig.loggerConfig.getProperties();
386 event.mergePropertiesIntoContextMap(properties, privateConfig.config.getStrSubstitutor());
387 final ReliabilityStrategy strategy = privateConfig.loggerConfig.getReliabilityStrategy();
388 strategy.log(this, event);
304389 }
305390
306391 public static void stop() {
324409 }
325410 temp.shutdown(); // busy-spins until all events currently in the disruptor have been processed
326411 executor.shutdown(); // finally, kill the processor thread
327 threadlocalInfo.remove(); // LOG4J2-323
412 Info.threadlocalInfo.remove(); // LOG4J2-323
328413 }
329414
330415 /**
344429 public static RingBufferAdmin createRingBufferAdmin(final String contextName) {
345430 return RingBufferAdmin.forAsyncLogger(disruptor.getRingBuffer(), contextName);
346431 }
432
433 /**
434 * Returns the {@code NanoClock} to use for creating the nanoTime timestamp of log events.
435 * @return the {@code NanoClock} to use for creating the nanoTime timestamp of log events
436 */
437 public static NanoClock getNanoClock() {
438 return nanoClock;
439 }
440
441 /**
442 * Sets the {@code NanoClock} to use for creating the nanoTime timestamp of log events.
443 * <p>
444 * FOR INTERNAL USE. This method may be called with a different {@code NanoClock} implementation when the
445 * configuration changes.
446 *
447 * @param nanoClock the {@code NanoClock} to use for creating the nanoTime timestamp of log events
448 */
449 public static void setNanoClock(NanoClock nanoClock) {
450 AsyncLogger.nanoClock = Objects.requireNonNull(nanoClock, "NanoClock must be non-null");
451 }
347452 }
235235
236236 return new AsyncLoggerConfig(LogManager.ROOT_LOGGER_NAME,
237237 appenderRefs, filter, level, additive, properties, config,
238 includeLocation(includeLocation));
238 AsyncLoggerConfig.includeLocation(includeLocation));
239239 }
240240 }
241241 }
2424 import org.apache.logging.log4j.core.jmx.RingBufferAdmin;
2525 import org.apache.logging.log4j.core.util.Integers;
2626 import org.apache.logging.log4j.status.StatusLogger;
27 import org.apache.logging.log4j.util.PropertiesUtil;
2728
2829 import com.lmax.disruptor.BlockingWaitStrategy;
2930 import com.lmax.disruptor.EventFactory;
6869 private static ExecutorService executor;
6970
7071 private static volatile int count = 0;
71 private static ThreadLocal<Boolean> isAppenderThread = new ThreadLocal<Boolean>();
72 private static ThreadLocal<Boolean> isAppenderThread = new ThreadLocal<>();
7273
7374 /**
7475 * Factory used to populate the RingBuffer with events. These event objects
112113 final WaitStrategy waitStrategy = createWaitStrategy();
113114 executor = Executors.newSingleThreadExecutor(threadFactory);
114115 initThreadLocalForExecutorThread();
115 disruptor = new Disruptor<Log4jEventWrapper>(FACTORY, ringBufferSize,
116 executor, ProducerType.MULTI, waitStrategy);
116 disruptor = new Disruptor<>(FACTORY, ringBufferSize, executor, ProducerType.MULTI, waitStrategy);
117117 final EventHandler<Log4jEventWrapper>[] handlers = new Log4jEventWrapperHandler[] {//
118118 new Log4jEventWrapperHandler() };
119 final ExceptionHandler errorHandler = getExceptionHandler();
119 final ExceptionHandler<Log4jEventWrapper> errorHandler = getExceptionHandler();
120120 disruptor.handleExceptionsWith(errorHandler);
121121 disruptor.handleEventsWith(handlers);
122122
143143
144144 private static int calculateRingBufferSize() {
145145 int ringBufferSize = RINGBUFFER_DEFAULT_SIZE;
146 final String userPreferredRBSize = System.getProperty(
146 final String userPreferredRBSize = PropertiesUtil.getProperties().getStringProperty(
147147 "AsyncLoggerConfig.RingBufferSize",
148148 String.valueOf(ringBufferSize));
149149 try {
162162 return Integers.ceilingNextPowerOfTwo(ringBufferSize);
163163 }
164164
165 private static ExceptionHandler getExceptionHandler() {
166 final String cls = System
167 .getProperty("AsyncLoggerConfig.ExceptionHandler");
165 private static ExceptionHandler<Log4jEventWrapper> getExceptionHandler() {
166 final String cls = System.getProperty("AsyncLoggerConfig.ExceptionHandler");
168167 if (cls == null) {
169168 return null;
170169 }
171170 try {
172171 @SuppressWarnings("unchecked")
173 final Class<? extends ExceptionHandler> klass = (Class<? extends ExceptionHandler>) Class
172 final Class<? extends ExceptionHandler<Log4jEventWrapper>> klass = (Class<? extends ExceptionHandler<Log4jEventWrapper>>) Class
174173 .forName(cls);
175 final ExceptionHandler result = klass.newInstance();
176 return result;
174 return klass.newInstance();
177175 } catch (final Exception ignored) {
178 LOGGER.debug(
179 "AsyncLoggerConfig.ExceptionHandler not set: error creating "
180 + cls + ": ", ignored);
176 LOGGER.debug("AsyncLoggerConfig.ExceptionHandler not set: error creating " + cls + ": ", ignored);
181177 return null;
182178 }
183179 }
221217 event.loggerConfig.asyncCallAppenders(event.event);
222218 event.clear();
223219
224 // notify the BatchEventProcessor that the sequence has progressed.
225 // Without this callback the sequence would not be progressed
226 // until the batch has completely finished.
220 notifyIntermediateProgress(sequence);
221 }
222
223 /**
224 * Notify the BatchEventProcessor that the sequence has progressed.
225 * Without this callback the sequence would not be progressed
226 * until the batch has completely finished.
227 */
228 private void notifyIntermediateProgress(final long sequence) {
227229 if (++counter > NOTIFY_PROGRESS_THRESHOLD) {
228230 sequenceCallback.set(sequence);
229231 counter = 0;
315317 * calling thread needs to process the event itself
316318 */
317319 public boolean callAppendersFromAnotherThread(final LogEvent event) {
318 // TODO refactor to reduce size to <= 35 bytecodes to allow JVM to inline it
319320 final Disruptor<Log4jEventWrapper> temp = disruptor;
320 if (temp == null) { // LOG4J2-639
321 if (!hasLog4jBeenShutDown(temp)) {
322
323 // LOG4J2-471: prevent deadlock when RingBuffer is full and object
324 // being logged calls Logger.log() from its toString() method
325 if (isCalledFromAppenderThreadAndBufferFull(temp)) {
326 // bypass RingBuffer and invoke Appender directly
327 return false;
328 }
329 enqueueEvent(event);
330 }
331 return true;
332 }
333
334 /**
335 * Returns {@code true} if the specified disruptor is null.
336 */
337 private boolean hasLog4jBeenShutDown(final Disruptor<Log4jEventWrapper> aDisruptor) {
338 if (aDisruptor == null) { // LOG4J2-639
321339 LOGGER.fatal("Ignoring log event after log4j was shut down");
322340 return true;
323341 }
324
325 // LOG4J2-471: prevent deadlock when RingBuffer is full and object
326 // being logged calls Logger.log() from its toString() method
327 if (isAppenderThread.get() == Boolean.TRUE //
328 && temp.getRingBuffer().remainingCapacity() == 0) {
329
330 // bypass RingBuffer and invoke Appender directly
331 return false;
332 }
342 return false;
343 }
344
345 private void enqueueEvent(final LogEvent event) {
333346 // LOG4J2-639: catch NPE if disruptor field was set to null after our check above
334347 try {
335 LogEvent logEvent = event;
336 if (event instanceof RingBufferLogEvent) {
337 logEvent = ((RingBufferLogEvent) event).createMemento();
338 }
339 logEvent.getMessage().getFormattedMessage(); // LOG4J2-763: ask message to freeze parameters
340
341 // Note: do NOT use the temp variable above!
342 // That could result in adding a log event to the disruptor after it was shut down,
343 // which could cause the publishEvent method to hang and never return.
344 disruptor.getRingBuffer().publishEvent(translator, logEvent, asyncLoggerConfig);
348 final LogEvent logEvent = prepareEvent(event);
349 enqueue(logEvent);
345350 } catch (final NullPointerException npe) {
346351 LOGGER.fatal("Ignoring log event after log4j was shut down.");
347352 }
348 return true;
353 }
354
355 private LogEvent prepareEvent(final LogEvent event) {
356 final LogEvent logEvent = ensureImmutable(event);
357 logEvent.getMessage().getFormattedMessage(); // LOG4J2-763: ask message to freeze parameters
358 return logEvent;
359 }
360
361 private void enqueue(LogEvent logEvent) {
362 // Note: do NOT use the temp variable above!
363 // That could result in adding a log event to the disruptor after it was shut down,
364 // which could cause the publishEvent method to hang and never return.
365 disruptor.getRingBuffer().publishEvent(translator, logEvent, asyncLoggerConfig);
366 }
367
368 private LogEvent ensureImmutable(final LogEvent event) {
369 LogEvent result = event;
370 if (event instanceof RingBufferLogEvent) {
371 // Deal with special case where both types of Async Loggers are used together:
372 // RingBufferLogEvents are created by the all-loggers-async type, but
373 // this event is also consumed by the some-loggers-async type (this class).
374 // The original event will be re-used and modified in an application thread later,
375 // so take a snapshot of it, which can be safely processed in the
376 // some-loggers-async background thread.
377 result = ((RingBufferLogEvent) event).createMemento();
378 }
379 return result;
380 }
381
382 /**
383 * Returns true if the specified ringbuffer is full and the Logger.log() call was made from the appender thread.
384 */
385 private boolean isCalledFromAppenderThreadAndBufferFull(Disruptor<Log4jEventWrapper> disruptor) {
386 return isAppenderThread.get() == Boolean.TRUE && disruptor.getRingBuffer().remainingCapacity() == 0;
349387 }
350388
351389 /**
3939
4040 @Override
4141 public List<LoggerContext> getLoggerContexts() {
42 final List<LoggerContext> list = new ArrayList<LoggerContext>();
42 final List<LoggerContext> list = new ArrayList<>();
4343 list.add(CONTEXT);
4444 return Collections.unmodifiableList(list);
4545 }
6969 private long currentTimeMillis;
7070 private boolean endOfBatch;
7171 private boolean includeLocation;
72 private long nanoTime;
7273
7374 public void setValues(final AsyncLogger asyncLogger, final String loggerName, final Marker marker,
7475 final String fqcn, final Level level, final Message data, final Throwable throwable,
7576 final Map<String, String> map, final ContextStack contextStack, final String threadName,
76 final StackTraceElement location, final long currentTimeMillis) {
77 final StackTraceElement location, final long currentTimeMillis, final long nanoTime) {
7778 this.asyncLogger = asyncLogger;
7879 this.loggerName = loggerName;
7980 this.marker = marker;
8788 this.threadName = threadName;
8889 this.location = location;
8990 this.currentTimeMillis = currentTimeMillis;
91 this.nanoTime = nanoTime;
9092 }
9193
9294 /**
201203 public long getTimeMillis() {
202204 return currentTimeMillis;
203205 }
206
207 @Override
208 public long getNanoTime() {
209 return nanoTime;
210 }
204211
205212 /**
206213 * Merges the contents of the specified map into the contextMap, after replacing any variables in the property
216223 }
217224
218225 final Map<String, String> map = contextMap == null ? new HashMap<String, String>()
219 : new HashMap<String, String>(contextMap);
226 : new HashMap<>(contextMap);
220227
221228 for (final Map.Entry<Property, Boolean> entry : properties.entrySet()) {
222229 final Property prop = entry.getKey();
245252 null, // contextStack
246253 null, // threadName
247254 null, // location
248 0 // currentTimeMillis
255 0, // currentTimeMillis
256 0 // nanoTime
249257 );
250258 }
251259
260268 * @return a new immutable copy of the data in this {@code RingBufferLogEvent}
261269 */
262270 public LogEvent createMemento() {
263 // Ideally, would like to use the LogEventFactory here but signature does not match:
264 // results in factory re-creating the timestamp, context map and context stack, which we don't want.
265 return new Log4jLogEvent(loggerName, marker, fqcn, level, message, thrown, contextMap, contextStack,
266 threadName, location, currentTimeMillis);
271 final LogEvent result = new Log4jLogEvent.Builder(this).build();
272 return result;
273 }
274
275 /**
276 * Initializes the specified {@code Log4jLogEvent.Builder} from this {@code RingBufferLogEvent}.
277 * @param builder the builder whose fields to populate
278 */
279 public void initializeBuilder(Log4jLogEvent.Builder builder) {
280 builder.setContextMap(contextMap) //
281 .setContextStack(contextStack) //
282 .setEndOfBatch(endOfBatch) //
283 .setIncludeLocation(includeLocation) //
284 .setLevel(getLevel()) // ensure non-null
285 .setLoggerFqcn(fqcn) //
286 .setLoggerName(loggerName) //
287 .setMarker(marker) //
288 .setMessage(getMessage()) // ensure non-null
289 .setNanoTime(nanoTime) //
290 .setSource(location) //
291 .setThreadName(threadName) //
292 .setThrown(getThrown()) // may deserialize from thrownProxy
293 .setThrownProxy(thrownProxy) // avoid unnecessarily creating thrownProxy
294 .setTimeMillis(currentTimeMillis) //
295 ;
267296 }
268297 }
4545 private String threadName;
4646 private StackTraceElement location;
4747 private long currentTimeMillis;
48 private long nanoTime;
4849
4950 // @Override
5051 @Override
5152 public void translateTo(final RingBufferLogEvent event, final long sequence) {
5253 event.setValues(asyncLogger, loggerName, marker, fqcn, level, message,
5354 thrown, contextMap, contextStack, threadName, location,
54 currentTimeMillis);
55 currentTimeMillis, nanoTime);
5556 clear();
5657 }
5758
7172 null, // contextStack
7273 null, // threadName
7374 null, // location
74 0 // currentTimeMillis
75 0, // currentTimeMillis
76 0 // nanoTime
7577 );
7678 }
7779
7981 final Marker marker, final String fqcn, final Level level, final Message message,
8082 final Throwable thrown, final Map<String, String> contextMap,
8183 final ContextStack contextStack, final String threadName,
82 final StackTraceElement location, final long currentTimeMillis) {
84 final StackTraceElement location, final long currentTimeMillis, final long nanoTime) {
8385 this.asyncLogger = asyncLogger;
8486 this.loggerName = loggerName;
8587 this.marker = marker;
9294 this.threadName = threadName;
9395 this.location = location;
9496 this.currentTimeMillis = currentTimeMillis;
97 this.nanoTime = nanoTime;
9598 }
96
9799 }
2626 import java.util.LinkedHashMap;
2727 import java.util.List;
2828 import java.util.Map;
29 import java.util.Objects;
2930 import java.util.Set;
3031 import java.util.concurrent.ConcurrentHashMap;
3132 import java.util.concurrent.ConcurrentMap;
5354 import org.apache.logging.log4j.core.lookup.StrSubstitutor;
5455 import org.apache.logging.log4j.core.net.Advertiser;
5556 import org.apache.logging.log4j.core.selector.ContextSelector;
56 import org.apache.logging.log4j.core.util.Assert;
5757 import org.apache.logging.log4j.core.util.Constants;
5858 import org.apache.logging.log4j.core.util.Loader;
5959 import org.apache.logging.log4j.core.util.NameUtil;
7777 /**
7878 * Listeners for configuration changes.
7979 */
80 protected final List<ConfigurationListener> listeners = new CopyOnWriteArrayList<ConfigurationListener>();
80 protected final List<ConfigurationListener> listeners = new CopyOnWriteArrayList<>();
8181
8282 /**
8383 * The ConfigurationMonitor that checks for configuration changes.
9696 */
9797 protected boolean isShutdownHookEnabled = true;
9898 private String name;
99 private ConcurrentMap<String, Appender> appenders = new ConcurrentHashMap<String, Appender>();
100 private ConcurrentMap<String, LoggerConfig> loggers = new ConcurrentHashMap<String, LoggerConfig>();
99 private ConcurrentMap<String, Appender> appenders = new ConcurrentHashMap<>();
100 private ConcurrentMap<String, LoggerConfig> loggers = new ConcurrentHashMap<>();
101101 private List<CustomLevelConfig> customLevels = Collections.emptyList();
102 private final ConcurrentMap<String, String> properties = new ConcurrentHashMap<String, String>();
102 private final ConcurrentMap<String, String> properties = new ConcurrentHashMap<>();
103103 private final StrLookup tempLookup = new Interpolator(properties);
104104 private final StrSubstitutor subst = new StrSubstitutor(tempLookup);
105105 private LoggerConfig root = new LoggerConfig();
106 private final ConcurrentMap<String, Object> componentMap = new ConcurrentHashMap<String, Object>();
107 protected final List<String> pluginPackages = new ArrayList<String>();
106 private final ConcurrentMap<String, Object> componentMap = new ConcurrentHashMap<>();
107 protected final List<String> pluginPackages = new ArrayList<>();
108108 protected PluginManager pluginManager;
109109 private final ConfigurationSource configurationSource;
110110
112112 * Constructor.
113113 */
114114 protected AbstractConfiguration(final ConfigurationSource configurationSource) {
115 this.configurationSource = Assert.requireNonNull(configurationSource, "configurationSource is null");
115 this.configurationSource = Objects.requireNonNull(configurationSource, "configurationSource is null");
116116 componentMap.put(Configuration.CONTEXT_PROPERTIES, properties);
117117 pluginManager = new PluginManager(Node.CATEGORY);
118118 rootNode = new Node();
119 setState(State.INITIALIZING);
119120 }
120121
121122 @Override
137138 * Initialize the configuration.
138139 */
139140 @Override
140 public void start() {
141 LOGGER.debug("Starting configuration {}", this);
142 this.setStarting();
141 public void initialize() {
142 LOGGER.debug("Initializing configuration {}", this);
143143 pluginManager.collectPlugins(pluginPackages);
144144 final PluginManager levelPlugins = new PluginManager(Level.CATEGORY);
145145 levelPlugins.collectPlugins(pluginPackages);
158158 setup();
159159 setupAdvertisement();
160160 doConfigure();
161 final Set<LoggerConfig> alreadyStarted = new HashSet<LoggerConfig>();
161 setState(State.INITIALIZED);
162 LOGGER.debug("Configuration {} initialized", this);
163 }
164
165 /**
166 * Start the configuration
167 */
168 @Override
169 public void start() {
170 // Preserve the prior behavior of initializing during start if not initialized.
171 if (getState().equals(State.INITIALIZING)) {
172 initialize();
173 }
174 LOGGER.debug("Starting configuration {}", this);
175 this.setStarting();
176 final Set<LoggerConfig> alreadyStarted = new HashSet<>();
162177 for (final LoggerConfig logger : loggers.values()) {
163178 logger.start();
164179 alreadyStarted.add(logger);
180195 public void stop() {
181196 this.setStopping();
182197 LOGGER.trace("Stopping {}...", this);
198
199 for (final LoggerConfig loggerConfig : loggers.values()) {
200 loggerConfig.getReliabilityStrategy().beforeStopConfiguration(this);
201 }
202 LOGGER.trace("AbstractConfiguration notified {} ReliabilityStrategies that config will be stopped.",
203 loggers.size());
183204
184205 // LOG4J2-392 first stop AsyncLogger Disruptor thread
185206 final LoggerContextFactory factory = LogManager.getFactory();
196217 }
197218 }
198219 // similarly, first stop AsyncLoggerConfig Disruptor thread(s)
199 final Set<LoggerConfig> alreadyStopped = new HashSet<LoggerConfig>();
220 final Set<LoggerConfig> alreadyStopped = new HashSet<>();
200221 int asyncLoggerConfigCount = 0;
201222 for (final LoggerConfig logger : loggers.values()) {
202223 if (logger instanceof AsyncLoggerConfig) {
230251 }
231252 LOGGER.trace("AbstractConfiguration stopped {} AsyncAppenders.", asyncAppenderCount);
232253
254 for (final LoggerConfig loggerConfig : loggers.values()) {
255 loggerConfig.getReliabilityStrategy().beforeStopAppenders();
256 }
257 LOGGER.trace("AbstractConfiguration notified {} ReliabilityStrategies that appenders will be stopped.",
258 loggers.size());
259
233260 int appenderCount = 0;
234261 for (int i = array.length - 1; i >= 0; --i) {
235262 if (array[i].isStarted()) { // then stop remaining Appenders
240267 LOGGER.trace("AbstractConfiguration stopped {} Appenders.", appenderCount);
241268
242269 int loggerCount = 0;
243 for (final LoggerConfig logger : loggers.values()) {
244 // clear appenders, even if this logger is already stopped.
245 logger.clearAppenders();
270 for (final LoggerConfig loggerConfig : loggers.values()) {
246271
247272 // AsyncLoggerConfigHelper decreases its ref count when an AsyncLoggerConfig is stopped.
248273 // Stopping the same AsyncLoggerConfig twice results in an incorrect ref count and
249274 // the shared Disruptor may be shut down prematurely, resulting in NPE or other errors.
250 if (alreadyStopped.contains(logger)) {
251 continue;
252 }
253 logger.stop();
254 loggerCount++;
255 }
256 LOGGER.trace("AbstractConfiguration stopped {} Loggers.", loggerCount);
275 if (!alreadyStopped.contains(loggerConfig)) {
276 loggerConfig.stop();
277 loggerCount++;
278 }
279 loggerConfig.clearAppenders();
280 }
281 LOGGER.trace("AbstractConfiguration stopped {} LoggerConfigs.", loggerCount);
257282
258283 // AsyncLoggerConfigHelper decreases its ref count when an AsyncLoggerConfig is stopped.
259284 // Stopping the same AsyncLoggerConfig twice results in an incorrect ref count and
373398 } else if (child.getName().equalsIgnoreCase("CustomLevels")) {
374399 customLevels = child.getObject(CustomLevels.class).getCustomLevels();
375400 } else if (child.isInstanceOf(CustomLevelConfig.class)) {
376 final List<CustomLevelConfig> copy = new ArrayList<CustomLevelConfig>(customLevels);
401 final List<CustomLevelConfig> copy = new ArrayList<>(customLevels);
377402 copy.add(child.getObject(CustomLevelConfig.class));
378403 customLevels = copy;
379404 } else {
464489
465490 /**
466491 * Returns the Appender with the specified name.
467 * @param name The name of the Appender.
492 * @param appenderName The name of the Appender.
468493 * @return the Appender with the specified name or null if the Appender cannot be located.
469494 */
470495 @Override
471 public Appender getAppender(final String name) {
472 return appenders.get(name);
496 @SuppressWarnings("unchecked")
497 public <T extends Appender> T getAppender(final String appenderName) {
498 return (T) appenders.get(appenderName);
473499 }
474500
475501 /**
547573 *
548574 * Note: This method is not used when configuring via configuration. It is primarily used by
549575 * unit tests.
550 * @param logger The Logger the Fo;ter will be associated with.
576 * @param logger The Logger the Footer will be associated with.
551577 * @param filter The Filter.
552578 */
553579 @Override
555581 final String name = logger.getName();
556582 final LoggerConfig lc = getLoggerConfig(name);
557583 if (lc.getName().equals(name)) {
558
559584 lc.addFilter(filter);
560585 } else {
561586 final LoggerConfig nlc = new LoggerConfig(name, lc.getLevel(), lc.isAdditive());
578603 @Override
579604 public synchronized void setLoggerAdditive(final org.apache.logging.log4j.core.Logger logger,
580605 final boolean additive) {
581 final String name = logger.getName();
582 final LoggerConfig lc = getLoggerConfig(name);
583 if (lc.getName().equals(name)) {
606 final String loggerName = logger.getName();
607 final LoggerConfig lc = getLoggerConfig(loggerName);
608 if (lc.getName().equals(loggerName)) {
584609 lc.setAdditive(additive);
585610 } else {
586 final LoggerConfig nlc = new LoggerConfig(name, lc.getLevel(), additive);
611 final LoggerConfig nlc = new LoggerConfig(loggerName, lc.getLevel(), additive);
587612 nlc.setParent(lc);
588 loggers.putIfAbsent(name, nlc);
613 loggers.putIfAbsent(loggerName, nlc);
589614 setParents();
590615 logger.getContext().updateLoggers();
591616 }
595620 * Remove an Appender. First removes any associations between LoggerConfigs and the Appender, removes
596621 * the Appender from this appender list and then stops the appender. This method is synchronized in
597622 * case an Appender with the same name is being added during the removal.
598 * @param name the name of the appender to remove.
599 */
600 public synchronized void removeAppender(final String name) {
623 * @param appenderName the name of the appender to remove.
624 */
625 public synchronized void removeAppender(final String appenderName) {
601626 for (final LoggerConfig logger : loggers.values()) {
602 logger.removeAppender(name);
603 }
604 final Appender app = appenders.remove(name);
627 logger.removeAppender(appenderName);
628 }
629 final Appender app = appenders.remove(appenderName);
605630
606631 if (app != null) {
607632 app.stop();
620645 /**
621646 * Locates the appropriate LoggerConfig for a Logger name. This will remove tokens from the
622647 * package name as necessary or return the root LoggerConfig if no other matches were found.
623 * @param name The Logger name.
648 * @param loggerName The Logger name.
624649 * @return The located LoggerConfig.
625650 */
626651 @Override
627 public LoggerConfig getLoggerConfig(final String name) {
628 if (loggers.containsKey(name)) {
629 return loggers.get(name);
630 }
631 String substr = name;
652 public LoggerConfig getLoggerConfig(final String loggerName) {
653 LoggerConfig loggerConfig = loggers.get(loggerName);
654 if (loggerConfig != null) {
655 return loggerConfig;
656 }
657 String substr = loggerName;
632658 while ((substr = NameUtil.getSubName(substr)) != null) {
633 if (loggers.containsKey(substr)) {
634 return loggers.get(substr);
659 loggerConfig = loggers.get(substr);
660 if (loggerConfig != null) {
661 return loggerConfig;
635662 }
636663 }
637664 return root;
641668 * Returns the root Logger.
642669 * @return the root Logger.
643670 */
671 @Override
644672 public LoggerConfig getRootLogger() {
645673 return root;
646674 }
656684
657685 /**
658686 * Returns the LoggerConfig with the specified name.
659 * @param name The Logger name.
687 * @param loggerName The Logger name.
660688 * @return The LoggerConfig or null if no match was found.
661689 */
662 public LoggerConfig getLogger(final String name) {
663 return loggers.get(name);
690 public LoggerConfig getLogger(final String loggerName) {
691 return loggers.get(loggerName);
664692 }
665693
666694 /**
667695 * Add a loggerConfig. The LoggerConfig must already be configured with Appenders, Filters, etc.
668696 * After addLogger is called LoggerContext.updateLoggers must be called.
669697 *
670 * @param name The name of the Logger.
698 * @param loggerName The name of the Logger.
671699 * @param loggerConfig The LoggerConfig.
672700 */
673701 @Override
674 public synchronized void addLogger(final String name, final LoggerConfig loggerConfig) {
675 loggers.putIfAbsent(name, loggerConfig);
702 public synchronized void addLogger(final String loggerName, final LoggerConfig loggerConfig) {
703 loggers.putIfAbsent(loggerName, loggerConfig);
676704 setParents();
677705 }
678706
679707 /**
680708 * Remove a LoggerConfig.
681709 *
682 * @param name The name of the Logger.
683 */
684 @Override
685 public synchronized void removeLogger(final String name) {
686 loggers.remove(name);
710 * @param loggerName The name of the Logger.
711 */
712 @Override
713 public synchronized void removeLogger(final String loggerName) {
714 loggers.remove(loggerName);
687715 setParents();
688716 }
689717
770798 }
771799
772800 private static Map<String, ?> createPluginMap(final Node node) {
773 final Map<String, Object> map = new LinkedHashMap<String, Object>();
801 final Map<String, Object> map = new LinkedHashMap<>();
774802 for (final Node child : node.getChildren()) {
775803 final Object object = child.getObject();
776804 map.put(child.getName(), object);
780808
781809 private static Collection<?> createPluginCollection(final Node node) {
782810 final List<Node> children = node.getChildren();
783 final Collection<Object> list = new ArrayList<Object>(children.size());
811 final Collection<Object> list = new ArrayList<>(children.size());
784812 for (final Node child : children) {
785813 final Object object = child.getObject();
786814 list.add(object);
791819 private void setParents() {
792820 for (final Map.Entry<String, LoggerConfig> entry : loggers.entrySet()) {
793821 final LoggerConfig logger = entry.getValue();
794 String name = entry.getKey();
795 if (!name.isEmpty()) {
796 final int i = name.lastIndexOf('.');
822 String key = entry.getKey();
823 if (!key.isEmpty()) {
824 final int i = key.lastIndexOf('.');
797825 if (i > 0) {
798 name = name.substring(0, i);
799 LoggerConfig parent = getLoggerConfig(name);
826 key = key.substring(0, i);
827 LoggerConfig parent = getLoggerConfig(key);
800828 if (parent == null) {
801829 parent = root;
802830 }
1515 */
1616 package org.apache.logging.log4j.core.config;
1717
18 import java.util.Objects;
19
1820 import org.apache.logging.log4j.Level;
1921 import org.apache.logging.log4j.core.Appender;
2022 import org.apache.logging.log4j.core.Filter;
2729 * Wraps an {@link Appender} with details an appender implementation shouldn't need to know about.
2830 */
2931 public class AppenderControl extends AbstractFilterable {
30
3132 private static final long serialVersionUID = 1L;
3233
33 private final ThreadLocal<AppenderControl> recursive = new ThreadLocal<AppenderControl>();
34
34 private final ThreadLocal<AppenderControl> recursive = new ThreadLocal<>();
3535 private final Appender appender;
36
3736 private final Level level;
38
3937 private final int intLevel;
38 private final String appenderName;
4039
4140 /**
4241 * Constructor.
4746 public AppenderControl(final Appender appender, final Level level, final Filter filter) {
4847 super(filter);
4948 this.appender = appender;
49 this.appenderName = appender.getName();
5050 this.level = level;
5151 this.intLevel = level == null ? Level.ALL.intLevel() : level.intLevel();
5252 start();
53 }
54
55 /**
56 * Returns the name the appender had when this AppenderControl was constructed.
57 * @return the appender name
58 */
59 public String getAppenderName() {
60 return appenderName;
5361 }
5462
5563 /**
6573 * @param event The event to process.
6674 */
6775 public void callAppender(final LogEvent event) {
68 if (getFilter() != null) {
69 final Filter.Result r = getFilter().filter(event);
70 if (r == Filter.Result.DENY) {
71 return;
72 }
73 }
74 if (level != null && intLevel < event.getLevel().intLevel()) {
76 if (shouldSkip(event)) {
7577 return;
7678 }
79 callAppenderPreventRecursion(event);
80 }
81
82 private boolean shouldSkip(final LogEvent event) {
83 return isFilteredByAppenderControl(event) || isFilteredByLevel(event) || isRecursiveCall();
84 }
85
86 private boolean isFilteredByAppenderControl(final LogEvent event) {
87 return getFilter() != null && Filter.Result.DENY == getFilter().filter(event);
88 }
89
90 private boolean isFilteredByLevel(final LogEvent event) {
91 return level != null && intLevel < event.getLevel().intLevel();
92 }
93
94 private boolean isRecursiveCall() {
7795 if (recursive.get() != null) {
78 appender.getHandler().error("Recursive call to appender " + appender.getName());
79 return;
96 appenderErrorHandlerMessage("Recursive call to appender ");
97 return true;
8098 }
99 return false;
100 }
101
102 private String appenderErrorHandlerMessage(final String prefix) {
103 String result = createErrorMsg(prefix);
104 appender.getHandler().error(result);
105 return result;
106 }
107
108 private void callAppenderPreventRecursion(final LogEvent event) {
81109 try {
82 recursive.set(this);
83
84 if (!appender.isStarted()) {
85 appender.getHandler().error("Attempted to append to non-started appender " + appender.getName());
86
87 if (!appender.ignoreExceptions()) {
88 throw new AppenderLoggingException(
89 "Attempted to append to non-started appender " + appender.getName());
90 }
91 }
92
93 if (appender instanceof Filterable && ((Filterable) appender).isFiltered(event)) {
94 return;
95 }
96
97 try {
98 appender.append(event);
99 } catch (final RuntimeException ex) {
100 appender.getHandler().error("An exception occurred processing Appender " + appender.getName(), ex);
101 if (!appender.ignoreExceptions()) {
102 throw ex;
103 }
104 } catch (final Exception ex) {
105 appender.getHandler().error("An exception occurred processing Appender " + appender.getName(), ex);
106 if (!appender.ignoreExceptions()) {
107 throw new AppenderLoggingException(ex);
108 }
109 }
110 recursive.set(this);
111 callAppender0(event);
110112 } finally {
111113 recursive.set(null);
112114 }
113115 }
114116
117 private void callAppender0(final LogEvent event) {
118 ensureAppenderStarted();
119 if (!isFilteredByAppender(event)) {
120 tryCallAppender(event);
121 }
122 }
123
124 private void ensureAppenderStarted() {
125 if (!appender.isStarted()) {
126 handleError("Attempted to append to non-started appender ");
127 }
128 }
129
130 private void handleError(final String prefix) {
131 final String msg = appenderErrorHandlerMessage(prefix);
132 if (!appender.ignoreExceptions()) {
133 throw new AppenderLoggingException(msg);
134 }
135 }
136
137 private String createErrorMsg(final String prefix) {
138 return prefix + appender.getName();
139 }
140
141 private boolean isFilteredByAppender(final LogEvent event) {
142 return appender instanceof Filterable && ((Filterable) appender).isFiltered(event);
143 }
144
145 private void tryCallAppender(final LogEvent event) {
146 try {
147 appender.append(event);
148 } catch (final RuntimeException ex) {
149 handleAppenderError(ex);
150 } catch (final Exception ex) {
151 handleAppenderError(new AppenderLoggingException(ex));
152 }
153 }
154
155 private void handleAppenderError(final RuntimeException ex) {
156 appender.getHandler().error(createErrorMsg("An exception occurred processing Appender "), ex);
157 if (!appender.ignoreExceptions()) {
158 throw ex;
159 }
160 }
161
162 // AppenderControl is a helper object whose purpose is to make it
163 // easier for LoggerConfig to manage and invoke Appenders.
164 // LoggerConfig manages Appenders by their name. To facilitate this,
165 // two AppenderControl objects are considered equal if and only
166 // if they have the same appender name.
167 @Override
168 public boolean equals(final Object obj) {
169 if (obj == this) {
170 return true;
171 }
172 if (!(obj instanceof AppenderControl)) {
173 return false;
174 }
175 final AppenderControl other = (AppenderControl) obj;
176 return Objects.equals(appenderName, other.appenderName);
177 }
178
179 @Override
180 public int hashCode() {
181 return appenderName.hashCode();
182 }
115183 }
4242 @PluginElement("Appenders") final Appender[] appenders) {
4343
4444 final ConcurrentMap<String, Appender> map =
45 new ConcurrentHashMap<String, Appender>();
45 new ConcurrentHashMap<>();
4646
4747 for (final Appender appender : appenders) {
4848 map.put(appender.getName(), appender);
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.config;
18
19 import java.util.Objects;
20 import java.util.concurrent.TimeUnit;
21 import java.util.concurrent.atomic.AtomicBoolean;
22 import java.util.concurrent.atomic.AtomicInteger;
23 import java.util.concurrent.locks.Condition;
24 import java.util.concurrent.locks.Lock;
25 import java.util.concurrent.locks.ReentrantLock;
26
27 import org.apache.logging.log4j.Level;
28 import org.apache.logging.log4j.Marker;
29 import org.apache.logging.log4j.core.LogEvent;
30 import org.apache.logging.log4j.message.Message;
31 import org.apache.logging.log4j.util.Supplier;
32
33 /**
34 * ReliabilityStrategy that counts the number of threads that have started to log an event but have not completed yet,
35 * and waits for these threads to finish before allowing the appenders to be stopped.
36 */
37 public class AwaitCompletionReliabilityStrategy implements ReliabilityStrategy {
38 private static final int MAX_RETRIES = 3;
39 private final AtomicInteger counter = new AtomicInteger();
40 private final AtomicBoolean shutdown = new AtomicBoolean(false);
41 private final Lock shutdownLock = new ReentrantLock();
42 private final Condition noLogEvents = shutdownLock.newCondition(); // should only be used when shutdown == true
43 private final LoggerConfig loggerConfig;
44
45 public AwaitCompletionReliabilityStrategy(final LoggerConfig loggerConfig) {
46 this.loggerConfig = Objects.requireNonNull(loggerConfig, "loggerConfig is null");
47 }
48
49 /* (non-Javadoc)
50 * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#log(org.apache.logging.log4j.util.Supplier, java.lang.String, java.lang.String, org.apache.logging.log4j.Marker, org.apache.logging.log4j.Level, org.apache.logging.log4j.message.Message, java.lang.Throwable)
51 */
52 @Override
53 public void log(final Supplier<LoggerConfig> reconfigured, final String loggerName, final String fqcn,
54 final Marker marker, final Level level, final Message data, final Throwable t) {
55
56 final LoggerConfig config = getActiveLoggerConfig(reconfigured);
57 try {
58 config.log(loggerName, fqcn, marker, level, data, t);
59 } finally {
60 config.getReliabilityStrategy().afterLogEvent();
61 }
62 }
63
64 /* (non-Javadoc)
65 * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#log(org.apache.logging.log4j.util.Supplier, org.apache.logging.log4j.core.LogEvent)
66 */
67 @Override
68 public void log(final Supplier<LoggerConfig> reconfigured, final LogEvent event) {
69 final LoggerConfig config = getActiveLoggerConfig(reconfigured);
70 try {
71 config.log(event);
72 } finally {
73 config.getReliabilityStrategy().afterLogEvent();
74 }
75 }
76
77 /* (non-Javadoc)
78 * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#beforeLogEvent(org.apache.logging.log4j.core.config.LoggerConfig, org.apache.logging.log4j.util.Supplier)
79 */
80 @Override
81 public LoggerConfig getActiveLoggerConfig(final Supplier<LoggerConfig> next) {
82 LoggerConfig result = this.loggerConfig;
83 if (!beforeLogEvent()) {
84 result = next.get();
85 return result.getReliabilityStrategy().getActiveLoggerConfig(next);
86 }
87 return result;
88 }
89
90 private boolean beforeLogEvent() {
91 return counter.incrementAndGet() > 0;
92 }
93
94 public void afterLogEvent() {
95 if (counter.decrementAndGet() == 0 && shutdown.get()) {
96 signalCompletionIfShutdown();
97 }
98 }
99
100 private void signalCompletionIfShutdown() {
101 final Lock lock = shutdownLock;
102 lock.lock();
103 try {
104 noLogEvents.signalAll();
105 } finally {
106 lock.unlock();
107 }
108 }
109
110 /* (non-Javadoc)
111 * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#beforeStopAppenders()
112 */
113 @Override
114 public void beforeStopAppenders() {
115 waitForCompletion();
116 }
117
118 /**
119 * Waits for all log events to complete before returning.
120 */
121 private void waitForCompletion() {
122 shutdownLock.lock();
123 try {
124 if (shutdown.compareAndSet(false, true)) {
125 int retries = 0;
126 // repeat while counter is non-zero
127 while (!counter.compareAndSet(0, Integer.MIN_VALUE)) {
128
129 // counter was non-zero
130 if (counter.get() < 0) { // this should not happen
131 return; // but if it does, we are already done
132 }
133 // counter greater than zero, wait for afterLogEvent to decrease count
134 try {
135 noLogEvents.await(retries + 1, TimeUnit.SECONDS);
136 } catch (final InterruptedException ie) {
137 if (++retries > MAX_RETRIES) {
138 break;
139 }
140 }
141 }
142 }
143 } finally {
144 shutdownLock.unlock();
145 }
146 }
147
148 /* (non-Javadoc)
149 * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#beforeStopConfiguration(org.apache.logging.log4j.core.config.Configuration)
150 */
151 @Override
152 public void beforeStopConfiguration(Configuration configuration) {
153 // no action
154 }
155
156 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.config;
18
19 import java.util.Objects;
20
21 import org.apache.logging.log4j.Level;
22 import org.apache.logging.log4j.Marker;
23 import org.apache.logging.log4j.core.LogEvent;
24 import org.apache.logging.log4j.message.Message;
25 import org.apache.logging.log4j.status.StatusLogger;
26 import org.apache.logging.log4j.util.PropertiesUtil;
27 import org.apache.logging.log4j.util.Supplier;
28
29 /**
30 * Reliability strategy that sleeps unconditionally for some time before allowing a Configuration to be stopped.
31 */
32 public class AwaitUnconditionallyReliabilityStrategy implements ReliabilityStrategy {
33
34 private static final long DEFAULT_SLEEP_MILLIS = 5000; // 5 seconds
35 private static final long SLEEP_MILLIS = sleepMillis();
36 private final LoggerConfig loggerConfig;
37
38 public AwaitUnconditionallyReliabilityStrategy(final LoggerConfig loggerConfig) {
39 this.loggerConfig = Objects.requireNonNull(loggerConfig, "loggerConfig is null");
40 }
41
42 private static long sleepMillis() {
43 return PropertiesUtil.getProperties().getLongProperty("log4j.waitMillisBeforeStopOldConfig",
44 DEFAULT_SLEEP_MILLIS);
45 }
46
47 /*
48 * (non-Javadoc)
49 *
50 * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#log(org.apache.logging.log4j.util.Supplier,
51 * java.lang.String, java.lang.String, org.apache.logging.log4j.Marker, org.apache.logging.log4j.Level,
52 * org.apache.logging.log4j.message.Message, java.lang.Throwable)
53 */
54 @Override
55 public void log(Supplier<LoggerConfig> reconfigured, String loggerName, String fqcn, Marker marker, Level level,
56 Message data, Throwable t) {
57 loggerConfig.log(loggerName, fqcn, marker, level, data, t);
58 }
59
60 /*
61 * (non-Javadoc)
62 *
63 * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#log(org.apache.logging.log4j.util.Supplier,
64 * org.apache.logging.log4j.core.LogEvent)
65 */
66 @Override
67 public void log(Supplier<LoggerConfig> reconfigured, LogEvent event) {
68 loggerConfig.log(event);
69 }
70
71 /*
72 * (non-Javadoc)
73 *
74 * @see
75 * org.apache.logging.log4j.core.config.ReliabilityStrategy#beforeLogEvent(org.apache.logging.log4j.core.config.
76 * LoggerConfig, org.apache.logging.log4j.util.Supplier)
77 */
78 @Override
79 public LoggerConfig getActiveLoggerConfig(Supplier<LoggerConfig> next) {
80 return this.loggerConfig;
81 }
82
83 /*
84 * (non-Javadoc)
85 *
86 * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#afterLogEvent()
87 */
88 @Override
89 public void afterLogEvent() {
90 // no action
91 }
92
93 /*
94 * (non-Javadoc)
95 *
96 * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#beforeStopAppenders()
97 */
98 @Override
99 public void beforeStopAppenders() {
100 // no action
101 }
102
103 /* (non-Javadoc)
104 * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#beforeStopConfiguration(org.apache.logging.log4j.core.config.Configuration)
105 */
106 @Override
107 public void beforeStopConfiguration(Configuration configuration) {
108 // only sleep once per configuration stop
109 if (loggerConfig == configuration.getRootLogger()) {
110 try {
111 Thread.sleep(SLEEP_MILLIS);
112 } catch (InterruptedException e) {
113 StatusLogger.getLogger().warn("Sleep before stop configuration was interrupted.");
114 }
115 }
116 }
117
118 }
5757 * @param name The name of the Appender.
5858 * @return the Appender with the specified name or null if the Appender cannot be located.
5959 */
60 Appender getAppender(String name);
60 <T extends Appender> T getAppender(String name);
6161
6262 /**
6363 * Returns a Map containing all the Appenders and their name.
8989 List<String> getPluginPackages();
9090
9191 Map<String, String> getProperties();
92
93 /**
94 * Returns the root Logger.
95 * @return the root Logger.
96 */
97 LoggerConfig getRootLogger();
9298
9399 void addListener(ConfigurationListener listener);
94100
136142 * @return the custom levels defined in the current configuration
137143 */
138144 List<CustomLevelConfig> getCustomLevels();
145
139146 }
3434
3535 import org.apache.logging.log4j.Level;
3636 import org.apache.logging.log4j.Logger;
37 import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
3738 import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
3839 import org.apache.logging.log4j.core.config.plugins.util.PluginType;
3940 import org.apache.logging.log4j.core.lookup.Interpolator;
4041 import org.apache.logging.log4j.core.lookup.StrSubstitutor;
4142 import org.apache.logging.log4j.core.util.FileUtils;
4243 import org.apache.logging.log4j.core.util.Loader;
44 import org.apache.logging.log4j.core.util.NetUtils;
4345 import org.apache.logging.log4j.core.util.ReflectionUtil;
4446 import org.apache.logging.log4j.status.StatusLogger;
4547 import org.apache.logging.log4j.util.LoaderUtil;
4648 import org.apache.logging.log4j.util.PropertiesUtil;
49 import org.apache.logging.log4j.util.Strings;
4750
4851 /**
4952 * Factory class for parsed {@link Configuration} objects from a configuration file.
6467 * </ol>
6568 *
6669 * If the ConfigurationFactory that was added returns null on a call to
67 * getConfiguration the any other ConfigurationFactories found as plugins will
70 * getConfiguration then any other ConfigurationFactories found as plugins will
6871 * be called in their respective order. DefaultConfiguration is always called
6972 * last if no configuration has been returned.
7073 */
71 public abstract class ConfigurationFactory {
74 public abstract class ConfigurationFactory extends ConfigurationBuilderFactory {
7275 /**
7376 * Allow the ConfigurationFactory class to be specified as a system property.
7477 */
131134 LOCK.lock();
132135 try {
133136 if (factories == null) {
134 final List<ConfigurationFactory> list = new ArrayList<ConfigurationFactory>();
137 final List<ConfigurationFactory> list = new ArrayList<>();
135138 final String factoryClass = PropertiesUtil.getProperties().getStringProperty(CONFIGURATION_FACTORY_PROPERTY);
136139 if (factoryClass != null) {
137140 addFactory(list, factoryClass);
140143 manager.collectPlugins();
141144 final Map<String, PluginType<?>> plugins = manager.getPlugins();
142145 final List<Class<? extends ConfigurationFactory>> ordered =
143 new ArrayList<Class<? extends ConfigurationFactory>>(plugins.size());
146 new ArrayList<>(plugins.size());
144147 for (final PluginType<?> type : plugins.values()) {
145148 try {
146149 ordered.add(type.getPluginClass().asSubclass(ConfigurationFactory.class));
386389 public Configuration getConfiguration(final String name, final URI configLocation) {
387390
388391 if (configLocation == null) {
389 final String config = this.substitutor.replace(
390 PropertiesUtil.getProperties().getStringProperty(CONFIGURATION_FILE_PROPERTY));
391 if (config != null) {
392 final String configLocationStr = this.substitutor.replace(PropertiesUtil.getProperties()
393 .getStringProperty(CONFIGURATION_FILE_PROPERTY));
394 if (configLocationStr != null) {
392395 ConfigurationSource source = null;
393396 try {
394 source = getInputFromUri(FileUtils.getCorrectedFilePathUri(config));
397 source = getInputFromUri(NetUtils.toURI(configLocationStr));
395398 } catch (final Exception ex) {
396399 // Ignore the error and try as a String.
397400 LOGGER.catching(Level.DEBUG, ex);
398401 }
399402 if (source == null) {
400403 final ClassLoader loader = LoaderUtil.getThreadContextClassLoader();
401 source = getInputFromString(config, loader);
404 source = getInputFromString(configLocationStr, loader);
402405 }
403406 if (source != null) {
404 for (final ConfigurationFactory factory : factories) {
407 for (final ConfigurationFactory factory : getFactories()) {
405408 final String[] types = factory.getSupportedTypes();
406409 if (types != null) {
407410 for (final String type : types) {
408 if (type.equals("*") || config.endsWith(type)) {
409 final Configuration c = factory.getConfiguration(source);
410 if (c != null) {
411 return c;
411 if (type.equals("*") || configLocationStr.endsWith(type)) {
412 final Configuration config = factory.getConfiguration(source);
413 if (config != null) {
414 return config;
412415 }
413416 }
414417 }
415418 }
416419 }
417420 }
421 } else {
422 for (final ConfigurationFactory factory : getFactories()) {
423 final String[] types = factory.getSupportedTypes();
424 if (types != null) {
425 for (final String type : types) {
426 if (type.equals("*")) {
427 final Configuration config = factory.getConfiguration(name, configLocation);
428 if (config != null) {
429 return config;
430 }
431 }
432 }
433 }
434 }
418435 }
419436 } else {
420 for (final ConfigurationFactory factory : factories) {
437 // configLocation != null
438 final String configLocationStr = configLocation.toString();
439 for (final ConfigurationFactory factory : getFactories()) {
421440 final String[] types = factory.getSupportedTypes();
422441 if (types != null) {
423442 for (final String type : types) {
424 if (type.equals("*") || configLocation.toString().endsWith(type)) {
443 if (type.equals("*") || configLocationStr.endsWith(type)) {
425444 final Configuration config = factory.getConfiguration(name, configLocation);
426445 if (config != null) {
427446 return config;
450469 }
451470
452471 private Configuration getConfiguration(final boolean isTest, final String name) {
453 final boolean named = name != null && name.length() > 0;
472 final boolean named = Strings.isNotEmpty(name);
454473 final ClassLoader loader = LoaderUtil.getThreadContextClassLoader();
455 for (final ConfigurationFactory factory : factories) {
474 for (final ConfigurationFactory factory : getFactories()) {
456475 String configName;
457476 final String prefix = isTest ? TEST_PREFIX : DEFAULT_PREFIX;
458477 final String [] types = factory.getSupportedTypes();
484503 public Configuration getConfiguration(final ConfigurationSource source) {
485504 if (source != null) {
486505 final String config = source.getLocation();
487 for (final ConfigurationFactory factory : factories) {
506 for (final ConfigurationFactory factory : getFactories()) {
488507 final String[] types = factory.getSupportedTypes();
489508 if (types != null) {
490509 for (final String type : types) {
505524 return null;
506525 }
507526 }
527
528 static List<ConfigurationFactory> getFactories() {
529 return factories;
530 }
508531 }
2424 * Called to determine if the configuration has changed.
2525 */
2626 void checkConfiguration();
27
28 /**
29 * Determines how to log events reliably during or after a configuration change.
30 *
31 * @param loggerConfig the LoggerConfig the resulting {@code ReliabilityStrategy} is associated with
32 * @return a ReliabilityStrategy that helps the specified LoggerConfig to log events reliably during or after a
33 * configuration change
34 */
35 ReliabilityStrategy getReliabilityStrategy(final LoggerConfig loggerConfig);
2736 }
2323 import java.io.IOException;
2424 import java.io.InputStream;
2525 import java.net.URL;
26
27 import org.apache.logging.log4j.core.util.Assert;
26 import java.util.Objects;
2827
2928 /**
3029 * Represents the source for the logging configuration.
7069 }
7170
7271 private ConfigurationSource(final byte[] data) {
73 this.data = Assert.requireNonNull(data, "data is null");
72 this.data = Objects.requireNonNull(data, "data is null");
7473 this.stream = new ByteArrayInputStream(data);
7574 this.file = null;
7675 this.url = null;
8584 * @param file the file where the input stream originated
8685 */
8786 public ConfigurationSource(final InputStream stream, final File file) {
88 this.stream = Assert.requireNonNull(stream, "stream is null");
89 this.file = Assert.requireNonNull(file, "file is null");
87 this.stream = Objects.requireNonNull(stream, "stream is null");
88 this.file = Objects.requireNonNull(file, "file is null");
9089 this.location = file.getAbsolutePath();
9190 this.url = null;
9291 this.data = null;
10099 * @param url the URL where the input stream originated
101100 */
102101 public ConfigurationSource(final InputStream stream, final URL url) {
103 this.stream = Assert.requireNonNull(stream, "stream is null");
104 this.url = Assert.requireNonNull(url, "URL is null");
102 this.stream = Objects.requireNonNull(stream, "stream is null");
103 this.url = Objects.requireNonNull(url, "URL is null");
105104 this.location = url.toString();
106105 this.file = null;
107106 this.data = null;
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config;
17
18 import java.net.URI;
19 import java.net.URISyntaxException;
20
21 import org.apache.logging.log4j.LogManager;
22 import org.apache.logging.log4j.Logger;
23 import org.apache.logging.log4j.core.LoggerContext;
24 import org.apache.logging.log4j.core.impl.Log4jContextFactory;
25 import org.apache.logging.log4j.core.util.FileUtils;
26 import org.apache.logging.log4j.spi.LoggerContextFactory;
27 import org.apache.logging.log4j.status.StatusLogger;
28
29 /**
30 * Initializes and configure the Logging system. This class provides several ways to construct a LoggerContext using
31 * the location of a configuration file, a context name, and various optional parameters.
32 */
33 public final class Configurator {
34
35 private static final Logger LOGGER = StatusLogger.getLogger();
36
37 private static final String FQCN = Configurator.class.getName();
38
39 private Configurator() {
40 }
41
42 /**
43 * Initializes the Logging Context.
44 * @param name The Context name.
45 * @param loader The ClassLoader for the Context (or null).
46 * @param configLocation The configuration for the logging context.
47 * @return The LoggerContext.
48 */
49 public static LoggerContext initialize(final String name, final ClassLoader loader, final String configLocation) {
50 return initialize(name, loader, configLocation, null);
51
52 }
53
54 /**
55 * Initializes the Logging Context.
56 * @param name The Context name.
57 * @param loader The ClassLoader for the Context (or null).
58 * @param configLocation The configuration for the logging context.
59 * @param externalContext The external context to be attached to the LoggerContext
60 * @return The LoggerContext.
61 */
62 public static LoggerContext initialize(final String name, final ClassLoader loader, final String configLocation,
63 final Object externalContext) {
64
65 try {
66 final URI uri = configLocation == null ? null : FileUtils.getCorrectedFilePathUri(configLocation);
67 return initialize(name, loader, uri, externalContext);
68 } catch (final URISyntaxException ex) {
69 LOGGER.error("There was a problem parsing the configuration location [{}].", configLocation, ex);
70 }
71 return null;
72 }
73
74 /**
75 * Initializes the Logging Context.
76 * @param name The Context name.
77 * @param configLocation The configuration for the logging context.
78 * @return The LoggerContext.
79 */
80 public static LoggerContext initialize(final String name, final String configLocation) {
81 return initialize(name, null, configLocation);
82 }
83
84 /**
85 * Initializes the Logging Context.
86 * @param name The Context name.
87 * @param loader The ClassLoader for the Context (or null).
88 * @param configLocation The configuration for the logging context.
89 * @return The LoggerContext.
90 */
91 public static LoggerContext initialize(final String name, final ClassLoader loader, final URI configLocation) {
92 return initialize(name, loader, configLocation, null);
93 }
94
95 /**
96 * Initializes the Logging Context.
97 * @param name The Context name.
98 * @param loader The ClassLoader for the Context (or null).
99 * @param configLocation The configuration for the logging context.
100 * @param externalContext The external context to be attached to the LoggerContext
101 * @return The LoggerContext.
102 */
103 public static LoggerContext initialize(final String name, final ClassLoader loader, final URI configLocation,
104 final Object externalContext) {
105
106 try {
107 final Log4jContextFactory factory = getFactory();
108 return factory == null ? null :
109 factory.getContext(FQCN, loader, externalContext, false, configLocation, name);
110 } catch (final Exception ex) {
111 LOGGER.error("There was a problem initializing the LoggerContext [{}] using configuration at [{}].",
112 name, configLocation, ex);
113 }
114 return null;
115 }
116
117 /**
118 * Initializes the Logging Context.
119 * @param loader The ClassLoader for the Context (or null).
120 * @param source The InputSource for the configuration.
121 * @return The LoggerContext.
122 */
123 public static LoggerContext initialize(final ClassLoader loader,
124 final ConfigurationSource source) {
125 return initialize(loader, source, null);
126 }
127
128 /**
129 * Initializes the Logging Context.
130 * @param loader The ClassLoader for the Context (or null).
131 * @param source The InputSource for the configuration.
132 * @param externalContext The external context to be attached to the LoggerContext.
133 * @return The LoggerContext.
134 */
135
136 public static LoggerContext initialize(final ClassLoader loader,
137 final ConfigurationSource source,
138 final Object externalContext)
139 {
140
141 try {
142 final Log4jContextFactory factory = getFactory();
143 return factory == null ? null :
144 factory.getContext(FQCN, loader, externalContext, false, source);
145 } catch (final Exception ex) {
146 LOGGER.error("There was a problem obtaining a LoggerContext using the configuration source [{}]", source, ex);
147 }
148 return null;
149 }
150
151 private static Log4jContextFactory getFactory() {
152 final LoggerContextFactory factory = LogManager.getFactory();
153 if (factory instanceof Log4jContextFactory) {
154 return (Log4jContextFactory) factory;
155 } else if (factory != null) {
156 LOGGER.error("LogManager returned an instance of {} which does not implement {}. Unable to initialize Log4j.",
157 factory.getClass().getName(), Log4jContextFactory.class.getName());
158 return null;
159 } else {
160 LOGGER.fatal("LogManager did not return a LoggerContextFactory. This indicates something has gone terribly wrong!");
161 return null;
162 }
163 }
164
165 /**
166 * Shuts down the given logging context.
167 * @param ctx the logging context to shut down, may be null.
168 */
169 public static void shutdown(final LoggerContext ctx) {
170 if (ctx != null) {
171 ctx.stop();
172 }
173 }
174 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config;
17
18 import java.net.URI;
19 import java.util.Map;
20
21 import org.apache.logging.log4j.Level;
22 import org.apache.logging.log4j.LogManager;
23 import org.apache.logging.log4j.Logger;
24 import org.apache.logging.log4j.core.LoggerContext;
25 import org.apache.logging.log4j.core.impl.Log4jContextFactory;
26 import org.apache.logging.log4j.core.util.NetUtils;
27 import org.apache.logging.log4j.spi.LoggerContextFactory;
28 import org.apache.logging.log4j.status.StatusLogger;
29 import org.apache.logging.log4j.util.Strings;
30
31 /**
32 * Initializes and configure the Logging system. This class provides several ways to construct a LoggerContext using
33 * the location of a configuration file, a context name, and various optional parameters.
34 */
35 public final class Configurator {
36
37 private static final String FQCN = Configurator.class.getName();
38
39 private static final Logger LOGGER = StatusLogger.getLogger();
40
41 private static Log4jContextFactory getFactory() {
42 final LoggerContextFactory factory = LogManager.getFactory();
43 if (factory instanceof Log4jContextFactory) {
44 return (Log4jContextFactory) factory;
45 } else if (factory != null) {
46 LOGGER.error("LogManager returned an instance of {} which does not implement {}. Unable to initialize Log4j.",
47 factory.getClass().getName(), Log4jContextFactory.class.getName());
48 return null;
49 } else {
50 LOGGER.fatal("LogManager did not return a LoggerContextFactory. This indicates something has gone terribly wrong!");
51 return null;
52 }
53 }
54
55 /**
56 * Initializes the Logging Context.
57 * @param loader The ClassLoader for the Context (or null).
58 * @param source The InputSource for the configuration.
59 * @return The LoggerContext.
60 */
61 public static LoggerContext initialize(final ClassLoader loader,
62 final ConfigurationSource source) {
63 return initialize(loader, source, null);
64 }
65
66 /**
67 * Initializes the Logging Context.
68 * @param loader The ClassLoader for the Context (or null).
69 * @param source The InputSource for the configuration.
70 * @param externalContext The external context to be attached to the LoggerContext.
71 * @return The LoggerContext.
72 */
73
74 public static LoggerContext initialize(final ClassLoader loader,
75 final ConfigurationSource source,
76 final Object externalContext)
77 {
78
79 try {
80 final Log4jContextFactory factory = getFactory();
81 return factory == null ? null :
82 factory.getContext(FQCN, loader, externalContext, false, source);
83 } catch (final Exception ex) {
84 LOGGER.error("There was a problem obtaining a LoggerContext using the configuration source [{}]", source, ex);
85 }
86 return null;
87 }
88
89 /**
90 * Initializes the Logging Context.
91 * @param name The Context name.
92 * @param loader The ClassLoader for the Context (or null).
93 * @param configLocation The configuration for the logging context.
94 * @return The LoggerContext or null if an error occurred (check the status logger).
95 */
96 public static LoggerContext initialize(final String name, final ClassLoader loader, final String configLocation) {
97 return initialize(name, loader, configLocation, null);
98
99 }
100
101 /**
102 * Initializes the Logging Context.
103 * @param name The Context name.
104 * @param loader The ClassLoader for the Context (or null).
105 * @param configLocation The configuration for the logging context (or null, or blank).
106 * @param externalContext The external context to be attached to the LoggerContext
107 * @return The LoggerContext or null if an error occurred (check the status logger).
108 */
109 public static LoggerContext initialize(final String name, final ClassLoader loader, final String configLocation,
110 final Object externalContext) {
111 final URI uri = Strings.isBlank(configLocation) ? null : NetUtils.toURI(configLocation);
112 return initialize(name, loader, uri, externalContext);
113 }
114
115 /**
116 * Initializes the Logging Context.
117 * @param name The Context name.
118 * @param loader The ClassLoader for the Context (or null).
119 * @param configLocation The configuration for the logging context.
120 * @return The LoggerContext.
121 */
122 public static LoggerContext initialize(final String name, final ClassLoader loader, final URI configLocation) {
123 return initialize(name, loader, configLocation, null);
124 }
125
126 /**
127 * Initializes the Logging Context.
128 * @param name The Context name.
129 * @param loader The ClassLoader for the Context (or null).
130 * @param configLocation The configuration for the logging context (or null).
131 * @param externalContext The external context to be attached to the LoggerContext
132 * @return The LoggerContext.
133 */
134 public static LoggerContext initialize(final String name, final ClassLoader loader, final URI configLocation,
135 final Object externalContext) {
136
137 try {
138 final Log4jContextFactory factory = getFactory();
139 return factory == null ? null :
140 factory.getContext(FQCN, loader, externalContext, false, configLocation, name);
141 } catch (final Exception ex) {
142 LOGGER.error("There was a problem initializing the LoggerContext [{}] using configuration at [{}].",
143 name, configLocation, ex);
144 }
145 return null;
146 }
147
148 /**
149 * Initializes the Logging Context.
150 * @param name The Context name.
151 * @param configLocation The configuration for the logging context.
152 * @return The LoggerContext or null if an error occurred (check the status logger).
153 */
154 public static LoggerContext initialize(final String name, final String configLocation) {
155 return initialize(name, null, configLocation);
156 }
157
158 /**
159 * Initializes the Logging Context.
160 * @param configuration The Configuration.
161 * @return The LoggerContext.
162 */
163 public static LoggerContext initialize(Configuration configuration) {
164 return initialize(null, configuration, null);
165 }
166
167 /**
168 * Initializes the Logging Context.
169 * @param loader The ClassLoader.
170 * @param configuration The Configuration.
171 * @return The LoggerContext.
172 */
173 public static LoggerContext initialize(final ClassLoader loader, Configuration configuration) {
174 return initialize(loader, configuration, null);
175 }
176
177 /**
178 * Initializes the Logging Context.
179 * @param loader The ClassLoader.
180 * @param configuration The Configuration.
181 * @param externalContext - The external context to be attached to the LoggerContext.
182 * @return The LoggerContext.
183 */
184 public static LoggerContext initialize(final ClassLoader loader, Configuration configuration, final Object externalContext) {
185 try {
186 final Log4jContextFactory factory = getFactory();
187 return factory == null ? null :
188 factory.getContext(FQCN, loader, externalContext, false, configuration);
189 } catch (final Exception ex) {
190 LOGGER.error("There was a problem initializing the LoggerContext using configuration {}",
191 configuration.getName(), ex);
192 }
193 return null;
194 }
195
196 /**
197 * Sets the levels of <code>parentLogger</code> and all 'child' loggers to the given <code>level</code>.
198 * @param parentLogger the parent logger
199 * @param level the new level
200 */
201 public static void setAllLevels(final String parentLogger, final Level level) {
202 // 1) get logger config
203 // 2) if exact match, use it, if not, create it.
204 // 3) set level on logger config
205 // 4) update child logger configs with level
206 // 5) update loggers
207 final LoggerContext loggerContext = LoggerContext.getContext(false);
208 final Configuration config = loggerContext.getConfiguration();
209 boolean set = setLevel(parentLogger, level, config);
210 for (final Map.Entry<String, LoggerConfig> entry : config.getLoggers().entrySet()) {
211 if (entry.getKey().startsWith(parentLogger)) {
212 set |= setLevel(entry.getValue(), level);
213 }
214 }
215 if (set) {
216 loggerContext.updateLoggers();
217 }
218 }
219
220 private static boolean setLevel(final LoggerConfig loggerConfig, final Level level) {
221 final boolean set = !loggerConfig.getLevel().equals(level);
222 if (set) {
223 loggerConfig.setLevel(level);
224 }
225 return set;
226 }
227
228 /**
229 * Sets logger levels.
230 *
231 * @param levelMap
232 * a levelMap where keys are level names and values are new
233 * Levels.
234 */
235 public static void setLevel(final Map<String, Level> levelMap) {
236 final LoggerContext loggerContext = LoggerContext.getContext(false);
237 final Configuration config = loggerContext.getConfiguration();
238 boolean set = false;
239 for (final Map.Entry<String, Level> entry : levelMap.entrySet()) {
240 final String loggerName = entry.getKey();
241 final Level level = entry.getValue();
242 set |= setLevel(loggerName, level, config);
243 }
244 if (set) {
245 loggerContext.updateLoggers();
246 }
247 }
248
249 /**
250 * Sets a logger's level.
251 *
252 * @param loggerName
253 * the logger name
254 * @param level
255 * the new level
256 */
257 public static void setLevel(final String loggerName, final Level level) {
258 final LoggerContext loggerContext = LoggerContext.getContext(false);
259 if (Strings.isEmpty(loggerName)) {
260 setRootLevel(level);
261 } else {
262 if (setLevel(loggerName, level, loggerContext.getConfiguration())) {
263 loggerContext.updateLoggers();
264 }
265 }
266 }
267
268 private static boolean setLevel(final String loggerName, final Level level, final Configuration config) {
269 boolean set;
270 LoggerConfig loggerConfig = config.getLoggerConfig(loggerName);
271 if (!loggerName.equals(loggerConfig.getName())) {
272 // TODO Should additivity be inherited?
273 loggerConfig = new LoggerConfig(loggerName, level, true);
274 config.addLogger(loggerName, loggerConfig);
275 loggerConfig.setLevel(level);
276 set = true;
277 } else {
278 set = setLevel(loggerConfig, level);
279 }
280 return set;
281 }
282
283 /**
284 * Sets the root logger's level.
285 *
286 * @param level
287 * the new level
288 */
289 public static void setRootLevel(final Level level) {
290 final LoggerContext loggerContext = LoggerContext.getContext(false);
291 final LoggerConfig loggerConfig = loggerContext.getConfiguration().getRootLogger();
292 if (!loggerConfig.getLevel().equals(level)) {
293 loggerConfig.setLevel(level);
294 loggerContext.updateLoggers();
295 }
296 }
297
298 /**
299 * Shuts down the given logging context.
300 * @param ctx the logging context to shut down, may be null.
301 */
302 public static void shutdown(final LoggerContext ctx) {
303 if (ctx != null) {
304 ctx.stop();
305 }
306 }
307
308 private Configurator() {
309 // empty
310 }
311 }
1515 */
1616 package org.apache.logging.log4j.core.config;
1717
18 import java.util.Objects;
19
1820 import org.apache.logging.log4j.Level;
1921 import org.apache.logging.log4j.core.config.plugins.Plugin;
2022 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
2123 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
22 import org.apache.logging.log4j.core.util.Assert;
2324 import org.apache.logging.log4j.status.StatusLogger;
2425
2526 /**
3233 private final int intLevel;
3334
3435 private CustomLevelConfig(final String levelName, final int intLevel) {
35 this.levelName = Assert.requireNonNull(levelName, "levelName is null");
36 this.levelName = Objects.requireNonNull(levelName, "levelName is null");
3637 this.intLevel = intLevel;
3738 }
3839
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.config;
18
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.List;
22
23 import org.apache.logging.log4j.core.config.plugins.Plugin;
24 import org.apache.logging.log4j.core.config.plugins.PluginElement;
25 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
26
27 /**
28 * Container for CustomLevelConfig objects.
29 */
30 @Plugin(name = "CustomLevels", category = "Core", printObject = true)
31 public final class CustomLevels {
32
33 private final List<CustomLevelConfig> customLevels;
34
35 private CustomLevels(final CustomLevelConfig[] customLevels) {
36 this.customLevels = new ArrayList<CustomLevelConfig>(Arrays.asList(customLevels));
37 }
38
39 /**
40 * Create a CustomLevels object to contain all the CustomLevelConfigs.
41 *
42 * @param customLevels An array of CustomLevelConfigs.
43 * @return A CustomLevels object.
44 */
45 @PluginFactory
46 public static CustomLevels createCustomLevels(//
47 @PluginElement("CustomLevels") final CustomLevelConfig[] customLevels) {
48 return new CustomLevels(customLevels == null ? new CustomLevelConfig[0] : customLevels);
49 }
50
51 /**
52 * Returns a list of the {@code CustomLevelConfig} objects created during configuration.
53 * @return the configured custom levels
54 */
55 public List<CustomLevelConfig> getCustomLevels() {
56 return customLevels;
57 }
58 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.config;
18
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.List;
22
23 import org.apache.logging.log4j.core.config.plugins.Plugin;
24 import org.apache.logging.log4j.core.config.plugins.PluginElement;
25 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
26
27 /**
28 * Container for CustomLevelConfig objects.
29 */
30 @Plugin(name = "CustomLevels", category = "Core", printObject = true)
31 public final class CustomLevels {
32
33 private final List<CustomLevelConfig> customLevels;
34
35 private CustomLevels(final CustomLevelConfig[] customLevels) {
36 this.customLevels = new ArrayList<>(Arrays.asList(customLevels));
37 }
38
39 /**
40 * Create a CustomLevels object to contain all the CustomLevelConfigs.
41 *
42 * @param customLevels An array of CustomLevelConfigs.
43 * @return A CustomLevels object.
44 */
45 @PluginFactory
46 public static CustomLevels createCustomLevels(//
47 @PluginElement("CustomLevels") final CustomLevelConfig[] customLevels) {
48 return new CustomLevels(customLevels == null ? new CustomLevelConfig[0] : customLevels);
49 }
50
51 /**
52 * Returns a list of the {@code CustomLevelConfig} objects created during configuration.
53 * @return the configured custom levels
54 */
55 public List<CustomLevelConfig> getCustomLevels() {
56 return customLevels;
57 }
58 }
2727 public void checkConfiguration() {
2828 // do nothing
2929 }
30
31 /* (non-Javadoc)
32 * @see org.apache.logging.log4j.core.config.ReliabilityStrategyFactory#getReliabilityStrategy(org.apache.logging.log4j.core.config.LoggerConfig)
33 */
34 @Override
35 public ReliabilityStrategy getReliabilityStrategy(LoggerConfig loggerConfig) {
36 return ReliabilityStrategyFactory.getReliabilityStrategy(loggerConfig);
37 }
3038 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.config;
18
19 import java.util.Objects;
20
21 import org.apache.logging.log4j.Level;
22 import org.apache.logging.log4j.Marker;
23 import org.apache.logging.log4j.core.LogEvent;
24 import org.apache.logging.log4j.message.Message;
25 import org.apache.logging.log4j.util.Supplier;
26
27 /**
28 * Reliability strategy that assumes reconfigurations will never take place.
29 */
30 public class DefaultReliabilityStrategy implements ReliabilityStrategy {
31
32 private final LoggerConfig loggerConfig;
33
34 public DefaultReliabilityStrategy(final LoggerConfig loggerConfig) {
35 this.loggerConfig = Objects.requireNonNull(loggerConfig, "loggerConfig is null");
36 }
37
38 /*
39 * (non-Javadoc)
40 *
41 * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#log(org.apache.logging.log4j.util.Supplier,
42 * java.lang.String, java.lang.String, org.apache.logging.log4j.Marker, org.apache.logging.log4j.Level,
43 * org.apache.logging.log4j.message.Message, java.lang.Throwable)
44 */
45 @Override
46 public void log(Supplier<LoggerConfig> reconfigured, String loggerName, String fqcn, Marker marker, Level level,
47 Message data, Throwable t) {
48 loggerConfig.log(loggerName, fqcn, marker, level, data, t);
49 }
50
51 /*
52 * (non-Javadoc)
53 *
54 * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#log(org.apache.logging.log4j.util.Supplier,
55 * org.apache.logging.log4j.core.LogEvent)
56 */
57 @Override
58 public void log(Supplier<LoggerConfig> reconfigured, LogEvent event) {
59 loggerConfig.log(event);
60 }
61
62 /*
63 * (non-Javadoc)
64 *
65 * @see
66 * org.apache.logging.log4j.core.config.ReliabilityStrategy#beforeLogEvent(org.apache.logging.log4j.core.config.
67 * LoggerConfig, org.apache.logging.log4j.util.Supplier)
68 */
69 @Override
70 public LoggerConfig getActiveLoggerConfig(Supplier<LoggerConfig> next) {
71 return this.loggerConfig;
72 }
73
74 /*
75 * (non-Javadoc)
76 *
77 * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#afterLogEvent()
78 */
79 @Override
80 public void afterLogEvent() {
81 // no action
82 }
83
84 /*
85 * (non-Javadoc)
86 *
87 * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#beforeStopAppenders()
88 */
89 @Override
90 public void beforeStopAppenders() {
91 // no action
92 }
93
94 /* (non-Javadoc)
95 * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#beforeStopConfiguration(org.apache.logging.log4j.core.config.Configuration)
96 */
97 @Override
98 public void beforeStopConfiguration(Configuration configuration) {
99 // no action
100 }
101
102 }
1717
1818 import java.io.File;
1919 import java.util.List;
20 import java.util.concurrent.TimeUnit;
2021 import java.util.concurrent.atomic.AtomicInteger;
2122 import java.util.concurrent.locks.Lock;
2223 import java.util.concurrent.locks.ReentrantLock;
2930
3031 private static final int MASK = 0x0f;
3132
32 private static final int MIN_INTERVAL = 5;
33
34 private static final int MILLIS_PER_SECOND = 1000;
33 static final int MIN_INTERVAL = 5;
3534
3635 private final File file;
3736
38 private long lastModified;
37 private volatile long lastModified;
3938
4039 private final List<ConfigurationListener> listeners;
4140
42 private final int interval;
41 private final long intervalNano;
4342
44 private long nextCheck;
43 private volatile long nextCheck;
4544
4645 private final AtomicInteger counter = new AtomicInteger(0);
4746
5453 * @param reconfigurable The Configuration that can be reconfigured.
5554 * @param file The File to monitor.
5655 * @param listeners The List of ConfigurationListeners to notify upon a change.
57 * @param interval The monitor interval in seconds. The minimum interval is 5 seconds.
56 * @param intervalSeconds The monitor interval in seconds. The minimum interval is 5 seconds.
5857 */
5958 public FileConfigurationMonitor(final Reconfigurable reconfigurable, final File file,
6059 final List<ConfigurationListener> listeners,
61 final int interval) {
60 final int intervalSeconds) {
6261 this.reconfigurable = reconfigurable;
6362 this.file = file;
6463 this.lastModified = file.lastModified();
6564 this.listeners = listeners;
66 this.interval = (interval < MIN_INTERVAL ? MIN_INTERVAL : interval) * MILLIS_PER_SECOND;
67 this.nextCheck = System.currentTimeMillis() + interval;
65 this.intervalNano = TimeUnit.SECONDS.toNanos(Math.max(intervalSeconds, MIN_INTERVAL));
66 this.nextCheck = System.nanoTime() + this.intervalNano;
6867 }
6968
7069 /**
7271 */
7372 @Override
7473 public void checkConfiguration() {
75 final long current = System.currentTimeMillis();
76 if (((counter.incrementAndGet() & MASK) == 0) && (current >= nextCheck)) {
74 final long current;
75 if (((counter.incrementAndGet() & MASK) == 0) && ((current = System.nanoTime()) - nextCheck >= 0)) {
7776 LOCK.lock();
7877 try {
79 nextCheck = current + interval;
80 if (file.lastModified() > lastModified) {
81 lastModified = file.lastModified();
78 nextCheck = current + intervalNano;
79 final long currentLastModified = file.lastModified();
80 if (currentLastModified > lastModified) {
81 lastModified = currentLastModified;
8282 for (final ConfigurationListener listener : listeners) {
8383 final Thread thread = new Thread(new ReconfigurationWorker(listener, reconfigurable));
8484 thread.setDaemon(true);
9191 }
9292 }
9393
94 private class ReconfigurationWorker implements Runnable {
94 private static class ReconfigurationWorker implements Runnable {
9595
9696 private final ConfigurationListener listener;
9797 private final Reconfigurable reconfigurable;
106106 listener.onChange(reconfigurable);
107107 }
108108 }
109
110 /* (non-Javadoc)
111 * @see org.apache.logging.log4j.core.config.ReliabilityStrategyFactory#getReliabilityStrategy(org.apache.logging.log4j.core.config.LoggerConfig)
112 */
113 @Override
114 public ReliabilityStrategy getReliabilityStrategy(LoggerConfig loggerConfig) {
115 return ReliabilityStrategyFactory.getReliabilityStrategy(loggerConfig);
116 }
109117 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.config;
18
19 import java.util.Objects;
20 import java.util.concurrent.locks.ReadWriteLock;
21 import java.util.concurrent.locks.ReentrantReadWriteLock;
22
23 import org.apache.logging.log4j.Level;
24 import org.apache.logging.log4j.Marker;
25 import org.apache.logging.log4j.core.LogEvent;
26 import org.apache.logging.log4j.message.Message;
27 import org.apache.logging.log4j.util.Supplier;
28
29 /**
30 * ReliabilityStrategy that uses read/write locks to prevent the LoggerConfig from stopping while it is in use.
31 */
32 public class LockingReliabilityStrategy implements ReliabilityStrategy {
33 private final LoggerConfig loggerConfig;
34 private final ReadWriteLock reconfigureLock = new ReentrantReadWriteLock();
35 private volatile boolean isStopping = false;
36
37 public LockingReliabilityStrategy(final LoggerConfig loggerConfig) {
38 this.loggerConfig = Objects.requireNonNull(loggerConfig, "loggerConfig was null");
39 }
40
41 /* (non-Javadoc)
42 * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#log(org.apache.logging.log4j.util.Supplier, java.lang.String, java.lang.String, org.apache.logging.log4j.Marker, org.apache.logging.log4j.Level, org.apache.logging.log4j.message.Message, java.lang.Throwable)
43 */
44 @Override
45 public void log(final Supplier<LoggerConfig> reconfigured, final String loggerName, final String fqcn,
46 final Marker marker, final Level level, final Message data, final Throwable t) {
47
48 final LoggerConfig config = getActiveLoggerConfig(reconfigured);
49 try {
50 config.log(loggerName, fqcn, marker, level, data, t);
51 } finally {
52 config.getReliabilityStrategy().afterLogEvent();
53 }
54 }
55
56 /* (non-Javadoc)
57 * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#log(org.apache.logging.log4j.util.Supplier, org.apache.logging.log4j.core.LogEvent)
58 */
59 @Override
60 public void log(final Supplier<LoggerConfig> reconfigured, final LogEvent event) {
61 final LoggerConfig config = getActiveLoggerConfig(reconfigured);
62 try {
63 config.log(event);
64 } finally {
65 config.getReliabilityStrategy().afterLogEvent();
66 }
67 }
68
69 /* (non-Javadoc)
70 * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#beforeLogEvent(org.apache.logging.log4j.core.config.LoggerConfig, org.apache.logging.log4j.util.Supplier)
71 */
72 @Override
73 public LoggerConfig getActiveLoggerConfig(final Supplier<LoggerConfig> next) {
74 LoggerConfig result = this.loggerConfig;
75 if (!beforeLogEvent()) {
76 result = next.get();
77 return result.getReliabilityStrategy().getActiveLoggerConfig(next);
78 }
79 return result;
80 }
81
82 private boolean beforeLogEvent() {
83 reconfigureLock.readLock().lock();
84 if (isStopping) {
85 reconfigureLock.readLock().unlock();
86 return false;
87 }
88 return true;
89 }
90
91 public void afterLogEvent() {
92 reconfigureLock.readLock().unlock();
93 }
94
95 /* (non-Javadoc)
96 * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#beforeStopAppenders()
97 */
98 @Override
99 public void beforeStopAppenders() {
100 reconfigureLock.writeLock().lock();
101 try {
102 isStopping = true;
103 } finally {
104 reconfigureLock.writeLock().unlock();
105 }
106 }
107
108 /* (non-Javadoc)
109 * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#beforeStopConfiguration(org.apache.logging.log4j.core.config.Configuration)
110 */
111 @Override
112 public void beforeStopConfiguration(Configuration configuration) {
113 // no action
114 }
115
116 }
1717
1818 import java.util.ArrayList;
1919 import java.util.Arrays;
20 import java.util.Collection;
2120 import java.util.Collections;
2221 import java.util.HashMap;
23 import java.util.Iterator;
2422 import java.util.List;
2523 import java.util.Map;
26 import java.util.concurrent.ConcurrentHashMap;
27 import java.util.concurrent.TimeUnit;
28 import java.util.concurrent.atomic.AtomicBoolean;
29 import java.util.concurrent.atomic.AtomicInteger;
30 import java.util.concurrent.locks.Condition;
31 import java.util.concurrent.locks.Lock;
32 import java.util.concurrent.locks.ReentrantLock;
24 import java.util.Objects;
25 import java.util.Set;
26 import java.util.concurrent.CopyOnWriteArraySet;
3327
3428 import org.apache.logging.log4j.Level;
3529 import org.apache.logging.log4j.LogManager;
4539 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
4640 import org.apache.logging.log4j.core.filter.AbstractFilterable;
4741 import org.apache.logging.log4j.core.impl.DefaultLogEventFactory;
42 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
4843 import org.apache.logging.log4j.core.impl.LogEventFactory;
4944 import org.apache.logging.log4j.core.lookup.StrSubstitutor;
5045 import org.apache.logging.log4j.core.util.Booleans;
6257
6358 private static final long serialVersionUID = 1L;
6459
65 private static final int MAX_RETRIES = 3;
6660 private static LogEventFactory LOG_EVENT_FACTORY = null;
6761
68 private List<AppenderRef> appenderRefs = new ArrayList<AppenderRef>();
69 private final Map<String, AppenderControl> appenders = new ConcurrentHashMap<String, AppenderControl>();
62 private List<AppenderRef> appenderRefs = new ArrayList<>();
63 private final Set<AppenderControl> appenders = new CopyOnWriteArraySet<>();
7064 private final String name;
7165 private LogEventFactory logEventFactory;
7266 private Level level;
7367 private boolean additive = true;
7468 private boolean includeLocation = true;
7569 private LoggerConfig parent;
76 private final AtomicInteger counter = new AtomicInteger();
77 private final AtomicBoolean shutdown = new AtomicBoolean(false);
7870 private final Map<Property, Boolean> properties;
7971 private final Configuration config;
80 private final Lock shutdownLock = new ReentrantLock();
81 private final Condition noLogEvents = shutdownLock.newCondition(); // should only be used when shutdown == true
72 private final ReliabilityStrategy reliabilityStrategy;
8273
8374 static {
8475 final String factory = PropertiesUtil.getProperties().getStringProperty(Constants.LOG4J_LOG_EVENT_FACTORY);
10697 this.name = Strings.EMPTY;
10798 this.properties = null;
10899 this.config = null;
100 this.reliabilityStrategy = new DefaultReliabilityStrategy(this);
109101 }
110102
111103 /**
115107 * @param level The Level.
116108 * @param additive true if the Logger is additive, false otherwise.
117109 */
118 public LoggerConfig(final String name, final Level level,
119 final boolean additive) {
110 public LoggerConfig(final String name, final Level level, final boolean additive) {
120111 this.logEventFactory = LOG_EVENT_FACTORY;
121112 this.name = name;
122113 this.level = level;
123114 this.additive = additive;
124115 this.properties = null;
125116 this.config = null;
126 }
127
128 protected LoggerConfig(final String name,
129 final List<AppenderRef> appenders, final Filter filter,
130 final Level level, final boolean additive,
131 final Property[] properties, final Configuration config,
117 this.reliabilityStrategy = new DefaultReliabilityStrategy(this);
118 }
119
120 protected LoggerConfig(final String name, final List<AppenderRef> appenders, final Filter filter,
121 final Level level, final boolean additive, final Property[] properties, final Configuration config,
132122 final boolean includeLocation) {
133123 super(filter);
134124 this.logEventFactory = LOG_EVENT_FACTORY;
139129 this.includeLocation = includeLocation;
140130 this.config = config;
141131 if (properties != null && properties.length > 0) {
142 this.properties = new HashMap<Property, Boolean>(properties.length);
132 this.properties = new HashMap<>(properties.length);
143133 for (final Property prop : properties) {
144134 final boolean interpolate = prop.getValue().contains("${");
145135 this.properties.put(prop, interpolate);
147137 } else {
148138 this.properties = null;
149139 }
140 this.reliabilityStrategy = config.getConfigurationMonitor().getReliabilityStrategy(this);
150141 }
151142
152143 @Override
188179 * @param level The Level to use.
189180 * @param filter A Filter for the Appender reference.
190181 */
191 public void addAppender(final Appender appender, final Level level,
192 final Filter filter) {
193 appenders.put(appender.getName(), new AppenderControl(appender, level,
194 filter));
182 public void addAppender(final Appender appender, final Level level, final Filter filter) {
183 appenders.add(new AppenderControl(appender, level, filter));
195184 }
196185
197186 /**
200189 * @param name The name of the Appender.
201190 */
202191 public void removeAppender(final String name) {
203 final AppenderControl ctl = appenders.remove(name);
204 if (ctl != null) {
205 cleanupFilter(ctl);
192 for (final AppenderControl appenderControl : appenders) {
193 if (Objects.equals(name, appenderControl.getAppenderName())) {
194 if (appenders.remove(appenderControl)) {
195 cleanupFilter(appenderControl);
196 }
197 }
206198 }
207199 }
208200
209201 /**
210202 * Returns all Appenders as a Map.
211203 *
212 * @return a Map with the Appender name as the key and the Appender as the
213 * value.
204 * @return a Map with the Appender name as the key and the Appender as the value.
214205 */
215206 public Map<String, Appender> getAppenders() {
216 final Map<String, Appender> map = new HashMap<String, Appender>();
217 for (final Map.Entry<String, AppenderControl> entry : appenders
218 .entrySet()) {
219 map.put(entry.getKey(), entry.getValue().getAppender());
207 final Map<String, Appender> map = new HashMap<>();
208 for (final AppenderControl appenderControl : appenders) {
209 map.put(appenderControl.getAppenderName(), appenderControl.getAppender());
220210 }
221211 return map;
222212 }
225215 * Removes all Appenders.
226216 */
227217 protected void clearAppenders() {
228 waitForCompletion();
229 final Collection<AppenderControl> controls = appenders.values();
230 final Iterator<AppenderControl> iterator = controls.iterator();
231 while (iterator.hasNext()) {
232 final AppenderControl ctl = iterator.next();
233 iterator.remove();
234 cleanupFilter(ctl);
218 List<AppenderControl> copy = new ArrayList<>(appenders);
219 while (!copy.isEmpty()) {
220 appenders.removeAll(copy);
221 for (final AppenderControl ctl : copy) {
222 cleanupFilter(ctl);
223 }
224 copy = new ArrayList<>(appenders);
235225 }
236226 }
237227
280270 }
281271
282272 /**
283 * Sets the LogEventFactory. Usually the LogEventFactory will be this
284 * LoggerConfig.
273 * Sets the LogEventFactory. Usually the LogEventFactory will be this LoggerConfig.
285274 *
286275 * @param logEventFactory the LogEventFactory.
287276 */
301290 /**
302291 * Sets the additive setting.
303292 *
304 * @param additive true if the LoggerConfig should be additive, false
305 * otherwise.
293 * @param additive true if the LoggerConfig should be additive, false otherwise.
306294 */
307295 public void setAdditive(final boolean additive) {
308296 this.additive = additive;
309297 }
310298
311299 /**
312 * Returns the value of logger configuration attribute {@code includeLocation},
313 * or, if no such attribute was configured, {@code true} if logging is
314 * synchronous or {@code false} if logging is asynchronous.
300 * Returns the value of logger configuration attribute {@code includeLocation}, or, if no such attribute was
301 * configured, {@code true} if logging is synchronous or {@code false} if logging is asynchronous.
315302 *
316303 * @return whether location should be passed downstream
317304 */
320307 }
321308
322309 /**
323 * Returns an unmodifiable map with the configuration properties, or
324 * {@code null} if this {@code LoggerConfig} does not have any configuration
325 * properties.
310 * Returns an unmodifiable map with the configuration properties, or {@code null} if this {@code LoggerConfig} does
311 * not have any configuration properties.
326312 * <p>
327 * For each {@code Property} key in the map, the value is {@code true} if
328 * the property value has a variable that needs to be substituted.
329 *
330 * @return an unmodifiable map with the configuration properties, or
331 * {@code null}
313 * For each {@code Property} key in the map, the value is {@code true} if the property value has a variable that
314 * needs to be substituted.
315 *
316 * @return an unmodifiable map with the configuration properties, or {@code null}
332317 * @see Configuration#getStrSubstitutor()
333318 * @see StrSubstitutor
334319 */
335320 // LOG4J2-157
336321 public Map<Property, Boolean> getProperties() {
337 return properties == null ? null : Collections
338 .unmodifiableMap(properties);
322 return properties == null ? null : Collections.unmodifiableMap(properties);
339323 }
340324
341325 /**
348332 * @param data The Message.
349333 * @param t A Throwable or null.
350334 */
351 public void log(final String loggerName, final String fqcn,
352 final Marker marker, final Level level, final Message data,
353 final Throwable t) {
335 public void log(final String loggerName, final String fqcn, final Marker marker, final Level level,
336 final Message data, final Throwable t) {
354337 List<Property> props = null;
355338 if (properties != null) {
356 props = new ArrayList<Property>(properties.size());
357
339 props = new ArrayList<>(properties.size());
340 Log4jLogEvent.Builder builder = new Log4jLogEvent.Builder();
341 builder.setMessage(data).setMarker(marker).setLevel(level).setLoggerName(loggerName);
342 builder.setLoggerFqcn(fqcn).setThrown(t);
343 LogEvent event = builder.build();
358344 for (final Map.Entry<Property, Boolean> entry : properties.entrySet()) {
359345 final Property prop = entry.getKey();
360 final String value = entry.getValue() ? config.getStrSubstitutor()
361 .replace(prop.getValue()) : prop.getValue();
346 final String value = entry.getValue() ? config.getStrSubstitutor().replace(event, prop.getValue())
347 : prop.getValue();
362348 props.add(Property.createProperty(prop.getName(), value));
363349 }
364350 }
365 final LogEvent event = logEventFactory.createEvent(loggerName, marker, fqcn, level, data, props, t);
366 log(event);
367 }
368
369 /**
370 * Waits for all log events to complete before shutting down this
371 * loggerConfig.
372 */
373 private void waitForCompletion() {
374 shutdownLock.lock();
375 try {
376 if (shutdown.compareAndSet(false, true)) {
377 int retries = 0;
378 while (counter.get() > 0) {
379 try {
380 noLogEvents.await(retries + 1, TimeUnit.SECONDS);
381 } catch (final InterruptedException ie) {
382 if (++retries > MAX_RETRIES) {
383 break;
384 }
385 }
386 }
387 }
388 } finally {
389 shutdownLock.unlock();
390 }
351 log(logEventFactory.createEvent(loggerName, marker, fqcn, level, data, props, t));
391352 }
392353
393354 /**
396357 * @param event The log event.
397358 */
398359 public void log(final LogEvent event) {
399
400 counter.incrementAndGet();
401 try {
402 if (isFiltered(event)) {
403 return;
404 }
405
406 event.setIncludeLocation(isIncludeLocation());
407
408 callAppenders(event);
409
410 if (additive && parent != null) {
411 parent.log(event);
412 }
413 } finally {
414 if (counter.decrementAndGet() == 0) {
415 shutdownLock.lock();
416 try {
417 if (shutdown.get()) {
418 noLogEvents.signalAll();
419 }
420 } finally {
421 shutdownLock.unlock();
422 }
423 }
360 if (!isFiltered(event)) {
361 processLogEvent(event);
362 }
363 }
364
365 /**
366 * Returns the object responsible for ensuring log events are delivered to a working appender, even during or after
367 * a reconfiguration.
368 *
369 * @return the object responsible for delivery of log events to the appender
370 */
371 public ReliabilityStrategy getReliabilityStrategy() {
372 return reliabilityStrategy;
373 }
374
375 private void processLogEvent(final LogEvent event) {
376 event.setIncludeLocation(isIncludeLocation());
377 callAppenders(event);
378 logParent(event);
379 }
380
381 private void logParent(final LogEvent event) {
382 if (additive && parent != null) {
383 parent.log(event);
424384 }
425385 }
426386
427387 protected void callAppenders(final LogEvent event) {
428 for (final AppenderControl control : appenders.values()) {
388 for (final AppenderControl control : appenders) {
429389 control.callAppender(event);
430390 }
431391 }
432
433392
434393 @Override
435394 public String toString() {
450409 * @return A new LoggerConfig.
451410 */
452411 @PluginFactory
453 public static LoggerConfig createLogger(
454 @PluginAttribute("additivity") final String additivity,
455 @PluginAttribute("level") final Level level,
456 @PluginAttribute("name") final String loggerName,
412 public static LoggerConfig createLogger(@PluginAttribute("additivity") final String additivity,
413 @PluginAttribute("level") final Level level, @PluginAttribute("name") final String loggerName,
457414 @PluginAttribute("includeLocation") final String includeLocation,
458415 @PluginElement("AppenderRef") final AppenderRef[] refs,
459 @PluginElement("Properties") final Property[] properties,
460 @PluginConfiguration final Configuration config,
416 @PluginElement("Properties") final Property[] properties, @PluginConfiguration final Configuration config,
461417 @PluginElement("Filter") final Filter filter) {
462418 if (loggerName == null) {
463419 LOGGER.error("Loggers cannot be configured without a name");
468424 final String name = loggerName.equals("root") ? Strings.EMPTY : loggerName;
469425 final boolean additive = Booleans.parseBoolean(additivity, true);
470426
471 return new LoggerConfig(name, appenderRefs, filter, level, additive,
472 properties, config, includeLocation(includeLocation));
427 return new LoggerConfig(name, appenderRefs, filter, level, additive, properties, config,
428 includeLocation(includeLocation));
473429 }
474430
475431 // Note: for asynchronous loggers, includeLocation default is FALSE,
476432 // for synchronous loggers, includeLocation default is TRUE.
477433 protected static boolean includeLocation(final String includeLocationConfigValue) {
478434 if (includeLocationConfigValue == null) {
479 final boolean sync = !AsyncLoggerContextSelector.class.getName()
480 .equals(System.getProperty(Constants.LOG4J_CONTEXT_SELECTOR));
435 final boolean sync = !AsyncLoggerContextSelector.class.getName().equals(
436 PropertiesUtil.getProperties().getStringProperty(Constants.LOG4J_CONTEXT_SELECTOR));
481437 return sync;
482438 }
483439 return Boolean.parseBoolean(includeLocationConfigValue);
492448 private static final long serialVersionUID = 1L;
493449
494450 @PluginFactory
495 public static LoggerConfig createLogger(
496 @PluginAttribute("additivity") final String additivity,
451 public static LoggerConfig createLogger(@PluginAttribute("additivity") final String additivity,
497452 @PluginAttribute("level") final Level level,
498453 @PluginAttribute("includeLocation") final String includeLocation,
499454 @PluginElement("AppenderRef") final AppenderRef[] refs,
500455 @PluginElement("Properties") final Property[] properties,
501 @PluginConfiguration final Configuration config,
502 @PluginElement("Filter") final Filter filter) {
456 @PluginConfiguration final Configuration config, @PluginElement("Filter") final Filter filter) {
503457 final List<AppenderRef> appenderRefs = Arrays.asList(refs);
504458 final Level actualLevel = level == null ? Level.ERROR : level;
505459 final boolean additive = Booleans.parseBoolean(additivity, true);
506460
507 return new LoggerConfig(LogManager.ROOT_LOGGER_NAME, appenderRefs,
508 filter, actualLevel, additive, properties, config,
509 includeLocation(includeLocation));
461 return new LoggerConfig(LogManager.ROOT_LOGGER_NAME, appenderRefs, filter, actualLevel, additive,
462 properties, config, includeLocation(includeLocation));
510463 }
511464 }
512465
3838 */
3939 @PluginFactory
4040 public static Loggers createLoggers(@PluginElement("Loggers") final LoggerConfig[] loggers) {
41 final ConcurrentMap<String, LoggerConfig> loggerMap = new ConcurrentHashMap<String, LoggerConfig>();
41 final ConcurrentMap<String, LoggerConfig> loggerMap = new ConcurrentHashMap<>();
4242 LoggerConfig root = null;
4343
4444 for (final LoggerConfig logger : loggers) {
3939 private final String name;
4040 private String value;
4141 private final PluginType<?> type;
42 private final Map<String, String> attributes = new HashMap<String, String>();
43 private final List<Node> children = new ArrayList<Node>();
42 private final Map<String, String> attributes = new HashMap<>();
43 private final List<Node> children = new ArrayList<>();
4444 private Object object;
4545
4646
1616 package org.apache.logging.log4j.core.config;
1717
1818 import java.util.Comparator;
19
20 import org.apache.logging.log4j.core.util.Assert;
19 import java.util.Objects;
2120
2221 /**
2322 * Comparator for classes annotated with {@link Order}.
3938
4039 @Override
4140 public int compare(final Class<?> lhs, final Class<?> rhs) {
42 final Order lhsOrder = Assert.requireNonNull(lhs, "lhs").getAnnotation(Order.class);
43 final Order rhsOrder = Assert.requireNonNull(rhs, "rhs").getAnnotation(Order.class);
41 final Order lhsOrder = Objects.requireNonNull(lhs, "lhs").getAnnotation(Order.class);
42 final Order rhsOrder = Objects.requireNonNull(rhs, "rhs").getAnnotation(Order.class);
4443 if (lhsOrder == null && rhsOrder == null) {
4544 // both unannotated means equal priority
4645 return 0;
4747 if (properties == null) {
4848 return new Interpolator(config.getProperties());
4949 }
50 final Map<String, String> map = new HashMap<String, String>(config.getProperties());
50 final Map<String, String> map = new HashMap<>(config.getProperties());
5151
5252 for (final Property prop : properties) {
5353 map.put(prop.getName(), prop.getValue());
1616 package org.apache.logging.log4j.core.config;
1717
1818 /**
19 * Interface to be implemented by Configurations that can be reconfigured at runtime.
19 * Implemented by Configurations that can be reconfigured at runtime.
2020 */
2121 public interface Reconfigurable {
2222
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.config;
18
19 import org.apache.logging.log4j.Level;
20 import org.apache.logging.log4j.Marker;
21 import org.apache.logging.log4j.core.LogEvent;
22 import org.apache.logging.log4j.message.Message;
23 import org.apache.logging.log4j.util.Supplier;
24
25 /**
26 * Interface for objects that know how to ensure delivery of log events to the appropriate appenders, even during and
27 * after the configuration has been modified while the system is actively used.
28 */
29 public interface ReliabilityStrategy {
30
31 /**
32 * Logs an event.
33 *
34 * @param loggerName The name of the Logger.
35 * @param fqcn The fully qualified class name of the caller.
36 * @param marker A Marker or null if none is present.
37 * @param level The event Level.
38 * @param data The Message.
39 * @param t A Throwable or null.
40 */
41 void log(Supplier<LoggerConfig> reconfigured, String loggerName, String fqcn, Marker marker,
42 Level level, Message data, Throwable t);
43
44 /**
45 * Logs an event.
46 *
47 * @param event The log event.
48 */
49 void log(Supplier<LoggerConfig> reconfigured, LogEvent event);
50
51 /**
52 * For internal use by the ReliabilityStrategy; returns the LoggerConfig to use.
53 * @param next
54 * @return
55 */
56 LoggerConfig getActiveLoggerConfig(Supplier<LoggerConfig> next);
57
58 /**
59 * Called after a log event was logged.
60 */
61 void afterLogEvent();
62
63 /**
64 * Called before all appenders are stopped.
65 */
66 void beforeStopAppenders();
67
68 /**
69 * Called before the configuration is stopped.
70 *
71 * @param configuration
72 */
73 void beforeStopConfiguration(Configuration configuration);
74
75 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.config;
18
19 import org.apache.logging.log4j.status.StatusLogger;
20 import org.apache.logging.log4j.util.PropertiesUtil;
21
22 /**
23 * Factory for ReliabilityStrategies.
24 */
25 public class ReliabilityStrategyFactory {
26 private ReliabilityStrategyFactory() {
27 }
28
29 /**
30 * Returns a new {@code ReliabilityStrategy} instance based on the value of system property
31 * {@code log4j.ReliabilityStrategy}. If not value was specified this method returns a new
32 * {@code AwaitUnconditionallyReliabilityStrategy}.
33 * <p>
34 * Valid values for this system property are {@code "AwaitUnconditionally"} (use
35 * {@code AwaitUnconditionallyReliabilityStrategy}), {@code "Locking"} (use {@code LockingReliabilityStrategy}) and
36 * {@code "AwaitCompletion"} (use the default {@code AwaitCompletionReliabilityStrategy}).
37 * <p>
38 * Users may also use this system property to specify the fully qualified class name of a class that implements the
39 * {@code ReliabilityStrategy} and has a constructor that accepts a single {@code LoggerConfig} argument.
40 *
41 * @param loggerConfig the LoggerConfig the resulting {@code ReliabilityStrategy} is associated with
42 * @return a ReliabilityStrategy that helps the specified LoggerConfig to log events reliably during or after a
43 * configuration change
44 */
45 public static ReliabilityStrategy getReliabilityStrategy(final LoggerConfig loggerConfig) {
46
47 String strategy = PropertiesUtil.getProperties().getStringProperty("log4j.ReliabilityStrategy",
48 "AwaitCompletion");
49 if ("AwaitCompletion".equals(strategy)) {
50 return new AwaitCompletionReliabilityStrategy(loggerConfig);
51 }
52 if ("AwaitUnconditionally".equals(strategy)) {
53 return new AwaitUnconditionallyReliabilityStrategy(loggerConfig);
54 }
55 if ("Locking".equals(strategy)) {
56 return new LockingReliabilityStrategy(loggerConfig);
57 }
58 try {
59 @SuppressWarnings("unchecked")
60 Class<? extends ReliabilityStrategy> cls = (Class<? extends ReliabilityStrategy>) Class.forName(strategy);
61 return cls.getConstructor(LoggerConfig.class).newInstance(loggerConfig);
62 } catch (Exception dynamicFailed) {
63 StatusLogger.getLogger().warn(
64 "Could not create ReliabilityStrategy for '{}', using default AwaitCompletionReliabilityStrategy");
65 return new AwaitCompletionReliabilityStrategy(loggerConfig);
66 }
67 }
68 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder.api;
17
18 /**
19 * Builder for constructing Appender Components.
20 * @since 2.4
21 */
22 public interface AppenderComponentBuilder extends ComponentBuilder<AppenderComponentBuilder> {
23
24 /**
25 * Adds a Layout to the Appender component.
26 * @param builder The LayoutComponentBuilder with all of its attributes set.
27 * @return this builder.
28 */
29 AppenderComponentBuilder add(LayoutComponentBuilder builder);
30
31 /**
32 * Adds a Filter to the Appender component.
33 * @param builder The FilterComponentBuilder with all of its attributes and sub components set.
34 * @return this builder.
35 */
36 AppenderComponentBuilder add(FilterComponentBuilder builder);
37
38 /**
39 * Returns the name of the Appender.
40 * @return the name of the Appender.
41 */
42 @Override
43 String getName();
44 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder.api;
17
18 /**
19 * Assembler for constructing AppenderRef Components.
20 * @since 2.4
21 */
22 public interface AppenderRefComponentBuilder extends ComponentBuilder<AppenderRefComponentBuilder> {
23
24 /**
25 * Add a Filter to the Appender component.
26 * @param assembler The FilterComponentBuilder with all of its attributes and sub components set.
27 * @return this Assembler.
28 */
29 AppenderRefComponentBuilder add(FilterComponentBuilder assembler);
30 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder.api;
17
18 import java.util.ArrayList;
19 import java.util.HashMap;
20 import java.util.List;
21 import java.util.Map;
22
23 /**
24 * Container for building Configurations. This class is not normally directly manipulated by users
25 * of the Assembler API.
26 * @since 2.4
27 */
28 public class Component {
29
30 private final Map<String, String> attributes = new HashMap<>();
31 private final List<Component> components = new ArrayList<>();
32 private final String pluginType;
33 private final String value;
34
35 public Component(final String pluginType) {
36 this(pluginType, null, null);
37 }
38
39 public Component(final String pluginType, final String name) {
40 this(pluginType, name, null);
41 }
42
43 public Component(final String pluginType, final String name, final String value) {
44 this.pluginType = pluginType;
45 this.value = value;
46 if (name != null && name.length() > 0) {
47 attributes.put("name", name);
48 }
49 }
50
51 public Component() {
52 this.pluginType = null;
53 this.value = null;
54 }
55
56
57 public String addAttribute(final String key, final String value) {
58 return attributes.put(key, value);
59 }
60
61 public void addComponent(final Component component) {
62 components.add(component);
63 }
64
65 public Map<String, String> getAttributes() {
66 return attributes;
67 }
68
69 public List<Component> getComponents() {
70 return components;
71 }
72
73 public String getPluginType() {
74 return pluginType;
75 }
76
77 public String getValue() {
78 return value;
79 }
80 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder.api;
17
18 import org.apache.logging.log4j.Level;
19 import org.apache.logging.log4j.core.config.Configuration;
20 import org.apache.logging.log4j.core.util.Builder;
21
22 /**
23 * Builds arbitrary components and is the base type for the provided components.
24 * @param <T> The ComponentBuilder's own type for fluent APIs.
25 * @since 2.4
26 */
27 public interface ComponentBuilder<T extends ComponentBuilder<T>> extends Builder<Component> {
28
29 /**
30 * Adds a String attribute.
31 * @param key The attribute key.
32 * @param value The value of the attribute.
33 * @return This ComponentBuilder.
34 */
35 T addAttribute(String key, String value);
36
37 /**
38 * Adds a logging Level attribute.
39 * @param key The attribute key.
40 * @param level The logging Level.
41 * @return This ComponentBuilder.
42 */
43 T addAttribute(String key, Level level);
44
45 /**
46 * Adds an enumeration attribute.
47 * @param key The attribute key.
48 * @param value The enumeration.
49 * @return This ComponentBuilder.
50 */
51 T addAttribute(String key, Enum<?> value);
52
53 /**
54 * Adds an integer attribute.
55 * @param key The attribute key.
56 * @param value The integer value.
57 * @return This ComponentBuilder.
58 */
59 T addAttribute(String key, int value);
60
61 /**
62 * Adds a boolean attribute.
63 * @param key The attribute key.
64 * @param value The integer value.
65 * @return This ComponentBuilder.
66 */
67 T addAttribute(String key, boolean value);
68
69 /**
70 * Adds an Object attribute.
71 * @param key The attribute key.
72 * @param value The integer value.
73 * @return This ComponentBuilder.
74 */
75 T addAttribute(String key, Object value);
76
77 /**
78 * Adds a sub component.
79 * @param builder The Assembler for the subcomponent with all of its attributes and sub-components set.
80 * @return This ComponentBuilder (<em>not</em> the argument).
81 */
82 T addComponent(ComponentBuilder<?> builder);
83
84 /**
85 * Returns the name of the component, if any.
86 * @return The components name or null if it doesn't have one.
87 */
88 String getName();
89
90 /**
91 * Retrieves the ConfigurationBuilder.
92 * @return The ConfigurationBuilder.
93 */
94 ConfigurationBuilder<? extends Configuration> getBuilder();
95 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder.api;
17
18 /**
19 * Wraps multiple Filter Comnponent builders.
20 */
21 public interface CompositeFilterComponentBuilder extends ComponentBuilder<CompositeFilterComponentBuilder> {
22
23 /**
24 * Add a FilterComponent.
25 * @param assembler The FilterComponentBuilder with all of its attributes and sub-components set.
26 * @return The CompositeFilterComponentBuilder.
27 * @since 2.4
28 */
29 CompositeFilterComponentBuilder add(FilterComponentBuilder assembler);
30 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder.api;
17
18 import org.apache.logging.log4j.Level;
19 import org.apache.logging.log4j.core.Filter;
20 import org.apache.logging.log4j.core.config.Configuration;
21 import org.apache.logging.log4j.core.config.ConfigurationSource;
22 import org.apache.logging.log4j.core.util.Builder;
23
24 /**
25 * Interface for building logging configurations.
26 * @param <T> The Configuration type created by this builder.
27 * @since 2.4
28 */
29 public interface ConfigurationBuilder<T extends Configuration> extends Builder<T> {
30
31 /**
32 * Adds an AppenderComponent.
33 * @param builder The AppenderComponentBuilder with all of its attributes and sub components set.
34 * @return this builder instance.
35 */
36 ConfigurationBuilder<T> add(AppenderComponentBuilder builder);
37
38 /**
39 * Adds a CustomLevel component.
40 * @param builder The CustomLevelComponentBuilder with all of its attributes set.
41 * @return this builder instance.
42 */
43 ConfigurationBuilder<T> add(CustomLevelComponentBuilder builder);
44
45 /**
46 * Adds a Filter component.
47 * @param builder the FilterComponentBuilder with all of its attributes and sub components set.
48 * @return this builder instance.
49 */
50 ConfigurationBuilder<T> add(FilterComponentBuilder builder);
51
52 /**
53 * Adds a Logger component.
54 * @param builder The LoggerComponentBuilder with all of its attributes and sub components set.
55 * @return this builder instance.
56 */
57 ConfigurationBuilder<T> add(LoggerComponentBuilder builder);
58
59 /**
60 * Adds the root Logger component.
61 * @param builder The RootLoggerComponentBuilder with all of its attributes and sub components set.
62 * @return this builder instance.
63 */
64 ConfigurationBuilder<T> add(RootLoggerComponentBuilder builder);
65
66 /**
67 * Adds a Property key and value.
68 * @param key The property key.
69 * @param value The property value.
70 * @return this builder instance.
71 */
72 ConfigurationBuilder<T> addProperty(String key, String value);
73
74 /**
75 * Returns a builder for creating Appenders.
76 * @param name The name of the Appender.
77 * @param pluginName The Plugin type of the Appender.
78 * @return A new AppenderComponentBuilder.
79 */
80 AppenderComponentBuilder newAppender(String name, String pluginName);
81
82 /**
83 * Returns a builder for creating AppenderRefs.
84 * @param ref The name of the Appender being referenced.
85 * @return A new AppenderRefComponentBuilder.
86 */
87 AppenderRefComponentBuilder newAppenderRef(String ref);
88
89 /**
90 * Returns a builder for creating Async Loggers.
91 * @param name The name of the Logger.
92 * @param level The logging Level to be assigned to the Logger.
93 * @return A new LoggerComponentBuilder.
94 */
95 LoggerComponentBuilder newAsyncLogger(String name, Level level);
96
97 /**
98 * Returns a builder for creating Async Loggers.
99 * @param name The name of the Logger.
100 * @param level The logging Level to be assigned to the Logger.
101 * @return A new LoggerComponentBuilder.
102 */
103 LoggerComponentBuilder newAsyncLogger(String name, String level);
104
105 /**
106 * Returns a builder for creating the async root Logger.
107 * @param level The logging Level to be assigned to the root Logger.
108 * @return A new RootLoggerComponentBuilder.
109 */
110 RootLoggerComponentBuilder newAsyncRootLogger(Level level);
111
112 /**
113 * Returns a builder for creating the async root Logger.
114 * @param level The logging Level to be assigned to the root Logger.
115 * @return A new RootLoggerComponentBuilder.
116 */
117 RootLoggerComponentBuilder newAsyncRootLogger(String level);
118
119 /**
120 * Returns a builder for creating generic components.
121 * @param <B> ComponentBuilder target type
122 * @param name The name of the component (may be null).
123 * @param pluginName The Plugin type of the component.
124 * @return A new ComponentBuilder.
125 */
126 <B extends ComponentBuilder<B>> ComponentBuilder<B> newComponent(String name, String pluginName);
127
128 /**
129 * Returns a builder for creating generic components.
130 * @param <B> ComponentBuilder target type
131 * @param name The name of the component (may be null).
132 * @param pluginName The Plugin type of the component.
133 * @param value The value of the component.
134 * @return A new ComponentBuilder.
135 */
136 <B extends ComponentBuilder<B>> ComponentBuilder<B> newComponent(String name, String pluginName, String value);
137
138
139 /**
140 * Returns a builder for creating CustomLevels
141 * @param name The name of the custom level.
142 * @param level The integer value to be assigned to the level.
143 * @return A new CustomLevelComponentBuilder.
144 */
145 CustomLevelComponentBuilder newCustomLevel(String name, int level);
146
147 /**
148 * Returns a builder for creating Filters.
149 * @param pluginName The Plugin type of the Filter.
150 * @param onMatch "ACCEPT", "DENY", or "NEUTRAL"
151 * @param onMisMatch "ACCEPT", "DENY", or "NEUTRAL"
152 * @return A new FilterComponentBuilder.
153 */
154 FilterComponentBuilder newFilter(String pluginName, Filter.Result onMatch, Filter.Result onMisMatch);
155
156 /**
157 * Returns a builder for creating Filters.
158 * @param pluginName The Plugin type of the Filter.
159 * @param onMatch "ACCEPT", "DENY", or "NEUTRAL"
160 * @param onMisMatch "ACCEPT", "DENY", or "NEUTRAL"
161 * @return A new FilterComponentBuilder.
162 */
163 FilterComponentBuilder newFilter(String pluginName, String onMatch, String onMisMatch);
164
165 /**
166 * Returns a builder for creating Layouts.
167 * @param pluginName The Plugin type of the Layout.
168 * @return A new LayoutComponentBuilder.
169 */
170 LayoutComponentBuilder newLayout(String pluginName);
171
172 /**
173 * Returns a builder for creating Loggers.
174 * @param name The name of the Logger.
175 * @param level The logging Level to be assigned to the Logger.
176 * @return A new LoggerComponentBuilder.
177 */
178 LoggerComponentBuilder newLogger(String name, Level level);
179
180 /**
181 * Returns a builder for creating Loggers.
182 * @param name The name of the Logger.
183 * @param level The logging Level to be assigned to the Logger.
184 * @return A new LoggerComponentBuilder.
185 */
186 LoggerComponentBuilder newLogger(String name, String level);
187
188 /**
189 * Returns a builder for creating the root Logger.
190 * @param level The logging Level to be assigned to the root Logger.
191 * @return A new RootLoggerComponentBuilder.
192 */
193 RootLoggerComponentBuilder newRootLogger(Level level);
194
195 /**
196 * Returns a builder for creating the root Logger.
197 * @param level The logging Level to be assigned to the root Logger.
198 * @return A new RootLoggerComponentBuilder.
199 */
200 RootLoggerComponentBuilder newRootLogger(String level);
201
202 /**
203 * Set the Advertiser Plugin name.
204 * @param advertiser The Advertiser Plugin name.
205 * @return this builder instance.
206 */
207 ConfigurationBuilder<T> setAdvertiser(String advertiser);
208
209 /**
210 * Sets the name of the configuration.
211 * @param name the name of the {@link Configuration}. By default is {@code "Constructed"}.
212 * @return this builder instance.
213 */
214 ConfigurationBuilder<T> setConfigurationName(String name);
215
216 /**
217 * Sets the configuration source, if one exists.
218 * @param configurationSource the ConfigurationSource.
219 * @return this builder instance.
220 */
221 ConfigurationBuilder<T> setConfigurationSource(ConfigurationSource configurationSource);
222
223 /**
224 * Sets the interval at which the configuration file should be checked for changes.
225 * @param intervalSeconds The number of seconds that should pass between checks of the configuration file.
226 * @return this builder instance.
227 */
228 ConfigurationBuilder<T> setMonitorInterval(String intervalSeconds);
229
230 /**
231 * Sets the list of packages to search for plugins.
232 * @param packages The comma separated list of packages.
233 * @return this builder instance.
234 */
235 ConfigurationBuilder<T> setPackages(String packages);
236
237 /**
238 * Sets whether the shutdown hook should be disabled.
239 * @param flag "disable" will prevent the shutdown hook from being set.
240 * @return this builder instance.
241 */
242 ConfigurationBuilder<T> setShutdownHook(String flag);
243
244
245 /**
246 * Sets the level of the StatusLogger.
247 * @param level The logging level.
248 * @return this builder instance.
249 */
250 ConfigurationBuilder<T> setStatusLevel(Level level);
251
252
253 /**
254 * Sets whether the logging should include constructing Plugins.
255 * @param verbosity "disable" will hide messages from plugin construction.
256 * @return this builder instance.
257 */
258 ConfigurationBuilder<T> setVerbosity(String verbosity);
259 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.config.builder.api;
18
19 import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
20 import org.apache.logging.log4j.core.config.builder.impl.DefaultConfigurationBuilder;
21
22 /**
23 * Provides methods to create ConfigurationBuilders.
24 * @since 2.4
25 */
26 public class ConfigurationBuilderFactory {
27
28 /**
29 * Returns a new default ConfigurationBuilder to construct Log4j configurations.
30 * @return A new ConfigurationBuilder.
31 */
32 public static ConfigurationBuilder<BuiltConfiguration> newConfigurationBuilder() {
33 return new DefaultConfigurationBuilder<>();
34 }
35
36 public static <T extends BuiltConfiguration> ConfigurationBuilder<T> newConfigurationBuilder(final Class<T> clazz) {
37 return new DefaultConfigurationBuilder<>(clazz);
38 }
39 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder.api;
17
18 /**
19 * Assembler for constructing CustomLevel Components.
20 * @since 2.4
21 */
22 public interface CustomLevelComponentBuilder extends ComponentBuilder<CustomLevelComponentBuilder> {
23
24 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder.api;
17
18 /**
19 * Assembler for constructing Filter Components.
20 * @since 2.4
21 */
22 public interface FilterComponentBuilder extends ComponentBuilder<FilterComponentBuilder> {
23
24 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder.api;
17
18 /**
19 * Assembler for constructing Layout Components.
20 * @since 2.4
21 */
22 public interface LayoutComponentBuilder extends ComponentBuilder<LayoutComponentBuilder> {
23
24 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder.api;
17
18 /**
19 * Assembler for constructing Logger Components.
20 * @since 2.4
21 */
22 public interface LoggerComponentBuilder extends ComponentBuilder<LoggerComponentBuilder> {
23
24 /**
25 * Add an Appender reference to the Logger component.
26 * @param assembler The AppenderRefComponentBuilder with all of its attributes and sub-components set.
27 * @return this Assembler.
28 */
29 LoggerComponentBuilder add(AppenderRefComponentBuilder assembler);
30
31 /**
32 * Add a Filter to the Logger component.
33 * @param assembler The FilterComponentBuilder with all of its attributes and sub-components set.
34 * @return this Assembler.
35 */
36 LoggerComponentBuilder add(FilterComponentBuilder assembler);
37 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder.api;
17
18 /**
19 * Assembler for constructing the root Logger Components.
20 * @since 2.4
21 */
22 public interface RootLoggerComponentBuilder extends ComponentBuilder<RootLoggerComponentBuilder> {
23
24 /**
25 * Add an Appender reference to the Logger component.
26 * @param assembler The AppenderRefComponentBuilder with all of its attributes and sub-components set.
27 * @return this Assembler.
28 */
29 RootLoggerComponentBuilder add(AppenderRefComponentBuilder assembler);
30
31 /**
32 * Add a Filter to the Logger component.
33 * @param assembler The FilterComponentBuilder with all of its attributes and sub-components set.
34 * @return this Assembler.
35 */
36 RootLoggerComponentBuilder add(FilterComponentBuilder assembler);
37 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder.impl;
17
18 import org.apache.logging.log4j.core.config.AbstractConfiguration;
19 import org.apache.logging.log4j.core.config.ConfigurationSource;
20 import org.apache.logging.log4j.core.config.FileConfigurationMonitor;
21 import org.apache.logging.log4j.core.config.Node;
22 import org.apache.logging.log4j.core.config.Reconfigurable;
23 import org.apache.logging.log4j.core.config.builder.api.Component;
24 import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
25 import org.apache.logging.log4j.core.config.plugins.util.PluginType;
26 import org.apache.logging.log4j.core.config.plugins.util.ResolverUtil;
27 import org.apache.logging.log4j.core.config.status.StatusConfiguration;
28 import org.apache.logging.log4j.core.util.Patterns;
29
30 import java.io.File;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.util.Arrays;
34 import java.util.List;
35
36 /**
37 * This is the general version of the Configuration created by the Builder. It may be extended to
38 * enhance its functionality.
39 */
40 public class BuiltConfiguration extends AbstractConfiguration {
41 private static final long serialVersionUID = -3071897330997405132L;
42 private static final String[] VERBOSE_CLASSES = new String[] { ResolverUtil.class.getName() };
43 private final StatusConfiguration statusConfig;
44 protected Component root;
45 private Component loggersComponent;
46 private Component appendersComponent;
47 private Component filtersComponent;
48 private Component propertiesComponent;
49 private Component customLevelsComponent;
50 private String contentType = "text";
51
52 public BuiltConfiguration(final ConfigurationSource source, final Component rootComponent) {
53 super(source);
54 statusConfig = new StatusConfiguration().withVerboseClasses(VERBOSE_CLASSES).withStatus(getDefaultStatus());
55 for (final Component component : rootComponent.getComponents()) {
56 switch (component.getPluginType()) {
57 case "Loggers": {
58 loggersComponent = component;
59 break;
60 }
61 case "Appenders": {
62 appendersComponent = component;
63 break;
64 }
65 case "Filters": {
66 filtersComponent = component;
67 break;
68 }
69 case "Properties": {
70 propertiesComponent = component;
71 break;
72 }
73 case "CustomLevels": {
74 customLevelsComponent = component;
75 break;
76 }
77 }
78 }
79 root = rootComponent;
80 }
81
82 @Override
83 public void setup() {
84 final List<Node> children = rootNode.getChildren();
85 if (propertiesComponent.getComponents().size() > 0) {
86 children.add(convertToNode(rootNode, propertiesComponent));
87 }
88 if (customLevelsComponent.getComponents().size() > 0) {
89 children.add(convertToNode(rootNode, customLevelsComponent));
90 }
91 children.add(convertToNode(rootNode, loggersComponent));
92 children.add(convertToNode(rootNode, appendersComponent));
93 if (filtersComponent.getComponents().size() > 0) {
94 if (filtersComponent.getComponents().size() == 1) {
95 children.add(convertToNode(rootNode, filtersComponent.getComponents().get(0)));
96 } else {
97 children.add(convertToNode(rootNode, filtersComponent));
98 }
99 }
100 root = null;
101 }
102
103 public String getContentType() {
104 return this.contentType;
105 }
106
107 public void setContentType(String contentType) {
108 this.contentType = contentType;
109 }
110
111 public void createAdvertiser(final String advertiserString, final ConfigurationSource configSource) {
112 byte[] buffer = null;
113 try {
114 if (configSource != null) {
115 InputStream is = configSource.getInputStream();
116 if (is != null) {
117 buffer = toByteArray(is);
118 }
119 }
120 } catch (IOException ioe) {
121 LOGGER.warn("Unable to read configuration source " + configSource.toString());
122 }
123 super.createAdvertiser(advertiserString, configSource, buffer, contentType);
124 }
125
126 public StatusConfiguration getStatusConfiguration() {
127 return statusConfig;
128 }
129
130 public void setPluginPackages(final String packages) {
131 pluginPackages.addAll(Arrays.asList(packages.split(Patterns.COMMA_SEPARATOR)));
132 }
133
134 public void setShutdownHook(final String flag) {
135 isShutdownHookEnabled = !"disable".equalsIgnoreCase(flag);
136 }
137
138 public void setMonitorInterval(final int intervalSeconds) {
139 if (this instanceof Reconfigurable && intervalSeconds > 0) {
140 final ConfigurationSource configSource = getConfigurationSource();
141 if (configSource != null) {
142 final File configFile = configSource.getFile();
143 if (intervalSeconds > 0 && configFile != null) {
144 monitor = new FileConfigurationMonitor((Reconfigurable)this, configFile, listeners, intervalSeconds);
145 }
146 }
147 }
148 }
149
150 public PluginManager getPluginManager() {
151 return pluginManager;
152 }
153
154 protected Node convertToNode(final Node parent, final Component component) {
155 final String name = component.getPluginType();
156 final PluginType<?> pluginType = pluginManager.getPluginType(name);
157 final Node node = new Node(parent, name, pluginType);
158 node.getAttributes().putAll(component.getAttributes());
159 node.setValue(component.getValue());
160 final List<Node> children = node.getChildren();
161 for (final Component child : component.getComponents()) {
162 children.add(convertToNode(node, child));
163 }
164 return node;
165 }
166 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder.impl;
17
18 import org.apache.logging.log4j.core.config.Configuration;
19 import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
20 import org.apache.logging.log4j.core.config.builder.api.FilterComponentBuilder;
21 import org.apache.logging.log4j.core.config.builder.api.LayoutComponentBuilder;
22
23 /**
24 * Holds the Appender Component attributes and subcomponents.
25 */
26 class DefaultAppenderComponentBuilder extends DefaultComponentAndConfigurationBuilder<AppenderComponentBuilder>
27 implements AppenderComponentBuilder {
28
29 public DefaultAppenderComponentBuilder(final DefaultConfigurationBuilder<? extends Configuration> builder, final String name,
30 final String type) {
31 super(builder, name, type);
32 }
33
34 @Override
35 public AppenderComponentBuilder add(final LayoutComponentBuilder builder) {
36 return addComponent(builder);
37 }
38
39 @Override
40 public AppenderComponentBuilder add(final FilterComponentBuilder builder) {
41 return addComponent(builder);
42 }
43 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder.impl;
17
18 import org.apache.logging.log4j.core.config.Configuration;
19 import org.apache.logging.log4j.core.config.builder.api.AppenderRefComponentBuilder;
20 import org.apache.logging.log4j.core.config.builder.api.FilterComponentBuilder;
21
22 /**
23 * Holds the Appender Component attributes and subcomponents.
24 */
25 class DefaultAppenderRefComponentBuilder extends DefaultComponentAndConfigurationBuilder<AppenderRefComponentBuilder>
26 implements AppenderRefComponentBuilder {
27
28 public DefaultAppenderRefComponentBuilder(final DefaultConfigurationBuilder<? extends Configuration> builder,
29 final String ref) {
30 super(builder, "AppenderRef");
31 addAttribute("ref", ref);
32 }
33
34
35 @Override
36 public AppenderRefComponentBuilder add(final FilterComponentBuilder builder) {
37 return addComponent(builder);
38 }
39 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder.impl;
17
18 import org.apache.logging.log4j.core.config.Configuration;
19 import org.apache.logging.log4j.core.config.builder.api.ComponentBuilder;
20
21 /**
22 * Extends {@code DefaultComponentBuilder} to specify
23 * {@code DefaultConfigurationBuilder<? extends Configuration>} as the
24 * {@code ConfigurationBuilder} type.
25 */
26 class DefaultComponentAndConfigurationBuilder<T extends ComponentBuilder<T>>
27 extends DefaultComponentBuilder<T, DefaultConfigurationBuilder<? extends Configuration>> {
28
29 DefaultComponentAndConfigurationBuilder(final DefaultConfigurationBuilder<? extends Configuration> builder, final String name,
30 final String type, final String value) {
31 super(builder, name, type, value);
32 }
33
34 DefaultComponentAndConfigurationBuilder(final DefaultConfigurationBuilder<? extends Configuration> builder, final String name,
35 final String type) {
36 super(builder, name, type);
37 }
38
39 public DefaultComponentAndConfigurationBuilder(final DefaultConfigurationBuilder<? extends Configuration> builder,
40 final String type) {
41 super(builder, type);
42 }
43
44 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder.impl;
17
18 import org.apache.logging.log4j.Level;
19 import org.apache.logging.log4j.core.config.Configuration;
20 import org.apache.logging.log4j.core.config.builder.api.Component;
21 import org.apache.logging.log4j.core.config.builder.api.ComponentBuilder;
22 import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
23
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28
29 /**
30 * Generic component that captures attributes and Components in preparation for assembling the Appender's
31 * Component.
32 */
33 class DefaultComponentBuilder<T extends ComponentBuilder<T>, CB extends ConfigurationBuilder<? extends Configuration>>
34 implements ComponentBuilder<T> {
35
36 private CB builder;
37 private String type;
38 private final Map<String, String> attributes = new HashMap<>();
39 private final List<Component> components = new ArrayList<>();
40 private String name;
41 private String value;
42
43 public DefaultComponentBuilder(final CB builder, final String type) {
44 this(builder, null, type, null);
45 }
46
47 public DefaultComponentBuilder(final CB builder, final String name, final String type) {
48 this(builder, name, type, null);
49 }
50
51 public DefaultComponentBuilder(final CB builder, final String name, final String type,
52 final String value) {
53 this.type = type;
54 this.builder = builder;
55 this.name = name;
56 this.value = value;
57 }
58
59 @Override
60 public T addAttribute(final String key, final boolean value) {
61 return put(key, Boolean.toString(value));
62 }
63
64 @Override
65 public T addAttribute(final String key, final Enum<?> value) {
66 return put(key, value.name());
67 }
68
69 @Override
70 public T addAttribute(final String key, final int value) {
71 return put(key, Integer.toString(value));
72 }
73
74
75 @Override
76 public T addAttribute(final String key, final Level level) {
77 return put(key, level.toString());
78 }
79
80 @Override
81 public T addAttribute(final String key, final Object value) {
82 return put(key, value.toString());
83 }
84
85
86 @Override
87 public T addAttribute(final String key, final String value) {
88 return put(key, value);
89 }
90
91 @Override
92 @SuppressWarnings("unchecked")
93 public T addComponent(final ComponentBuilder<?> builder) {
94 components.add(builder.build());
95 return (T) this;
96 }
97
98 @Override
99 public Component build() {
100 final Component component = new Component(type, name, value);
101 component.getAttributes().putAll(attributes);
102 component.getComponents().addAll(components);
103 return component;
104 }
105
106 @Override
107 public CB getBuilder() {
108 return builder;
109 }
110
111 @Override
112 public String getName() {
113 return name;
114 }
115
116 protected T put(final String key, final String value) {
117 attributes.put(key, value);
118 return (T) this;
119 }
120 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder.impl;
17
18 import org.apache.logging.log4j.core.config.Configuration;
19 import org.apache.logging.log4j.core.config.builder.api.CompositeFilterComponentBuilder;
20 import org.apache.logging.log4j.core.config.builder.api.FilterComponentBuilder;
21
22 /**
23 *
24 */
25 class DefaultCompositeFilterComponentBuilder
26 extends DefaultComponentAndConfigurationBuilder<CompositeFilterComponentBuilder>
27 implements CompositeFilterComponentBuilder {
28
29 public DefaultCompositeFilterComponentBuilder(final DefaultConfigurationBuilder<? extends Configuration> builder,
30 final String onMatch, final String onMisMatch) {
31 super(builder, "Filters");
32 addAttribute("onMatch", onMatch);
33 addAttribute("onMisMatch", onMisMatch);
34 }
35
36 @Override
37 public CompositeFilterComponentBuilder add(final FilterComponentBuilder builder) {
38 return addComponent(builder);
39 }
40
41 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder.impl;
17
18 import org.apache.logging.log4j.Level;
19 import org.apache.logging.log4j.core.Filter;
20 import org.apache.logging.log4j.core.config.Configuration;
21 import org.apache.logging.log4j.core.config.ConfigurationException;
22 import org.apache.logging.log4j.core.config.ConfigurationSource;
23 import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
24 import org.apache.logging.log4j.core.config.builder.api.AppenderRefComponentBuilder;
25 import org.apache.logging.log4j.core.config.builder.api.Component;
26 import org.apache.logging.log4j.core.config.builder.api.ComponentBuilder;
27 import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
28 import org.apache.logging.log4j.core.config.builder.api.CustomLevelComponentBuilder;
29 import org.apache.logging.log4j.core.config.builder.api.FilterComponentBuilder;
30 import org.apache.logging.log4j.core.config.builder.api.LayoutComponentBuilder;
31 import org.apache.logging.log4j.core.config.builder.api.LoggerComponentBuilder;
32 import org.apache.logging.log4j.core.config.builder.api.RootLoggerComponentBuilder;
33
34 import java.lang.reflect.Constructor;
35 import java.util.List;
36
37 /**
38 * @param <T> The BuiltConfiguration type.
39 *
40 */
41 public class DefaultConfigurationBuilder<T extends BuiltConfiguration> implements ConfigurationBuilder<T> {
42
43 private final Component root = new Component();
44 private Component loggers;
45 private Component appenders;
46 private Component filters;
47 private Component properties;
48 private Component customLevels;
49 private final Class<T> clazz;
50 private ConfigurationSource source;
51 private int monitorInterval = 0;
52 private Level level = null;
53 private String verbosity = null;
54 private String packages = null;
55 private String shutdownFlag = null;
56 private String advertiser = null;
57
58 private String name = null;
59
60 public DefaultConfigurationBuilder() {
61 this((Class<T>) BuiltConfiguration.class);
62 root.addAttribute("name", "Built");
63 }
64
65 public DefaultConfigurationBuilder(final Class<T> clazz) {
66 if (clazz == null) {
67 throw new IllegalArgumentException("A Configuration class must be provided");
68 }
69 this.clazz = clazz;
70 final List<Component> components = root.getComponents();
71 properties = new Component("Properties");
72 components.add(properties);
73 customLevels = new Component("CustomLevels");
74 components.add(customLevels);
75 filters = new Component("Filters");
76 components.add(filters);
77 appenders = new Component("Appenders");
78 components.add(appenders);
79 loggers = new Component("Loggers");
80 components.add(loggers);
81 }
82
83 protected ConfigurationBuilder<T> add(final Component parent, final ComponentBuilder<?> builder) {
84 parent.getComponents().add(builder.build());
85 return this;
86 }
87
88 @Override
89 public ConfigurationBuilder<T> add(final AppenderComponentBuilder builder) {
90 return add(appenders, builder);
91 }
92
93 @Override
94 public ConfigurationBuilder<T> add(final CustomLevelComponentBuilder builder) {
95 return add(customLevels, builder);
96 }
97
98 @Override
99 public ConfigurationBuilder<T> add(final FilterComponentBuilder builder) {
100 return add(filters, builder);
101 }
102
103 @Override
104 public ConfigurationBuilder<T> add(final LoggerComponentBuilder builder) {
105 return add(loggers, builder);
106 }
107
108 @Override
109 public ConfigurationBuilder<T> add(final RootLoggerComponentBuilder builder) {
110 for (final Component c : loggers.getComponents()) {
111 if (c.getPluginType().equals("root")) {
112 throw new ConfigurationException("Root Logger was previously defined");
113 }
114 }
115 return add(loggers, builder);
116 }
117
118 @Override
119 public ConfigurationBuilder<T> addProperty(final String key, final String value) {
120 properties.addComponent(newComponent(key, "Property", value).build());
121 return this;
122 }
123
124 @Override
125 public T build() {
126 T configuration;
127 try {
128 if (source == null) {
129 source = ConfigurationSource.NULL_SOURCE;
130 }
131 final Constructor<T> constructor = clazz.getConstructor(ConfigurationSource.class, Component.class);
132 configuration = constructor.newInstance(source, root);
133 configuration.setMonitorInterval(monitorInterval);
134 if (name != null) {
135 configuration.setName(name);
136 }
137 if (level != null) {
138 configuration.getStatusConfiguration().withStatus(level);
139 }
140 if (verbosity != null) {
141 configuration.getStatusConfiguration().withVerbosity(verbosity);
142 }
143 if (packages != null) {
144 configuration.setPluginPackages(packages);
145 }
146 if (shutdownFlag != null) {
147 configuration.setShutdownHook(shutdownFlag);
148 }
149 if (advertiser != null) {
150 configuration.createAdvertiser(advertiser, source);
151 }
152 } catch (final Exception ex) {
153 throw new IllegalArgumentException("Invalid Configuration class specified", ex);
154 }
155 configuration.getStatusConfiguration().initialize();
156 configuration.initialize();
157 return configuration;
158 }
159
160 @Override
161 public AppenderComponentBuilder newAppender(final String name, final String type) {
162 return new DefaultAppenderComponentBuilder(this, name, type);
163 }
164
165 @Override
166 public AppenderRefComponentBuilder newAppenderRef(final String ref) {
167 return new DefaultAppenderRefComponentBuilder(this, ref);
168 }
169
170 @Override
171 public LoggerComponentBuilder newAsyncLogger(final String name, final Level level) {
172 return new DefaultLoggerComponentBuilder(this, name, level.toString(), "AsyncLogger");
173 }
174
175 @Override
176 public LoggerComponentBuilder newAsyncLogger(final String name, final String level) {
177 return new DefaultLoggerComponentBuilder(this, name, level, "AsyncLogger");
178 }
179
180 @Override
181 public RootLoggerComponentBuilder newAsyncRootLogger(final Level level) {
182 return new DefaultRootLoggerComponentBuilder(this, level.toString(), "AsyncRoot");
183 }
184
185 @Override
186 public RootLoggerComponentBuilder newAsyncRootLogger(final String level) {
187 return new DefaultRootLoggerComponentBuilder(this, level, "AsyncRoot");
188 }
189
190 @Override
191 public <B extends ComponentBuilder<B>> ComponentBuilder<B> newComponent(final String name, final String type) {
192 return new DefaultComponentBuilder<>(this, name, type);
193 }
194
195 @Override
196 public <B extends ComponentBuilder<B>> ComponentBuilder<B> newComponent(final String name, final String type, final String value) {
197 return new DefaultComponentBuilder<>(this, name, type, value);
198 }
199
200
201 @Override
202 public CustomLevelComponentBuilder newCustomLevel(final String name, final int level) {
203 return new DefaultCustomLevelComponentBuilder(this, name, level);
204 }
205
206 @Override
207 public FilterComponentBuilder newFilter(final String type, final Filter.Result onMatch, final Filter.Result onMisMatch) {
208 return new DefaultFilterComponentBuilder(this, type, onMatch.name(), onMisMatch.name());
209 }
210
211 @Override
212 public FilterComponentBuilder newFilter(final String type, final String onMatch, final String onMisMatch) {
213 return new DefaultFilterComponentBuilder(this, type, onMatch, onMisMatch);
214 }
215
216 @Override
217 public LayoutComponentBuilder newLayout(final String type) {
218 return new DefaultLayoutComponentBuilder(this, type);
219 }
220
221
222 @Override
223 public LoggerComponentBuilder newLogger(final String name, final Level level) {
224 return new DefaultLoggerComponentBuilder(this, name, level.toString());
225 }
226
227 @Override
228 public LoggerComponentBuilder newLogger(final String name, final String level) {
229 return new DefaultLoggerComponentBuilder(this, name, level);
230 }
231
232 @Override
233 public RootLoggerComponentBuilder newRootLogger(final Level level) {
234 return new DefaultRootLoggerComponentBuilder(this, level.toString());
235 }
236
237 @Override
238 public RootLoggerComponentBuilder newRootLogger(final String level) {
239 return new DefaultRootLoggerComponentBuilder(this, level);
240 }
241
242 @Override
243 public ConfigurationBuilder<T> setAdvertiser(final String advertiser) {
244 this.advertiser = advertiser;
245 return this;
246 }
247
248 /**
249 * Set the name of the configuration.
250 *
251 * @param name the name of the {@link Configuration}. By default is {@code "Assembled"}.
252 * @return this builder instance
253 */
254 @Override
255 public ConfigurationBuilder<T> setConfigurationName(final String name) {
256 this.name = name;
257 return this;
258 }
259
260 /**
261 * Set the ConfigurationSource.
262 *
263 * @param configurationSource the {@link ConfigurationSource}
264 * @return this builder instance
265 */
266 @Override
267 public ConfigurationBuilder<T> setConfigurationSource(final ConfigurationSource configurationSource) {
268 source = configurationSource;
269 return this;
270 }
271
272 @Override
273 public ConfigurationBuilder<T> setMonitorInterval(final String intervalSeconds) {
274 monitorInterval = Integer.parseInt(intervalSeconds);
275 return this;
276 }
277
278 @Override
279 public ConfigurationBuilder<T> setPackages(final String packages) {
280 this.packages = packages;
281 return this;
282 }
283
284 @Override
285 public ConfigurationBuilder<T> setShutdownHook(final String flag) {
286 this.shutdownFlag = flag;
287 return this;
288 }
289
290 @Override
291 public ConfigurationBuilder<T> setStatusLevel(final Level level) {
292 this.level = level;
293 return this;
294 }
295
296 @Override
297 public ConfigurationBuilder<T> setVerbosity(final String verbosity) {
298 this.verbosity = verbosity;
299 return this;
300 }
301 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder.impl;
17
18 import org.apache.logging.log4j.core.config.Configuration;
19 import org.apache.logging.log4j.core.config.builder.api.CustomLevelComponentBuilder;
20
21 /**
22 *
23 */
24 class DefaultCustomLevelComponentBuilder extends DefaultComponentAndConfigurationBuilder<CustomLevelComponentBuilder>
25 implements CustomLevelComponentBuilder {
26
27 public DefaultCustomLevelComponentBuilder(final DefaultConfigurationBuilder<? extends Configuration> builder,
28 final String name, final int level) {
29 super(builder, name, "CustomLevel");
30 addAttribute("level", Integer.toString(level));
31 }
32 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder.impl;
17
18 import org.apache.logging.log4j.core.config.Configuration;
19 import org.apache.logging.log4j.core.config.builder.api.FilterComponentBuilder;
20
21 /**
22 *
23 */
24 class DefaultFilterComponentBuilder extends DefaultComponentAndConfigurationBuilder<FilterComponentBuilder>
25 implements FilterComponentBuilder {
26
27 public DefaultFilterComponentBuilder(final DefaultConfigurationBuilder<? extends Configuration> builder, final String type,
28 final String onMatch, final String onMisMatch) {
29 super(builder, type);
30 addAttribute("onMatch", onMatch);
31 addAttribute("onMisMatch", onMisMatch);
32 }
33 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder.impl;
17
18 import org.apache.logging.log4j.core.config.Configuration;
19 import org.apache.logging.log4j.core.config.builder.api.LayoutComponentBuilder;
20
21 /**
22 *
23 */
24 class DefaultLayoutComponentBuilder extends DefaultComponentAndConfigurationBuilder<LayoutComponentBuilder>
25 implements LayoutComponentBuilder {
26
27 public DefaultLayoutComponentBuilder(final DefaultConfigurationBuilder<? extends Configuration> builder, final String type) {
28 super(builder, type);
29 }
30 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder.impl;
17
18 import org.apache.logging.log4j.core.config.Configuration;
19 import org.apache.logging.log4j.core.config.builder.api.AppenderRefComponentBuilder;
20 import org.apache.logging.log4j.core.config.builder.api.FilterComponentBuilder;
21 import org.apache.logging.log4j.core.config.builder.api.LoggerComponentBuilder;
22
23 /**
24 *
25 */
26 class DefaultLoggerComponentBuilder extends DefaultComponentAndConfigurationBuilder<LoggerComponentBuilder>
27 implements LoggerComponentBuilder {
28
29 /**
30 * Configure a logger.
31 * @param builder
32 * @param name
33 * @param level
34 */
35 public DefaultLoggerComponentBuilder(final DefaultConfigurationBuilder<? extends Configuration> builder, final String name,
36 final String level) {
37 super(builder, name, "Logger");
38 addAttribute("level", level);
39 }
40
41 /**
42 * Configure a logger.
43 * @param builder
44 * @param name
45 * @param level
46 * @param type
47 */
48 public DefaultLoggerComponentBuilder(final DefaultConfigurationBuilder<? extends Configuration> builder, final String name,
49 final String level, final String type) {
50 super(builder, name, type);
51 addAttribute("level", level);
52 }
53
54 @Override
55 public LoggerComponentBuilder add(final AppenderRefComponentBuilder builder) {
56 return addComponent(builder);
57 }
58
59 @Override
60 public LoggerComponentBuilder add(final FilterComponentBuilder builder) {
61 return addComponent(builder);
62 }
63 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder.impl;
17
18 import org.apache.logging.log4j.core.config.Configuration;
19 import org.apache.logging.log4j.core.config.builder.api.AppenderRefComponentBuilder;
20 import org.apache.logging.log4j.core.config.builder.api.FilterComponentBuilder;
21 import org.apache.logging.log4j.core.config.builder.api.RootLoggerComponentBuilder;
22
23 /**
24 *
25 */
26 class DefaultRootLoggerComponentBuilder extends DefaultComponentAndConfigurationBuilder<RootLoggerComponentBuilder>
27 implements RootLoggerComponentBuilder {
28
29 /**
30 * Configure the root logger.
31 * @param builder
32 * @param level
33 */
34 public DefaultRootLoggerComponentBuilder(final DefaultConfigurationBuilder<? extends Configuration> builder,
35 final String level) {
36 super(builder, "", "Root");
37 addAttribute("level", level);
38 }
39
40 /**
41 * Configure the root logger.
42 * @param builder
43 * @param level
44 * @param type
45 */
46 public DefaultRootLoggerComponentBuilder(final DefaultConfigurationBuilder<? extends Configuration> builder,
47 final String level, final String type) {
48 super(builder, "", type);
49 addAttribute("level", level);
50 }
51
52 @Override
53 public RootLoggerComponentBuilder add(final AppenderRefComponentBuilder builder) {
54 return addComponent(builder);
55 }
56
57
58 @Override
59 public RootLoggerComponentBuilder add(final FilterComponentBuilder builder) {
60 return addComponent(builder);
61 }
62 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.json;
17
18 import com.fasterxml.jackson.core.JsonParser;
19 import com.fasterxml.jackson.databind.JsonNode;
20 import com.fasterxml.jackson.databind.ObjectMapper;
21 import org.apache.logging.log4j.core.config.AbstractConfiguration;
22 import org.apache.logging.log4j.core.config.Configuration;
23 import org.apache.logging.log4j.core.config.ConfigurationSource;
24 import org.apache.logging.log4j.core.config.FileConfigurationMonitor;
25 import org.apache.logging.log4j.core.config.Node;
26 import org.apache.logging.log4j.core.config.Reconfigurable;
27 import org.apache.logging.log4j.core.config.plugins.util.PluginType;
28 import org.apache.logging.log4j.core.config.plugins.util.ResolverUtil;
29 import org.apache.logging.log4j.core.config.status.StatusConfiguration;
30 import org.apache.logging.log4j.core.util.Patterns;
31
32 import java.io.ByteArrayInputStream;
33 import java.io.File;
34 import java.io.IOException;
35 import java.io.InputStream;
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.Iterator;
39 import java.util.List;
40 import java.util.Map;
41
42 /**
43 * Creates a Node hierarchy from a JSON file.
44 */
45 public class JsonConfiguration extends AbstractConfiguration implements Reconfigurable {
46
47 private static final long serialVersionUID = 1L;
48 private static final String[] VERBOSE_CLASSES = new String[] { ResolverUtil.class.getName() };
49 private final List<Status> status = new ArrayList<Status>();
50 private JsonNode root;
51
52 public JsonConfiguration(final ConfigurationSource configSource) {
53 super(configSource);
54 final File configFile = configSource.getFile();
55 byte[] buffer;
56 try {
57 final InputStream configStream = configSource.getInputStream();
58 try {
59 buffer = toByteArray(configStream);
60 } finally {
61 configStream.close();
62 }
63 final InputStream is = new ByteArrayInputStream(buffer);
64 root = getObjectMapper().readTree(is);
65 if (root.size() == 1) {
66 for (final JsonNode node : root) {
67 root = node;
68 }
69 }
70 processAttributes(rootNode, root);
71 final StatusConfiguration statusConfig = new StatusConfiguration().withVerboseClasses(VERBOSE_CLASSES)
72 .withStatus(getDefaultStatus());
73 for (final Map.Entry<String, String> entry : rootNode.getAttributes().entrySet()) {
74 final String key = entry.getKey();
75 final String value = getStrSubstitutor().replace(entry.getValue());
76 // TODO: this duplicates a lot of the XmlConfiguration constructor
77 if ("status".equalsIgnoreCase(key)) {
78 statusConfig.withStatus(value);
79 } else if ("dest".equalsIgnoreCase(key)) {
80 statusConfig.withDestination(value);
81 } else if ("shutdownHook".equalsIgnoreCase(key)) {
82 isShutdownHookEnabled = !"disable".equalsIgnoreCase(value);
83 } else if ("verbose".equalsIgnoreCase(entry.getKey())) {
84 statusConfig.withVerbosity(value);
85 } else if ("packages".equalsIgnoreCase(key)) {
86 pluginPackages.addAll(Arrays.asList(value.split(Patterns.COMMA_SEPARATOR)));
87 } else if ("name".equalsIgnoreCase(key)) {
88 setName(value);
89 } else if ("monitorInterval".equalsIgnoreCase(key)) {
90 final int interval = Integer.parseInt(value);
91 if (interval > 0 && configFile != null) {
92 monitor = new FileConfigurationMonitor(this, configFile, listeners, interval);
93 }
94 } else if ("advertiser".equalsIgnoreCase(key)) {
95 createAdvertiser(value, configSource, buffer, "application/json");
96 }
97 }
98 statusConfig.initialize();
99 if (getName() == null) {
100 setName(configSource.getLocation());
101 }
102 } catch (final Exception ex) {
103 LOGGER.error("Error parsing {}", configSource.getLocation(), ex);
104 }
105 }
106
107 protected ObjectMapper getObjectMapper() {
108 return new ObjectMapper().configure(JsonParser.Feature.ALLOW_COMMENTS, true);
109 }
110
111 @Override
112 public void setup() {
113 final Iterator<Map.Entry<String, JsonNode>> iter = root.fields();
114 final List<Node> children = rootNode.getChildren();
115 while (iter.hasNext()) {
116 final Map.Entry<String, JsonNode> entry = iter.next();
117 final JsonNode n = entry.getValue();
118 if (n.isObject()) {
119 LOGGER.debug("Processing node for object {}", entry.getKey());
120 children.add(constructNode(entry.getKey(), rootNode, n));
121 } else if (n.isArray()) {
122 LOGGER.error("Arrays are not supported at the root configuration.");
123 }
124 }
125 LOGGER.debug("Completed parsing configuration");
126 if (status.size() > 0) {
127 for (final Status s : status) {
128 LOGGER.error("Error processing element " + s.name + ": " + s.errorType);
129 }
130 }
131 }
132
133 @Override
134 public Configuration reconfigure() {
135 try {
136 final ConfigurationSource source = getConfigurationSource().resetInputStream();
137 if (source == null) {
138 return null;
139 }
140 return new JsonConfiguration(source);
141 } catch (final IOException ex) {
142 LOGGER.error("Cannot locate file {}", getConfigurationSource(), ex);
143 }
144 return null;
145 }
146
147 private Node constructNode(final String name, final Node parent, final JsonNode jsonNode) {
148 final PluginType<?> type = pluginManager.getPluginType(name);
149 final Node node = new Node(parent, name, type);
150 processAttributes(node, jsonNode);
151 final Iterator<Map.Entry<String, JsonNode>> iter = jsonNode.fields();
152 final List<Node> children = node.getChildren();
153 while (iter.hasNext()) {
154 final Map.Entry<String, JsonNode> entry = iter.next();
155 final JsonNode n = entry.getValue();
156 if (n.isArray() || n.isObject()) {
157 if (type == null) {
158 status.add(new Status(name, n, ErrorType.CLASS_NOT_FOUND));
159 }
160 if (n.isArray()) {
161 LOGGER.debug("Processing node for array {}", entry.getKey());
162 for (int i = 0; i < n.size(); ++i) {
163 final String pluginType = getType(n.get(i), entry.getKey());
164 final PluginType<?> entryType = pluginManager.getPluginType(pluginType);
165 final Node item = new Node(node, entry.getKey(), entryType);
166 processAttributes(item, n.get(i));
167 if (pluginType.equals(entry.getKey())) {
168 LOGGER.debug("Processing {}[{}]", entry.getKey(), i);
169 } else {
170 LOGGER.debug("Processing {} {}[{}]", pluginType, entry.getKey(), i);
171 }
172 final Iterator<Map.Entry<String, JsonNode>> itemIter = n.get(i).fields();
173 final List<Node> itemChildren = item.getChildren();
174 while (itemIter.hasNext()) {
175 final Map.Entry<String, JsonNode> itemEntry = itemIter.next();
176 if (itemEntry.getValue().isObject()) {
177 LOGGER.debug("Processing node for object {}", itemEntry.getKey());
178 itemChildren.add(constructNode(itemEntry.getKey(), item, itemEntry.getValue()));
179 } else if (itemEntry.getValue().isArray()) {
180 final JsonNode array = itemEntry.getValue();
181 final String entryName = itemEntry.getKey();
182 LOGGER.debug("Processing array for object {}", entryName);
183 for (int j = 0; j < array.size(); ++j) {
184 itemChildren.add(constructNode(entryName, item, array.get(j)));
185 }
186 }
187
188 }
189 children.add(item);
190 }
191 } else {
192 LOGGER.debug("Processing node for object {}", entry.getKey());
193 children.add(constructNode(entry.getKey(), node, n));
194 }
195 } else {
196 LOGGER.debug("Node {} is of type {}", entry.getKey(), n.getNodeType());
197 }
198 }
199
200 String t;
201 if (type == null) {
202 t = "null";
203 } else {
204 t = type.getElementName() + ':' + type.getPluginClass();
205 }
206
207 final String p = node.getParent() == null ? "null" : node.getParent().getName() == null ? "root" : node
208 .getParent().getName();
209 LOGGER.debug("Returning {} with parent {} of type {}", node.getName(), p, t);
210 return node;
211 }
212
213 private String getType(final JsonNode node, final String name) {
214 final Iterator<Map.Entry<String, JsonNode>> iter = node.fields();
215 while (iter.hasNext()) {
216 final Map.Entry<String, JsonNode> entry = iter.next();
217 if (entry.getKey().equalsIgnoreCase("type")) {
218 final JsonNode n = entry.getValue();
219 if (n.isValueNode()) {
220 return n.asText();
221 }
222 }
223 }
224 return name;
225 }
226
227 private void processAttributes(final Node parent, final JsonNode node) {
228 final Map<String, String> attrs = parent.getAttributes();
229 final Iterator<Map.Entry<String, JsonNode>> iter = node.fields();
230 while (iter.hasNext()) {
231 final Map.Entry<String, JsonNode> entry = iter.next();
232 if (!entry.getKey().equalsIgnoreCase("type")) {
233 final JsonNode n = entry.getValue();
234 if (n.isValueNode()) {
235 attrs.put(entry.getKey(), n.asText());
236 }
237 }
238 }
239 }
240
241 @Override
242 public String toString() {
243 return getClass().getSimpleName() + "[location=" + getConfigurationSource() + "]";
244 }
245
246 /**
247 * The error that occurred.
248 */
249 private enum ErrorType {
250 CLASS_NOT_FOUND
251 }
252
253 /**
254 * Status for recording errors.
255 */
256 private static class Status {
257 private final JsonNode node;
258 private final String name;
259 private final ErrorType errorType;
260
261 public Status(final String name, final JsonNode node, final ErrorType errorType) {
262 this.name = name;
263 this.node = node;
264 this.errorType = errorType;
265 }
266 }
267 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.json;
17
18 import com.fasterxml.jackson.core.JsonParser;
19 import com.fasterxml.jackson.databind.JsonNode;
20 import com.fasterxml.jackson.databind.ObjectMapper;
21 import org.apache.logging.log4j.core.config.AbstractConfiguration;
22 import org.apache.logging.log4j.core.config.Configuration;
23 import org.apache.logging.log4j.core.config.ConfigurationSource;
24 import org.apache.logging.log4j.core.config.FileConfigurationMonitor;
25 import org.apache.logging.log4j.core.config.Node;
26 import org.apache.logging.log4j.core.config.Reconfigurable;
27 import org.apache.logging.log4j.core.config.plugins.util.PluginType;
28 import org.apache.logging.log4j.core.config.plugins.util.ResolverUtil;
29 import org.apache.logging.log4j.core.config.status.StatusConfiguration;
30 import org.apache.logging.log4j.core.util.Patterns;
31
32 import java.io.ByteArrayInputStream;
33 import java.io.File;
34 import java.io.IOException;
35 import java.io.InputStream;
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.Iterator;
39 import java.util.List;
40 import java.util.Map;
41
42 /**
43 * Creates a Node hierarchy from a JSON file.
44 */
45 public class JsonConfiguration extends AbstractConfiguration implements Reconfigurable {
46
47 private static final long serialVersionUID = 1L;
48 private static final String[] VERBOSE_CLASSES = new String[] { ResolverUtil.class.getName() };
49 private final List<Status> status = new ArrayList<>();
50 private JsonNode root;
51
52 public JsonConfiguration(final ConfigurationSource configSource) {
53 super(configSource);
54 final File configFile = configSource.getFile();
55 byte[] buffer;
56 try {
57 try (final InputStream configStream = configSource.getInputStream()) {
58 buffer = toByteArray(configStream);
59 }
60 final InputStream is = new ByteArrayInputStream(buffer);
61 root = getObjectMapper().readTree(is);
62 if (root.size() == 1) {
63 for (final JsonNode node : root) {
64 root = node;
65 }
66 }
67 processAttributes(rootNode, root);
68 final StatusConfiguration statusConfig = new StatusConfiguration().withVerboseClasses(VERBOSE_CLASSES)
69 .withStatus(getDefaultStatus());
70 for (final Map.Entry<String, String> entry : rootNode.getAttributes().entrySet()) {
71 final String key = entry.getKey();
72 final String value = getStrSubstitutor().replace(entry.getValue());
73 // TODO: this duplicates a lot of the XmlConfiguration constructor
74 if ("status".equalsIgnoreCase(key)) {
75 statusConfig.withStatus(value);
76 } else if ("dest".equalsIgnoreCase(key)) {
77 statusConfig.withDestination(value);
78 } else if ("shutdownHook".equalsIgnoreCase(key)) {
79 isShutdownHookEnabled = !"disable".equalsIgnoreCase(value);
80 } else if ("verbose".equalsIgnoreCase(entry.getKey())) {
81 statusConfig.withVerbosity(value);
82 } else if ("packages".equalsIgnoreCase(key)) {
83 pluginPackages.addAll(Arrays.asList(value.split(Patterns.COMMA_SEPARATOR)));
84 } else if ("name".equalsIgnoreCase(key)) {
85 setName(value);
86 } else if ("monitorInterval".equalsIgnoreCase(key)) {
87 final int intervalSeconds = Integer.parseInt(value);
88 if (intervalSeconds > 0 && configFile != null) {
89 monitor = new FileConfigurationMonitor(this, configFile, listeners, intervalSeconds);
90 }
91 } else if ("advertiser".equalsIgnoreCase(key)) {
92 createAdvertiser(value, configSource, buffer, "application/json");
93 }
94 }
95 statusConfig.initialize();
96 if (getName() == null) {
97 setName(configSource.getLocation());
98 }
99 } catch (final Exception ex) {
100 LOGGER.error("Error parsing {}", configSource.getLocation(), ex);
101 }
102 }
103
104 protected ObjectMapper getObjectMapper() {
105 return new ObjectMapper().configure(JsonParser.Feature.ALLOW_COMMENTS, true);
106 }
107
108 @Override
109 public void setup() {
110 final Iterator<Map.Entry<String, JsonNode>> iter = root.fields();
111 final List<Node> children = rootNode.getChildren();
112 while (iter.hasNext()) {
113 final Map.Entry<String, JsonNode> entry = iter.next();
114 final JsonNode n = entry.getValue();
115 if (n.isObject()) {
116 LOGGER.debug("Processing node for object {}", entry.getKey());
117 children.add(constructNode(entry.getKey(), rootNode, n));
118 } else if (n.isArray()) {
119 LOGGER.error("Arrays are not supported at the root configuration.");
120 }
121 }
122 LOGGER.debug("Completed parsing configuration");
123 if (status.size() > 0) {
124 for (final Status s : status) {
125 LOGGER.error("Error processing element " + s.name + ": " + s.errorType);
126 }
127 }
128 }
129
130 @Override
131 public Configuration reconfigure() {
132 try {
133 final ConfigurationSource source = getConfigurationSource().resetInputStream();
134 if (source == null) {
135 return null;
136 }
137 return new JsonConfiguration(source);
138 } catch (final IOException ex) {
139 LOGGER.error("Cannot locate file {}", getConfigurationSource(), ex);
140 }
141 return null;
142 }
143
144 private Node constructNode(final String name, final Node parent, final JsonNode jsonNode) {
145 final PluginType<?> type = pluginManager.getPluginType(name);
146 final Node node = new Node(parent, name, type);
147 processAttributes(node, jsonNode);
148 final Iterator<Map.Entry<String, JsonNode>> iter = jsonNode.fields();
149 final List<Node> children = node.getChildren();
150 while (iter.hasNext()) {
151 final Map.Entry<String, JsonNode> entry = iter.next();
152 final JsonNode n = entry.getValue();
153 if (n.isArray() || n.isObject()) {
154 if (type == null) {
155 status.add(new Status(name, n, ErrorType.CLASS_NOT_FOUND));
156 }
157 if (n.isArray()) {
158 LOGGER.debug("Processing node for array {}", entry.getKey());
159 for (int i = 0; i < n.size(); ++i) {
160 final String pluginType = getType(n.get(i), entry.getKey());
161 final PluginType<?> entryType = pluginManager.getPluginType(pluginType);
162 final Node item = new Node(node, entry.getKey(), entryType);
163 processAttributes(item, n.get(i));
164 if (pluginType.equals(entry.getKey())) {
165 LOGGER.debug("Processing {}[{}]", entry.getKey(), i);
166 } else {
167 LOGGER.debug("Processing {} {}[{}]", pluginType, entry.getKey(), i);
168 }
169 final Iterator<Map.Entry<String, JsonNode>> itemIter = n.get(i).fields();
170 final List<Node> itemChildren = item.getChildren();
171 while (itemIter.hasNext()) {
172 final Map.Entry<String, JsonNode> itemEntry = itemIter.next();
173 if (itemEntry.getValue().isObject()) {
174 LOGGER.debug("Processing node for object {}", itemEntry.getKey());
175 itemChildren.add(constructNode(itemEntry.getKey(), item, itemEntry.getValue()));
176 } else if (itemEntry.getValue().isArray()) {
177 final JsonNode array = itemEntry.getValue();
178 final String entryName = itemEntry.getKey();
179 LOGGER.debug("Processing array for object {}", entryName);
180 for (int j = 0; j < array.size(); ++j) {
181 itemChildren.add(constructNode(entryName, item, array.get(j)));
182 }
183 }
184
185 }
186 children.add(item);
187 }
188 } else {
189 LOGGER.debug("Processing node for object {}", entry.getKey());
190 children.add(constructNode(entry.getKey(), node, n));
191 }
192 } else {
193 LOGGER.debug("Node {} is of type {}", entry.getKey(), n.getNodeType());
194 }
195 }
196
197 String t;
198 if (type == null) {
199 t = "null";
200 } else {
201 t = type.getElementName() + ':' + type.getPluginClass();
202 }
203
204 final String p = node.getParent() == null ? "null" : node.getParent().getName() == null ? "root" : node
205 .getParent().getName();
206 LOGGER.debug("Returning {} with parent {} of type {}", node.getName(), p, t);
207 return node;
208 }
209
210 private String getType(final JsonNode node, final String name) {
211 final Iterator<Map.Entry<String, JsonNode>> iter = node.fields();
212 while (iter.hasNext()) {
213 final Map.Entry<String, JsonNode> entry = iter.next();
214 if (entry.getKey().equalsIgnoreCase("type")) {
215 final JsonNode n = entry.getValue();
216 if (n.isValueNode()) {
217 return n.asText();
218 }
219 }
220 }
221 return name;
222 }
223
224 private void processAttributes(final Node parent, final JsonNode node) {
225 final Map<String, String> attrs = parent.getAttributes();
226 final Iterator<Map.Entry<String, JsonNode>> iter = node.fields();
227 while (iter.hasNext()) {
228 final Map.Entry<String, JsonNode> entry = iter.next();
229 if (!entry.getKey().equalsIgnoreCase("type")) {
230 final JsonNode n = entry.getValue();
231 if (n.isValueNode()) {
232 attrs.put(entry.getKey(), n.asText());
233 }
234 }
235 }
236 }
237
238 @Override
239 public String toString() {
240 return getClass().getSimpleName() + "[location=" + getConfigurationSource() + "]";
241 }
242
243 /**
244 * The error that occurred.
245 */
246 private enum ErrorType {
247 CLASS_NOT_FOUND
248 }
249
250 /**
251 * Status for recording errors.
252 */
253 private static class Status {
254 private final JsonNode node;
255 private final String name;
256 private final ErrorType errorType;
257
258 public Status(final String name, final JsonNode node, final ErrorType errorType) {
259 this.name = name;
260 this.node = node;
261 this.errorType = errorType;
262 }
263
264 @Override
265 public String toString() {
266 return "Status [name=" + name + ", errorType=" + errorType + ", node=" + node + "]";
267 }
268 }
269 }
1919 import java.lang.reflect.Type;
2020 import java.util.Collection;
2121 import java.util.Map;
22 import java.util.Objects;
2223 import java.util.UnknownFormatConversionException;
2324 import java.util.concurrent.ConcurrentHashMap;
2425 import java.util.concurrent.ConcurrentMap;
2627 import org.apache.logging.log4j.Logger;
2728 import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
2829 import org.apache.logging.log4j.core.config.plugins.util.PluginType;
29 import org.apache.logging.log4j.core.util.Assert;
3030 import org.apache.logging.log4j.core.util.ReflectionUtil;
3131 import org.apache.logging.log4j.core.util.TypeUtil;
3232 import org.apache.logging.log4j.status.StatusLogger;
4242 private static volatile TypeConverterRegistry INSTANCE;
4343 private static final Object INSTANCE_LOCK = new Object();
4444
45 private final ConcurrentMap<Type, TypeConverter<?>> registry = new ConcurrentHashMap<Type, TypeConverter<?>>();
45 private final ConcurrentMap<Type, TypeConverter<?>> registry = new ConcurrentHashMap<>();
4646
4747 /**
4848 * Gets the singleton instance of the TypeConverterRegistry.
7373 * @throws UnknownFormatConversionException if no TypeConverter can be found for the given type.
7474 */
7575 public TypeConverter<?> findCompatibleConverter(final Type type) {
76 Assert.requireNonNull(type, "No type was provided");
76 Objects.requireNonNull(type, "No type was provided");
7777 final TypeConverter<?> primary = registry.get(type);
7878 // cached type converters
7979 if (primary != null) {
3434 */
3535 public class PluginCache {
3636 private final Map<String, Map<String, PluginEntry>> categories =
37 new LinkedHashMap<String, Map<String, PluginEntry>>();
37 new LinkedHashMap<>();
3838
3939 /**
4040 * Returns all categories of plugins in this cache.
3838 import java.util.Collection;
3939 import java.util.Collections;
4040 import java.util.Map;
41 import java.util.Objects;
4142 import java.util.Set;
4243
4344 /**
100101 }
101102
102103 private void writeCacheFile(final Element... elements) throws IOException {
103 final FileObject fo = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT,
104 Strings.EMPTY, PLUGIN_CACHE_FILE, elements);
105 final OutputStream out = fo.openOutputStream();
106 try {
104 final FileObject fo = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, Strings.EMPTY,
105 PLUGIN_CACHE_FILE, elements);
106 try (final OutputStream out = fo.openOutputStream()) {
107107 pluginCache.writeCache(out);
108 } finally {
109 out.close();
110108 }
111109 }
112110
123121
124122 @Override
125123 public PluginEntry visitType(final TypeElement e, final Plugin plugin) {
126 if (plugin == null) {
127 throw new NullPointerException("Plugin annotation is null.");
128 }
124 Objects.requireNonNull(plugin, "Plugin annotation is null.");
129125 final PluginEntry entry = new PluginEntry();
130126 entry.setKey(plugin.name().toLowerCase());
131127 entry.setClassName(elements.getBinaryName(e).toString());
155151 if (aliases == null) {
156152 return DEFAULT_VALUE;
157153 }
158 final Collection<PluginEntry> entries = new ArrayList<PluginEntry>(aliases.value().length);
154 final Collection<PluginEntry> entries = new ArrayList<>(aliases.value().length);
159155 for (final String alias : aliases.value()) {
160156 final PluginEntry entry = new PluginEntry();
161157 entry.setKey(alias.toLowerCase());
2525 import java.util.Collection;
2626 import java.util.List;
2727 import java.util.Map;
28 import java.util.Objects;
2829
2930 import org.apache.logging.log4j.Logger;
3031 import org.apache.logging.log4j.core.LogEvent;
3839 import org.apache.logging.log4j.core.config.plugins.validation.ConstraintValidators;
3940 import org.apache.logging.log4j.core.config.plugins.visitors.PluginVisitor;
4041 import org.apache.logging.log4j.core.config.plugins.visitors.PluginVisitors;
41 import org.apache.logging.log4j.core.util.Assert;
4242 import org.apache.logging.log4j.core.util.Builder;
4343 import org.apache.logging.log4j.core.util.ReflectionUtil;
4444 import org.apache.logging.log4j.core.util.TypeUtil;
4545 import org.apache.logging.log4j.status.StatusLogger;
46 import org.apache.logging.log4j.util.StringBuilders;
4647
4748 /**
4849 * Builder class to instantiate and configure a Plugin object using a PluginFactory method or PluginBuilderFactory
142143 }
143144
144145 private void verify() {
145 Assert.requireNonNull(this.configuration, "No Configuration object was set.");
146 Assert.requireNonNull(this.node, "No Node object was set.");
146 Objects.requireNonNull(this.configuration, "No Configuration object was set.");
147 Objects.requireNonNull(this.node, "No Node object was set.");
147148 }
148149
149150 private static Builder<?> createBuilder(final Class<?> clazz)
301302 } else {
302303 sb.append(", ");
303304 }
304 sb.append('"');
305 sb.append(key);
306 sb.append('"');
307
305 StringBuilders.appendDqValue(sb, key);
308306 }
309307 LOGGER.error(sb.toString());
310308 }
3232 */
3333 public class PluginManager {
3434
35 private static final CopyOnWriteArrayList<String> PACKAGES = new CopyOnWriteArrayList<String>();
35 private static final CopyOnWriteArrayList<String> PACKAGES = new CopyOnWriteArrayList<>();
3636 private static final String LOG4J_PACKAGES = "org.apache.logging.log4j.core";
3737
3838 private static final Logger LOGGER = StatusLogger.getLogger();
3939
40 private Map<String, PluginType<?>> plugins = new HashMap<String, PluginType<?>>();
40 private Map<String, PluginType<?>> plugins = new HashMap<>();
4141 private final String category;
4242
4343 /**
125125 */
126126 public void collectPlugins(final List<String> packages) {
127127 final String categoryLowerCase = category.toLowerCase();
128 final Map<String, PluginType<?>> newPlugins = new LinkedHashMap<String, PluginType<?>>();
128 final Map<String, PluginType<?>> newPlugins = new LinkedHashMap<>();
129129
130130 // First, iterate the Log4j2Plugin.dat files found in the main CLASSPATH
131131 Map<String, List<PluginType<?>>> builtInPlugins = PluginRegistry.getInstance().loadFromMainClassLoader();
5454 * Contains plugins found in Log4j2Plugins.dat cache files in the main CLASSPATH.
5555 */
5656 private final AtomicReference<Map<String, List<PluginType<?>>>> pluginsByCategoryRef =
57 new AtomicReference<Map<String, List<PluginType<?>>>>();
57 new AtomicReference<>();
5858
5959 /**
6060 * Contains plugins found in Log4j2Plugins.dat cache files in OSGi Bundles.
6161 */
6262 private final ConcurrentMap<Long, Map<String, List<PluginType<?>>>> pluginsByCategoryByBundleId =
63 new ConcurrentHashMap<Long, Map<String, List<PluginType<?>>>>();
63 new ConcurrentHashMap<>();
6464
6565 /**
6666 * Contains plugins found by searching for annotated classes at runtime.
6767 */
6868 private final ConcurrentMap<String, Map<String, List<PluginType<?>>>> pluginsByCategoryByPackage =
69 new ConcurrentHashMap<String, Map<String, List<PluginType<?>>>>();
69 new ConcurrentHashMap<>();
7070
7171 private PluginRegistry() {
7272 }
167167 } catch (final IOException ioe) {
168168 LOGGER.warn("Unable to preload plugins", ioe);
169169 }
170 final Map<String, List<PluginType<?>>> newPluginsByCategory = new HashMap<String, List<PluginType<?>>>();
170 final Map<String, List<PluginType<?>>> newPluginsByCategory = new HashMap<>();
171171 int pluginCount = 0;
172172 for (final Map.Entry<String, Map<String, PluginEntry>> outer : cache.getAllCategories().entrySet()) {
173173 final String categoryLowerCase = outer.getKey();
174 final List<PluginType<?>> types = new ArrayList<PluginType<?>>(outer.getValue().size());
174 final List<PluginType<?>> types = new ArrayList<>(outer.getValue().size());
175175 newPluginsByCategory.put(categoryLowerCase, types);
176176 for (final Map.Entry<String, PluginEntry> inner : outer.getValue().entrySet()) {
177177 final PluginEntry entry = inner.getValue();
179179 try {
180180 final Class<?> clazz = loader.loadClass(className);
181181 @SuppressWarnings({"unchecked","rawtypes"})
182 final PluginType<?> type = new PluginType(entry, clazz, entry.getName());
182 final PluginType<?> type = new PluginType<>(entry, clazz, entry.getName());
183183 types.add(type);
184184 ++pluginCount;
185185 } catch (final ClassNotFoundException e) {
220220 }
221221 resolver.findInPackage(new PluginTest(), pkg);
222222
223 final Map<String, List<PluginType<?>>> newPluginsByCategory = new HashMap<String, List<PluginType<?>>>();
223 final Map<String, List<PluginType<?>>> newPluginsByCategory = new HashMap<>();
224224 for (final Class<?> clazz : resolver.getClasses()) {
225225 final Plugin plugin = clazz.getAnnotation(Plugin.class);
226226 final String categoryLowerCase = plugin.category().toLowerCase();
227227 List<PluginType<?>> list = newPluginsByCategory.get(categoryLowerCase);
228228 if (list == null) {
229 newPluginsByCategory.put(categoryLowerCase, list = new ArrayList<PluginType<?>>());
229 newPluginsByCategory.put(categoryLowerCase, list = new ArrayList<>());
230230 }
231231 final PluginEntry mainEntry = new PluginEntry();
232232 final String mainElementName = plugin.elementType().equals(
237237 mainEntry.setClassName(clazz.getName());
238238 mainEntry.setPrintable(plugin.printObject());
239239 mainEntry.setDefer(plugin.deferChildren());
240 @SuppressWarnings({"unchecked","rawtypes"})
241 final PluginType<?> mainType = new PluginType(mainEntry, clazz, mainElementName);
240 final PluginType<?> mainType = new PluginType<>(mainEntry, clazz, mainElementName);
242241 list.add(mainType);
243242 final PluginAliases pluginAliases = clazz.getAnnotation(PluginAliases.class);
244243 if (pluginAliases != null) {
252251 aliasEntry.setClassName(clazz.getName());
253252 aliasEntry.setPrintable(plugin.printObject());
254253 aliasEntry.setDefer(plugin.deferChildren());
255 @SuppressWarnings({"unchecked","rawtypes"})
256 final PluginType<?> aliasType = new PluginType(aliasEntry, clazz, aliasElementName);
254 final PluginType<?> aliasType = new PluginType<>(aliasEntry, clazz, aliasElementName);
257255 list.add(aliasType);
258256 }
259257 }
2121 import java.io.IOException;
2222 import java.io.UnsupportedEncodingException;
2323 import java.net.URI;
24 import java.net.URISyntaxException;
2425 import java.net.URL;
2526 import java.net.URLDecoder;
27 import java.nio.charset.StandardCharsets;
2628 import java.util.Arrays;
2729 import java.util.Collection;
2830 import java.util.Enumeration;
3335 import java.util.jar.JarInputStream;
3436
3537 import org.apache.logging.log4j.Logger;
36 import org.apache.logging.log4j.core.util.Charsets;
3738 import org.apache.logging.log4j.core.util.Loader;
3839 import org.apache.logging.log4j.status.StatusLogger;
3940 import org.osgi.framework.FrameworkUtil;
4041 import org.osgi.framework.wiring.BundleWiring;
4142
4243 /**
43 * <p>ResolverUtil is used to locate classes that are available in the/a class path and meet
44 * arbitrary conditions. The two most common conditions are that a class implements/extends
45 * another class, or that is it annotated with a specific annotation. However, through the use
46 * of the {@link Test} class it is possible to search using arbitrary conditions.</p>
47 *
48 * <p>A ClassLoader is used to locate all locations (directories and jar files) in the class
49 * path that contain classes within certain packages, and then to load those classes and
50 * check them. By default the ClassLoader returned by
51 * {@code Thread.currentThread().getContextClassLoader()} is used, but this can be overridden
52 * by calling {@link #setClassLoader(ClassLoader)} prior to invoking any of the {@code find()}
53 * methods.</p>
54 *
55 * <p>General searches are initiated by calling the
56 * {@link #find(ResolverUtil.Test, String...)} method and supplying
57 * a package name and a Test instance. This will cause the named package <b>and all sub-packages</b>
58 * to be scanned for classes that meet the test. There are also utility methods for the common
59 * use cases of scanning multiple packages for extensions of particular classes, or classes
60 * annotated with a specific annotation.</p>
61 *
62 * <p>The standard usage pattern for the ResolverUtil class is as follows:</p>
63 *
64 *<pre>
65 *ResolverUtil&lt;ActionBean&gt; resolver = new ResolverUtil&lt;ActionBean&gt;();
66 *resolver.findImplementation(ActionBean.class, pkg1, pkg2);
67 *resolver.find(new CustomTest(), pkg1);
68 *resolver.find(new CustomTest(), pkg2);
69 *Collection&lt;ActionBean&gt; beans = resolver.getClasses();
70 *</pre>
71 *
72 * <p>This class was copied and modified from Stripes - http://stripes.mc4j.org/confluence/display/stripes/Home
44 * <p>
45 * ResolverUtil is used to locate classes that are available in the/a class path and meet arbitrary conditions. The two
46 * most common conditions are that a class implements/extends another class, or that is it annotated with a specific
47 * annotation. However, through the use of the {@link Test} class it is possible to search using arbitrary conditions.
48 * </p>
49 *
50 * <p>
51 * A ClassLoader is used to locate all locations (directories and jar files) in the class path that contain classes
52 * within certain packages, and then to load those classes and check them. By default the ClassLoader returned by
53 * {@code Thread.currentThread().getContextClassLoader()} is used, but this can be overridden by calling
54 * {@link #setClassLoader(ClassLoader)} prior to invoking any of the {@code find()} methods.
55 * </p>
56 *
57 * <p>
58 * General searches are initiated by calling the {@link #find(ResolverUtil.Test, String...)} method and supplying a
59 * package name and a Test instance. This will cause the named package <b>and all sub-packages</b> to be scanned for
60 * classes that meet the test. There are also utility methods for the common use cases of scanning multiple packages for
61 * extensions of particular classes, or classes annotated with a specific annotation.
62 * </p>
63 *
64 * <p>
65 * The standard usage pattern for the ResolverUtil class is as follows:
66 * </p>
67 *
68 * <pre>
69 * ResolverUtil&lt;ActionBean&gt; resolver = new ResolverUtil&lt;ActionBean&gt;();
70 * resolver.findImplementation(ActionBean.class, pkg1, pkg2);
71 * resolver.find(new CustomTest(), pkg1);
72 * resolver.find(new CustomTest(), pkg2);
73 * Collection&lt;ActionBean&gt; beans = resolver.getClasses();
74 * </pre>
75 *
76 * <p>
77 * This class was copied and modified from Stripes - http://stripes.mc4j.org/confluence/display/stripes/Home
7378 * </p>
7479 */
7580 public class ResolverUtil {
8186 private static final String BUNDLE_RESOURCE = "bundleresource";
8287
8388 /** The set of matches being accumulated. */
84 private final Set<Class<?>> classMatches = new HashSet<Class<?>>();
89 private final Set<Class<?>> classMatches = new HashSet<>();
8590
8691 /** The set of matches being accumulated. */
87 private final Set<URI> resourceMatches = new HashSet<URI>();
88
89 /**
90 * The ClassLoader to use when looking for classes. If null then the ClassLoader returned
91 * by Thread.currentThread().getContextClassLoader() will be used.
92 private final Set<URI> resourceMatches = new HashSet<>();
93
94 /**
95 * The ClassLoader to use when looking for classes. If null then the ClassLoader returned by
96 * Thread.currentThread().getContextClassLoader() will be used.
9297 */
9398 private ClassLoader classloader;
9499
95100 /**
96 * Provides access to the classes discovered so far. If no calls have been made to
97 * any of the {@code find()} methods, this set will be empty.
101 * Provides access to the classes discovered so far. If no calls have been made to any of the {@code find()}
102 * methods, this set will be empty.
98103 *
99104 * @return the set of classes that have been discovered.
100105 */
104109
105110 /**
106111 * Returns the matching resources.
112 *
107113 * @return A Set of URIs that match the criteria.
108114 */
109115 public Set<URI> getResources() {
110116 return resourceMatches;
111117 }
112118
113
114 /**
115 * Returns the classloader that will be used for scanning for classes. If no explicit
116 * ClassLoader has been set by the calling, the context class loader will be used.
119 /**
120 * Returns the classloader that will be used for scanning for classes. If no explicit ClassLoader has been set by
121 * the calling, the context class loader will be used.
117122 *
118123 * @return the ClassLoader that will be used to scan for classes
119124 */
122127 }
123128
124129 /**
125 * Sets an explicit ClassLoader that should be used when scanning for classes. If none
126 * is set then the context classloader will be used.
127 *
128 * @param classloader a ClassLoader to use when scanning for classes
129 */
130 public void setClassLoader(final ClassLoader classloader) { this.classloader = classloader; }
131
132 /**
133 * Attempts to discover classes that pass the test. Accumulated
134 * classes can be accessed by calling {@link #getClasses()}.
135 *
136 * @param test the test to determine matching classes
137 * @param packageNames one or more package names to scan (including subpackages) for classes
130 * Sets an explicit ClassLoader that should be used when scanning for classes. If none is set then the context
131 * classloader will be used.
132 *
133 * @param classloader
134 * a ClassLoader to use when scanning for classes
135 */
136 public void setClassLoader(final ClassLoader classloader) {
137 this.classloader = classloader;
138 }
139
140 /**
141 * Attempts to discover classes that pass the test. Accumulated classes can be accessed by calling
142 * {@link #getClasses()}.
143 *
144 * @param test
145 * the test to determine matching classes
146 * @param packageNames
147 * one or more package names to scan (including subpackages) for classes
138148 */
139149 public void find(final Test test, final String... packageNames) {
140150 if (packageNames == null) {
147157 }
148158
149159 /**
150 * Scans for classes starting at the package provided and descending into subpackages.
151 * Each class is offered up to the Test as it is discovered, and if the Test returns
152 * true the class is retained. Accumulated classes can be fetched by calling
153 * {@link #getClasses()}.
154 *
155 * @param test an instance of {@link Test} that will be used to filter classes
156 * @param packageName the name of the package from which to start scanning for
157 * classes, e.g. {@code net.sourceforge.stripes}
160 * Scans for classes starting at the package provided and descending into subpackages. Each class is offered up to
161 * the Test as it is discovered, and if the Test returns true the class is retained. Accumulated classes can be
162 * fetched by calling {@link #getClasses()}.
163 *
164 * @param test
165 * an instance of {@link Test} that will be used to filter classes
166 * @param packageName
167 * the name of the package from which to start scanning for classes, e.g. {@code net.sourceforge.stripes}
158168 */
159169 public void findInPackage(final Test test, String packageName) {
160170 packageName = packageName.replace('.', '/');
197207 }
198208 } catch (final IOException ioe) {
199209 LOGGER.warn("could not read entries", ioe);
200 }
201 }
202 }
203
204 String extractPath(final URL url) throws UnsupportedEncodingException {
210 } catch (final URISyntaxException e) {
211 LOGGER.warn("could not read entries", e);
212 }
213 }
214 }
215
216 String extractPath(final URL url) throws UnsupportedEncodingException, URISyntaxException {
205217 String urlPath = url.getPath(); // same as getFile but without the Query portion
206 //System.out.println(url.getProtocol() + "->" + urlPath);
218 // System.out.println(url.getProtocol() + "->" + urlPath);
207219
208220 // I would be surprised if URL.getPath() ever starts with "jar:" but no harm in checking
209221 if (urlPath.startsWith("jar:")) {
225237 if (neverDecode.contains(protocol)) {
226238 return urlPath;
227239 }
228 if (new File(urlPath).exists()) {
240 final String cleanPath = new URI(urlPath).getPath();
241 if (new File(cleanPath).exists()) {
229242 // if URL-encoded file exists, don't decode it
230 return urlPath;
231 }
232 urlPath = URLDecoder.decode(urlPath, Charsets.UTF_8.name());
233 return urlPath;
243 return cleanPath;
244 }
245 return URLDecoder.decode(urlPath, StandardCharsets.UTF_8.name());
234246 }
235247
236248 private void loadImplementationsInBundle(final Test test, final String packageName) {
237 //Do not remove the cast on the next line as removing it will cause a compile error on Java 7.
238 @SuppressWarnings("RedundantCast")
239 final BundleWiring wiring = (BundleWiring) FrameworkUtil.getBundle(
240 ResolverUtil.class).adapt(BundleWiring.class);
241 @SuppressWarnings("unchecked")
242 final Collection<String> list = (Collection<String>) wiring.listResources(packageName, "*.class",
243 BundleWiring.LISTRESOURCES_RECURSE);
249 final BundleWiring wiring = FrameworkUtil.getBundle(ResolverUtil.class).adapt(BundleWiring.class);
250 final Collection<String> list = wiring.listResources(packageName, "*.class",
251 BundleWiring.LISTRESOURCES_RECURSE);
244252 for (final String name : list) {
245253 addIfMatching(test, name);
246254 }
247255 }
248256
249
250 /**
251 * Finds matches in a physical directory on a filesystem. Examines all
252 * files within a directory - if the File object is not a directory, and ends with <i>.class</i>
253 * the file is loaded and tested to see if it is acceptable according to the Test. Operates
254 * recursively to find classes within a folder structure matching the package structure.
255 *
256 * @param test a Test used to filter the classes that are discovered
257 * @param parent the package name up to this directory in the package hierarchy. E.g. if
258 * /classes is in the classpath and we wish to examine files in /classes/org/apache then
259 * the values of <i>parent</i> would be <i>org/apache</i>
260 * @param location a File object representing a directory
257 /**
258 * Finds matches in a physical directory on a filesystem. Examines all files within a directory - if the File object
259 * is not a directory, and ends with <i>.class</i> the file is loaded and tested to see if it is acceptable
260 * according to the Test. Operates recursively to find classes within a folder structure matching the package
261 * structure.
262 *
263 * @param test
264 * a Test used to filter the classes that are discovered
265 * @param parent
266 * the package name up to this directory in the package hierarchy. E.g. if /classes is in the classpath and
267 * we wish to examine files in /classes/org/apache then the values of <i>parent</i> would be
268 * <i>org/apache</i>
269 * @param location
270 * a File object representing a directory
261271 */
262272 private void loadImplementationsInDirectory(final Test test, final String parent, final File location) {
263273 final File[] files = location.listFiles();
284294 }
285295
286296 /**
287 * Finds matching classes within a jar files that contains a folder structure
288 * matching the package structure. If the File is not a JarFile or does not exist a warning
289 * will be logged, but no error will be raised.
290 *
291 * @param test a Test used to filter the classes that are discovered
292 * @param parent the parent package under which classes must be in order to be considered
293 * @param jarFile the jar file to be examined for classes
297 * Finds matching classes within a jar files that contains a folder structure matching the package structure. If the
298 * File is not a JarFile or does not exist a warning will be logged, but no error will be raised.
299 *
300 * @param test
301 * a Test used to filter the classes that are discovered
302 * @param parent
303 * the parent package under which classes must be in order to be considered
304 * @param jarFile
305 * the jar file to be examined for classes
294306 */
295307 private void loadImplementationsInJar(final Test test, final String parent, final File jarFile) {
296308 @SuppressWarnings("resource")
324336 }
325337
326338 /**
327 * Finds matching classes within a jar files that contains a folder structure
328 * matching the package structure. If the File is not a JarFile or does not exist a warning
329 * will be logged, but no error will be raised.
330 *
331 * @param test a Test used to filter the classes that are discovered
332 * @param parent the parent package under which classes must be in order to be considered
333 * @param stream The jar InputStream
339 * Finds matching classes within a jar files that contains a folder structure matching the package structure. If the
340 * File is not a JarFile or does not exist a warning will be logged, but no error will be raised.
341 *
342 * @param test
343 * a Test used to filter the classes that are discovered
344 * @param parent
345 * the parent package under which classes must be in order to be considered
346 * @param stream
347 * The jar InputStream
334348 */
335349 private void loadImplementationsInJar(final Test test, final String parent, final String path,
336 final JarInputStream stream) {
350 final JarInputStream stream) {
337351
338352 try {
339353 JarEntry entry;
345359 }
346360 }
347361 } catch (final IOException ioe) {
348 LOGGER.error("Could not search jar file '" + path + "' for classes matching criteria: " +
349 test + " due to an IOException", ioe);
350 }
351 }
352
353 /**
354 * Add the class designated by the fully qualified class name provided to the set of
355 * resolved classes if and only if it is approved by the Test supplied.
356 *
357 * @param test the test used to determine if the class matches
358 * @param fqn the fully qualified name of a class
362 LOGGER.error("Could not search jar file '" + path + "' for classes matching criteria: " + test
363 + " due to an IOException", ioe);
364 }
365 }
366
367 /**
368 * Add the class designated by the fully qualified class name provided to the set of resolved classes if and only if
369 * it is approved by the Test supplied.
370 *
371 * @param test
372 * the test used to determine if the class matches
373 * @param fqn
374 * the fully qualified name of a class
359375 */
360376 protected void addIfMatching(final Test test, final String fqn) {
361377 try {
386402 }
387403
388404 /**
389 * A simple interface that specifies how to test classes to determine if they
390 * are to be included in the results produced by the ResolverUtil.
405 * A simple interface that specifies how to test classes to determine if they are to be included in the results
406 * produced by the ResolverUtil.
391407 */
392408 public interface Test {
393409 /**
394 * Will be called repeatedly with candidate classes. Must return True if a class
395 * is to be included in the results, false otherwise.
396 * @param type The Class to match against.
410 * Will be called repeatedly with candidate classes. Must return True if a class is to be included in the
411 * results, false otherwise.
412 *
413 * @param type
414 * The Class to match against.
397415 * @return true if the Class matches.
398416 */
399417 boolean matches(Class<?> type);
400418
401419 /**
402420 * Test for a resource.
403 * @param resource The URI to the resource.
421 *
422 * @param resource
423 * The URI to the resource.
404424 * @return true if the resource matches.
405425 */
406426 boolean matches(URI resource);
4242 */
4343 public static Collection<ConstraintValidator<?>> findValidators(final Annotation... annotations) {
4444 final Collection<ConstraintValidator<?>> validators =
45 new ArrayList<ConstraintValidator<?>>();
45 new ArrayList<>();
4646 for (final Annotation annotation : annotations) {
4747 final Class<? extends Annotation> type = annotation.annotationType();
4848 if (type.isAnnotationPresent(Constraint.class)) {
1919 import java.lang.annotation.Annotation;
2020 import java.lang.reflect.Member;
2121 import java.util.Map;
22 import java.util.Objects;
2223
2324 import org.apache.logging.log4j.Logger;
2425 import org.apache.logging.log4j.core.config.plugins.convert.TypeConverters;
2526 import org.apache.logging.log4j.core.lookup.StrSubstitutor;
26 import org.apache.logging.log4j.core.util.Assert;
2727 import org.apache.logging.log4j.status.StatusLogger;
2828 import org.apache.logging.log4j.util.Strings;
2929
5656 @SuppressWarnings("unchecked")
5757 @Override
5858 public PluginVisitor<A> setAnnotation(final Annotation annotation) {
59 final Annotation a = Assert.requireNonNull(annotation, "No annotation was provided");
59 final Annotation a = Objects.requireNonNull(annotation, "No annotation was provided");
6060 if (this.clazz.isInstance(a)) {
6161 this.annotation = (A) a;
6262 }
7171
7272 @Override
7373 public PluginVisitor<A> setConversionType(final Class<?> conversionType) {
74 this.conversionType = Assert.requireNonNull(conversionType, "No conversion type class was provided");
74 this.conversionType = Objects.requireNonNull(conversionType, "No conversion type class was provided");
7575 return this;
7676 }
7777
7878 @Override
7979 public PluginVisitor<A> setStrSubstitutor(final StrSubstitutor substitutor) {
80 this.substitutor = Assert.requireNonNull(substitutor, "No StrSubstitutor was provided");
80 this.substitutor = Objects.requireNonNull(substitutor, "No StrSubstitutor was provided");
8181 return this;
8282 }
8383
2323 import org.apache.logging.log4j.core.config.Node;
2424 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
2525 import org.apache.logging.log4j.core.util.NameUtil;
26 import org.apache.logging.log4j.util.StringBuilders;
2627
2728 /**
2829 * PluginVisitor implementation for {@link PluginAttribute}.
4243 final Object defaultValue = findDefaultValue(event);
4344 final Object value = convert(replacedValue, defaultValue);
4445 final Object debugValue = this.annotation.sensitive() ? NameUtil.md5(value + this.getClass().getName()) : value;
45 log.append(name).append("=\"").append(debugValue).append('"');
46 StringBuilders.appendKeyDqValue(log, name, debugValue);
4647 return value;
4748 }
4849
2323 import org.apache.logging.log4j.core.config.Node;
2424 import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
2525 import org.apache.logging.log4j.core.util.NameUtil;
26 import org.apache.logging.log4j.util.StringBuilders;
2627
2728 /**
2829 * PluginVisitor for PluginBuilderAttribute. If {@code null} is returned for the
4748 final String replacedValue = this.substitutor.replace(event, rawValue);
4849 final Object value = convert(replacedValue, null);
4950 final Object debugValue = this.annotation.sensitive() ? NameUtil.md5(value + this.getClass().getName()) : value;
50 log.append(name).append("=\"").append(debugValue).append('"');
51 StringBuilders.appendKeyDqValue(log, name, debugValue);
5152 return value;
5253 }
5354 }
4242 final String name = this.annotation.value();
4343 if (this.conversionType.isArray()) {
4444 setConversionType(this.conversionType.getComponentType());
45 final List<Object> values = new ArrayList<Object>();
46 final Collection<Node> used = new ArrayList<Node>();
45 final List<Object> values = new ArrayList<>();
46 final Collection<Node> used = new ArrayList<>();
4747 log.append("={");
4848 boolean first = true;
4949 for (final Node child : node.getChildren()) {
2020 import org.apache.logging.log4j.core.config.Configuration;
2121 import org.apache.logging.log4j.core.config.Node;
2222 import org.apache.logging.log4j.core.config.plugins.PluginValue;
23 import org.apache.logging.log4j.util.StringBuilders;
2324
2425 /**
2526 * PluginVisitor implementation for {@link PluginValue}.
3637 final String rawValue = node.getValue() != null ? node.getValue() :
3738 removeAttributeValue(node.getAttributes(), "value");
3839 final String value = this.substitutor.replace(event, rawValue);
39 log.append(name).append("=\"").append(value).append('"');
40 StringBuilders.appendKeyDqValue(log, name, value);
4041 return value;
4142 }
4243 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.properties;
17
18 import org.apache.logging.log4j.core.config.Configuration;
19 import org.apache.logging.log4j.core.config.ConfigurationSource;
20 import org.apache.logging.log4j.core.config.Reconfigurable;
21 import org.apache.logging.log4j.core.config.builder.api.Component;
22 import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
23
24 import java.io.IOException;
25
26 /**
27 * Configuration created from a properties file.
28 * @since 2.4
29 */
30 public class PropertiesConfiguration extends BuiltConfiguration implements Reconfigurable {
31
32 private static final long serialVersionUID = 5198216024278070407L;
33
34 public PropertiesConfiguration(ConfigurationSource source, Component root) {
35 super(source, root);
36 }
37
38 @Override
39 public Configuration reconfigure() {
40 try {
41 final ConfigurationSource source = getConfigurationSource().resetInputStream();
42 if (source == null) {
43 return null;
44 }
45 final PropertiesConfigurationFactory factory = new PropertiesConfigurationFactory();
46 final PropertiesConfiguration config = factory.getConfiguration(source);
47 return config.root.getComponents().size() == 0 ? null : config;
48 } catch (final IOException ex) {
49 LOGGER.error("Cannot locate file {}: {}", getConfigurationSource(), ex);
50 }
51 return null;
52 }
53
54
55 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.properties;
17
18 import org.apache.logging.log4j.Level;
19 import org.apache.logging.log4j.core.config.ConfigurationException;
20 import org.apache.logging.log4j.core.config.ConfigurationFactory;
21 import org.apache.logging.log4j.core.config.ConfigurationSource;
22 import org.apache.logging.log4j.core.config.Order;
23 import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
24 import org.apache.logging.log4j.core.config.builder.api.AppenderRefComponentBuilder;
25 import org.apache.logging.log4j.core.config.builder.api.ComponentBuilder;
26 import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
27 import org.apache.logging.log4j.core.config.builder.api.FilterComponentBuilder;
28 import org.apache.logging.log4j.core.config.builder.api.LayoutComponentBuilder;
29 import org.apache.logging.log4j.core.config.builder.api.LoggerComponentBuilder;
30 import org.apache.logging.log4j.core.config.builder.api.RootLoggerComponentBuilder;
31 import org.apache.logging.log4j.core.config.plugins.Plugin;
32 import org.apache.logging.log4j.util.PropertiesUtil;
33 import org.apache.logging.log4j.util.Strings;
34
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.util.Properties;
38
39 /**
40 * Creates a PropertiesConfiguration from a properties file.
41 * @since 2.4
42 */
43 @Plugin(name = "PropertiesConfigurationFactory", category = ConfigurationFactory.CATEGORY)
44 @Order(8)
45 public class PropertiesConfigurationFactory extends ConfigurationFactory {
46 private static final String ADVERTISER_KEY = "advertiser";
47 private static final String STATUS_KEY = "status";
48 private static final String SHUTDOWN_HOOK = "shutdownHook";
49 private static final String VERBOSE = "verbose";
50 private static final String PACKAGES = "packages";
51 private static final String CONFIG_NAME = "name";
52 private static final String MONITOR_INTERVAL = "monitorInterval";
53 private static final String CONFIG_TYPE = "type";
54
55 @Override
56 protected String[] getSupportedTypes() {
57 return new String[] {".properties"};
58 }
59
60 @Override
61 public PropertiesConfiguration getConfiguration(ConfigurationSource source) {
62 final InputStream configStream = source.getInputStream();
63 Properties properties = new Properties();
64 try {
65 properties.load(configStream);
66 } catch (IOException ioe) {
67 throw new ConfigurationException("Unable to load " + source.toString(), ioe);
68 }
69 ConfigurationBuilder<PropertiesConfiguration> builder = newConfigurationBuilder(PropertiesConfiguration.class);
70 String value = properties.getProperty(STATUS_KEY);
71 if (value != null) {
72 builder.setStatusLevel(Level.toLevel(value, Level.ERROR));
73 } else {
74 builder.setStatusLevel(Level.ERROR);
75 }
76 value = properties.getProperty(SHUTDOWN_HOOK);
77 if (value != null) {
78 builder.setShutdownHook(value);
79 }
80 value = properties.getProperty(VERBOSE);
81 if (value != null) {
82 builder.setVerbosity(value);
83 }
84 value = properties.getProperty(PACKAGES);
85 if (value != null) {
86 builder.setPackages(value);
87 }
88 value = properties.getProperty(CONFIG_NAME);
89 if (value != null) {
90 builder.setConfigurationName(value);
91 }
92 value = properties.getProperty(MONITOR_INTERVAL);
93 if (value != null) {
94 builder.setMonitorInterval(value);
95 }
96 value = properties.getProperty(ADVERTISER_KEY);
97 if (value != null) {
98 builder.setAdvertiser(value);
99 }
100 Properties props = PropertiesUtil.extractSubset(properties, "property");
101 for (String key : props.stringPropertyNames()) {
102 builder.addProperty(key, props.getProperty(key));
103 }
104
105 Properties levelProps = PropertiesUtil.extractSubset(properties, "customLevel");
106 if (levelProps.size() > 0) {
107 for (String key : levelProps.stringPropertyNames()) {
108 builder.add(builder.newCustomLevel(key, Integer.parseInt(props.getProperty(key))));
109 }
110 }
111
112 String filterProp = properties.getProperty("filters");
113 if (filterProp != null) {
114 String[] filterNames = filterProp.split(",");
115 for (String filterName : filterNames) {
116 String name = filterName.trim();
117 builder.add(createFilter(builder, name, PropertiesUtil.extractSubset(properties, "filter." + name)));
118 }
119 }
120 String appenderProp = properties.getProperty("appenders");
121 if (appenderProp != null) {
122 String[] appenderNames = appenderProp.split(",");
123 for (String appenderName : appenderNames) {
124 String name = appenderName.trim();
125 builder.add(
126 createAppender(builder, name, PropertiesUtil.extractSubset(properties, "appender." + name)));
127 }
128 }
129 String loggerProp = properties.getProperty("loggers");
130 if (appenderProp != null) {
131 String[] loggerNames = loggerProp.split(",");
132 for (String loggerName : loggerNames) {
133 String name = loggerName.trim();
134 if (!name.equals("root")) {
135 builder.add(
136 createLogger(builder, name, PropertiesUtil.extractSubset(properties, "logger." + name)));
137 }
138 }
139 }
140
141 props = PropertiesUtil.extractSubset(properties, "rootLogger");
142 if (props.size() > 0) {
143 builder.add(createRootLogger(builder, props));
144 }
145
146 return builder.build();
147 }
148
149 private AppenderComponentBuilder createAppender(ConfigurationBuilder<PropertiesConfiguration> builder, String key, Properties properties) {
150 String name = properties.getProperty(CONFIG_NAME);
151 if (Strings.isEmpty(name)) {
152 throw new ConfigurationException("No name attribute provided for Appender " + key);
153 }
154 properties.remove(CONFIG_NAME);
155 String type = properties.getProperty(CONFIG_TYPE);
156 if (Strings.isEmpty(type)) {
157 throw new ConfigurationException("No type attribute provided for Appender " + key);
158 }
159 properties.remove(CONFIG_TYPE);
160 AppenderComponentBuilder appenderBuilder = builder.newAppender(name, type);
161 String filters = properties.getProperty("filters");
162 if (filters != null) {
163 properties.remove("filters");
164 String[] filterNames = filters.split(",");
165 for (String filterName : filterNames) {
166 filterName = filterName.trim();
167 Properties filterProps = PropertiesUtil.extractSubset(properties, "filter." + filterName);
168 appenderBuilder.add(createFilter(builder, filterName, filterProps));
169 }
170 }
171 Properties layoutProps = PropertiesUtil.extractSubset(properties, "layout");
172 if (layoutProps.size() > 0) {
173 appenderBuilder.add(createLayout(builder, name, layoutProps));
174 }
175
176 processRemainingProperties(appenderBuilder, name, properties);
177 return appenderBuilder;
178 }
179
180 private FilterComponentBuilder createFilter(ConfigurationBuilder<PropertiesConfiguration> builder, String key, Properties properties) {
181 String type = properties.getProperty(CONFIG_TYPE);
182 if (Strings.isEmpty(type)) {
183 throw new ConfigurationException("No type attribute provided for Appender " + key);
184 }
185 properties.remove(CONFIG_TYPE);
186 String onMatch = properties.getProperty("onMatch");
187 if (onMatch != null) {
188 properties.remove("onMatch");
189 }
190 String onMisMatch = properties.getProperty("onMisMatch");
191 if (onMisMatch != null) {
192 properties.remove("onMisMatch");
193 }
194 FilterComponentBuilder filterBuilder = builder.newFilter(type, onMatch, onMisMatch);
195 processRemainingProperties(filterBuilder, key, properties);
196 return filterBuilder;
197 }
198
199 private AppenderRefComponentBuilder createAppenderRef(ConfigurationBuilder<PropertiesConfiguration> builder, String key, Properties properties) {
200 String ref = properties.getProperty("ref");
201 if (Strings.isEmpty(ref)) {
202 throw new ConfigurationException("No ref attribute provided for AppenderRef " + key);
203 }
204 properties.remove("ref");
205 AppenderRefComponentBuilder appenderRefBuilder = builder.newAppenderRef(ref);
206 String level = properties.getProperty("level");
207 if (!Strings.isEmpty(level)) {
208 appenderRefBuilder.addAttribute("level", level);
209 }
210 String filters = properties.getProperty("filters");
211 if (filters != null) {
212 properties.remove("filters");
213 String[] filterNames = filters.split(",");
214 for (String filterName : filterNames) {
215 filterName = filterName.trim();
216 Properties filterProps = PropertiesUtil.extractSubset(properties, "filter." + filterName);
217 appenderRefBuilder.add(createFilter(builder, filterName, filterProps));
218 }
219 }
220 return appenderRefBuilder;
221 }
222
223 private LoggerComponentBuilder createLogger(ConfigurationBuilder<PropertiesConfiguration> builder, String key, Properties properties) {
224 String name = properties.getProperty(CONFIG_NAME);
225 if (Strings.isEmpty(name)) {
226 throw new ConfigurationException("No name attribute provided for Logger " + key);
227 }
228 properties.remove(CONFIG_NAME);
229 String level = properties.getProperty("level");
230 if (level != null) {
231 properties.remove("level");
232 }
233 LoggerComponentBuilder loggerBuilder;
234 String type = properties.getProperty(CONFIG_TYPE);
235 if (type != null) {
236 if (type.equalsIgnoreCase("asyncLogger")) {
237 loggerBuilder = builder.newAsyncLogger(name, level);
238 } else {
239 throw new ConfigurationException("Unknown Logger type " + type + " for Logger " + name);
240 }
241 } else {
242 loggerBuilder = builder.newLogger(name, level);
243 }
244 String appenderRefs = properties.getProperty("appenderRefs");
245 if (appenderRefs != null) {
246 properties.remove("appenderRefs");
247 String[] refNames = appenderRefs.split(",");
248 for (String appenderRef : refNames) {
249 appenderRef = appenderRef.trim();
250 Properties refProps = PropertiesUtil.extractSubset(properties, "appenderRef." + appenderRef);
251 loggerBuilder.add(createAppenderRef(builder, appenderRef, refProps));
252 }
253 }
254 String filters = properties.getProperty("filters");
255 if (filters != null) {
256 properties.remove("filters");
257 String[] filterNames = filters.split(",");
258 for (String filterName : filterNames) {
259 filterName = filterName.trim();
260 Properties filterProps = PropertiesUtil.extractSubset(properties, "filter." + filterName);
261 loggerBuilder.add(createFilter(builder, filterName, filterProps));
262 }
263 }
264 String additivity = properties.getProperty("additivity");
265 if (!Strings.isEmpty(additivity)) {
266 loggerBuilder.addAttribute("additivity", additivity);
267 }
268 return loggerBuilder;
269 }
270
271 private RootLoggerComponentBuilder createRootLogger(ConfigurationBuilder<PropertiesConfiguration> builder, Properties properties) {
272 String level = properties.getProperty("level");
273 if (level != null) {
274 properties.remove("level");
275 }
276 RootLoggerComponentBuilder loggerBuilder;
277 String type = properties.getProperty(CONFIG_TYPE);
278 if (type != null) {
279 if (type.equalsIgnoreCase("asyncRoot")) {
280 loggerBuilder = builder.newAsyncRootLogger(level);
281 } else {
282 throw new ConfigurationException("Unknown Logger type for root logger" + type);
283 }
284 } else {
285 loggerBuilder = builder.newRootLogger(level);
286 }
287 String appenderRefs = properties.getProperty("appenderRefs");
288 if (appenderRefs != null) {
289 properties.remove("appenderRefs");
290 String[] refNames = appenderRefs.split(",");
291 for (String appenderRef : refNames) {
292 appenderRef = appenderRef.trim();
293 Properties refProps = PropertiesUtil.extractSubset(properties, "appenderRef." + appenderRef);
294 loggerBuilder.add(createAppenderRef(builder, appenderRef, refProps));
295 }
296 }
297 String filters = properties.getProperty("filters");
298 if (filters != null) {
299 properties.remove("filters");
300 String[] filterNames = filters.split(",");
301 for (String filterName : filterNames) {
302 filterName = filterName.trim();
303 Properties filterProps = PropertiesUtil.extractSubset(properties, "filter." + filterName);
304 loggerBuilder.add(createFilter(builder, filterName, filterProps));
305 }
306 }
307 return loggerBuilder;
308 }
309
310 private LayoutComponentBuilder createLayout(ConfigurationBuilder<PropertiesConfiguration> builder, String appenderName, Properties properties) {
311 String type = properties.getProperty(CONFIG_TYPE);
312 if (Strings.isEmpty(type)) {
313 throw new ConfigurationException("No type attribute provided for Layout on Appender " + appenderName);
314 }
315 properties.remove(CONFIG_TYPE);
316 LayoutComponentBuilder layoutBuilder = builder.newLayout(type);
317 processRemainingProperties(layoutBuilder, appenderName, properties);
318 return layoutBuilder;
319 }
320
321 private <B extends ComponentBuilder<B>> ComponentBuilder<B> createComponent(ComponentBuilder<?> parent, String key, Properties properties) {
322 String name = properties.getProperty(CONFIG_NAME);
323 if (name != null) {
324 properties.remove(CONFIG_NAME);
325 }
326 String type = properties.getProperty(CONFIG_TYPE);
327 if (Strings.isEmpty(type)) {
328 throw new ConfigurationException("No type attribute provided for component " + key);
329 }
330 properties.remove(CONFIG_TYPE);
331 ComponentBuilder<B> componentBuilder = parent.getBuilder().newComponent(name, type);
332 processRemainingProperties(componentBuilder, name, properties);
333 return componentBuilder;
334 }
335
336 @SuppressWarnings({"unchecked", "rawtypes"})
337 private void processRemainingProperties(ComponentBuilder<?> builder, String name, Properties properties) {
338 while (properties.size() > 0) {
339 String propertyName = properties.stringPropertyNames().iterator().next();
340
341 int index = propertyName.indexOf('.');
342 if (index > 0) {
343 String prefix = propertyName.substring(0, index);
344 Properties componentProperties = PropertiesUtil.extractSubset(properties, prefix);
345 builder.addComponent(createComponent(builder, prefix, componentProperties));
346 } else {
347 builder.addAttribute(propertyName, properties.getProperty(propertyName));
348 properties.remove(propertyName);
349 }
350 }
351 }
352 }
2828
2929 import org.apache.logging.log4j.Level;
3030 import org.apache.logging.log4j.core.util.FileUtils;
31 import org.apache.logging.log4j.core.util.NetUtils;
3132 import org.apache.logging.log4j.status.StatusConsoleListener;
3233 import org.apache.logging.log4j.status.StatusListener;
3334 import org.apache.logging.log4j.status.StatusLogger;
112113 if (name.equalsIgnoreCase("err")) {
113114 return System.err;
114115 }
115 final URI destination = FileUtils.getCorrectedFilePathUri(name);
116 final File output = FileUtils.fileFromUri(destination);
116 final URI destUri = NetUtils.toURI(name);
117 final File output = FileUtils.fileFromUri(destUri);
117118 if (output == null) {
118119 // don't want any NPEs, no sir
119120 return DEFAULT_STREAM;
6666 private static final String[] VERBOSE_CLASSES = new String[] { ResolverUtil.class.getName() };
6767 private static final String LOG4J_XSD = "Log4j-config.xsd";
6868
69 private final List<Status> status = new ArrayList<Status>();
69 private final List<Status> status = new ArrayList<>();
7070 private Element rootElement;
7171 private boolean strict;
7272 private String schemaResource;
161161 } else if ("schema".equalsIgnoreCase(key)) {
162162 schemaResource = value;
163163 } else if ("monitorInterval".equalsIgnoreCase(key)) {
164 final int interval = Integer.parseInt(value);
165 if (interval > 0 && configFile != null) {
166 monitor = new FileConfigurationMonitor(this, configFile, listeners, interval);
164 final int intervalSeconds = Integer.parseInt(value);
165 if (intervalSeconds > 0 && configFile != null) {
166 monitor = new FileConfigurationMonitor(this, configFile, listeners, intervalSeconds);
167167 }
168168 } else if ("advertiser".equalsIgnoreCase(key)) {
169169 createAdvertiser(value, configSource, buffer, "text/xml");
235235 return null;
236236 }
237237 final XmlConfiguration config = new XmlConfiguration(source);
238 return (config.rootElement == null) ? null : config;
238 return config.rootElement == null ? null : config;
239239 } catch (final IOException ex) {
240240 LOGGER.error("Cannot locate file {}", getConfigurationSource(), ex);
241241 }
1515 */
1616 package org.apache.logging.log4j.core.config.yaml;
1717
18 import java.io.IOException;
19
20 import org.apache.logging.log4j.core.config.Configuration;
1821 import org.apache.logging.log4j.core.config.ConfigurationSource;
1922 import org.apache.logging.log4j.core.config.json.JsonConfiguration;
2023
3538 return new ObjectMapper(new YAMLFactory()).configure(JsonParser.Feature.ALLOW_COMMENTS, true);
3639 }
3740
41 @Override
42 public Configuration reconfigure() {
43 try {
44 final ConfigurationSource source = getConfigurationSource().resetInputStream();
45 if (source == null) {
46 return null;
47 }
48 return new YamlConfiguration(source);
49 } catch (final IOException ex) {
50 LOGGER.error("Cannot locate file {}", getConfigurationSource(), ex);
51 }
52 return null;
53 }
3854 }
6161 }
6262
6363 @Override
64 public boolean equals(final Object obj) {
64 protected boolean equalsImpl(final Object obj) {
6565 if (this == obj) {
6666 return true;
6767 }
68 if (!super.equals(obj)) {
68 if (!super.equalsImpl(obj)) {
6969 return false;
7070 }
7171 if (getClass() != obj.getClass()) {
155155 }
156156
157157 @Override
158 public int hashCode() {
158 protected int hashCodeImpl() {
159159 final int prime = 31;
160 int result = super.hashCode();
160 int result = super.hashCodeImpl();
161161 result = prime * result + ((onMatch == null) ? 0 : onMatch.hashCode());
162162 result = prime * result + ((onMismatch == null) ? 0 : onMismatch.hashCode());
163163 return result;
7676
7777 private final long burstInterval;
7878
79 private final DelayQueue<LogDelay> history = new DelayQueue<LogDelay>();
80
81 private final Queue<LogDelay> available = new ConcurrentLinkedQueue<LogDelay>();
82
79 private final DelayQueue<LogDelay> history = new DelayQueue<>();
80
81 private final Queue<LogDelay> available = new ConcurrentLinkedQueue<>();
82
83 static LogDelay createLogDelay(final long expireTime) {
84 return new LogDelay(expireTime);
85 }
86
8387 private BurstFilter(final Level level, final float rate, final long maxBurst, final Result onMatch,
8488 final Result onMismatch) {
8589 super(onMatch, onMismatch);
8690 this.level = level;
8791 this.burstInterval = (long) (NANOS_IN_SECONDS * (maxBurst / rate));
8892 for (int i = 0; i < maxBurst; ++i) {
89 available.add(new LogDelay());
93 available.add(createLogDelay(0));
9094 }
9195 }
9296
166170
167171 /**
168172 * Delay object to represent each log event that has occurred within the timespan.
169 */
170 private class LogDelay implements Delayed {
173 *
174 * Consider this class private, package visibility for testing.
175 */
176 private static class LogDelay implements Delayed {
177
178 LogDelay(final long expireTime) {
179 this.expireTime = expireTime;
180 }
171181
172182 private long expireTime;
173
174 public LogDelay() {
175 }
176183
177184 public void setDelay(final long delay) {
178185 this.expireTime = delay + System.nanoTime();
185192
186193 @Override
187194 public int compareTo(final Delayed delayed) {
188 if (this.expireTime < ((LogDelay) delayed).expireTime) {
189 return -1;
190 } else if (this.expireTime > ((LogDelay) delayed).expireTime) {
191 return 1;
192 }
193 return 0;
195 final long diff = this.expireTime - ((LogDelay) delayed).expireTime;
196 return Long.signum(diff);
194197 }
195198
196199 @Override
4444 private final List<Filter> filters;
4545
4646 private CompositeFilter() {
47 this.filters = new ArrayList<Filter>();
47 this.filters = new ArrayList<>();
4848 }
4949
5050 private CompositeFilter(final List<Filter> filters) {
6060 // null does nothing
6161 return this;
6262 }
63 final List<Filter> filterList = new ArrayList<Filter>(this.filters);
63 final List<Filter> filterList = new ArrayList<>(this.filters);
6464 filterList.add(filter);
6565 return new CompositeFilter(Collections.unmodifiableList(filterList));
6666 }
7070 // null does nothing
7171 return this;
7272 }
73 final List<Filter> filterList = new ArrayList<Filter>(this.filters);
73 final List<Filter> filterList = new ArrayList<>(this.filters);
7474 filterList.remove(filter);
7575 return new CompositeFilter(Collections.unmodifiableList(filterList));
7676 }
1717
1818 import java.util.HashMap;
1919 import java.util.Map;
20 import java.util.Objects;
2021
2122 import org.apache.logging.log4j.Level;
2223 import org.apache.logging.log4j.Marker;
5657 @PluginAttribute("defaultThreshold") final Level defaultThreshold,
5758 @PluginAttribute("onMatch") final Result onMatch,
5859 @PluginAttribute("onMismatch") final Result onMismatch) {
59 final Map<String, Level> map = new HashMap<String, Level>();
60 final Map<String, Level> map = new HashMap<>();
6061 for (final KeyValuePair pair : pairs) {
6162 map.put(pair.getKey(), Level.toLevel(pair.getValue()));
6263 }
6667 private Level defaultThreshold = Level.ERROR;
6768 private final String key;
6869
69 private Map<String, Level> levelMap = new HashMap<String, Level>();
70 private Map<String, Level> levelMap = new HashMap<>();
7071
7172 private DynamicThresholdFilter(final String key, final Map<String, Level> pairs, final Level defaultLevel,
7273 final Result onMatch, final Result onMismatch) {
7374 super(onMatch, onMismatch);
74 if (key == null) {
75 throw new NullPointerException("key cannot be null");
76 }
75 Objects.requireNonNull(key, "key cannot be null");
7776 this.key = key;
7877 this.levelMap = pairs;
7978 this.defaultThreshold = defaultLevel;
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.filter;
17
18 import org.apache.logging.log4j.Level;
19 import org.apache.logging.log4j.Marker;
20 import org.apache.logging.log4j.core.Filter;
21 import org.apache.logging.log4j.core.LogEvent;
22 import org.apache.logging.log4j.core.Logger;
23 import org.apache.logging.log4j.core.config.Node;
24 import org.apache.logging.log4j.core.config.plugins.Plugin;
25 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
26 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
27 import org.apache.logging.log4j.message.Message;
28
29 /**
30 * This filter returns the onMatch result if the level in the LogEvent is in the
31 * range of the configured min and max levels, otherwise it returns onMismatch
32 * value . For example, if the filter is configured with Level ERROR and Level
33 * INFO and the LogEvent contains Level WARN then the onMatch value will be
34 * returned since WARN events are in between ERROR and INFO.
35 *
36 * The default Levels are both ERROR.
37 */
38 @Plugin(name = "LevelRangeFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true)
39 public final class LevelRangeFilter extends AbstractFilter {
40
41 private static final long serialVersionUID = 1L;
42
43 /**
44 * Create a ThresholdFilter.
45 *
46 * @param minLevel
47 * The log Level.
48 * @param match
49 * The action to take on a match.
50 * @param mismatch
51 * The action to take on a mismatch.
52 * @return The created ThresholdFilter.
53 */
54 @PluginFactory
55 public static LevelRangeFilter createFilter(
56 // @formatter:off
57 @PluginAttribute("minLevel") final Level minLevel,
58 @PluginAttribute("maxLevel") final Level maxLevel,
59 @PluginAttribute("onMatch") final Result match,
60 @PluginAttribute("onMismatch") final Result mismatch) {
61 // @formatter:on
62 final Level actualMinLevel = minLevel == null ? Level.ERROR : minLevel;
63 final Level actualMaxLevel = minLevel == null ? Level.ERROR : maxLevel;
64 final Result onMatch = match == null ? Result.NEUTRAL : match;
65 final Result onMismatch = mismatch == null ? Result.DENY : mismatch;
66 return new LevelRangeFilter(actualMinLevel, actualMaxLevel, onMatch, onMismatch);
67 }
68 private final Level maxLevel;
69
70 private final Level minLevel;
71
72 private LevelRangeFilter(final Level minLevel, final Level maxLevel, final Result onMatch, final Result onMismatch) {
73 super(onMatch, onMismatch);
74 this.minLevel = minLevel;
75 this.maxLevel = maxLevel;
76 }
77
78 private Result filter(final Level level) {
79 return level.isInRange(this.minLevel, this.maxLevel) ? onMatch : onMismatch;
80 }
81
82 @Override
83 public Result filter(final LogEvent event) {
84 return filter(event.getLevel());
85 }
86
87 @Override
88 public Result filter(final Logger logger, final Level level, final Marker marker, final Message msg,
89 final Throwable t) {
90 return filter(level);
91 }
92
93 @Override
94 public Result filter(final Logger logger, final Level level, final Marker marker, final Object msg,
95 final Throwable t) {
96 return filter(level);
97 }
98
99 @Override
100 public Result filter(final Logger logger, final Level level, final Marker marker, final String msg,
101 final Object... params) {
102 return filter(level);
103 }
104
105 public Level getMinLevel() {
106 return minLevel;
107 }
108
109 @Override
110 public String toString() {
111 return minLevel.toString();
112 }
113
114 }
1919 import java.util.HashMap;
2020 import java.util.List;
2121 import java.util.Map;
22 import java.util.Objects;
2223
2324 import org.apache.logging.log4j.Level;
2425 import org.apache.logging.log4j.Marker;
4950 protected MapFilter(final Map<String, List<String>> map, final boolean oper, final Result onMatch,
5051 final Result onMismatch) {
5152 super(onMatch, onMismatch);
52 if (map == null) {
53 throw new NullPointerException("key cannot be null");
54 }
53 Objects.requireNonNull(map, "map cannot be null");
5554 this.isAnd = oper;
5655 this.map = map;
5756 }
129128 LOGGER.error("keys and values must be specified for the MapFilter");
130129 return null;
131130 }
132 final Map<String, List<String>> map = new HashMap<String, List<String>>();
131 final Map<String, List<String>> map = new HashMap<>();
133132 for (final KeyValuePair pair : pairs) {
134133 final String key = pair.getKey();
135134 if (key == null) {
145144 if (list != null) {
146145 list.add(value);
147146 } else {
148 list = new ArrayList<String>();
147 list = new ArrayList<>();
149148 list.add(value);
150149 map.put(pair.getKey(), list);
151150 }
2929 /**
3030 * This filter returns the onMatch result if the marker in the LogEvent is the same as or has the
3131 * configured marker as a parent.
32 *
3332 */
3433 @Plugin(name = "MarkerFilter", category = Node.CATEGORY, elementType = Filter.ELEMENT_TYPE, printObject = true)
3534 public final class MarkerFilter extends AbstractFilter {
113113 LOGGER.error("keys and values must be specified for the StructuredDataFilter");
114114 return null;
115115 }
116 final Map<String, List<String>> map = new HashMap<String, List<String>>();
116 final Map<String, List<String>> map = new HashMap<>();
117117 for (final KeyValuePair pair : pairs) {
118118 final String key = pair.getKey();
119119 if (key == null) {
129129 if (list != null) {
130130 list.add(value);
131131 } else {
132 list = new ArrayList<String>();
132 list = new ArrayList<>();
133133 list.add(value);
134134 map.put(pair.getKey(), list);
135135 }
123123 LOGGER.error("key and value pairs must be specified for the ThreadContextMapFilter");
124124 return null;
125125 }
126 final Map<String, List<String>> map = new HashMap<String, List<String>>();
126 final Map<String, List<String>> map = new HashMap<>();
127127 for (final KeyValuePair pair : pairs) {
128128 final String key = pair.getKey();
129129 if (key == null) {
139139 if (list != null) {
140140 list.add(value);
141141 } else {
142 list = new ArrayList<String>();
142 list = new ArrayList<>();
143143 list.add(value);
144144 map.put(pair.getKey(), list);
145145 }
7373 return level.isMoreSpecificThan(this.level) ? onMatch : onMismatch;
7474 }
7575
76 public Level getLevel() {
77 return level;
78 }
79
7680 @Override
7781 public String toString() {
7882 return level.toString();
2525 /**
2626 * Anchor for the LoggerContext for the current Thread.
2727 */
28 public static final ThreadLocal<LoggerContext> THREAD_CONTEXT = new ThreadLocal<LoggerContext>();
28 public static final ThreadLocal<LoggerContext> THREAD_CONTEXT = new ThreadLocal<>();
2929
3030 private ContextAnchor() {
3131 }
1616 package org.apache.logging.log4j.core.impl;
1717
1818 import java.net.URI;
19 import java.util.Objects;
1920
2021 import org.apache.logging.log4j.core.LifeCycle;
2122 import org.apache.logging.log4j.core.LoggerContext;
2425 import org.apache.logging.log4j.core.config.ConfigurationSource;
2526 import org.apache.logging.log4j.core.selector.ClassLoaderContextSelector;
2627 import org.apache.logging.log4j.core.selector.ContextSelector;
27 import org.apache.logging.log4j.core.util.Assert;
2828 import org.apache.logging.log4j.core.util.Cancellable;
2929 import org.apache.logging.log4j.core.util.Constants;
3030 import org.apache.logging.log4j.core.util.DefaultShutdownCallbackRegistry;
8181 */
8282 public Log4jContextFactory(final ContextSelector selector,
8383 final ShutdownCallbackRegistry shutdownCallbackRegistry) {
84 this.selector = Assert.requireNonNull(selector, "No ContextSelector provided");
85 this.shutdownCallbackRegistry = Assert.requireNonNull(shutdownCallbackRegistry,
86 "No ShutdownCallbackRegistry provided");
84 this.selector = Objects.requireNonNull(selector, "No ContextSelector provided");
85 this.shutdownCallbackRegistry = Objects.requireNonNull(shutdownCallbackRegistry, "No ShutdownCallbackRegistry provided");
8786 LOGGER.debug("Using ShutdownCallbackRegistry {}", shutdownCallbackRegistry.getClass());
8887 initializeShutdownCallbackRegistry();
8988 }
179178 }
180179
181180 /**
181 * Loads the LoggerContext using the ContextSelector using the provided Configuration
182 * @param fqcn The fully qualified class name of the caller.
183 * @param loader The ClassLoader to use or null.
184 * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext.
185 * @param currentContext If true returns the current Context, if false returns the Context appropriate
186 * for the caller if a more appropriate Context can be determined.
187 * @param configuration The Configuration.
188 * @return The LoggerContext.
189 */
190 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext,
191 final boolean currentContext, final Configuration configuration) {
192 final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext, null);
193 if (externalContext != null && ctx.getExternalContext() == null) {
194 ctx.setExternalContext(externalContext);
195 }
196 if (ctx.getState() == LifeCycle.State.INITIALIZED) {
197 ContextAnchor.THREAD_CONTEXT.set(ctx);
198 try {
199 ctx.start(configuration);
200 } finally {
201 ContextAnchor.THREAD_CONTEXT.remove();
202 }
203 }
204 return ctx;
205 }
206
207 /**
182208 * Loads the LoggerContext using the ContextSelector.
183209 * @param fqcn The fully qualified class name of the caller.
184210 * @param loader The ClassLoader to use or null.
185211 * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext.
186212 * @param currentContext If true returns the current Context, if false returns the Context appropriate
187213 * for the caller if a more appropriate Context can be determined.
188 * @param configLocation The location of the configuration for the LoggerContext.
214 * @param configLocation The location of the configuration for the LoggerContext (or null).
189215 * @return The LoggerContext.
190216 */
191217 @Override
217243 return selector;
218244 }
219245
246 /**
247 * Returns the ShutdownCallbackRegistry
248 *
249 * @return the ShutdownCallbackRegistry
250 * @since 2.4
251 */
252 public ShutdownCallbackRegistry getShutdownCallbackRegistry() {
253 return shutdownCallbackRegistry;
254 }
255
220256 /**
221257 * Removes knowledge of a LoggerContext.
222258 *
233269 public Cancellable addShutdownCallback(final Runnable callback) {
234270 return SHUTDOWN_HOOK_ENABLED ? shutdownCallbackRegistry.addShutdownCallback(callback) : null;
235271 }
272
236273 }
2222 import java.util.HashMap;
2323 import java.util.List;
2424 import java.util.Map;
25 import java.util.Objects;
2526
2627 import org.apache.logging.log4j.Level;
2728 import org.apache.logging.log4j.Marker;
2829 import org.apache.logging.log4j.ThreadContext;
2930 import org.apache.logging.log4j.core.LogEvent;
31 import org.apache.logging.log4j.core.async.RingBufferLogEvent;
3032 import org.apache.logging.log4j.core.config.Property;
3133 import org.apache.logging.log4j.core.util.Clock;
3234 import org.apache.logging.log4j.core.util.ClockFactory;
35 import org.apache.logging.log4j.core.util.DummyNanoClock;
36 import org.apache.logging.log4j.core.util.NanoClock;
3337 import org.apache.logging.log4j.message.LoggerNameAwareMessage;
3438 import org.apache.logging.log4j.message.Message;
3539 import org.apache.logging.log4j.message.TimestampMessage;
4145 public class Log4jLogEvent implements LogEvent {
4246
4347 private static final long serialVersionUID = -1351367343806656055L;
44 private static final Clock clock = ClockFactory.getClock();
48 private static final Clock CLOCK = ClockFactory.getClock();
49 private static volatile NanoClock nanoClock = new DummyNanoClock();
4550 private final String loggerFqcn;
4651 private final Marker marker;
4752 private final Level level;
4853 private final String loggerName;
4954 private final Message message;
5055 private final long timeMillis;
51 private transient final Throwable thrown;
56 private final transient Throwable thrown;
5257 private ThrowableProxy thrownProxy;
5358 private final Map<String, String> contextMap;
5459 private final ThreadContext.ContextStack contextStack;
55 private String threadName = null;
60 private String threadName;
5661 private StackTraceElement source;
5762 private boolean includeLocation;
5863 private boolean endOfBatch = false;
59
64 /** @since Log4J 2.4 */
65 private final transient long nanoTime;
66
67 /** LogEvent Builder helper class. */
6068 public static class Builder implements org.apache.logging.log4j.core.util.Builder<LogEvent> {
6169
6270 private String loggerFqcn;
6573 private String loggerName;
6674 private Message message;
6775 private Throwable thrown;
76 private long timeMillis = CLOCK.currentTimeMillis();
77 private ThrowableProxy thrownProxy;
78 private Map<String, String> contextMap = ThreadContext.getImmutableContext();
79 private ThreadContext.ContextStack contextStack = ThreadContext.getImmutableStack();
80 private String threadName = null;
81 private StackTraceElement source;
82 private boolean includeLocation;
83 private boolean endOfBatch = false;
84 private long nanoTime;
85
86 public Builder() {
87 }
88
89 public Builder(LogEvent other) {
90 Objects.requireNonNull(other);
91 if (other instanceof RingBufferLogEvent) {
92 RingBufferLogEvent evt = (RingBufferLogEvent) other;
93 evt.initializeBuilder(this);
94 return;
95 }
96 this.loggerFqcn = other.getLoggerFqcn();
97 this.marker = other.getMarker();
98 this.level = other.getLevel();
99 this.loggerName = other.getLoggerName();
100 this.message = other.getMessage();
101 this.timeMillis = other.getTimeMillis();
102 this.thrown = other.getThrown();
103 this.contextMap = other.getContextMap();
104 this.contextStack = other.getContextStack();
105 this.includeLocation = other.isIncludeLocation();
106 this.endOfBatch = other.isEndOfBatch();
107 this.nanoTime = other.getNanoTime();
108
109 // Avoid unnecessarily initializing thrownProxy, threadName and source if possible
110 if (other instanceof Log4jLogEvent) {
111 Log4jLogEvent evt = (Log4jLogEvent) other;
112 this.thrownProxy = evt.thrownProxy;
113 this.source = evt.source;
114 this.threadName = evt.threadName;
115 } else {
116 this.thrownProxy = other.getThrownProxy();
117 this.source = other.getSource();
118 this.threadName = other.getThreadName();
119 }
120 }
121
122 public Builder setLevel(final Level level) {
123 this.level = level;
124 return this;
125 }
68126
69127 public Builder setLoggerFqcn(final String loggerFqcn) {
70128 this.loggerFqcn = loggerFqcn;
71129 return this;
72130 }
73131
132 public Builder setLoggerName(final String loggerName) {
133 this.loggerName = loggerName;
134 return this;
135 }
136
74137 public Builder setMarker(final Marker marker) {
75138 this.marker = marker;
76139 return this;
77140 }
78141
79 public Builder setLevel(final Level level) {
80 this.level = level;
81 return this;
82 }
83
84 public Builder setLoggerName(final String loggerName) {
85 this.loggerName = loggerName;
86 return this;
87 }
88
89142 public Builder setMessage(final Message message) {
90143 this.message = message;
91144 return this;
96149 return this;
97150 }
98151
152 public Builder setTimeMillis(long timeMillis) {
153 this.timeMillis = timeMillis;
154 return this;
155 }
156
157 public Builder setThrownProxy(ThrowableProxy thrownProxy) {
158 this.thrownProxy = thrownProxy;
159 return this;
160 }
161
162 public Builder setContextMap(Map<String, String> contextMap) {
163 this.contextMap = contextMap;
164 return this;
165 }
166
167 public Builder setContextStack(ThreadContext.ContextStack contextStack) {
168 this.contextStack = contextStack;
169 return this;
170 }
171
172 public Builder setThreadName(String threadName) {
173 this.threadName = threadName;
174 return this;
175 }
176
177 public Builder setSource(StackTraceElement source) {
178 this.source = source;
179 return this;
180 }
181
182 public Builder setIncludeLocation(boolean includeLocation) {
183 this.includeLocation = includeLocation;
184 return this;
185 }
186
187 public Builder setEndOfBatch(boolean endOfBatch) {
188 this.endOfBatch = endOfBatch;
189 return this;
190 }
191
192 /**
193 * Sets the nano time for the event.
194 * @param nanoTime The value of the running Java Virtual Machine's high-resolution time source when the event
195 * was created.
196 * @return this builder
197 */
198 public Builder setNanoTime(long nanoTime) {
199 this.nanoTime = nanoTime;
200 return this;
201 }
202
99203 @Override
100204 public Log4jLogEvent build() {
101 return new Log4jLogEvent(loggerName, marker, loggerFqcn, level, message, thrown);
102 }
103 }
104
205 final Log4jLogEvent result = new Log4jLogEvent(loggerName, marker, loggerFqcn, level, message, thrown,
206 thrownProxy, contextMap, contextStack, threadName, source, timeMillis, nanoTime);
207 result.setIncludeLocation(includeLocation);
208 result.setEndOfBatch(endOfBatch);
209 return result;
210 }
211 }
212
213 /**
214 * Returns a new empty {@code Log4jLogEvent.Builder} with all fields empty.
215 * @return a new empty builder.
216 */
105217 public static Builder newBuilder() {
106218 return new Builder();
107219 }
108220
109221 public Log4jLogEvent() {
110 this(clock.currentTimeMillis());
111 }
112
113 /**
114 *
115 */
116 public Log4jLogEvent(final long timestamp) {
117 this(Strings.EMPTY, null, Strings.EMPTY, null, null, (Throwable) null, null, null, null, null, timestamp);
118 }
119
120 /**
121 * Constructor.
122 * @param loggerName The name of the Logger.
123 * @param marker The Marker or null.
124 * @param loggerFQCN The fully qualified class name of the caller.
125 * @param level The logging Level.
126 * @param message The Message.
127 * @param t A Throwable or null.
128 */
129 public Log4jLogEvent(final String loggerName, final Marker marker, final String loggerFQCN, final Level level,
130 final Message message, final Throwable t) {
131 this(loggerName, marker, loggerFQCN, level, message, null, t);
132 }
133
134 /**
135 * Constructor.
136 * @param loggerName The name of the Logger.
137 * @param marker The Marker or null.
138 * @param loggerFQCN The fully qualified class name of the caller.
139 * @param level The logging Level.
140 * @param message The Message.
141 * @param properties properties to add to the event.
142 * @param t A Throwable or null.
143 */
144 public Log4jLogEvent(final String loggerName, final Marker marker, final String loggerFQCN, final Level level,
145 final Message message, final List<Property> properties, final Throwable t) {
146 this(loggerName, marker, loggerFQCN, level, message, t,
147 createMap(properties),
148 ThreadContext.getDepth() == 0 ? null : ThreadContext.cloneStack(), null,
149 null,
150 // LOG4J2-628 use log4j.Clock for timestamps
151 // LOG4J2-744 unless TimestampMessage already has one
152 message instanceof TimestampMessage ? ((TimestampMessage) message).getTimestamp() :
153 clock.currentTimeMillis());
154 }
155
156 /**
157 * Constructor.
158 * @param loggerName The name of the Logger.
159 * @param marker The Marker or null.
160 * @param loggerFQCN The fully qualified class name of the caller.
161 * @param level The logging Level.
162 * @param message The Message.
163 * @param t A Throwable or null.
164 * @param mdc The mapped diagnostic context.
165 * @param ndc the nested diagnostic context.
166 * @param threadName The name of the thread.
167 * @param location The locations of the caller.
168 * @param timestamp The timestamp of the event.
169 */
170 public Log4jLogEvent(final String loggerName, final Marker marker, final String loggerFQCN, final Level level,
171 final Message message, final Throwable t, final Map<String, String> mdc,
172 final ThreadContext.ContextStack ndc, final String threadName,
173 final StackTraceElement location, final long timestamp) {
174 this(loggerName, marker, loggerFQCN, level, message, t, null, mdc, ndc, threadName,
175 location, timestamp);
176 }
177
178 /**
179 * Create a new LogEvent.
180 * @param loggerName The name of the Logger.
181 * @param marker The Marker or null.
182 * @param loggerFQCN The fully qualified class name of the caller.
183 * @param level The logging Level.
184 * @param message The Message.
185 * @param thrown A Throwable or null.
186 * @param thrownProxy A ThrowableProxy or null.
187 * @param mdc The mapped diagnostic context.
188 * @param ndc the nested diagnostic context.
189 * @param threadName The name of the thread.
190 * @param location The locations of the caller.
191 * @param timestamp The timestamp of the event.
192 */
222 this(Strings.EMPTY, null, Strings.EMPTY, null, null, (Throwable) null, null, null, null, null, null,
223 CLOCK.currentTimeMillis(), nanoClock.nanoTime());
224 }
225
226 /**
227 *
228 * @deprecated use {@link Log4jLogEvent.Builder} instead. This constructor will be removed in an upcoming release.
229 */
230 @Deprecated
231 public Log4jLogEvent(final long timestamp) {
232 this(Strings.EMPTY, null, Strings.EMPTY, null, null, (Throwable) null, null, null, null, null, null,
233 timestamp, nanoClock.nanoTime());
234 }
235
236 /**
237 * Constructor.
238 * @param loggerName The name of the Logger.
239 * @param marker The Marker or null.
240 * @param loggerFQCN The fully qualified class name of the caller.
241 * @param level The logging Level.
242 * @param message The Message.
243 * @param t A Throwable or null.
244 * @deprecated use {@link Log4jLogEvent.Builder} instead. This constructor will be removed in an upcoming release.
245 */
246 @Deprecated
247 public Log4jLogEvent(final String loggerName, final Marker marker, final String loggerFQCN, final Level level,
248 final Message message, final Throwable t) {
249 this(loggerName, marker, loggerFQCN, level, message, null, t);
250 }
251
252 /**
253 * Constructor.
254 * @param loggerName The name of the Logger.
255 * @param marker The Marker or null.
256 * @param loggerFQCN The fully qualified class name of the caller.
257 * @param level The logging Level.
258 * @param message The Message.
259 * @param properties properties to add to the event.
260 * @param t A Throwable or null.
261 */
262 // This constructor is called from LogEventFactories.
263 public Log4jLogEvent(final String loggerName, final Marker marker, final String loggerFQCN, final Level level,
264 final Message message, final List<Property> properties, final Throwable t) {
265 this(loggerName, marker, loggerFQCN, level, message, t, null,
266 createMap(properties),
267 ThreadContext.getDepth() == 0 ? null : ThreadContext.cloneStack(), // mutable copy
268 null, // thread name
269 null, // stack trace element
270 // LOG4J2-628 use log4j.Clock for timestamps
271 // LOG4J2-744 unless TimestampMessage already has one
272 message instanceof TimestampMessage ? ((TimestampMessage) message).getTimestamp() :
273 CLOCK.currentTimeMillis(),
274 nanoClock.nanoTime());
275 }
276
277 /**
278 * Constructor.
279 * @param loggerName The name of the Logger.
280 * @param marker The Marker or null.
281 * @param loggerFQCN The fully qualified class name of the caller.
282 * @param level The logging Level.
283 * @param message The Message.
284 * @param t A Throwable or null.
285 * @param mdc The mapped diagnostic context.
286 * @param ndc the nested diagnostic context.
287 * @param threadName The name of the thread.
288 * @param location The locations of the caller.
289 * @param timestampMillis The timestamp of the event.
290 * @deprecated use {@link Log4jLogEvent.Builder} instead. This constructor will be removed in an upcoming release.
291 */
292 @Deprecated
293 public Log4jLogEvent(final String loggerName, final Marker marker, final String loggerFQCN, final Level level,
294 final Message message, final Throwable t, final Map<String, String> mdc,
295 final ThreadContext.ContextStack ndc, final String threadName,
296 final StackTraceElement location, final long timestampMillis) {
297 this(loggerName, marker, loggerFQCN, level, message, t, null, mdc, ndc, threadName,
298 location, timestampMillis, nanoClock.nanoTime());
299 }
300
301 /**
302 * Create a new LogEvent.
303 * @param loggerName The name of the Logger.
304 * @param marker The Marker or null.
305 * @param loggerFQCN The fully qualified class name of the caller.
306 * @param level The logging Level.
307 * @param message The Message.
308 * @param thrown A Throwable or null.
309 * @param thrownProxy A ThrowableProxy or null.
310 * @param mdc The mapped diagnostic context.
311 * @param ndc the nested diagnostic context.
312 * @param threadName The name of the thread.
313 * @param location The locations of the caller.
314 * @param timestamp The timestamp of the event.
315 * @return a new LogEvent
316 * @deprecated use {@link Log4jLogEvent.Builder} instead. This method will be removed in an upcoming release.
317 */
318 @Deprecated
193319 public static Log4jLogEvent createEvent(final String loggerName, final Marker marker, final String loggerFQCN,
194 final Level level, final Message message, final Throwable thrown,
320 final Level level, final Message message, final Throwable thrown,
195321 final ThrowableProxy thrownProxy,
196322 final Map<String, String> mdc, final ThreadContext.ContextStack ndc,
197323 final String threadName, final StackTraceElement location,
198324 final long timestamp) {
199325 final Log4jLogEvent result = new Log4jLogEvent(loggerName, marker, loggerFQCN, level, message, thrown,
200 thrownProxy, mdc, ndc, threadName, location, timestamp);
326 thrownProxy, mdc, ndc, threadName, location, timestamp, nanoClock.nanoTime());
201327 return result;
202328 }
203329
215341 * @param threadName The name of the thread.
216342 * @param source The locations of the caller.
217343 * @param timestamp The timestamp of the event.
344 * @param nanoTime The value of the running Java Virtual Machine's high-resolution time source when the event was
345 * created.
218346 */
219347 private Log4jLogEvent(final String loggerName, final Marker marker, final String loggerFQCN, final Level level,
220 final Message message, final Throwable thrown, final ThrowableProxy thrownProxy,
221 final Map<String, String> contextMap, final ThreadContext.ContextStack contextStack,
222 final String threadName, final StackTraceElement source, final long timestamp) {
348 final Message message, final Throwable thrown, final ThrowableProxy thrownProxy,
349 final Map<String, String> contextMap, final ThreadContext.ContextStack contextStack,
350 final String threadName, final StackTraceElement source, final long timestampMillis, final long nanoTime) {
223351 this.loggerName = loggerName;
224352 this.marker = marker;
225353 this.loggerFqcn = loggerFQCN;
229357 this.thrownProxy = thrownProxy;
230358 this.contextMap = contextMap == null ? ThreadContext.EMPTY_MAP : contextMap;
231359 this.contextStack = contextStack == null ? ThreadContext.EMPTY_STACK : contextStack;
232 this.timeMillis = message instanceof TimestampMessage ? ((TimestampMessage) message).getTimestamp() : timestamp;
360 this.timeMillis = message instanceof TimestampMessage
361 ? ((TimestampMessage) message).getTimestamp()
362 : timestampMillis;
233363 this.threadName = threadName;
234364 this.source = source;
235365 if (message != null && message instanceof LoggerNameAwareMessage) {
236366 ((LoggerNameAwareMessage) message).setLoggerName(loggerName);
237367 }
368 this.nanoTime = nanoTime;
238369 }
239370
240371 private static Map<String, String> createMap(final List<Property> properties) {
241372 final Map<String, String> contextMap = ThreadContext.getImmutableContext();
242 if (contextMap == null && (properties == null || properties.isEmpty())) {
243 return null;
244 }
245373 if (properties == null || properties.isEmpty()) {
246 return contextMap; // contextMap is not null
247 }
248 final Map<String, String> map = new HashMap<String, String>(contextMap);
374 return contextMap; // may be ThreadContext.EMPTY_MAP but not null
375 }
376 final Map<String, String> map = new HashMap<>(contextMap);
249377
250378 for (final Property prop : properties) {
251379 if (!map.containsKey(prop.getName())) {
253381 }
254382 }
255383 return Collections.unmodifiableMap(map);
384 }
385
386 /**
387 * Returns the {@code NanoClock} to use for creating the nanoTime timestamp of log events.
388 * @return the {@code NanoClock} to use for creating the nanoTime timestamp of log events
389 */
390 public static NanoClock getNanoClock() {
391 return nanoClock;
392 }
393
394 /**
395 * Sets the {@code NanoClock} to use for creating the nanoTime timestamp of log events.
396 * <p>
397 * FOR INTERNAL USE. This method may be called with a different {@code NanoClock} implementation when the
398 * configuration changes.
399 *
400 * @param nanoClock the {@code NanoClock} to use for creating the nanoTime timestamp of log events
401 */
402 public static void setNanoClock(NanoClock nanoClock) {
403 Log4jLogEvent.nanoClock = Objects.requireNonNull(nanoClock, "NanoClock must be non-null");
404 }
405
406 /**
407 * Returns a new fully initialized {@code Log4jLogEvent.Builder} containing a copy of all fields of this event.
408 * @return a new fully initialized builder.
409 */
410 public Builder asBuilder() {
411 return new Builder(this);
256412 }
257413
258414 /**
414570 this.endOfBatch = endOfBatch;
415571 }
416572
573 @Override
574 public long getNanoTime() {
575 return nanoTime;
576 }
577
417578 /**
418579 * Creates a LogEventProxy that can be serialized.
419580 * @return a LogEventProxy.
434595 }
435596
436597 public static Log4jLogEvent deserialize(final Serializable event) {
437 if (event == null) {
438 throw new NullPointerException("Event cannot be null");
439 }
598 Objects.requireNonNull(event, "Event cannot be null");
440599 if (event instanceof LogEventProxy) {
441600 final LogEventProxy proxy = (LogEventProxy) event;
442601 final Log4jLogEvent result = new Log4jLogEvent(proxy.loggerName, proxy.marker,
443602 proxy.loggerFQCN, proxy.level, proxy.message,
444603 proxy.thrown, proxy.thrownProxy, proxy.contextMap, proxy.contextStack, proxy.threadName,
445 proxy.source, proxy.timeMillis);
604 proxy.source, proxy.timeMillis, proxy.nanoTime);
446605 result.setEndOfBatch(proxy.isEndOfBatch);
447606 result.setIncludeLocation(proxy.isLocationRequired);
448607 return result;
484643 if (timeMillis != that.timeMillis) {
485644 return false;
486645 }
646 if (nanoTime != that.nanoTime) {
647 return false;
648 }
487649 if (loggerFqcn != null ? !loggerFqcn.equals(that.loggerFqcn) : that.loggerFqcn != null) {
488650 return false;
489651 }
523685
524686 @Override
525687 public int hashCode() {
688 // Check:OFF: MagicNumber
526689 int result = loggerFqcn != null ? loggerFqcn.hashCode() : 0;
527690 result = 31 * result + (marker != null ? marker.hashCode() : 0);
528691 result = 31 * result + (level != null ? level.hashCode() : 0);
529692 result = 31 * result + loggerName.hashCode();
530693 result = 31 * result + message.hashCode();
531694 result = 31 * result + (int) (timeMillis ^ (timeMillis >>> 32));
695 result = 31 * result + (int) (nanoTime ^ (nanoTime >>> 32));
532696 result = 31 * result + (thrown != null ? thrown.hashCode() : 0);
533697 result = 31 * result + (thrownProxy != null ? thrownProxy.hashCode() : 0);
534698 result = 31 * result + (contextMap != null ? contextMap.hashCode() : 0);
537701 result = 31 * result + (source != null ? source.hashCode() : 0);
538702 result = 31 * result + (includeLocation ? 1 : 0);
539703 result = 31 * result + (endOfBatch ? 1 : 0);
704 // Check:ON: MagicNumber
540705 return result;
541706 }
542707
560725 private final StackTraceElement source;
561726 private final boolean isLocationRequired;
562727 private final boolean isEndOfBatch;
728 /** @since Log4J 2.4 */
729 private final transient long nanoTime;
563730
564731 public LogEventProxy(final Log4jLogEvent event, final boolean includeLocation) {
565732 this.loggerFQCN = event.loggerFqcn;
576743 this.threadName = event.getThreadName();
577744 this.isLocationRequired = includeLocation;
578745 this.isEndOfBatch = event.endOfBatch;
746 this.nanoTime = event.nanoTime;
579747 }
580748
581749 /**
584752 */
585753 protected Object readResolve() {
586754 final Log4jLogEvent result = new Log4jLogEvent(loggerName, marker, loggerFQCN, level, message, thrown,
587 thrownProxy, contextMap, contextStack, threadName, source, timeMillis);
755 thrownProxy, contextMap, contextStack, threadName, source, timeMillis, nanoTime);
588756 result.setEndOfBatch(isEndOfBatch);
589757 result.setIncludeLocation(isLocationRequired);
590758 return result;
2121
2222 import org.apache.logging.log4j.core.util.Constants;
2323 import org.apache.logging.log4j.core.util.Patterns;
24 import org.apache.logging.log4j.util.Strings;
2425
2526 /**
2627 * Contains options which control how a {@link Throwable} pattern is formatted.
188189 // %xEx{["none"|"short"|"full"|depth],[filters(packages)}
189190 // However, the convention for multiple options should be:
190191 // %xEx{["none"|"short"|"full"|depth]}[{filters(packages)}]
191 if (options.length == 1 && options[0] != null && options[0].length() > 0) {
192 if (options.length == 1 && Strings.isNotEmpty(options[0])) {
192193 final String[] opts = options[0].split(Patterns.COMMA_SEPARATOR, 2);
193194 final String first = opts[0].trim();
194 final Scanner scanner = new Scanner(first);
195 if (opts.length > 1 && (first.equalsIgnoreCase(FULL) || first.equalsIgnoreCase(SHORT) || first.equalsIgnoreCase(NONE) || scanner.hasNextInt())) {
196 options = new String[]{first, opts[1].trim()};
195 try (final Scanner scanner = new Scanner(first)) {
196 if (opts.length > 1
197 && (first.equalsIgnoreCase(FULL) || first.equalsIgnoreCase(SHORT)
198 || first.equalsIgnoreCase(NONE) || scanner.hasNextInt())) {
199 options = new String[] {
200 first,
201 opts[1].trim() };
202 }
197203 }
198 scanner.close();
199204 }
200205
201206 int lines = DEFAULT.lines;
213218 if (filterStr.length() > 0) {
214219 final String[] array = filterStr.split(Patterns.COMMA_SEPARATOR);
215220 if (array.length > 0) {
216 packages = new ArrayList<String>(array.length);
221 packages = new ArrayList<>(array.length);
217222 for (String token : array) {
218223 token = token.trim();
219224 if (token.length() > 0) {
1818 import java.io.Serializable;
1919 import java.net.URL;
2020 import java.security.CodeSource;
21 import java.util.ArrayList;
2122 import java.util.Arrays;
2223 import java.util.HashMap;
24 import java.util.HashSet;
2325 import java.util.List;
2426 import java.util.Map;
27 import java.util.Set;
2528 import java.util.Stack;
2629
2730 import org.apache.logging.log4j.core.util.Loader;
28 import org.apache.logging.log4j.core.util.Throwables;
2931 import org.apache.logging.log4j.status.StatusLogger;
3032 import org.apache.logging.log4j.util.ReflectionUtil;
3133 import org.apache.logging.log4j.util.Strings;
4850 */
4951 public class ThrowableProxy implements Serializable {
5052
51 /**
53 private static final String CAUSED_BY_LABEL = "Caused by: ";
54 private static final String SUPPRESSED_LABEL = "Suppressed: ";
55 private static final String WRAPPED_BY_LABEL = "Wrapped by: ";
56
57 /**
5258 * Cached StackTracePackageElement and ClassLoader.
5359 * <p>
5460 * Consider this class private.
107113 * The Throwable to wrap, must not be null.
108114 */
109115 public ThrowableProxy(final Throwable throwable) {
116 this(throwable, null);
117 }
118
119 /**
120 * Constructs the wrapper for the Throwable that includes packaging data.
121 *
122 * @param throwable
123 * The Throwable to wrap, must not be null.
124 * @param visited
125 * The set of visited suppressed exceptions.
126 */
127 private ThrowableProxy(final Throwable throwable, final Set<Throwable> visited) {
110128 this.throwable = throwable;
111129 this.name = throwable.getClass().getName();
112130 this.message = throwable.getMessage();
113131 this.localizedMessage = throwable.getLocalizedMessage();
114 final Map<String, CacheEntry> map = new HashMap<String, CacheEntry>();
132 final Map<String, CacheEntry> map = new HashMap<>();
115133 final Stack<Class<?>> stack = ReflectionUtil.getCurrentStackTrace();
116134 this.extendedStackTrace = this.toExtendedStackTrace(stack, map, null, throwable.getStackTrace());
117135 final Throwable throwableCause = throwable.getCause();
118 this.causeProxy = throwableCause == null ? null : new ThrowableProxy(throwable, stack, map, throwableCause);
119 this.suppressedProxies = this.toSuppressedProxies(throwable);
136 final Set<Throwable> causeVisited = new HashSet<>(1);
137 this.causeProxy = throwableCause == null ? null : new ThrowableProxy(throwable, stack, map, throwableCause, visited, causeVisited);
138 this.suppressedProxies = this.toSuppressedProxies(throwable, visited);
120139 }
121140
122141 /**
130149 * The cache containing the packaging data.
131150 * @param cause
132151 * The Throwable to wrap.
152 * @param suppressedVisited TODO
153 * @param causeVisited TODO
133154 */
134155 private ThrowableProxy(final Throwable parent, final Stack<Class<?>> stack, final Map<String, CacheEntry> map,
135 final Throwable cause) {
156 final Throwable cause, final Set<Throwable> suppressedVisited, final Set<Throwable> causeVisited) {
157 causeVisited.add(cause);
136158 this.throwable = cause;
137159 this.name = cause.getClass().getName();
138160 this.message = this.throwable.getMessage();
139161 this.localizedMessage = this.throwable.getLocalizedMessage();
140162 this.extendedStackTrace = this.toExtendedStackTrace(stack, map, parent.getStackTrace(), cause.getStackTrace());
141 this.causeProxy = cause.getCause() == null ? null : new ThrowableProxy(parent, stack, map, cause.getCause());
142 this.suppressedProxies = this.toSuppressedProxies(cause);
163 final Throwable causeCause = cause.getCause();
164 this.causeProxy = causeCause == null || causeVisited.contains(causeCause) ? null : new ThrowableProxy(parent,
165 stack, map, causeCause, suppressedVisited, causeVisited);
166 this.suppressedProxies = this.toSuppressedProxies(cause, suppressedVisited);
143167 }
144168
145169 @Override
180204 return true;
181205 }
182206
183 @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
184 private void formatCause(final StringBuilder sb, final ThrowableProxy cause, final List<String> ignorePackages) {
185 if (cause == null) {
186 return;
187 }
188 sb.append("Caused by: ").append(cause).append(EOL);
189 this.formatElements(sb, cause.commonElementCount, cause.getThrowable().getStackTrace(),
190 cause.extendedStackTrace, ignorePackages);
191 this.formatCause(sb, cause.causeProxy, ignorePackages);
192 }
193
194 private void formatElements(final StringBuilder sb, final int commonCount, final StackTraceElement[] causedTrace,
195 final ExtendedStackTraceElement[] extStackTrace, final List<String> ignorePackages) {
196 if (ignorePackages == null || ignorePackages.isEmpty()) {
197 for (final ExtendedStackTraceElement element : extStackTrace) {
198 this.formatEntry(element, sb);
199 }
200 } else {
201 int count = 0;
202 for (int i = 0; i < extStackTrace.length; ++i) {
203 if (!this.ignoreElement(causedTrace[i], ignorePackages)) {
204 if (count > 0) {
205 appendSuppressedCount(sb, count);
206 count = 0;
207 }
208 this.formatEntry(extStackTrace[i], sb);
209 } else {
210 ++count;
211 }
212 }
213 if (count > 0) {
214 appendSuppressedCount(sb, count);
215 }
216 }
217 if (commonCount != 0) {
218 sb.append("\t... ").append(commonCount).append(" more").append(EOL);
219 }
220 }
221
222 private void appendSuppressedCount(final StringBuilder sb, int count) {
207 private void formatCause(final StringBuilder sb, final String prefix, final ThrowableProxy cause, final List<String> ignorePackages) {
208 formatThrowableProxy(sb, prefix, CAUSED_BY_LABEL, cause, ignorePackages);
209 }
210
211 private void formatThrowableProxy(final StringBuilder sb, final String prefix, final String causeLabel,
212 final ThrowableProxy throwableProxy, final List<String> ignorePackages) {
213 if (throwableProxy == null) {
214 return;
215 }
216 sb.append(prefix).append(causeLabel).append(throwableProxy).append(EOL);
217 this.formatElements(sb, prefix, throwableProxy.commonElementCount,
218 throwableProxy.getStackTrace(), throwableProxy.extendedStackTrace, ignorePackages);
219 this.formatSuppressed(sb, prefix + "\t", throwableProxy.suppressedProxies, ignorePackages);
220 this.formatCause(sb, prefix, throwableProxy.causeProxy, ignorePackages);
221 }
222
223 private void formatSuppressed(final StringBuilder sb, final String prefix, final ThrowableProxy[] suppressedProxies,
224 final List<String> ignorePackages) {
225 if (suppressedProxies == null) {
226 return;
227 }
228 for (final ThrowableProxy suppressedProxy : suppressedProxies) {
229 final ThrowableProxy cause = suppressedProxy;
230 formatThrowableProxy(sb, prefix, SUPPRESSED_LABEL, cause, ignorePackages);
231 }
232 }
233
234 private void formatElements(final StringBuilder sb, final String prefix, final int commonCount,
235 final StackTraceElement[] causedTrace, final ExtendedStackTraceElement[] extStackTrace,
236 final List<String> ignorePackages) {
237 if (ignorePackages == null || ignorePackages.isEmpty()) {
238 for (final ExtendedStackTraceElement element : extStackTrace) {
239 this.formatEntry(element, sb, prefix);
240 }
241 } else {
242 int count = 0;
243 for (int i = 0; i < extStackTrace.length; ++i) {
244 if (!this.ignoreElement(causedTrace[i], ignorePackages)) {
245 if (count > 0) {
246 appendSuppressedCount(sb, prefix, count);
247 count = 0;
248 }
249 this.formatEntry(extStackTrace[i], sb, prefix);
250 } else {
251 ++count;
252 }
253 }
254 if (count > 0) {
255 appendSuppressedCount(sb, prefix, count);
256 }
257 }
258 if (commonCount != 0) {
259 sb.append(prefix).append("\t... ").append(commonCount).append(" more").append(EOL);
260 }
261 }
262
263 private void appendSuppressedCount(final StringBuilder sb, final String prefix, final int count) {
264 sb.append(prefix);
223265 if (count == 1) {
224266 sb.append("\t....").append(EOL);
225267 } else {
227269 }
228270 }
229271
230 private void formatEntry(final ExtendedStackTraceElement extStackTraceElement, final StringBuilder sb) {
272 private void formatEntry(final ExtendedStackTraceElement extStackTraceElement, final StringBuilder sb, final String prefix) {
273 sb.append(prefix);
231274 sb.append("\tat ");
232275 sb.append(extStackTraceElement);
233276 sb.append(EOL);
260303 final Throwable caused = cause.getCauseProxy() != null ? cause.getCauseProxy().getThrowable() : null;
261304 if (caused != null) {
262305 this.formatWrapper(sb, cause.causeProxy);
263 sb.append("Wrapped by: ");
306 sb.append(WRAPPED_BY_LABEL);
264307 }
265308 sb.append(cause).append(EOL);
266 this.formatElements(sb, cause.commonElementCount, cause.getThrowable().getStackTrace(),
267 cause.extendedStackTrace, packages);
309 this.formatElements(sb, "", cause.commonElementCount,
310 cause.getThrowable().getStackTrace(), cause.extendedStackTrace, packages);
268311 }
269312
270313 public ThrowableProxy getCauseProxy() {
291334 final StringBuilder sb = new StringBuilder();
292335 if (this.causeProxy != null) {
293336 this.formatWrapper(sb, this.causeProxy);
294 sb.append("Wrapped by: ");
337 sb.append(WRAPPED_BY_LABEL);
295338 }
296339 sb.append(this.toString());
297340 sb.append(EOL);
298 this.formatElements(sb, 0, this.throwable.getStackTrace(), this.extendedStackTrace, packages);
341 this.formatElements(sb, "", 0, this.throwable.getStackTrace(), this.extendedStackTrace, packages);
299342 return sb.toString();
300343 }
301344
341384 sb.append(": ").append(msg);
342385 }
343386 sb.append(EOL);
344 StackTraceElement[] causedTrace = this.throwable != null ? this.throwable.getStackTrace() : null;
345 this.formatElements(sb, 0, causedTrace, this.extendedStackTrace, ignorePackages);
346 this.formatCause(sb, this.causeProxy, ignorePackages);
387 final StackTraceElement[] causedTrace = this.throwable != null ? this.throwable.getStackTrace() : null;
388 this.formatElements(sb, "", 0, causedTrace, this.extendedStackTrace, ignorePackages);
389 this.formatSuppressed(sb, "\t", this.suppressedProxies, ignorePackages);
390 this.formatCause(sb, "", this.causeProxy, ignorePackages);
347391 return sb.toString();
348392 }
349393
561605 stack.pop();
562606 clazz = stack.isEmpty() ? null : stack.peek();
563607 } else {
564 if (map.containsKey(className)) {
565 final CacheEntry entry = map.get(className);
608 final CacheEntry cacheEntry = map.get(className);
609 if (cacheEntry != null) {
610 final CacheEntry entry = cacheEntry;
566611 extClassInfo = entry.element;
567612 if (entry.loader != null) {
568613 lastLoader = entry.loader;
588633 return msg != null ? this.name + ": " + msg : this.name;
589634 }
590635
591 private ThrowableProxy[] toSuppressedProxies(final Throwable thrown) {
636 private ThrowableProxy[] toSuppressedProxies(final Throwable thrown, Set<Throwable> suppressedVisited) {
592637 try {
593 final Throwable[] suppressed = Throwables.getSuppressed(thrown);
638 final Throwable[] suppressed = thrown.getSuppressed();
594639 if (suppressed == null) {
595640 return EMPTY_THROWABLE_PROXY_ARRAY;
596641 }
597 final ThrowableProxy[] proxies = new ThrowableProxy[suppressed.length];
642 final List<ThrowableProxy> proxies = new ArrayList<>(suppressed.length);
643 if (suppressedVisited == null) {
644 suppressedVisited = new HashSet<>(proxies.size());
645 }
598646 for (int i = 0; i < suppressed.length; i++) {
599 proxies[i] = new ThrowableProxy(suppressed[i]);
600 }
601 return proxies;
647 final Throwable candidate = suppressed[i];
648 if (!suppressedVisited.contains(candidate)) {
649 suppressedVisited.add(candidate);
650 proxies.add(new ThrowableProxy(candidate, suppressedVisited));
651 }
652 }
653 return proxies.toArray(new ThrowableProxy[proxies.size()]);
602654 } catch (final Exception e) {
603655 StatusLogger.getLogger().error(e);
604656 }
2929 public static final String ELT_THROWN = "thrown";
3030 public static final String ELT_MESSAGE = "message";
3131 public static final String ELT_EXTENDED_STACK_TRACE = "extendedStackTrace";
32 public static final String ELT_NANO_TIME = "nanoTime";
3233 }
4545 final List<MapEntry> list = jp.readValueAs(new TypeReference<List<MapEntry>>() {
4646 // empty
4747 });
48 final HashMap<String, String> map = new HashMap<String, String>(list.size());
48 final HashMap<String, String> map = new HashMap<>(list.size());
4949 for (final MapEntry mapEntry : list) {
5050 map.put(mapEntry.getKey(), mapEntry.getValue());
5151 }
6161 } else {
6262 // An XML number always comes in a string since there is no syntax help as with JSON.
6363 try {
64 lineNumber = Integer.valueOf(jp.getText().trim()).intValue();
64 lineNumber = Integer.parseInt(jp.getText().trim());
6565 } catch (final NumberFormatException e) {
6666 throw JsonMappingException.from(jp, "Non-numeric token (" + t + ") for property 'line'", e);
6767 }
1515 */
1616 package org.apache.logging.log4j.core.jmx;
1717
18 import java.util.Objects;
19
1820 import javax.management.ObjectName;
1921
2022 import org.apache.logging.log4j.core.Appender;
2123 import org.apache.logging.log4j.core.filter.AbstractFilterable;
22 import org.apache.logging.log4j.core.util.Assert;
2324
2425 /**
2526 * Implementation of the {@code AppenderAdminMBean} interface.
3940 */
4041 public AppenderAdmin(final String contextName, final Appender appender) {
4142 // super(executor); // no notifications for now
42 this.contextName = Assert.requireNonNull(contextName, "contextName");
43 this.appender = Assert.requireNonNull(appender, "appender");
43 this.contextName = Objects.requireNonNull(contextName, "contextName");
44 this.appender = Objects.requireNonNull(appender, "appender");
4445 try {
4546 final String ctxName = Server.escape(this.contextName);
4647 final String configName = Server.escape(appender.getName());
1515 */
1616 package org.apache.logging.log4j.core.jmx;
1717
18 import java.util.Objects;
19
1820 import javax.management.ObjectName;
1921
2022 import org.apache.logging.log4j.core.appender.AsyncAppender;
21 import org.apache.logging.log4j.core.util.Assert;
2223
2324 /**
2425 * Implementation of the {@code AsyncAppenderAdminMBean} interface.
3839 */
3940 public AsyncAppenderAdmin(final String contextName, final AsyncAppender appender) {
4041 // super(executor); // no notifications for now
41 this.contextName = Assert.requireNonNull(contextName, "contextName");
42 this.asyncAppender = Assert.requireNonNull(appender, "async appender");
42 this.contextName = Objects.requireNonNull(contextName, "contextName");
43 this.asyncAppender = Objects.requireNonNull(appender, "async appender");
4344 try {
4445 final String ctxName = Server.escape(this.contextName);
4546 final String configName = Server.escape(appender.getName());
1515 */
1616 package org.apache.logging.log4j.core.jmx;
1717
18 import java.util.Objects;
19
1820 import javax.management.ObjectName;
1921
2022 import org.apache.logging.log4j.core.selector.ContextSelector;
21 import org.apache.logging.log4j.core.util.Assert;
2223
2324 /**
2425 * Implementation of the {@code ContextSelectorAdminMBean} interface.
4243 */
4344 public ContextSelectorAdmin(final String contextName, final ContextSelector selector) {
4445 super();
45 this.selector = Assert.requireNonNull(selector, "ContextSelector");
46 this.selector = Objects.requireNonNull(selector, "ContextSelector");
4647 try {
4748 final String mbeanName = String.format(PATTERN, Server.escape(contextName));
4849 objectName = new ObjectName(mbeanName);
1616 package org.apache.logging.log4j.core.jmx;
1717
1818 import java.util.List;
19 import java.util.Objects;
1920
2021 import javax.management.ObjectName;
2122
2324 import org.apache.logging.log4j.core.LoggerContext;
2425 import org.apache.logging.log4j.core.config.AppenderRef;
2526 import org.apache.logging.log4j.core.config.LoggerConfig;
26 import org.apache.logging.log4j.core.util.Assert;
2727
2828 /**
2929 * Implementation of the {@code LoggerConfigAdminMBean} interface.
4343 */
4444 public LoggerConfigAdmin(final LoggerContext loggerContext, final LoggerConfig loggerConfig) {
4545 // super(executor); // no notifications for now
46 this.loggerContext = Assert.requireNonNull(loggerContext, "loggerContext");
47 this.loggerConfig = Assert.requireNonNull(loggerConfig, "loggerConfig");
46 this.loggerContext = Objects.requireNonNull(loggerContext, "loggerContext");
47 this.loggerConfig = Objects.requireNonNull(loggerConfig, "loggerConfig");
4848 try {
4949 final String ctxName = Server.escape(loggerContext.getName());
5050 final String configName = Server.escape(loggerConfig.getName());
2929 import java.net.URISyntaxException;
3030 import java.net.URL;
3131 import java.nio.charset.Charset;
32 import java.nio.charset.StandardCharsets;
3233 import java.util.Map;
34 import java.util.Objects;
3335 import java.util.concurrent.Executor;
3436 import java.util.concurrent.atomic.AtomicLong;
3537
4244 import org.apache.logging.log4j.core.config.Configuration;
4345 import org.apache.logging.log4j.core.config.ConfigurationFactory;
4446 import org.apache.logging.log4j.core.config.ConfigurationSource;
45 import org.apache.logging.log4j.core.util.Assert;
46 import org.apache.logging.log4j.core.util.Charsets;
4747 import org.apache.logging.log4j.core.util.Closer;
4848 import org.apache.logging.log4j.status.StatusLogger;
4949 import org.apache.logging.log4j.util.Strings;
7171 */
7272 public LoggerContextAdmin(final LoggerContext loggerContext, final Executor executor) {
7373 super(executor, createNotificationInfo());
74 this.loggerContext = Assert.requireNonNull(loggerContext, "loggerContext");
74 this.loggerContext = Objects.requireNonNull(loggerContext, "loggerContext");
7575 try {
7676 final String ctxName = Server.escape(loggerContext.getName());
7777 final String name = String.format(PATTERN, ctxName);
147147
148148 @Override
149149 public String getConfigText() throws IOException {
150 return getConfigText(Charsets.UTF_8.name());
150 return getConfigText(StandardCharsets.UTF_8.name());
151151 }
152152
153153 @Override
1515 */
1616 package org.apache.logging.log4j.core.jmx;
1717
18 import java.util.Objects;
19
1820 import javax.management.ObjectName;
19
20 import org.apache.logging.log4j.core.util.Assert;
2121
2222 import com.lmax.disruptor.RingBuffer;
2323
4444 }
4545
4646 protected RingBufferAdmin(final RingBuffer<?> ringBuffer, final String mbeanName) {
47 this.ringBuffer = Assert.requireNonNull(ringBuffer, "ringbuffer");
47 this.ringBuffer = Objects.requireNonNull(ringBuffer, "ringbuffer");
4848 try {
4949 objectName = new ObjectName(mbeanName);
5050 } catch (final Exception e) {
6161 private static final String PROPERTY_ASYNC_NOTIF = "log4j2.jmx.notify.async";
6262 private static final String THREAD_NAME_PREFIX = "log4j2.jmx.notif";
6363 private static final StatusLogger LOGGER = StatusLogger.getLogger();
64 static final Executor executor = createExecutor();
64 static final Executor executor = isJmxDisabled() ? null : createExecutor();
6565
6666 private Server() {
6767 }
7171 * background thread Executor, depending on the value of system property "log4j2.jmx.notify.async". If this
7272 * property is not set, use a {@code null} Executor for web apps to avoid memory leaks and other issues when the
7373 * web app is restarted.
74 * @see LOG4J2-938
74 * @see <a href="https://issues.apache.org/jira/browse/LOG4J2-938">LOG4J2-938</a>
7575 */
7676 private static ExecutorService createExecutor() {
77 boolean defaultAsync = !isWebApp();
78 boolean async = PropertiesUtil.getProperties().getBooleanProperty(PROPERTY_ASYNC_NOTIF, defaultAsync);
77 final boolean defaultAsync = !isWebApp();
78 final boolean async = PropertiesUtil.getProperties().getBooleanProperty(PROPERTY_ASYNC_NOTIF, defaultAsync);
7979 return async ? Executors.newFixedThreadPool(1, new DaemonThreadFactory(THREAD_NAME_PREFIX)) : null;
8080 }
8181
132132 return sb.toString();
133133 }
134134
135 private static boolean isJmxDisabled() {
136 return PropertiesUtil.getProperties().getBooleanProperty(PROPERTY_DISABLE_JMX);
137 }
138
135139 public static void reregisterMBeansAfterReconfigure() {
136140 // avoid creating Platform MBean Server if JMX disabled
137 if (PropertiesUtil.getProperties().getBooleanProperty(PROPERTY_DISABLE_JMX)) {
141 if (isJmxDisabled()) {
138142 LOGGER.debug("JMX disabled for log4j2. Not registering MBeans.");
139143 return;
140144 }
143147 }
144148
145149 public static void reregisterMBeansAfterReconfigure(final MBeanServer mbs) {
146 if (PropertiesUtil.getProperties().getBooleanProperty(PROPERTY_DISABLE_JMX)) {
150 if (isJmxDisabled()) {
147151 LOGGER.debug("JMX disabled for log4j2. Not registering MBeans.");
148152 return;
149153 }
6262 } catch (final Exception e) {
6363 throw new IllegalStateException(e);
6464 }
65 removeListeners(contextName);
6566 StatusLogger.getLogger().registerListener(this);
6667 }
6768
69 /**
70 * Add listener to StatusLogger for this context, or replace it if it already exists.
71 *
72 * @param ctxName
73 */
74 private void removeListeners(final String ctxName) {
75 final StatusLogger logger = StatusLogger.getLogger();
76 final Iterable<StatusListener> listeners = logger.getListeners();
77 // Remove any StatusLoggerAdmin listeners already registered for this context
78 for (final StatusListener statusListener : listeners) {
79 if (statusListener instanceof StatusLoggerAdmin) {
80 final StatusLoggerAdmin adminListener = (StatusLoggerAdmin) statusListener;
81 if (ctxName != null && ctxName.equals(adminListener.contextName)) {
82 logger.removeListener(adminListener);
83 }
84 }
85 }
86 }
87
6888 private static MBeanNotificationInfo createNotificationInfo() {
69 final String[] notifTypes = new String[] {//
70 NOTIF_TYPE_DATA, NOTIF_TYPE_MESSAGE };
89 final String[] notifTypes = new String[] {
90 NOTIF_TYPE_DATA,
91 NOTIF_TYPE_MESSAGE };
7192 final String name = Notification.class.getName();
7293 final String description = "StatusLogger has logged an event";
7394 return new MBeanNotificationInfo(notifTypes, name, description);
117138 */
118139 @Override
119140 public void log(final StatusData data) {
120 final Notification notifMsg = new Notification(NOTIF_TYPE_MESSAGE, getObjectName(), nextSeqNo(), now(),
141 final Notification notifMsg = new Notification(NOTIF_TYPE_MESSAGE, getObjectName(), nextSeqNo(), nowMillis(),
121142 data.getFormattedStatus());
122143 sendNotification(notifMsg);
123144
124 final Notification notifData = new Notification(NOTIF_TYPE_DATA, getObjectName(), nextSeqNo(), now());
145 final Notification notifData = new Notification(NOTIF_TYPE_DATA, getObjectName(), nextSeqNo(), nowMillis());
125146 notifData.setUserData(data);
126147 sendNotification(notifData);
127148 }
141162 return sequenceNo.getAndIncrement();
142163 }
143164
144 private long now() {
165 private long nowMillis() {
145166 return System.currentTimeMillis();
146167 }
147168
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.layout;
17
18 import java.nio.charset.Charset;
19
20 import org.apache.commons.csv.CSVFormat;
21 import org.apache.commons.csv.QuoteMode;
22
23 /**
24 * A superclass for Comma-Separated Value (CSV) layouts.
25 *
26 * Depends on Apache Commons CSV 1.2.
27 *
28 * @since 2.4
29 */
30 public abstract class AbstractCsvLayout extends AbstractStringLayout {
31
32 private static final String CONTENT_TYPE = "text/csv";
33 protected static final String DEFAULT_CHARSET = "UTF-8";
34 protected static final String DEFAULT_FORMAT = "Default";
35 private static final long serialVersionUID = 1L;
36
37 protected static CSVFormat createFormat(final String format, final Character delimiter, final Character escape, final Character quote, final QuoteMode quoteMode, final String nullString,
38 final String recordSeparator) {
39 CSVFormat csvFormat = CSVFormat.valueOf(format);
40 if (delimiter != null) {
41 csvFormat = csvFormat.withDelimiter(delimiter);
42 }
43 if (escape != null) {
44 csvFormat = csvFormat.withEscape(escape);
45 }
46 if (quote != null) {
47 csvFormat = csvFormat.withQuote(quote);
48 }
49 if (quoteMode != null) {
50 csvFormat = csvFormat.withQuoteMode(quoteMode);
51 }
52 if (nullString != null) {
53 csvFormat = csvFormat.withNullString(nullString);
54 }
55 if (recordSeparator != null) {
56 csvFormat = csvFormat.withRecordSeparator(recordSeparator);
57 }
58 return csvFormat;
59 }
60
61 private final CSVFormat format;
62
63 protected AbstractCsvLayout(final Charset charset, final CSVFormat csvFormat, final String header,
64 final String footer) {
65 super(charset, toBytes(header, charset), toBytes(footer, charset));
66 this.format = csvFormat;
67 }
68
69 @Override
70 public String getContentType() {
71 return CONTENT_TYPE + "; charset=" + this.getCharset();
72 }
73
74 public CSVFormat getFormat() {
75 return format;
76 }
77
78 }
3333 protected final boolean compact;
3434 protected final boolean complete;
3535
36 protected AbstractJacksonLayout(final ObjectWriter objectWriter, final Charset charset, final boolean compact, final boolean complete, boolean eventEol) {
36 protected AbstractJacksonLayout(final ObjectWriter objectWriter, final Charset charset, final boolean compact, final boolean complete, final boolean eventEol) {
3737 super(charset);
3838 this.objectWriter = objectWriter;
3939 this.compact = compact;
6464
6565 @Override
6666 public Map<String, String> getContentFormat() {
67 return new HashMap<String, String>();
67 return new HashMap<>();
6868 }
6969
7070 /**
1616 package org.apache.logging.log4j.core.layout;
1717
1818 import java.nio.charset.Charset;
19 import java.nio.charset.StandardCharsets;
1920
2021 import org.apache.logging.log4j.core.LogEvent;
21 import org.apache.logging.log4j.core.util.Charsets;
2222
2323 /**
2424 * Abstract base class for Layouts that result in a String.
2626 public abstract class AbstractStringLayout extends AbstractLayout<String> {
2727
2828 private static final long serialVersionUID = 1L;
29
30 /**
31 * Converts a String to a byte[].
32 *
33 * @param str
34 * if null, return null.
35 * @param charset
36 * if null, use the default charset.
37 * @return a byte[]
38 */
39 static byte[] toBytes(final String str, final Charset charset) {
40 if (str != null) {
41 return str.getBytes(charset != null ? charset : Charset.defaultCharset());
42 }
43 return null;
44 }
2945
3046 /**
3147 * The charset for the formatted message.
3955
4056 protected AbstractStringLayout(final Charset charset, final byte[] header, final byte[] footer) {
4157 super(header, footer);
42 this.charset = charset == null ? Charsets.UTF_8 : charset;
58 this.charset = charset == null ? StandardCharsets.UTF_8 : charset;
4359 }
4460
45 protected byte[] getBytes(String s) {
61 protected byte[] getBytes(final String s) {
4662 return s.getBytes(charset);
4763 }
4864
6985 public byte[] toByteArray(final LogEvent event) {
7086 return toSerializable(event).getBytes(charset);
7187 }
88
7289 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.layout;
17
18 import java.io.IOException;
19 import java.nio.charset.Charset;
20
21 import org.apache.commons.csv.CSVFormat;
22 import org.apache.commons.csv.CSVPrinter;
23 import org.apache.commons.csv.QuoteMode;
24 import org.apache.logging.log4j.core.Layout;
25 import org.apache.logging.log4j.core.LogEvent;
26 import org.apache.logging.log4j.core.config.Node;
27 import org.apache.logging.log4j.core.config.plugins.Plugin;
28 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
29 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
30 import org.apache.logging.log4j.status.StatusLogger;
31
32 /**
33 * A Comma-Separated Value (CSV) layout to log events.
34 *
35 * Depends on Apache Commons CSV 1.2.
36 *
37 * @since 2.4
38 */
39 @Plugin(name = "CsvLogEventLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true)
40 public class CsvLogEventLayout extends AbstractCsvLayout {
41
42 /**
43 *
44 */
45 private static final long serialVersionUID = 1L;
46
47 public static CsvLogEventLayout createDefaultLayout() {
48 return new CsvLogEventLayout(Charset.forName(DEFAULT_CHARSET), CSVFormat.valueOf(DEFAULT_FORMAT), null, null);
49 }
50
51 public static CsvLogEventLayout createLayout(final CSVFormat format) {
52 return new CsvLogEventLayout(Charset.forName(DEFAULT_CHARSET), format, null, null);
53 }
54
55 @PluginFactory
56 public static CsvLogEventLayout createLayout(
57 // @formatter:off
58 @PluginAttribute(value = "format", defaultString = DEFAULT_FORMAT) final String format,
59 @PluginAttribute("delimiter") final Character delimiter,
60 @PluginAttribute("escape") final Character escape,
61 @PluginAttribute("quote") final Character quote,
62 @PluginAttribute("quoteMode") final QuoteMode quoteMode,
63 @PluginAttribute("nullString") final String nullString,
64 @PluginAttribute("recordSeparator") final String recordSeparator,
65 @PluginAttribute(value = "charset", defaultString = DEFAULT_CHARSET) final Charset charset,
66 @PluginAttribute("header") final String header,
67 @PluginAttribute("footer") final String footer)
68 // @formatter:on
69 {
70
71 final CSVFormat csvFormat = createFormat(format, delimiter, escape, quote, quoteMode, nullString, recordSeparator);
72 return new CsvLogEventLayout(charset, csvFormat, header, footer);
73 }
74
75 protected CsvLogEventLayout(final Charset charset, final CSVFormat csvFormat, final String header, final String footer) {
76 super(charset, csvFormat, header, footer);
77 }
78
79 @Override
80 public String toSerializable(final LogEvent event) {
81 final StringBuilder buffer = new StringBuilder(1024);
82 try {
83 // Revisit when 1.3 is out so that we do not need to create a new
84 // printer for each event.
85 // No need to close the printer.
86 final CSVPrinter printer = new CSVPrinter(buffer, getFormat());
87 printer.print(event.getNanoTime());
88 printer.print(event.getTimeMillis());
89 printer.print(event.getLevel());
90 printer.print(event.getThreadName());
91 printer.print(event.getMessage().getFormattedMessage());
92 printer.print(event.getLoggerFqcn());
93 printer.print(event.getLoggerName());
94 printer.print(event.getMarker());
95 printer.print(event.getThrownProxy());
96 printer.print(event.getSource());
97 printer.print(event.getContextMap());
98 printer.print(event.getContextStack());
99 printer.println();
100 return buffer.toString();
101 } catch (final IOException e) {
102 StatusLogger.getLogger().error(event.toString(), e);
103 return getFormat().getCommentMarker() + " " + e;
104 }
105 }
106
107 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.layout;
17
18 import java.io.IOException;
19 import java.nio.charset.Charset;
20
21 import org.apache.commons.csv.CSVFormat;
22 import org.apache.commons.csv.CSVPrinter;
23 import org.apache.commons.csv.QuoteMode;
24 import org.apache.logging.log4j.core.Layout;
25 import org.apache.logging.log4j.core.LogEvent;
26 import org.apache.logging.log4j.core.config.Node;
27 import org.apache.logging.log4j.core.config.plugins.Plugin;
28 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
29 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
30 import org.apache.logging.log4j.message.Message;
31 import org.apache.logging.log4j.status.StatusLogger;
32
33 /**
34 * A Comma-Separated Value (CSV) layout to log event parameters.
35 * The event message is currently ignored.
36 *
37 * <p>
38 * Best used with:
39 * </p>
40 * <p>
41 * {@code logger.debug(new ObjectArrayMessage(1, 2, "Bob"));}
42 * </p>
43 *
44 * Depends on Apache Commons CSV 1.2.
45 *
46 * @since 2.4
47 */
48 @Plugin(name = "CsvParameterLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true)
49 public class CsvParameterLayout extends AbstractCsvLayout {
50
51 private static final long serialVersionUID = 1L;
52
53 public static AbstractCsvLayout createDefaultLayout() {
54 return new CsvParameterLayout(Charset.forName(DEFAULT_CHARSET), CSVFormat.valueOf(DEFAULT_FORMAT), null, null);
55 }
56
57 public static AbstractCsvLayout createLayout(final CSVFormat format) {
58 return new CsvParameterLayout(Charset.forName(DEFAULT_CHARSET), format, null, null);
59 }
60
61 @PluginFactory
62 public static AbstractCsvLayout createLayout(
63 // @formatter:off
64 @PluginAttribute(value = "format", defaultString = DEFAULT_FORMAT) final String format,
65 @PluginAttribute("delimiter") final Character delimiter,
66 @PluginAttribute("escape") final Character escape,
67 @PluginAttribute("quote") final Character quote,
68 @PluginAttribute("quoteMode") final QuoteMode quoteMode,
69 @PluginAttribute("nullString") final String nullString,
70 @PluginAttribute("recordSeparator") final String recordSeparator,
71 @PluginAttribute(value = "charset", defaultString = DEFAULT_CHARSET) final Charset charset,
72 @PluginAttribute("header") final String header,
73 @PluginAttribute("footer") final String footer)
74 // @formatter:on
75 {
76
77 final CSVFormat csvFormat = createFormat(format, delimiter, escape, quote, quoteMode, nullString, recordSeparator);
78 return new CsvParameterLayout(charset, csvFormat, header, footer);
79 }
80
81 public CsvParameterLayout(final Charset charset, final CSVFormat csvFormat, final String header, final String footer) {
82 super(charset, csvFormat, header, footer);
83 }
84
85 @Override
86 public String toSerializable(final LogEvent event) {
87 final Message message = event.getMessage();
88 final Object[] parameters = message.getParameters();
89 final StringBuilder buffer = new StringBuilder(1024);
90 try {
91 // Revisit when 1.3 is out so that we do not need to create a new
92 // printer for each event.
93 // No need to close the printer.
94 final CSVPrinter printer = new CSVPrinter(buffer, getFormat());
95 printer.printRecord(parameters);
96 return buffer.toString();
97 } catch (final IOException e) {
98 StatusLogger.getLogger().error(message, e);
99 return getFormat().getCommentMarker() + " " + e;
100 }
101 }
102
103 }
2121 import java.io.PrintWriter;
2222 import java.io.StringWriter;
2323 import java.math.BigDecimal;
24 import java.nio.charset.StandardCharsets;
2425 import java.util.Collections;
2526 import java.util.Map;
2627 import java.util.zip.DeflaterOutputStream;
3536 import org.apache.logging.log4j.core.config.plugins.PluginElement;
3637 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
3738 import org.apache.logging.log4j.core.net.Severity;
38 import org.apache.logging.log4j.core.util.Charsets;
3939 import org.apache.logging.log4j.core.util.KeyValuePair;
4040 import org.apache.logging.log4j.status.StatusLogger;
41 import org.apache.logging.log4j.util.Strings;
4142
4243 import com.fasterxml.jackson.core.io.JsonStringEncoder;
4344
4445 /**
4546 * Lays out events in the Graylog Extended Log Format (GELF) 1.1.
4647 * <p>
47 * This layout compresses JSON to GZIP or ZLIB (the {@code compressionType}) if log event data is larger than 1024 bytes
48 * (the {@code compressionThreshold}). This layout does not implement chunking.
48 * This layout compresses JSON to GZIP or ZLIB (the {@code compressionType}) if
49 * log event data is larger than 1024 bytes (the {@code compressionThreshold}).
50 * This layout does not implement chunking.
4951 * </p>
5052 * <p>
5153 * Configure as follows to send to a Graylog2 server:
6365 * </pre>
6466 *
6567 * @see <a href="http://graylog2.org/gelf">GELF home page</a>
66 * @see <a href="http://graylog2.org/resources/gelf/specification">GELF specification</a>
68 * @see <a href="http://graylog2.org/resources/gelf/specification">GELF
69 * specification</a>
6770 */
6871 @Plugin(name = "GelfLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true)
6972 public final class GelfLayout extends AbstractStringLayout {
106109 //@formatter:off
107110 @PluginAttribute("host") final String host,
108111 @PluginElement("AdditionalField") final KeyValuePair[] additionalFields,
109 @PluginAttribute(value = "compressionThreshold",
112 @PluginAttribute(value = "compressionType",
110113 defaultString = "GZIP") final CompressionType compressionType,
111114 @PluginAttribute(value = "compressionThreshold",
112115 defaultInt= COMPRESSION_THRESHOLD) final int compressionThreshold) {
144147
145148 public GelfLayout(final String host, final KeyValuePair[] additionalFields, final CompressionType compressionType,
146149 final int compressionThreshold) {
147 super(Charsets.UTF_8);
150 super(StandardCharsets.UTF_8);
148151 this.host = host;
149152 this.additionalFields = additionalFields;
150153 this.compressionType = compressionType;
154157 private byte[] compress(final byte[] bytes) {
155158 try {
156159 final ByteArrayOutputStream baos = new ByteArrayOutputStream(compressionThreshold / 8);
157 final DeflaterOutputStream stream = compressionType.createDeflaterOutputStream(baos);
158 if (stream == null) {
159 return bytes;
160 }
161 stream.write(bytes);
162 stream.finish();
163 stream.close();
160 try (final DeflaterOutputStream stream = compressionType.createDeflaterOutputStream(baos)) {
161 if (stream == null) {
162 return bytes;
163 }
164 stream.write(bytes);
165 stream.finish();
166 }
164167 return baos.toByteArray();
165168 } catch (final IOException e) {
166169 StatusLogger.getLogger().error(e);
190193 final JsonStringEncoder jsonEncoder = JsonStringEncoder.getInstance();
191194 builder.append('{');
192195 builder.append("\"version\":\"1.1\",");
193 builder.append("\"host\":\"").append(jsonEncoder.quoteAsString(host)).append(QC);
196 builder.append("\"host\":\"").append(jsonEncoder.quoteAsString(toNullSafeString(host))).append(QC);
194197 builder.append("\"timestamp\":").append(formatTimestamp(event.getTimeMillis())).append(C);
195198 builder.append("\"level\":").append(formatLevel(event.getLevel())).append(C);
196199 if (event.getThreadName() != null) {
202205
203206 for (final KeyValuePair additionalField : additionalFields) {
204207 builder.append(QU).append(jsonEncoder.quoteAsString(additionalField.getKey())).append("\":\"")
205 .append(jsonEncoder.quoteAsString(additionalField.getValue())).append(QC);
208 .append(jsonEncoder.quoteAsString(toNullSafeString(additionalField.getValue()))).append(QC);
206209 }
207210 for (final Map.Entry<String, String> entry : event.getContextMap().entrySet()) {
208211 builder.append(QU).append(jsonEncoder.quoteAsString(entry.getKey())).append("\":\"")
209 .append(jsonEncoder.quoteAsString(entry.getValue())).append(QC);
212 .append(jsonEncoder.quoteAsString(toNullSafeString(entry.getValue()))).append(QC);
210213 }
211214 if (event.getThrown() != null) {
212215 builder.append("\"full_message\":\"").append(jsonEncoder.quoteAsString(formatThrowable(event.getThrown())))
213216 .append(QC);
214217 }
215218
216 builder.append("\"short_message\":\"")
217 .append(jsonEncoder.quoteAsString(event.getMessage().getFormattedMessage())).append(Q);
219 builder.append("\"short_message\":\"").append(jsonEncoder.quoteAsString(toNullSafeString(event.getMessage().getFormattedMessage())))
220 .append(Q);
218221 builder.append('}');
219222 return builder.toString();
220223 }
224
225 private String toNullSafeString(final String s) {
226 return s == null ? Strings.EMPTY : s;
227 }
221228 }
2323 import java.io.StringWriter;
2424 import java.lang.management.ManagementFactory;
2525 import java.nio.charset.Charset;
26 import java.nio.charset.StandardCharsets;
2627 import java.util.ArrayList;
28
2729 import org.apache.logging.log4j.Level;
2830 import org.apache.logging.log4j.core.Layout;
2931 import org.apache.logging.log4j.core.LogEvent;
3335 import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
3436 import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
3537 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
36 import org.apache.logging.log4j.core.util.Charsets;
3738 import org.apache.logging.log4j.core.util.Constants;
3839 import org.apache.logging.log4j.core.util.Transform;
3940
223224 }
224225 pw.flush();
225226 final LineNumberReader reader = new LineNumberReader(new StringReader(sw.toString()));
226 final ArrayList<String> lines = new ArrayList<String>();
227 final ArrayList<String> lines = new ArrayList<>();
227228 try {
228229 String line = reader.readLine();
229230 while (line != null) {
356357 private String contentType = null; // defer default value in order to use specified charset
357358
358359 @PluginBuilderAttribute
359 private Charset charset = Charsets.UTF_8;
360 private Charset charset = StandardCharsets.UTF_8;
360361
361362 @PluginBuilderAttribute
362363 private FontSize fontSize = FontSize.SMALL;
4848 }
4949
5050 @Override
51 protected String getPropertNameForNanoTime() {
52 return JsonConstants.ELT_NANO_TIME;
53 }
54
55 @Override
5156 protected PrettyPrinter newCompactPrinter() {
5257 return new MinimalPrettyPrinter();
5358 }
7681 }
7782
7883 @Override
84 protected String getPropertNameForNanoTime() {
85 return JsonConstants.ELT_NANO_TIME;
86 }
87
88 @Override
7989 protected PrettyPrinter newCompactPrinter() {
8090 // Yes, null is the proper answer.
8191 return null;
95105 abstract protected String getPropertNameForContextMap();
96106
97107 abstract protected String getPropertNameForSource();
108
109 abstract protected String getPropertNameForNanoTime();
98110
99111 abstract protected PrettyPrinter newCompactPrinter();
100112
104116
105117 ObjectWriter newWriter(final boolean locationInfo, final boolean properties, final boolean compact) {
106118 final SimpleFilterProvider filters = new SimpleFilterProvider();
107 final Set<String> except = new HashSet<String>(2);
119 final Set<String> except = new HashSet<>(2);
108120 if (!locationInfo) {
109121 except.add(this.getPropertNameForSource());
110122 }
111123 if (!properties) {
112124 except.add(this.getPropertNameForContextMap());
113125 }
126 except.add(this.getPropertNameForNanoTime());
114127 filters.addFilter(Log4jLogEvent.class.getName(), SimpleBeanPropertyFilter.serializeAllExcept(except));
115128 final ObjectWriter writer = this.newObjectMapper().writer(compact ? this.newCompactPrinter() : this.newPrettyPrinter());
116129 return writer.with(filters);
1616 package org.apache.logging.log4j.core.layout;
1717
1818 import java.nio.charset.Charset;
19 import java.nio.charset.StandardCharsets;
1920 import java.util.HashMap;
2021 import java.util.Map;
2122
2425 import org.apache.logging.log4j.core.config.plugins.Plugin;
2526 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
2627 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
27 import org.apache.logging.log4j.core.util.Charsets;
2828
2929 /**
3030 * Appends a series of JSON events as strings serialized as bytes.
798798 private static final long serialVersionUID = 1L;
799799
800800 protected JsonLayout(final boolean locationInfo, final boolean properties, final boolean complete, final boolean compact,
801 boolean eventEol, final Charset charset) {
801 final boolean eventEol, final Charset charset) {
802802 super(new JacksonFactory.JSON().newWriter(locationInfo, properties, compact), charset, compact, complete, eventEol);
803803 }
804804
833833
834834 @Override
835835 public Map<String, String> getContentFormat() {
836 final Map<String, String> result = new HashMap<String, String>();
836 final Map<String, String> result = new HashMap<>();
837837 result.put("version", "2.0");
838838 return result;
839839 }
884884 * @return A JSON Layout.
885885 */
886886 public static AbstractJacksonLayout createDefaultLayout() {
887 return new JsonLayout(false, false, false, false, false, Charsets.UTF_8);
887 return new JsonLayout(false, false, false, false, false, StandardCharsets.UTF_8);
888888 }
889889 }
7474 @PluginAttribute("sdId") final String sdId,
7575 @PluginAttribute("enterpriseId") final String enterpriseId,
7676 @PluginAttribute(value = "discardIfAllFieldsAreEmpty", defaultBoolean = false) final boolean discardIfAllFieldsAreEmpty) {
77 final Map<String, String> map = new HashMap<String, String>();
77 final Map<String, String> map = new HashMap<>();
7878
7979 for (final KeyValuePair keyValuePair : keyValuePairs) {
8080 map.put(keyValuePair.getKey(), keyValuePair.getValue());
8383 /**
8484 * Initial converter for pattern.
8585 */
86 private final List<PatternFormatter> formatters;
86 private final PatternFormatter[] formatters;
87
88 private static ThreadLocal<StringBuilder> strBuilder = new ThreadLocal<StringBuilder>() {
89 @Override
90 protected StringBuilder initialValue() {
91 return new StringBuilder(1024);
92 }
93 };
8794
8895 /**
8996 * Conversion pattern.
125132 this.alwaysWriteExceptions = alwaysWriteExceptions;
126133 this.noConsoleNoAnsi = noConsoleNoAnsi;
127134 final PatternParser parser = createPatternParser(config);
128 this.formatters = parser.parse(pattern == null ? DEFAULT_CONVERSION_PATTERN : pattern, this.alwaysWriteExceptions, this.noConsoleNoAnsi);
129 }
130
131 private static byte[] toBytes(final String str, final Charset charset) {
132 if (str != null) {
133 return str.getBytes(charset != null ? charset : Charset.defaultCharset());
134 }
135 return null;
135 try {
136 List<PatternFormatter> list = parser.parse(pattern == null ? DEFAULT_CONVERSION_PATTERN : pattern,
137 this.alwaysWriteExceptions, this.noConsoleNoAnsi);
138 this.formatters = list.toArray(new PatternFormatter[0]);
139 } catch (RuntimeException ex) {
140 throw new IllegalArgumentException("Cannot parse pattern '" + pattern + "'", ex);
141 }
136142 }
137143
138144 private byte[] strSubstitutorReplace(final byte... b) {
174180 @Override
175181 public Map<String, String> getContentFormat()
176182 {
177 final Map<String, String> result = new HashMap<String, String>();
183 final Map<String, String> result = new HashMap<>();
178184 result.put("structured", "false");
179185 result.put("formatType", "conversion");
180186 result.put("format", conversionPattern);
190196 */
191197 @Override
192198 public String toSerializable(final LogEvent event) {
193 final StringBuilder buf = new StringBuilder();
194 for (final PatternFormatter formatter : formatters) {
195 formatter.format(event, buf);
199 final StringBuilder buf = strBuilder.get();
200 buf.setLength(0);
201 final int len = formatters.length;
202 for (int i = 0; i < len; i++) {
203 formatters[i].format(event, buf);
196204 }
197205 String str = buf.toString();
198206 if (replace != null) {
1616 package org.apache.logging.log4j.core.layout;
1717
1818 import java.nio.charset.Charset;
19 import java.nio.charset.StandardCharsets;
1920 import java.util.ArrayList;
2021 import java.util.Calendar;
2122 import java.util.GregorianCalendar;
4647 import org.apache.logging.log4j.core.pattern.PatternFormatter;
4748 import org.apache.logging.log4j.core.pattern.PatternParser;
4849 import org.apache.logging.log4j.core.pattern.ThrowablePatternConverter;
49 import org.apache.logging.log4j.core.util.Charsets;
5050 import org.apache.logging.log4j.core.util.NetUtils;
5151 import org.apache.logging.log4j.core.util.Patterns;
5252 import org.apache.logging.log4j.message.Message;
5353 import org.apache.logging.log4j.message.StructuredDataId;
5454 import org.apache.logging.log4j.message.StructuredDataMessage;
55 import org.apache.logging.log4j.util.StringBuilders;
5556 import org.apache.logging.log4j.util.Strings;
5657
5758
147148 final String[] array = excludes.split(Patterns.COMMA_SEPARATOR);
148149 if (array.length > 0) {
149150 c = new ExcludeChecker();
150 mdcExcludes = new ArrayList<String>(array.length);
151 mdcExcludes = new ArrayList<>(array.length);
151152 for (final String str : array) {
152153 mdcExcludes.add(str.trim());
153154 }
161162 final String[] array = includes.split(Patterns.COMMA_SEPARATOR);
162163 if (array.length > 0) {
163164 c = new IncludeChecker();
164 mdcIncludes = new ArrayList<String>(array.length);
165 mdcIncludes = new ArrayList<>(array.length);
165166 for (final String str : array) {
166167 mdcIncludes.add(str.trim());
167168 }
174175 if (required != null) {
175176 final String[] array = required.split(Patterns.COMMA_SEPARATOR);
176177 if (array.length > 0) {
177 mdcRequired = new ArrayList<String>(array.length);
178 mdcRequired = new ArrayList<>(array.length);
178179 for (final String str : array) {
179180 mdcRequired.add(str.trim());
180181 }
187188 }
188189 this.checker = c != null ? c : noopChecker;
189190 final String name = config == null ? null : config.getName();
190 configName = name != null && name.length() > 0 ? name : null;
191 configName = Strings.isNotEmpty(name) ? name : null;
191192 this.fieldFormatters = createFieldFormatters(loggerFields, config);
192193 }
193194
194195 private Map<String, FieldFormatter> createFieldFormatters(final LoggerFields[] loggerFields,
195196 final Configuration config) {
196 final Map<String, FieldFormatter> sdIdMap = new HashMap<String, FieldFormatter>();
197 final Map<String, FieldFormatter> sdIdMap = new HashMap<>();
197198
198199 if (loggerFields != null) {
199200 for (final LoggerFields lField : loggerFields) {
200201 final StructuredDataId key = lField.getSdId() == null ? mdcSdId : lField.getSdId();
201 final Map<String, List<PatternFormatter>> sdParams = new HashMap<String, List<PatternFormatter>>();
202 final Map<String, List<PatternFormatter>> sdParams = new HashMap<>();
202203 final Map<String, String> fields = lField.getMap();
203204 if (!fields.isEmpty()) {
204205 final PatternParser fieldParser = createPatternParser(config, null);
248249 */
249250 @Override
250251 public Map<String, String> getContentFormat() {
251 final Map<String, String> result = new HashMap<String, String>();
252 final Map<String, String> result = new HashMap<>();
252253 result.put("structured", "true");
253254 result.put("formatType", "RFC5424");
254255 return result;
356357 return;
357358 }
358359
359 final Map<String, StructuredDataElement> sdElements = new HashMap<String, StructuredDataElement>();
360 final Map<String, StructuredDataElement> sdElements = new HashMap<>();
360361 final Map<String, String> contextMap = event.getContextMap();
361362
362363 if (mdcRequired != null) {
372373 }
373374
374375 if (includeMdc && contextMap.size() > 0) {
375 if (sdElements.containsKey(mdcSdId.toString())) {
376 final StructuredDataElement union = sdElements.get(mdcSdId.toString());
376 final String mdcSdIdStr = mdcSdId.toString();
377 final StructuredDataElement union = sdElements.get(mdcSdIdStr);
378 if (union != null) {
377379 union.union(contextMap);
378 sdElements.put(mdcSdId.toString(), union);
380 sdElements.put(mdcSdIdStr, union);
379381 } else {
380382 final StructuredDataElement formattedContextMap = new StructuredDataElement(contextMap, false);
381 sdElements.put(mdcSdId.toString(), formattedContextMap);
383 sdElements.put(mdcSdIdStr, formattedContextMap);
382384 }
383385 }
384386
531533 }
532534
533535 private void appendMap(final String prefix, final Map<String, String> map, final StringBuilder sb,
534 final ListChecker checker) {
535 final SortedMap<String, String> sorted = new TreeMap<String, String>(map);
536 final ListChecker checker) {
537 final SortedMap<String, String> sorted = new TreeMap<>(map);
536538 for (final Map.Entry<String, String> entry : sorted.entrySet()) {
537539 if (checker.check(entry.getKey()) && entry.getValue() != null) {
538540 sb.append(' ');
539541 if (prefix != null) {
540542 sb.append(prefix);
541543 }
542 sb.append(escapeNewlines(escapeSDParams(entry.getKey()), escapeNewLine)).append("=\"")
543 .append(escapeNewlines(escapeSDParams(entry.getValue()), escapeNewLine)).append('"');
544 final String safeKey = escapeNewlines(escapeSDParams(entry.getKey()), escapeNewLine);
545 final String safeValue = escapeNewlines(escapeSDParams(entry.getValue()), escapeNewLine);
546 StringBuilders.appendKeyDqValue(sb, safeKey, safeValue);
544547 }
545548 }
546549 }
643646 @PluginAttribute(value = "useTlsMessageFormat", defaultBoolean = false) final boolean useTlsMessageFormat, // RFC 5425
644647 @PluginElement("LoggerFields") final LoggerFields[] loggerFields,
645648 @PluginConfiguration final Configuration config) {
646 final Charset charset = Charsets.UTF_8;
647649 if (includes != null && excludes != null) {
648650 LOGGER.error("mdcIncludes and mdcExcludes are mutually exclusive. Includes wil be ignored");
649651 includes = null;
650652 }
651653
652654 return new Rfc5424Layout(config, facility, id, enterpriseNumber, includeMDC, newLine, escapeNL, mdcId, mdcPrefix,
653 eventPrefix, appName, msgId, excludes, includes, required, charset, exceptionPattern,
655 eventPrefix, appName, msgId, excludes, includes, required, StandardCharsets.UTF_8, exceptionPattern,
654656 useTlsMessageFormat, loggerFields);
655657 }
656658
665667 }
666668
667669 public StructuredDataElement format(final LogEvent event) {
668 final Map<String, String> map = new HashMap<String, String>();
670 final Map<String, String> map = new HashMap<>();
669671
670672 for (final Map.Entry<String, List<PatternFormatter>> entry : delegateMap.entrySet()) {
671673 final StringBuilder buffer = new StringBuilder();
3939 static {
4040 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
4141 try {
42 final ObjectOutputStream oos = new ObjectOutputStream(baos);
43 oos.close();
42 new ObjectOutputStream(baos).close();
4443 serializedHeader = baos.toByteArray();
4544 } catch (final Exception ex) {
4645 LOGGER.error("Unable to generate Object stream header", ex);
6059 @Override
6160 public byte[] toByteArray(final LogEvent event) {
6261 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
63 try {
64 final ObjectOutputStream oos = new PrivateObjectOutputStream(baos);
65 try {
66 oos.writeObject(event);
67 oos.reset();
68 } finally {
69 oos.close();
70 }
62 try (final ObjectOutputStream oos = new PrivateObjectOutputStream(baos)) {
63 oos.writeObject(event);
64 oos.reset();
7165 } catch (final IOException ioe) {
7266 LOGGER.error("Serialization of LogEvent failed.", ioe);
7367 }
3333 import org.apache.logging.log4j.core.net.Facility;
3434 import org.apache.logging.log4j.core.net.Priority;
3535 import org.apache.logging.log4j.core.util.NetUtils;
36 import org.apache.logging.log4j.util.Chars;
3637
3738
3839 /**
5556 /**
5657 * Date format used if header = true.
5758 */
58 private final SimpleDateFormat dateFormat = new SimpleDateFormat("MMM dd HH:mm:ss ", Locale.ENGLISH);
59 private final SimpleDateFormat dateFormat = new SimpleDateFormat("MMM dd HH:mm:ss", Locale.ENGLISH);
5960 /**
6061 * Host name used to identify messages from this appender.
6162 */
6263 private final String localHostname = NetUtils.getLocalHostname();
63
64
6564
6665 protected SyslogLayout(final Facility facility, final boolean includeNL, final String escapeNL, final Charset charset) {
6766 super(charset);
8483 buf.append(Priority.getPriority(facility, event.getLevel()));
8584 buf.append('>');
8685 addDate(event.getTimeMillis(), buf);
87 buf.append(' ');
86 buf.append(Chars.SPACE);
8887 buf.append(localHostname);
89 buf.append(' ');
88 buf.append(Chars.SPACE);
9089
9190 String message = event.getMessage().getFormattedMessage();
9291 if (null != escapeNewLine) {
105104 buf.append(dateFormat.format(new Date(timestamp)));
106105 // RFC 3164 says leading space, not leading zero on days 1-9
107106 if (buf.charAt(index) == '0') {
108 buf.setCharAt(index, ' ');
107 buf.setCharAt(index, Chars.SPACE);
109108 }
110109 }
111110
113112 * Gets this SyslogLayout's content format. Specified by:
114113 * <ul>
115114 * <li>Key: "structured" Value: "false"</li>
116 * <li>Key: "dateFormat" Value: "MMM dd HH:mm:ss "</li>
115 * <li>Key: "dateFormat" Value: "MMM dd HH:mm:ss"</li>
117116 * <li>Key: "format" Value: "&lt;LEVEL&gt;TIMESTAMP PROP(HOSTNAME) MESSAGE"</li>
118117 * <li>Key: "formatType" Value: "logfilepatternreceiver" (format uses the keywords supported by
119118 * LogFilePatternReceiver)</li>
123122 */
124123 @Override
125124 public Map<String, String> getContentFormat() {
126 final Map<String, String> result = new HashMap<String, String>();
125 final Map<String, String> result = new HashMap<>();
127126 result.put("structured", "false");
128127 result.put("formatType", "logfilepatternreceiver");
129128 result.put("dateFormat", dateFormat.toPattern());
1616 package org.apache.logging.log4j.core.layout;
1717
1818 import java.nio.charset.Charset;
19 import java.nio.charset.StandardCharsets;
1920 import java.util.HashMap;
2021 import java.util.Map;
2122
2526 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
2627 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
2728 import org.apache.logging.log4j.core.jackson.XmlConstants;
28 import org.apache.logging.log4j.core.util.Charsets;
2929
3030 /**
3131 * Appends a series of {@code event} elements as defined in the <a href="log4j.dtd">log4j.dtd</a>.
247247 */
248248 @Override
249249 public Map<String, String> getContentFormat() {
250 final Map<String, String> result = new HashMap<String, String>();
250 final Map<String, String> result = new HashMap<>();
251251 // result.put("dtd", "log4j-events.dtd");
252252 result.put("xsd", "log4j-events.xsd");
253253 result.put("version", "2.0");
254254 return result;
255255 }
256256
257 @Override
258257 /**
259258 * @return The content type.
260259 */
260 @Override
261261 public String getContentType() {
262262 return "text/xml; charset=" + this.getCharset();
263263 }
291291 * @return an XML Layout.
292292 */
293293 public static XmlLayout createDefaultLayout() {
294 return new XmlLayout(false, false, false, false, Charsets.UTF_8);
294 return new XmlLayout(false, false, false, false, StandardCharsets.UTF_8);
295295 }
296296 }
3737 /** Constant for the prefix separator. */
3838 private static final char PREFIX_SEPARATOR = ':';
3939
40 private final Map<String, StrLookup> lookups = new HashMap<String, StrLookup>();
40 private final Map<String, StrLookup> lookups = new HashMap<>();
4141
4242 private final StrLookup defaultLookup;
4343
8181 public Interpolator(final Map<String, String> properties) {
8282 this.defaultLookup = new MapLookup(properties == null ? new HashMap<String, String>() : properties);
8383 // TODO: this ought to use the PluginManager
84 lookups.put("log4j", new Log4jLookup());
8485 lookups.put("sys", new SystemPropertiesLookup());
8586 lookups.put("env", new EnvironmentLookup());
86 lookups.put("main", MapLookup.MAIN_SINGLETON);
87 lookups.put("main", MainMapLookup.MAIN_SINGLETON);
88 lookups.put("marker", new MarkerLookup());
8789 lookups.put("java", new JavaLookup());
8890 // JNDI
8991 try {
9898 */
9999 @Override
100100 public String lookup(final LogEvent event, final String key) {
101 // TODO Use a Java 7 switch
102 if ("version".equals(key)) {
101 switch (key) {
102 case "version":
103103 return "Java version " + getSystemProperty("java.version");
104 } else if ("runtime".equals(key)) {
104 case "runtime":
105105 return getRuntime();
106 } else if ("vm".equals(key)) {
106 case "vm":
107107 return getVirtualMachine();
108 } else if ("os".equals(key)) {
108 case "os":
109109 return getOperatingSystem();
110 } else if ("hw".equals(key)) {
110 case "hw":
111111 return getHardware();
112 } else if ("locale".equals(key)) {
112 case "locale":
113113 return getLocale();
114 default:
115 throw new IllegalArgumentException(key);
114116 }
115 throw new IllegalArgumentException(key);
116117 }
117118 }
0 /*
1 * Copyright 2015 Apache Software Foundation.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 package org.apache.logging.log4j.core.lookup;
16
17 import java.net.URI;
18 import java.net.URISyntaxException;
19
20 import org.apache.logging.log4j.core.LogEvent;
21 import org.apache.logging.log4j.core.LoggerContext;
22 import org.apache.logging.log4j.core.config.plugins.Plugin;
23 import org.apache.logging.log4j.core.impl.ContextAnchor;
24 import org.apache.logging.log4j.status.StatusLogger;
25
26 /**
27 * Lookup properties of Log4j
28 */
29 @Plugin(name = "log4j", category = StrLookup.CATEGORY)
30 public class Log4jLookup extends AbstractLookup {
31
32 public final static String KEY_CONFIG_LOCATION = "configLocation";
33 public final static String KEY_CONFIG_PARENT_LOCATION = "configParentLocation";
34
35 private static final org.apache.logging.log4j.Logger LOGGER = StatusLogger.getLogger();
36
37 private static String asPath(final URI uri) {
38 if (uri.getScheme() == null || uri.getScheme().equals("file")) {
39 return uri.getPath();
40 }
41 return uri.toString();
42 }
43
44 private static URI getParent(final URI uri) throws URISyntaxException {
45 final String s = uri.toString();
46 final int offset = s.lastIndexOf('/');
47 if (offset > -1) {
48 return new URI(s.substring(0, offset));
49 }
50 return new URI("../");
51 }
52
53 @Override
54 public String lookup(final LogEvent event, final String key) {
55 final LoggerContext ctx = ContextAnchor.THREAD_CONTEXT.get();
56 if (ctx == null) {
57 return null;
58 }
59
60 switch (key) {
61 case KEY_CONFIG_LOCATION:
62 return asPath(ctx.getConfigLocation());
63
64 case KEY_CONFIG_PARENT_LOCATION:
65 try {
66 return asPath(getParent(ctx.getConfigLocation()));
67 } catch (final URISyntaxException use) {
68 LOGGER.error(use);
69 return null;
70 }
71
72 default:
73 return null;
74 }
75 }
76 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.lookup;
17
18 import java.util.Map;
19
20 import org.apache.logging.log4j.core.LogEvent;
21 import org.apache.logging.log4j.core.config.plugins.Plugin;
22
23 /**
24 * A map-based lookup for main arguments.
25 *
26 * See {@link #setMainArguments(String[])}.
27 *
28 * @since 2.4
29 */
30 @Plugin(name = "main", category = StrLookup.CATEGORY)
31 public class MainMapLookup extends MapLookup {
32
33 /**
34 * A singleton used by a main method to save its arguments.
35 */
36 static final MapLookup MAIN_SINGLETON = new MapLookup(MapLookup.newMap(0));
37
38 /**
39 * An application's {@code public static main(String[])} method calls this method to make its main arguments
40 * available for lookup with the prefix {@code main}.
41 * <p>
42 * The map provides two kinds of access: First by index, starting at {@code "0"}, {@code "1"} and so on. For
43 * example, the command line {@code --file path/file.txt -x 2} can be accessed from a configuration file with:
44 * </p>
45 * <ul>
46 * <li>{@code "main:0"} = {@code "--file"}</li>
47 * <li>{@code "main:1"} = {@code "path/file.txt"}</li>
48 * <li>{@code "main:2"} = {@code "-x"}</li>
49 * <li>{@code "main:3"} = {@code "2"}</li>
50 * </ul>
51 * <p>
52 * Second using the argument at position n as the key to access the value at n+1.
53 * </p>
54 * <ul>
55 * <li>{@code "main:--file"} = {@code "path/file.txt"}</li>
56 * <li>{@code "main:-x"} = {@code "2"}</li>
57 * </ul>
58 *
59 * @param args
60 * An application's {@code public static main(String[])} arguments.
61 */
62 public static void setMainArguments(final String... args) {
63 if (args == null) {
64 return;
65 }
66 initMap(args, MainMapLookup.MAIN_SINGLETON.getMap());
67 }
68
69 /**
70 * Constructor when used directly as a plugin.
71 */
72 public MainMapLookup() {
73 // no-init
74 }
75
76 public MainMapLookup(final Map<String, String> map) {
77 super(map);
78 }
79
80 @Override
81 public String lookup(final LogEvent event, final String key) {
82 return MAIN_SINGLETON.getMap().get(key);
83 }
84
85 @Override
86 public String lookup(final String key) {
87 return MAIN_SINGLETON.getMap().get(key);
88 }
89
90 }
2929 @Plugin(name = "map", category = StrLookup.CATEGORY)
3030 public class MapLookup implements StrLookup {
3131
32 /**
33 * A singleton used by a main method to save its arguments.
34 */
35 static final MapLookup MAIN_SINGLETON = new MapLookup(newMap(0));
36
3732 static Map<String, String> initMap(final String[] srcArgs, final Map<String, String> destMap) {
3833 for (int i = 0; i < srcArgs.length; i++) {
3934 final int next = i + 1;
4439 return destMap;
4540 }
4641
47 private static HashMap<String, String> newMap(final int initialCapacity) {
48 return new HashMap<String, String>(initialCapacity);
42 static HashMap<String, String> newMap(final int initialCapacity) {
43 return new HashMap<>(initialCapacity);
4944 }
5045
5146 /**
7267 * @param args
7368 * An application's {@code public static main(String[])} arguments.
7469 * @since 2.1
70 * @deprecated As of 2.4, use {@link MainMapLookup#setMainArguments(String[])}
7571 */
76 public static void setMainArguments(final String[] args) {
77 if (args == null) {
78 return;
79 }
80 initMap(args, MAIN_SINGLETON.map);
72 @Deprecated
73 public static void setMainArguments(final String... args) {
74 MainMapLookup.setMainArguments(args);
8175 }
8276
8377 static Map<String, String> toMap(final List<String> args) {
117111 this.map = map;
118112 }
119113
114 protected Map<String, String> getMap() {
115 return map;
116 }
117
120118 @Override
121119 public String lookup(final LogEvent event, final String key) {
122 if (map == null && !(event.getMessage() instanceof MapMessage)) {
120 final boolean isMapMessage = event.getMessage() instanceof MapMessage;
121 if (map == null && !isMapMessage) {
123122 return null;
124123 }
125124 if (map != null && map.containsKey(key)) {
128127 return obj;
129128 }
130129 }
131 if (event.getMessage() instanceof MapMessage) {
130 if (isMapMessage) {
132131 return ((MapMessage) event.getMessage()).get(key);
133132 }
134133 return null;
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.lookup;
18
19 import org.apache.logging.log4j.Marker;
20 import org.apache.logging.log4j.MarkerManager;
21 import org.apache.logging.log4j.core.LogEvent;
22 import org.apache.logging.log4j.core.config.plugins.Plugin;
23
24 /**
25 * Looks-up markers.
26 *
27 * @since 2.4
28 */
29 @Plugin(name = "marker", category = StrLookup.CATEGORY)
30 public class MarkerLookup extends AbstractLookup {
31
32 static final String MARKER = "marker";
33
34 @Override
35 public String lookup(final LogEvent event, final String key) {
36 final Marker marker = event == null ? null : event.getMarker();
37 return marker == null ? null : marker.getName();
38 }
39
40 @Override
41 public String lookup(final String key) {
42 return MarkerManager.exists(key) ? key : null;
43 }
44
45 }
1717
1818 import java.util.Arrays;
1919
20 import org.apache.logging.log4j.util.Chars;
2021 import org.apache.logging.log4j.util.Strings;
2122
2223 /**
3536 /**
3637 * Matches the tab character.
3738 */
38 private static final StrMatcher TAB_MATCHER = new CharMatcher('\t');
39 private static final StrMatcher TAB_MATCHER = new CharMatcher(Chars.TAB);
3940 /**
4041 * Matches the space character.
4142 */
42 private static final StrMatcher SPACE_MATCHER = new CharMatcher(' ');
43 private static final StrMatcher SPACE_MATCHER = new CharMatcher(Chars.SPACE);
4344 /**
4445 * Matches the same characters as StringTokenizer,
4546 * namely space, tab, newline, formfeed.
5253 /**
5354 * Matches the double quote character.
5455 */
55 private static final StrMatcher SINGLE_QUOTE_MATCHER = new CharMatcher('\'');
56 private static final StrMatcher SINGLE_QUOTE_MATCHER = new CharMatcher(Chars.QUOTE);
5657 /**
5758 * Matches the double quote character.
5859 */
59 private static final StrMatcher DOUBLE_QUOTE_MATCHER = new CharMatcher('"');
60 private static final StrMatcher DOUBLE_QUOTE_MATCHER = new CharMatcher(Chars.DQUOTE);
6061 /**
6162 * Matches the single or double quote character.
6263 */
367368 }
368369 return len;
369370 }
371
372 @Override
373 public String toString() {
374 return super.toString() + Chars.SPACE + Arrays.toString(chars);
375 }
376
370377 }
371378
372379 //-----------------------------------------------------------------------
363363 if (valueProperties == null) {
364364 return source.toString();
365365 }
366 final Map<String, String> valueMap = new HashMap<String, String>();
366 final Map<String, String> valueMap = new HashMap<>();
367367 final Enumeration<?> propNames = valueProperties.propertyNames();
368368 while (propNames.hasMoreElements()) {
369369 final String propName = (String) propNames.nextElement();
867867 final StrMatcher valueDelimiterMatcher = getValueDelimiterMatcher();
868868 final boolean substitutionInVariablesEnabled = isEnableSubstitutionInVariables();
869869
870 final boolean top = (priorVariables == null);
870 final boolean top = priorVariables == null;
871871 boolean altered = false;
872872 int lengthChange = 0;
873873 char[] chars = getChars(buf);
943943
944944 // on the first call initialize priorVariables
945945 if (priorVariables == null) {
946 priorVariables = new ArrayList<String>();
946 priorVariables = new ArrayList<>();
947947 priorVariables.add(new String(chars,
948948 offset, length + lengthChange));
949949 }
978978 priorVariables
979979 .remove(priorVariables.size() - 1);
980980 break;
981 } else {
982 nestedVarCount--;
983 pos += endMatchLen;
984981 }
982 nestedVarCount--;
983 pos += endMatchLen;
985984 }
986985 }
987986 }
5252 * @param host The target host name.
5353 * @param port The target port number.
5454 */
55 public AbstractSocketManager(final String name, final OutputStream os, final InetAddress inetAddress, final String host,
56 final int port, final Layout<? extends Serializable> layout) {
57 super(os, name, layout);
55 public AbstractSocketManager(final String name, final OutputStream os, final InetAddress inetAddress,
56 final String host, final int port, final Layout<? extends Serializable> layout, final boolean writeHeader) {
57 super(os, name, layout, writeHeader);
5858 this.inetAddress = inetAddress;
5959 this.host = host;
6060 this.port = port;
7171 */
7272 @Override
7373 public Map<String, String> getContentFormat() {
74 final Map<String, String> result = new HashMap<String, String>(super.getContentFormat());
74 final Map<String, String> result = new HashMap<>(super.getContentFormat());
7575 result.put("port", Integer.toString(port));
7676 result.put("address", inetAddress.getHostAddress());
7777 return result;
4444 */
4545 protected DatagramSocketManager(final String name, final OutputStream os, final InetAddress inetAddress, final String host,
4646 final int port, final Layout<? extends Serializable> layout) {
47 super(name, os, inetAddress, host, port, layout);
47 super(name, os, inetAddress, host, port, layout, true);
4848 }
4949
5050 /**
7676 */
7777 @Override
7878 public Map<String, String> getContentFormat() {
79 final Map<String, String> result = new HashMap<String, String>(super.getContentFormat());
79 final Map<String, String> result = new HashMap<>(super.getContentFormat());
8080 result.put("protocol", "udp");
8181 result.put("direction", "out");
8282 return result;
1515 */
1616 package org.apache.logging.log4j.core.net;
1717
18 import java.nio.charset.StandardCharsets;
19
1820 import javax.mail.Message;
1921 import javax.mail.MessagingException;
2022 import javax.mail.Session;
2123 import javax.mail.internet.AddressException;
2224 import javax.mail.internet.InternetAddress;
2325 import javax.mail.internet.MimeMessage;
24
25 import org.apache.logging.log4j.core.util.Charsets;
2626
2727 /**
2828 * Helper class for SmtpManager.
7070
7171 public MimeMessageBuilder setSubject(final String subject) throws MessagingException {
7272 if (subject != null) {
73 message.setSubject(subject, Charsets.UTF_8.name());
73 message.setSubject(subject, StandardCharsets.UTF_8.name());
7474 }
7575 return this;
7676 }
6262 @Override
6363 public Object advertise(final Map<String, String> properties) {
6464 //default to tcp if "protocol" was not set
65 final Map<String, String> truncatedProperties = new HashMap<String, String>();
65 final Map<String, String> truncatedProperties = new HashMap<>();
6666 for (final Map.Entry<String, String> entry:properties.entrySet())
6767 {
6868 if (entry.getKey().length() <= 255 && entry.getValue().length() <= 255)
169169 final Map<String, String> properties) {
170170 //version 1 uses a hashtable
171171 @SuppressWarnings("UseOfObsoleteCollectionType")
172 final Hashtable<String, String> hashtableProperties = new Hashtable<String, String>(properties);
172 final Hashtable<String, String> hashtableProperties = new Hashtable<>(properties);
173173 try {
174174 return serviceInfoClass
175175 .getConstructor(String.class, String.class, int.class, int.class, int.class, Hashtable.class)
4242 * @return The integer value of the priority.
4343 */
4444 public static int getPriority(final Facility facility, final Level level) {
45 return (facility.getCode() << 3) + Severity.getSeverity(level).getCode();
45 return toPriority(facility, Severity.getSeverity(level));
4646 }
4747
48 private static int toPriority(final Facility aFacility, final Severity aSeverity) {
49 return (aFacility.getCode() << 3) + aSeverity.getCode();
50 }
51
4852 /**
4953 * Returns the Facility.
5054 * @return the Facility.
6670 * @return the value of this Priority.
6771 */
6872 public int getValue() {
69 return facility.getCode() << 3 + severity.getCode();
73 return toPriority(facility, severity);
7074 }
7175
7276 @Override
6666 this.session = session;
6767 this.message = message;
6868 this.data = data;
69 this.buffer = new CyclicBuffer<LogEvent>(LogEvent.class, data.numElements);
69 this.buffer = new CyclicBuffer<>(LogEvent.class, data.numElements);
7070 }
7171
7272 public void add(final LogEvent event) {
212212 }
213213
214214 protected void encodeContent(final byte[] bytes, final String encoding, final ByteArrayOutputStream out)
215 throws MessagingException, IOException {
216 final OutputStream encoder = MimeUtility.encode(out, encoding);
217 encoder.write(bytes);
218 encoder.close();
215 throws MessagingException, IOException {
216 try (final OutputStream encoder = MimeUtility.encode(out, encoding)) {
217 encoder.write(bytes);
218 }
219219 }
220220
221221 protected InternetHeaders getHeaders(final String contentType, final String encoding) {
5757 */
5858 public SslSocketManager(final String name, final OutputStream os, final Socket sock,
5959 final SslConfiguration sslConfig, final InetAddress inetAddress, final String host, final int port,
60 int connectTimeoutMillis, final int delay, final boolean immediateFail,
60 final int connectTimeoutMillis, final int delay, final boolean immediateFail,
6161 final Layout<? extends Serializable> layout) {
6262 super(name, os, sock, inetAddress, host, port, connectTimeoutMillis, delay, immediateFail, layout);
6363 this.sslConfig = sslConfig;
7373 private final Layout<? extends Serializable> layout;
7474
7575 public SslFactoryData(final SslConfiguration sslConfig, final String host, final int port,
76 int connectTimeoutMillis, final int delayMillis, final boolean immediateFail,
76 final int connectTimeoutMillis, final int delayMillis, final boolean immediateFail,
7777 final Layout<? extends Serializable> layout) {
7878 this.host = host;
7979 this.port = port;
8686 }
8787
8888 public static SslSocketManager getSocketManager(final SslConfiguration sslConfig, final String host, int port,
89 int connectTimeoutMillis, int delayMillis, final boolean immediateFail,
89 final int connectTimeoutMillis, int delayMillis, final boolean immediateFail,
9090 final Layout<? extends Serializable> layout) {
9191 if (Strings.isEmpty(host)) {
9292 throw new IllegalArgumentException("A host name is required");
7575 * @param layout The Layout.
7676 */
7777 public TcpSocketManager(final String name, final OutputStream os, final Socket sock, final InetAddress inetAddress,
78 final String host, final int port, int connectTimeoutMillis, final int delay,
78 final String host, final int port, final int connectTimeoutMillis, final int delay,
7979 final boolean immediateFail, final Layout<? extends Serializable> layout) {
80 super(name, os, inetAddress, host, port, layout);
80 super(name, os, inetAddress, host, port, layout, true);
8181 this.connectTimeoutMillis = connectTimeoutMillis;
8282 this.reconnectionDelay = delay;
8383 this.socket = sock;
9999 * @param delayMillis The interval to pause between retries.
100100 * @return A TcpSocketManager.
101101 */
102 public static TcpSocketManager getSocketManager(final String host, int port, int connectTimeoutMillis,
102 public static TcpSocketManager getSocketManager(final String host, int port, final int connectTimeoutMillis,
103103 int delayMillis, final boolean immediateFail, final Layout<? extends Serializable> layout) {
104104 if (Strings.isEmpty(host)) {
105105 throw new IllegalArgumentException("A host name is required");
166166 */
167167 @Override
168168 public Map<String, String> getContentFormat() {
169 final Map<String, String> result = new HashMap<String, String>(super.getContentFormat());
169 final Map<String, String> result = new HashMap<>(super.getContentFormat());
170170 result.put("protocol", "tcp");
171171 result.put("direction", "out");
172172 return result;
254254 private final boolean immediateFail;
255255 private final Layout<? extends Serializable> layout;
256256
257 public FactoryData(final String host, final int port, int connectTimeoutMillis, final int delayMillis,
257 public FactoryData(final String host, final int port, final int connectTimeoutMillis, final int delayMillis,
258258 final boolean immediateFail, final Layout<? extends Serializable> layout) {
259259 this.host = host;
260260 this.port = port;
281281 return null;
282282 }
283283 try {
284 final Socket socket = new Socket(data.host, data.port);
284 // LOG4J2-1042
285 final Socket socket = new Socket();
286 socket.connect(new InetSocketAddress(data.host, data.port), data.connectTimeoutMillis);
285287 os = socket.getOutputStream();
286288 return new TcpSocketManager(name, os, socket, inetAddress, data.host, data.port,
287289 data.connectTimeoutMillis, data.delayMillis, data.immediateFail, data.layout);
2323 import java.net.MalformedURLException;
2424 import java.net.URI;
2525 import java.net.URL;
26 import java.util.Objects;
2627
2728 import org.apache.logging.log4j.LogManager;
2829 import org.apache.logging.log4j.Logger;
3132 import org.apache.logging.log4j.core.config.ConfigurationSource;
3233 import org.apache.logging.log4j.core.config.xml.XmlConfiguration;
3334 import org.apache.logging.log4j.core.config.xml.XmlConfigurationFactory;
34 import org.apache.logging.log4j.core.util.Assert;
35 import org.apache.logging.log4j.util.Strings;
3536
3637 /**
3738 * Abstract socket server for TCP and UDP implementations.
5556
5657 @Override
5758 public Configuration getConfiguration(final String name, final URI configLocation) {
58 if (path != null && path.length() > 0) {
59 if (Strings.isNotEmpty(path)) {
5960 File file = null;
6061 ConfigurationSource source = null;
6162 try {
105106 */
106107 public AbstractSocketServer(final int port, final LogEventBridge<T> logEventInput) {
107108 this.logger = LogManager.getLogger(this.getClass().getName() + '.' + port);
108 this.logEventInput = Assert.requireNonNull(logEventInput, "LogEventInput");
109 this.logEventInput = Objects.requireNonNull(logEventInput, "LogEventInput");
109110 }
110111
111112 protected boolean isActive() {
4040 public class JmsServer extends LogEventListener implements MessageListener, LifeCycle {
4141
4242 private static final Logger LOGGER = StatusLogger.getLogger();
43 private final AtomicReference<State> state = new AtomicReference<State>(State.INITIALIZED);
43 private final AtomicReference<State> state = new AtomicReference<>(State.INITIALIZED);
4444 private final JmsManager jmsManager;
4545 private MessageConsumer messageConsumer;
4646
7979 }
8080
8181 @Override
82 public void initialize() {
83 }
84
85 @Override
8286 public void start() {
8387 if (state.compareAndSet(State.INITIALIZED, State.STARTING)) {
8488 try {
2020
2121 import org.apache.logging.log4j.core.LogEvent;
2222 import org.apache.logging.log4j.core.jackson.Log4jJsonObjectMapper;
23 import org.apache.logging.log4j.util.Chars;
2324
2425 /**
2526 * Reads and logs JSON {@link LogEvent}s from an {@link InputStream}..
3031 private static final char EVENT_END_MARKER = '}';
3132 private static final char EVENT_START_MARKER = '{';
3233 private static final char JSON_ESC = '\\';
33 private static final char JSON_STR_DELIM = '"';
34 private static final char JSON_STR_DELIM = Chars.DQUOTE;
3435
3536 public JsonInputStreamLogEventBridge() {
3637 this(1024, Charset.defaultCharset());
5354 boolean inEsc = false;
5455 for (int i = start; i < charArray.length; i++) {
5556 final char c = charArray[i];
56 if (!inEsc) {
57 inEsc = false;
57 if (inEsc) {
58 // Skip this char and continue
59 inEsc = false;
60 } else {
5861 switch (c) {
5962 case EVENT_START_MARKER:
6063 if (!inStr) {
9595 * if an I/O error occurs when opening the socket.
9696 */
9797 public static TcpSocketServer<InputStream> createJsonSocketServer(final int port) throws IOException {
98 return new TcpSocketServer<InputStream>(port, new JsonInputStreamLogEventBridge());
98 return new TcpSocketServer<>(port, new JsonInputStreamLogEventBridge());
9999 }
100100
101101 /**
108108 * if an I/O error occurs when opening the socket.
109109 */
110110 public static TcpSocketServer<ObjectInputStream> createSerializedSocketServer(final int port) throws IOException {
111 return new TcpSocketServer<ObjectInputStream>(port, new ObjectInputStreamLogEventBridge());
111 return new TcpSocketServer<>(port, new ObjectInputStreamLogEventBridge());
112112 }
113113
114114 /**
121121 * if an I/O error occurs when opening the socket.
122122 */
123123 public static TcpSocketServer<InputStream> createXmlSocketServer(final int port) throws IOException {
124 return new TcpSocketServer<InputStream>(port, new XmlInputStreamLogEventBridge());
124 return new TcpSocketServer<>(port, new XmlInputStreamLogEventBridge());
125125 }
126126
127127 /**
167167 System.out.println("Usage: ServerSocket port configFilePath");
168168 }
169169
170 private final ConcurrentMap<Long, SocketHandler> handlers = new ConcurrentHashMap<Long, SocketHandler>();
170 private final ConcurrentMap<Long, SocketHandler> handlers = new ConcurrentHashMap<>();
171171
172172 private final ServerSocket serverSocket;
173173
4646 * if an I/O error occurs when opening the socket.
4747 */
4848 public static UdpSocketServer<InputStream> createJsonSocketServer(final int port) throws IOException {
49 return new UdpSocketServer<InputStream>(port, new JsonInputStreamLogEventBridge());
49 return new UdpSocketServer<>(port, new JsonInputStreamLogEventBridge());
5050 }
5151
5252 /**
5959 * if an I/O error occurs when opening the socket.
6060 */
6161 public static UdpSocketServer<ObjectInputStream> createSerializedSocketServer(final int port) throws IOException {
62 return new UdpSocketServer<ObjectInputStream>(port, new ObjectInputStreamLogEventBridge());
62 return new UdpSocketServer<>(port, new ObjectInputStreamLogEventBridge());
6363 }
6464
6565 /**
7272 * if an I/O error occurs when opening the socket.
7373 */
7474 public static UdpSocketServer<InputStream> createXmlSocketServer(final int port) throws IOException {
75 return new UdpSocketServer<InputStream>(port, new XmlInputStreamLogEventBridge());
75 return new UdpSocketServer<>(port, new XmlInputStreamLogEventBridge());
7676 }
7777
7878 /**
3939
4040 @Override
4141 protected KeyStore load() throws StoreConfigurationException {
42 FileInputStream fin = null;
43
4442 LOGGER.debug("Loading keystore from file with params(location={})", this.getLocation());
4543 try {
4644 if (this.getLocation() == null) {
4745 throw new IOException("The location is null");
4846 }
49 fin = new FileInputStream(this.getLocation());
50 final KeyStore ks = KeyStore.getInstance(this.keyStoreType);
51 ks.load(fin, this.getPasswordAsCharArray());
52 LOGGER.debug("Keystore successfully loaded with params(location={})", this.getLocation());
53 return ks;
47 try (final FileInputStream fin = new FileInputStream(this.getLocation())) {
48 final KeyStore ks = KeyStore.getInstance(this.keyStoreType);
49 ks.load(fin, this.getPasswordAsCharArray());
50 LOGGER.debug("Keystore successfully loaded with params(location={})", this.getLocation());
51 return ks;
52 }
5453 } catch (final CertificateException e) {
5554 LOGGER.error("No Provider supports a KeyStoreSpi implementation for the specified type {}", this.keyStoreType);
5655 throw new StoreConfigurationException(e);
6665 } catch (final IOException e) {
6766 LOGGER.error("Something is wrong with the format of the keystore or the given password");
6867 throw new StoreConfigurationException(e);
69 } finally {
70 try {
71 if (fin != null) {
72 fin.close();
73 }
74 } catch (final IOException e) {
75 LOGGER.debug(e);
76 }
7768 }
7869 }
7970
5050 * @param keyStoreType
5151 * The KeyStore type, null defaults to {@code "JKS"}.
5252 * @param keyManagerFactoryAlgorithm
53 * TODO
53 * The standard name of the requested algorithm. See the Java Secure Socket Extension Reference Guide for information about these names.
5454 * @return a new KeyStoreConfiguration
5555 * @throws StoreConfigurationException
5656 */
6262 @PluginAttribute("type") final String keyStoreType,
6363 @PluginAttribute("keyManagerFactoryAlgorithm") final String keyManagerFactoryAlgorithm) throws StoreConfigurationException {
6464 // @formatter:on
65 return new KeyStoreConfiguration(location, password, keyStoreType, null);
65 return new KeyStoreConfiguration(location, password, keyStoreType, keyManagerFactoryAlgorithm);
6666 }
6767
6868 public KeyManagerFactory initKeyManagerFactory() throws NoSuchAlgorithmException, UnrecoverableKeyException,
4949 * @param keyStoreType
5050 * The KeyStore type, null defaults to {@code "JKS"}.
5151 * @param trustManagerFactoryAlgorithm
52 * TODO
52 * The standard name of the requested trust management algorithm. See the Java Secure Socket Extension Reference Guide for information these names.
5353 * @return a new TrustStoreConfiguration
5454 * @throws StoreConfigurationException
5555 */
3737
3838 private static final Logger LOGGER = StatusLogger.getLogger();
3939
40 private final AtomicReference<BundleContext> context = new AtomicReference<BundleContext>();
40 private final AtomicReference<BundleContext> context = new AtomicReference<>();
4141
4242 @Override
4343 public void start(final BundleContext context) throws Exception {
1717
1818 import java.lang.ref.WeakReference;
1919 import java.net.URI;
20 import java.util.Objects;
2021 import java.util.concurrent.atomic.AtomicReference;
2122
2223 import org.apache.logging.log4j.core.LoggerContext;
2324 import org.apache.logging.log4j.core.impl.ContextAnchor;
2425 import org.apache.logging.log4j.core.selector.ClassLoaderContextSelector;
25 import org.apache.logging.log4j.core.selector.ContextSelector;
26 import org.apache.logging.log4j.core.util.Assert;
2726 import org.apache.logging.log4j.util.ReflectionUtil;
2827 import org.osgi.framework.Bundle;
2928 import org.osgi.framework.BundleReference;
3635 *
3736 * @since 2.1
3837 */
39 public class BundleContextSelector extends ClassLoaderContextSelector implements ContextSelector {
38 public class BundleContextSelector extends ClassLoaderContextSelector {
4039
4140 @Override
4241 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final boolean currentContext,
6160 }
6261
6362 private static LoggerContext locateContext(final Bundle bundle, final URI configLocation) {
64 final String name = Assert.requireNonNull(bundle, "No Bundle provided").getSymbolicName();
63 final String name = Objects.requireNonNull(bundle, "No Bundle provided").getSymbolicName();
6564 final AtomicReference<WeakReference<LoggerContext>> ref = CONTEXT_MAP.get(name);
6665 if (ref == null) {
6766 final LoggerContext context = new LoggerContext(name, bundle, configLocation);
6867 CONTEXT_MAP.putIfAbsent(name,
69 new AtomicReference<WeakReference<LoggerContext>>(new WeakReference<LoggerContext>(context)));
68 new AtomicReference<>(new WeakReference<>(context)));
7069 return CONTEXT_MAP.get(name).get().get();
7170 }
7271 final WeakReference<LoggerContext> r = ref.get();
7372 final LoggerContext ctx = r.get();
7473 if (ctx == null) {
7574 final LoggerContext context = new LoggerContext(name, bundle, configLocation);
76 ref.compareAndSet(r, new WeakReference<LoggerContext>(context));
75 ref.compareAndSet(r, new WeakReference<>(context));
7776 return ref.get().get();
7877 }
7978 final URI oldConfigLocation = ctx.getConfigLocation();
288288 public static Map<String, String> createMap(final String[] values, final String[] dontEscapeKeys) {
289289 final String[] sortedIgnoreKeys = dontEscapeKeys != null ? dontEscapeKeys.clone() : new String[0];
290290 Arrays.sort(sortedIgnoreKeys);
291 final Map<String, String> map = new HashMap<String, String>();
291 final Map<String, String> map = new HashMap<>();
292292 for (final String string : values) {
293293 final String[] keyValue = string.split(Patterns.toWhitespaceSeparator("="));
294294 if (keyValue.length > 1) {
1515 */
1616 package org.apache.logging.log4j.core.pattern;
1717
18 import java.text.SimpleDateFormat;
1918 import java.util.Date;
19 import java.util.Objects;
2020 import java.util.TimeZone;
21 import java.util.concurrent.atomic.AtomicReference;
2122
2223 import org.apache.logging.log4j.core.LogEvent;
2324 import org.apache.logging.log4j.core.config.plugins.Plugin;
25 import org.apache.logging.log4j.core.util.datetime.FastDateFormat;
26 import org.apache.logging.log4j.core.util.datetime.FixedDateFormat;
27 import org.apache.logging.log4j.core.util.datetime.FixedDateFormat.FixedFormat;
2428
2529 /**
26 * Convert and format the event's date in a StringBuilder.
30 * Converts and formats the event's date in a StringBuilder.
2731 */
2832 @Plugin(name = "DatePatternConverter", category = PatternConverter.CATEGORY)
2933 @ConverterKeys({ "d", "date" })
3034 public final class DatePatternConverter extends LogEventPatternConverter implements ArrayPatternConverter {
3135
36 private final class CachedTime {
37 public long timestampMillis;
38 public String formatted;
39
40 public CachedTime(final long timestampMillis) {
41 this.timestampMillis = timestampMillis;
42 this.formatted = formatter.format(this.timestampMillis);
43 }
44 }
45
46 private final AtomicReference<CachedTime> cachedTime;
47
3248 private abstract static class Formatter {
33 abstract String format(long time);
49 abstract String format(long timeMillis);
3450
3551 public String toPattern() {
3652 return null;
3753 }
3854 }
3955
40 private static class PatternFormatter extends Formatter {
41 private final SimpleDateFormat simpleDateFormat;
42
43 PatternFormatter(final SimpleDateFormat simpleDateFormat) {
44 this.simpleDateFormat = simpleDateFormat;
45 }
46
47 @Override
48 String format(final long time) {
49 return simpleDateFormat.format(Long.valueOf(time));
56 private static final class PatternFormatter extends Formatter {
57 private final FastDateFormat fastDateFormat;
58
59 PatternFormatter(final FastDateFormat fastDateFormat) {
60 this.fastDateFormat = fastDateFormat;
61 }
62
63 @Override
64 String format(final long timeMillis) {
65 return fastDateFormat.format(timeMillis);
5066 }
5167
5268 @Override
5369 public String toPattern() {
54 return simpleDateFormat.toPattern();
55 }
56 }
57
58 private static class UnixFormatter extends Formatter {
59
60 @Override
61 String format(final long time) {
62 return Long.toString(time / 1000);
63 }
64
65 }
66
67 private static class UnixMillisFormatter extends Formatter {
68
69 @Override
70 String format(final long time) {
71 return Long.toString(time);
72 }
73
74 }
75
76 /**
77 * ABSOLUTE string literal.
78 */
79 private static final String ABSOLUTE_FORMAT = "ABSOLUTE";
80
81 /**
82 * SimpleTimePattern for ABSOLUTE.
83 */
84 private static final String ABSOLUTE_TIME_PATTERN = "HH:mm:ss,SSS";
85
86 /**
87 * COMPACT string literal.
88 */
89 private static final String COMPACT_FORMAT = "COMPACT";
90
91 /**
92 * SimpleTimePattern for COMPACT.
93 */
94 private static final String COMPACT_PATTERN = "yyyyMMddHHmmssSSS";
95
96 /**
97 * DATE string literal.
98 */
99 private static final String DATE_AND_TIME_FORMAT = "DATE";
100
101 /**
102 * SimpleTimePattern for DATE.
103 */
104 private static final String DATE_AND_TIME_PATTERN = "dd MMM yyyy HH:mm:ss,SSS";
105
106 /**
107 * DEFAULT string literal.
108 */
109 private static final String DEFAULT_FORMAT = "DEFAULT";
110
111 /**
112 * SimpleTimePattern for DEFAULT.
113 */
114 // package private for unit tests
115 static final String DEFAULT_PATTERN = "yyyy-MM-dd HH:mm:ss,SSS";
116
117 /**
118 * ISO8601_BASIC string literal.
119 */
120 private static final String ISO8601_BASIC_FORMAT = "ISO8601_BASIC";
121
122 /**
123 * SimpleTimePattern for ISO8601_BASIC.
124 */
125 private static final String ISO8601_BASIC_PATTERN = "yyyyMMdd'T'HHmmss,SSS";
126
127 /**
128 * ISO8601 string literal.
129 */
130 // package private for unit tests
131 static final String ISO8601_FORMAT = "ISO8601";
132
133 /**
134 * SimpleTimePattern for ISO8601.
135 */
136 // package private for unit tests
137 static final String ISO8601_PATTERN = "yyyy-MM-dd'T'HH:mm:ss,SSS";
70 return fastDateFormat.toPattern();
71 }
72 }
73
74 private static final class FixedFormatter extends Formatter {
75 private final FixedDateFormat fixedDateFormat;
76
77 FixedFormatter(final FixedDateFormat fixedDateFormat) {
78 this.fixedDateFormat = fixedDateFormat;
79 }
80
81 @Override
82 String format(final long timeMillis) {
83 return fixedDateFormat.format(timeMillis);
84 }
85
86 @Override
87 public String toPattern() {
88 return fixedDateFormat.getFormat();
89 }
90 }
91
92 private static final class UnixFormatter extends Formatter {
93
94 @Override
95 String format(final long timeMillis) {
96 return Long.toString(timeMillis / 1000);
97 }
98 }
99
100 private static final class UnixMillisFormatter extends Formatter {
101
102 @Override
103 String format(final long timeMillis) {
104 return Long.toString(timeMillis);
105 }
106 }
138107
139108 /**
140109 * UNIX formatter in seconds (standard).
157126 return new DatePatternConverter(options);
158127 }
159128
160 /**
161 * Date format.
162 */
163 private String cachedDateString;
164
165129 private final Formatter formatter;
166
167 private long lastTimestamp;
168130
169131 /**
170132 * Private constructor.
175137 private DatePatternConverter(final String[] options) {
176138 super("Date", "date");
177139
178 // null patternOption is OK.
179 final String patternOption = options != null && options.length > 0 ? options[0] : null;
180
181 String pattern = null;
182 Formatter tempFormatter = null;
183
184 if (patternOption == null || patternOption.equalsIgnoreCase(DEFAULT_FORMAT)) {
185 pattern = DEFAULT_PATTERN;
186 } else if (patternOption.equalsIgnoreCase(ISO8601_FORMAT)) {
187 pattern = ISO8601_PATTERN;
188 } else if (patternOption.equalsIgnoreCase(ISO8601_BASIC_FORMAT)) {
189 pattern = ISO8601_BASIC_PATTERN;
190 } else if (patternOption.equalsIgnoreCase(ABSOLUTE_FORMAT)) {
191 pattern = ABSOLUTE_TIME_PATTERN;
192 } else if (patternOption.equalsIgnoreCase(DATE_AND_TIME_FORMAT)) {
193 pattern = DATE_AND_TIME_PATTERN;
194 } else if (patternOption.equalsIgnoreCase(COMPACT_FORMAT)) {
195 pattern = COMPACT_PATTERN;
196 } else if (patternOption.equalsIgnoreCase(UNIX_FORMAT)) {
197 tempFormatter = new UnixFormatter();
198 } else if (patternOption.equalsIgnoreCase(UNIX_MILLIS_FORMAT)) {
199 tempFormatter = new UnixMillisFormatter();
140 final FixedDateFormat fixedDateFormat = FixedDateFormat.createIfSupported(options);
141 if (fixedDateFormat != null) {
142 formatter = createFormatter(fixedDateFormat);
200143 } else {
201 pattern = patternOption;
202 }
203
204 if (pattern != null) {
205 SimpleDateFormat tempFormat;
206
207 try {
208 tempFormat = new SimpleDateFormat(pattern);
209 } catch (final IllegalArgumentException e) {
210 LOGGER.warn("Could not instantiate SimpleDateFormat with pattern " + patternOption, e);
211
212 // default to the DEFAULT format
213 tempFormat = new SimpleDateFormat(DEFAULT_PATTERN);
214 }
215
216 // if the option list contains a TZ option, then set it.
217 if (options != null && options.length > 1) {
218 final TimeZone tz = TimeZone.getTimeZone(options[1]);
219 tempFormat.setTimeZone(tz);
220 }
221 tempFormatter = new PatternFormatter(tempFormat);
222 }
223 formatter = tempFormatter;
224 }
225
226 /**
227 * Append formatted date to string buffer.
144 formatter = createFormatter(options);
145 }
146 cachedTime = new AtomicReference<>(new CachedTime(System.currentTimeMillis()));
147 }
148
149 private static Formatter createFormatter(final FixedDateFormat fixedDateFormat) {
150 return new FixedFormatter(fixedDateFormat);
151 }
152
153 private static Formatter createFormatter(final String[] options) {
154 // if we get here, options is a non-null array with at least one element (first of which non-null)
155 Objects.requireNonNull(options);
156 if (options.length == 0) {
157 throw new IllegalArgumentException("options array must have at least one element");
158 }
159 Objects.requireNonNull(options[0]);
160 final String patternOption = options[0];
161 if (UNIX_FORMAT.equals(patternOption)) {
162 return new UnixFormatter();
163 }
164 if (UNIX_MILLIS_FORMAT.equals(patternOption)) {
165 return new UnixMillisFormatter();
166 }
167
168 // if the option list contains a TZ option, then set it.
169 TimeZone tz = null;
170 if (options != null && options.length > 1) {
171 tz = TimeZone.getTimeZone(options[1]);
172 }
173
174 try {
175 final FastDateFormat tempFormat = FastDateFormat.getInstance(patternOption, tz);
176 return new PatternFormatter(tempFormat);
177 } catch (final IllegalArgumentException e) {
178 LOGGER.warn("Could not instantiate FastDateFormat with pattern " + patternOption, e);
179
180 // default to the DEFAULT format
181 return createFormatter(FixedDateFormat.create(FixedFormat.DEFAULT));
182 }
183 }
184
185 /**
186 * Appends formatted date to string buffer.
228187 *
229188 * @param date
230189 * date
232191 * buffer to which formatted date is appended.
233192 */
234193 public void format(final Date date, final StringBuilder toAppendTo) {
235 synchronized (this) {
236 toAppendTo.append(formatter.format(date.getTime()));
237 }
194 format(date.getTime(), toAppendTo);
238195 }
239196
240197 /**
242199 */
243200 @Override
244201 public void format(final LogEvent event, final StringBuilder output) {
245 final long timestamp = event.getTimeMillis();
246
247 synchronized (this) {
248 if (timestamp != lastTimestamp) {
249 lastTimestamp = timestamp;
250 cachedDateString = formatter.format(timestamp);
202 format(event.getTimeMillis(), output);
203 }
204
205 public void format(final long timestampMillis, final StringBuilder output) {
206 CachedTime cached = cachedTime.get();
207 if (timestampMillis != cached.timestampMillis) {
208 final CachedTime newTime = new CachedTime(timestampMillis);
209 if (cachedTime.compareAndSet(cached, newTime)) {
210 cached = newTime;
211 } else {
212 cached = cachedTime.get();
251213 }
252214 }
253 output.append(cachedDateString);
215 output.append(cached.formatted);
254216 }
255217
256218 /**
2222 import org.apache.logging.log4j.core.util.Constants;
2323
2424 /**
25 * Outputs the Throwable portion of the LoggingEvent as a full stacktrace
25 * Outputs the Throwable portion of the LoggingEvent as a full stack trace
2626 * unless this converter's option is 'short', where it just outputs the first line of the trace, or if
2727 * the number of lines to print is explicitly specified.
2828 * <p>
6363 proxy = ((Log4jLogEvent) event).getThrownProxy();
6464 }
6565 final Throwable throwable = event.getThrown();
66 if (throwable != null && options.anyLines()) {
66 if ((throwable != null || proxy != null) && options.anyLines()) {
6767 if (proxy == null) {
6868 super.format(event, toAppendTo);
6969 return;
7070 }
71 final String trace = proxy.getExtendedStackTraceAsString(options.getPackages());
71 final String extStackTrace = proxy.getExtendedStackTraceAsString(options.getPackages());
7272 final int len = toAppendTo.length();
7373 if (len > 0 && !Character.isWhitespace(toAppendTo.charAt(len - 1))) {
7474 toAppendTo.append(' ');
7575 }
7676 if (!options.allLines() || !Constants.LINE_SEPARATOR.equals(options.getSeparator())) {
7777 final StringBuilder sb = new StringBuilder();
78 final String[] array = trace.split(Constants.LINE_SEPARATOR);
78 final String[] array = extStackTrace.split(Constants.LINE_SEPARATOR);
7979 final int limit = options.minLines(array.length) - 1;
8080 for (int i = 0; i <= limit; ++i) {
8181 sb.append(array[i]);
8686 toAppendTo.append(sb.toString());
8787
8888 } else {
89 toAppendTo.append(trace);
89 toAppendTo.append(extStackTrace);
9090 }
9191 }
9292 }
2828 /**
2929 * Default instance.
3030 */
31 private static final FormattingInfo DEFAULT = new FormattingInfo(false, 0, Integer.MAX_VALUE);
31 private static final FormattingInfo DEFAULT = new FormattingInfo(false, 0, Integer.MAX_VALUE, true);
3232
3333 /**
3434 * Minimum length.
4646 private final boolean leftAlign;
4747
4848 /**
49 * Left vs. right-hand side truncation.
50 */
51 private final boolean leftTruncate;
52
53 /**
4954 * Creates new instance.
5055 *
5156 * @param leftAlign
5560 * @param maxLength
5661 * maximum length.
5762 */
58 public FormattingInfo(final boolean leftAlign, final int minLength, final int maxLength) {
63 public FormattingInfo(final boolean leftAlign, final int minLength, final int maxLength, final boolean leftTruncate) {
5964 this.leftAlign = leftAlign;
6065 this.minLength = minLength;
6166 this.maxLength = maxLength;
67 this.leftTruncate = leftTruncate;
6268 }
6369
6470 /**
7884 public boolean isLeftAligned() {
7985 return leftAlign;
8086 }
87
88 /**
89 * Determine if left truncated.
90 *
91 * @return true if left truncated.
92 */
93 public boolean isLeftTruncate() {
94 return leftTruncate;
95 }
8196
8297 /**
8398 * Get minimum length.
109124 final int rawLength = buffer.length() - fieldStart;
110125
111126 if (rawLength > maxLength) {
112 buffer.delete(fieldStart, buffer.length() - maxLength);
127 if (leftTruncate) {
128 buffer.delete(fieldStart, buffer.length() - maxLength);
129 } else {
130 buffer.delete(fieldStart + maxLength, fieldStart + buffer.length());
131 }
113132 } else if (rawLength < minLength) {
114133 if (leftAlign) {
115134 final int fieldEnd = buffer.length();
145164 sb.append(maxLength);
146165 sb.append(", minLength=");
147166 sb.append(minLength);
167 sb.append(", leftTruncate=");
168 sb.append(leftTruncate);
148169 sb.append(']');
149170 return sb.toString();
150171 }
6969 @ConverterKeys({ "highlight" })
7070 public final class HighlightConverter extends LogEventPatternConverter implements AnsiConverter {
7171
72 private static final Map<Level, String> DEFAULT_STYLES = new HashMap<Level, String>();
73
74 private static final Map<Level, String> LOGBACK_STYLES = new HashMap<Level, String>();
72 private static final Map<Level, String> DEFAULT_STYLES = new HashMap<>();
73
74 private static final Map<Level, String> LOGBACK_STYLES = new HashMap<>();
7575
7676 private static final String STYLE_KEY = "STYLE";
7777
7979
8080 private static final String STYLE_KEY_LOGBACK = "LOGBACK";
8181
82 private static final Map<String, Map<Level, String>> STYLES = new HashMap<String, Map<Level, String>>();
82 private static final Map<String, Map<Level, String>> STYLES = new HashMap<>();
8383
8484 static {
8585 // Default styles:
137137 final String string = options[1].replaceAll(PatternParser.NO_CONSOLE_NO_ANSI + "=(true|false)", Strings.EMPTY);
138138 //
139139 final Map<String, String> styles = AnsiEscape.createMap(string, new String[] {STYLE_KEY});
140 final Map<Level, String> levelStyles = new HashMap<Level, String>(DEFAULT_STYLES);
140 final Map<Level, String> levelStyles = new HashMap<>(DEFAULT_STYLES);
141141 for (final Map.Entry<String, String> entry : styles.entrySet()) {
142142 final String key = entry.getKey().toUpperCase(Locale.ENGLISH);
143143 final String value = entry.getValue();
181181 }
182182 final PatternParser parser = PatternLayout.createPatternParser(config);
183183 final List<PatternFormatter> formatters = parser.parse(options[0]);
184 return new HighlightConverter(formatters, createLevelStyleMap(options));
184 final boolean noConsoleNoAnsi = Arrays.toString(options).contains(PatternParser.NO_CONSOLE_NO_ANSI + "=true");
185 final boolean hideAnsi = noConsoleNoAnsi && System.console() == null;
186 return new HighlightConverter(formatters, createLevelStyleMap(options), hideAnsi);
185187 }
186188
187189 private final Map<Level, String> levelStyles;
188190
189191 private final List<PatternFormatter> patternFormatters;
192
193 private final boolean noAnsi;
190194
191195 /**
192196 * Construct the converter.
193197 *
194198 * @param patternFormatters
195199 * The PatternFormatters to generate the text to manipulate.
196 */
197 private HighlightConverter(final List<PatternFormatter> patternFormatters, final Map<Level, String> levelStyles) {
200 * @param noAnsi
201 * If true, do not output ANSI escape codes.
202 */
203 private HighlightConverter(final List<PatternFormatter> patternFormatters, final Map<Level, String> levelStyles, final boolean noAnsi) {
198204 super("style", "style");
199205 this.patternFormatters = patternFormatters;
200206 this.levelStyles = levelStyles;
207 this.noAnsi = noAnsi;
201208 }
202209
203210 /**
211218 }
212219
213220 if (buf.length() > 0) {
214 toAppendTo.append(levelStyles.get(event.getLevel())).append(buf.toString()).
215 append(AnsiEscape.getDefaultStyle());
221 if (noAnsi) {
222 toAppendTo.append(buf.toString());
223 } else {
224 toAppendTo.append(levelStyles.get(event.getLevel())).append(buf.toString()).
225 append(AnsiEscape.getDefaultStyle());
226 }
216227 }
217228 }
218229
6060 if (options == null || options.length == 0) {
6161 return INSTANCE;
6262 }
63 final Map<Level, String> levelMap = new HashMap<Level, String>();
63 final Map<Level, String> levelMap = new HashMap<>();
6464 int length = Integer.MAX_VALUE; // More than the longest level name.
6565 boolean lowerCase = false;
6666 final String[] definitions = options[0].split(Patterns.COMMA_SEPARATOR);
7777 return;
7878 }
7979 final StringBuilder sb = new StringBuilder("{");
80 final Set<String> keys = new TreeSet<String>(map.keySet());
80 final Set<String> keys = new TreeSet<>(map.keySet());
8181 for (final String key : keys) {
8282 if (sb.length() > 1) {
8383 sb.append(", ");
2929 * within the property bundle
3030 * when this pattern converter has the option set.
3131 */
32 @Plugin(name = "MdcPatternConverter", category = PatternConverter.CATEGORY)
32 @Plugin(name = "MdcPatternConverter", category = PatternConverter.CATEGORY)
3333 @ConverterKeys({ "X", "mdc", "MDC" })
3434 public final class MdcPatternConverter extends LogEventPatternConverter {
3535 /**
3636 * Name of property to output.
3737 */
3838 private final String key;
39 private final String[] keys;
40 private final boolean full;
3941
4042 /**
4143 * Private constructor.
4446 */
4547 private MdcPatternConverter(final String[] options) {
4648 super(options != null && options.length > 0 ? "MDC{" + options[0] + '}' : "MDC", "mdc");
47 key = options != null && options.length > 0 ? options[0] : null;
49 if (options != null && options.length > 0) {
50 full = false;
51 if (options[0].indexOf(',') > 0) {
52 keys = options[0].split(",");
53 key = null;
54 } else {
55 keys = null;
56 key = options[0];
57 }
58 } else {
59 full = true;
60 key = null;
61 keys = null;
62 }
4863 }
4964
5065 /**
6580 final Map<String, String> contextMap = event.getContextMap();
6681 // if there is no additional options, we output every single
6782 // Key/Value pair for the MDC in a similar format to Hashtable.toString()
68 if (key == null) {
69
70
83 if (full) {
7184 if (contextMap == null || contextMap.isEmpty()) {
7285 toAppendTo.append("{}");
7386 return;
7487 }
7588 final StringBuilder sb = new StringBuilder("{");
76 final Set<String> keys = new TreeSet<String>(contextMap.keySet());
89 final Set<String> keys = new TreeSet<>(contextMap.keySet());
7790 for (final String key : keys) {
7891 if (sb.length() > 1) {
7992 sb.append(", ");
8396 }
8497 sb.append('}');
8598 toAppendTo.append(sb);
86 } else if (contextMap != null) {
87 // otherwise they just want a single key output
88 final Object val = contextMap.get(key);
99 } else {
100 if (keys != null) {
101 if (contextMap == null || contextMap.isEmpty()) {
102 toAppendTo.append("{}");
103 return;
104 }
105 // Print all the keys in the array that have a value.
106 final StringBuilder sb = new StringBuilder("{");
107 for (String key : keys) {
108 key = key.trim();
109 if (contextMap.containsKey(key)) {
110 if (sb.length() > 1) {
111 sb.append(", ");
112 }
113 sb.append(key).append('=').append(contextMap.get(key));
114 }
115 }
116 sb.append('}');
117 toAppendTo.append(sb);
118 } else if (contextMap != null){
119 // otherwise they just want a single key output
120 final Object val = contextMap.get(key);
89121
90 if (val != null) {
91 toAppendTo.append(val);
122 if (val != null) {
123 toAppendTo.append(val);
124 }
92125 }
93126 }
94127 }
6565 return new MaxElementAbbreviator(Integer.parseInt(trimmed));
6666 }
6767
68 final ArrayList<PatternAbbreviatorFragment> fragments = new ArrayList<PatternAbbreviatorFragment>(5);
68 final ArrayList<PatternAbbreviatorFragment> fragments = new ArrayList<>(5);
6969 char ellipsis;
7070 int charCount;
7171 int pos = 0;
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.pattern;
17
18 import org.apache.logging.log4j.core.LogEvent;
19 import org.apache.logging.log4j.core.config.plugins.Plugin;
20
21 /**
22 * Converts and formats the event's nanoTime in a StringBuilder.
23 */
24 @Plugin(name = "NanoTimePatternConverter", category = PatternConverter.CATEGORY)
25 @ConverterKeys({ "N", "nano" })
26 public final class NanoTimePatternConverter extends LogEventPatternConverter {
27
28 /**
29 * Obtains an instance of pattern converter.
30 *
31 * @param options
32 * options, may be null.
33 * @return instance of pattern converter.
34 */
35 public static NanoTimePatternConverter newInstance(final String[] options) {
36 return new NanoTimePatternConverter(options);
37 }
38
39 /**
40 * Private constructor.
41 *
42 * @param options
43 * options, may be null.
44 */
45 private NanoTimePatternConverter(final String[] options) {
46 super("Nanotime", "nanotime");
47 }
48
49 /**
50 * {@inheritDoc}
51 */
52 @Override
53 public void format(final LogEvent event, final StringBuilder output) {
54 output.append(event.getNanoTime());
55 }
56 }
1515 */
1616 package org.apache.logging.log4j.core.pattern;
1717
18 import org.apache.logging.log4j.Logger;
19 import org.apache.logging.log4j.core.config.Configuration;
20 import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
21 import org.apache.logging.log4j.core.config.plugins.util.PluginType;
22 import org.apache.logging.log4j.status.StatusLogger;
23 import org.apache.logging.log4j.util.Strings;
24
2518 import java.lang.reflect.Method;
2619 import java.lang.reflect.Modifier;
2720 import java.util.ArrayList;
2922 import java.util.LinkedHashMap;
3023 import java.util.List;
3124 import java.util.Map;
25 import java.util.Objects;
26
27 import org.apache.logging.log4j.Logger;
28 import org.apache.logging.log4j.core.config.Configuration;
29 import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
30 import org.apache.logging.log4j.core.config.plugins.util.PluginType;
31 import org.apache.logging.log4j.core.util.NanoClockFactory;
32 import org.apache.logging.log4j.status.StatusLogger;
33 import org.apache.logging.log4j.util.Strings;
3234
3335 /**
3436 * Most of the work of the {@link org.apache.logging.log4j.core.layout.PatternLayout} class is delegated to the
127129 final PluginManager manager = new PluginManager(converterKey);
128130 manager.collectPlugins(config == null ? null : config.getPluginPackages());
129131 final Map<String, PluginType<?>> plugins = manager.getPlugins();
130 final Map<String, Class<PatternConverter>> converters = new LinkedHashMap<String, Class<PatternConverter>>();
132 final Map<String, Class<PatternConverter>> converters = new LinkedHashMap<>();
131133
132134 for (final PluginType<?> type : plugins.values()) {
133135 try {
161163
162164 public List<PatternFormatter> parse(final String pattern, final boolean alwaysWriteExceptions,
163165 final boolean noConsoleNoAnsi) {
164 final List<PatternFormatter> list = new ArrayList<PatternFormatter>();
165 final List<PatternConverter> converters = new ArrayList<PatternConverter>();
166 final List<FormattingInfo> fields = new ArrayList<FormattingInfo>();
166 final List<PatternFormatter> list = new ArrayList<>();
167 final List<PatternConverter> converters = new ArrayList<>();
168 final List<FormattingInfo> fields = new ArrayList<>();
167169
168170 parse(pattern, converters, fields, noConsoleNoAnsi, true);
169171
170172 final Iterator<FormattingInfo> fieldIter = fields.iterator();
171173 boolean handlesThrowable = false;
172174
175 NanoClockFactory.setMode(NanoClockFactory.Mode.Dummy); // LOG4J2-1074 use dummy clock by default
173176 for (final PatternConverter converter : converters) {
177 if (converter instanceof NanoTimePatternConverter) {
178 // LOG4J2-1074 Switch to actual clock if nanosecond timestamps are required in config.
179 // LoggerContext will notify known NanoClockFactory users that the configuration has changed.
180 NanoClockFactory.setMode(NanoClockFactory.Mode.System);
181 }
174182 LogEventPatternConverter pc;
175183 if (converter instanceof LogEventPatternConverter) {
176184 pc = (LogEventPatternConverter) converter;
302310 public void parse(final String pattern, final List<PatternConverter> patternConverters,
303311 final List<FormattingInfo> formattingInfos, final boolean noConsoleNoAnsi,
304312 final boolean convertBackslashes) {
305 if (pattern == null) {
306 throw new NullPointerException("pattern");
307 }
313 Objects.requireNonNull(pattern, "pattern");
308314
309315 final StringBuilder currentLiteral = new StringBuilder(BUF_SIZE);
310316
361367 switch (c) {
362368 case '-':
363369 formattingInfo = new FormattingInfo(true, formattingInfo.getMinLength(),
364 formattingInfo.getMaxLength());
370 formattingInfo.getMaxLength(), formattingInfo.isLeftTruncate());
365371 break;
366372
367373 case '.':
372378
373379 if (c >= '0' && c <= '9') {
374380 formattingInfo = new FormattingInfo(formattingInfo.isLeftAligned(), c - '0',
375 formattingInfo.getMaxLength());
381 formattingInfo.getMaxLength(), formattingInfo.isLeftTruncate());
376382 state = ParserState.MIN_STATE;
377383 } else {
378384 i = finalizeConverter(c, pattern, i, currentLiteral, formattingInfo, converterRules,
393399 if (c >= '0' && c <= '9') {
394400 // Multiply the existing value and add the value of the number just encountered.
395401 formattingInfo = new FormattingInfo(formattingInfo.isLeftAligned(), formattingInfo.getMinLength()
396 * DECIMAL + c - '0', formattingInfo.getMaxLength());
402 * DECIMAL + c - '0', formattingInfo.getMaxLength(), formattingInfo.isLeftTruncate());
397403 } else if (c == '.') {
398404 state = ParserState.DOT_STATE;
399405 } else {
408414
409415 case DOT_STATE:
410416 currentLiteral.append(c);
411
412 if (c >= '0' && c <= '9') {
417 switch (c) {
418 case '-':
413419 formattingInfo = new FormattingInfo(formattingInfo.isLeftAligned(), formattingInfo.getMinLength(),
414 c - '0');
415 state = ParserState.MAX_STATE;
416 } else {
417 LOGGER.error("Error occurred in position " + i + ".\n Was expecting digit, instead got char \"" + c
418 + "\".");
419
420 state = ParserState.LITERAL_STATE;
420 formattingInfo.getMaxLength(),false);
421 break;
422
423 default:
424
425 if (c >= '0' && c <= '9') {
426 formattingInfo = new FormattingInfo(formattingInfo.isLeftAligned(), formattingInfo.getMinLength(),
427 c - '0', formattingInfo.isLeftTruncate());
428 state = ParserState.MAX_STATE;
429 } else {
430 LOGGER.error("Error occurred in position " + i + ".\n Was expecting digit, instead got char \"" + c
431 + "\".");
432
433 state = ParserState.LITERAL_STATE;
434 }
421435 }
422436
423437 break;
428442 if (c >= '0' && c <= '9') {
429443 // Multiply the existing value and add the value of the number just encountered.
430444 formattingInfo = new FormattingInfo(formattingInfo.isLeftAligned(), formattingInfo.getMinLength(),
431 formattingInfo.getMaxLength() * DECIMAL + c - '0');
445 formattingInfo.getMaxLength() * DECIMAL + c - '0', formattingInfo.isLeftTruncate());
432446 } else {
433447 i = finalizeConverter(c, pattern, i, currentLiteral, formattingInfo, converterRules,
434448 patternConverters, formattingInfos, noConsoleNoAnsi, convertBackslashes);
580594
581595 final String converterId = convBuf.toString();
582596
583 final List<String> options = new ArrayList<String>();
597 final List<String> options = new ArrayList<>();
584598 i = extractOptions(pattern, i, options);
585599
586600 final PatternConverter pc = createConverter(converterId, currentLiteral, rules, options, noConsoleNoAnsi);
1515 */
1616 package org.apache.logging.log4j.core.pattern;
1717
18 import java.util.Arrays;
1819 import java.util.List;
1920
2021 import org.apache.logging.log4j.core.LogEvent;
5657 final PatternParser parser = PatternLayout.createPatternParser(config);
5758 final List<PatternFormatter> formatters = parser.parse(options[0]);
5859 final String style = AnsiEscape.createSequence(options[1].split(Patterns.COMMA_SEPARATOR));
59 final boolean noConsoleNoAnsi = options.length > 2
60 && (PatternParser.NO_CONSOLE_NO_ANSI + "=true").equals(options[2]);
60 final boolean noConsoleNoAnsi = Arrays.toString(options).contains(PatternParser.NO_CONSOLE_NO_ANSI + "=true");
6161 final boolean hideAnsi = noConsoleNoAnsi && System.console() == null;
6262 return new StyleConverter(formatters, style, hideAnsi);
6363 }
2626
2727
2828 /**
29 * Outputs the Throwable portion of the LoggingEvent as a full stacktrace
29 * Outputs the Throwable portion of the LoggingEvent as a full stack trace
3030 * unless this converter's option is 'short', where it just outputs the first line of the trace, or if
3131 * the number of lines to print is explicitly specified.
3232 */
5656
5757 @Override
5858 public List<LoggerContext> getLoggerContexts() {
59 final List<LoggerContext> list = new ArrayList<LoggerContext>();
59 final List<LoggerContext> list = new ArrayList<>();
6060 list.add(CONTEXT);
6161 return Collections.unmodifiableList(list);
6262 }
4444 */
4545 public class ClassLoaderContextSelector implements ContextSelector {
4646
47 private static final AtomicReference<LoggerContext> CONTEXT = new AtomicReference<LoggerContext>();
47 private static final AtomicReference<LoggerContext> CONTEXT = new AtomicReference<>();
4848
4949 protected static final StatusLogger LOGGER = StatusLogger.getLogger();
5050
5151 protected static final ConcurrentMap<String, AtomicReference<WeakReference<LoggerContext>>> CONTEXT_MAP =
52 new ConcurrentHashMap<String, AtomicReference<WeakReference<LoggerContext>>>();
52 new ConcurrentHashMap<>();
5353
5454 @Override
5555 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final boolean currentContext) {
9292
9393 @Override
9494 public List<LoggerContext> getLoggerContexts() {
95 final List<LoggerContext> list = new ArrayList<LoggerContext>();
95 final List<LoggerContext> list = new ArrayList<>();
9696 final Collection<AtomicReference<WeakReference<LoggerContext>>> coll = CONTEXT_MAP.values();
9797 for (final AtomicReference<WeakReference<LoggerContext>> ref : coll) {
9898 final LoggerContext ctx = ref.get().get();
143143 }
144144 LoggerContext ctx = new LoggerContext(name, null, configLocation);
145145 final AtomicReference<WeakReference<LoggerContext>> r =
146 new AtomicReference<WeakReference<LoggerContext>>();
147 r.set(new WeakReference<LoggerContext>(ctx));
146 new AtomicReference<>();
147 r.set(new WeakReference<>(ctx));
148148 CONTEXT_MAP.putIfAbsent(name, r);
149149 ctx = CONTEXT_MAP.get(name).get().get();
150150 return ctx;
163163 return ctx;
164164 }
165165 ctx = new LoggerContext(name, null, configLocation);
166 ref.compareAndSet(weakRef, new WeakReference<LoggerContext>(ctx));
166 ref.compareAndSet(weakRef, new WeakReference<>(ctx));
167167 return ctx;
168168 }
169169
8787 private static final LoggerContext CONTEXT = new LoggerContext("Default");
8888
8989 private static final ConcurrentMap<String, LoggerContext> CONTEXT_MAP =
90 new ConcurrentHashMap<String, LoggerContext>();
90 new ConcurrentHashMap<>();
9191
9292 private static final StatusLogger LOGGER = StatusLogger.getLogger();
9393
149149
150150 @Override
151151 public List<LoggerContext> getLoggerContexts() {
152 final List<LoggerContext> list = new ArrayList<LoggerContext>(CONTEXT_MAP.values());
152 final List<LoggerContext> list = new ArrayList<>(CONTEXT_MAP.values());
153153 return Collections.unmodifiableList(list);
154154 }
155155
3131 * [CUSTOMLEVEL2=WEIGHT2 [CUSTOMLEVEL3=WEIGHT3] ...]}
3232 * <p>
3333 * Example of creating an extended logger:<br>
34 * {@code java org.apache.logging.log4j.core.tools.Generate$ExtendedLogger com.mycomp.ExtLogger DIAG=350 NOTICE=450 VERBOSE=550}
34 * {@code java org.apache.logging.log4j.core.tools.Generate$ExtendedLogger com.mycomp.ExtLogger DIAG=350 NOTICE=450
35 * VERBOSE=550}
3536 * <p>
3637 * To generate source code for a custom logger that replaces the existing log levels with custom ones: <br>
3738 * {@code java org.apache.logging.log4j.core.tools.Generate$CustomLogger <logger.class.name> <CUSTOMLEVEL>=<WEIGHT>
3839 * [CUSTOMLEVEL2=WEIGHT2 [CUSTOMLEVEL3=WEIGHT3] ...]}
3940 * <p>
4041 * Example of creating a custom logger:<br>
41 * {@code java org.apache.logging.log4j.core.tools.Generate$CustomLogger com.mycomp.MyLogger DEFCON1=350 DEFCON2=450 DEFCON3=550}
42 * {@code java org.apache.logging.log4j.core.tools.Generate$CustomLogger com.mycomp.MyLogger DEFCON1=350 DEFCON2=450
43 * DEFCON3=550}
4244 */
4345 public final class Generate {
4446
5153 return "" //
5254 + "import java.io.Serializable;%n" //
5355 + "import org.apache.logging.log4j.Level;%n" //
54 + "import org.apache.logging.log4j.LogManager;%n" + "import org.apache.logging.log4j.Logger;%n" //
56 + "import org.apache.logging.log4j.LogManager;%n" //
57 + "import org.apache.logging.log4j.Logger;%n" //
5558 + "import org.apache.logging.log4j.Marker;%n" //
5659 + "import org.apache.logging.log4j.message.Message;%n" //
5760 + "import org.apache.logging.log4j.message.MessageFactory;%n" //
5861 + "import org.apache.logging.log4j.spi.AbstractLogger;%n" //
5962 + "import org.apache.logging.log4j.spi.ExtendedLoggerWrapper;%n" //
63 + "import org.apache.logging.log4j.util.MessageSupplier;%n" //
64 + "import org.apache.logging.log4j.util.Supplier;%n"
6065 + "%n";
6166 }
6267
7075 + "public final class %s implements Serializable {%n" //
7176 + " private static final long serialVersionUID = " + System.nanoTime() + "L;%n" //
7277 + " private final ExtendedLoggerWrapper logger;%n" //
73 + "%n" //
74 ;
78 + "%n";
7579 }
7680
7781 @Override
7983 return "" //
8084 + "%n" //
8185 + " private %s(final Logger logger) {%n" //
82 + " this.logger = new ExtendedLoggerWrapper((AbstractLogger) logger, logger.getName(), logger.getMessageFactory());%n" //
83 + " }%n" //
84 ;
86 + " this.logger = new ExtendedLoggerWrapper((AbstractLogger) logger, logger.getName(), "
87 + "logger.getMessageFactory());%n" //
88 + " }%n";
8589 }
8690
8791 @Override
9498 String imports() {
9599 return "" //
96100 + "import org.apache.logging.log4j.Level;%n" //
97 + "import org.apache.logging.log4j.LogManager;%n" + "import org.apache.logging.log4j.Logger;%n" //
101 + "import org.apache.logging.log4j.LogManager;%n" //
102 + "import org.apache.logging.log4j.Logger;%n" //
98103 + "import org.apache.logging.log4j.Marker;%n" //
99104 + "import org.apache.logging.log4j.message.Message;%n" //
100105 + "import org.apache.logging.log4j.message.MessageFactory;%n" //
101106 + "import org.apache.logging.log4j.spi.AbstractLogger;%n" //
102107 + "import org.apache.logging.log4j.spi.ExtendedLoggerWrapper;%n" //
108 + "import org.apache.logging.log4j.util.MessageSupplier;%n" //
109 + "import org.apache.logging.log4j.util.Supplier;%n"
103110 + "%n";
104111 }
105112
113120 + "public final class %s extends ExtendedLoggerWrapper {%n" //
114121 + " private static final long serialVersionUID = " + System.nanoTime() + "L;%n" //
115122 + " private final ExtendedLoggerWrapper logger;%n" //
116 + "%n" //
117 ;
123 + "%n";
118124 }
119125
120126 @Override
124130 + " private %s(final Logger logger) {%n" //
125131 + " super((AbstractLogger) logger, logger.getName(), logger.getMessageFactory());%n" //
126132 + " this.logger = this;%n" //
127 + " }%n" //
128 ;
133 + " }%n";
129134 }
130135
131136 @Override
245250 + " public static CLASSNAME create(final String name, final MessageFactory factory) {%n" //
246251 + " final Logger wrapped = LogManager.getLogger(name, factory);%n" //
247252 + " return new CLASSNAME(wrapped);%n" //
248 + " }%n" //
249 ;
253 + " }%n";
254
250255 static final String METHODS = "" //
251256 + "%n" //
252257 + " /**%n" //
394399 + " */%n" //
395400 + " public void methodName(final String message, final Throwable t) {%n" //
396401 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, t);%n" //
397 + " }%n" //
398 ;
402 + " }%n"
403 + "%n" //
404 + " /**%n" //
405 + " * Logs a message which is only to be constructed if the logging level is the {@code CUSTOM_LEVEL}"//
406 + "level.%n" //
407 + " *%n" //
408 + " * @param msgSupplier A function, which when called, produces the desired log message;%n" //
409 + " * the format depends on the message factory.%n" //
410 + " * @since 2.4%n" //
411 + " */%n" //
412 + " public void methodName(final Supplier<?> msgSupplier) {%n" //
413 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, msgSupplier, (Throwable) null);%n" //
414 + " }%n" //
415 + "%n" //
416 + " /**%n" //
417 + " * Logs a message (only to be constructed if the logging level is the {@code CUSTOM_LEVEL}%n" //
418 + " * level) including the stack trace of the {@link Throwable} <code>t</code> passed as parameter.%n"//
419 + " *%n" //
420 + " * @param msgSupplier A function, which when called, produces the desired log message;%n" //
421 + " * the format depends on the message factory.%n" //
422 + " * @param t the exception to log, including its stack trace.%n" //
423 + " * @since 2.4%n" //
424 + " */%n" //
425 + " public void methodName(final Supplier<?> msgSupplier, final Throwable t) {%n" //
426 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, msgSupplier, t);%n" //
427 + " }%n" //
428 + "%n" //
429 + " /**%n" //
430 + " * Logs a message which is only to be constructed if the logging level is the%n" //
431 + " * {@code CUSTOM_LEVEL} level with the specified Marker.%n" //
432 + " *%n" //
433 + " * @param marker the marker data specific to this log statement%n" //
434 + " * @param msgSupplier A function, which when called, produces the desired log message;%n" //
435 + " * the format depends on the message factory.%n" //
436 + " * @since 2.4%n" //
437 + " */%n" //
438 + " public void methodName(final Marker marker, final Supplier<?> msgSupplier) {%n" //
439 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, msgSupplier, (Throwable) null);%n" //
440 + " }%n" //
441 + "%n" //
442 + " /**%n" //
443 + " * Logs a message with parameters which are only to be constructed if the logging level is the%n" //
444 + " * {@code CUSTOM_LEVEL} level.%n" //
445 + " *%n" //
446 + " * @param marker the marker data specific to this log statement%n" //
447 + " * @param message the message to log; the format depends on the message factory.%n" //
448 + " * @param paramSuppliers An array of functions, which when called, produce the desired log" //
449 + " message parameters.%n" //
450 + " * @since 2.4%n" //
451 + " */%n" //
452 + " public void methodName(final Marker marker, final String message, final Supplier<?>..." //
453 + " paramSuppliers) {%n" //
454 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, message, paramSuppliers);%n" //
455 + " }%n" //
456 + "%n" //
457 + " /**%n" //
458 + " * Logs a message (only to be constructed if the logging level is the {@code CUSTOM_LEVEL}%n" //
459 + " * level) with the specified Marker and including the stack trace of the {@link Throwable}%n" //
460 + " * <code>t</code> passed as parameter.%n"
461 + " *%n" //
462 + " * @param marker the marker data specific to this log statement%n" //
463 + " * @param msgSupplier A function, which when called, produces the desired log message;%n" //
464 + " * the format depends on the message factory.%n" //
465 + " * @param t A Throwable or null.%n" //
466 + " * @since 2.4%n" //
467 + " */%n" //
468 + " public void methodName(final Marker marker, final Supplier<?> msgSupplier, final Throwable t) {%n" //
469 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, msgSupplier, t);%n" //
470 + " }%n" //
471 + "%n" //
472 + " /**%n" //
473 + " * Logs a message with parameters which are only to be constructed if the logging level is%n" //
474 + " * the {@code CUSTOM_LEVEL} level.%n" //
475 + " *%n" //
476 + " * @param message the message to log; the format depends on the message factory.%n" //
477 + " * @param paramSuppliers An array of functions, which when called, produce the desired log" //
478 + " message parameters.%n" //
479 + " * @since 2.4%n" //
480 + " */%n" //
481 + " public void methodName(final String message, final Supplier<?>... paramSuppliers) {%n" //
482 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, message, paramSuppliers);%n" //
483 + " }%n" //
484 + "%n" //
485 + " /**%n" //
486 + " * Logs a message which is only to be constructed if the logging level is the%n" //
487 + " * {@code CUSTOM_LEVEL} level with the specified Marker. The {@code MessageSupplier} may or may%n" //
488 + " * not use the {@link MessageFactory} to construct the {@code Message}.%n" //
489 + " *%n" //
490 + " * @param marker the marker data specific to this log statement%n" //
491 + " * @param msgSupplier A function, which when called, produces the desired log message.%n" //
492 + " * @since 2.4%n" //
493 + " */%n" //
494 + " public void methodName(final Marker marker, final MessageSupplier msgSupplier) {%n" //
495 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, msgSupplier, (Throwable) null);%n" //
496 + " }%n" //
497 + "%n" //
498 + " /**%n" //
499 + " * Logs a message (only to be constructed if the logging level is the {@code CUSTOM_LEVEL}%n" //
500 + " * level) with the specified Marker and including the stack trace of the {@link Throwable}%n" //
501 + " * <code>t</code> passed as parameter. The {@code MessageSupplier} may or may not use the%n" //
502 + " * {@link MessageFactory} to construct the {@code Message}.%n"
503 + " *%n" //
504 + " * @param marker the marker data specific to this log statement%n" //
505 + " * @param msgSupplier A function, which when called, produces the desired log message.%n" //
506 + " * @param t A Throwable or null.%n" //
507 + " * @since 2.4%n" //
508 + " */%n" //
509 + " public void methodName(final Marker marker, final MessageSupplier msgSupplier, final " //
510 + "Throwable t) {%n" //
511 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, marker, msgSupplier, t);%n" //
512 + " }%n" //
513 + "%n" //
514 + " /**%n" //
515 + " * Logs a message which is only to be constructed if the logging level is the%n" //
516 + " * {@code CUSTOM_LEVEL} level. The {@code MessageSupplier} may or may not use the%n" //
517 + " * {@link MessageFactory} to construct the {@code Message}.%n"
518 + " *%n" //
519 + " * @param msgSupplier A function, which when called, produces the desired log message.%n" //
520 + " * @since 2.4%n" //
521 + " */%n" //
522 + " public void methodName(final MessageSupplier msgSupplier) {%n" //
523 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, msgSupplier, (Throwable) null);%n" //
524 + " }%n" //
525 + "%n" //
526 + " /**%n" //
527 + " * Logs a message (only to be constructed if the logging level is the {@code CUSTOM_LEVEL}%n" //
528 + " * level) including the stack trace of the {@link Throwable} <code>t</code> passed as parameter.%n"//
529 + " * The {@code MessageSupplier} may or may not use the {@link MessageFactory} to construct the%n" //
530 + " * {@code Message}.%n"
531 + " *%n" //
532 + " * @param msgSupplier A function, which when called, produces the desired log message.%n" //
533 + " * @param t the exception to log, including its stack trace.%n" //
534 + " * @since 2.4%n" //
535 + " */%n" //
536 + " public void methodName(final MessageSupplier msgSupplier, final Throwable t) {%n" //
537 + " logger.logIfEnabled(FQCN, CUSTOM_LEVEL, null, msgSupplier, t);%n" //
538 + " }%n";
399539
400540 private Generate() {
401541 }
452592 }
453593
454594 public static List<LevelInfo> parse(final List<String> values, final Class<?> generator) {
455 final List<LevelInfo> result = new ArrayList<Generate.LevelInfo>(values.size());
595 final List<LevelInfo> result = new ArrayList<>(values.size());
456596 for (int i = 0; i < values.size(); i++) {
457597 try {
458598 result.add(new LevelInfo(values.get(i)));
475615 usage(printStream, type.generator());
476616 System.exit(-1);
477617 }
478 final List<String> values = new ArrayList<String>(Arrays.asList(args));
618 final List<String> values = new ArrayList<>(Arrays.asList(args));
479619 final String classFQN = values.remove(0);
480620 final List<LevelInfo> levels = LevelInfo.parse(values, type.generator());
481621 printStream.println(generateSource(classFQN, levels, type));
490630
491631 private static void usage(final PrintStream out, final Class<?> generator) {
492632 out.println("Usage: java " + generator.getName() + " className LEVEL1=intLevel1 [LEVEL2=intLevel2...]");
493 out.println(" Where className is the fully qualified class name of the custom/extended logger to generate,");
494 out.println(" followed by a space-separated list of custom log levels.");
633 out.println(" Where className is the fully qualified class name of the custom/extended logger");
634 out.println(" to generate, followed by a space-separated list of custom log levels.");
495635 out.println(" For each custom log level, specify NAME=intLevel (without spaces).");
496636 }
497637
519659 sb.append(String.format(phase2, ""));
520660 }
521661
522 sb.append(String.format("}%n", ""));
662 sb.append(String.format("}%n", "")); // yes, does not use args to apply %n
523663 return sb.toString();
524664 }
525665
1414 * limitations under the license.
1515 */
1616 package org.apache.logging.log4j.core.util;
17
18 import java.util.Objects;
1719
1820 /**
1921 * Utility class providing common validation logic.
5153 * @param message message to populate the NPE with if necessary
5254 * @return the specified parameter
5355 * @throws NullPointerException if {@code object} is {@code null}
56 * @deprecated Will be removed in 2.5.
5457 */
58 @Deprecated
5559 public static <T> T requireNonNull(final T object, final String message) {
56 if (object == null) {
57 throw new NullPointerException(message);
58 }
59 return object;
60 return Objects.requireNonNull(object, message);
6061 }
6162 }
1717 package org.apache.logging.log4j.core.util;
1818
1919 /**
20 * A type of Plugin builder that can be used to configure and create a plugin instance using a Java DSL instead of
20 * A type of builder that can be used to configure and create a instances using a Java DSL instead of
2121 * through a configuration file. These builders are primarily useful for internal code and unit tests, but they can
2222 * technically be used as a verbose alternative to configuration files.
2323 *
2424 * <p>
25 * When creating plugin builders, it is customary to create the builder class as a public static inner class
25 * When creating <em>plugin</em> builders, it is customary to create the builder class as a public static inner class
2626 * called {@code Builder}. For instance, the builder class for
2727 * {@link org.apache.logging.log4j.core.layout.PatternLayout PatternLayout} would be
2828 * {@code PatternLayout.Builder}.
2929 * </p>
3030 *
31 * @param <T> the Plugin class this is a builder for.
31 * @param <T> This builder creates instances of this class.
3232 */
3333 public interface Builder<T> {
3434
3535 /**
36 * Builds the plugin object after all configuration has been set. This will use default values for any
37 * unspecified attributes for the plugin.
36 * Builds the object after all configuration has been set. This will use default values for any
37 * unspecified attributes for the object.
3838 *
39 * @return the configured plugin instance.
40 * @throws org.apache.logging.log4j.core.config.ConfigurationException if there was an error building the plugin
39 * @return the configured instance.
40 * @throws org.apache.logging.log4j.core.config.ConfigurationException if there was an error building the
4141 * object.
4242 */
4343 T build();
+0
-101
log4j-core/src/main/java/org/apache/logging/log4j/core/util/Charsets.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.util;
17
18 import java.nio.charset.Charset;
19
20 import org.apache.logging.log4j.status.StatusLogger;
21
22 /**
23 * Charset utilities. Contains the standard character sets guaranteed to be available on all implementations of the
24 * Java platform. Parts adapted from JDK 1.7 (in particular, the {@code java.nio.charset.StandardCharsets} class).
25 *
26 * @see java.nio.charset.Charset
27 */
28 public final class Charsets {
29
30 /**
31 * Seven-bit ASCII. ISO646-US. The Basic Latin block of the Unicode character set.
32 */
33 public static final Charset US_ASCII = Charset.forName("US-ASCII");
34
35 /**
36 * ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.
37 */
38 public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
39
40 /**
41 * Eight-bit UCS Transformation Format.
42 */
43 public static final Charset UTF_8 = Charset.forName("UTF-8");
44
45 /**
46 * Sixteen-bit UCS Transformation Format, big-endian byte order.
47 */
48 public static final Charset UTF_16BE = Charset.forName("UTF-16BE");
49
50 /**
51 * Sixteen-bit UCS Transformation Format, little-endian byte order.
52 */
53 public static final Charset UTF_16LE = Charset.forName("UTF-16LE");
54
55 /**
56 * Sixteen-bit UCS Transformation Format, byte order identified by an optional byte-order mark.
57 */
58 public static final Charset UTF_16 = Charset.forName("UTF-16");
59
60 /**
61 * Returns a Charset, if possible the Charset for the specified {@code charsetName}, otherwise (if the specified
62 * {@code charsetName} is {@code null} or not supported) this method returns the platform default Charset.
63 *
64 * @param charsetName
65 * name of the preferred charset or {@code null}
66 * @return a Charset, not null.
67 */
68 public static Charset getSupportedCharset(final String charsetName) {
69 return getSupportedCharset(charsetName, Charset.defaultCharset());
70 }
71
72 /**
73 * Returns a Charset, if possible the Charset for the specified {@code charsetName}, otherwise (if the specified
74 * {@code charsetName} is {@code null} or not supported) this method returns the platform default Charset.
75 *
76 * @param charsetName
77 * name of the preferred charset or {@code null}
78 * @param defaultCharset
79 * returned if {@code charsetName} is null or is not supported.
80 * @return a Charset, never null.
81 */
82 public static Charset getSupportedCharset(final String charsetName, final Charset defaultCharset) {
83 Charset charset = null;
84 if (charsetName != null && Charset.isSupported(charsetName)) {
85 charset = Charset.forName(charsetName);
86 }
87 if (charset == null) {
88 charset = defaultCharset;
89 if (charsetName != null) {
90 StatusLogger.getLogger().error(
91 "Charset " + charsetName + " is not supported for layout, using " + charset.displayName());
92 }
93 }
94 return charset;
95 }
96
97 private Charsets() {
98 }
99
100 }
1414 * limitations under the license.
1515 */
1616 package org.apache.logging.log4j.core.util;
17
18 import java.nio.charset.Charset;
19 import java.nio.charset.StandardCharsets;
1720
1821 import org.apache.logging.log4j.util.PropertiesUtil;
1922
4851 * Number of milliseconds in a second.
4952 */
5053 public static final int MILLIS_IN_SECONDS = 1000;
54
55 /**
56 * Equivalent to StandardCharsets.UTF_8.
57 *
58 * @deprecated Use {@link StandardCharsets#UTF_8}. Will be removed in 2.5.
59 */
60 @Deprecated
61 public static final Charset UTF_8 = StandardCharsets.UTF_8;
5162
5263 /**
5364 * Prevent class instantiation.
2828
2929 import org.apache.logging.log4j.Logger;
3030 import org.apache.logging.log4j.core.LifeCycle;
31 import org.apache.logging.log4j.core.LifeCycle.State;
3231 import org.apache.logging.log4j.status.StatusLogger;
3332
3433 /**
4241 private static final long serialVersionUID = 1L;
4342 protected static final Logger LOGGER = StatusLogger.getLogger();
4443
45 private final AtomicReference<State> state = new AtomicReference<State>(State.INITIALIZED);
44 private final AtomicReference<State> state = new AtomicReference<>(State.INITIALIZED);
4645 private final ThreadFactory threadFactory;
47 private final Collection<Cancellable> hooks = new CopyOnWriteArrayList<Cancellable>();
46 private final Collection<Cancellable> hooks = new CopyOnWriteArrayList<>();
4847 private Reference<Thread> shutdownHookRef;
4948
5049 /**
8584 if (isStarted()) {
8685 final Cancellable receipt = new Cancellable() {
8786 // use a reference to prevent memory leaks
88 private final Reference<Runnable> hook = new SoftReference<Runnable>(callback);
87 private final Reference<Runnable> hook = new SoftReference<>(callback);
8988
9089 @Override
9190 public void cancel() {
114113 state.get().name());
115114 }
116115
116 @Override
117 public void initialize() {
118 }
119
117120 /**
118121 * Registers the shutdown thread only if this is initialized.
119122 */
131134 }
132135
133136 private void addShutdownHook(final Thread thread) {
134 shutdownHookRef = new WeakReference<Thread>(thread);
137 shutdownHookRef = new WeakReference<>(thread);
135138 Runtime.getRuntime().addShutdownHook(thread);
136139 }
137140
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.util;
17
18 /**
19 * Implementation of the {@code NanoClock} interface that always returns a fixed value.
20 */
21 public final class DummyNanoClock implements NanoClock {
22
23 private final long fixedNanoTime;
24
25 public DummyNanoClock() {
26 this(0L);
27 }
28
29 /**
30 * Constructs a new DummyNanoClock with the specified value to return.
31 * @param fixedNanoTime the value to return from {@link #nanoTime()}.
32 */
33 public DummyNanoClock(long fixedNanoTime) {
34 this.fixedNanoTime = fixedNanoTime;
35 }
36
37 /**
38 * Returns the constructor value.
39 *
40 * @return the constructor value
41 */
42 @Override
43 public long nanoTime() {
44 return fixedNanoTime;
45 }
46
47 }
2323 import java.net.URISyntaxException;
2424 import java.net.URL;
2525 import java.net.URLDecoder;
26 import java.nio.charset.StandardCharsets;
2627 import java.util.regex.Pattern;
2728
2829 import org.apache.logging.log4j.Logger;
4546 }
4647
4748 /**
48 * Tries to convert the specified URL to a file object. If this fails,
49 * Tries to convert the specified URI to a file object. If this fails,
4950 * <b>null</b> is returned.
5051 *
5152 * @param uri the URI
5253 * @return the resulting file object
5354 */
5455 public static File fileFromUri(URI uri) {
55 if (uri == null || (uri.getScheme() != null &&
56 (!PROTOCOL_FILE.equals(uri.getScheme()) && !JBOSS_FILE.equals(uri.getScheme())))) {
56 // There MUST be a better way to do this. TODO Search other ASL projects...
57 if (uri == null
58 || (uri.getScheme() != null && (!PROTOCOL_FILE.equals(uri.getScheme()) && !JBOSS_FILE.equals(uri
59 .getScheme())))) {
5760 return null;
5861 }
5962 if (uri.getScheme() == null) {
63 File file = new File(uri.toString());
64 if (file.exists()) {
65 return file;
66 }
6067 try {
61 uri = new File(uri.getPath()).toURI();
68 final String path = uri.getPath();
69 file = new File(path);
70 if (file.exists()) {
71 return file;
72 }
73 uri = new File(path).toURI();
6274 } catch (final Exception ex) {
6375 LOGGER.warn("Invalid URI {}", uri);
6476 return null;
6577 }
6678 }
67 final String charsetName = Charsets.UTF_8.name();
79 final String charsetName = StandardCharsets.UTF_8.name();
6880 try {
69 final String fileName = uri.toURL().getFile();
81 String fileName = uri.toURL().getFile();
7082 if (new File(fileName).exists()) { // LOG4J2-466
7183 return new File(fileName); // allow files with '+' char in name
7284 }
73 return new File(URLDecoder.decode(fileName, charsetName));
85 fileName = URLDecoder.decode(fileName, charsetName);
86 return new File(fileName);
7487 } catch (final MalformedURLException ex) {
7588 LOGGER.warn("Invalid URL {}", uri, ex);
7689 } catch (final UnsupportedEncodingException uee) {
103116 throw new IOException("File " + dir + " exists and is not a directory. Unable to create directory.");
104117 }
105118 }
106
107 /**
108 * Takes a given URI string which may contain backslashes (illegal in URIs) in it due to user input or variable
109 * substitution and returns a URI with the backslashes replaced with forward slashes.
110 *
111 * @param uri The URI string
112 * @return the URI.
113 * @throws URISyntaxException if instantiating the URI threw a {@code URISyntaxException}.
114 */
115 public static URI getCorrectedFilePathUri(final String uri) throws URISyntaxException {
116 return new URI(WINDOWS_DIRECTORY_SEPARATOR.matcher(uri).replaceAll("/"));
117 }
118119 }
1818
1919 import java.io.InputStream;
2020 import java.lang.reflect.InvocationTargetException;
21 import java.lang.reflect.ReflectPermission;
2221 import java.net.URL;
2322
2423 import org.apache.logging.log4j.Logger;
3433
3534 private static final String TSTR = "Caught Exception while in Loader.getResource. This may be innocuous.";
3635
37 static {
38 final SecurityManager sm = System.getSecurityManager();
39 if (sm != null) {
40 sm.checkPermission(new RuntimePermission("getStackTrace"));
41 sm.checkPermission(new ReflectPermission("suppressAccessChecks"));
42 }
43 }
44
4536 /**
4637 * Returns the ClassLoader to use.
4738 * @return the ClassLoader.
6354
6455 // TODO: this method could use some explanation
6556 public static ClassLoader getClassLoader(final Class<?> class1, final Class<?> class2) {
66 final ClassLoader threadContextClassLoader = getTcl();
57 final ClassLoader threadContextClassLoader = getThreadContextClassLoader();
6758 final ClassLoader loader1 = class1 == null ? null : class1.getClassLoader();
6859 final ClassLoader loader2 = class2 == null ? null : class2.getClassLoader();
6960
9586 */
9687 public static URL getResource(final String resource, final ClassLoader defaultLoader) {
9788 try {
98 ClassLoader classLoader = getTcl();
89 ClassLoader classLoader = getThreadContextClassLoader();
9990 if (classLoader != null) {
10091 LOGGER.trace("Trying to find [{}] using context class loader {}.", resource, classLoader);
10192 final URL url = classLoader.getResource(resource);
157148 */
158149 public static InputStream getResourceAsStream(final String resource, final ClassLoader defaultLoader) {
159150 try {
160 ClassLoader classLoader = getTcl();
151 ClassLoader classLoader = getThreadContextClassLoader();
161152 InputStream is;
162153 if (classLoader != null) {
163154 LOGGER.trace("Trying to find [{}] using context class loader {}.", resource, classLoader);
198189 // code below.
199190 LOGGER.trace("Trying to find [{}] using ClassLoader.getSystemResource().", resource);
200191 return ClassLoader.getSystemResourceAsStream(resource);
201 }
202
203 private static ClassLoader getTcl() {
204 return LoaderUtil.getThreadContextClassLoader();
205192 }
206193
207194 /**
3030 }
3131
3232 public static String getSubName(final String name) {
33 if (name.isEmpty()) {
33 if (Strings.isEmpty(name)) {
3434 return null;
3535 }
3636 final int i = name.lastIndexOf('.');
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.util;
18
19 /**
20 * Provides the high-resolution time stamp used in log events.
21 */
22 public interface NanoClock {
23 /**
24 * Returns the current value of the running Java Virtual Machine's high-resolution time source, in nanoseconds.
25 *
26 * @return the current value of the running Java Virtual Machine's high-resolution time source, in nanoseconds
27 */
28 long nanoTime();
29 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.util;
18
19 import java.util.Objects;
20
21 /**
22 * Creates the appropriate {@link NanoClock} instance for the current configuration.
23 */
24 public class NanoClockFactory {
25
26 /**
27 * Enum over the different kinds of nano clocks this factory can create.
28 */
29 public static enum Mode {
30 /**
31 * Creates dummy nano clocks that always return a fixed value.
32 */
33 Dummy {
34 @Override
35 public NanoClock createNanoClock() {
36 return new DummyNanoClock();
37 }
38 },
39 /**
40 * Creates real nano clocks which call {{System.nanoTime()}}.
41 */
42 System {
43 @Override
44 public NanoClock createNanoClock() {
45 return new SystemNanoClock();
46 }
47 },
48 ;
49
50 public abstract NanoClock createNanoClock();
51 }
52
53 private static volatile Mode mode = Mode.Dummy;
54
55 /**
56 * Returns a new {@code NanoClock} determined by the mode of this factory.
57 *
58 * @return the appropriate {@code NanoClock} for the factory mode
59 */
60 public static NanoClock createNanoClock() {
61 return mode.createNanoClock();
62 }
63
64 /**
65 * Returns the factory mode.
66 *
67 * @return the factory mode that determines which kind of nano clocks this factory creates
68 */
69 public static Mode getMode() {
70 return mode;
71 }
72
73 /**
74 * Sets the factory mode.
75 *
76 * @param mode the factory mode that determines which kind of nano clocks this factory creates
77 */
78 public static void setMode(Mode mode) {
79 NanoClockFactory.mode = Objects.requireNonNull(mode, "mode must be non-null");
80 }
81 }
1515 */
1616 package org.apache.logging.log4j.core.util;
1717
18 import java.io.File;
1819 import java.net.InetAddress;
20 import java.net.MalformedURLException;
1921 import java.net.NetworkInterface;
2022 import java.net.SocketException;
23 import java.net.URI;
24 import java.net.URISyntaxException;
25 import java.net.URL;
2126 import java.net.UnknownHostException;
2227 import java.util.Enumeration;
2328
3035 public final class NetUtils {
3136
3237 private static final Logger LOGGER = StatusLogger.getLogger();
38 private static final String UNKNOWN_LOCALHOST = "UNKNOWN_LOCALHOST";
3339
3440 private NetUtils() {
41 // empty
3542 }
3643
3744 /**
6370 }
6471 } catch (final SocketException se) {
6572 LOGGER.error("Could not determine local host name", uhe);
66 return "UNKNOWN_LOCALHOST";
73 return UNKNOWN_LOCALHOST;
6774 }
6875 LOGGER.error("Could not determine local host name", uhe);
69 return "UNKNOWN_LOCALHOST";
76 return UNKNOWN_LOCALHOST;
77 }
78 }
79
80 /**
81 * Converts a URI string or file path to a URI object
82 * @param path the URI string or path
83 * @return the URI object
84 */
85 public static URI toURI(final String path) {
86 try {
87 // Resolves absolute URI
88 return new URI(path);
89 } catch (final URISyntaxException e) {
90 // A file path or a Apache Commons VFS URL might contain blanks.
91 // A file path may start with a driver letter
92 try {
93 final URL url = new URL(path);
94 return new URI(url.getProtocol(), url.getHost(), url.getPath(), null);
95 } catch (MalformedURLException | URISyntaxException nestedEx) {
96 return new File(path).toURI();
97 }
7098 }
7199 }
72100
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.util;
18
19 import java.io.IOException;
20 import java.io.OutputStream;
21
22 /**
23 * Writes all data to the famous <b>/dev/null</b>.
24 * <p>
25 * This output stream has no destination (file/socket etc.) and all bytes written to it are ignored and lost.
26 * </p>
27 * Originally from Apache Commons IO.
28 *
29 * @since 2.3
30 */
31 public class NullOutputStream extends OutputStream {
32
33 /**
34 * A singleton.
35 */
36 public static final NullOutputStream NULL_OUTPUT_STREAM = new NullOutputStream();
37
38 /**
39 * Does nothing - output to <code>/dev/null</code>.
40 *
41 * @param b
42 * The bytes to write
43 * @param off
44 * The start offset
45 * @param len
46 * The number of bytes to write
47 */
48 @Override
49 public void write(final byte[] b, final int off, final int len) {
50 // to /dev/null
51 }
52
53 /**
54 * Does nothing - output to <code>/dev/null</code>.
55 *
56 * @param b
57 * The byte to write
58 */
59 @Override
60 public void write(final int b) {
61 // to /dev/null
62 }
63
64 /**
65 * Does nothing - output to <code>/dev/null</code>.
66 *
67 * @param b
68 * The bytes to write
69 * @throws IOException
70 * never
71 */
72 @Override
73 public void write(final byte[] b) throws IOException {
74 // to /dev/null
75 }
76 }
2121 import org.apache.logging.log4j.Logger;
2222 import org.apache.logging.log4j.status.StatusLogger;
2323 import org.apache.logging.log4j.util.PropertiesUtil;
24 import org.apache.logging.log4j.util.Strings;
2425
2526 /**
2627 * A convenience class to convert property values to specific types.
299300 sbuf.append(val.substring(i, j));
300301 k = val.indexOf(DELIM_STOP, j);
301302 if (k == -1) {
302 throw new IllegalArgumentException('"' + val +
303 "\" has no closing brace. Opening brace at position " + j
303 throw new IllegalArgumentException(Strings.dquote(val)
304 + " has no closing brace. Opening brace at position " + j
304305 + '.');
305306 }
306307 j += DELIM_START_LEN;
2222 import java.lang.reflect.InvocationTargetException;
2323 import java.lang.reflect.Member;
2424 import java.lang.reflect.Modifier;
25 import java.util.Objects;
2526
2627 /**
2728 * Utility class for performing common reflective operations.
4041 * @throws NullPointerException if {@code member} is {@code null}.
4142 */
4243 public static <T extends AccessibleObject & Member> boolean isAccessible(final T member) {
43 Assert.requireNonNull(member, "No member provided");
44 Objects.requireNonNull(member, "No member provided");
4445 return Modifier.isPublic(member.getModifiers()) && Modifier.isPublic(member.getDeclaringClass().getModifiers());
4546 }
4647
6667 * @throws NullPointerException if {@code field} is {@code null}.
6768 */
6869 public static void makeAccessible(final Field field) {
69 Assert.requireNonNull(field, "No field provided");
70 Objects.requireNonNull(field, "No field provided");
7071 if ((!isAccessible(field) || Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) {
7172 field.setAccessible(true);
7273 }
8586 public static Object getFieldValue(final Field field, final Object instance) {
8687 makeAccessible(field);
8788 if (!Modifier.isStatic(field.getModifiers())) {
88 Assert.requireNonNull(instance, "No instance given for non-static field");
89 Objects.requireNonNull(instance, "No instance given for non-static field");
8990 }
9091 try {
9192 return field.get(instance);
119120 public static void setFieldValue(final Field field, final Object instance, final Object value) {
120121 makeAccessible(field);
121122 if (!Modifier.isStatic(field.getModifiers())) {
122 Assert.requireNonNull(instance, "No instance given for non-static field");
123 Objects.requireNonNull(instance, "No instance given for non-static field");
123124 }
124125 try {
125126 field.set(instance, value);
149150 * @throws IllegalStateException if no default constructor can be found
150151 */
151152 public static <T> Constructor<T> getDefaultConstructor(final Class<T> clazz) {
152 Assert.requireNonNull(clazz, "No class provided");
153 Objects.requireNonNull(clazz, "No class provided");
153154 try {
154155 final Constructor<T> constructor = clazz.getDeclaredConstructor();
155156 makeAccessible(constructor);
178179 * @throws IllegalStateException if access is denied to the constructor, or there are no default constructors
179180 */
180181 public static <T> T instantiate(final Class<T> clazz) {
181 Assert.requireNonNull(clazz, "No class provided");
182 Objects.requireNonNull(clazz, "No class provided");
182183 final Constructor<T> constructor = getDefaultConstructor(clazz);
183184 try {
184185 return constructor.newInstance();
186 } catch (final NoClassDefFoundError e) {
187 // LOG4J2-1051
188 // On platforms like Google App Engine and Android, some JRE classes are not supported: JMX, JNDI, etc.
189 throw new IllegalArgumentException(e);
185190 } catch (final InstantiationException e) {
186191 throw new IllegalArgumentException(e);
187192 } catch (final IllegalAccessException e) {
3434 * @return an array of the matching strings from the given set
3535 */
3636 public static String[] prefixSet(final Set<String> set, final String prefix) {
37 final Set<String> prefixSet = new HashSet<String>();
37 final Set<String> prefixSet = new HashSet<>();
3838 for (final String str : set) {
3939 if (str.startsWith(prefix)) {
4040 prefixSet.add(str);
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.util;
17
18 /**
19 * Implementation of the {@code NanoClock} interface that returns the system nano time.
20 */
21 public final class SystemNanoClock implements NanoClock {
22
23 /**
24 * Returns the system high-resolution time.
25 * @return the result of calling {@code System.nanoTime()}
26 */
27 @Override
28 public long nanoTime() {
29 return System.nanoTime();
30 }
31
32 }
2121 import java.io.PrintWriter;
2222 import java.io.StringReader;
2323 import java.io.StringWriter;
24 import java.lang.reflect.InvocationTargetException;
25 import java.lang.reflect.Method;
2624 import java.lang.reflect.UndeclaredThrowableException;
2725 import java.util.ArrayList;
2826 import java.util.List;
29
30 import org.apache.logging.log4j.status.StatusLogger;
3127
3228 /**
3329 * Helps with Throwable objects.
3430 */
3531 public final class Throwables {
36
37 private static final Method ADD_SUPPRESSED;
38
39 private static final Method GET_SUPPRESSED;
40
41 static {
42 Method getSuppressed = null, addSuppressed = null;
43 final Method[] methods = Throwable.class.getMethods();
44 for (final Method method : methods) {
45 if (method.getName().equals("getSuppressed")) {
46 getSuppressed = method;
47 } else if (method.getName().equals("addSuppressed")) {
48 addSuppressed = method;
49 }
50 }
51 GET_SUPPRESSED = getSuppressed;
52 ADD_SUPPRESSED = addSuppressed;
53 }
5432
5533 /**
5634 * Has no effect on Java 6 and below.
5937 * @param suppressedThrowable a suppressed Throwable
6038 * @see Throwable#addSuppressed(Throwable)
6139 * @deprecated If compiling on Java 7 and above use {@link Throwable#addSuppressed(Throwable)}. Marked as deprecated because Java 6 is
62 * deprecated.
40 * deprecated. Will be removed in 2.5.
6341 */
6442 @Deprecated
6543 public static void addSuppressed(final Throwable throwable, final Throwable suppressedThrowable) {
66 if (ADD_SUPPRESSED != null) {
67 try {
68 ADD_SUPPRESSED.invoke(throwable, suppressedThrowable);
69 } catch (final IllegalAccessException e) {
70 // Only happens on Java >= 7 if this class has a bug.
71 StatusLogger.getLogger().error(e);
72 } catch (final IllegalArgumentException e) {
73 // Only happens on Java >= 7 if this class has a bug.
74 StatusLogger.getLogger().error(e);
75 } catch (final InvocationTargetException e) {
76 // Only happens on Java >= 7 if this class has a bug.
77 StatusLogger.getLogger().error(e);
78 }
79 }
80
44 throwable.addSuppressed(suppressedThrowable);
8145 }
8246
8347 /**
8751 * @return see Java 7's {@link Throwable#getSuppressed()}
8852 * @see Throwable#getSuppressed()
8953 * @deprecated If compiling on Java 7 and above use {@link Throwable#getSuppressed()}. Marked as deprecated because Java 6 is
90 * deprecated.
54 * deprecated. Will be removed 2.5.
9155 */
9256 @Deprecated
9357 public static Throwable[] getSuppressed(final Throwable throwable) {
94 if (GET_SUPPRESSED != null) {
95 try {
96 return (Throwable[]) GET_SUPPRESSED.invoke(throwable);
97 } catch (final Exception e) {
98 // Only happens on Java >= 7 if this class has a bug.
99 StatusLogger.getLogger().error(e);
100 return null;
101 }
102 }
103 return null;
58 return throwable.getSuppressed();
10459 }
10560
10661 /**
10762 * Returns true if the getSuppressed method is available.
10863 *
109 * @return True if getSuppressed is available.
64 * @return True if getSuppressed is available. As of 2.4, always returns true.
65 * @deprecated Will be removed in 2.5. As of 2.4, always returns true.
11066 */
67 @Deprecated
11168 public static boolean isGetSuppressedAvailable() {
112 return GET_SUPPRESSED != null;
69 return true;
11370 }
11471
11572 /**
12784 // Ignore any exceptions.
12885 }
12986 pw.flush();
130 final List<String> lines = new ArrayList<String>();
87 final List<String> lines = new ArrayList<>();
13188 final LineNumberReader reader = new LineNumberReader(new StringReader(sw.toString()));
13289 try {
13390 String line = reader.readLine();
1919 import java.lang.reflect.ParameterizedType;
2020 import java.lang.reflect.Type;
2121 import java.lang.reflect.WildcardType;
22 import java.util.Objects;
2223
2324 /**
2425 * Utility class for working with Java {@link Type}s and derivatives. This class is adapted heavily from the
4647 * @see Class#isAssignableFrom(Class)
4748 */
4849 public static boolean isAssignable(final Type lhs, final Type rhs) {
49 Assert.requireNonNull(lhs, "No left hand side type provided");
50 Assert.requireNonNull(rhs, "No right hand side type provided");
50 Objects.requireNonNull(lhs, "No left hand side type provided");
51 Objects.requireNonNull(rhs, "No right hand side type provided");
5152 if (lhs.equals(rhs)) {
5253 return true;
5354 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.logging.log4j.core.util.datetime;
17
18 import java.text.ParseException;
19 import java.text.ParsePosition;
20 import java.util.Date;
21 import java.util.Locale;
22 import java.util.TimeZone;
23
24 /**
25 * Copied from Commons Lang 3
26 */
27 public interface DateParser {
28
29 /**
30 * Equivalent to DateFormat.parse(String).
31 *
32 * See {@link java.text.DateFormat#parse(String)} for more information.
33 * @param source A <code>String</code> whose beginning should be parsed.
34 * @return A <code>Date</code> parsed from the string
35 * @throws ParseException if the beginning of the specified string cannot be parsed.
36 */
37 Date parse(String source) throws ParseException;
38
39 /**
40 * Equivalent to DateFormat.parse(String, ParsePosition).
41 *
42 * See {@link java.text.DateFormat#parse(String, ParsePosition)} for more information.
43 *
44 * @param source A <code>String</code>, part of which should be parsed.
45 * @param pos A <code>ParsePosition</code> object with index and error index information
46 * as described above.
47 * @return A <code>Date</code> parsed from the string. In case of error, returns null.
48 * @throws NullPointerException if text or pos is null.
49 */
50 Date parse(String source, ParsePosition pos);
51
52 // Accessors
53 //-----------------------------------------------------------------------
54 /**
55 * <p>Get the pattern used by this parser.</p>
56 *
57 * @return the pattern, {@link java.text.SimpleDateFormat} compatible
58 */
59 String getPattern();
60
61 /**
62 * <p>
63 * Get the time zone used by this parser.
64 * </p>
65 *
66 * <p>
67 * The default {@link TimeZone} used to create a {@link Date} when the {@link TimeZone} is not specified by
68 * the format pattern.
69 * </p>
70 *
71 * @return the time zone
72 */
73 TimeZone getTimeZone();
74
75 /**
76 * <p>Get the locale used by this parser.</p>
77 *
78 * @return the locale
79 */
80 Locale getLocale();
81
82 /**
83 * Parses text from a string to produce a Date.
84 *
85 * @param source A <code>String</code> whose beginning should be parsed.
86 * @return a <code>java.util.Date</code> object
87 * @throws ParseException if the beginning of the specified string cannot be parsed.
88 * @see java.text.DateFormat#parseObject(String)
89 */
90 Object parseObject(String source) throws ParseException;
91
92 /**
93 * Parse a date/time string according to the given parse position.
94 *
95 * @param source A <code>String</code> whose beginning should be parsed.
96 * @param pos the parse position
97 * @return a <code>java.util.Date</code> object
98 * @see java.text.DateFormat#parseObject(String, ParsePosition)
99 */
100 Object parseObject(String source, ParsePosition pos);
101 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.logging.log4j.core.util.datetime;
17
18 import java.text.FieldPosition;
19 import java.util.Calendar;
20 import java.util.Date;
21 import java.util.Locale;
22 import java.util.TimeZone;
23
24 /**
25 * Copied from Commons Lang 3
26 */
27 public interface DatePrinter {
28
29 /**
30 * <p>Formats a millisecond {@code long} value.</p>
31 *
32 * @param millis the millisecond value to format
33 * @return the formatted string
34 * @since 2.1
35 */
36 String format(long millis);
37
38 /**
39 * <p>Formats a {@code Date} object using a {@code GregorianCalendar}.</p>
40 *
41 * @param date the date to format
42 * @return the formatted string
43 */
44 String format(Date date);
45
46 /**
47 * <p>Formats a {@code Calendar} object.</p>
48 * The TimeZone set on the Calendar is only used to adjust the time offset.
49 * The TimeZone specified during the construction of the Parser will determine the TimeZone
50 * used in the formatted string.
51 *
52 * @param calendar the calendar to format.
53 * @return the formatted string
54 */
55 String format(Calendar calendar);
56
57 /**
58 * <p>Formats a milliseond {@code long} value into the
59 * supplied {@code StringBuilder}.</p>
60 *
61 * @param millis the millisecond value to format
62 * @param buf the buffer to format into
63 * @return the specified string buffer
64 */
65 StringBuilder format(long millis, StringBuilder buf);
66
67 /**
68 * <p>Formats a {@code Date} object into the
69 * supplied {@code StringBuilder} using a {@code GregorianCalendar}.</p>
70 *
71 * @param date the date to format
72 * @param buf the buffer to format into
73 * @return the specified string buffer
74 */
75 StringBuilder format(Date date, StringBuilder buf);
76
77 /**
78 * <p>Formats a {@code Calendar} object into the supplied {@code StringBuilder}.</p>
79 * The TimeZone set on the Calendar is only used to adjust the time offset.
80 * The TimeZone specified during the construction of the Parser will determine the TimeZone
81 * used in the formatted string.
82 *
83 * @param calendar the calendar to format
84 * @param buf the buffer to format into
85 * @return the specified string buffer
86 */
87 StringBuilder format(Calendar calendar, StringBuilder buf);
88
89 // Accessors
90 //-----------------------------------------------------------------------
91 /**
92 * <p>Gets the pattern used by this printer.</p>
93 *
94 * @return the pattern, {@link java.text.SimpleDateFormat} compatible
95 */
96 String getPattern();
97
98 /**
99 * <p>Gets the time zone used by this printer.</p>
100 *
101 * <p>This zone is always used for {@code Date} printing. </p>
102 *
103 * @return the time zone
104 */
105 TimeZone getTimeZone();
106
107 /**
108 * <p>Gets the locale used by this printer.</p>
109 *
110 * @return the locale
111 */
112 Locale getLocale();
113
114 /**
115 * <p>Formats a {@code Date}, {@code Calendar} or
116 * {@code Long} (milliseconds) object.</p>
117 *
118 * See {@link java.text.DateFormat#format(Object, StringBuffer, FieldPosition)}
119 *
120 * @param obj the object to format
121 * @param toAppendTo the buffer to append to
122 * @param pos the position - ignored
123 * @return the buffer passed in
124 */
125 StringBuilder format(Object obj, StringBuilder toAppendTo, FieldPosition pos);
126 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.logging.log4j.core.util.datetime;
17
18 import java.io.Serializable;
19 import java.text.DateFormat;
20 import java.text.FieldPosition;
21 import java.text.ParseException;
22 import java.text.ParsePosition;
23 import java.util.Calendar;
24 import java.util.Date;
25 import java.util.Locale;
26 import java.util.TimeZone;
27
28 /**
29 * This is a copy of Commons Lang's Fast Date Formatter.
30 */
31 public class FastDateFormat extends Format implements DatePrinter, DateParser, Serializable {
32 /**
33 * Required for serialization support.
34 *
35 * @see java.io.Serializable
36 */
37 private static final long serialVersionUID = 2L;
38
39 /**
40 * FULL locale dependent date or time style.
41 */
42 public static final int FULL = DateFormat.FULL;
43 /**
44 * LONG locale dependent date or time style.
45 */
46 public static final int LONG = DateFormat.LONG;
47 /**
48 * MEDIUM locale dependent date or time style.
49 */
50 public static final int MEDIUM = DateFormat.MEDIUM;
51 /**
52 * SHORT locale dependent date or time style.
53 */
54 public static final int SHORT = DateFormat.SHORT;
55
56 private static final FormatCache<FastDateFormat> cache= new FormatCache<FastDateFormat>() {
57 @Override
58 protected FastDateFormat createInstance(final String pattern, final TimeZone timeZone, final Locale locale) {
59 return new FastDateFormat(pattern, timeZone, locale);
60 }
61 };
62
63 private final FastDatePrinter printer;
64 private final FastDateParser parser;
65
66 //-----------------------------------------------------------------------
67 /**
68 * <p>Gets a formatter instance using the default pattern in the
69 * default locale.</p>
70 *
71 * @return a date/time formatter
72 */
73 public static FastDateFormat getInstance() {
74 return cache.getInstance();
75 }
76
77 /**
78 * <p>Gets a formatter instance using the specified pattern in the
79 * default locale.</p>
80 *
81 * @param pattern {@link java.text.SimpleDateFormat} compatible
82 * pattern
83 * @return a pattern based date/time formatter
84 * @throws IllegalArgumentException if pattern is invalid
85 */
86 public static FastDateFormat getInstance(final String pattern) {
87 return cache.getInstance(pattern, null, null);
88 }
89
90 /**
91 * <p>Gets a formatter instance using the specified pattern and
92 * time zone.</p>
93 *
94 * @param pattern {@link java.text.SimpleDateFormat} compatible
95 * pattern
96 * @param timeZone optional time zone, overrides time zone of
97 * formatted date
98 * @return a pattern based date/time formatter
99 * @throws IllegalArgumentException if pattern is invalid
100 */
101 public static FastDateFormat getInstance(final String pattern, final TimeZone timeZone) {
102 return cache.getInstance(pattern, timeZone, null);
103 }
104
105 /**
106 * <p>Gets a formatter instance using the specified pattern and
107 * locale.</p>
108 *
109 * @param pattern {@link java.text.SimpleDateFormat} compatible
110 * pattern
111 * @param locale optional locale, overrides system locale
112 * @return a pattern based date/time formatter
113 * @throws IllegalArgumentException if pattern is invalid
114 */
115 public static FastDateFormat getInstance(final String pattern, final Locale locale) {
116 return cache.getInstance(pattern, null, locale);
117 }
118
119 /**
120 * <p>Gets a formatter instance using the specified pattern, time zone
121 * and locale.</p>
122 *
123 * @param pattern {@link java.text.SimpleDateFormat} compatible
124 * pattern
125 * @param timeZone optional time zone, overrides time zone of
126 * formatted date
127 * @param locale optional locale, overrides system locale
128 * @return a pattern based date/time formatter
129 * @throws IllegalArgumentException if pattern is invalid
130 * or {@code null}
131 */
132 public static FastDateFormat getInstance(final String pattern, final TimeZone timeZone, final Locale locale) {
133 return cache.getInstance(pattern, timeZone, locale);
134 }
135
136 //-----------------------------------------------------------------------
137 /**
138 * <p>Gets a date formatter instance using the specified style in the
139 * default time zone and locale.</p>
140 *
141 * @param style date style: FULL, LONG, MEDIUM, or SHORT
142 * @return a localized standard date formatter
143 * @throws IllegalArgumentException if the Locale has no date
144 * pattern defined
145 * @since 2.1
146 */
147 public static FastDateFormat getDateInstance(final int style) {
148 return cache.getDateInstance(style, null, null);
149 }
150
151 /**
152 * <p>Gets a date formatter instance using the specified style and
153 * locale in the default time zone.</p>
154 *
155 * @param style date style: FULL, LONG, MEDIUM, or SHORT
156 * @param locale optional locale, overrides system locale
157 * @return a localized standard date formatter
158 * @throws IllegalArgumentException if the Locale has no date
159 * pattern defined
160 * @since 2.1
161 */
162 public static FastDateFormat getDateInstance(final int style, final Locale locale) {
163 return cache.getDateInstance(style, null, locale);
164 }
165
166 /**
167 * <p>Gets a date formatter instance using the specified style and
168 * time zone in the default locale.</p>
169 *
170 * @param style date style: FULL, LONG, MEDIUM, or SHORT
171 * @param timeZone optional time zone, overrides time zone of
172 * formatted date
173 * @return a localized standard date formatter
174 * @throws IllegalArgumentException if the Locale has no date
175 * pattern defined
176 * @since 2.1
177 */
178 public static FastDateFormat getDateInstance(final int style, final TimeZone timeZone) {
179 return cache.getDateInstance(style, timeZone, null);
180 }
181
182 /**
183 * <p>Gets a date formatter instance using the specified style, time
184 * zone and locale.</p>
185 *
186 * @param style date style: FULL, LONG, MEDIUM, or SHORT
187 * @param timeZone optional time zone, overrides time zone of
188 * formatted date
189 * @param locale optional locale, overrides system locale
190 * @return a localized standard date formatter
191 * @throws IllegalArgumentException if the Locale has no date
192 * pattern defined
193 */
194 public static FastDateFormat getDateInstance(final int style, final TimeZone timeZone, final Locale locale) {
195 return cache.getDateInstance(style, timeZone, locale);
196 }
197
198 //-----------------------------------------------------------------------
199 /**
200 * <p>Gets a time formatter instance using the specified style in the
201 * default time zone and locale.</p>
202 *
203 * @param style time style: FULL, LONG, MEDIUM, or SHORT
204 * @return a localized standard time formatter
205 * @throws IllegalArgumentException if the Locale has no time
206 * pattern defined
207 * @since 2.1
208 */
209 public static FastDateFormat getTimeInstance(final int style) {
210 return cache.getTimeInstance(style, null, null);
211 }
212
213 /**
214 * <p>Gets a time formatter instance using the specified style and
215 * locale in the default time zone.</p>
216 *
217 * @param style time style: FULL, LONG, MEDIUM, or SHORT
218 * @param locale optional locale, overrides system locale
219 * @return a localized standard time formatter
220 * @throws IllegalArgumentException if the Locale has no time
221 * pattern defined
222 * @since 2.1
223 */
224 public static FastDateFormat getTimeInstance(final int style, final Locale locale) {
225 return cache.getTimeInstance(style, null, locale);
226 }
227
228 /**
229 * <p>Gets a time formatter instance using the specified style and
230 * time zone in the default locale.</p>
231 *
232 * @param style time style: FULL, LONG, MEDIUM, or SHORT
233 * @param timeZone optional time zone, overrides time zone of
234 * formatted time
235 * @return a localized standard time formatter
236 * @throws IllegalArgumentException if the Locale has no time
237 * pattern defined
238 * @since 2.1
239 */
240 public static FastDateFormat getTimeInstance(final int style, final TimeZone timeZone) {
241 return cache.getTimeInstance(style, timeZone, null);
242 }
243
244 /**
245 * <p>Gets a time formatter instance using the specified style, time
246 * zone and locale.</p>
247 *
248 * @param style time style: FULL, LONG, MEDIUM, or SHORT
249 * @param timeZone optional time zone, overrides time zone of
250 * formatted time
251 * @param locale optional locale, overrides system locale
252 * @return a localized standard time formatter
253 * @throws IllegalArgumentException if the Locale has no time
254 * pattern defined
255 */
256 public static FastDateFormat getTimeInstance(final int style, final TimeZone timeZone, final Locale locale) {
257 return cache.getTimeInstance(style, timeZone, locale);
258 }
259
260 //-----------------------------------------------------------------------
261 /**
262 * <p>Gets a date/time formatter instance using the specified style
263 * in the default time zone and locale.</p>
264 *
265 * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
266 * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
267 * @return a localized standard date/time formatter
268 * @throws IllegalArgumentException if the Locale has no date/time
269 * pattern defined
270 * @since 2.1
271 */
272 public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle) {
273 return cache.getDateTimeInstance(dateStyle, timeStyle, null, null);
274 }
275
276 /**
277 * <p>Gets a date/time formatter instance using the specified style and
278 * locale in the default time zone.</p>
279 *
280 * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
281 * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
282 * @param locale optional locale, overrides system locale
283 * @return a localized standard date/time formatter
284 * @throws IllegalArgumentException if the Locale has no date/time
285 * pattern defined
286 * @since 2.1
287 */
288 public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle, final Locale locale) {
289 return cache.getDateTimeInstance(dateStyle, timeStyle, null, locale);
290 }
291
292 /**
293 * <p>Gets a date/time formatter instance using the specified style and
294 * time zone in the default locale.</p>
295 *
296 * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
297 * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
298 * @param timeZone optional time zone, overrides time zone of
299 * formatted date
300 * @return a localized standard date/time formatter
301 * @throws IllegalArgumentException if the Locale has no date/time
302 * pattern defined
303 * @since 2.1
304 */
305 public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle, final TimeZone timeZone) {
306 return getDateTimeInstance(dateStyle, timeStyle, timeZone, null);
307 }
308 /**
309 * <p>Gets a date/time formatter instance using the specified style,
310 * time zone and locale.</p>
311 *
312 * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
313 * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
314 * @param timeZone optional time zone, overrides time zone of
315 * formatted date
316 * @param locale optional locale, overrides system locale
317 * @return a localized standard date/time formatter
318 * @throws IllegalArgumentException if the Locale has no date/time
319 * pattern defined
320 */
321 public static FastDateFormat getDateTimeInstance(
322 final int dateStyle, final int timeStyle, final TimeZone timeZone, final Locale locale) {
323 return cache.getDateTimeInstance(dateStyle, timeStyle, timeZone, locale);
324 }
325
326 // Constructor
327 //-----------------------------------------------------------------------
328 /**
329 * <p>Constructs a new FastDateFormat.</p>
330 *
331 * @param pattern {@link java.text.SimpleDateFormat} compatible pattern
332 * @param timeZone non-null time zone to use
333 * @param locale non-null locale to use
334 * @throws NullPointerException if pattern, timeZone, or locale is null.
335 */
336 protected FastDateFormat(final String pattern, final TimeZone timeZone, final Locale locale) {
337 this(pattern, timeZone, locale, null);
338 }
339
340 // Constructor
341 //-----------------------------------------------------------------------
342 /**
343 * <p>Constructs a new FastDateFormat.</p>
344 *
345 * @param pattern {@link java.text.SimpleDateFormat} compatible pattern
346 * @param timeZone non-null time zone to use
347 * @param locale non-null locale to use
348 * @param centuryStart The start of the 100 year period to use as the "default century" for 2 digit year parsing. If centuryStart is null, defaults to now - 80 years
349 * @throws NullPointerException if pattern, timeZone, or locale is null.
350 */
351 protected FastDateFormat(final String pattern, final TimeZone timeZone, final Locale locale, final Date centuryStart) {
352 printer= new FastDatePrinter(pattern, timeZone, locale);
353 parser= new FastDateParser(pattern, timeZone, locale, centuryStart);
354 }
355
356 // Format methods
357 //-----------------------------------------------------------------------
358 /**
359 * <p>Formats a {@code Date}, {@code Calendar} or
360 * {@code Long} (milliseconds) object.</p>
361 *
362 * @param obj the object to format
363 * @param toAppendTo the buffer to append to
364 * @param pos the position - ignored
365 * @return the buffer passed in
366 */
367 @Override
368 public StringBuilder format(final Object obj, final StringBuilder toAppendTo, final FieldPosition pos) {
369 return printer.format(obj, toAppendTo, pos);
370 }
371
372 /**
373 * <p>Formats a millisecond {@code long} value.</p>
374 *
375 * @param millis the millisecond value to format
376 * @return the formatted string
377 * @since 2.1
378 */
379 @Override
380 public String format(final long millis) {
381 return printer.format(millis);
382 }
383
384 /**
385 * <p>Formats a {@code Date} object using a {@code GregorianCalendar}.</p>
386 *
387 * @param date the date to format
388 * @return the formatted string
389 */
390 @Override
391 public String format(final Date date) {
392 return printer.format(date);
393 }
394
395 /**
396 * <p>Formats a {@code Calendar} object.</p>
397 *
398 * @param calendar the calendar to format
399 * @return the formatted string
400 */
401 @Override
402 public String format(final Calendar calendar) {
403 return printer.format(calendar);
404 }
405
406 /**
407 * <p>Formats a millisecond {@code long} value into the
408 * supplied {@code StringBuilder}.</p>
409 *
410 * @param millis the millisecond value to format
411 * @param buf the buffer to format into
412 * @return the specified string buffer
413 * @since 2.1
414 */
415 @Override
416 public StringBuilder format(final long millis, final StringBuilder buf) {
417 return printer.format(millis, buf);
418 }
419
420 /**
421 * <p>Formats a {@code Date} object into the
422 * supplied {@code StringBuilder} using a {@code GregorianCalendar}.</p>
423 *
424 * @param date the date to format
425 * @param buf the buffer to format into
426 * @return the specified string buffer
427 */
428 @Override
429 public StringBuilder format(final Date date, final StringBuilder buf) {
430 return printer.format(date, buf);
431 }
432
433 /**
434 * <p>Formats a {@code Calendar} object into the
435 * supplied {@code StringBuilder}.</p>
436 *
437 * @param calendar the calendar to format
438 * @param buf the buffer to format into
439 * @return the specified string buffer
440 */
441 @Override
442 public StringBuilder format(final Calendar calendar, final StringBuilder buf) {
443 return printer.format(calendar, buf);
444 }
445
446 // Parsing
447 //-----------------------------------------------------------------------
448
449
450 /* (non-Javadoc)
451 * @see DateParser#parse(java.lang.String)
452 */
453 @Override
454 public Date parse(final String source) throws ParseException {
455 return parser.parse(source);
456 }
457
458 /* (non-Javadoc)
459 * @see DateParser#parse(java.lang.String, java.text.ParsePosition)
460 */
461 @Override
462 public Date parse(final String source, final ParsePosition pos) {
463 return parser.parse(source, pos);
464 }
465
466 /* (non-Javadoc)
467 * @see java.text.Format#parseObject(java.lang.String, java.text.ParsePosition)
468 */
469 @Override
470 public Object parseObject(final String source, final ParsePosition pos) {
471 return parser.parseObject(source, pos);
472 }
473
474 // Accessors
475 //-----------------------------------------------------------------------
476 /**
477 * <p>Gets the pattern used by this formatter.</p>
478 *
479 * @return the pattern, {@link java.text.SimpleDateFormat} compatible
480 */
481 @Override
482 public String getPattern() {
483 return printer.getPattern();
484 }
485
486 /**
487 * <p>Gets the time zone used by this formatter.</p>
488 *
489 * <p>This zone is always used for {@code Date} formatting. </p>
490 *
491 * @return the time zone
492 */
493 @Override
494 public TimeZone getTimeZone() {
495 return printer.getTimeZone();
496 }
497
498 /**
499 * <p>Gets the locale used by this formatter.</p>
500 *
501 * @return the locale
502 */
503 @Override
504 public Locale getLocale() {
505 return printer.getLocale();
506 }
507
508 /**
509 * <p>Gets an estimate for the maximum string length that the
510 * formatter will produce.</p>
511 *
512 * <p>The actual formatted length will almost always be less than or
513 * equal to this amount.</p>
514 *
515 * @return the maximum formatted length
516 */
517 public int getMaxLengthEstimate() {
518 return printer.getMaxLengthEstimate();
519 }
520
521 public String toPattern() {
522 return printer.getPattern();
523 }
524
525 // Basics
526 //-----------------------------------------------------------------------
527 /**
528 * <p>Compares two objects for equality.</p>
529 *
530 * @param obj the object to compare to
531 * @return {@code true} if equal
532 */
533 @Override
534 public boolean equals(final Object obj) {
535 if (obj instanceof FastDateFormat == false) {
536 return false;
537 }
538 final FastDateFormat other = (FastDateFormat) obj;
539 // no need to check parser, as it has same invariants as printer
540 return printer.equals(other.printer);
541 }
542
543 /**
544 * <p>Returns a hashcode compatible with equals.</p>
545 *
546 * @return a hashcode compatible with equals
547 */
548 @Override
549 public int hashCode() {
550 return printer.hashCode();
551 }
552
553 /**
554 * <p>Gets a debugging string version of this formatter.</p>
555 *
556 * @return a debugging string
557 */
558 @Override
559 public String toString() {
560 return "FastDateFormat[" + printer.getPattern() + "," + printer.getLocale() + "," + printer.getTimeZone().getID() + "]";
561 }
562
563
564 /**
565 * <p>Performs the formatting by applying the rules to the
566 * specified calendar.</p>
567 *
568 * @param calendar the calendar to format
569 * @param buf the buffer to format into
570 * @return the specified string buffer
571 */
572 protected StringBuilder applyRules(final Calendar calendar, final StringBuilder buf) {
573 return printer.applyRules(calendar, buf);
574 }
575
576
577 }
578
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.logging.log4j.core.util.datetime;
17
18 import java.io.IOException;
19 import java.io.ObjectInputStream;
20 import java.io.Serializable;
21 import java.text.DateFormatSymbols;
22 import java.text.ParseException;
23 import java.text.ParsePosition;
24 import java.util.ArrayList;
25 import java.util.Calendar;
26 import java.util.Date;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Locale;
30 import java.util.Map;
31 import java.util.TimeZone;
32 import java.util.concurrent.ConcurrentHashMap;
33 import java.util.concurrent.ConcurrentMap;
34 import java.util.regex.Matcher;
35 import java.util.regex.Pattern;
36
37 /**
38 * Copied from Commons Lang 3
39 */
40 public class FastDateParser implements DateParser, Serializable {
41 /**
42 * Required for serialization support.
43 *
44 * @see java.io.Serializable
45 */
46 private static final long serialVersionUID = 3L;
47
48 static final Locale JAPANESE_IMPERIAL = new Locale("ja","JP","JP");
49
50 // defining fields
51 private final String pattern;
52 private final TimeZone timeZone;
53 private final Locale locale;
54 private final int century;
55 private final int startYear;
56 private final boolean lenient;
57
58 // derived fields
59 private transient Pattern parsePattern;
60 private transient Strategy[] strategies;
61
62 // dynamic fields to communicate with Strategy
63 private transient String currentFormatField;
64 private transient Strategy nextStrategy;
65
66 /**
67 * <p>Constructs a new FastDateParser.</p>
68 *
69 * Use {@link FastDateFormat#getInstance(String, TimeZone, Locale)} or another variation of the
70 * factory methods of {@link FastDateFormat} to get a cached FastDateParser instance.
71 *
72 * @param pattern non-null {@link java.text.SimpleDateFormat} compatible
73 * pattern
74 * @param timeZone non-null time zone to use
75 * @param locale non-null locale
76 */
77 protected FastDateParser(final String pattern, final TimeZone timeZone, final Locale locale) {
78 this(pattern, timeZone, locale, null, true);
79 }
80
81 /**
82 * <p>Constructs a new FastDateParser.</p>
83 *
84 * @param pattern non-null {@link java.text.SimpleDateFormat} compatible
85 * pattern
86 * @param timeZone non-null time zone to use
87 * @param locale non-null locale
88 * @param centuryStart The start of the century for 2 digit year parsing
89 *
90 * @since 3.3
91 */
92 protected FastDateParser(final String pattern, final TimeZone timeZone, final Locale locale, final Date centuryStart) {
93 this(pattern, timeZone, locale, centuryStart, true);
94 }
95
96 /**
97 * <p>Constructs a new FastDateParser.</p>
98 *
99 * @param pattern non-null {@link java.text.SimpleDateFormat} compatible
100 * pattern
101 * @param timeZone non-null time zone to use
102 * @param locale non-null locale
103 * @param centuryStart The start of the century for 2 digit year parsing
104 * @param lenient if true, non-standard values for Calendar fields should be accepted;
105 * if false, non-standard values will cause a ParseException to be thrown {@link Calendar#setLenient(boolean)}
106 *
107 * @since 3.5
108 */
109 protected FastDateParser(final String pattern, final TimeZone timeZone, final Locale locale,
110 final Date centuryStart, final boolean lenient) {
111 this.pattern = pattern;
112 this.timeZone = timeZone;
113 this.locale = locale;
114 this.lenient = lenient;
115
116 final Calendar definingCalendar = Calendar.getInstance(timeZone, locale);
117
118 int centuryStartYear;
119 if(centuryStart!=null) {
120 definingCalendar.setTime(centuryStart);
121 centuryStartYear= definingCalendar.get(Calendar.YEAR);
122 }
123 else if(locale.equals(JAPANESE_IMPERIAL)) {
124 centuryStartYear= 0;
125 }
126 else {
127 // from 80 years ago to 20 years from now
128 definingCalendar.setTime(new Date());
129 centuryStartYear= definingCalendar.get(Calendar.YEAR)-80;
130 }
131 century= centuryStartYear / 100 * 100;
132 startYear= centuryStartYear - century;
133
134 init(definingCalendar);
135 }
136
137 /**
138 * Initialize derived fields from defining fields.
139 * This is called from constructor and from readObject (de-serialization)
140 *
141 * @param definingCalendar the {@link java.util.Calendar} instance used to initialize this FastDateParser
142 */
143 private void init(final Calendar definingCalendar) {
144
145 final StringBuilder regex= new StringBuilder();
146 final List<Strategy> collector = new ArrayList<Strategy>();
147
148 final Matcher patternMatcher= formatPattern.matcher(pattern);
149 if(!patternMatcher.lookingAt()) {
150 throw new IllegalArgumentException(
151 "Illegal pattern character '" + pattern.charAt(patternMatcher.regionStart()) + "'");
152 }
153
154 currentFormatField= patternMatcher.group();
155 Strategy currentStrategy= getStrategy(currentFormatField, definingCalendar);
156 for(;;) {
157 patternMatcher.region(patternMatcher.end(), patternMatcher.regionEnd());
158 if(!patternMatcher.lookingAt()) {
159 nextStrategy = null;
160 break;
161 }
162 final String nextFormatField= patternMatcher.group();
163 nextStrategy = getStrategy(nextFormatField, definingCalendar);
164 if(currentStrategy.addRegex(this, regex)) {
165 collector.add(currentStrategy);
166 }
167 currentFormatField= nextFormatField;
168 currentStrategy= nextStrategy;
169 }
170 if (patternMatcher.regionStart() != patternMatcher.regionEnd()) {
171 throw new IllegalArgumentException("Failed to parse \""+pattern+"\" ; gave up at index "+patternMatcher.regionStart());
172 }
173 if(currentStrategy.addRegex(this, regex)) {
174 collector.add(currentStrategy);
175 }
176 currentFormatField= null;
177 strategies= collector.toArray(new Strategy[collector.size()]);
178 parsePattern= Pattern.compile(regex.toString());
179 }
180
181 // Accessors
182 //-----------------------------------------------------------------------
183 /* (non-Javadoc)
184 * @see org.apache.commons.lang3.time.DateParser#getPattern()
185 */
186 @Override
187 public String getPattern() {
188 return pattern;
189 }
190
191 /* (non-Javadoc)
192 * @see org.apache.commons.lang3.time.DateParser#getTimeZone()
193 */
194 @Override
195 public TimeZone getTimeZone() {
196 return timeZone;
197 }
198
199 /* (non-Javadoc)
200 * @see org.apache.commons.lang3.time.DateParser#getLocale()
201 */
202 @Override
203 public Locale getLocale() {
204 return locale;
205 }
206
207 /**
208 * Returns the generated pattern (for testing purposes).
209 *
210 * @return the generated pattern
211 */
212 Pattern getParsePattern() {
213 return parsePattern;
214 }
215
216 // Basics
217 //-----------------------------------------------------------------------
218 /**
219 * <p>Compare another object for equality with this object.</p>
220 *
221 * @param obj the object to compare to
222 * @return <code>true</code>if equal to this instance
223 */
224 @Override
225 public boolean equals(final Object obj) {
226 if (! (obj instanceof FastDateParser) ) {
227 return false;
228 }
229 final FastDateParser other = (FastDateParser) obj;
230 return pattern.equals(other.pattern)
231 && timeZone.equals(other.timeZone)
232 && locale.equals(other.locale);
233 }
234
235 /**
236 * <p>Return a hashcode compatible with equals.</p>
237 *
238 * @return a hashcode compatible with equals
239 */
240 @Override
241 public int hashCode() {
242 return pattern.hashCode() + 13 * (timeZone.hashCode() + 13 * locale.hashCode());
243 }
244
245 /**
246 * <p>Get a string version of this formatter.</p>
247 *
248 * @return a debugging string
249 */
250 @Override
251 public String toString() {
252 return "FastDateParser[" + pattern + "," + locale + "," + timeZone.getID() + "]";
253 }
254
255 // Serializing
256 //-----------------------------------------------------------------------
257 /**
258 * Create the object after serialization. This implementation reinitializes the
259 * transient properties.
260 *
261 * @param in ObjectInputStream from which the object is being deserialized.
262 * @throws IOException if there is an IO issue.
263 * @throws ClassNotFoundException if a class cannot be found.
264 */
265 private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
266 in.defaultReadObject();
267
268 final Calendar definingCalendar = Calendar.getInstance(timeZone, locale);
269 init(definingCalendar);
270 }
271
272 /* (non-Javadoc)
273 * @see org.apache.commons.lang3.time.DateParser#parseObject(java.lang.String)
274 */
275 @Override
276 public Object parseObject(final String source) throws ParseException {
277 return parse(source);
278 }
279
280 /* (non-Javadoc)
281 * @see org.apache.commons.lang3.time.DateParser#parse(java.lang.String)
282 */
283 @Override
284 public Date parse(final String source) throws ParseException {
285 final Date date= parse(source, new ParsePosition(0));
286 if(date==null) {
287 // Add a note re supported date range
288 if (locale.equals(JAPANESE_IMPERIAL)) {
289 throw new ParseException(
290 "(The " +locale + " locale does not support dates before 1868 AD)\n" +
291 "Unparseable date: \""+source+"\" does not match "+parsePattern.pattern(), 0);
292 }
293 throw new ParseException("Unparseable date: \""+source+"\" does not match "+parsePattern.pattern(), 0);
294 }
295 return date;
296 }
297
298 /* (non-Javadoc)
299 * @see org.apache.commons.lang3.time.DateParser#parseObject(java.lang.String, java.text.ParsePosition)
300 */
301 @Override
302 public Object parseObject(final String source, final ParsePosition pos) {
303 return parse(source, pos);
304 }
305
306 /**
307 * This implementation updates the ParsePosition if the parse succeeeds.
308 * However, unlike the method {@link java.text.SimpleDateFormat#parse(String, ParsePosition)}
309 * it is not able to set the error Index - i.e. {@link ParsePosition#getErrorIndex()} - if the parse fails.
310 * <p>
311 * To determine if the parse has succeeded, the caller must check if the current parse position
312 * given by {@link ParsePosition#getIndex()} has been updated. If the input buffer has been fully
313 * parsed, then the index will point to just after the end of the input buffer.
314 *
315 * {@inheritDoc}
316 */
317 @Override
318 public Date parse(final String source, final ParsePosition pos) {
319 final int offset= pos.getIndex();
320 final Matcher matcher= parsePattern.matcher(source.substring(offset));
321 if(!matcher.lookingAt()) {
322 return null;
323 }
324 // timing tests indicate getting new instance is 19% faster than cloning
325 final Calendar cal= Calendar.getInstance(timeZone, locale);
326 cal.clear();
327 cal.setLenient(lenient);
328
329 for(int i=0; i<strategies.length;) {
330 final Strategy strategy= strategies[i++];
331 strategy.setCalendar(this, cal, matcher.group(i));
332 }
333 pos.setIndex(offset+matcher.end());
334 return cal.getTime();
335 }
336
337 // Support for strategies
338 //-----------------------------------------------------------------------
339
340 private static StringBuilder simpleQuote(final StringBuilder sb, final String value) {
341 for(int i= 0; i<value.length(); ++i) {
342 final char c= value.charAt(i);
343 switch(c) {
344 case '\\':
345 case '^':
346 case '$':
347 case '.':
348 case '|':
349 case '?':
350 case '*':
351 case '+':
352 case '(':
353 case ')':
354 case '[':
355 case '{':
356 sb.append('\\');
357 default:
358 sb.append(c);
359 }
360 }
361 return sb;
362 }
363
364 /**
365 * Escape constant fields into regular expression
366 * @param regex The destination regex
367 * @param value The source field
368 * @param unquote If true, replace two success quotes ('') with single quote (')
369 * @return The <code>StringBuilder</code>
370 */
371 private static StringBuilder escapeRegex(final StringBuilder regex, final String value, final boolean unquote) {
372 regex.append("\\Q");
373 for(int i= 0; i<value.length(); ++i) {
374 char c= value.charAt(i);
375 switch(c) {
376 case '\'':
377 if(unquote) {
378 if(++i==value.length()) {
379 return regex;
380 }
381 c= value.charAt(i);
382 }
383 break;
384 case '\\':
385 if(++i==value.length()) {
386 break;
387 }
388 /*
389 * If we have found \E, we replace it with \E\\E\Q, i.e. we stop the quoting,
390 * quote the \ in \E, then restart the quoting.
391 *
392 * Otherwise we just output the two characters.
393 * In each case the initial \ needs to be output and the final char is done at the end
394 */
395 regex.append(c); // we always want the original \
396 c = value.charAt(i); // Is it followed by E ?
397 if (c == 'E') { // \E detected
398 regex.append("E\\\\E\\"); // see comment above
399 c = 'Q'; // appended below
400 }
401 break;
402 default:
403 break;
404 }
405 regex.append(c);
406 }
407 regex.append("\\E");
408 return regex;
409 }
410
411
412 /**
413 * Get the short and long values displayed for a field
414 * @param field The field of interest
415 * @param definingCalendar The calendar to obtain the short and long values
416 * @param locale The locale of display names
417 * @return A Map of the field key / value pairs
418 */
419 private static Map<String, Integer> getDisplayNames(final int field, final Calendar definingCalendar, final Locale locale) {
420 return definingCalendar.getDisplayNames(field, Calendar.ALL_STYLES, locale);
421 }
422
423 /**
424 * Adjust dates to be within appropriate century
425 * @param twoDigitYear The year to adjust
426 * @return A value between centuryStart(inclusive) to centuryStart+100(exclusive)
427 */
428 private int adjustYear(final int twoDigitYear) {
429 final int trial= century + twoDigitYear;
430 return twoDigitYear>=startYear ?trial :trial+100;
431 }
432
433 /**
434 * Is the next field a number?
435 * @return true, if next field will be a number
436 */
437 boolean isNextNumber() {
438 return nextStrategy!=null && nextStrategy.isNumber();
439 }
440
441 /**
442 * What is the width of the current field?
443 * @return The number of characters in the current format field
444 */
445 int getFieldWidth() {
446 return currentFormatField.length();
447 }
448
449 /**
450 * A strategy to parse a single field from the parsing pattern
451 */
452 private static abstract class Strategy {
453
454 /**
455 * Is this field a number?
456 * The default implementation returns false.
457 *
458 * @return true, if field is a number
459 */
460 boolean isNumber() {
461 return false;
462 }
463
464 /**
465 * Set the Calendar with the parsed field.
466 *
467 * The default implementation does nothing.
468 *
469 * @param parser The parser calling this strategy
470 * @param cal The <code>Calendar</code> to set
471 * @param value The parsed field to translate and set in cal
472 */
473 void setCalendar(final FastDateParser parser, final Calendar cal, final String value) {
474
475 }
476
477 /**
478 * Generate a <code>Pattern</code> regular expression to the <code>StringBuilder</code>
479 * which will accept this field
480 * @param parser The parser calling this strategy
481 * @param regex The <code>StringBuilder</code> to append to
482 * @return true, if this field will set the calendar;
483 * false, if this field is a constant value
484 */
485 abstract boolean addRegex(FastDateParser parser, StringBuilder regex);
486
487 }
488
489 /**
490 * A <code>Pattern</code> to parse the user supplied SimpleDateFormat pattern
491 */
492 private static final Pattern formatPattern= Pattern.compile(
493 "D+|E+|F+|G+|H+|K+|M+|S+|W+|X+|Z+|a+|d+|h+|k+|m+|s+|w+|y+|z+|''|'[^']++(''[^']*+)*+'|[^'A-Za-z]++");
494
495 /**
496 * Obtain a Strategy given a field from a SimpleDateFormat pattern
497 * @param formatField A sub-sequence of the SimpleDateFormat pattern
498 * @param definingCalendar The calendar to obtain the short and long values
499 * @return The Strategy that will handle parsing for the field
500 */
501 private Strategy getStrategy(final String formatField, final Calendar definingCalendar) {
502 switch(formatField.charAt(0)) {
503 case '\'':
504 if(formatField.length()>2) {
505 return new CopyQuotedStrategy(formatField.substring(1, formatField.length()-1));
506 }
507 //$FALL-THROUGH$
508 default:
509 return new CopyQuotedStrategy(formatField);
510 case 'D':
511 return DAY_OF_YEAR_STRATEGY;
512 case 'E':
513 return getLocaleSpecificStrategy(Calendar.DAY_OF_WEEK, definingCalendar);
514 case 'F':
515 return DAY_OF_WEEK_IN_MONTH_STRATEGY;
516 case 'G':
517 return getLocaleSpecificStrategy(Calendar.ERA, definingCalendar);
518 case 'H': // Hour in day (0-23)
519 return HOUR_OF_DAY_STRATEGY;
520 case 'K': // Hour in am/pm (0-11)
521 return HOUR_STRATEGY;
522 case 'M':
523 return formatField.length()>=3 ?getLocaleSpecificStrategy(Calendar.MONTH, definingCalendar) :NUMBER_MONTH_STRATEGY;
524 case 'S':
525 return MILLISECOND_STRATEGY;
526 case 'W':
527 return WEEK_OF_MONTH_STRATEGY;
528 case 'a':
529 return getLocaleSpecificStrategy(Calendar.AM_PM, definingCalendar);
530 case 'd':
531 return DAY_OF_MONTH_STRATEGY;
532 case 'h': // Hour in am/pm (1-12), i.e. midday/midnight is 12, not 0
533 return HOUR12_STRATEGY;
534 case 'k': // Hour in day (1-24), i.e. midnight is 24, not 0
535 return HOUR24_OF_DAY_STRATEGY;
536 case 'm':
537 return MINUTE_STRATEGY;
538 case 's':
539 return SECOND_STRATEGY;
540 case 'w':
541 return WEEK_OF_YEAR_STRATEGY;
542 case 'y':
543 return formatField.length()>2 ?LITERAL_YEAR_STRATEGY :ABBREVIATED_YEAR_STRATEGY;
544 case 'X':
545 return ISO8601TimeZoneStrategy.getStrategy(formatField.length());
546 case 'Z':
547 if (formatField.equals("ZZ")) {
548 return ISO_8601_STRATEGY;
549 }
550 //$FALL-THROUGH$
551 case 'z':
552 return getLocaleSpecificStrategy(Calendar.ZONE_OFFSET, definingCalendar);
553 }
554 }
555
556 @SuppressWarnings("unchecked") // OK because we are creating an array with no entries
557 private static final ConcurrentMap<Locale, Strategy>[] caches = new ConcurrentMap[Calendar.FIELD_COUNT];
558
559 /**
560 * Get a cache of Strategies for a particular field
561 * @param field The Calendar field
562 * @return a cache of Locale to Strategy
563 */
564 private static ConcurrentMap<Locale, Strategy> getCache(final int field) {
565 synchronized(caches) {
566 if(caches[field]==null) {
567 caches[field]= new ConcurrentHashMap<Locale,Strategy>(3);
568 }
569 return caches[field];
570 }
571 }
572
573 /**
574 * Construct a Strategy that parses a Text field
575 * @param field The Calendar field
576 * @param definingCalendar The calendar to obtain the short and long values
577 * @return a TextStrategy for the field and Locale
578 */
579 private Strategy getLocaleSpecificStrategy(final int field, final Calendar definingCalendar) {
580 final ConcurrentMap<Locale,Strategy> cache = getCache(field);
581 Strategy strategy= cache.get(locale);
582 if(strategy==null) {
583 strategy= field==Calendar.ZONE_OFFSET
584 ? new TimeZoneStrategy(locale)
585 : new CaseInsensitiveTextStrategy(field, definingCalendar, locale);
586 final Strategy inCache= cache.putIfAbsent(locale, strategy);
587 if(inCache!=null) {
588 return inCache;
589 }
590 }
591 return strategy;
592 }
593
594 /**
595 * A strategy that copies the static or quoted field in the parsing pattern
596 */
597 private static class CopyQuotedStrategy extends Strategy {
598 private final String formatField;
599
600 /**
601 * Construct a Strategy that ensures the formatField has literal text
602 * @param formatField The literal text to match
603 */
604 CopyQuotedStrategy(final String formatField) {
605 this.formatField= formatField;
606 }
607
608 /**
609 * {@inheritDoc}
610 */
611 @Override
612 boolean isNumber() {
613 char c= formatField.charAt(0);
614 if(c=='\'') {
615 c= formatField.charAt(1);
616 }
617 return Character.isDigit(c);
618 }
619
620 /**
621 * {@inheritDoc}
622 */
623 @Override
624 boolean addRegex(final FastDateParser parser, final StringBuilder regex) {
625 escapeRegex(regex, formatField, true);
626 return false;
627 }
628 }
629
630 /**
631 * A strategy that handles a text field in the parsing pattern
632 */
633 private static class CaseInsensitiveTextStrategy extends Strategy {
634 private final int field;
635 private final Locale locale;
636 private final Map<String, Integer> lKeyValues;
637
638 /**
639 * Construct a Strategy that parses a Text field
640 * @param field The Calendar field
641 * @param definingCalendar The Calendar to use
642 * @param locale The Locale to use
643 */
644 CaseInsensitiveTextStrategy(final int field, final Calendar definingCalendar, final Locale locale) {
645 this.field= field;
646 this.locale= locale;
647 final Map<String, Integer> keyValues = getDisplayNames(field, definingCalendar, locale);
648 this.lKeyValues= new HashMap<String,Integer>();
649
650 for(final Map.Entry<String, Integer> entry : keyValues.entrySet()) {
651 lKeyValues.put(entry.getKey().toLowerCase(locale), entry.getValue());
652 }
653 }
654
655 /**
656 * {@inheritDoc}
657 */
658 @Override
659 boolean addRegex(final FastDateParser parser, final StringBuilder regex) {
660 regex.append("((?iu)");
661 for(final String textKeyValue : lKeyValues.keySet()) {
662 simpleQuote(regex, textKeyValue).append('|');
663 }
664 regex.setCharAt(regex.length()-1, ')');
665 return true;
666 }
667
668 /**
669 * {@inheritDoc}
670 */
671 @Override
672 void setCalendar(final FastDateParser parser, final Calendar cal, final String value) {
673 final Integer iVal = lKeyValues.get(value.toLowerCase(locale));
674 if(iVal == null) {
675 final StringBuilder sb= new StringBuilder(value);
676 sb.append(" not in (");
677 for(final String textKeyValue : lKeyValues.keySet()) {
678 sb.append(textKeyValue).append(' ');
679 }
680 sb.setCharAt(sb.length()-1, ')');
681 throw new IllegalArgumentException(sb.toString());
682 }
683 cal.set(field, iVal.intValue());
684 }
685 }
686
687
688 /**
689 * A strategy that handles a number field in the parsing pattern
690 */
691 private static class NumberStrategy extends Strategy {
692 private final int field;
693
694 /**
695 * Construct a Strategy that parses a Number field
696 * @param field The Calendar field
697 */
698 NumberStrategy(final int field) {
699 this.field= field;
700 }
701
702 /**
703 * {@inheritDoc}
704 */
705 @Override
706 boolean isNumber() {
707 return true;
708 }
709
710 /**
711 * {@inheritDoc}
712 */
713 @Override
714 boolean addRegex(final FastDateParser parser, final StringBuilder regex) {
715 // See LANG-954: We use {Nd} rather than {IsNd} because Android does not support the Is prefix
716 if(parser.isNextNumber()) {
717 regex.append("(\\p{Nd}{").append(parser.getFieldWidth()).append("}+)");
718 }
719 else {
720 regex.append("(\\p{Nd}++)");
721 }
722 return true;
723 }
724
725 /**
726 * {@inheritDoc}
727 */
728 @Override
729 void setCalendar(final FastDateParser parser, final Calendar cal, final String value) {
730 cal.set(field, modify(Integer.parseInt(value)));
731 }
732
733 /**
734 * Make any modifications to parsed integer
735 * @param iValue The parsed integer
736 * @return The modified value
737 */
738 int modify(final int iValue) {
739 return iValue;
740 }
741 }
742
743 private static final Strategy ABBREVIATED_YEAR_STRATEGY = new NumberStrategy(Calendar.YEAR) {
744 /**
745 * {@inheritDoc}
746 */
747 @Override
748 void setCalendar(final FastDateParser parser, final Calendar cal, final String value) {
749 int iValue= Integer.parseInt(value);
750 if(iValue<100) {
751 iValue= parser.adjustYear(iValue);
752 }
753 cal.set(Calendar.YEAR, iValue);
754 }
755 };
756
757 /**
758 * A strategy that handles a timezone field in the parsing pattern
759 */
760 static class TimeZoneStrategy extends Strategy {
761 private static final String RFC_822_TIME_ZONE = "[+-]\\d{4}";
762 private static final String GMT_OPTION= "GMT[+-]\\d{1,2}:\\d{2}";
763
764 private final Locale locale;
765 private final Map<String, TimeZone> tzNames= new HashMap<String, TimeZone>();
766 private final String validTimeZoneChars;
767
768 /**
769 * Index of zone id
770 */
771 private static final int ID = 0;
772
773 /**
774 * Construct a Strategy that parses a TimeZone
775 * @param locale The Locale
776 */
777 TimeZoneStrategy(final Locale locale) {
778 this.locale = locale;
779
780 final StringBuilder sb = new StringBuilder();
781 sb.append('(' + RFC_822_TIME_ZONE + "|(?iu)" + GMT_OPTION );
782
783 final String[][] zones = DateFormatSymbols.getInstance(locale).getZoneStrings();
784 for (final String[] zoneNames : zones) {
785 final String tzId = zoneNames[ID];
786 if (tzId.equalsIgnoreCase("GMT")) {
787 continue;
788 }
789 final TimeZone tz = TimeZone.getTimeZone(tzId);
790 for(int i= 1; i<zoneNames.length; ++i) {
791 final String zoneName = zoneNames[i].toLowerCase(locale);
792 if (!tzNames.containsKey(zoneName)){
793 tzNames.put(zoneName, tz);
794 simpleQuote(sb.append('|'), zoneName);
795 }
796 }
797 }
798
799 sb.append(')');
800 validTimeZoneChars = sb.toString();
801 }
802
803 /**
804 * {@inheritDoc}
805 */
806 @Override
807 boolean addRegex(final FastDateParser parser, final StringBuilder regex) {
808 regex.append(validTimeZoneChars);
809 return true;
810 }
811
812 /**
813 * {@inheritDoc}
814 */
815 @Override
816 void setCalendar(final FastDateParser parser, final Calendar cal, final String value) {
817 TimeZone tz;
818 if(value.charAt(0)=='+' || value.charAt(0)=='-') {
819 tz= TimeZone.getTimeZone("GMT"+value);
820 }
821 else if(value.regionMatches(true, 0, "GMT", 0, 3)) {
822 tz= TimeZone.getTimeZone(value.toUpperCase());
823 }
824 else {
825 tz= tzNames.get(value.toLowerCase(locale));
826 if(tz==null) {
827 throw new IllegalArgumentException(value + " is not a supported timezone name");
828 }
829 }
830 cal.setTimeZone(tz);
831 }
832 }
833
834 private static class ISO8601TimeZoneStrategy extends Strategy {
835 // Z, +hh, -hh, +hhmm, -hhmm, +hh:mm or -hh:mm
836 private final String pattern;
837
838 /**
839 * Construct a Strategy that parses a TimeZone
840 * @param pattern The Pattern
841 */
842 ISO8601TimeZoneStrategy(final String pattern) {
843 this.pattern = pattern;
844 }
845
846 /**
847 * {@inheritDoc}
848 */
849 @Override
850 boolean addRegex(final FastDateParser parser, final StringBuilder regex) {
851 regex.append(pattern);
852 return true;
853 }
854
855 /**
856 * {@inheritDoc}
857 */
858 @Override
859 void setCalendar(final FastDateParser parser, final Calendar cal, final String value) {
860 if (value.equals("Z")) {
861 cal.setTimeZone(TimeZone.getTimeZone("UTC"));
862 } else {
863 cal.setTimeZone(TimeZone.getTimeZone("GMT" + value));
864 }
865 }
866
867 private static final Strategy ISO_8601_1_STRATEGY = new ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}))");
868 private static final Strategy ISO_8601_2_STRATEGY = new ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}\\d{2}))");
869 private static final Strategy ISO_8601_3_STRATEGY = new ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}(?::)\\d{2}))");
870
871 /**
872 * Factory method for ISO8601TimeZoneStrategies.
873 *
874 * @param tokenLen a token indicating the length of the TimeZone String to be formatted.
875 * @return a ISO8601TimeZoneStrategy that can format TimeZone String of length {@code tokenLen}. If no such
876 * strategy exists, an IllegalArgumentException will be thrown.
877 */
878 static Strategy getStrategy(final int tokenLen) {
879 switch(tokenLen) {
880 case 1:
881 return ISO_8601_1_STRATEGY;
882 case 2:
883 return ISO_8601_2_STRATEGY;
884 case 3:
885 return ISO_8601_3_STRATEGY;
886 default:
887 throw new IllegalArgumentException("invalid number of X");
888 }
889 }
890 }
891
892 private static final Strategy NUMBER_MONTH_STRATEGY = new NumberStrategy(Calendar.MONTH) {
893 @Override
894 int modify(final int iValue) {
895 return iValue-1;
896 }
897 };
898 private static final Strategy LITERAL_YEAR_STRATEGY = new NumberStrategy(Calendar.YEAR);
899 private static final Strategy WEEK_OF_YEAR_STRATEGY = new NumberStrategy(Calendar.WEEK_OF_YEAR);
900 private static final Strategy WEEK_OF_MONTH_STRATEGY = new NumberStrategy(Calendar.WEEK_OF_MONTH);
901 private static final Strategy DAY_OF_YEAR_STRATEGY = new NumberStrategy(Calendar.DAY_OF_YEAR);
902 private static final Strategy DAY_OF_MONTH_STRATEGY = new NumberStrategy(Calendar.DAY_OF_MONTH);
903 private static final Strategy DAY_OF_WEEK_IN_MONTH_STRATEGY = new NumberStrategy(Calendar.DAY_OF_WEEK_IN_MONTH);
904 private static final Strategy HOUR_OF_DAY_STRATEGY = new NumberStrategy(Calendar.HOUR_OF_DAY);
905 private static final Strategy HOUR24_OF_DAY_STRATEGY = new NumberStrategy(Calendar.HOUR_OF_DAY) {
906 @Override
907 int modify(final int iValue) {
908 return iValue == 24 ? 0 : iValue;
909 }
910 };
911 private static final Strategy HOUR12_STRATEGY = new NumberStrategy(Calendar.HOUR) {
912 @Override
913 int modify(final int iValue) {
914 return iValue == 12 ? 0 : iValue;
915 }
916 };
917 private static final Strategy HOUR_STRATEGY = new NumberStrategy(Calendar.HOUR);
918 private static final Strategy MINUTE_STRATEGY = new NumberStrategy(Calendar.MINUTE);
919 private static final Strategy SECOND_STRATEGY = new NumberStrategy(Calendar.SECOND);
920 private static final Strategy MILLISECOND_STRATEGY = new NumberStrategy(Calendar.MILLISECOND);
921 private static final Strategy ISO_8601_STRATEGY = new ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}(?::?\\d{2})?))");
922
923
924 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.logging.log4j.core.util.datetime;
17
18 import java.io.IOException;
19 import java.io.ObjectInputStream;
20 import java.io.Serializable;
21 import java.text.DateFormat;
22 import java.text.DateFormatSymbols;
23 import java.text.FieldPosition;
24 import java.util.ArrayList;
25 import java.util.Calendar;
26 import java.util.Date;
27 import java.util.GregorianCalendar;
28 import java.util.List;
29 import java.util.Locale;
30 import java.util.TimeZone;
31 import java.util.concurrent.ConcurrentHashMap;
32 import java.util.concurrent.ConcurrentMap;
33
34 /**
35 * Copied from Commons Lang 3
36 *
37 */
38 public class FastDatePrinter implements DatePrinter, Serializable {
39 // A lot of the speed in this class comes from caching, but some comes
40 // from the special int to StringBuilder conversion.
41 //
42 // The following produces a padded 2 digit number:
43 // buffer.append((char)(value / 10 + '0'));
44 // buffer.append((char)(value % 10 + '0'));
45 //
46 // Note that the fastest append to StringBuilder is a single char (used here).
47 // Note that Integer.toString() is not called, the conversion is simply
48 // taking the value and adding (mathematically) the ASCII value for '0'.
49 // So, don't change this code! It works and is very fast.
50
51 /**
52 * Required for serialization support.
53 *
54 * @see java.io.Serializable
55 */
56 private static final long serialVersionUID = 1L;
57
58 /**
59 * FULL locale dependent date or time style.
60 */
61 public static final int FULL = DateFormat.FULL;
62 /**
63 * LONG locale dependent date or time style.
64 */
65 public static final int LONG = DateFormat.LONG;
66 /**
67 * MEDIUM locale dependent date or time style.
68 */
69 public static final int MEDIUM = DateFormat.MEDIUM;
70 /**
71 * SHORT locale dependent date or time style.
72 */
73 public static final int SHORT = DateFormat.SHORT;
74
75 /**
76 * The pattern.
77 */
78 private final String mPattern;
79 /**
80 * The time zone.
81 */
82 private final TimeZone mTimeZone;
83 /**
84 * The locale.
85 */
86 private final Locale mLocale;
87 /**
88 * The parsed rules.
89 */
90 private transient Rule[] mRules;
91 /**
92 * The estimated maximum length.
93 */
94 private transient int mMaxLengthEstimate;
95
96 // Constructor
97 //-----------------------------------------------------------------------
98 /**
99 * <p>Constructs a new FastDatePrinter.</p>
100 * Use {@link FastDateFormat#getInstance(String, TimeZone, Locale)} or another variation of the
101 * factory methods of {@link FastDateFormat} to get a cached FastDatePrinter instance.
102 *
103 * @param pattern {@link java.text.SimpleDateFormat} compatible pattern
104 * @param timeZone non-null time zone to use
105 * @param locale non-null locale to use
106 * @throws NullPointerException if pattern, timeZone, or locale is null.
107 */
108 protected FastDatePrinter(final String pattern, final TimeZone timeZone, final Locale locale) {
109 mPattern = pattern;
110 mTimeZone = timeZone;
111 mLocale = locale;
112
113 init();
114 }
115
116 /**
117 * <p>Initializes the instance for first use.</p>
118 */
119 private void init() {
120 final List<Rule> rulesList = parsePattern();
121 mRules = rulesList.toArray(new Rule[rulesList.size()]);
122
123 int len = 0;
124 for (int i=mRules.length; --i >= 0; ) {
125 len += mRules[i].estimateLength();
126 }
127
128 mMaxLengthEstimate = len;
129 }
130
131 // Parse the pattern
132 //-----------------------------------------------------------------------
133 /**
134 * <p>Returns a list of Rules given a pattern.</p>
135 *
136 * @return a {@code List} of Rule objects
137 * @throws IllegalArgumentException if pattern is invalid
138 */
139 protected List<Rule> parsePattern() {
140 final DateFormatSymbols symbols = new DateFormatSymbols(mLocale);
141 final List<Rule> rules = new ArrayList<Rule>();
142
143 final String[] ERAs = symbols.getEras();
144 final String[] months = symbols.getMonths();
145 final String[] shortMonths = symbols.getShortMonths();
146 final String[] weekdays = symbols.getWeekdays();
147 final String[] shortWeekdays = symbols.getShortWeekdays();
148 final String[] AmPmStrings = symbols.getAmPmStrings();
149
150 final int length = mPattern.length();
151 final int[] indexRef = new int[1];
152
153 for (int i = 0; i < length; i++) {
154 indexRef[0] = i;
155 final String token = parseToken(mPattern, indexRef);
156 i = indexRef[0];
157
158 final int tokenLen = token.length();
159 if (tokenLen == 0) {
160 break;
161 }
162
163 Rule rule;
164 final char c = token.charAt(0);
165
166 switch (c) {
167 case 'G': // era designator (text)
168 rule = new TextField(Calendar.ERA, ERAs);
169 break;
170 case 'y': // year (number)
171 if (tokenLen == 2) {
172 rule = TwoDigitYearField.INSTANCE;
173 } else {
174 rule = selectNumberRule(Calendar.YEAR, tokenLen < 4 ? 4 : tokenLen);
175 }
176 break;
177 case 'M': // month in year (text and number)
178 if (tokenLen >= 4) {
179 rule = new TextField(Calendar.MONTH, months);
180 } else if (tokenLen == 3) {
181 rule = new TextField(Calendar.MONTH, shortMonths);
182 } else if (tokenLen == 2) {
183 rule = TwoDigitMonthField.INSTANCE;
184 } else {
185 rule = UnpaddedMonthField.INSTANCE;
186 }
187 break;
188 case 'd': // day in month (number)
189 rule = selectNumberRule(Calendar.DAY_OF_MONTH, tokenLen);
190 break;
191 case 'h': // hour in am/pm (number, 1..12)
192 rule = new TwelveHourField(selectNumberRule(Calendar.HOUR, tokenLen));
193 break;
194 case 'H': // hour in day (number, 0..23)
195 rule = selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen);
196 break;
197 case 'm': // minute in hour (number)
198 rule = selectNumberRule(Calendar.MINUTE, tokenLen);
199 break;
200 case 's': // second in minute (number)
201 rule = selectNumberRule(Calendar.SECOND, tokenLen);
202 break;
203 case 'S': // millisecond (number)
204 rule = selectNumberRule(Calendar.MILLISECOND, tokenLen);
205 break;
206 case 'E': // day in week (text)
207 rule = new TextField(Calendar.DAY_OF_WEEK, tokenLen < 4 ? shortWeekdays : weekdays);
208 break;
209 case 'D': // day in year (number)
210 rule = selectNumberRule(Calendar.DAY_OF_YEAR, tokenLen);
211 break;
212 case 'F': // day of week in month (number)
213 rule = selectNumberRule(Calendar.DAY_OF_WEEK_IN_MONTH, tokenLen);
214 break;
215 case 'w': // week in year (number)
216 rule = selectNumberRule(Calendar.WEEK_OF_YEAR, tokenLen);
217 break;
218 case 'W': // week in month (number)
219 rule = selectNumberRule(Calendar.WEEK_OF_MONTH, tokenLen);
220 break;
221 case 'a': // am/pm marker (text)
222 rule = new TextField(Calendar.AM_PM, AmPmStrings);
223 break;
224 case 'k': // hour in day (1..24)
225 rule = new TwentyFourHourField(selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen));
226 break;
227 case 'K': // hour in am/pm (0..11)
228 rule = selectNumberRule(Calendar.HOUR, tokenLen);
229 break;
230 case 'X': // ISO 8601
231 rule = Iso8601_Rule.getRule(tokenLen);
232 break;
233 case 'z': // time zone (text)
234 if (tokenLen >= 4) {
235 rule = new TimeZoneNameRule(mTimeZone, mLocale, TimeZone.LONG);
236 } else {
237 rule = new TimeZoneNameRule(mTimeZone, mLocale, TimeZone.SHORT);
238 }
239 break;
240 case 'Z': // time zone (value)
241 if (tokenLen == 1) {
242 rule = TimeZoneNumberRule.INSTANCE_NO_COLON;
243 } else if (tokenLen == 2) {
244 rule = Iso8601_Rule.ISO8601_HOURS_COLON_MINUTES;
245 } else {
246 rule = TimeZoneNumberRule.INSTANCE_COLON;
247 }
248 break;
249 case '\'': // literal text
250 final String sub = token.substring(1);
251 if (sub.length() == 1) {
252 rule = new CharacterLiteral(sub.charAt(0));
253 } else {
254 rule = new StringLiteral(sub);
255 }
256 break;
257 default:
258 throw new IllegalArgumentException("Illegal pattern component: " + token);
259 }
260
261 rules.add(rule);
262 }
263
264 return rules;
265 }
266
267 /**
268 * <p>Performs the parsing of tokens.</p>
269 *
270 * @param pattern the pattern
271 * @param indexRef index references
272 * @return parsed token
273 */
274 protected String parseToken(final String pattern, final int[] indexRef) {
275 final StringBuilder buf = new StringBuilder();
276
277 int i = indexRef[0];
278 final int length = pattern.length();
279
280 char c = pattern.charAt(i);
281 if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z') {
282 // Scan a run of the same character, which indicates a time
283 // pattern.
284 buf.append(c);
285
286 while (i + 1 < length) {
287 final char peek = pattern.charAt(i + 1);
288 if (peek == c) {
289 buf.append(c);
290 i++;
291 } else {
292 break;
293 }
294 }
295 } else {
296 // This will identify token as text.
297 buf.append('\'');
298
299 boolean inLiteral = false;
300
301 for (; i < length; i++) {
302 c = pattern.charAt(i);
303
304 if (c == '\'') {
305 if (i + 1 < length && pattern.charAt(i + 1) == '\'') {
306 // '' is treated as escaped '
307 i++;
308 buf.append(c);
309 } else {
310 inLiteral = !inLiteral;
311 }
312 } else if (!inLiteral &&
313 (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z')) {
314 i--;
315 break;
316 } else {
317 buf.append(c);
318 }
319 }
320 }
321
322 indexRef[0] = i;
323 return buf.toString();
324 }
325
326 /**
327 * <p>Gets an appropriate rule for the padding required.</p>
328 *
329 * @param field the field to get a rule for
330 * @param padding the padding required
331 * @return a new rule with the correct padding
332 */
333 protected NumberRule selectNumberRule(final int field, final int padding) {
334 switch (padding) {
335 case 1:
336 return new UnpaddedNumberField(field);
337 case 2:
338 return new TwoDigitNumberField(field);
339 default:
340 return new PaddedNumberField(field, padding);
341 }
342 }
343
344 // Format methods
345 //-----------------------------------------------------------------------
346 /**
347 * <p>Formats a {@code Date}, {@code Calendar} or
348 * {@code Long} (milliseconds) object.</p>
349 *
350 * @param obj the object to format
351 * @param toAppendTo the buffer to append to
352 * @param pos the position - ignored
353 * @return the buffer passed in
354 */
355 @Override
356 public StringBuilder format(final Object obj, final StringBuilder toAppendTo, final FieldPosition pos) {
357 if (obj instanceof Date) {
358 return format((Date) obj, toAppendTo);
359 } else if (obj instanceof Calendar) {
360 return format((Calendar) obj, toAppendTo);
361 } else if (obj instanceof Long) {
362 return format(((Long) obj).longValue(), toAppendTo);
363 } else {
364 throw new IllegalArgumentException("Unknown class: " +
365 (obj == null ? "<null>" : obj.getClass().getName()));
366 }
367 }
368
369 /* (non-Javadoc)
370 * @see org.apache.commons.lang3.time.DatePrinter#format(long)
371 */
372 @Override
373 public String format(final long millis) {
374 final Calendar c = newCalendar(); // hard code GregorianCalendar
375 c.setTimeInMillis(millis);
376 return applyRulesToString(c);
377 }
378
379 /**
380 * Creates a String representation of the given Calendar by applying the rules of this printer to it.
381 * @param c the Calender to apply the rules to.
382 * @return a String representation of the given Calendar.
383 */
384 private String applyRulesToString(final Calendar c) {
385 return applyRules(c, new StringBuilder(mMaxLengthEstimate)).toString();
386 }
387
388 /**
389 * Creation method for ne calender instances.
390 * @return a new Calendar instance.
391 */
392 private GregorianCalendar newCalendar() {
393 // hard code GregorianCalendar
394 return new GregorianCalendar(mTimeZone, mLocale);
395 }
396
397 /* (non-Javadoc)
398 * @see org.apache.commons.lang3.time.DatePrinter#format(java.util.Date)
399 */
400 @Override
401 public String format(final Date date) {
402 final Calendar c = newCalendar(); // hard code GregorianCalendar
403 c.setTime(date);
404 return applyRulesToString(c);
405 }
406
407 /* (non-Javadoc)
408 * @see org.apache.commons.lang3.time.DatePrinter#format(java.util.Calendar)
409 */
410 @Override
411 public String format(final Calendar calendar) {
412 return format(calendar, new StringBuilder(mMaxLengthEstimate)).toString();
413 }
414
415 /* (non-Javadoc)
416 * @see org.apache.commons.lang3.time.DatePrinter#format(long, java.lang.StringBuilder)
417 */
418 @Override
419 public StringBuilder format(final long millis, final StringBuilder buf) {
420 return format(new Date(millis), buf);
421 }
422
423 /* (non-Javadoc)
424 * @see org.apache.commons.lang3.time.DatePrinter#format(java.util.Date, java.lang.StringBuilder)
425 */
426 @Override
427 public StringBuilder format(final Date date, final StringBuilder buf) {
428 final Calendar c = newCalendar(); // hard code GregorianCalendar
429 c.setTime(date);
430 return applyRules(c, buf);
431 }
432
433 /* (non-Javadoc)
434 * @see org.apache.commons.lang3.time.DatePrinter#format(java.util.Calendar, java.lang.StringBuilder)
435 */
436 @Override
437 public StringBuilder format(final Calendar calendar, final StringBuilder buf) {
438 // do not pass in calendar directly, this will cause TimeZone of FastDatePrinter to be ignored
439 return format(calendar.getTime(), buf);
440 }
441
442 /**
443 * <p>Performs the formatting by applying the rules to the
444 * specified calendar.</p>
445 *
446 * @param calendar the calendar to format
447 * @param buf the buffer to format into
448 * @return the specified string buffer
449 */
450 protected StringBuilder applyRules(final Calendar calendar, final StringBuilder buf) {
451 for (final Rule rule : mRules) {
452 rule.appendTo(buf, calendar);
453 }
454 return buf;
455 }
456
457 // Accessors
458 //-----------------------------------------------------------------------
459 /* (non-Javadoc)
460 * @see org.apache.commons.lang3.time.DatePrinter#getPattern()
461 */
462 @Override
463 public String getPattern() {
464 return mPattern;
465 }
466
467 /* (non-Javadoc)
468 * @see org.apache.commons.lang3.time.DatePrinter#getTimeZone()
469 */
470 @Override
471 public TimeZone getTimeZone() {
472 return mTimeZone;
473 }
474
475 /* (non-Javadoc)
476 * @see org.apache.commons.lang3.time.DatePrinter#getLocale()
477 */
478 @Override
479 public Locale getLocale() {
480 return mLocale;
481 }
482
483 /**
484 * <p>Gets an estimate for the maximum string length that the
485 * formatter will produce.</p>
486 *
487 * <p>The actual formatted length will almost always be less than or
488 * equal to this amount.</p>
489 *
490 * @return the maximum formatted length
491 */
492 public int getMaxLengthEstimate() {
493 return mMaxLengthEstimate;
494 }
495
496 // Basics
497 //-----------------------------------------------------------------------
498 /**
499 * <p>Compares two objects for equality.</p>
500 *
501 * @param obj the object to compare to
502 * @return {@code true} if equal
503 */
504 @Override
505 public boolean equals(final Object obj) {
506 if (obj instanceof FastDatePrinter == false) {
507 return false;
508 }
509 final FastDatePrinter other = (FastDatePrinter) obj;
510 return mPattern.equals(other.mPattern)
511 && mTimeZone.equals(other.mTimeZone)
512 && mLocale.equals(other.mLocale);
513 }
514
515 /**
516 * <p>Returns a hashcode compatible with equals.</p>
517 *
518 * @return a hashcode compatible with equals
519 */
520 @Override
521 public int hashCode() {
522 return mPattern.hashCode() + 13 * (mTimeZone.hashCode() + 13 * mLocale.hashCode());
523 }
524
525 /**
526 * <p>Gets a debugging string version of this formatter.</p>
527 *
528 * @return a debugging string
529 */
530 @Override
531 public String toString() {
532 return "FastDatePrinter[" + mPattern + "," + mLocale + "," + mTimeZone.getID() + "]";
533 }
534
535 // Serializing
536 //-----------------------------------------------------------------------
537 /**
538 * Create the object after serialization. This implementation reinitializes the
539 * transient properties.
540 *
541 * @param in ObjectInputStream from which the object is being deserialized.
542 * @throws IOException if there is an IO issue.
543 * @throws ClassNotFoundException if a class cannot be found.
544 */
545 private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
546 in.defaultReadObject();
547 init();
548 }
549
550 /**
551 * Appends digits to the given buffer.
552 *
553 * @param buffer the buffer to append to.
554 * @param value the value to append digits from.
555 */
556 private static void appendDigits(final StringBuilder buffer, final int value) {
557 buffer.append((char)(value / 10 + '0'));
558 buffer.append((char)(value % 10 + '0'));
559 }
560
561 // Rules
562 //-----------------------------------------------------------------------
563 /**
564 * <p>Inner class defining a rule.</p>
565 */
566 private interface Rule {
567 /**
568 * Returns the estimated length of the result.
569 *
570 * @return the estimated length
571 */
572 int estimateLength();
573
574 /**
575 * Appends the value of the specified calendar to the output buffer based on the rule implementation.
576 *
577 * @param buffer the output buffer
578 * @param calendar calendar to be appended
579 */
580 void appendTo(StringBuilder buffer, Calendar calendar);
581 }
582
583 /**
584 * <p>Inner class defining a numeric rule.</p>
585 */
586 private interface NumberRule extends Rule {
587 /**
588 * Appends the specified value to the output buffer based on the rule implementation.
589 *
590 * @param buffer the output buffer
591 * @param value the value to be appended
592 */
593 void appendTo(StringBuilder buffer, int value);
594 }
595
596 /**
597 * <p>Inner class to output a constant single character.</p>
598 */
599 private static class CharacterLiteral implements Rule {
600 private final char mValue;
601
602 /**
603 * Constructs a new instance of {@code CharacterLiteral}
604 * to hold the specified value.
605 *
606 * @param value the character literal
607 */
608 CharacterLiteral(final char value) {
609 mValue = value;
610 }
611
612 /**
613 * {@inheritDoc}
614 */
615 @Override
616 public int estimateLength() {
617 return 1;
618 }
619
620 /**
621 * {@inheritDoc}
622 */
623 @Override
624 public void appendTo(final StringBuilder buffer, final Calendar calendar) {
625 buffer.append(mValue);
626 }
627 }
628
629 /**
630 * <p>Inner class to output a constant string.</p>
631 */
632 private static class StringLiteral implements Rule {
633 private final String mValue;
634
635 /**
636 * Constructs a new instance of {@code StringLiteral}
637 * to hold the specified value.
638 *
639 * @param value the string literal
640 */
641 StringLiteral(final String value) {
642 mValue = value;
643 }
644
645 /**
646 * {@inheritDoc}
647 */
648 @Override
649 public int estimateLength() {
650 return mValue.length();
651 }
652
653 /**
654 * {@inheritDoc}
655 */
656 @Override
657 public void appendTo(final StringBuilder buffer, final Calendar calendar) {
658 buffer.append(mValue);
659 }
660 }
661
662 /**
663 * <p>Inner class to output one of a set of values.</p>
664 */
665 private static class TextField implements Rule {
666 private final int mField;
667 private final String[] mValues;
668
669 /**
670 * Constructs an instance of {@code TextField}
671 * with the specified field and values.
672 *
673 * @param field the field
674 * @param values the field values
675 */
676 TextField(final int field, final String[] values) {
677 mField = field;
678 mValues = values;
679 }
680
681 /**
682 * {@inheritDoc}
683 */
684 @Override
685 public int estimateLength() {
686 int max = 0;
687 for (int i=mValues.length; --i >= 0; ) {
688 final int len = mValues[i].length();
689 if (len > max) {
690 max = len;
691 }
692 }
693 return max;
694 }
695
696 /**
697 * {@inheritDoc}
698 */
699 @Override
700 public void appendTo(final StringBuilder buffer, final Calendar calendar) {
701 buffer.append(mValues[calendar.get(mField)]);
702 }
703 }
704
705 /**
706 * <p>Inner class to output an unpadded number.</p>
707 */
708 private static class UnpaddedNumberField implements NumberRule {
709 private final int mField;
710
711 /**
712 * Constructs an instance of {@code UnpadedNumberField} with the specified field.
713 *
714 * @param field the field
715 */
716 UnpaddedNumberField(final int field) {
717 mField = field;
718 }
719
720 /**
721 * {@inheritDoc}
722 */
723 @Override
724 public int estimateLength() {
725 return 4;
726 }
727
728 /**
729 * {@inheritDoc}
730 */
731 @Override
732 public void appendTo(final StringBuilder buffer, final Calendar calendar) {
733 appendTo(buffer, calendar.get(mField));
734 }
735
736 /**
737 * {@inheritDoc}
738 */
739 @Override
740 public final void appendTo(final StringBuilder buffer, final int value) {
741 if (value < 10) {
742 buffer.append((char)(value + '0'));
743 } else if (value < 100) {
744 appendDigits(buffer, value);
745 } else {
746 buffer.append(value);
747 }
748 }
749 }
750
751 /**
752 * <p>Inner class to output an unpadded month.</p>
753 */
754 private static class UnpaddedMonthField implements NumberRule {
755 static final UnpaddedMonthField INSTANCE = new UnpaddedMonthField();
756
757 /**
758 * Constructs an instance of {@code UnpaddedMonthField}.
759 *
760 */
761 UnpaddedMonthField() {
762 super();
763 }
764
765 /**
766 * {@inheritDoc}
767 */
768 @Override
769 public int estimateLength() {
770 return 2;
771 }
772
773 /**
774 * {@inheritDoc}
775 */
776 @Override
777 public void appendTo(final StringBuilder buffer, final Calendar calendar) {
778 appendTo(buffer, calendar.get(Calendar.MONTH) + 1);
779 }
780
781 /**
782 * {@inheritDoc}
783 */
784 @Override
785 public final void appendTo(final StringBuilder buffer, final int value) {
786 if (value < 10) {
787 buffer.append((char)(value + '0'));
788 } else {
789 appendDigits(buffer, value);
790 }
791 }
792 }
793
794 /**
795 * <p>Inner class to output a padded number.</p>
796 */
797 private static class PaddedNumberField implements NumberRule {
798 private final int mField;
799 private final int mSize;
800
801 /**
802 * Constructs an instance of {@code PaddedNumberField}.
803 *
804 * @param field the field
805 * @param size size of the output field
806 */
807 PaddedNumberField(final int field, final int size) {
808 if (size < 3) {
809 // Should use UnpaddedNumberField or TwoDigitNumberField.
810 throw new IllegalArgumentException();
811 }
812 mField = field;
813 mSize = size;
814 }
815
816 /**
817 * {@inheritDoc}
818 */
819 @Override
820 public int estimateLength() {
821 return mSize;
822 }
823
824 /**
825 * {@inheritDoc}
826 */
827 @Override
828 public void appendTo(final StringBuilder buffer, final Calendar calendar) {
829 appendTo(buffer, calendar.get(mField));
830 }
831
832 /**
833 * {@inheritDoc}
834 */
835 @Override
836 public final void appendTo(final StringBuilder buffer, int value) {
837 // pad the buffer with adequate zeros
838 for(int digit = 0; digit<mSize; ++digit) {
839 buffer.append('0');
840 }
841 // backfill the buffer with non-zero digits
842 int index = buffer.length();
843 for( ; value>0; value /= 10) {
844 buffer.setCharAt(--index, (char)('0' + value % 10));
845 }
846 }
847 }
848
849 /**
850 * <p>Inner class to output a two digit number.</p>
851 */
852 private static class TwoDigitNumberField implements NumberRule {
853 private final int mField;
854
855 /**
856 * Constructs an instance of {@code TwoDigitNumberField} with the specified field.
857 *
858 * @param field the field
859 */
860 TwoDigitNumberField(final int field) {
861 mField = field;
862 }
863
864 /**
865 * {@inheritDoc}
866 */
867 @Override
868 public int estimateLength() {
869 return 2;
870 }
871
872 /**
873 * {@inheritDoc}
874 */
875 @Override
876 public void appendTo(final StringBuilder buffer, final Calendar calendar) {
877 appendTo(buffer, calendar.get(mField));
878 }
879
880 /**
881 * {@inheritDoc}
882 */
883 @Override
884 public final void appendTo(final StringBuilder buffer, final int value) {
885 if (value < 100) {
886 appendDigits(buffer, value);
887 } else {
888 buffer.append(value);
889 }
890 }
891 }
892
893 /**
894 * <p>Inner class to output a two digit year.</p>
895 */
896 private static class TwoDigitYearField implements NumberRule {
897 static final TwoDigitYearField INSTANCE = new TwoDigitYearField();
898
899 /**
900 * Constructs an instance of {@code TwoDigitYearField}.
901 */
902 TwoDigitYearField() {
903 super();
904 }
905
906 /**
907 * {@inheritDoc}
908 */
909 @Override
910 public int estimateLength() {
911 return 2;
912 }
913
914 /**
915 * {@inheritDoc}
916 */
917 @Override
918 public void appendTo(final StringBuilder buffer, final Calendar calendar) {
919 appendTo(buffer, calendar.get(Calendar.YEAR) % 100);
920 }
921
922 /**
923 * {@inheritDoc}
924 */
925 @Override
926 public final void appendTo(final StringBuilder buffer, final int value) {
927 appendDigits(buffer, value);
928 }
929 }
930
931 /**
932 * <p>Inner class to output a two digit month.</p>
933 */
934 private static class TwoDigitMonthField implements NumberRule {
935 static final TwoDigitMonthField INSTANCE = new TwoDigitMonthField();
936
937 /**
938 * Constructs an instance of {@code TwoDigitMonthField}.
939 */
940 TwoDigitMonthField() {
941 super();
942 }
943
944 /**
945 * {@inheritDoc}
946 */
947 @Override
948 public int estimateLength() {
949 return 2;
950 }
951
952 /**
953 * {@inheritDoc}
954 */
955 @Override
956 public void appendTo(final StringBuilder buffer, final Calendar calendar) {
957 appendTo(buffer, calendar.get(Calendar.MONTH) + 1);
958 }
959
960 /**
961 * {@inheritDoc}
962 */
963 @Override
964 public final void appendTo(final StringBuilder buffer, final int value) {
965 appendDigits(buffer, value);
966 }
967 }
968
969 /**
970 * <p>Inner class to output the twelve hour field.</p>
971 */
972 private static class TwelveHourField implements NumberRule {
973 private final NumberRule mRule;
974
975 /**
976 * Constructs an instance of {@code TwelveHourField} with the specified
977 * {@code NumberRule}.
978 *
979 * @param rule the rule
980 */
981 TwelveHourField(final NumberRule rule) {
982 mRule = rule;
983 }
984
985 /**
986 * {@inheritDoc}
987 */
988 @Override
989 public int estimateLength() {
990 return mRule.estimateLength();
991 }
992
993 /**
994 * {@inheritDoc}
995 */
996 @Override
997 public void appendTo(final StringBuilder buffer, final Calendar calendar) {
998 int value = calendar.get(Calendar.HOUR);
999 if (value == 0) {
1000 value = calendar.getLeastMaximum(Calendar.HOUR) + 1;
1001 }
1002 mRule.appendTo(buffer, value);
1003 }
1004
1005 /**
1006 * {@inheritDoc}
1007 */
1008 @Override
1009 public void appendTo(final StringBuilder buffer, final int value) {
1010 mRule.appendTo(buffer, value);
1011 }
1012 }
1013
1014 /**
1015 * <p>Inner class to output the twenty four hour field.</p>
1016 */
1017 private static class TwentyFourHourField implements NumberRule {
1018 private final NumberRule mRule;
1019
1020 /**
1021 * Constructs an instance of {@code TwentyFourHourField} with the specified
1022 * {@code NumberRule}.
1023 *
1024 * @param rule the rule
1025 */
1026 TwentyFourHourField(final NumberRule rule) {
1027 mRule = rule;
1028 }
1029
1030 /**
1031 * {@inheritDoc}
1032 */
1033 @Override
1034 public int estimateLength() {
1035 return mRule.estimateLength();
1036 }
1037
1038 /**
1039 * {@inheritDoc}
1040 */
1041 @Override
1042 public void appendTo(final StringBuilder buffer, final Calendar calendar) {
1043 int value = calendar.get(Calendar.HOUR_OF_DAY);
1044 if (value == 0) {
1045 value = calendar.getMaximum(Calendar.HOUR_OF_DAY) + 1;
1046 }
1047 mRule.appendTo(buffer, value);
1048 }
1049
1050 /**
1051 * {@inheritDoc}
1052 */
1053 @Override
1054 public void appendTo(final StringBuilder buffer, final int value) {
1055 mRule.appendTo(buffer, value);
1056 }
1057 }
1058
1059 //-----------------------------------------------------------------------
1060
1061 private static final ConcurrentMap<TimeZoneDisplayKey, String> cTimeZoneDisplayCache =
1062 new ConcurrentHashMap<TimeZoneDisplayKey, String>(7);
1063 /**
1064 * <p>Gets the time zone display name, using a cache for performance.</p>
1065 *
1066 * @param tz the zone to query
1067 * @param daylight true if daylight savings
1068 * @param style the style to use {@code TimeZone.LONG} or {@code TimeZone.SHORT}
1069 * @param locale the locale to use
1070 * @return the textual name of the time zone
1071 */
1072 static String getTimeZoneDisplay(final TimeZone tz, final boolean daylight, final int style, final Locale locale) {
1073 final TimeZoneDisplayKey key = new TimeZoneDisplayKey(tz, daylight, style, locale);
1074 String value = cTimeZoneDisplayCache.get(key);
1075 if (value == null) {
1076 // This is a very slow call, so cache the results.
1077 value = tz.getDisplayName(daylight, style, locale);
1078 final String prior = cTimeZoneDisplayCache.putIfAbsent(key, value);
1079 if (prior != null) {
1080 value= prior;
1081 }
1082 }
1083 return value;
1084 }
1085
1086 /**
1087 * <p>Inner class to output a time zone name.</p>
1088 */
1089 private static class TimeZoneNameRule implements Rule {
1090 private final Locale mLocale;
1091 private final int mStyle;
1092 private final String mStandard;
1093 private final String mDaylight;
1094
1095 /**
1096 * Constructs an instance of {@code TimeZoneNameRule} with the specified properties.
1097 *
1098 * @param timeZone the time zone
1099 * @param locale the locale
1100 * @param style the style
1101 */
1102 TimeZoneNameRule(final TimeZone timeZone, final Locale locale, final int style) {
1103 mLocale = locale;
1104 mStyle = style;
1105
1106 mStandard = getTimeZoneDisplay(timeZone, false, style, locale);
1107 mDaylight = getTimeZoneDisplay(timeZone, true, style, locale);
1108 }
1109
1110 /**
1111 * {@inheritDoc}
1112 */
1113 @Override
1114 public int estimateLength() {
1115 // We have no access to the Calendar object that will be passed to
1116 // appendTo so base estimate on the TimeZone passed to the
1117 // constructor
1118 return Math.max(mStandard.length(), mDaylight.length());
1119 }
1120
1121 /**
1122 * {@inheritDoc}
1123 */
1124 @Override
1125 public void appendTo(final StringBuilder buffer, final Calendar calendar) {
1126 final TimeZone zone = calendar.getTimeZone();
1127 if (calendar.get(Calendar.DST_OFFSET) != 0) {
1128 buffer.append(getTimeZoneDisplay(zone, true, mStyle, mLocale));
1129 } else {
1130 buffer.append(getTimeZoneDisplay(zone, false, mStyle, mLocale));
1131 }
1132 }
1133 }
1134
1135 /**
1136 * <p>Inner class to output a time zone as a number {@code +/-HHMM}
1137 * or {@code +/-HH:MM}.</p>
1138 */
1139 private static class TimeZoneNumberRule implements Rule {
1140 static final TimeZoneNumberRule INSTANCE_COLON = new TimeZoneNumberRule(true);
1141 static final TimeZoneNumberRule INSTANCE_NO_COLON = new TimeZoneNumberRule(false);
1142
1143 final boolean mColon;
1144
1145 /**
1146 * Constructs an instance of {@code TimeZoneNumberRule} with the specified properties.
1147 *
1148 * @param colon add colon between HH and MM in the output if {@code true}
1149 */
1150 TimeZoneNumberRule(final boolean colon) {
1151 mColon = colon;
1152 }
1153
1154 /**
1155 * {@inheritDoc}
1156 */
1157 @Override
1158 public int estimateLength() {
1159 return 5;
1160 }
1161
1162 /**
1163 * {@inheritDoc}
1164 */
1165 @Override
1166 public void appendTo(final StringBuilder buffer, final Calendar calendar) {
1167
1168 int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
1169
1170 if (offset < 0) {
1171 buffer.append('-');
1172 offset = -offset;
1173 } else {
1174 buffer.append('+');
1175 }
1176
1177 final int hours = offset / (60 * 60 * 1000);
1178 appendDigits(buffer, hours);
1179
1180 if (mColon) {
1181 buffer.append(':');
1182 }
1183
1184 final int minutes = offset / (60 * 1000) - 60 * hours;
1185 appendDigits(buffer, minutes);
1186 }
1187 }
1188
1189 /**
1190 * <p>Inner class to output a time zone as a number {@code +/-HHMM}
1191 * or {@code +/-HH:MM}.</p>
1192 */
1193 private static class Iso8601_Rule implements Rule {
1194
1195 // Sign TwoDigitHours or Z
1196 static final Iso8601_Rule ISO8601_HOURS = new Iso8601_Rule(3);
1197 // Sign TwoDigitHours Minutes or Z
1198 static final Iso8601_Rule ISO8601_HOURS_MINUTES = new Iso8601_Rule(5);
1199 // Sign TwoDigitHours : Minutes or Z
1200 static final Iso8601_Rule ISO8601_HOURS_COLON_MINUTES = new Iso8601_Rule(6);
1201
1202 /**
1203 * Factory method for Iso8601_Rules.
1204 *
1205 * @param tokenLen a token indicating the length of the TimeZone String to be formatted.
1206 * @return a Iso8601_Rule that can format TimeZone String of length {@code tokenLen}. If no such
1207 * rule exists, an IllegalArgumentException will be thrown.
1208 */
1209 static Iso8601_Rule getRule(final int tokenLen) {
1210 switch(tokenLen) {
1211 case 1:
1212 return Iso8601_Rule.ISO8601_HOURS;
1213 case 2:
1214 return Iso8601_Rule.ISO8601_HOURS_MINUTES;
1215 case 3:
1216 return Iso8601_Rule.ISO8601_HOURS_COLON_MINUTES;
1217 default:
1218 throw new IllegalArgumentException("invalid number of X");
1219 }
1220 }
1221
1222 final int length;
1223
1224 /**
1225 * Constructs an instance of {@code Iso8601_Rule} with the specified properties.
1226 *
1227 * @param length The number of characters in output (unless Z is output)
1228 */
1229 Iso8601_Rule(final int length) {
1230 this.length = length;
1231 }
1232
1233 /**
1234 * {@inheritDoc}
1235 */
1236 @Override
1237 public int estimateLength() {
1238 return length;
1239 }
1240
1241 /**
1242 * {@inheritDoc}
1243 */
1244 @Override
1245 public void appendTo(final StringBuilder buffer, final Calendar calendar) {
1246 int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
1247 if (offset == 0) {
1248 buffer.append("Z");
1249 return;
1250 }
1251
1252 if (offset < 0) {
1253 buffer.append('-');
1254 offset = -offset;
1255 } else {
1256 buffer.append('+');
1257 }
1258
1259 final int hours = offset / (60 * 60 * 1000);
1260 appendDigits(buffer, hours);
1261
1262 if (length<5) {
1263 return;
1264 }
1265
1266 if (length==6) {
1267 buffer.append(':');
1268 }
1269
1270 final int minutes = offset / (60 * 1000) - 60 * hours;
1271 appendDigits(buffer, minutes);
1272 }
1273 }
1274
1275 // ----------------------------------------------------------------------
1276 /**
1277 * <p>Inner class that acts as a compound key for time zone names.</p>
1278 */
1279 private static class TimeZoneDisplayKey {
1280 private final TimeZone mTimeZone;
1281 private final int mStyle;
1282 private final Locale mLocale;
1283
1284 /**
1285 * Constructs an instance of {@code TimeZoneDisplayKey} with the specified properties.
1286 *
1287 * @param timeZone the time zone
1288 * @param daylight adjust the style for daylight saving time if {@code true}
1289 * @param style the timezone style
1290 * @param locale the timezone locale
1291 */
1292 TimeZoneDisplayKey(final TimeZone timeZone,
1293 final boolean daylight, final int style, final Locale locale) {
1294 mTimeZone = timeZone;
1295 if (daylight) {
1296 mStyle = style | 0x80000000;
1297 } else {
1298 mStyle = style;
1299 }
1300 mLocale = locale;
1301 }
1302
1303 /**
1304 * {@inheritDoc}
1305 */
1306 @Override
1307 public int hashCode() {
1308 return (mStyle * 31 + mLocale.hashCode() ) * 31 + mTimeZone.hashCode();
1309 }
1310
1311 /**
1312 * {@inheritDoc}
1313 */
1314 @Override
1315 public boolean equals(final Object obj) {
1316 if (this == obj) {
1317 return true;
1318 }
1319 if (obj instanceof TimeZoneDisplayKey) {
1320 final TimeZoneDisplayKey other = (TimeZoneDisplayKey)obj;
1321 return
1322 mTimeZone.equals(other.mTimeZone) &&
1323 mStyle == other.mStyle &&
1324 mLocale.equals(other.mLocale);
1325 }
1326 return false;
1327 }
1328 }
1329 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.util.datetime;
18
19 import java.util.Calendar;
20 import java.util.Objects;
21
22 /**
23 * Custom time formatter that trades flexibility for performance. This formatter only supports the date patterns defined
24 * in {@link FixedFormat}. For any other date patterns use {@link FastDateFormat}.
25 * <p>
26 * Related benchmarks: /log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/TimeFormatBenchmark.java and
27 * /log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadsafeDateFormatBenchmark.java
28 */
29 public class FixedDateFormat {
30 /**
31 * Enumeration over the supported date/time format patterns.
32 * <p>
33 * Package protected for unit tests.
34 */
35 public static enum FixedFormat {
36 /**
37 * ABSOLUTE time format: {@code "HH:mm:ss,SSS"}.
38 */
39 ABSOLUTE("HH:mm:ss,SSS", null, 0, ':', 1, ',', 1),
40
41 /**
42 * ABSOLUTE time format variation with period separator: {@code "HH:mm:ss.SSS"}.
43 */
44 ABSOLUTE_PERIOD("HH:mm:ss.SSS", null, 0, ':', 1, '.', 1),
45
46 /**
47 * COMPACT time format: {@code "yyyyMMddHHmmssSSS"}.
48 */
49 COMPACT("yyyyMMddHHmmssSSS", "yyyyMMdd", 0, ' ', 0, ' ', 0),
50
51 /**
52 * DATE_AND_TIME time format: {@code "dd MMM yyyy HH:mm:ss,SSS"}.
53 */
54 DATE("dd MMM yyyy HH:mm:ss,SSS", "dd MMM yyyy ", 0, ':', 1, ',', 1),
55
56 /**
57 * DATE_AND_TIME time format variation with period separator: {@code "dd MMM yyyy HH:mm:ss.SSS"}.
58 */
59 DATE_PERIOD("dd MMM yyyy HH:mm:ss.SSS", "dd MMM yyyy ", 0, ':', 1, '.', 1),
60
61 /**
62 * DEFAULT time format: {@code "yyyy-MM-dd HH:mm:ss,SSS"}.
63 */
64 DEFAULT("yyyy-MM-dd HH:mm:ss,SSS", "yyyy-MM-dd ", 0, ':', 1, ',', 1),
65
66 /**
67 * DEFAULT time format variation with period separator: {@code "yyyy-MM-dd HH:mm:ss.SSS"}.
68 */
69 DEFAULT_PERIOD("yyyy-MM-dd HH:mm:ss.SSS", "yyyy-MM-dd ", 0, ':', 1, '.', 1),
70
71 /**
72 * ISO8601_BASIC time format: {@code "yyyyMMdd'T'HHmmss,SSS"}.
73 */
74 ISO8601_BASIC("yyyyMMdd'T'HHmmss,SSS", "yyyyMMdd'T'", 2, ' ', 0, ',', 1),
75
76 /**
77 * ISO8601 time format: {@code "yyyy-MM-dd'T'HH:mm:ss,SSS"}.
78 */
79 ISO8601("yyyy-MM-dd'T'HH:mm:ss,SSS", "yyyy-MM-dd'T'", 2, ':', 1, ',', 1), ;
80
81 private final String pattern;
82 private final String datePattern;
83 private final int escapeCount;
84 private final char timeSeparatorChar;
85 private final int timeSeparatorLength;
86 private final char millisSeparatorChar;
87 private final int millisSeparatorLength;
88
89 private FixedFormat(final String pattern, final String datePattern, final int escapeCount,
90 final char timeSeparator, final int timeSepLength, final char millisSeparator, final int millisSepLength) {
91 this.timeSeparatorChar = timeSeparator;
92 this.timeSeparatorLength = timeSepLength;
93 this.millisSeparatorChar = millisSeparator;
94 this.millisSeparatorLength = millisSepLength;
95 this.pattern = Objects.requireNonNull(pattern);
96 this.datePattern = datePattern; // may be null
97 this.escapeCount = escapeCount;
98 }
99
100 public String getPattern() {
101 return pattern;
102 }
103
104 public String getDatePattern() {
105 return datePattern;
106 }
107
108 /**
109 * Returns the FixedFormat with the name or pattern matching the specified string or {@code null} if not found.
110 */
111 public static FixedFormat lookup(final String nameOrPattern) {
112 for (final FixedFormat type : FixedFormat.values()) {
113 if (type.name().equals(nameOrPattern) || type.getPattern().equals(nameOrPattern)) {
114 return type;
115 }
116 }
117 return null;
118 }
119
120 public int getLength() {
121 return pattern.length() - escapeCount;
122 }
123
124 public int getDatePatternLength() {
125 return getDatePattern() == null ? 0 : getDatePattern().length() - escapeCount;
126 }
127
128 public FastDateFormat getFastDateFormat() {
129 return getDatePattern() == null ? null : FastDateFormat.getInstance(getDatePattern());
130 }
131 }
132
133 public static FixedDateFormat createIfSupported(final String... options) {
134 if (options == null || options.length == 0 || options[0] == null) {
135 return new FixedDateFormat(FixedFormat.DEFAULT);
136 }
137 if (options.length > 1) {
138 return null; // time zone not supported
139 }
140 final FixedFormat type = FixedFormat.lookup(options[0]);
141 return type == null ? null : new FixedDateFormat(type);
142 }
143
144 public static FixedDateFormat create(FixedFormat format) {
145 return new FixedDateFormat(format);
146 }
147
148 private final FixedFormat fixedFormat;
149 private final int length;
150 private final int dateLength;
151 private final FastDateFormat fastDateFormat; // may be null
152 private final char timeSeparatorChar;
153 private final char millisSeparatorChar;
154 private final int timeSeparatorLength;
155 private final int millisSeparatorLength;
156
157 private volatile long midnightToday = 0;
158 private volatile long midnightTomorrow = 0;
159 // cachedDate does not need to be volatile because
160 // there is a write to a volatile field *after* cachedDate is modified,
161 // and there is a read from a volatile field *before* cachedDate is read.
162 // The Java memory model guarantees that because of the above,
163 // changes to cachedDate in one thread are visible to other threads.
164 // See http://g.oswego.edu/dl/jmm/cookbook.html
165 private char[] cachedDate; // may be null
166
167 /**
168 * Constructs a FixedDateFormat for the specified fixed format.
169 * <p>
170 * Package protected for unit tests.
171 *
172 * @param fixedFormat the fixed format
173 */
174 FixedDateFormat(final FixedFormat fixedFormat) {
175 this.fixedFormat = Objects.requireNonNull(fixedFormat);
176 this.timeSeparatorChar = fixedFormat.timeSeparatorChar;
177 this.timeSeparatorLength = fixedFormat.timeSeparatorLength;
178 this.millisSeparatorChar = fixedFormat.millisSeparatorChar;
179 this.millisSeparatorLength = fixedFormat.millisSeparatorLength;
180 this.length = fixedFormat.getLength();
181 this.dateLength = fixedFormat.getDatePatternLength();
182 this.fastDateFormat = fixedFormat.getFastDateFormat();
183 }
184
185 public String getFormat() {
186 return fixedFormat.getPattern();
187 }
188
189 // Profiling showed this method is important to log4j performance. Modify with care!
190 // 30 bytes (allows immediate JVM inlining: <= -XX:MaxInlineSize=35 bytes)
191 private long millisSinceMidnight(final long now) {
192 if (now >= midnightTomorrow || now < midnightToday) {
193 updateMidnightMillis(now);
194 }
195 return now - midnightToday;
196 }
197
198 private void updateMidnightMillis(final long now) {
199
200 updateCachedDate(now);
201
202 midnightToday = calcMidnightMillis(now, 0);
203 midnightTomorrow = calcMidnightMillis(now, 1);
204 }
205
206 static long calcMidnightMillis(final long time, final int addDays) {
207 final Calendar cal = Calendar.getInstance();
208 cal.setTimeInMillis(time);
209 cal.set(Calendar.HOUR_OF_DAY, 0);
210 cal.set(Calendar.MINUTE, 0);
211 cal.set(Calendar.SECOND, 0);
212 cal.set(Calendar.MILLISECOND, 0);
213 cal.add(Calendar.DATE, addDays);
214 return cal.getTimeInMillis();
215 }
216
217 private void updateCachedDate(final long now) {
218 if (fastDateFormat != null) {
219 final StringBuilder result = fastDateFormat.format(now, new StringBuilder());
220 cachedDate = result.toString().toCharArray();
221 }
222 }
223
224 // Profiling showed this method is important to log4j performance. Modify with care!
225 // 28 bytes (allows immediate JVM inlining: <= -XX:MaxInlineSize=35 bytes)
226 public String format(final long time) {
227 final char[] result = new char[length];
228 int written = format(time, result, 0);
229 return new String(result, 0, written);
230 }
231
232 // Profiling showed this method is important to log4j performance. Modify with care!
233 // 31 bytes (allows immediate JVM inlining: <= -XX:MaxInlineSize=35 bytes)
234 public int format(final long time, final char[] buffer, final int startPos) {
235 // Calculate values by getting the ms values first and do then
236 // calculate the hour minute and second values divisions.
237
238 // Get daytime in ms: this does fit into an int
239 // int ms = (int) (time % 86400000);
240 final int ms = (int) (millisSinceMidnight(time));
241 writeDate(buffer, startPos);
242 return writeTime(ms, buffer, startPos + dateLength) - startPos;
243 }
244
245 // Profiling showed this method is important to log4j performance. Modify with care!
246 // 22 bytes (allows immediate JVM inlining: <= -XX:MaxInlineSize=35 bytes)
247 private void writeDate(final char[] buffer, final int startPos) {
248 if (cachedDate != null) {
249 System.arraycopy(cachedDate, 0, buffer, startPos, dateLength);
250 }
251 }
252
253 // Profiling showed this method is important to log4j performance. Modify with care!
254 // 262 bytes (will be inlined when hot enough: <= -XX:FreqInlineSize=325 bytes on Linux)
255 private int writeTime(int ms, final char[] buffer, int pos) {
256 final int hours = ms / 3600000;
257 ms -= 3600000 * hours;
258
259 final int minutes = ms / 60000;
260 ms -= 60000 * minutes;
261
262 final int seconds = ms / 1000;
263 ms -= 1000 * seconds;
264
265 // Hour
266 int temp = hours / 10;
267 buffer[pos++] = ((char) (temp + '0'));
268
269 // Do subtract to get remainder instead of doing % 10
270 buffer[pos++] = ((char) (hours - 10 * temp + '0'));
271 buffer[pos] = timeSeparatorChar;
272 pos += timeSeparatorLength;
273
274 // Minute
275 temp = minutes / 10;
276 buffer[pos++] = ((char) (temp + '0'));
277
278 // Do subtract to get remainder instead of doing % 10
279 buffer[pos++] = ((char) (minutes - 10 * temp + '0'));
280 buffer[pos] = timeSeparatorChar;
281 pos += timeSeparatorLength;
282
283 // Second
284 temp = seconds / 10;
285 buffer[pos++] = ((char) (temp + '0'));
286 buffer[pos++] = ((char) (seconds - 10 * temp + '0'));
287 buffer[pos] = millisSeparatorChar;
288 pos += millisSeparatorLength;
289
290 // Millisecond
291 temp = ms / 100;
292 buffer[pos++] = ((char) (temp + '0'));
293
294 ms -= 100 * temp;
295 temp = ms / 10;
296 buffer[pos++] = ((char) (temp + '0'));
297
298 ms -= 10 * temp;
299 buffer[pos++] = ((char) (ms + '0'));
300 return pos;
301 }
302 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.util.datetime;
17
18 import java.text.FieldPosition;
19 import java.text.ParseException;
20 import java.text.ParsePosition;
21
22 /**
23 * The basic methods for performing date formatting.
24 */
25 public abstract class Format {
26
27 public final String format (final Object obj) {
28 return format(obj, new StringBuilder(), new FieldPosition(0)).toString();
29 }
30
31 public abstract StringBuilder format(Object obj, StringBuilder toAppendTo, FieldPosition pos);
32
33 public abstract Object parseObject (String source, ParsePosition pos);
34
35 public Object parseObject(final String source) throws ParseException {
36 final ParsePosition pos = new ParsePosition(0);
37 final Object result = parseObject(source, pos);
38 if (pos.getIndex() == 0) {
39 throw new ParseException("Format.parseObject(String) failed", pos.getErrorIndex());
40 }
41 return result;
42 }
43 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.logging.log4j.core.util.datetime;
18
19 import java.text.DateFormat;
20 import java.text.SimpleDateFormat;
21 import java.util.Arrays;
22 import java.util.Locale;
23 import java.util.TimeZone;
24 import java.util.concurrent.ConcurrentHashMap;
25 import java.util.concurrent.ConcurrentMap;
26
27 /**
28 * <p>FormatCache is a cache and factory for {@link Format}s.</p>
29 *
30 * @since 3.0
31 */
32 // TODO: Before making public move from getDateTimeInstance(Integer,...) to int; or some other approach.
33 abstract class FormatCache<F extends Format> {
34 /**
35 * No date or no time. Used in same parameters as DateFormat.SHORT or DateFormat.LONG
36 */
37 static final int NONE= -1;
38
39 private final ConcurrentMap<MultipartKey, F> cInstanceCache
40 = new ConcurrentHashMap<MultipartKey, F>(7);
41
42 private static final ConcurrentMap<MultipartKey, String> cDateTimeInstanceCache
43 = new ConcurrentHashMap<MultipartKey, String>(7);
44
45 /**
46 * <p>Gets a formatter instance using the default pattern in the
47 * default timezone and locale.</p>
48 *
49 * @return a date/time formatter
50 */
51 public F getInstance() {
52 return getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, TimeZone.getDefault(), Locale.getDefault());
53 }
54
55 /**
56 * <p>Gets a formatter instance using the specified pattern, time zone
57 * and locale.</p>
58 *
59 * @param pattern {@link java.text.SimpleDateFormat} compatible
60 * pattern, non-null
61 * @param timeZone the time zone, null means use the default TimeZone
62 * @param locale the locale, null means use the default Locale
63 * @return a pattern based date/time formatter
64 * @throws IllegalArgumentException if pattern is invalid
65 * or <code>null</code>
66 */
67 public F getInstance(final String pattern, TimeZone timeZone, Locale locale) {
68 if (pattern == null) {
69 throw new NullPointerException("pattern must not be null");
70 }
71 if (timeZone == null) {
72 timeZone = TimeZone.getDefault();
73 }
74 if (locale == null) {
75 locale = Locale.getDefault();
76 }
77 final MultipartKey key = new MultipartKey(pattern, timeZone, locale);
78 F format = cInstanceCache.get(key);
79 if (format == null) {
80 format = createInstance(pattern, timeZone, locale);
81 final F previousValue= cInstanceCache.putIfAbsent(key, format);
82 if (previousValue != null) {
83 // another thread snuck in and did the same work
84 // we should return the instance that is in ConcurrentMap
85 format= previousValue;
86 }
87 }
88 return format;
89 }
90
91 /**
92 * <p>Create a format instance using the specified pattern, time zone
93 * and locale.</p>
94 *
95 * @param pattern {@link java.text.SimpleDateFormat} compatible pattern, this will not be null.
96 * @param timeZone time zone, this will not be null.
97 * @param locale locale, this will not be null.
98 * @return a pattern based date/time formatter
99 * @throws IllegalArgumentException if pattern is invalid
100 * or <code>null</code>
101 */
102 abstract protected F createInstance(String pattern, TimeZone timeZone, Locale locale);
103
104 /**
105 * <p>Gets a date/time formatter instance using the specified style,
106 * time zone and locale.</p>
107 *
108 * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT, null indicates no date in format
109 * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT, null indicates no time in format
110 * @param timeZone optional time zone, overrides time zone of
111 * formatted date, null means use default Locale
112 * @param locale optional locale, overrides system locale
113 * @return a localized standard date/time formatter
114 * @throws IllegalArgumentException if the Locale has no date/time
115 * pattern defined
116 */
117 // This must remain private, see LANG-884
118 private F getDateTimeInstance(final Integer dateStyle, final Integer timeStyle, final TimeZone timeZone, Locale locale) {
119 if (locale == null) {
120 locale = Locale.getDefault();
121 }
122 final String pattern = getPatternForStyle(dateStyle, timeStyle, locale);
123 return getInstance(pattern, timeZone, locale);
124 }
125
126 /**
127 * <p>Gets a date/time formatter instance using the specified style,
128 * time zone and locale.</p>
129 *
130 * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
131 * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
132 * @param timeZone optional time zone, overrides time zone of
133 * formatted date, null means use default Locale
134 * @param locale optional locale, overrides system locale
135 * @return a localized standard date/time formatter
136 * @throws IllegalArgumentException if the Locale has no date/time
137 * pattern defined
138 */
139 // package protected, for access from FastDateFormat; do not make public or protected
140 F getDateTimeInstance(final int dateStyle, final int timeStyle, final TimeZone timeZone, final Locale locale) {
141 return getDateTimeInstance(Integer.valueOf(dateStyle), Integer.valueOf(timeStyle), timeZone, locale);
142 }
143
144 /**
145 * <p>Gets a date formatter instance using the specified style,
146 * time zone and locale.</p>
147 *
148 * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
149 * @param timeZone optional time zone, overrides time zone of
150 * formatted date, null means use default Locale
151 * @param locale optional locale, overrides system locale
152 * @return a localized standard date/time formatter
153 * @throws IllegalArgumentException if the Locale has no date/time
154 * pattern defined
155 */
156 // package protected, for access from FastDateFormat; do not make public or protected
157 F getDateInstance(final int dateStyle, final TimeZone timeZone, final Locale locale) {
158 return getDateTimeInstance(Integer.valueOf(dateStyle), null, timeZone, locale);
159 }
160
161 /**
162 * <p>Gets a time formatter instance using the specified style,
163 * time zone and locale.</p>
164 *
165 * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
166 * @param timeZone optional time zone, overrides time zone of
167 * formatted date, null means use default Locale
168 * @param locale optional locale, overrides system locale
169 * @return a localized standard date/time formatter
170 * @throws IllegalArgumentException if the Locale has no date/time
171 * pattern defined
172 */
173 // package protected, for access from FastDateFormat; do not make public or protected
174 F getTimeInstance(final int timeStyle, final TimeZone timeZone, final Locale locale) {
175 return getDateTimeInstance(null, Integer.valueOf(timeStyle), timeZone, locale);
176 }
177
178 /**
179 * <p>Gets a date/time format for the specified styles and locale.</p>
180 *
181 * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT, null indicates no date in format
182 * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT, null indicates no time in format
183 * @param locale The non-null locale of the desired format
184 * @return a localized standard date/time format
185 * @throws IllegalArgumentException if the Locale has no date/time pattern defined
186 */
187 // package protected, for access from test code; do not make public or protected
188 static String getPatternForStyle(final Integer dateStyle, final Integer timeStyle, final Locale locale) {
189 final MultipartKey key = new MultipartKey(dateStyle, timeStyle, locale);
190
191 String pattern = cDateTimeInstanceCache.get(key);
192 if (pattern == null) {
193 try {
194 DateFormat formatter;
195 if (dateStyle == null) {
196 formatter = DateFormat.getTimeInstance(timeStyle.intValue(), locale);
197 }
198 else if (timeStyle == null) {
199 formatter = DateFormat.getDateInstance(dateStyle.intValue(), locale);
200 }
201 else {
202 formatter = DateFormat.getDateTimeInstance(dateStyle.intValue(), timeStyle.intValue(), locale);
203 }
204 pattern = ((SimpleDateFormat)formatter).toPattern();
205 final String previous = cDateTimeInstanceCache.putIfAbsent(key, pattern);
206 if (previous != null) {
207 // even though it doesn't matter if another thread put the pattern
208 // it's still good practice to return the String instance that is
209 // actually in the ConcurrentMap
210 pattern= previous;
211 }
212 } catch (final ClassCastException ex) {
213 throw new IllegalArgumentException("No date time pattern for locale: " + locale);
214 }
215 }
216 return pattern;
217 }
218
219 // ----------------------------------------------------------------------
220 /**
221 * <p>Helper class to hold multi-part Map keys</p>
222 */
223 private static class MultipartKey {
224 private final Object[] keys;
225 private int hashCode;
226
227 /**
228 * Constructs an instance of <code>MultipartKey</code> to hold the specified objects.
229 * @param keys the set of objects that make up the key. Each key may be null.
230 */
231 public MultipartKey(final Object... keys) {
232 this.keys = keys;
233 }
234
235 /**
236 * {@inheritDoc}
237 */
238 @Override
239 public boolean equals(final Object obj) {
240 // Eliminate the usual boilerplate because
241 // this inner static class is only used in a generic ConcurrentHashMap
242 // which will not compare against other Object types
243 return Arrays.equals(keys, ((MultipartKey) obj).keys);
244 }
245
246 /**
247 * {@inheritDoc}
248 */
249 @Override
250 public int hashCode() {
251 if(hashCode==0) {
252 int rc= 0;
253 for(final Object key : keys) {
254 if(key!=null) {
255 rc= rc*7 + key.hashCode();
256 }
257 }
258 hashCode= rc;
259 }
260 return hashCode;
261 }
262 }
263
264 }
5555 </xs:sequence>
5656 <xs:attribute name="logger" type="xs:string" use="required"/>
5757 <xs:attribute name="timestamp" type="xs:long" use="required"/>
58 <xs:attribute name="nanoTime" type="xs:long" use="optional"/>
5859 <xs:attribute name="level" type="log4j:LevelEnum" use="required"/>
5960 <xs:attribute name="thread" type="xs:string" use="required"/>
6061 </xs:complexType>
3131
3232 <section name="Requirements">
3333 <p>
34 Log4j 2 requires Java 6. Some features may require optional
34 As of version 2.4, Log4j 2 requires Java 7. Versions 2.3 and earlier require Java 6.
35 Some features may require optional
3536 <a href="dependencies.html">dependencies</a>. These dependencies are specified in the
3637 documentation for those features.
3738 </p>
4647 <li>SMTPAppender requires Javax Mail.</li>
4748 <li>JMSQueueAppender and JMSTopicAppender require a JMS implementation like
4849 <a href="http://activemq.apache.org/">Apache ActiveMQ</a>.</li>
50 <li>Kafka appender requires <a href="http://search.maven.org/#artifactdetails|org.apache.kafka|kafka-clients|0.8.2.1|jar">Kafka client library</a></li>
4951 <li>Windows color support requires <a href="http://jansi.fusesource.org/">Jansi</a>.</li>
5052 <li>The JDBC Appender requires a JDBC driver for the database you choose to write events to.</li>
5153 <li>The JPA Appender requires the Java Persistence API classes, a JPA provider implementation,
5456 <li>The NoSQL Appender with Apache CouchDB provider requires the LightCouch CouchDB client library.</li>
5557 <li>The NoSQL Appender can be customized with a user-supplied provider, which will require the
5658 appropriate client library.</li>
59 <li>bzip2, Deflate, Pack200, and XZ compression on rollover requires
60 <a href="http://commons.apache.org/proper/commons-compress/">Apache Commons Compress</a>. In addition,
61 XZ requires <a href="http://tukaani.org/xz/java.html">XZ for Java</a>.</li>
5762 </ul>
5863 </section>
5964
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.dumbster.smtp;
17
18 import java.io.BufferedReader;
19 import java.io.IOException;
20 import java.io.InputStreamReader;
21 import java.io.PrintWriter;
22 import java.net.ServerSocket;
23 import java.net.Socket;
24 import java.util.ArrayList;
25 import java.util.Iterator;
26 import java.util.List;
27
28 import org.apache.logging.log4j.util.Strings;
29
30 /**
31 * Dummy SMTP server for testing purposes.
32 *
33 * @todo constructor allowing user to pass preinitialized ServerSocket
34 */
35 public class SimpleSmtpServer implements Runnable {
36 /**
37 * Stores all of the email received since this instance started up.
38 */
39 private final List<SmtpMessage> receivedMail;
40
41 /**
42 * Default SMTP port is 25.
43 */
44 public static final int DEFAULT_SMTP_PORT = 25;
45
46 /**
47 * Indicates whether this server is stopped or not.
48 */
49 private volatile boolean stopped = true;
50
51 /**
52 * Handle to the server socket this server listens to.
53 */
54 private ServerSocket serverSocket;
55
56 /**
57 * Port the server listens on - set to the default SMTP port initially.
58 */
59 private int port = DEFAULT_SMTP_PORT;
60
61 /**
62 * Timeout listening on server socket.
63 */
64 private static final int TIMEOUT = 500;
65
66 /**
67 * Constructor.
68 *
69 * @param port port number
70 */
71 public SimpleSmtpServer(final int port) {
72 receivedMail = new ArrayList<SmtpMessage>();
73 this.port = port;
74 }
75
76 /**
77 * Main loop of the SMTP server.
78 */
79 @Override
80 public void run() {
81 stopped = false;
82 try {
83 try {
84 serverSocket = new ServerSocket(port);
85 serverSocket.setSoTimeout(TIMEOUT); // Block for maximum of 1.5 seconds
86 } finally {
87 synchronized (this) {
88 // Notify when server socket has been created
89 notifyAll();
90 }
91 }
92
93 // Server: loop until stopped
94 while (!isStopped()) {
95 // Start server socket and listen for client connections
96 Socket socket = null;
97 try {
98 socket = serverSocket.accept();
99 } catch (final Exception e) {
100 if (socket != null) {
101 socket.close();
102 }
103 continue; // Non-blocking socket timeout occurred: try accept() again
104 }
105
106 // Get the input and output streams
107 final BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
108 final PrintWriter out = new PrintWriter(socket.getOutputStream());
109
110 synchronized (this) {
111 /*
112 * We synchronize over the handle method and the list update because the client call completes inside
113 * the handle method and we have to prevent the client from reading the list until we've updated it.
114 * For higher concurrency, we could just change handle to return void and update the list inside the method
115 * to limit the duration that we hold the lock.
116 */
117 final List<SmtpMessage> msgs = handleTransaction(out, input);
118 receivedMail.addAll(msgs);
119 }
120 socket.close();
121 }
122 } catch (final Exception e) {
123 /** @todo Should throw an appropriate exception here. */
124 e.printStackTrace();
125 } finally {
126 if (serverSocket != null) {
127 try {
128 serverSocket.close();
129 } catch (final IOException e) {
130 e.printStackTrace();
131 }
132 }
133 }
134 }
135
136 /**
137 * Check if the server has been placed in a stopped state. Allows another thread to
138 * stop the server safely.
139 *
140 * @return true if the server has been sent a stop signal, false otherwise
141 */
142 public synchronized boolean isStopped() {
143 return stopped;
144 }
145
146 /**
147 * Stops the server. Server is shutdown after processing of the current request is complete.
148 */
149 public synchronized void stop() {
150 // Mark us closed
151 stopped = true;
152 try {
153 // Kick the server accept loop
154 serverSocket.close();
155 } catch (final IOException e) {
156 // Ignore
157 }
158 }
159
160 /**
161 * Handle an SMTP transaction, i.e. all activity between initial connect and QUIT command.
162 *
163 * @param out output stream
164 * @param input input stream
165 * @return List of SmtpMessage
166 * @throws IOException
167 */
168 private List<SmtpMessage> handleTransaction(final PrintWriter out, final BufferedReader input) throws IOException {
169 // Initialize the state machine
170 SmtpState smtpState = SmtpState.CONNECT;
171 final SmtpRequest smtpRequest = new SmtpRequest(SmtpActionType.CONNECT, Strings.EMPTY, smtpState);
172
173 // Execute the connection request
174 final SmtpResponse smtpResponse = smtpRequest.execute();
175
176 // Send initial response
177 sendResponse(out, smtpResponse);
178 smtpState = smtpResponse.getNextState();
179
180 final List<SmtpMessage> msgList = new ArrayList<SmtpMessage>();
181 SmtpMessage msg = new SmtpMessage();
182
183 while (smtpState != SmtpState.CONNECT) {
184 final String line = input.readLine();
185
186 if (line == null) {
187 break;
188 }
189
190 // Create request from client input and current state
191 final SmtpRequest request = SmtpRequest.createRequest(line, smtpState);
192 // Execute request and create response object
193 final SmtpResponse response = request.execute();
194 // Move to next internal state
195 smtpState = response.getNextState();
196 // Send response to client
197 sendResponse(out, response);
198
199 // Store input in message
200 final String params = request.getParams();
201 msg.store(response, params);
202
203 // If message reception is complete save it
204 if (smtpState == SmtpState.QUIT) {
205 msgList.add(msg);
206 msg = new SmtpMessage();
207 }
208 }
209
210 return msgList;
211 }
212
213 /**
214 * Send response to client.
215 *
216 * @param out socket output stream
217 * @param smtpResponse response object
218 */
219 private static void sendResponse(final PrintWriter out, final SmtpResponse smtpResponse) {
220 if (smtpResponse.getCode() > 0) {
221 final int code = smtpResponse.getCode();
222 final String message = smtpResponse.getMessage();
223 out.print(code + " " + message + "\r\n");
224 out.flush();
225 }
226 }
227
228 /**
229 * Get email received by this instance since start up.
230 *
231 * @return List of String
232 */
233 public synchronized Iterator<SmtpMessage> getReceivedEmail() {
234 return receivedMail.iterator();
235 }
236
237 /**
238 * Get the number of messages received.
239 *
240 * @return size of received email list
241 */
242 public synchronized int getReceivedEmailSize() {
243 return receivedMail.size();
244 }
245
246 /**
247 * Creates an instance of SimpleSmtpServer and starts it. Will listen on the default port.
248 *
249 * @return a reference to the SMTP server
250 */
251 public static SimpleSmtpServer start() {
252 return start(DEFAULT_SMTP_PORT);
253 }
254
255 /**
256 * Creates an instance of SimpleSmtpServer and starts it.
257 *
258 * @param port port number the server should listen to
259 * @return a reference to the SMTP server
260 */
261 public static SimpleSmtpServer start(final int port) {
262 final SimpleSmtpServer server = new SimpleSmtpServer(port);
263 final Thread t = new Thread(server);
264
265
266 // Block until the server socket is created
267 synchronized (server) {
268 t.start();
269 try {
270 server.wait();
271 } catch (final InterruptedException e) {
272 // Ignore don't care.
273 }
274 }
275 return server;
276 }
277
278 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.dumbster.smtp;
17
18 import java.io.BufferedReader;
19 import java.io.IOException;
20 import java.io.InputStreamReader;
21 import java.io.PrintWriter;
22 import java.net.ServerSocket;
23 import java.net.Socket;
24 import java.util.ArrayList;
25 import java.util.Iterator;
26 import java.util.List;
27
28 import org.apache.logging.log4j.util.Strings;
29
30 /**
31 * Dummy SMTP server for testing purposes.
32 *
33 * @todo constructor allowing user to pass preinitialized ServerSocket
34 */
35 public class SimpleSmtpServer implements Runnable {
36 /**
37 * Stores all of the email received since this instance started up.
38 */
39 private final List<SmtpMessage> receivedMail;
40
41 /**
42 * Default SMTP port is 25.
43 */
44 public static final int DEFAULT_SMTP_PORT = 25;
45
46 /**
47 * Indicates whether this server is stopped or not.
48 */
49 private volatile boolean stopped = true;
50
51 /**
52 * Handle to the server socket this server listens to.
53 */
54 private ServerSocket serverSocket;
55
56 /**
57 * Port the server listens on - set to the default SMTP port initially.
58 */
59 private int port = DEFAULT_SMTP_PORT;
60
61 /**
62 * Timeout listening on server socket.
63 */
64 private static final int TIMEOUT = 500;
65
66 /**
67 * Constructor.
68 *
69 * @param port port number
70 */
71 public SimpleSmtpServer(final int port) {
72 receivedMail = new ArrayList<>();
73 this.port = port;
74 }
75
76 /**
77 * Main loop of the SMTP server.
78 */
79 @Override
80 public void run() {
81 stopped = false;
82 try {
83 try {
84 serverSocket = new ServerSocket(port);
85 serverSocket.setSoTimeout(TIMEOUT); // Block for maximum of 1.5 seconds
86 } finally {
87 synchronized (this) {
88 // Notify when server socket has been created
89 notifyAll();
90 }
91 }
92
93 // Server: loop until stopped
94 while (!isStopped()) {
95 // Start server socket and listen for client connections
96 Socket socket = null;
97 try {
98 socket = serverSocket.accept();
99 } catch (final Exception e) {
100 if (socket != null) {
101 socket.close();
102 }
103 continue; // Non-blocking socket timeout occurred: try accept() again
104 }
105
106 // Get the input and output streams
107 final BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
108 final PrintWriter out = new PrintWriter(socket.getOutputStream());
109
110 synchronized (this) {
111 /*
112 * We synchronize over the handle method and the list update because the client call completes
113 * inside the handle method and we have to prevent the client from reading the list until we've
114 * updated it. For higher concurrency, we could just change handle to return void and update the
115 * list inside the method to limit the duration that we hold the lock.
116 */
117 final List<SmtpMessage> msgs = handleTransaction(out, input);
118 receivedMail.addAll(msgs);
119 }
120 socket.close();
121 }
122 } catch (final Exception e) {
123 /** @todo Should throw an appropriate exception here. */
124 e.printStackTrace();
125 } finally {
126 if (serverSocket != null) {
127 try {
128 serverSocket.close();
129 } catch (final IOException e) {
130 e.printStackTrace();
131 }
132 }
133 }
134 }
135
136 /**
137 * Check if the server has been placed in a stopped state. Allows another thread to
138 * stop the server safely.
139 *
140 * @return true if the server has been sent a stop signal, false otherwise
141 */
142 public synchronized boolean isStopped() {
143 return stopped;
144 }
145
146 /**
147 * Stops the server. Server is shutdown after processing of the current request is complete.
148 */
149 public synchronized void stop() {
150 // Mark us closed
151 stopped = true;
152 try {
153 // Kick the server accept loop
154 serverSocket.close();
155 } catch (final IOException e) {
156 // Ignore
157 }
158 }
159
160 /**
161 * Handle an SMTP transaction, i.e. all activity between initial connect and QUIT command.
162 *
163 * @param out output stream
164 * @param input input stream
165 * @return List of SmtpMessage
166 * @throws IOException
167 */
168 private List<SmtpMessage> handleTransaction(final PrintWriter out, final BufferedReader input) throws IOException {
169 // Initialize the state machine
170 SmtpState smtpState = SmtpState.CONNECT;
171 final SmtpRequest smtpRequest = new SmtpRequest(SmtpActionType.CONNECT, Strings.EMPTY, smtpState);
172
173 // Execute the connection request
174 final SmtpResponse smtpResponse = smtpRequest.execute();
175
176 // Send initial response
177 sendResponse(out, smtpResponse);
178 smtpState = smtpResponse.getNextState();
179
180 final List<SmtpMessage> msgList = new ArrayList<>();
181 SmtpMessage msg = new SmtpMessage();
182
183 while (smtpState != SmtpState.CONNECT) {
184 final String line = input.readLine();
185
186 if (line == null) {
187 break;
188 }
189
190 // Create request from client input and current state
191 final SmtpRequest request = SmtpRequest.createRequest(line, smtpState);
192 // Execute request and create response object
193 final SmtpResponse response = request.execute();
194 // Move to next internal state
195 smtpState = response.getNextState();
196 // Send response to client
197 sendResponse(out, response);
198
199 // Store input in message
200 final String params = request.getParams();
201 msg.store(response, params);
202
203 // If message reception is complete save it
204 if (smtpState == SmtpState.QUIT) {
205 msgList.add(msg);
206 msg = new SmtpMessage();
207 }
208 }
209
210 return msgList;
211 }
212
213 /**
214 * Send response to client.
215 *
216 * @param out socket output stream
217 * @param smtpResponse response object
218 */
219 private static void sendResponse(final PrintWriter out, final SmtpResponse smtpResponse) {
220 if (smtpResponse.getCode() > 0) {
221 final int code = smtpResponse.getCode();
222 final String message = smtpResponse.getMessage();
223 out.print(code + " " + message + "\r\n");
224 out.flush();
225 }
226 }
227
228 /**
229 * Get email received by this instance since start up.
230 *
231 * @return List of String
232 */
233 public synchronized Iterator<SmtpMessage> getReceivedEmail() {
234 return receivedMail.iterator();
235 }
236
237 /**
238 * Get the number of messages received.
239 *
240 * @return size of received email list
241 */
242 public synchronized int getReceivedEmailSize() {
243 return receivedMail.size();
244 }
245
246 /**
247 * Creates an instance of SimpleSmtpServer and starts it. Will listen on the default port.
248 *
249 * @return a reference to the SMTP server
250 */
251 public static SimpleSmtpServer start() {
252 return start(DEFAULT_SMTP_PORT);
253 }
254
255 /**
256 * Creates an instance of SimpleSmtpServer and starts it.
257 *
258 * @param port port number the server should listen to
259 * @return a reference to the SMTP server
260 */
261 public static SimpleSmtpServer start(final int port) {
262 final SimpleSmtpServer server = new SimpleSmtpServer(port);
263 final Thread t = new Thread(server);
264
265
266 // Block until the server socket is created
267 synchronized (server) {
268 t.start();
269 try {
270 server.wait();
271 } catch (final InterruptedException e) {
272 // Ignore don't care.
273 }
274 }
275 return server;
276 }
277
278 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.dumbster.smtp;
17
18 import java.util.ArrayList;
19 import java.util.HashMap;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Set;
24
25 /**
26 * Container for a complete SMTP message - headers and message body.
27 */
28 public class SmtpMessage {
29 /**
30 * Headers: Map of List of String hashed on header name.
31 */
32 private final Map<String, List<String>> headers;
33 /**
34 * Message body.
35 */
36 private final StringBuffer body;
37
38 /**
39 * Constructor. Initializes headers Map and body buffer.
40 */
41 public SmtpMessage() {
42 headers = new HashMap<String, List<String>>(10);
43 body = new StringBuffer();
44 }
45
46 /**
47 * Update the headers or body depending on the SmtpResponse object and line of input.
48 *
49 * @param response SmtpResponse object
50 * @param params remainder of input line after SMTP command has been removed
51 */
52 public void store(final SmtpResponse response, final String params) {
53 if (params != null) {
54 if (SmtpState.DATA_HDR.equals(response.getNextState())) {
55 final int headerNameEnd = params.indexOf(':');
56 if (headerNameEnd >= 0) {
57 final String name = params.substring(0, headerNameEnd).trim();
58 final String value = params.substring(headerNameEnd + 1).trim();
59 addHeader(name, value);
60 }
61 } else if (SmtpState.DATA_BODY == response.getNextState()) {
62 body.append(params);
63 }
64 }
65 }
66
67 /**
68 * Get an Iterator over the header names.
69 *
70 * @return an Iterator over the set of header names (String)
71 */
72 public Iterator<String> getHeaderNames() {
73 final Set<String> nameSet = headers.keySet();
74 return nameSet.iterator();
75 }
76
77 /**
78 * Get the value(s) associated with the given header name.
79 *
80 * @param name header name
81 * @return value(s) associated with the header name
82 */
83 public String[] getHeaderValues(final String name) {
84 final List<String> values = headers.get(name);
85 if (values == null) {
86 return new String[0];
87 } else {
88 return values.toArray(new String[values.size()]);
89 }
90 }
91
92 /**
93 * Get the first values associated with a given header name.
94 *
95 * @param name header name
96 * @return first value associated with the header name
97 */
98 public String getHeaderValue(final String name) {
99 final List<String> values = headers.get(name);
100 if (values == null) {
101 return null;
102 } else {
103 final Iterator<String> iterator = values.iterator();
104 return iterator.hasNext() ? iterator.next() : null;
105 }
106 }
107
108 /**
109 * Get the message body.
110 *
111 * @return message body
112 */
113 public String getBody() {
114 return body.toString();
115 }
116
117 /**
118 * Adds a header to the Map.
119 *
120 * @param name header name
121 * @param value header value
122 */
123 private void addHeader(final String name, final String value) {
124 List<String> valueList = headers.get(name);
125 if (valueList == null) {
126 valueList = new ArrayList<String>(1);
127 headers.put(name, valueList);
128 }
129 valueList.add(value);
130 }
131
132 /**
133 * String representation of the SmtpMessage.
134 *
135 * @return a String
136 */
137 @Override
138 public String toString() {
139 final StringBuilder msg = new StringBuilder();
140 for (final Map.Entry<String, List<String>> entry : headers.entrySet()) {
141 final String name = entry.getKey();
142 final List<String> values = entry.getValue();
143 for (final String value : values) {
144 msg.append(name);
145 msg.append(": ");
146 msg.append(value);
147 msg.append('\n');
148 }
149 }
150 msg.append('\n');
151 msg.append(body);
152 msg.append('\n');
153 return msg.toString();
154 }
155 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.dumbster.smtp;
17
18 import java.util.ArrayList;
19 import java.util.HashMap;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Set;
24
25 /**
26 * Container for a complete SMTP message - headers and message body.
27 */
28 public class SmtpMessage {
29 /**
30 * Headers: Map of List of String hashed on header name.
31 */
32 private final Map<String, List<String>> headers;
33 /**
34 * Message body.
35 */
36 private final StringBuffer body;
37
38 /**
39 * Constructor. Initializes headers Map and body buffer.
40 */
41 public SmtpMessage() {
42 headers = new HashMap<>(10);
43 body = new StringBuffer();
44 }
45
46 /**
47 * Update the headers or body depending on the SmtpResponse object and line of input.
48 *
49 * @param response SmtpResponse object
50 * @param params remainder of input line after SMTP command has been removed
51 */
52 public void store(final SmtpResponse response, final String params) {
53 if (params != null) {
54 if (SmtpState.DATA_HDR.equals(response.getNextState())) {
55 final int headerNameEnd = params.indexOf(':');
56 if (headerNameEnd >= 0) {
57 final String name = params.substring(0, headerNameEnd).trim();
58 final String value = params.substring(headerNameEnd + 1).trim();
59 addHeader(name, value);
60 }
61 } else if (SmtpState.DATA_BODY == response.getNextState()) {
62 body.append(params);
63 }
64 }
65 }
66
67 /**
68 * Get an Iterator over the header names.
69 *
70 * @return an Iterator over the set of header names (String)
71 */
72 public Iterator<String> getHeaderNames() {
73 final Set<String> nameSet = headers.keySet();
74 return nameSet.iterator();
75 }
76
77 /**
78 * Get the value(s) associated with the given header name.
79 *
80 * @param name header name
81 * @return value(s) associated with the header name
82 */
83 public String[] getHeaderValues(final String name) {
84 final List<String> values = headers.get(name);
85 if (values == null) {
86 return new String[0];
87 }
88 return values.toArray(new String[values.size()]);
89 }
90
91 /**
92 * Get the first values associated with a given header name.
93 *
94 * @param name header name
95 * @return first value associated with the header name
96 */
97 public String getHeaderValue(final String name) {
98 final List<String> values = headers.get(name);
99 if (values == null) {
100 return null;
101 }
102 final Iterator<String> iterator = values.iterator();
103 return iterator.hasNext() ? iterator.next() : null;
104 }
105
106 /**
107 * Get the message body.
108 *
109 * @return message body
110 */
111 public String getBody() {
112 return body.toString();
113 }
114
115 /**
116 * Adds a header to the Map.
117 *
118 * @param name header name
119 * @param value header value
120 */
121 private void addHeader(final String name, final String value) {
122 List<String> valueList = headers.get(name);
123 if (valueList == null) {
124 valueList = new ArrayList<>(1);
125 headers.put(name, valueList);
126 }
127 valueList.add(value);
128 }
129
130 /**
131 * String representation of the SmtpMessage.
132 *
133 * @return a String
134 */
135 @Override
136 public String toString() {
137 final StringBuilder msg = new StringBuilder();
138 for (final Map.Entry<String, List<String>> entry : headers.entrySet()) {
139 final String name = entry.getKey();
140 final List<String> values = entry.getValue();
141 for (final String value : values) {
142 msg.append(name);
143 msg.append(": ");
144 msg.append(value);
145 msg.append('\n');
146 }
147 }
148 msg.append('\n');
149 msg.append(body);
150 msg.append('\n');
151 return msg.toString();
152 }
153 }
112112 }
113113
114114 private long logback(final int loop) {
115 final Integer j = new Integer(2);
115 final Integer j = Integer.valueOf(2);
116116 final long start = System.nanoTime();
117117 for (int i = 0; i < loop; i++) {
118118 logbacklogger.debug("SEE IF THIS IS LOGGED {}.", j);
122122
123123
124124 private long log4j2(final int loop) {
125 final Integer j = new Integer(2);
125 final Integer j = Integer.valueOf(2);
126126 final long start = System.nanoTime();
127127 for (int i = 0; i < loop; i++) {
128128 logger.debug("SEE IF THIS IS LOGGED {}.", j);
1616 package org.apache.logging.log4j;
1717
1818 import java.io.BufferedOutputStream;
19 import java.io.File;
1920 import java.io.FileOutputStream;
2021 import java.io.FileWriter;
2122 import java.io.OutputStream;
4344
4445
4546 // How many times should we try to log:
46 private static final int COUNT = 1000000;
47 private static final int COUNT = 500000;
4748 private static final int PROFILE_COUNT = 500000;
48 private static final int WARMUP = 1000;
49 private static final int WARMUP = 50000;
4950
5051 private static final String CONFIG = "log4j2-perf.xml";
5152 private static final String LOGBACK_CONFIG = "logback-perf.xml";
6667 System.clearProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY);
6768 System.clearProperty(LOGBACK_CONF);
6869 System.clearProperty(LOG4J_CONF);
70 new File("target/testlog4j.log").deleteOnExit();
71 new File("target/testlog4j2.log").deleteOnExit();
72 new File("target/testlogback.log").deleteOnExit();
6973 }
7074
7175 @Test
8488 System.out.println("Log4j 2.0: " + result);
8589 System.out.println("###############################################");
8690 } else {
87 System.out.println("Starting Log4j 2.0");
88 final long result3 = log4j2(COUNT);
89 System.out.println("Starting Log4j");
90 final long result1 = log4j(COUNT);
91 System.out.println("Starting Logback");
92 final long result2 = logback(COUNT);
93
94 System.out.println("###############################################");
95 System.out.println("Log4j: " + result1);
96 System.out.println("Logback: " + result2);
97 System.out.println("Log4j 2.0: " + result3);
98 System.out.println("###############################################");
99 }
91 doRun();
92 doRun();
93 doRun();
94 doRun();
95 }
96 }
97
98 private void doRun() {
99 System.out.print("Log4j : ");
100 System.out.println(log4j(COUNT));
101
102 System.out.print("Logback : ");
103 System.out.println(logback(COUNT));
104
105 System.out.print("Log4j 2.0: ");
106 System.out.println(log4j2(COUNT));
107
108 System.out.println("###############################################");
100109 }
101110
102111 //@Test
123132 }
124133
125134 private long log4j(final int loop) {
126 final Integer j = new Integer(2);
135 final Integer j = Integer.valueOf(2);
127136 final long start = System.nanoTime();
128137 for (int i = 0; i < loop; i++) {
129138 log4jlogger.debug("SEE IF THIS IS LOGGED " + j + '.');
132141 }
133142
134143 private long logback(final int loop) {
135 final Integer j = new Integer(2);
144 final Integer j = Integer.valueOf(2);
136145 final long start = System.nanoTime();
137146 for (int i = 0; i < loop; i++) {
138147 logbacklogger.debug("SEE IF THIS IS LOGGED " + j + '.');
142151
143152
144153 private long log4j2(final int loop) {
145 final Integer j = new Integer(2);
154 final Integer j = Integer.valueOf(2);
146155 final long start = System.nanoTime();
147156 for (int i = 0; i < loop; i++) {
148157 logger.debug("SEE IF THIS IS LOGGED " + j + '.');
152161
153162
154163 private long writeToWriter(final int loop, final Writer w) throws Exception {
155 final Integer j = new Integer(2);
164 final Integer j = Integer.valueOf(2);
156165 final long start = System.nanoTime();
157166 for (int i = 0; i < loop; i++) {
158167 w.write("SEE IF THIS IS LOGGED " + j + '.');
161170 }
162171
163172 private long writeToStream(final int loop, final OutputStream os) throws Exception {
164 final Integer j = new Integer(2);
173 final Integer j = Integer.valueOf(2);
165174 final long start = System.nanoTime();
166175 for (int i = 0; i < loop; i++) {
167176 os.write(getBytes("SEE IF THIS IS LOGGED " + j + '.'));
170179 }
171180
172181 private long writeToChannel(final int loop, final FileChannel channel) throws Exception {
173 final Integer j = new Integer(2);
182 final Integer j = Integer.valueOf(2);
174183 final ByteBuffer buf = ByteBuffer.allocateDirect(8*1024);
175184 final long start = System.nanoTime();
176185 for (int i = 0; i < loop; i++) {
2424 import java.nio.channels.FileChannel;
2525
2626 import org.apache.logging.log4j.categories.PerformanceTests;
27 import org.apache.logging.log4j.junit.InitialLoggerContext;
27 import org.apache.logging.log4j.junit.LoggerContextRule;
2828 import org.junit.ClassRule;
2929 import org.junit.Ignore;
3030 import org.junit.Test;
4242 private static final String CONFIG = "log4j2-perf.xml";
4343
4444 @ClassRule
45 public static InitialLoggerContext context = new InitialLoggerContext(CONFIG);
45 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
4646
4747 private final Logger logger = context.getLogger(PerformanceRun.class.getName());
4848
9494 }
9595
9696 private long writeToWriter(final int loop, final Writer w) throws Exception {
97 final Integer j = new Integer(2);
97 final Integer j = Integer.valueOf(2);
9898 final long start = System.nanoTime();
9999 for (int i = 0; i < loop; i++) {
100100 w.write("SEE IF THIS IS LOGGED " + j + '.');
103103 }
104104
105105 private long writeToStream(final int loop, final OutputStream os) throws Exception {
106 final Integer j = new Integer(2);
106 final Integer j = Integer.valueOf(2);
107107 final long start = System.nanoTime();
108108 for (int i = 0; i < loop; i++) {
109109 os.write(getBytes("SEE IF THIS IS LOGGED " + j + '.'));
112112 }
113113
114114 private long writeToChannel(final int loop, final FileChannel channel) throws Exception {
115 final Integer j = new Integer(2);
115 final Integer j = Integer.valueOf(2);
116116 final ByteBuffer buf = ByteBuffer.allocateDirect(8 * 1024);
117117 final long start = System.nanoTime();
118118 for (int i = 0; i < loop; i++) {
1717
1818 import org.apache.logging.log4j.Marker;
1919 import org.apache.logging.log4j.MarkerManager;
20 import org.apache.logging.log4j.junit.InitialLoggerContext;
20 import org.apache.logging.log4j.junit.LoggerContextRule;
2121 import org.apache.logging.log4j.test.appender.ListAppender;
2222 import org.junit.Before;
2323 import org.junit.ClassRule;
3636 private ListAppender app2;
3737
3838 @ClassRule
39 public static InitialLoggerContext context = new InitialLoggerContext(CONFIG);
39 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
4040
4141 org.apache.logging.log4j.Logger logger1 = context.getLogger("org.apache.logging.log4j.test1");
4242 org.apache.logging.log4j.Logger logger2 = context.getLogger("org.apache.logging.log4j.test2");
1919
2020 import org.apache.logging.log4j.Marker;
2121 import org.apache.logging.log4j.MarkerManager;
22 import org.apache.logging.log4j.junit.InitialLoggerContext;
22 import org.apache.logging.log4j.junit.LoggerContextRule;
2323 import org.apache.logging.log4j.test.appender.ListAppender;
2424 import org.junit.Before;
2525 import org.junit.ClassRule;
3737 private ListAppender app2;
3838
3939 @ClassRule
40 public static InitialLoggerContext context = new InitialLoggerContext(CONFIG);
40 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
4141
4242 org.apache.logging.log4j.Logger logger1 = context.getLogger("org.apache.logging.log4j.test1");
4343 org.apache.logging.log4j.Logger logger2 = context.getLogger("org.apache.logging.log4j.test2");
5353 super(ConfigurationSource.NULL_SOURCE);
5454
5555 final LoggerConfig root = getRootLogger();
56 final String l = System.getProperty(DEFAULT_LEVEL);
57 final Level level = (l != null && Level.getLevel(l) != null) ? Level.getLevel(l) : Level.ERROR;
56 final String name = System.getProperty(DEFAULT_LEVEL);
57 final Level level = (name != null && Level.getLevel(name) != null) ? Level.getLevel(name) : Level.ERROR;
5858 root.setLevel(level);
5959 }
6060 }
2222 import java.util.Map;
2323
2424 import org.apache.logging.log4j.Logger;
25 import org.apache.logging.log4j.junit.InitialLoggerContext;
25 import org.apache.logging.log4j.junit.LoggerContextRule;
2626 import org.apache.logging.log4j.message.MapMessage;
2727 import org.apache.logging.log4j.test.appender.ListAppender;
2828 import org.junit.Before;
3838 private ListAppender app;
3939
4040 @ClassRule
41 public static InitialLoggerContext context = new InitialLoggerContext(CONFIG);
41 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
4242
4343 @Before
4444 public void before() {
5757 public void testSimpleMap() {
5858 final Logger logger = context.getLogger(CollectionLoggingTest.class.getName());
5959 logger.error(System.getProperties());
60 final Map<String, String> map = new HashMap<String, String>();
60 final Map<String, String> map = new HashMap<>();
6161 map.put("MyKey1", "MyValue1");
6262 map.put("MyKey2", "MyValue2");
6363 logger.error(new MapMessage(map));
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core;
18
19 import java.io.File;
20
21 import org.apache.logging.log4j.LogManager;
22
23 public class CoreLoggerContexts {
24
25 private static void sleepAndCheck(final File checkFilePresence) throws InterruptedException {
26 Thread.sleep(100);
27 if (checkFilePresence.length() == 0) {
28 Thread.sleep(500);
29 }
30 }
31
32 public static void stopLoggerContext() {
33 ((LifeCycle) LogManager.getContext()).stop(); // stops async thread
34 }
35
36 public static void stopLoggerContext(final boolean currentContext) {
37 ((LifeCycle) LogManager.getContext(currentContext)).stop(); // stops async thread
38 }
39
40 public static void stopLoggerContext(final boolean currentContext, final File checkFilePresence) throws InterruptedException {
41 stopLoggerContext(currentContext);
42 sleepAndCheck(checkFilePresence);
43 }
44
45 public static void stopLoggerContext(final File checkFilePresence) throws InterruptedException {
46 stopLoggerContext();
47 sleepAndCheck(checkFilePresence);
48 }
49
50 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core;
17
18 import static org.hamcrest.Matchers.hasSize;
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertNotEquals;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertThat;
23
24 import java.util.List;
25
26 import org.apache.logging.log4j.Level;
27 import org.apache.logging.log4j.junit.LoggerContextRule;
28 import org.apache.logging.log4j.test.appender.ListAppender;
29 import org.junit.Before;
30 import org.junit.ClassRule;
31 import org.junit.Test;
32
33 /**
34 *
35 */
36 public class CustomLevelsOverrideTest {
37
38 private static final String CONFIG = "log4j-customLevels.xml";
39
40 @ClassRule
41 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
42
43 private ListAppender listAppender;
44 private Level warnLevel;
45 private Level infoLevel;
46 private Level debugLevel;
47
48 @Before
49 public void before() {
50 warnLevel = Level.getLevel("WARN");
51 infoLevel = Level.getLevel("INFO");
52 debugLevel = Level.getLevel("DEBUG");
53 listAppender = context.getListAppender("List1").clear();
54 }
55
56 @Test
57 public void testCustomLevelInts() {
58 // assertEquals(350, warnLevel.intLevel());
59 // assertEquals(450, infoLevel.intLevel());
60 // assertEquals(550, debugLevel.intLevel());
61 assertNotEquals(350, warnLevel.intLevel());
62 assertNotEquals(450, infoLevel.intLevel());
63 assertNotEquals(550, debugLevel.intLevel());
64 }
65
66 @Test
67 public void testCustomLevelPresence() {
68 assertNotNull(warnLevel);
69 assertNotNull(infoLevel);
70 assertNotNull(debugLevel);
71 }
72
73 @Test
74 public void testCustomLevelVsStdLevel() {
75 assertEquals(Level.WARN, warnLevel);
76 assertEquals(Level.INFO, infoLevel);
77 assertEquals(Level.DEBUG, debugLevel);
78 }
79
80 @Test
81 public void testLog() {
82 final Logger logger = context.getLogger();
83 final List<LogEvent> events = listAppender.getEvents();
84 assertThat(events, hasSize(0));
85 logger.debug("Hello, {}", "World");
86 assertThat(events, hasSize(1));
87 logger.log(warnLevel, "Hello DIAG");
88 assertThat(events, hasSize(2));
89 assertEquals(events.get(1).getLevel(), warnLevel);
90
91 }
92 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core;
17
18 import static org.hamcrest.Matchers.hasSize;
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.assertThat;
22
23 import java.util.List;
24
25 import org.apache.logging.log4j.Level;
26 import org.apache.logging.log4j.junit.LoggerContextRule;
27 import org.apache.logging.log4j.test.appender.ListAppender;
28 import org.junit.Before;
29 import org.junit.ClassRule;
30 import org.junit.Test;
31
32 /**
33 *
34 */
35 public class CustomLevelsTest {
36
37 private static final String CONFIG = "log4j-customLevels.xml";
38
39 @ClassRule
40 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
41
42 private ListAppender listAppender;
43 private Level diagLevel;
44 private Level noticeLevel;
45 private Level verboseLevel;
46
47 @Before
48 public void before() {
49 diagLevel = Level.getLevel("DIAG");
50 noticeLevel = Level.getLevel("NOTICE");
51 verboseLevel = Level.getLevel("VERBOSE");
52 listAppender = context.getListAppender("List1").clear();
53 }
54
55 @Test
56 public void testCustomLevelInts() {
57 assertEquals(350, diagLevel.intLevel());
58 assertEquals(450, noticeLevel.intLevel());
59 assertEquals(550, verboseLevel.intLevel());
60 }
61
62 @Test
63 public void testCustomLevelPresence() {
64 assertNotNull(diagLevel);
65 assertNotNull(noticeLevel);
66 assertNotNull(verboseLevel);
67 }
68
69 @Test
70 public void testLog() {
71 final Logger logger = context.getLogger();
72 final List<LogEvent> events = listAppender.getEvents();
73 assertThat(events, hasSize(0));
74 logger.debug("Hello, {}", "World");
75 assertThat(events, hasSize(1));
76 logger.log(diagLevel, "Hello DIAG");
77 assertThat(events, hasSize(2));
78 assertEquals(events.get(1).getLevel(), diagLevel);
79
80 }
81 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core;
17
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertNotNull;
20
21 import java.util.List;
22
23 import org.apache.logging.log4j.Level;
24 import org.apache.logging.log4j.core.appender.FileAppender;
25 import org.apache.logging.log4j.core.config.Configuration;
26 import org.apache.logging.log4j.core.filter.CompositeFilter;
27 import org.apache.logging.log4j.core.filter.ThresholdFilter;
28 import org.apache.logging.log4j.junit.LoggerContextRule;
29 import org.junit.Assert;
30 import org.junit.Before;
31 import org.junit.ClassRule;
32 import org.junit.Test;
33
34 /**
35 *
36 */
37 public class CustomLevelsWithFiltersTest {
38
39 private static final String CONFIG = "log4j-customLevelsWithFilters.xml";
40
41 @ClassRule
42 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
43
44 private Level infom1Level;
45 private Level infop1Level;
46
47 @Before
48 public void before() {
49 infom1Level = Level.getLevel("INFOM1");
50 infop1Level = Level.getLevel("INFOP1");
51 }
52
53 @Test
54 public void testConfiguration() {
55 final Configuration configuration = context.getConfiguration();
56 assertNotNull(configuration);
57 final FileAppender appender = configuration.getAppender("info");
58 assertNotNull(appender);
59 final CompositeFilter compFilter = (CompositeFilter) appender.getFilter();
60 assertNotNull(compFilter);
61 final List<Filter> filterList = compFilter.getFilters();
62 assertNotNull(filterList);
63 boolean foundLevel = false;
64 for (final Filter filter : filterList) {
65 final ThresholdFilter tFilter = (ThresholdFilter) filter;
66 if (infom1Level.equals(tFilter.getLevel())) {
67 foundLevel = true;
68 break;
69 }
70 }
71 Assert.assertTrue("Level not found: " + infom1Level, foundLevel);
72 }
73
74 @Test
75 public void testCustomLevelInts() {
76 assertEquals(399, infom1Level.intLevel());
77 assertEquals(401, infop1Level.intLevel());
78 }
79
80 @Test
81 public void testCustomLevelPresence() {
82 assertNotNull(infom1Level);
83 assertNotNull(infop1Level);
84 }
85
86 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core;
17
18 import org.apache.logging.log4j.junit.LoggerContextRule;
19 import org.junit.ClassRule;
20 import org.junit.Test;
21
22 /**
23 *
24 */
25 public class DeadlockTest {
26
27 private static final String CONFIG = "log4j-deadlock.xml";
28
29 @ClassRule
30 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
31
32 @Test
33 public void deadlockOnReconfigure() {
34 context.getContext().reconfigure();
35 }
36 }
1818 import java.util.List;
1919
2020 import org.apache.logging.log4j.Level;
21 import org.apache.logging.log4j.junit.InitialLoggerContext;
21 import org.apache.logging.log4j.junit.LoggerContextRule;
2222 import org.apache.logging.log4j.test.ExtendedLevels;
2323 import org.apache.logging.log4j.test.appender.ListAppender;
2424 import org.junit.Before;
3838 private ListAppender list2;
3939
4040 @ClassRule
41 public static InitialLoggerContext context = new InitialLoggerContext(CONFIG);
41 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
4242
4343 @Before
4444 public void before() {
1616 package org.apache.logging.log4j.core;
1717
1818 import static org.junit.Assert.assertNotSame;
19 import static org.junit.Assert.assertTrue;
1920
2021 import java.io.File;
22 import java.util.concurrent.TimeUnit;
2123
2224 import org.apache.logging.log4j.core.config.Configuration;
23 import org.apache.logging.log4j.junit.InitialLoggerContext;
25 import org.apache.logging.log4j.junit.LoggerContextRule;
2426 import org.junit.Before;
2527 import org.junit.ClassRule;
2628 import org.junit.Test;
3335 private static final String CONFIG = "target/test-classes/log4j-test2.xml";
3436
3537 @ClassRule
36 public static InitialLoggerContext context = new InitialLoggerContext(CONFIG);
38 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
3739
3840 private final org.apache.logging.log4j.Logger logger = context.getLogger("LoggerTest");
3941
4547 @Test
4648 public void testReconfiguration() throws Exception {
4749 final Configuration oldConfig = context.getConfiguration();
48 final int MONITOR_INTERVAL_SECONDS = 1;
50 final int MONITOR_INTERVAL_SECONDS = 5;
4951 final File file = new File(CONFIG);
5052 final long orig = file.lastModified();
5153 final long newTime = orig + 10000;
52 file.setLastModified(newTime);
53 int sleepMillis = (MONITOR_INTERVAL_SECONDS + 1) * 1000;
54 Thread.sleep(sleepMillis);
54 assertTrue("setLastModified should have succeeded.", file.setLastModified(newTime));
55 TimeUnit.SECONDS.sleep(MONITOR_INTERVAL_SECONDS + 1);
5556 for (int i = 0; i < 17; ++i) {
5657 logger.debug("Reconfigure");
5758 }
58 Thread.sleep(sleepMillis);
59 final Configuration newConfig = context.getConfiguration();
59 int loopCount = 0;
60 Configuration newConfig;
61 do {
62 Thread.sleep(100);
63 newConfig = context.getConfiguration();
64 } while (newConfig == oldConfig && loopCount < 5);
6065 assertNotSame("Reconfiguration failed", newConfig, oldConfig);
6166 }
6267 }
2020 import org.apache.logging.log4j.core.appender.RollingFileAppender;
2121 import org.apache.logging.log4j.core.util.Constants;
2222 import org.apache.logging.log4j.core.util.NetUtils;
23 import org.apache.logging.log4j.junit.InitialLoggerContext;
23 import org.apache.logging.log4j.junit.LoggerContextRule;
2424 import org.apache.logging.log4j.test.appender.ListAppender;
2525 import org.junit.Before;
2626 import org.junit.ClassRule;
4040 private RollingFileAppender hostFile;
4141
4242 @ClassRule
43 public static InitialLoggerContext context = new InitialLoggerContext(CONFIG);
43 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
4444
4545 @Before
4646 public void before() {
2020
2121 import java.io.File;
2222
23 import org.apache.logging.log4j.LogManager;
2423 import org.apache.logging.log4j.core.config.Configuration;
2524 import org.apache.logging.log4j.core.config.Configurator;
2625 import org.apache.logging.log4j.core.config.DefaultConfiguration;
4039
4140 @BeforeClass
4241 public static void setupClass() {
43 context = (LoggerContext) LogManager.getContext(false);
42 context = LoggerContext.getContext(false);
4443 }
4544
4645 @AfterClass
5554 assertNotNull("No configuration", cfg);
5655 assertTrue("Not set to default configuration", cfg instanceof DefaultConfiguration);
5756 final File file = new File(CONFIG);
58 final LoggerContext loggerContext = (LoggerContext) LogManager.getContext(null, false, file.toURI());
57 final LoggerContext loggerContext = LoggerContext.getContext(null, false, file.toURI());
5958 assertNotNull("No Logger Context", loggerContext);
6059 final Configuration newConfig = loggerContext.getConfiguration();
6160 assertTrue("Configuration not reset", cfg != newConfig);
6261 assertTrue("Reconfiguration failed", newConfig instanceof XmlConfiguration);
63 context = (LoggerContext) LogManager.getContext(false);
62 context = LoggerContext.getContext(false);
6463 final Configuration sameConfig = context.getConfiguration();
6564 assertTrue("Configuration should not have been reset", newConfig == sameConfig);
6665 }
2121 import org.apache.logging.log4j.Logger;
2222 import org.apache.logging.log4j.Marker;
2323 import org.apache.logging.log4j.MarkerManager;
24 import org.apache.logging.log4j.junit.InitialLoggerContext;
24 import org.apache.logging.log4j.junit.LoggerContextRule;
2525 import org.apache.logging.log4j.message.Message;
2626 import org.apache.logging.log4j.message.ObjectMessage;
2727 import org.apache.logging.log4j.test.appender.ListAppender;
4747 private ListAppender listFatal;
4848
4949 @ClassRule
50 public static InitialLoggerContext context = new InitialLoggerContext(CONFIG);
50 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
5151
5252 @Before
5353 public void before() {
3030 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
3131 import org.apache.logging.log4j.core.impl.LogEventFactory;
3232 import org.apache.logging.log4j.core.util.Constants;
33 import org.apache.logging.log4j.junit.InitialLoggerContext;
33 import org.apache.logging.log4j.junit.LoggerContextRule;
3434 import org.apache.logging.log4j.message.Message;
3535 import org.apache.logging.log4j.test.appender.ListAppender;
3636 import org.junit.Before;
4747 public class LogEventFactoryTest {
4848
4949 private static final String CONFIG = "log4j2-config.xml";
50 private static final InitialLoggerContext context = new InitialLoggerContext(CONFIG);
50 private static final LoggerContextRule context = new LoggerContextRule(CONFIG);
5151
5252 private ListAppender app;
5353
6969 }
7070 }
7171
72 private void resetLogEventFactory(LogEventFactory logEventFactory) throws IllegalAccessException {
73 Field field = FieldUtils.getField(LoggerConfig.class, "LOG_EVENT_FACTORY", true);
72 private void resetLogEventFactory(final LogEventFactory logEventFactory) throws IllegalAccessException {
73 final Field field = FieldUtils.getField(LoggerConfig.class, "LOG_EVENT_FACTORY", true);
7474 FieldUtils.removeFinalModifier(field, true);
7575 FieldUtils.writeStaticField(field, logEventFactory, false);
7676 }
3636
3737 @Test
3838 public void testSerialization() throws Exception {
39 final LogEvent event1 = new Log4jLogEvent(this.getClass().getName(), null, "org.apache.logging.log4j.core.Logger",
40 Level.INFO, new SimpleMessage("Hello, world!"), null);
39 final LogEvent event1 = Log4jLogEvent.newBuilder() //
40 .setLoggerName(this.getClass().getName()) //
41 .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
42 .setLevel(Level.INFO) //
43 .setMessage(new SimpleMessage("Hello, world!")) //
44 .build();
4145 final Exception parent = new IllegalStateException("Test");
4246 final Throwable child = new LoggingException("This is a test", parent);
43 final LogEvent event2 = new Log4jLogEvent(this.getClass().getName(), null, "org.apache.logging.log4j.core.Logger",
44 Level.INFO, new SimpleMessage("Hello, world!"), child);
47 final LogEvent event2 = Log4jLogEvent.newBuilder() //
48 .setLoggerName(this.getClass().getName()) //
49 .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
50 .setLevel(Level.INFO) //
51 .setMessage(new SimpleMessage("Hello, world!")) //
52 .setThrown(child) //
53 .build();
4554
4655 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
4756 final ObjectOutputStream oos = new ObjectOutputStream(baos);
5059
5160 final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
5261 final ObjectInputStream ois = new ObjectInputStream(bais);
53 LogEvent returned;
5462 try {
55 returned = (LogEvent) ois.readObject();
63 ois.readObject();
5664 } catch (final IOException ioe) {
5765 fail("Exception processing event1");
5866 }
5967 try {
60 returned = (LogEvent) ois.readObject();
68 ois.readObject();
6169 } catch (final IOException ioe) {
6270 fail("Exception processing event2");
6371 }
6472 }
6573
74 @Test
75 public void testNanoTimeIsNotSerialized1() throws Exception {
76 final LogEvent event1 = Log4jLogEvent.newBuilder() //
77 .setLoggerName(this.getClass().getName()) //
78 .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
79 .setLevel(Level.INFO) //
80 .setMessage(new SimpleMessage("Hello, world!")) //
81 .setThreadName("this must be initialized or the test fails") //
82 .setNanoTime(12345678L) //
83 .build();
84 final LogEvent copy = new Log4jLogEvent.Builder(event1).build();
85
86 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
87 final ObjectOutputStream oos = new ObjectOutputStream(baos);
88 oos.writeObject(event1);
89
90 final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
91 final ObjectInputStream ois = new ObjectInputStream(bais);
92
93 LogEvent actual = (LogEvent) ois.readObject();
94 assertNotEquals("Different event: nanoTime", copy, actual);
95 assertNotEquals("Different nanoTime", copy.getNanoTime(), actual.getNanoTime());
96 assertEquals("deserialized nanoTime is zero", 0, actual.getNanoTime());
97 }
98
99 @Test
100 public void testNanoTimeIsNotSerialized2() throws Exception {
101 final LogEvent event1 = Log4jLogEvent.newBuilder() //
102 .setLoggerName(this.getClass().getName()) //
103 .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
104 .setLevel(Level.INFO) //
105 .setMessage(new SimpleMessage("Hello, world!")) //
106 .setThreadName("this must be initialized or the test fails") //
107 .setNanoTime(0) //
108 .build();
109 final LogEvent event2 = new Log4jLogEvent.Builder(event1).build();
110
111 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
112 final ObjectOutputStream oos = new ObjectOutputStream(baos);
113 oos.writeObject(event1);
114
115 final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
116 final ObjectInputStream ois = new ObjectInputStream(bais);
117
118 LogEvent actual = (LogEvent) ois.readObject();
119 assertEquals("both zero nanoTime", event2, actual);
120 }
121
66122 public void testEquals() {
67 final LogEvent event1 = new Log4jLogEvent(this.getClass().getName(), null, "org.apache.logging.log4j.core.Logger",
68 Level.INFO, new SimpleMessage("Hello, world!"), null);
69 final LogEvent event2 = new Log4jLogEvent(this.getClass().getName(), null, "org.apache.logging.log4j.core.Logger",
70 Level.INFO, new SimpleMessage("Hello, Apache!"), null);
71 final LogEvent event3 = new Log4jLogEvent(this.getClass().getName(), null, "org.apache.logging.log4j.core.Logger",
72 Level.INFO, new SimpleMessage("Hello, Apache!"), null);
123 final LogEvent event1 = Log4jLogEvent.newBuilder() //
124 .setLoggerName(this.getClass().getName()) //
125 .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
126 .setLevel(Level.INFO) //
127 .setMessage(new SimpleMessage("Hello, world!")) //
128 .build();
129 final LogEvent event2 = Log4jLogEvent.newBuilder() //
130 .setLoggerName(this.getClass().getName()) //
131 .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
132 .setLevel(Level.INFO) //
133 .setMessage(new SimpleMessage("Hello, world!")) //
134 .build();
135 final LogEvent event3 = Log4jLogEvent.newBuilder() //
136 .setLoggerName(this.getClass().getName()) //
137 .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
138 .setLevel(Level.INFO) //
139 .setMessage(new SimpleMessage("Hello, world!")) //
140 .build();
73141 assertNotEquals("Events should not be equal", event1, event2);
74142 assertEquals("Events should be equal", event2, event3);
75143 }
1818 import java.util.Calendar;
1919
2020 import org.apache.logging.log4j.core.appender.FileAppender;
21 import org.apache.logging.log4j.junit.InitialLoggerContext;
21 import org.apache.logging.log4j.junit.LoggerContextRule;
2222 import org.junit.Before;
2323 import org.junit.ClassRule;
2424 import org.junit.Test;
3434 private FileAppender fileApp;
3535
3636 @ClassRule
37 public static InitialLoggerContext context = new InitialLoggerContext(CONFIG);
37 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
3838
3939 @Before
4040 public void before() {
4141 fileApp = (FileAppender) context.getRequiredAppender("File");
4242 }
43
4443
4544 @Test
4645 public void testFileName() {
1515 */
1616 package org.apache.logging.log4j.core;
1717
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertNotNull;
20 import static org.junit.Assert.assertNotSame;
21 import static org.junit.Assert.assertTrue;
22
1823 import java.io.File;
1924 import java.util.Date;
25 import java.util.HashMap;
2026 import java.util.List;
2127 import java.util.Locale;
28 import java.util.Map;
29 import java.util.concurrent.TimeUnit;
2230
2331 import org.apache.logging.log4j.Level;
2432 import org.apache.logging.log4j.LogManager;
2533 import org.apache.logging.log4j.MarkerManager;
2634 import org.apache.logging.log4j.ThreadContext;
2735 import org.apache.logging.log4j.core.config.Configuration;
36 import org.apache.logging.log4j.core.config.Configurator;
2837 import org.apache.logging.log4j.core.config.LoggerConfig;
29 import org.apache.logging.log4j.junit.InitialLoggerContext;
38 import org.apache.logging.log4j.junit.LoggerContextRule;
3039 import org.apache.logging.log4j.message.MessageFactory;
3140 import org.apache.logging.log4j.message.ParameterizedMessageFactory;
3241 import org.apache.logging.log4j.message.StringFormatterMessageFactory;
3342 import org.apache.logging.log4j.message.StructuredDataMessage;
3443 import org.apache.logging.log4j.test.appender.ListAppender;
3544 import org.junit.Before;
36 import org.junit.ClassRule;
45 import org.junit.Rule;
3746 import org.junit.Test;
38
39 import static org.junit.Assert.*;
4047
4148 /**
4249 *
4855 private ListAppender host;
4956 private ListAppender noThrown;
5057
51 @ClassRule
52 public static InitialLoggerContext context = new InitialLoggerContext(CONFIG);
53
58 @Rule
59 public LoggerContextRule context = new LoggerContextRule(CONFIG);
60
61 private void assertEventCount(final List<LogEvent> events, final int expected) {
62 assertEquals("Incorrect number of events.", expected, events.size());
63 }
64
5465 @Before
5566 public void before() {
67 logger = context.getLogger("LoggerTest");
68 loggerChild = context.getLogger("LoggerTest.child");
69 loggerGrandchild = context.getLogger("LoggerTest.child.grand");
70 //
5671 app = context.getListAppender("List").clear();
5772 host = context.getListAppender("HostTest").clear();
5873 noThrown = context.getListAppender("NoThrowable").clear();
5974 }
6075
61
62 org.apache.logging.log4j.Logger logger = context.getLogger("LoggerTest");
76 org.apache.logging.log4j.Logger logger;
77 org.apache.logging.log4j.Logger loggerChild;
78 org.apache.logging.log4j.Logger loggerGrandchild;
6379
6480 @Test
6581 public void basicFlow() {
6682 logger.entry();
6783 logger.exit();
6884 final List<LogEvent> events = app.getEvents();
69 assertEquals("Incorrect number of events. Expected 2, actual " + events.size(), 2, events.size());
85 assertEventCount(events, 2);
7086 }
7187
7288 @Test
7490 logger.entry(CONFIG);
7591 logger.exit(0);
7692 final List<LogEvent> events = app.getEvents();
77 assertEquals("Incorrect number of events. Expected 2, actual " + events.size(), 2, events.size());
93 assertEventCount(events, 2);
7894 }
7995
8096 @Test
8197 public void throwing() {
8298 logger.throwing(new IllegalArgumentException("Test Exception"));
8399 final List<LogEvent> events = app.getEvents();
84 assertEquals("Incorrect number of events. Expected 1, actual " + events.size(), 1, events.size());
100 assertEventCount(events, 1);
85101 }
86102
87103 @Test
92108 logger.catching(e);
93109 }
94110 final List<LogEvent> events = app.getEvents();
95 assertEquals("Incorrect number of events. Expected 1, actual " + events.size(), 1, events.size());
111 assertEventCount(events, 1);
96112 }
97113
98114 @Test
99115 public void debug() {
100116 logger.debug("Debug message");
101117 final List<LogEvent> events = app.getEvents();
102 assertEquals("Incorrect number of events. Expected 1, actual " + events.size(), 1, events.size());
118 assertEventCount(events, 1);
119 }
120
121 @Test
122 public void debugChangeLevel() {
123 logger.debug("Debug message 1");
124 final List<LogEvent> events = app.getEvents();
125 assertEventCount(events, 1);
126 Configurator.setLevel(logger.getName(), Level.OFF);
127 logger.debug("Debug message 2");
128 assertEventCount(events, 1);
129 Configurator.setLevel(logger.getName(), Level.DEBUG);
130 logger.debug("Debug message 3");
131 assertEventCount(events, 2);
132 }
133
134 @Test
135 public void debugChangeLevelAllChildrenLoggers() {
136 // Use logger AND child loggers
137 logger.debug("Debug message 1");
138 loggerChild.debug("Debug message 1 child");
139 loggerGrandchild.debug("Debug message 1 grandchild");
140 final List<LogEvent> events = app.getEvents();
141 assertEventCount(events, 3);
142 Configurator.setAllLevels(logger.getName(), Level.OFF);
143 logger.debug("Debug message 2");
144 loggerChild.warn("Warn message 2 child");
145 loggerGrandchild.fatal("Fatal message 2 grandchild");
146 assertEventCount(events, 3);
147 Configurator.setAllLevels(logger.getName(), Level.DEBUG);
148 logger.debug("Debug message 3");
149 loggerChild.warn("Trace message 3 child");
150 loggerGrandchild.trace("Fatal message 3 grandchild");
151 assertEventCount(events, 5);
152 }
153
154 @Test
155 public void debugChangeLevelChildLogger() {
156 // Use logger AND child loggers
157 logger.debug("Debug message 1");
158 loggerChild.debug("Debug message 1 child");
159 loggerGrandchild.debug("Debug message 1 grandchild");
160 final List<LogEvent> events = app.getEvents();
161 assertEventCount(events, 3);
162 Configurator.setLevel(logger.getName(), Level.OFF);
163 logger.debug("Debug message 2");
164 loggerChild.debug("Debug message 2 child");
165 loggerGrandchild.debug("Debug message 2 grandchild");
166 assertEventCount(events, 3);
167 Configurator.setLevel(logger.getName(), Level.DEBUG);
168 logger.debug("Debug message 3");
169 loggerChild.debug("Debug message 3 child");
170 loggerGrandchild.debug("Debug message 3 grandchild");
171 assertEventCount(events, 6);
172 }
173
174 @Test
175 public void debugChangeLevelsChildLoggers() {
176 org.apache.logging.log4j.Logger loggerChild = context.getLogger(logger.getName() + ".child");
177 // Use logger AND loggerChild
178 logger.debug("Debug message 1");
179 loggerChild.debug("Debug message 1 child");
180 final List<LogEvent> events = app.getEvents();
181 assertEventCount(events, 2);
182 Configurator.setLevel(logger.getName(), Level.ERROR);
183 Configurator.setLevel(loggerChild.getName(), Level.DEBUG);
184 logger.debug("Debug message 2");
185 loggerChild.debug("Debug message 2 child");
186 assertEventCount(events, 3);
187 Configurator.setLevel(logger.getName(), Level.DEBUG);
188 logger.debug("Debug message 3");
189 loggerChild.debug("Debug message 3 child");
190 assertEventCount(events, 5);
191 }
192
193 @Test
194 public void debugChangeLevelsMap() {
195 logger.debug("Debug message 1");
196 final List<LogEvent> events = app.getEvents();
197 assertEventCount(events, 1);
198 Map<String, Level> map = new HashMap<>();
199 map.put(logger.getName(), Level.OFF);
200 Configurator.setLevel(map);
201 logger.debug("Debug message 2");
202 assertEventCount(events, 1);
203 map.put(logger.getName(), Level.DEBUG);
204 Configurator.setLevel(map);
205 logger.debug("Debug message 3");
206 assertEventCount(events, 2);
207 }
208
209 @Test
210 public void debugChangeLevelsMapChildLoggers() {
211 logger.debug("Debug message 1");
212 loggerChild.debug("Debug message 1 C");
213 loggerGrandchild.debug("Debug message 1 GC");
214 final List<LogEvent> events = app.getEvents();
215 assertEventCount(events, 3);
216 Map<String, Level> map = new HashMap<>();
217 map.put(logger.getName(), Level.OFF);
218 map.put(loggerChild.getName(), Level.DEBUG);
219 map.put(loggerGrandchild.getName(), Level.WARN);
220 Configurator.setLevel(map);
221 logger.debug("Debug message 2");
222 loggerChild.debug("Debug message 2 C");
223 loggerGrandchild.debug("Debug message 2 GC");
224 assertEventCount(events, 4);
225 map.put(logger.getName(), Level.DEBUG);
226 map.put(loggerChild.getName(), Level.OFF);
227 map.put(loggerGrandchild.getName(), Level.DEBUG);
228 Configurator.setLevel(map);
229 logger.debug("Debug message 3");
230 loggerChild.debug("Debug message 3 C");
231 loggerGrandchild.debug("Debug message 3 GC");
232 assertEventCount(events, 6);
233 }
234
235 @Test
236 public void debugChangeRootLevel() {
237 logger.debug("Debug message 1");
238 final List<LogEvent> events = app.getEvents();
239 assertEventCount(events, 1);
240 Configurator.setRootLevel(Level.OFF);
241 logger.debug("Debug message 2");
242 assertEventCount(events, 1);
243 Configurator.setRootLevel(Level.DEBUG);
244 logger.debug("Debug message 3");
245 assertEventCount(events, 2);
103246 }
104247
105248 @Test
108251 StringFormatterMessageFactory.INSTANCE, ParameterizedMessageFactory.INSTANCE);
109252 testLogger.debug("%,d", Integer.MAX_VALUE);
110253 final List<LogEvent> events = app.getEvents();
111 assertEquals("Incorrect number of events. Expected 1, actual " + events.size(), 1, events.size());
254 assertEventCount(events, 1);
112255 assertEquals(String.format("%,d", Integer.MAX_VALUE), events.get(0).getMessage().getFormattedMessage());
113256 }
114257
117260 final Logger testLogger = testMessageFactoryMismatch("getLogger_String_MessageFactoryMismatchNull", StringFormatterMessageFactory.INSTANCE, null);
118261 testLogger.debug("%,d", Integer.MAX_VALUE);
119262 final List<LogEvent> events = app.getEvents();
120 assertEquals("Incorrect number of events. Expected 1, actual " + events.size(), 1, events.size());
263 assertEventCount(events, 1);
121264 assertEquals(String.format("%,d", Integer.MAX_VALUE), events.get(0).getMessage().getFormattedMessage());
122265 }
123266
136279 public void debugObject() {
137280 logger.debug(new Date());
138281 final List<LogEvent> events = app.getEvents();
139 assertEquals("Incorrect number of events. Expected 1, actual " + events.size(), 1, events.size());
282 assertEventCount(events, 1);
140283 }
141284
142285 @Test
143286 public void debugWithParms() {
144287 logger.debug("Hello, {}", "World");
145288 final List<LogEvent> events = app.getEvents();
146 assertEquals("Incorrect number of events. Expected 1, actual " + events.size(), 1, events.size());
289 assertEventCount(events, 1);
147290 }
148291
149292 @Test
175318 ThreadContext.clearMap();
176319 logger.debug("Debug message");
177320 final List<LogEvent> events = app.getEvents();
178 assertEquals("Incorrect number of events. Expected 2, actual " + events.size(), 2, events.size());
321 assertEventCount(events, 2);
179322 }
180323
181324 @Test
190333 logger.info(MarkerManager.getMarker("EVENT"), msg);
191334 ThreadContext.clearMap();
192335 final List<LogEvent> events = app.getEvents();
193 assertEquals("Incorrect number of events. Expected 1, actual " + events.size(), 1, events.size());
336 assertEventCount(events, 1);
194337 }
195338
196339 @Test
197340 public void testReconfiguration() throws Exception {
198341 final Configuration oldConfig = context.getConfiguration();
199 final int MONITOR_INTERVAL_SECONDS = 1;
342 final int MONITOR_INTERVAL_SECONDS = 5;
200343 final File file = new File("target/test-classes/" + CONFIG);
201344 final long orig = file.lastModified();
202345 final long newTime = orig + 10000;
203 file.setLastModified(newTime);
204 Thread.sleep((MONITOR_INTERVAL_SECONDS + 1) * 1000);
346 assertTrue("setLastModified should have succeeded.", file.setLastModified(newTime));
347 TimeUnit.SECONDS.sleep(MONITOR_INTERVAL_SECONDS + 1);
205348 for (int i = 0; i < 17; ++i) {
206349 logger.debug("Reconfigure");
207350 }
208351 Thread.sleep(100);
352 for (int i = 0; i < 20; i++) {
353 if (context.getConfiguration() != oldConfig) {
354 break;
355 }
356 Thread.sleep(50);
357 }
209358 final Configuration newConfig = context.getConfiguration();
210359 assertNotNull("No configuration", newConfig);
211360 assertNotSame("Reconfiguration failed", newConfig, oldConfig);
216365 final Logger localLogger = context.getLogger("org.apache.test");
217366 localLogger.error("Test parent additivity");
218367 final List<LogEvent> events = app.getEvents();
219 assertEquals("Incorrect number of events. Expected 1, actual " + events.size(), 1, events.size());
368 assertEventCount(events, 1);
220369 }
221370
222371 @Test
2020 import org.apache.logging.log4j.*;
2121 import org.apache.logging.log4j.core.config.Configuration;
2222 import org.apache.logging.log4j.core.config.LoggerConfig;
23 import org.apache.logging.log4j.junit.InitialLoggerContext;
23 import org.apache.logging.log4j.junit.LoggerContextRule;
2424 import org.apache.logging.log4j.test.appender.ListAppender;
2525 import org.junit.Before;
2626 import org.junit.ClassRule;
3737 private ListAppender app;
3838
3939 @ClassRule
40 public static InitialLoggerContext context = new InitialLoggerContext(CONFIG);
40 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
4141
4242 @Before
4343 public void before() {
5151 List<LogEvent> events = app.getEvents();
5252 assertEquals("Incorrect number of events. Expected 1, actual " + events.size(), 1, events.size());
5353 app.clear();
54 final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
54 final LoggerContext ctx = LoggerContext.getContext(false);
5555 final Configuration config = ctx.getConfiguration();
5656 final LoggerConfig loggerConfig = config.getLoggerConfig(LogManager.ROOT_LOGGER_NAME);
5757 /* You could also specify the actual logger name as below and it will return the LoggerConfig used by the Logger.
1717
1818 import org.apache.logging.log4j.core.appender.ConsoleAppender;
1919 import org.apache.logging.log4j.core.layout.PatternLayout;
20 import org.apache.logging.log4j.junit.InitialLoggerContext;
20 import org.apache.logging.log4j.junit.LoggerContextRule;
2121 import org.junit.ClassRule;
2222 import org.junit.Test;
2323
3131 private static final String CONFIG = "log4j-lookup.xml";
3232
3333 @ClassRule
34 public static InitialLoggerContext context = new InitialLoggerContext(CONFIG);
34 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
3535
3636 @Test
3737 public void testHostname() {
1616 package org.apache.logging.log4j.core;
1717
1818 import org.apache.logging.log4j.core.config.Configuration;
19 import org.apache.logging.log4j.junit.InitialLoggerContext;
19 import org.apache.logging.log4j.junit.LoggerContextRule;
2020 import org.junit.ClassRule;
2121 import org.junit.Test;
2222
3030 private static final String CONFIG = "log4j-test3.xml";
3131
3232 @ClassRule
33 public static InitialLoggerContext context = new InitialLoggerContext(CONFIG);
33 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
3434
3535 @Test
3636 public void testShutdownFlag() {
4747 @BeforeClass
4848 public static void setupClass() {
4949
50 final Configuration config = ((LoggerContext)LogManager.getContext()).getConfiguration();
51 if (!DefaultConfiguration.DEFAULT_NAME.equals(config.getName())) {
52 System.out.println("Configuration was " + config.getName());
53 ((LoggerContext)LogManager.getContext()).start(new DefaultConfiguration());
54 }
50 final Configuration config = LoggerContext.getContext().getConfiguration();
51
52 if (!DefaultConfiguration.DEFAULT_NAME.equals(config.getName())) {
53 System.out.println("Configuration was " + config.getName());
54 LoggerContext.getContext().start(new DefaultConfiguration());
55 }
5556
5657 for (int i=0; i < WARMUP; ++i) {
5758 overhead();
2121
2222 import org.apache.logging.log4j.MarkerManager;
2323 import org.apache.logging.log4j.ThreadContext;
24 import org.apache.logging.log4j.junit.InitialLoggerContext;
24 import org.apache.logging.log4j.junit.LoggerContextRule;
2525 import org.apache.logging.log4j.message.StructuredDataMessage;
2626 import org.apache.logging.log4j.test.appender.ListAppender;
2727 import org.junit.Before;
3939 private ListAppender app;
4040
4141 @ClassRule
42 public static InitialLoggerContext context = new InitialLoggerContext(CONFIG);
42 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
4343
4444 @Before
4545 public void setUp() throws Exception {
2323 import org.apache.logging.log4j.Level;
2424 import org.apache.logging.log4j.Logger;
2525 import org.apache.logging.log4j.categories.PerformanceTests;
26 import org.apache.logging.log4j.junit.InitialLoggerContext;
26 import org.apache.logging.log4j.junit.LoggerContextRule;
2727 import org.junit.ClassRule;
2828 import org.junit.Test;
2929 import org.junit.experimental.categories.Category;
4242 private static final int LOOP_CNT = 25;
4343 private static final int THREADS = 4;
4444 private static final AtomicInteger counter = new AtomicInteger(0);
45 private static final InitialLoggerContext context = new InitialLoggerContext(CONFIG);
45 private static final LoggerContextRule context = new LoggerContextRule(CONFIG);
4646
4747 private final Logger logger = context.getLogger(ThreadedTest.class.getName());
4848 private volatile Level lvl = Level.DEBUG;
2525 import org.apache.logging.log4j.core.util.ClockFactory;
2626 import org.apache.logging.log4j.core.util.ClockFactoryTest;
2727 import org.apache.logging.log4j.core.util.Constants;
28 import org.apache.logging.log4j.junit.InitialLoggerContext;
28 import org.apache.logging.log4j.junit.LoggerContextRule;
2929 import org.apache.logging.log4j.message.SimpleMessage;
3030 import org.apache.logging.log4j.message.TimestampMessage;
3131 import org.apache.logging.log4j.test.appender.ListAppender;
4646 private ListAppender app;
4747
4848 @ClassRule
49 public static InitialLoggerContext context = new InitialLoggerContext("log4j2-744.xml");
49 public static LoggerContextRule context = new LoggerContextRule("log4j2-744.xml");
5050
5151 @BeforeClass
5252 public static void beforeClass() {
1919
2020 import org.apache.logging.log4j.EventLogger;
2121 import org.apache.logging.log4j.ThreadContext;
22 import org.apache.logging.log4j.junit.InitialLoggerContext;
22 import org.apache.logging.log4j.junit.LoggerContextRule;
2323 import org.apache.logging.log4j.message.StructuredDataMessage;
2424 import org.junit.ClassRule;
2525 import org.junit.Test;
3232 private static final String CONFIG = "xml-events.xml";
3333
3434 @ClassRule
35 public static InitialLoggerContext context = new InitialLoggerContext(CONFIG);
35 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
3636
3737 @Test
3838 public void testEvents() {
1919
2020 import org.apache.logging.log4j.LogManager;
2121 import org.apache.logging.log4j.Logger;
22 import org.apache.logging.log4j.junit.InitialLoggerContext;
22 import org.apache.logging.log4j.junit.LoggerContextRule;
2323 import org.apache.logging.log4j.test.appender.ListAppender;
2424 import org.junit.After;
2525 import org.junit.Before;
26 import org.junit.Rule;
26 import org.junit.ClassRule;
2727 import org.junit.Test;
2828
2929 import static org.junit.Assert.*;
3434 public class AsyncAppenderNoLocationTest {
3535 private ListAppender app;
3636
37 @Rule
38 public InitialLoggerContext init = new InitialLoggerContext("log4j-asynch-no-location.xml");
37 @ClassRule
38 public static LoggerContextRule init = new LoggerContextRule("log4j-asynch-no-location.xml");
3939
4040 @Before
4141 public void setUp() throws Exception {
42 this.app = (ListAppender) this.init.getAppender("List");
42 this.app = (ListAppender) init.getAppender("List");
4343 }
4444
4545 @After
4343 @BeforeClass
4444 public static void setupClass() {
4545 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
46 ctx = (LoggerContext) LogManager.getContext(false);
46 ctx = LoggerContext.getContext(false);
4747 config = ctx.getConfiguration();
4848 listAppender = (ListAppender) config.getAppender("List");
4949 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.appender;
17
18 import java.io.IOException;
19
20 import org.apache.logging.log4j.LogManager;
21 import org.apache.logging.log4j.Logger;
22 import org.apache.logging.log4j.core.LoggerContext;
23 import org.apache.logging.log4j.core.config.Configurator;
24
25 /**
26 * Shows how to use ANSI escape codes to color messages. Each message is printed
27 * to the console in color, but the rest of the log entry (time stamp for
28 * example) is in the default color for that console.
29 * <p>
30 * Running from a Windows command line from the root of the project:
31 * </p>
32 *
33 * <pre>
34 * java -classpath log4j-core\target\test-classes;log4j-core\target\classes;log4j-api\target\classes;%HOME%\.m2\repository\org\fusesource\jansi\jansi\1.11\jansi-1.11.jar; org.apache.logging.log4j.core.appender.ConsoleAppenderNoAnsiStyleLayoutMain log4j-core/target/test-classes/log4j2-console-style-ansi.xml
35 * </pre>
36 */
37 public class ConsoleAppenderDefaultSuppressedThrowable {
38
39 private static final Logger LOG = LogManager.getLogger(ConsoleAppenderDefaultSuppressedThrowable.class);
40
41 public static void main(final String[] args) {
42 final String config = args.length == 0 ? "target/test-classes/log4j2-console-default-suppressed-throwable.xml"
43 : args[0];
44 test(args, config);
45 }
46
47 static void test(final String[] args, final String config) {
48 // System.out.println(System.getProperty("java.class.path"));
49 final LoggerContext ctx = Configurator.initialize(ConsoleAppenderDefaultSuppressedThrowable.class.getName(),
50 config);
51 try {
52 final IOException ioEx = new IOException("test suppressed");
53 ioEx.addSuppressed(new IOException("test suppressed 1", new IOException("test 1")));
54 final IOException ioEx2 = new IOException("test 2");
55 ioEx2.addSuppressed(new IOException("test 3"));
56 ioEx.addSuppressed(new IOException("test suppressed 2", ioEx2));
57 final IOException e = new IOException("test", ioEx);
58 LOG.error("Error message {}, suppressed?", "Hi", e);
59 System.out.println("printStackTrace");
60 e.printStackTrace();
61 } finally {
62 Configurator.shutdown(ctx);
63 }
64 }
65
66 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.appender;
17
18
19 /**
20 * Tests LOG4J2-1002.
21 */
22 public class ConsoleAppenderJira1002ShortThrowableLayoutMain {
23
24 public static void main(final String[] args) {
25 ConsoleAppenderNoAnsiStyleLayoutMain.test(args, "target/test-classes/log4j2-1002.xml");
26 }
27
28 }
2323 import org.apache.logging.log4j.core.config.Configurator;
2424
2525 /**
26 * Shows how to use ANSI escape codes to color messages. Each message is printed to the console in color, but the rest
27 * of the log entry (time stamp for example) is in the default color for that console.
26 * Shows how to use ANSI escape codes to color messages. Each message is printed
27 * to the console in color, but the rest of the log entry (time stamp for
28 * example) is in the default color for that console.
2829 * <p>
2930 * Running from a Windows command line from the root of the project:
3031 * </p>
3536 */
3637 public class ConsoleAppenderNoAnsiStyleLayoutMain {
3738
38 private static final Logger LOG = LogManager.getLogger(ConsoleAppenderNoAnsiStyleLayoutMain.class);
39 private static final Logger LOG = LogManager.getLogger(ConsoleAppenderNoAnsiStyleLayoutMain.class);
3940
40 public static void main(final String[] args) {
41 // System.out.println(System.getProperty("java.class.path"));
42 final String config = args.length == 0 ? "target/test-classes/log4j2-console-style-no-ansi.xml" : args[0];
43 final LoggerContext ctx = Configurator.initialize(ConsoleAppenderNoAnsiStyleLayoutMain.class.getName(), config);
44 try {
45 LOG.fatal("Fatal message.");
46 LOG.error("Error message.");
47 LOG.warn("Warning message.");
48 LOG.info("Information message.");
49 LOG.debug("Debug message.");
50 LOG.trace("Trace message.");
51 LOG.error("Error message.", new IOException("test"));
52 // This will log the stack trace as well:
53 LOG.error("Error message {}", "Hi", new IOException("test"));
54 } finally {
55 Configurator.shutdown(ctx);
56 }
57 }
41 private static void logThrowableFromMethod() {
42 LOG.error("Error message.", new IOException("test"));
43 }
44
45 public static void main(final String[] args) {
46 final String config = args.length == 0 ? "target/test-classes/log4j2-console-style-no-ansi.xml" : args[0];
47 test(args, config);
48 }
49
50 static void test(final String[] args, final String config) {
51 // System.out.println(System.getProperty("java.class.path"));
52 final LoggerContext ctx = Configurator.initialize(ConsoleAppenderNoAnsiStyleLayoutMain.class.getName(), config);
53 try {
54 LOG.fatal("Fatal message.");
55 LOG.error("Error message.");
56 LOG.warn("Warning message.");
57 LOG.info("Information message.");
58 LOG.debug("Debug message.");
59 LOG.trace("Trace message.");
60 logThrowableFromMethod();
61 // This will log the stack trace as well:
62 final IOException ioException = new IOException("test");
63 LOG.error("Error message {}", "Hi", ioException);
64 final Throwable t = new IOException("test suppressed");
65 t.addSuppressed(new IOException("test suppressed 2", ioException));
66 LOG.error("Error message {}, suppressed?", "Hi", t);
67 LOG.error("Error message {}, suppressed?", "Hi", new IOException("test", t));
68 } finally {
69 Configurator.shutdown(ctx);
70 }
71 }
5872
5973 }
1818 import static org.easymock.EasyMock.anyInt;
1919 import static org.easymock.EasyMock.anyObject;
2020 import static org.easymock.EasyMock.expectLastCall;
21
2122 import static org.junit.Assert.assertFalse;
2223 import static org.junit.Assert.assertNotNull;
2324 import static org.junit.Assert.assertTrue;
2829 import org.apache.logging.log4j.Level;
2930 import org.apache.logging.log4j.core.Layout;
3031 import org.apache.logging.log4j.core.LogEvent;
32 import org.apache.logging.log4j.core.appender.ConsoleAppender.Target;
3133 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
3234 import org.apache.logging.log4j.core.layout.PatternLayout;
3335 import org.apache.logging.log4j.core.util.Constants;
3436 import org.apache.logging.log4j.message.SimpleMessage;
3537 import org.easymock.EasyMockSupport;
3638 import org.junit.AfterClass;
39 import org.junit.Before;
3740 import org.junit.BeforeClass;
3841 import org.junit.Test;
3942
4245 */
4346 public class ConsoleAppenderTest {
4447
45 private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
46 EasyMockSupport mocks = new EasyMockSupport();
47 PrintStream psMock = mocks.createMock("psMock", PrintStream.class);
48 private static final String LOG4J_SKIP_JANSI = "log4j.skipJansi";
49
50 @AfterClass
51 public static void afterClass() {
52 System.clearProperty(LOG4J_SKIP_JANSI);
53 }
4854
4955 @BeforeClass
50 public static void before() {
51 System.setProperty("log4j.skipJansi", "true");
56 public static void beforeClass() {
57 System.setProperty(LOG4J_SKIP_JANSI, "true");
5258 }
5359
54 @AfterClass
55 public static void after() {
56 System.clearProperty("log4j.skipJansi");
60 ByteArrayOutputStream baos;
61
62 EasyMockSupport mocks;
63
64 PrintStream psMock;
65
66 @Before
67 public void before() {
68 System.setProperty(LOG4J_SKIP_JANSI, "true");
69 mocks = new EasyMockSupport();
70 psMock = mocks.createMock("psMock", PrintStream.class);
71 baos = new ByteArrayOutputStream();
72 }
73
74 private enum SystemSetter {
75 SYSTEM_OUT {
76 @Override
77 void systemSet(final PrintStream printStream) {
78 System.setOut(printStream);
79 }
80 },
81 SYSTEM_ERR {
82 @Override
83 void systemSet(final PrintStream printStream) {
84 System.setErr(printStream);
85 }
86 },
87 ;
88 abstract void systemSet(PrintStream printStream);
89 }
90
91 private void testConsoleStreamManagerDoesNotClose(final PrintStream ps, final String targetName, final SystemSetter systemSetter) {
92 try {
93 psMock.write((byte[]) anyObject(), anyInt(), anyInt());
94 expectLastCall().anyTimes();
95 psMock.flush();
96 expectLastCall().anyTimes();
97
98 mocks.replayAll();
99 systemSetter.systemSet(psMock);
100 final Layout<String> layout = PatternLayout.createLayout(null, null, null, null, false, false, null, null);
101 final ConsoleAppender app = ConsoleAppender.createAppender(layout, null, targetName, "Console", "false",
102 "false");
103 app.start();
104 assertTrue("Appender did not start", app.isStarted());
105
106 final LogEvent event = Log4jLogEvent.newBuilder() //
107 .setLoggerName("TestLogger") //
108 .setLoggerFqcn(ConsoleAppenderTest.class.getName()) //
109 .setLevel(Level.INFO) //
110 .setMessage(new SimpleMessage("Test")) //
111 .build();
112 app.append(event);
113
114 app.stop();
115 assertFalse("Appender did not stop", app.isStarted());
116 } finally {
117 systemSetter.systemSet(ps);
118 }
119 mocks.verifyAll();
57120 }
58121
59122 @Test
60 public void testConsoleStreamManagerDoesNotClose() {
61 final PrintStream ps = System.out;
123 public void testFollowSystemErr() {
124 testFollowSystemPrintStream(System.err, Target.SYSTEM_ERR, SystemSetter.SYSTEM_ERR);
125 }
62126
63 psMock.write((byte[]) anyObject(), anyInt(), anyInt());
64 expectLastCall().anyTimes();
65 psMock.flush();
127 @Test
128 public void testFollowSystemOut() {
129 testFollowSystemPrintStream(System.out, Target.SYSTEM_OUT, SystemSetter.SYSTEM_OUT);
130 }
66131
67 mocks.replayAll();
68 System.setOut(psMock);
69 final Layout<String> layout = PatternLayout.createLayout(null, null, null, null, false, false, null, null);
70 final ConsoleAppender app = ConsoleAppender.createAppender(layout, null, "SYSTEM_OUT", "Console", "false",
71 "false");
132 private void testFollowSystemPrintStream(final PrintStream ps, final Target target, final SystemSetter systemSetter) {
133 final ConsoleAppender app = ConsoleAppender.newBuilder().setTarget(target).setFollow(true)
134 .setIgnoreExceptions(false).build();
72135 app.start();
73 assertTrue("Appender did not start", app.isStarted());
136 try {
137 final LogEvent event = Log4jLogEvent.newBuilder() //
138 .setLoggerName("TestLogger") //
139 .setLoggerFqcn(ConsoleAppenderTest.class.getName()) //
140 .setLevel(Level.INFO) //
141 .setMessage(new SimpleMessage("Test")) //
142 .build();
74143
75 final LogEvent event = new Log4jLogEvent("TestLogger", null, ConsoleAppenderTest.class.getName(), Level.INFO,
76 new SimpleMessage("Test"), null);
77 app.append(event);
78
79 app.stop();
80 assertFalse("Appender did not stop", app.isStarted());
81
82 System.setOut(ps);
83 mocks.verifyAll();
84 }
85
86 @Test
87 public void testFollow() {
88 final PrintStream ps = System.out;
89 final ConsoleAppender app = ConsoleAppender.newBuilder()
90 .setFollow(true)
91 .setIgnoreExceptions(false)
92 .build();
93 app.start();
94 final LogEvent event = new Log4jLogEvent("TestLogger", null, ConsoleAppenderTest.class.getName(), Level.INFO,
95 new SimpleMessage("Test"), null);
96
97 assertTrue("Appender did not start", app.isStarted());
98 System.setOut(new PrintStream(baos));
99 app.append(event);
100 System.setOut(ps);
101 final String msg = baos.toString();
102 assertNotNull("No message", msg);
103 assertTrue("Incorrect message: " + msg , msg.endsWith("Test" + Constants.LINE_SEPARATOR));
104 app.stop();
144 assertTrue("Appender did not start", app.isStarted());
145 systemSetter.systemSet(new PrintStream(baos));
146 try {
147 app.append(event);
148 } finally {
149 systemSetter.systemSet(ps);
150 }
151 final String msg = baos.toString();
152 assertNotNull("No message", msg);
153 assertTrue("Incorrect message: \"" + msg + "\"", msg.endsWith("Test" + Constants.LINE_SEPARATOR));
154 } finally {
155 app.stop();
156 }
105157 assertFalse("Appender did not stop", app.isStarted());
106158 }
107159
160 @Test
161 public void testSystemErrStreamManagerDoesNotClose() {
162 testConsoleStreamManagerDoesNotClose(System.err, "SYSTEM_ERR", SystemSetter.SYSTEM_ERR);
163 }
164
165 @Test
166 public void testSystemOutStreamManagerDoesNotClose() {
167 testConsoleStreamManagerDoesNotClose(System.out, "SYSTEM_OUT", SystemSetter.SYSTEM_OUT);
168 }
169
108170 }
1919
2020 import org.apache.logging.log4j.Logger;
2121 import org.apache.logging.log4j.core.LogEvent;
22 import org.apache.logging.log4j.junit.InitialLoggerContext;
22 import org.apache.logging.log4j.junit.LoggerContextRule;
2323 import org.apache.logging.log4j.test.appender.FailOnceAppender;
2424 import org.apache.logging.log4j.test.appender.ListAppender;
2525 import org.junit.After;
2626 import org.junit.Before;
27 import org.junit.Rule;
27 import org.junit.ClassRule;
2828 import org.junit.Test;
2929
3030 import static org.junit.Assert.*;
3838 private Logger logger;
3939 private Logger onceLogger;
4040
41 @Rule
42 public InitialLoggerContext init = new InitialLoggerContext("log4j-failover.xml");
41 @ClassRule
42 public static LoggerContextRule init = new LoggerContextRule("log4j-failover.xml");
4343
4444 @Before
4545 public void setUp() throws Exception {
46 app = this.init.getListAppender("List");
47 foApp = (FailOnceAppender) this.init.getAppender("Once");
48 logger = this.init.getLogger("LoggerTest");
49 onceLogger = this.init.getLogger("Once");
46 app = init.getListAppender("List");
47 foApp = (FailOnceAppender) init.getAppender("Once");
48 logger = init.getLogger("LoggerTest");
49 onceLogger = init.getLogger("Once");
5050 }
5151
5252 @After
5454
5555 @AfterClass
5656 public static void cleanupClass() {
57 assertTrue("Manager for " + FILENAME + " not removed", !OutputStreamManager.hasManager(FILENAME));
57 assertTrue("Manager for " + FILENAME + " not removed", !AbstractManager.hasManager(FILENAME));
5858 }
5959
6060 @Test
7676 long prevLen = curLen;
7777 assertTrue("File length: " + curLen, curLen == 0);
7878 for (int i = 0; i < 100; ++i) {
79 final LogEvent event = new Log4jLogEvent("TestLogger", null, FileAppenderTest.class.getName(), Level.INFO,
80 new SimpleMessage("Test"), null, null, null, this.getClass().getSimpleName(), null,
81 System.currentTimeMillis());
79 final LogEvent event = Log4jLogEvent.newBuilder().setLoggerName("TestLogger") //
80 .setLoggerFqcn(FileAppenderTest.class.getName()).setLevel(Level.INFO) //
81 .setMessage(new SimpleMessage("Test")).setThreadName(this.getClass().getSimpleName()) //
82 .setTimeMillis(System.currentTimeMillis()).build();
8283 try {
8384 appender.append(event);
8485 curLen = file.length();
165166 app.start();
166167 assertTrue("Appender did not start", app.isStarted());
167168 for (int i = 0; i < count; ++i) {
168 final LogEvent event = new Log4jLogEvent("TestLogger", null, FileAppenderTest.class.getName(), Level.INFO,
169 new SimpleMessage("Test"), null, null, null, name, null, System.currentTimeMillis());
169 final LogEvent event = Log4jLogEvent.newBuilder().setLoggerName("TestLogger")
170 .setLoggerFqcn(FileAppenderTest.class.getName()).setLevel(Level.INFO)
171 .setMessage(new SimpleMessage("Test")).setThreadName(name).setTimeMillis(System.currentTimeMillis())
172 .build();
170173 try {
171174 app.append(event);
172175 Thread.sleep(25); // Give up control long enough for another thread/process to occasionally do
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.appender;
18
19 import org.slf4j.LoggerFactory;
20
21 public class JansiConsoleAppenderJira965 {
22
23 public static void main(final String[] args) {
24 System.out.println("Able to print on Windows");
25 LoggerFactory.getLogger(JansiConsoleAppenderJira965.class);
26 System.out.println("Unable to print on Windows");
27 }
28
29 }
2121
2222 import org.apache.logging.log4j.Logger;
2323 import org.apache.logging.log4j.junit.CleanFiles;
24 import org.apache.logging.log4j.junit.InitialLoggerContext;
24 import org.apache.logging.log4j.junit.LoggerContextRule;
2525 import org.junit.Rule;
2626 import org.junit.Test;
2727 import org.junit.rules.RuleChain;
3535
3636 private final File logFile = new File("target", "JsonCompleteFileAppenderTest.log");
3737
38 private final InitialLoggerContext init = new InitialLoggerContext("JsonCompleteFileAppenderTest.xml");
38 private final LoggerContextRule init = new LoggerContextRule("JsonCompleteFileAppenderTest.xml");
3939 private final CleanFiles files = new CleanFiles(logFile);
4040
4141 @Rule
6868 log.warn("Test log2");
6969 assertEquals("not grown", expectedFileLength, f.length());
7070 } finally {
71 ((LoggerContext) LogManager.getContext(false)).stop();
71 (LoggerContext.getContext(false)).stop();
7272 }
7373 final int LINESEP = System.getProperty("line.separator").length();
7474 assertEquals("Shrunk to actual used size", 474 + 2 * LINESEP, f.length());
6868 log.warn(new String(text));
6969 assertEquals("grown again", 256 * 3, f.length());
7070 } finally {
71 ((LoggerContext) LogManager.getContext(false)).stop();
71 (LoggerContext.getContext(false)).stop();
7272 }
7373 final int LINESEP = System.getProperty("line.separator").length();
7474 assertEquals("Shrunk to actual used size", 658 + 3 * LINESEP, f.length());
6363 log.warn("Test log2");
6464 assertEquals("not grown", MemoryMappedFileManager.DEFAULT_REGION_LENGTH, f.length());
6565 } finally {
66 ((LoggerContext) LogManager.getContext(false)).stop();
66 (LoggerContext.getContext(false)).stop();
6767 }
6868 final int LINESEP = System.getProperty("line.separator").length();
6969 assertEquals("Shrunk to actual used size", 186 + 2 * LINESEP, f.length());
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.appender;
17
18 import java.io.BufferedReader;
19 import java.io.File;
20 import java.io.FileOutputStream;
21 import java.io.FileReader;
22 import java.io.IOException;
23
24 import org.apache.logging.log4j.core.util.Closer;
25 import org.junit.Test;
26
27 import static org.junit.Assert.*;
28
29 /**
30 * Tests the MemoryMappedFileManager class.
31 *
32 * @since 2.1
33 */
34 public class MemoryMappedFileManagerTest {
35
36 @Test
37 public void testRemapAfterInitialMapSizeExceeded() throws IOException {
38 final int mapSize = 64; // very small, on purpose
39 final File file = File.createTempFile("log4j2", "test");
40 file.deleteOnExit();
41 assertEquals(0, file.length());
42
43 final boolean append = false;
44 final boolean force = false;
45 final MemoryMappedFileManager manager = MemoryMappedFileManager.getFileManager(file.getAbsolutePath(), append,
46 force, mapSize, null, null);
47
48 byte[] msg;
49
50 for (int i = 0; i < 1000; i++) {
51 msg = ("Message " + i + "\n").getBytes();
52 manager.write(msg, 0, msg.length);
53 }
54
55 manager.release();
56
57 BufferedReader reader = null;
58 try {
59 reader = new BufferedReader(new FileReader(file));
60 String line = reader.readLine();
61
62 for (int i = 0; i < 1000; i++) {
63 assertNotNull("line", line);
64 assertTrue("line incorrect", line.contains("Message " + i));
65 line = reader.readLine();
66 }
67 } finally {
68 Closer.close(reader);
69 }
70 }
71
72 @Test
73 public void testAppendDoesNotOverwriteExistingFile() throws IOException {
74 final File file = File.createTempFile("log4j2", "test");
75 file.deleteOnExit();
76 assertEquals(0, file.length());
77
78 final int initialLength = 4 * 1024;
79
80 // create existing file
81 FileOutputStream fos = null;
82 try {
83 fos = new FileOutputStream(file);
84 fos.write(new byte[initialLength], 0, initialLength);
85 fos.flush();
86 } finally {
87 fos.close();
88 }
89 assertEquals("all flushed to disk", initialLength, file.length());
90
91 final boolean isAppend = true;
92 final boolean isForce = false;
93 final MemoryMappedFileManager manager = MemoryMappedFileManager.getFileManager(file.getAbsolutePath(),
94 isAppend, isForce, MemoryMappedFileManager.DEFAULT_REGION_LENGTH, null, null);
95
96 manager.write(new byte[initialLength], 0, initialLength);
97 manager.release();
98 final int expected = initialLength * 2;
99 assertEquals("appended, not overwritten", expected, file.length());
100 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.appender;
17
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertNotNull;
20 import static org.junit.Assert.assertTrue;
21
22 import java.io.BufferedReader;
23 import java.io.File;
24 import java.io.FileOutputStream;
25 import java.io.FileReader;
26 import java.io.IOException;
27
28 import org.junit.Test;
29
30 /**
31 * Tests the MemoryMappedFileManager class.
32 *
33 * @since 2.1
34 */
35 public class MemoryMappedFileManagerTest {
36
37 @Test
38 public void testRemapAfterInitialMapSizeExceeded() throws IOException {
39 final int mapSize = 64; // very small, on purpose
40 final File file = File.createTempFile("log4j2", "test");
41 file.deleteOnExit();
42 assertEquals(0, file.length());
43
44 final boolean append = false;
45 final boolean force = false;
46 final MemoryMappedFileManager manager = MemoryMappedFileManager.getFileManager(file.getAbsolutePath(), append,
47 force, mapSize, null, null);
48
49 byte[] msg;
50
51 for (int i = 0; i < 1000; i++) {
52 msg = ("Message " + i + "\n").getBytes();
53 manager.write(msg, 0, msg.length);
54 }
55
56 manager.release();
57
58 try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
59 String line = reader.readLine();
60 for (int i = 0; i < 1000; i++) {
61 assertNotNull("line", line);
62 assertTrue("line incorrect", line.contains("Message " + i));
63 line = reader.readLine();
64 }
65 }
66 }
67
68 @Test
69 public void testAppendDoesNotOverwriteExistingFile() throws IOException {
70 final File file = File.createTempFile("log4j2", "test");
71 file.deleteOnExit();
72 assertEquals(0, file.length());
73
74 final int initialLength = 4 * 1024;
75
76 // create existing file
77 try (FileOutputStream fos = new FileOutputStream(file)) {
78 fos.write(new byte[initialLength], 0, initialLength);
79 fos.flush();
80 }
81 assertEquals("all flushed to disk", initialLength, file.length());
82
83 final boolean isAppend = true;
84 final boolean isForce = false;
85 final MemoryMappedFileManager manager = MemoryMappedFileManager.getFileManager(file.getAbsolutePath(),
86 isAppend, isForce, MemoryMappedFileManager.DEFAULT_REGION_LENGTH, null, null);
87
88 manager.write(new byte[initialLength], 0, initialLength);
89 manager.release();
90 final int expected = initialLength * 2;
91 assertEquals("appended, not overwritten", expected, file.length());
92 }
10193 }
3535 @Test
3636 public void testAppender() {
3737 final Layout<String> layout = PatternLayout.createDefaultLayout();
38 final InMemoryAppender app = new InMemoryAppender("test", layout, null, false);
39 final LogEvent event = new Log4jLogEvent("TestLogger", null, OutputStreamAppenderTest.class.getName(), Level.INFO,
40 new SimpleMessage("Test"), null);
38 final boolean writeHeader = true;
39 final InMemoryAppender app = new InMemoryAppender("test", layout, null, false, writeHeader);
40 final String expectedHeader = null;
41 assertMessage("Test", app, expectedHeader);
42 }
43
44 @Test
45 public void testHeaderRequested() {
46 final PatternLayout layout = PatternLayout.newBuilder().withHeader("HEADERHEADER").build();
47 final boolean writeHeader = true;
48 final InMemoryAppender app = new InMemoryAppender("test", layout, null, false, writeHeader);
49 final String expectedHeader = "HEADERHEADER";
50 assertMessage("Test", app, expectedHeader);
51 }
52
53 @Test
54 public void testHeaderSuppressed() {
55 final PatternLayout layout = PatternLayout.newBuilder().withHeader("HEADERHEADER").build();
56 final boolean writeHeader = false;
57 final InMemoryAppender app = new InMemoryAppender("test", layout, null, false, writeHeader);
58 final String expectedHeader = null;
59 assertMessage("Test", app, expectedHeader);
60 }
61
62 private void assertMessage(final String string, final InMemoryAppender app, final String header) {
63 final LogEvent event = Log4jLogEvent.newBuilder() //
64 .setLoggerName("TestLogger") //
65 .setLoggerFqcn(OutputStreamAppenderTest.class.getName()) //
66 .setLevel(Level.INFO) //
67 .setMessage(new SimpleMessage("Test")) //
68 .build();
4169 app.start();
4270 assertTrue("Appender did not start", app.isStarted());
4371 app.append(event);
72 app.append(event);
4473 final String msg = app.toString();
4574 assertNotNull("No message", msg);
46 assertTrue("Incorrect message: " + msg , msg.endsWith("Test" + Constants.LINE_SEPARATOR));
75 final String expectedHeader = header == null ? "" : header;
76 final String expected = expectedHeader + "Test" + Constants.LINE_SEPARATOR + "Test" + Constants.LINE_SEPARATOR;
77 assertTrue("Incorrect message: " + msg, msg.equals(expected));
4778 app.stop();
4879 assertFalse("Appender did not stop", app.isStarted());
4980 }
2323
2424 import org.apache.logging.log4j.Logger;
2525 import org.apache.logging.log4j.junit.CleanFiles;
26 import org.apache.logging.log4j.junit.InitialLoggerContext;
26 import org.apache.logging.log4j.junit.LoggerContextRule;
2727 import org.hamcrest.Matcher;
2828 import org.junit.Rule;
2929 import org.junit.Test;
5353 );
5454 }
5555
56 private final InitialLoggerContext init;
56 private final LoggerContextRule init;
5757 private final CleanFiles files;
5858
5959 @Rule
6363 private final boolean locationEnabled;
6464
6565 public RandomAccessFileAppenderTests(final String testName, final boolean locationEnabled) {
66 this.init = new InitialLoggerContext(testName + ".xml");
66 this.init = new LoggerContextRule(testName + ".xml");
6767 this.logFile = new File("target", testName + ".log");
6868 this.files = new CleanFiles(this.logFile);
6969 this.locationEnabled = locationEnabled;
2121 import java.io.OutputStream;
2222 import java.io.RandomAccessFile;
2323
24 import org.apache.logging.log4j.core.util.NullOutputStream;
2425 import org.junit.Test;
2526
2627 import static org.junit.Assert.*;
3940 public void testWrite_multiplesOfBufferSize() throws IOException {
4041 final File file = File.createTempFile("log4j2", "test");
4142 file.deleteOnExit();
42 final RandomAccessFile raf = new RandomAccessFile(file, "rw");
43 final OutputStream os = new RandomAccessFileManager.DummyOutputStream();
44 final RandomAccessFileManager manager = new RandomAccessFileManager(raf, file.getName(), os,
45 false, RandomAccessFileManager.DEFAULT_BUFFER_SIZE, null, null);
43 try (final RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
44 final OutputStream os = NullOutputStream.NULL_OUTPUT_STREAM;
45 final RandomAccessFileManager manager = new RandomAccessFileManager(raf, file.getName(), os, false,
46 RandomAccessFileManager.DEFAULT_BUFFER_SIZE, null, null, true);
4647
47 final int size = RandomAccessFileManager.DEFAULT_BUFFER_SIZE * 3;
48 final byte[] data = new byte[size];
49 manager.write(data); // no buffer overflow exception
48 final int size = RandomAccessFileManager.DEFAULT_BUFFER_SIZE * 3;
49 final byte[] data = new byte[size];
50 manager.write(data); // no buffer overflow exception
5051
51 // buffer is full but not flushed yet
52 assertEquals(RandomAccessFileManager.DEFAULT_BUFFER_SIZE * 2, raf.length());
53 }
52 // buffer is full but not flushed yet
53 assertEquals(RandomAccessFileManager.DEFAULT_BUFFER_SIZE * 2, raf.length());
54 }}
5455
5556 /**
5657 * Test method for
6162 public void testWrite_dataExceedingBufferSize() throws IOException {
6263 final File file = File.createTempFile("log4j2", "test");
6364 file.deleteOnExit();
64 final RandomAccessFile raf = new RandomAccessFile(file, "rw");
65 final OutputStream os = new RandomAccessFileManager.DummyOutputStream();
66 final RandomAccessFileManager manager = new RandomAccessFileManager(raf, file.getName(), os,
67 false, RandomAccessFileManager.DEFAULT_BUFFER_SIZE, null, null);
65 try (final RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
66 final OutputStream os = NullOutputStream.NULL_OUTPUT_STREAM;
67 final RandomAccessFileManager manager = new RandomAccessFileManager(raf, file.getName(), os, false,
68 RandomAccessFileManager.DEFAULT_BUFFER_SIZE, null, null, true);
6869
69 final int size = RandomAccessFileManager.DEFAULT_BUFFER_SIZE * 3 + 1;
70 final byte[] data = new byte[size];
71 manager.write(data); // no exception
72 assertEquals(RandomAccessFileManager.DEFAULT_BUFFER_SIZE * 3, raf.length());
70 final int size = RandomAccessFileManager.DEFAULT_BUFFER_SIZE * 3 + 1;
71 final byte[] data = new byte[size];
72 manager.write(data); // no exception
73 assertEquals(RandomAccessFileManager.DEFAULT_BUFFER_SIZE * 3, raf.length());
7374
74 manager.flush();
75 assertEquals(size, raf.length()); // all data written to file now
76 }
75 manager.flush();
76 assertEquals(size, raf.length()); // all data written to file now
77 }}
7778
7879 @Test
7980 public void testConfigurableBufferSize() throws IOException {
8081 final File file = File.createTempFile("log4j2", "test");
8182 file.deleteOnExit();
82 final RandomAccessFile raf = new RandomAccessFile(file, "rw");
83 final OutputStream os = new RandomAccessFileManager.DummyOutputStream();
84 final int bufferSize = 4 * 1024;
85 assertNotEquals(bufferSize, RandomAccessFileManager.DEFAULT_BUFFER_SIZE);
86
87 final RandomAccessFileManager manager = new RandomAccessFileManager(raf, file.getName(), os,
88 false, bufferSize, null, null);
89
90 // check the resulting buffer size is what was requested
91 assertEquals(bufferSize, manager.getBufferSize());
92 }
83 try (final RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
84 final OutputStream os = NullOutputStream.NULL_OUTPUT_STREAM;
85 final int bufferSize = 4 * 1024;
86 assertNotEquals(bufferSize, RandomAccessFileManager.DEFAULT_BUFFER_SIZE);
87
88 final RandomAccessFileManager manager = new RandomAccessFileManager(raf, file.getName(), os, false,
89 bufferSize, null, null, true);
90
91 // check the resulting buffer size is what was requested
92 assertEquals(bufferSize, manager.getBufferSize());
93 }}
9394
9495 @Test
9596 public void testWrite_dataExceedingMinBufferSize() throws IOException {
9697 final File file = File.createTempFile("log4j2", "test");
9798 file.deleteOnExit();
98 final RandomAccessFile raf = new RandomAccessFile(file, "rw");
99 final OutputStream os = new RandomAccessFileManager.DummyOutputStream();
100 final int bufferSize = 1;
101 final RandomAccessFileManager manager = new RandomAccessFileManager(raf, file.getName(), os,
102 false, bufferSize, null, null);
99 try (final RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
100 final OutputStream os = NullOutputStream.NULL_OUTPUT_STREAM;
101 final int bufferSize = 1;
102 final RandomAccessFileManager manager = new RandomAccessFileManager(raf, file.getName(), os, false,
103 bufferSize, null, null, true);
103104
104 final int size = bufferSize * 3 + 1;
105 final byte[] data = new byte[size];
106 manager.write(data); // no exception
107 assertEquals(bufferSize * 3, raf.length());
105 final int size = bufferSize * 3 + 1;
106 final byte[] data = new byte[size];
107 manager.write(data); // no exception
108 assertEquals(bufferSize * 3, raf.length());
108109
109 manager.flush();
110 assertEquals(size, raf.length()); // all data written to file now
111 }
110 manager.flush();
111 assertEquals(size, raf.length()); // all data written to file now
112 }}
112113
113114 @Test
114115 public void testAppendDoesNotOverwriteExistingFile() throws IOException {
120121 final byte[] bytes = new byte[4 * 1024];
121122
122123 // create existing file
123 FileOutputStream fos = null;
124 try {
125 fos = new FileOutputStream(file);
124 try (FileOutputStream fos = new FileOutputStream(file)) {
126125 fos.write(bytes, 0, bytes.length);
127126 fos.flush();
128 } finally {
129 fos.close();
130127 }
131128 assertEquals("all flushed to disk", bytes.length, file.length());
132129
2222
2323 import org.apache.logging.log4j.LogManager;
2424 import org.apache.logging.log4j.Logger;
25 import org.apache.logging.log4j.core.LifeCycle;
25 import org.apache.logging.log4j.core.CoreLoggerContexts;
2626 import org.apache.logging.log4j.core.config.ConfigurationFactory;
2727 import org.junit.BeforeClass;
2828 import org.junit.Test;
3939
4040 @Test
4141 public void testRollover() throws Exception {
42 final File f = new File("target", "RollingRandomAccessFileAppenderTest.log");
42 final File file = new File("target", "RollingRandomAccessFileAppenderTest.log");
4343 // System.out.println(f.getAbsolutePath());
4444 final File after1 = new File("target", "afterRollover-1.log");
45 f.delete();
45 file.delete();
4646 after1.delete();
4747
4848 final Logger log = LogManager.getLogger("com.foo.Bar");
5050 log.info(msg);
5151 Thread.sleep(50);
5252
53 BufferedReader reader = new BufferedReader(new FileReader(f));
53 BufferedReader reader = new BufferedReader(new FileReader(file));
5454 final String line1 = reader.readLine();
5555 assertTrue(line1.contains(msg));
5656 reader.close();
6767 final String trigger = "This message triggers rollover.";
6868 log.warn(trigger);
6969
70 ((LifeCycle) LogManager.getContext()).stop(); // stop async thread
70 CoreLoggerContexts.stopLoggerContext(); // stop async thread
7171
7272 final int MAX_ATTEMPTS = 50;
7373 int count = 0;
7777
7878 assertTrue("afterRollover-1.log created", after1.exists());
7979
80 reader = new BufferedReader(new FileReader(f));
80 reader = new BufferedReader(new FileReader(file));
8181 final String new1 = reader.readLine();
8282 assertTrue("after rollover only new msg", new1.contains(trigger));
8383 assertNull("No more lines", reader.readLine());
8484 reader.close();
85 f.delete();
85 file.delete();
8686
8787 reader = new BufferedReader(new FileReader(after1));
8888 final String old1 = reader.readLine();
2525 import org.apache.logging.dumbster.smtp.SimpleSmtpServer;
2626 import org.apache.logging.dumbster.smtp.SmtpMessage;
2727 import org.apache.logging.log4j.Level;
28 import org.apache.logging.log4j.LogManager;
2928 import org.apache.logging.log4j.core.Logger;
3029 import org.apache.logging.log4j.core.LoggerContext;
3130 import org.apache.logging.log4j.core.net.MimeMessageBuilder;
109108
110109 @Test
111110 public void testCyclicBuffer() {
112 final CyclicBuffer<Integer> buffer = new CyclicBuffer<Integer>(
111 final CyclicBuffer<Integer> buffer = new CyclicBuffer<>(
113112 Integer.class, 3);
114113
115114 assertTrue(buffer.isEmpty());
136135 HOST, PORT, null, null, "false", "3", null, null, "true");
137136 appender.start();
138137
139 final LoggerContext context = (LoggerContext) LogManager.getContext();
138 final LoggerContext context = LoggerContext.getContext();
140139 final Logger root = context.getLogger("SMTPAppenderTest");
141140 root.addAppender(appender);
142141 root.setAdditive(false);
3535 import java.util.concurrent.TimeUnit;
3636
3737 import org.apache.logging.log4j.Level;
38 import org.apache.logging.log4j.LogManager;
3938 import org.apache.logging.log4j.LoggingException;
4039 import org.apache.logging.log4j.ThreadContext;
4140 import org.apache.logging.log4j.core.Appender;
6059 private static final String DYN_PORT = String.valueOf(PORTNUM2);
6160 private static final String ERROR_PORT = String.valueOf(AvailablePortFinder.getNextAvailable());
6261
63 private static BlockingQueue<LogEvent> list = new ArrayBlockingQueue<LogEvent>(10);
62 private static BlockingQueue<LogEvent> list = new ArrayBlockingQueue<>(10);
6463
6564 private static TCPSocketServer tcpServer;
6665 private static UDPSocketServer udpServer;
6766
68 LoggerContext context = (LoggerContext) LogManager.getContext();
67 LoggerContext context = LoggerContext.getContext();
6968 Logger root = context.getLogger("SocketAppenderTest");
7069
7170 private static int tcpCount = 0;
7776 tcpServer.start();
7877 udpServer = new UDPSocketServer();
7978 udpServer.start();
80 ((LoggerContext) LogManager.getContext()).reconfigure();
79 (LoggerContext.getContext()).reconfigure();
8180 }
8281
8382 @AfterClass
111110 root.addAppender(appender);
112111 root.setAdditive(false);
113112 root.setLevel(Level.DEBUG);
114 String tcKey = "UUID";
115 String expectedUuidStr = UUID.randomUUID().toString();
113 final String tcKey = "UUID";
114 final String expectedUuidStr = UUID.randomUUID().toString();
116115 ThreadContext.put(tcKey, expectedUuidStr);
117116 ThreadContext.push(expectedUuidStr);
118117 final String expectedExMsg = "This is a test";
2121 import java.util.Map;
2222
2323 import org.apache.logging.log4j.Level;
24 import org.apache.logging.log4j.LogManager;
2524 import org.apache.logging.log4j.MarkerManager;
2625 import org.apache.logging.log4j.ThreadContext;
2726 import org.apache.logging.log4j.core.Appender;
3837 protected static final String line1 =
3938 "TestApp - Audit [Transfer@18060 Amount=\"200.00\" FromAccount=\"123457\" ToAccount=\"123456\"]" +
4039 "[RequestContext@18060 ipAddress=\"192.168.0.120\" loginId=\"JohnDoe\"] Transfer Complete";
41 protected LoggerContext ctx = (LoggerContext) LogManager.getContext();
40 protected LoggerContext ctx = LoggerContext.getContext();
4241 protected static final int DEFAULT_TIMEOUT_IN_MS = 100;
4342 protected static final int PORTNUM = 8199;
4443 protected MockSyslogServer syslogServer;
4544 protected SyslogAppender appender;
4645 protected Logger root = ctx.getLogger("SyslogAppenderTest");
47 protected List<String> sentMessages = new ArrayList<String>();
46 protected List<String> sentMessages = new ArrayList<>();
4847 protected boolean includeNewLine = true;
4948
5049 @BeforeClass
5150 public static void setupClass() throws Exception {
52 ((LoggerContext) LogManager.getContext()).reconfigure();
51 (LoggerContext.getContext()).reconfigure();
5352 }
5453
5554 protected void sendAndCheckLegacyBSDMessages(final List<String> messagesToSend) throws InterruptedException {
1717
1818 import java.util.Arrays;
1919
20 import org.apache.logging.log4j.util.Chars;
2021 import org.junit.Assert;
2122 import org.junit.Test;
2223
4950 }
5051
5152 private byte[] getByteRepresentation(final String message) {
52 final String frame = message.length() + Character.toString(TlsSyslogFrame.SPACE) + message;
53 final String frame = message.length() + Character.toString(Chars.SPACE) + message;
5354 final byte[] representation = frame.getBytes();
5455 return representation;
5556 }
2121
2222 import org.apache.logging.log4j.LogManager;
2323 import org.apache.logging.log4j.Logger;
24 import org.apache.logging.log4j.core.LifeCycle;
24 import org.apache.logging.log4j.core.CoreLoggerContexts;
2525 import org.apache.logging.log4j.core.config.ConfigurationFactory;
2626 import org.junit.BeforeClass;
2727 import org.junit.Test;
4646 final Logger log = LogManager.getLogger("com.foo.Bar");
4747 final String logMsg = "Message flushed with immediate flush=false";
4848 log.info(logMsg);
49 ((LifeCycle) LogManager.getContext(false)).stop(); // stop async thread
49 CoreLoggerContexts.stopLoggerContext(false, file); // stop async thread
5050
5151 final BufferedReader reader = new BufferedReader(new FileReader(file));
5252 String line1;
2828
2929 import org.apache.logging.log4j.LogManager;
3030 import org.apache.logging.log4j.Logger;
31 import org.apache.logging.log4j.core.LifeCycle;
31 import org.apache.logging.log4j.core.CoreLoggerContexts;
3232 import org.apache.logging.log4j.core.config.ConfigurationFactory;
3333 import org.junit.BeforeClass;
3434 import org.junit.Ignore;
5555 log.warn("Message 1");
5656 log.info("Message 2");
5757 log.debug("Message 3");
58 ((LifeCycle) LogManager.getContext()).stop(); // stop async thread
58 CoreLoggerContexts.stopLoggerContext(file); // stop async thread
5959 this.validateXmlSchema(file);
6060 }
6161
6363 public void validateXmlSchemaNoEvents() throws Exception {
6464 final File file = new File("target", "XmlCompactFileAsyncAppenderValidationTest.log.xml");
6565 file.delete();
66 ((LifeCycle) LogManager.getContext()).stop(); // stop async thread
66 CoreLoggerContexts.stopLoggerContext(file); // stop async thread
6767 this.validateXmlSchema(file);
6868 }
6969
2121
2222 import org.apache.logging.log4j.LogManager;
2323 import org.apache.logging.log4j.Logger;
24 import org.apache.logging.log4j.core.LifeCycle;
24 import org.apache.logging.log4j.core.CoreLoggerContexts;
2525 import org.apache.logging.log4j.core.config.ConfigurationFactory;
2626 import org.junit.BeforeClass;
2727 import org.junit.Test;
4141
4242 @Test
4343 public void testFlushAtEndOfBatch() throws Exception {
44 final File f = new File("target", "XmlCompleteFileAppenderTest.log");
44 final File file = new File("target", "XmlCompleteFileAppenderTest.log");
4545 // System.out.println(f.getAbsolutePath());
46 f.delete();
46 file.delete();
4747 final Logger log = LogManager.getLogger("com.foo.Bar");
4848 final String logMsg = "Message flushed with immediate flush=false";
4949 log.info(logMsg);
50 ((LifeCycle) LogManager.getContext(false)).stop(); // stop async thread
50 CoreLoggerContexts.stopLoggerContext(false, file); // stop async thread
5151
52 final BufferedReader reader = new BufferedReader(new FileReader(f));
52 final BufferedReader reader = new BufferedReader(new FileReader(file));
5353 String line1;
5454 String line2;
5555 String line3;
6161 line4 = reader.readLine();
6262 } finally {
6363 reader.close();
64 f.delete();
64 file.delete();
6565 }
6666 assertNotNull("line1", line1);
6767 final String msg1 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
2121
2222 import org.apache.logging.log4j.LogManager;
2323 import org.apache.logging.log4j.Logger;
24 import org.apache.logging.log4j.core.LifeCycle;
24 import org.apache.logging.log4j.core.CoreLoggerContexts;
2525 import org.apache.logging.log4j.core.config.ConfigurationFactory;
2626 import org.junit.BeforeClass;
2727 import org.junit.Test;
4141
4242 @Test
4343 public void testFlushAtEndOfBatch() throws Exception {
44 final File f = new File("target", "XmlFileAppenderTest.log");
44 final File file = new File("target", "XmlFileAppenderTest.log");
4545 // System.out.println(f.getAbsolutePath());
46 f.delete();
46 file.delete();
4747 final Logger log = LogManager.getLogger("com.foo.Bar");
4848 final String logMsg = "Message flushed with immediate flush=false";
4949 log.info(logMsg);
50 ((LifeCycle) LogManager.getContext(false)).stop(); // stop async thread
50 CoreLoggerContexts.stopLoggerContext(false, file); // stop async thread
5151
52 final BufferedReader reader = new BufferedReader(new FileReader(f));
52 final BufferedReader reader = new BufferedReader(new FileReader(file));
5353 String line1;
5454 String line2;
5555 String line3;
5959 line3 = reader.readLine();
6060 } finally {
6161 reader.close();
62 f.delete();
62 file.delete();
6363 }
6464 assertNotNull("line1", line1);
6565
2121
2222 import org.apache.logging.log4j.LogManager;
2323 import org.apache.logging.log4j.Logger;
24 import org.apache.logging.log4j.core.LifeCycle;
24 import org.apache.logging.log4j.core.CoreLoggerContexts;
2525 import org.apache.logging.log4j.core.config.ConfigurationFactory;
2626 import org.junit.BeforeClass;
2727 import org.junit.Ignore;
4343 @Test
4444 @Ignore
4545 public void testFlushAtEndOfBatch() throws Exception {
46 final File f = new File("target", "XmlRandomAccessFileAppenderTest.log");
46 final File file = new File("target", "XmlRandomAccessFileAppenderTest.log");
4747 // System.out.println(f.getAbsolutePath());
48 f.delete();
48 file.delete();
4949 final Logger log = LogManager.getLogger("com.foo.Bar");
5050 final String logMsg = "Message flushed with immediate flush=false";
5151 log.info(logMsg);
52 ((LifeCycle) LogManager.getContext(false)).stop(); // stop async thread
52 CoreLoggerContexts.stopLoggerContext(false, file); // stop async thread
5353
54 final BufferedReader reader = new BufferedReader(new FileReader(f));
54 final BufferedReader reader = new BufferedReader(new FileReader(file));
5555 String line1;
5656 String line2;
5757 String line3;
6363 line4 = reader.readLine();
6464 } finally {
6565 reader.close();
66 f.delete();
66 file.delete();
6767 }
6868 assertNotNull("line1", line1);
6969 final String msg1 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
6565 }
6666 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY,
6767 "org/apache/logging/log4j/core/appender/db/jdbc/" + configFileName);
68 final LoggerContext context = (LoggerContext) LogManager.getContext(false);
68 final LoggerContext context = LoggerContext.getContext(false);
6969 if (context.getConfiguration() instanceof DefaultConfiguration) {
7070 context.reconfigure();
7171 }
7474
7575 @After
7676 public void tearDown() throws SQLException {
77 final LoggerContext context = (LoggerContext) LogManager.getContext(false);
77 final LoggerContext context = LoggerContext.getContext(false);
7878 try {
7979 final Appender appender = context.getConfiguration().getAppender("databaseAppender");
8080 assertNotNull("The appender should not be null.", appender);
2525 import javax.sql.DataSource;
2626
2727 import org.apache.logging.log4j.Level;
28 import org.apache.logging.log4j.LogManager;
2928 import org.apache.logging.log4j.core.LoggerContext;
3029 import org.apache.logging.log4j.core.config.ConfigurationFactory;
3130 import org.apache.logging.log4j.status.StatusLogger;
6665 @BeforeClass
6766 public static void beforeClass() {
6867 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
69 final LoggerContext ctx = (LoggerContext) LogManager.getContext();
68 final LoggerContext ctx = LoggerContext.getContext();
7069 ctx.reconfigure();
7170 final StatusLogger logger = StatusLogger.getLogger();
7271 logger.setLevel(Level.FATAL);
2121 import javax.sql.DataSource;
2222
2323 import org.apache.logging.log4j.Level;
24 import org.apache.logging.log4j.LogManager;
2524 import org.apache.logging.log4j.core.LoggerContext;
2625 import org.apache.logging.log4j.core.config.ConfigurationFactory;
2726 import org.apache.logging.log4j.status.StatusLogger;
3635 import static org.junit.Assert.*;
3736
3837 public class FactoryMethodConnectionSourceTest {
39 private static ThreadLocal<Object> holder = new ThreadLocal<Object>();
38 private static ThreadLocal<Object> holder = new ThreadLocal<>();
4039 private static final String CONFIG = "log4j-fatalOnly.xml";
4140
4241 @BeforeClass
4342 public static void beforeClass() {
4443 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
45 final LoggerContext ctx = (LoggerContext) LogManager.getContext();
44 final LoggerContext ctx = LoggerContext.getContext();
4645 ctx.reconfigure();
4746 final StatusLogger logger = StatusLogger.getLogger();
4847 logger.setLevel(Level.FATAL);
4848
4949 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY,
5050 "org/apache/logging/log4j/core/appender/db/jpa/" + configFileName);
51 final LoggerContext context = (LoggerContext) LogManager.getContext(false);
51 final LoggerContext context = LoggerContext.getContext(false);
5252 if (context.getConfiguration() instanceof DefaultConfiguration) {
5353 context.reconfigure();
5454 }
5656 }
5757
5858 public void tearDown() throws SQLException {
59 final LoggerContext context = (LoggerContext) LogManager.getContext(false);
59 final LoggerContext context = LoggerContext.getContext(false);
6060 try {
6161 final Appender appender = context.getConfiguration().getAppender("databaseAppender");
6262 assertNotNull("The appender should not be null.", appender);
4343
4444 statement = connection.createStatement();
4545 statement.executeUpdate("CREATE TABLE jpaBasicLogEntry ( " +
46 "id INTEGER IDENTITY, timemillis BIGINT, level NVARCHAR(10), loggerName NVARCHAR(255), " +
46 "id INTEGER IDENTITY, timemillis BIGINT, nanoTime BIGINT, level NVARCHAR(10), loggerName NVARCHAR(255), " +
4747 "message NVARCHAR(1024), thrown NVARCHAR(1048576), contextMapJson NVARCHAR(1048576)," +
4848 "loggerFQCN NVARCHAR(1024), contextStack NVARCHAR(1048576), marker NVARCHAR(255), source NVARCHAR(2048)," +
4949 "threadName NVARCHAR(255)" +
4747
4848 statement = connection.createStatement();
4949 statement.executeUpdate("CREATE TABLE jpaBasicLogEntry ( " +
50 "id INTEGER IDENTITY, timemillis BIGINT, level VARCHAR(10), loggerName VARCHAR(255), " +
50 "id INTEGER IDENTITY, timemillis BIGINT, nanoTime BIGINT, level VARCHAR(10), loggerName VARCHAR(255), " +
5151 "message VARCHAR(1024), thrown VARCHAR(1048576), contextMapJson VARCHAR(1048576)," +
5252 "loggerFQCN VARCHAR(1024), contextStack VARCHAR(1048576), marker VARCHAR(255), source VARCHAR(2048)," +
5353 "threadName VARCHAR(255)" +
4242
4343 @Entity
4444 @Table(name = "jpaBaseLogEntry")
45 @SuppressWarnings("unused")
4645 public class TestBaseEntity extends AbstractLogEventWrapperEntity {
4746 private static final long serialVersionUID = 1L;
4847
123122 }
124123
125124 @Override
125 @Transient
126 public long getNanoTime() {
127 return this.getWrappedEvent().getNanoTime();
128 }
129
130 @Override
126131 @Convert(converter = ThrowableAttributeConverter.class)
127132 @Column(name = "exception")
128133 public Throwable getThrown() {
3939
4040 @Test
4141 public void testConvertToDatabaseColumn01() {
42 final Map<String, String> map = new HashMap<String, String>();
42 final Map<String, String> map = new HashMap<>();
4343 map.put("test1", "another1");
4444 map.put("key2", "value2");
4545
4949
5050 @Test
5151 public void testConvertToDatabaseColumn02() {
52 final Map<String, String> map = new HashMap<String, String>();
52 final Map<String, String> map = new HashMap<>();
5353 map.put("someKey", "coolValue");
5454 map.put("anotherKey", "testValue");
5555 map.put("myKey", "yourValue");
3939
4040 @Test
4141 public void testConvert01() {
42 final Map<String, String> map = new HashMap<String, String>();
42 final Map<String, String> map = new HashMap<>();
4343 map.put("test1", "another1");
4444 map.put("key2", "value2");
4545
5555
5656 @Test
5757 public void testConvert02() {
58 final Map<String, String> map = new HashMap<String, String>();
58 final Map<String, String> map = new HashMap<>();
5959 map.put("someKey", "coolValue");
6060 map.put("anotherKey", "testValue");
6161 map.put("myKey", "yourValue");
2121 import java.util.Properties;
2222 import java.util.concurrent.CountDownLatch;
2323 import java.util.concurrent.TimeUnit;
24
2425 import javax.jms.JMSException;
2526 import javax.jms.Message;
2627 import javax.jms.MessageConsumer;
7980 final String messageText = "Hello, World!";
8081 final String loggerName = this.getClass().getName();
8182 for (int i = 0; i < messageCount; i++) {
82 final LogEvent event = Log4jLogEvent.createEvent(loggerName, null, loggerName, Level.ERROR,
83 new SimpleMessage(messageText), null, null, null, null, Thread.currentThread().getName(), null,
84 System.currentTimeMillis());
83 final LogEvent event = Log4jLogEvent.newBuilder().setLoggerName(loggerName) //
84 .setLoggerFqcn(loggerName).setLevel(Level.INFO) //
85 .setMessage(new SimpleMessage(messageText)).setThreadName(Thread.currentThread().getName()) //
86 .setTimeMillis(System.currentTimeMillis()).build();
8587 appender.append(event);
8688 }
8789 consumer.awaitAndAssertAllMessagesConsumed();
9698 private JmsQueueConsumer(final int messageCount) {
9799 this.messageCount = messageCount;
98100 this.countDownLatch = new CountDownLatch(messageCount);
99 this.events = new ArrayList<LogEvent>(messageCount);
101 this.events = new ArrayList<>(messageCount);
100102 }
101103
102104 @Override
2626 import org.apache.logging.log4j.core.LogEvent;
2727 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
2828 import org.apache.logging.log4j.core.util.JndiCloser;
29 import org.apache.logging.log4j.junit.InitialLoggerContext;
29 import org.apache.logging.log4j.junit.LoggerContextRule;
3030 import org.apache.logging.log4j.message.SimpleMessage;
3131 import org.junit.AfterClass;
3232 import org.junit.BeforeClass;
7676 }
7777
7878 @Rule
79 public InitialLoggerContext ctx = new InitialLoggerContext("JmsAppenderTest.xml");
79 public LoggerContextRule ctx = new LoggerContextRule("JmsAppenderTest.xml");
8080
8181 @Test
8282 public void testAppendToQueue() throws Exception {
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.appender.mom.jeromq;
18
19 import java.util.List;
20 import java.util.concurrent.ExecutorService;
21 import java.util.concurrent.Executors;
22 import java.util.concurrent.Future;
23
24 import org.apache.logging.log4j.core.Logger;
25 import org.apache.logging.log4j.junit.LoggerContextRule;
26 import org.junit.AfterClass;
27 import org.junit.Assert;
28 import org.junit.ClassRule;
29 import org.junit.Test;
30
31 public class JeroMqAppenderTest {
32
33 @AfterClass
34 public static void tearDownClass() {
35 // JeroMqAppender.shutdown();
36 }
37
38 @ClassRule
39 public static LoggerContextRule ctx = new LoggerContextRule("JeroMqAppenderTest.xml");
40
41 @Test(timeout = 10000)
42 public void testAppenderLifeCycle() throws Exception {
43 // do nothing to make sure the appender starts and stops without
44 // locking up resources.
45 Assert.assertNotNull(JeroMqAppender.getContext());
46 }
47
48 @Test(timeout = 10000)
49 public void testClientServer() throws Exception {
50 final JeroMqAppender appender = ctx.getRequiredAppender("JeroMQAppender", JeroMqAppender.class);
51 final int expectedReceiveCount = 2;
52 final JeroMqTestClient client = new JeroMqTestClient(JeroMqAppender.getContext(), "tcp://localhost:5556", expectedReceiveCount);
53 final ExecutorService executor = Executors.newSingleThreadExecutor();
54 try {
55 final Future<List<String>> future = executor.submit(client);
56 Thread.sleep(100);
57 final Logger logger = ctx.getLogger(getClass().getName());
58 appender.resetSendRcs();
59 logger.info("Hello");
60 logger.info("Again");
61 final List<String> list = future.get();
62 Assert.assertEquals(expectedReceiveCount, appender.getSendRcTrue());
63 Assert.assertEquals(0, appender.getSendRcFalse());
64 Assert.assertEquals("Hello", list.get(0));
65 Assert.assertEquals("Again", list.get(1));
66 } finally {
67 executor.shutdown();
68 }
69 }
70
71 @Test(timeout = 10000)
72 public void testMultiThreadedServer() throws Exception {
73 final int nThreads = 10;
74 final JeroMqAppender appender = ctx.getRequiredAppender("JeroMQAppender", JeroMqAppender.class);
75 final int expectedReceiveCount = 2 * nThreads;
76 final JeroMqTestClient client = new JeroMqTestClient(JeroMqAppender.getContext(), "tcp://localhost:5556",
77 expectedReceiveCount);
78 final ExecutorService executor = Executors.newSingleThreadExecutor();
79 try {
80 final Future<List<String>> future = executor.submit(client);
81 Thread.sleep(100);
82 final Logger logger = ctx.getLogger(getClass().getName());
83 appender.resetSendRcs();
84 final ExecutorService fixedThreadPool = Executors.newFixedThreadPool(nThreads);
85 for (int i = 0; i < 10.; i++) {
86 fixedThreadPool.submit(new Runnable() {
87 @Override
88 public void run() {
89 logger.info("Hello");
90 logger.info("Again");
91 }
92 });
93 }
94 final List<String> list = future.get();
95 Assert.assertEquals(expectedReceiveCount, appender.getSendRcTrue());
96 Assert.assertEquals(0, appender.getSendRcFalse());
97 int hello = 0;
98 int again = 0;
99 for (final String string : list) {
100 switch (string) {
101 case "Hello":
102 hello++;
103 break;
104 case "Again":
105 again++;
106 break;
107 default:
108 Assert.fail("Unexpected message: " + string);
109 }
110 }
111 Assert.assertEquals(nThreads, hello);
112 Assert.assertEquals(nThreads, again);
113 } finally {
114 executor.shutdown();
115 }
116 }
117
118 @Test(timeout = 10000)
119 public void testServerOnly() throws Exception {
120 final Logger logger = ctx.getLogger(getClass().getName());
121 final JeroMqAppender appender = ctx.getRequiredAppender("JeroMQAppender", JeroMqAppender.class);
122 appender.resetSendRcs();
123 logger.info("Hello");
124 logger.info("Again");
125 Assert.assertEquals(2, appender.getSendRcTrue());
126 Assert.assertEquals(0, appender.getSendRcFalse());
127 }
128 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.appender.mom.jeromq;
18
19 import java.util.ArrayList;
20 import java.util.List;
21 import java.util.concurrent.Callable;
22
23 import org.zeromq.ZMQ;
24
25 class JeroMqTestClient implements Callable<List<String>> {
26
27 private final ZMQ.Context context;
28
29 private final String endpoint;
30 private final List<String> messages;
31 private final int receiveCount;
32
33 JeroMqTestClient(final ZMQ.Context context, final String endpoint, final int receiveCount) {
34 super();
35 this.context = context;
36 this.endpoint = endpoint;
37 this.receiveCount = receiveCount;
38 this.messages = new ArrayList<>(receiveCount);
39 }
40
41 @Override
42 public List<String> call() throws Exception {
43 try (ZMQ.Socket subscriber = context.socket(ZMQ.SUB)) {
44 subscriber.connect(endpoint);
45 subscriber.subscribe(new byte[0]);
46 for (int messageNum = 0; messageNum < receiveCount
47 && !Thread.currentThread().isInterrupted(); messageNum++) {
48 // Use trim to remove the tailing '0' character
49 messages.add(subscriber.recvStr(0).trim());
50 }
51 }
52 return messages;
53 }
54 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.appender.mom.kafka;
18
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.assertNull;
22
23 import java.nio.charset.StandardCharsets;
24 import java.util.List;
25 import java.util.Properties;
26
27 import org.apache.kafka.clients.producer.MockProducer;
28 import org.apache.kafka.clients.producer.Producer;
29 import org.apache.kafka.clients.producer.ProducerRecord;
30 import org.apache.logging.log4j.Level;
31 import org.apache.logging.log4j.core.Appender;
32 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
33 import org.apache.logging.log4j.junit.LoggerContextRule;
34 import org.apache.logging.log4j.message.SimpleMessage;
35 import org.junit.Before;
36 import org.junit.BeforeClass;
37 import org.junit.Rule;
38 import org.junit.Test;
39
40 public class KafkaAppenderTest {
41
42 private static final MockProducer kafka = new MockProducer();
43
44 private static final String LOG_MESSAGE = "Hello, world!";
45 private static final String TOPIC_NAME = "kafka-topic";
46
47 private static Log4jLogEvent createLogEvent() {
48 return Log4jLogEvent.newBuilder()
49 .setLoggerName(KafkaAppenderTest.class.getName())
50 .setLoggerFqcn(KafkaAppenderTest.class.getName())
51 .setLevel(Level.INFO)
52 .setMessage(new SimpleMessage(LOG_MESSAGE))
53 .build();
54 }
55
56 @BeforeClass
57 public static void setUpClass() throws Exception {
58 KafkaManager.producerFactory = new KafkaProducerFactory() {
59 @Override
60 public Producer<byte[], byte[]> newKafkaProducer(final Properties config) {
61 return kafka;
62 }
63 };
64 }
65
66 @Rule
67 public LoggerContextRule ctx = new LoggerContextRule("KafkaAppenderTest.xml");
68
69 @Before
70 public void setUp() throws Exception {
71 kafka.clear();
72 }
73
74 @Test
75 public void testAppend() throws Exception {
76 final Appender appender = ctx.getRequiredAppender("KafkaAppender");
77 appender.append(createLogEvent());
78 final List<ProducerRecord<byte[], byte[]>> history = kafka.history();
79 assertEquals(1, history.size());
80 final ProducerRecord<byte[], byte[]> item = history.get(0);
81 assertNotNull(item);
82 assertEquals(TOPIC_NAME, item.topic());
83 assertNull(item.key());
84 assertEquals(LOG_MESSAGE, new String(item.value(), StandardCharsets.UTF_8));
85 }
86
87 @Test
88 public void testAppendWithLayout() throws Exception {
89 final Appender appender = ctx.getRequiredAppender("KafkaAppenderWithLayout");
90 appender.append(createLogEvent());
91 final List<ProducerRecord<byte[], byte[]>> history = kafka.history();
92 assertEquals(1, history.size());
93 final ProducerRecord<byte[], byte[]> item = history.get(0);
94 assertNotNull(item);
95 assertEquals(TOPIC_NAME, item.topic());
96 assertNull(item.key());
97 assertEquals("[" + LOG_MESSAGE + "]", new String(item.value(), StandardCharsets.UTF_8));
98 }
99
100 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.appender.rewrite;
17
18 import org.apache.logging.log4j.Level;
19 import org.apache.logging.log4j.core.LogEvent;
20 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
21 import org.apache.logging.log4j.core.util.KeyValuePair;
22 import org.apache.logging.log4j.message.SimpleMessage;
23 import org.junit.Assert;
24 import org.junit.Test;
25
26 /**
27 * Tests {@link LoggerNameLevelRewritePolicy}.
28 *
29 * @since 2.4
30 */
31 public class LoggerNameLevelRewritePolicyTest {
32
33 @Test
34 public void testUpdate() {
35 final KeyValuePair[] rewrite = new KeyValuePair[] {
36 new KeyValuePair("INFO", "DEBUG"),
37 new KeyValuePair("WARN", "INFO") };
38 final String loggerNameRewrite = "com.foo.bar";
39 LogEvent logEvent = Log4jLogEvent.newBuilder().setLoggerName(loggerNameRewrite)
40 .setLoggerFqcn("LoggerNameLevelRewritePolicyTest.testUpdate()").setLevel(Level.INFO)
41 .setMessage(new SimpleMessage("Test")).setThrown(new RuntimeException("test")).setThreadName("none")
42 .setTimeMillis(1).build();
43 final LoggerNameLevelRewritePolicy updatePolicy = LoggerNameLevelRewritePolicy.createPolicy(loggerNameRewrite,
44 rewrite);
45 LogEvent rewritten = updatePolicy.rewrite(logEvent);
46 Assert.assertEquals(Level.DEBUG, rewritten.getLevel());
47 logEvent = Log4jLogEvent.newBuilder().setLoggerName(loggerNameRewrite)
48 .setLoggerFqcn("LoggerNameLevelRewritePolicyTest.testUpdate()").setLevel(Level.WARN)
49 .setMessage(new SimpleMessage("Test")).setThrown(new RuntimeException("test")).setThreadName("none")
50 .setTimeMillis(1).build();
51 rewritten = updatePolicy.rewrite(logEvent);
52 Assert.assertEquals(Level.INFO, rewritten.getLevel());
53 final String loggerNameReadOnly = "com.nochange";
54 logEvent = Log4jLogEvent.newBuilder().setLoggerName(loggerNameReadOnly)
55 .setLoggerFqcn("LoggerNameLevelRewritePolicyTest.testUpdate()").setLevel(Level.INFO)
56 .setMessage(new SimpleMessage("Test")).setThrown(new RuntimeException("test")).setThreadName("none")
57 .setTimeMillis(1).build();
58 rewritten = updatePolicy.rewrite(logEvent);
59 Assert.assertEquals(Level.INFO, rewritten.getLevel());
60 logEvent = Log4jLogEvent.newBuilder().setLoggerName(loggerNameReadOnly)
61 .setLoggerFqcn("LoggerNameLevelRewritePolicyTest.testUpdate()").setLevel(Level.WARN)
62 .setMessage(new SimpleMessage("Test")).setThrown(new RuntimeException("test")).setThreadName("none")
63 .setTimeMillis(1).build();
64 rewritten = updatePolicy.rewrite(logEvent);
65 Assert.assertEquals(Level.WARN, rewritten.getLevel());
66 }
67
68 }
3434
3535 import static org.apache.logging.log4j.hamcrest.MapMatchers.hasSize;
3636 import static org.hamcrest.Matchers.hasEntry;
37
3738 import static org.junit.Assert.*;
3839
3940
4041 public class MapRewritePolicyTest {
41 private static Map<String, String> map = new HashMap<String, String>();
42 private static Map<String, String> map = new HashMap<>();
4243 private static KeyValuePair[] rewrite;
4344 private static LogEvent logEvent0, logEvent1, logEvent2, logEvent3;
4445
4647 public static void setupClass() {
4748 map.put("test1", "one");
4849 map.put("test2", "two");
49 logEvent0 = new Log4jLogEvent("test", null, "MapRewritePolicyTest.setupClass()", Level.ERROR,
50 new SimpleMessage("Test"), new RuntimeException("test"), map, null, "none",
51 new StackTraceElement("MapRewritePolicyTest", "setupClass", "MapRewritePolicyTest", 28), 2);
52 logEvent1 = new Log4jLogEvent("test", null, "MapRewritePolicyTest.setupClass()", Level.ERROR,
53 new MapMessage(map), null, map, null, "none",
54 new StackTraceElement("MapRewritePolicyTest", "setupClass", "MapRewritePolicyTest", 29), 2);
55 final ThreadContextStack stack = new MutableThreadContextStack(new ArrayList<String>(map.values()));
56 logEvent2 = new Log4jLogEvent("test", MarkerManager.getMarker("test"), "MapRewritePolicyTest.setupClass()",
57 Level.TRACE, new StructuredDataMessage("test", "Nothing", "test", map), new RuntimeException("test"), null,
58 stack, "none", new StackTraceElement("MapRewritePolicyTest",
59 "setupClass", "MapRewritePolicyTest", 30), 20000000);
60 logEvent3 = new Log4jLogEvent("test", null, "MapRewritePolicyTest.setupClass()", Level.ALL, new MapMessage(map),
61 null, map, stack, null, new StackTraceElement("MapRewritePolicyTest",
62 "setupClass", "MapRewritePolicyTest", 31), Long.MAX_VALUE);
50 logEvent0 = Log4jLogEvent.newBuilder() //
51 .setLoggerName("test") //
52 .setContextMap(map) //
53 .setLoggerFqcn("MapRewritePolicyTest.setupClass()") //
54 .setLevel(Level.ERROR) //
55 .setMessage(new SimpleMessage("Test")) //
56 .setThrown(new RuntimeException("test")) //
57 .setThreadName("none")
58 .setSource(new StackTraceElement("MapRewritePolicyTest", "setupClass", "MapRewritePolicyTest", 28))
59 .setTimeMillis(2).build();
60
61 logEvent1 = ((Log4jLogEvent) logEvent0).asBuilder() //
62 .setMessage(new MapMessage(map)) //
63 .setSource(new StackTraceElement("MapRewritePolicyTest", "setupClass", "MapRewritePolicyTest", 29)) //
64 .build();
65
66 final ThreadContextStack stack = new MutableThreadContextStack(new ArrayList<>(map.values()));
67 logEvent2 = ((Log4jLogEvent) logEvent0).asBuilder() //
68 .setContextStack(stack) //
69 .setMarker(MarkerManager.getMarker("test")) //
70 .setLevel(Level.TRACE) //
71 .setMessage(new StructuredDataMessage("test", "Nothing", "test", map)) //
72 .setTimeMillis(20000000) //
73 .setSource(new StackTraceElement("MapRewritePolicyTest", "setupClass", "MapRewritePolicyTest", 30)) //
74 .build();
75 logEvent3 = ((Log4jLogEvent) logEvent0).asBuilder() //
76 .setContextStack(stack) //
77 .setLevel(Level.ALL) //
78 .setMessage(new MapMessage(map)) //
79 .setTimeMillis(Long.MAX_VALUE) //
80 .setSource(new StackTraceElement("MapRewritePolicyTest", "setupClass", "MapRewritePolicyTest", 31)) //
81 .build();
6382 rewrite = new KeyValuePair[]{new KeyValuePair("test2", "2"), new KeyValuePair("test3", "three")};
6483 }
6584
1515 */
1616 package org.apache.logging.log4j.core.appender.rewrite;
1717
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertFalse;
20 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.assertTrue;
22
1823 import java.util.List;
1924 import java.util.Map;
2025
2227 import org.apache.logging.log4j.LogManager;
2328 import org.apache.logging.log4j.Logger;
2429 import org.apache.logging.log4j.core.LogEvent;
25 import org.apache.logging.log4j.junit.InitialLoggerContext;
30 import org.apache.logging.log4j.junit.LoggerContextRule;
2631 import org.apache.logging.log4j.message.MapMessage;
2732 import org.apache.logging.log4j.message.Message;
2833 import org.apache.logging.log4j.message.StructuredDataMessage;
2934 import org.apache.logging.log4j.test.appender.ListAppender;
3035 import org.junit.After;
3136 import org.junit.Before;
32 import org.junit.Rule;
37 import org.junit.ClassRule;
3338 import org.junit.Test;
34
35 import static org.junit.Assert.*;
3639
3740 /**
3841 *
4144 private ListAppender app;
4245 private ListAppender app2;
4346
44 @Rule
45 public InitialLoggerContext init = new InitialLoggerContext("log4j-rewrite.xml");
47 @ClassRule
48 public static LoggerContextRule init = new LoggerContextRule("log4j-rewrite.xml");
4649
4750 @Before
4851 public void setUp() throws Exception {
49 app = this.init.getListAppender("List");
50 app2 = this.init.getListAppender("List2");
52 app = init.getListAppender("List");
53 app2 = init.getListAppender("List2");
5154 }
5255
5356 @After
2828
2929 @Override
3030 public LogEvent rewrite(final LogEvent source) {
31
32 return new Log4jLogEvent(source.getLoggerName(), source.getMarker(), source.getLoggerFqcn(), source.getLevel(),
33 source.getMessage(), source.getThrown(), source.getContextMap(), source.getContextStack(),
34 source.getThreadName(), source.getSource(), source.getTimeMillis());
31 return new Log4jLogEvent.Builder(source).build();
3532 }
3633
3734 @PluginFactory
3535 OnStartupTriggeringPolicy policy = OnStartupTriggeringPolicy.createPolicy();
3636 final MyRollingManager manager = new MyRollingManager(policy, null);
3737 manager.setFileTime(System.currentTimeMillis() - 36000000);
38 final LogEvent event = new Log4jLogEvent(null, null, null, Level.ERROR, new SimpleMessage("Test"), null);
38 final LogEvent event = Log4jLogEvent.newBuilder() //
39 .setLevel(Level.ERROR) //
40 .setMessage(new SimpleMessage("Test")).build();
3941 assertTrue("Expected trigger to succeed", policy.isTriggeringEvent(event));
4042 assertTrue("Expected trigger not to fire", !policy.isTriggeringEvent(event));
4143 policy = OnStartupTriggeringPolicy.createPolicy();
5153
5254 public MyRollingManager(final TriggeringPolicy policy, final RolloverStrategy strategy) {
5355 super("testfile", "target/rolling1/test1-%i.log.gz", new ByteArrayOutputStream(),
54 false, 0, System.currentTimeMillis(), policy, strategy, null, null, 8192);
56 false, 0, System.currentTimeMillis(), policy, strategy, null, null, 8192, true);
5557 }
5658
5759 public void setFileTime(final long timestamp) {
2020 import java.util.Collection;
2121
2222 import org.apache.logging.log4j.Logger;
23 import org.apache.logging.log4j.junit.InitialLoggerContext;
23 import org.apache.logging.log4j.junit.LoggerContextRule;
2424 import org.junit.After;
2525 import org.junit.Before;
2626 import org.junit.Rule;
5151 return Arrays.asList(
5252 new Object[][]{
5353 { "log4j-rolling-gz.xml", ".gz" },
54 { "log4j-rolling-zip.xml", ".zip" }
54 { "log4j-rolling-zip.xml", ".zip" },
55 // Apache Commons Compress
56 { "log4j-rolling-bzip2.xml", ".bz2" },
57 { "log4j-rolling-deflate.xml", ".deflate" },
58 { "log4j-rolling-pack200.xml", ".pack200" },
59 { "log4j-rolling-xy.xml", ".xy" },
5560 }
5661 );
5762 }
5863
5964 @Rule
60 public InitialLoggerContext init;
65 public LoggerContextRule init;
6166
6267 public RollingAppenderSizeTest(final String configFile, final String fileExtension) {
6368 this.fileExtension = fileExtension;
64 this.init = new InitialLoggerContext(configFile);
69 this.init = new LoggerContextRule(configFile);
6570 }
6671
6772 @Before
1515 */
1616 package org.apache.logging.log4j.core.appender.rolling;
1717
18 import static org.apache.logging.log4j.hamcrest.Descriptors.that;
19 import static org.apache.logging.log4j.hamcrest.FileMatchers.hasName;
20 import static org.hamcrest.Matchers.endsWith;
21 import static org.hamcrest.Matchers.hasItemInArray;
22 import static org.junit.Assert.assertNotNull;
23 import static org.junit.Assert.assertThat;
24 import static org.junit.Assert.assertTrue;
25
1826 import java.io.File;
1927
2028 import org.apache.logging.log4j.Logger;
21 import org.apache.logging.log4j.junit.InitialLoggerContext;
29 import org.apache.logging.log4j.junit.LoggerContextRule;
2230 import org.junit.After;
2331 import org.junit.Before;
24 import org.junit.Rule;
32 import org.junit.ClassRule;
2533 import org.junit.Test;
26
27 import static org.apache.logging.log4j.hamcrest.FileMatchers.hasName;
28 import static org.apache.logging.log4j.hamcrest.Descriptors.that;
29 import static org.hamcrest.Matchers.endsWith;
30 import static org.hamcrest.Matchers.hasItemInArray;
31 import static org.junit.Assert.*;
3234
3335 /**
3436 *
3739
3840 private static final String DIR = "target/rolling3/test";
3941
40 @Rule
41 public InitialLoggerContext init = new InitialLoggerContext("log4j-rolling3.xml");
42 @ClassRule
43 public static LoggerContextRule init = new LoggerContextRule("log4j-rolling3.xml");
4244
4345 private Logger logger;
4446
4547 @Before
4648 public void setUp() throws Exception {
47 this.logger = this.init.getLogger(RollingAppenderTimeAndSizeTest.class.getName());
49 this.logger = init.getLogger(RollingAppenderTimeAndSizeTest.class.getName());
4850 deleteDir();
4951 }
5052
1818 import java.io.File;
1919
2020 import org.apache.logging.log4j.Logger;
21 import org.apache.logging.log4j.junit.InitialLoggerContext;
21 import org.apache.logging.log4j.junit.LoggerContextRule;
2222 import org.hamcrest.Matcher;
2323 import org.junit.Rule;
2424 import org.junit.Test;
3939 private static final String CONFIG = "log4j-rolling2.xml";
4040 private static final String DIR = "target/rolling2";
4141
42 private final InitialLoggerContext ctx = new InitialLoggerContext(CONFIG);
42 private final LoggerContextRule ctx = new LoggerContextRule(CONFIG);
4343
4444 @Rule
4545 public RuleChain chain = RuleChain.outerRule(new ExternalResource() {
4242 public static void setupClass() {
4343 deleteDir();
4444 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
45 final LoggerContext ctx = (LoggerContext) LogManager.getContext();
45 final LoggerContext ctx = LoggerContext.getContext();
4646 final Configuration config = ctx.getConfiguration();
4747 }
4848
5050 public static void cleanupClass() {
5151 //deleteDir();
5252 System.clearProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY);
53 final LoggerContext ctx = (LoggerContext) LogManager.getContext();
53 final LoggerContext ctx = LoggerContext.getContext();
5454 ctx.reconfigure();
5555 StatusLogger.getLogger().reset();
5656 }
1818 import java.io.File;
1919 import java.io.IOException;
2020
21 import org.apache.logging.log4j.LogManager;
2221 import org.apache.logging.log4j.core.LoggerContext;
2322 import org.apache.logging.log4j.core.appender.RollingFileAppender;
2423 import org.apache.logging.log4j.core.config.Configuration;
3332 */
3433 @Test
3534 public void testAccessManager() throws IOException {
36 final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
35 final LoggerContext ctx = LoggerContext.getContext(false);
3736 final Configuration config = ctx.getConfiguration();
3837 final File file = File.createTempFile("RollingFileAppenderAccessTest", ".tmp");
3938 file.deleteOnExit();
1515 */
1616 package org.apache.logging.log4j.core.appender.rolling;
1717
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertNotNull;
20 import static org.junit.Assert.assertTrue;
21
1822 import java.io.File;
1923 import java.io.FileInputStream;
2024 import java.nio.charset.Charset;
2226 import org.apache.logging.log4j.Logger;
2327 import org.apache.logging.log4j.core.layout.HtmlLayout;
2428 import org.apache.logging.log4j.core.util.Closer;
25 import org.apache.logging.log4j.junit.InitialLoggerContext;
29 import org.apache.logging.log4j.junit.LoggerContextRule;
2630 import org.junit.After;
2731 import org.junit.Before;
28 import org.junit.Rule;
32 import org.junit.ClassRule;
2933 import org.junit.Test;
30
31 import static org.junit.Assert.*;
3234
3335 /**
3436 *
3840 private static final String DIR = "target/RollingRandomAccessFileAppenderHeaderFooterTest/";
3941 private static final String LOGFILE = "target/RollingRandomAccessFileAppenderHeaderFooterTest.log";
4042
41 @Rule
42 public InitialLoggerContext init = new InitialLoggerContext("RollingRandomAccessFileAppenderHeaderFooterTest.xml");
43 @ClassRule
44 public static LoggerContextRule init = new LoggerContextRule("RollingRandomAccessFileAppenderHeaderFooterTest.xml");
4345
4446 private Logger logger;
4547
2424 import java.util.concurrent.locks.LockSupport;
2525
2626 import org.apache.logging.log4j.core.util.Closer;
27 import org.apache.logging.log4j.core.util.NullOutputStream;
2728 import org.apache.logging.log4j.util.Strings;
2829 import org.junit.Test;
2930
5051 final File file = File.createTempFile("log4j2", "test");
5152 file.deleteOnExit();
5253 final RandomAccessFile raf = new RandomAccessFile(file, "rw");
53 final OutputStream os = new RollingRandomAccessFileManager.DummyOutputStream();
54 final OutputStream os = NullOutputStream.NULL_OUTPUT_STREAM;
5455 final boolean append = false;
5556 final boolean flushNow = false;
5657 final long triggerSize = Long.MAX_VALUE;
6061 final RolloverStrategy rolloverStrategy = null;
6162 final RollingRandomAccessFileManager manager = new RollingRandomAccessFileManager(raf,
6263 file.getName(), Strings.EMPTY, os, append, flushNow, RollingRandomAccessFileManager.DEFAULT_BUFFER_SIZE, triggerSize, time,
63 triggerPolicy, rolloverStrategy, null, null);
64 triggerPolicy, rolloverStrategy, null, null, true);
6465
6566 final int size = RollingRandomAccessFileManager.DEFAULT_BUFFER_SIZE * 3;
6667 final byte[] data = new byte[size];
8182 final File file = File.createTempFile("log4j2", "test");
8283 file.deleteOnExit();
8384 final RandomAccessFile raf = new RandomAccessFile(file, "rw");
84 final OutputStream os = new RollingRandomAccessFileManager.DummyOutputStream();
85 final OutputStream os = NullOutputStream.NULL_OUTPUT_STREAM;
8586 final boolean append = false;
8687 final boolean flushNow = false;
8788 final long triggerSize = 0;
9192 final RolloverStrategy rolloverStrategy = null;
9293 final RollingRandomAccessFileManager manager = new RollingRandomAccessFileManager(raf,
9394 file.getName(), Strings.EMPTY, os, append, flushNow, RollingRandomAccessFileManager.DEFAULT_BUFFER_SIZE, triggerSize, time,
94 triggerPolicy, rolloverStrategy, null, null);
95 triggerPolicy, rolloverStrategy, null, null, true);
9596
9697 final int size = RollingRandomAccessFileManager.DEFAULT_BUFFER_SIZE * 3 + 1;
9798 final byte[] data = new byte[size];
107108 final File file = File.createTempFile("log4j2", "test");
108109 file.deleteOnExit();
109110 final RandomAccessFile raf = new RandomAccessFile(file, "rw");
110 final OutputStream os = new RollingRandomAccessFileManager.DummyOutputStream();
111 final OutputStream os = NullOutputStream.NULL_OUTPUT_STREAM;
111112 final boolean append = false;
112113 final boolean flushNow = false;
113114 final long triggerSize = 0;
118119 final RolloverStrategy rolloverStrategy = null;
119120 final RollingRandomAccessFileManager manager = new RollingRandomAccessFileManager(raf,
120121 file.getName(), Strings.EMPTY, os, append, flushNow, bufferSize, triggerSize, time,
121 triggerPolicy, rolloverStrategy, null, null);
122 triggerPolicy, rolloverStrategy, null, null, true);
122123
123124 // check the resulting buffer size is what was requested
124125 assertEquals(bufferSize, manager.getBufferSize());
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.appender.rolling.action;
18
19 import java.io.ByteArrayInputStream;
20 import java.io.File;
21 import java.io.FileInputStream;
22 import java.io.FileWriter;
23 import java.io.IOException;
24
25 import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
26 import org.junit.Test;
27
28 import static org.junit.Assert.*;
29
30 /**
31 * Tests Bzip2CompressAction.
32 */
33 public class Bzip2CompressActionTest {
34
35 @Test(expected = NullPointerException.class)
36 public void testConstructorDisallowsNullSource() {
37 new CommonsCompressAction("bzip2", null, new File("any"), true);
38 }
39
40 @Test(expected = NullPointerException.class)
41 public void testConstructorDisallowsNullDestination() {
42 new CommonsCompressAction("bzip2", new File("any"), null, true);
43 }
44
45 @Test
46 public void testExecuteReturnsFalseIfSourceDoesNotExist() throws IOException {
47 File source = new File("any");
48 while (source.exists()) {
49 source = new File(source.getName() + Math.random());
50 }
51 final boolean actual = CommonsCompressAction.execute("bzip2", source, new File("any2"), true);
52 assertEquals("Cannot compress non-existing file", false, actual);
53 }
54
55 @Test
56 public void testExecuteCompressesSourceFileToDestinationFile() throws IOException {
57 final String LINE1 = "Here is line 1. Random text: ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n";
58 final String LINE2 = "Here is line 2. Random text: ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n";
59 final String LINE3 = "Here is line 3. Random text: ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n";
60 final File source = new File("target/compressme");
61 try (FileWriter fw = new FileWriter(source, false)) {
62 fw.write(LINE1);
63 fw.write(LINE2);
64 fw.write(LINE3);
65 fw.flush();
66 }
67 final File destination = new File("target/compressme.bz2");
68 destination.delete(); // just in case
69 assertFalse("Destination should not exist yet", destination.exists());
70
71 final boolean actual = CommonsCompressAction.execute("bzip2", source, destination, true);
72 assertEquals("Bzip2CompressAction should have succeeded", true, actual);
73 assertTrue("Destination should exist after Bzip2CompressAction", destination.exists());
74 assertFalse("Source should have been deleted", source.exists());
75
76 final byte[] bz2 = new byte[] { (byte) 0x42, (byte) 0x5A, (byte) 0x68, (byte) 0x39, (byte) 0x31, (byte) 0x41,
77 (byte) 0x59, (byte) 0x26, (byte) 0x53, (byte) 0x59, (byte) 0x9C, (byte) 0xE1, (byte) 0xE8, (byte) 0x2D,
78 (byte) 0x00, (byte) 0x00, (byte) 0x1C, (byte) 0xDF, (byte) 0x80, (byte) 0x00, (byte) 0x12, (byte) 0x40,
79 (byte) 0x01, (byte) 0x38, (byte) 0x10, (byte) 0x3F, (byte) 0xFF, (byte) 0xFF, (byte) 0xF0, (byte) 0x26,
80 (byte) 0x27, (byte) 0x9C, (byte) 0x40, (byte) 0x20, (byte) 0x00, (byte) 0x70, (byte) 0x63, (byte) 0x4D,
81 (byte) 0x06, (byte) 0x80, (byte) 0x19, (byte) 0x34, (byte) 0x06, (byte) 0x46, (byte) 0x9A, (byte) 0x18,
82 (byte) 0x9A, (byte) 0x30, (byte) 0xCF, (byte) 0xFD, (byte) 0x55, (byte) 0x4D, (byte) 0x0D, (byte) 0x06,
83 (byte) 0x9A, (byte) 0x0C, (byte) 0x40, (byte) 0x1A, (byte) 0x1A, (byte) 0x34, (byte) 0x34, (byte) 0xCD,
84 (byte) 0x46, (byte) 0x05, (byte) 0x6B, (byte) 0x19, (byte) 0x92, (byte) 0x23, (byte) 0x5E, (byte) 0xB5,
85 (byte) 0x2E, (byte) 0x79, (byte) 0x65, (byte) 0x41, (byte) 0x81, (byte) 0x33, (byte) 0x4B, (byte) 0x53,
86 (byte) 0x5B, (byte) 0x62, (byte) 0x75, (byte) 0x0A, (byte) 0x14, (byte) 0xB6, (byte) 0xB7, (byte) 0x37,
87 (byte) 0xB8, (byte) 0x38, (byte) 0xB9, (byte) 0x39, (byte) 0xBA, (byte) 0x2A, (byte) 0x4E, (byte) 0xEA,
88 (byte) 0xEC, (byte) 0xEE, (byte) 0xAD, (byte) 0xE1, (byte) 0xE5, (byte) 0x63, (byte) 0xD3, (byte) 0x22,
89 (byte) 0xE8, (byte) 0x90, (byte) 0x52, (byte) 0xA9, (byte) 0x7A, (byte) 0x68, (byte) 0x90, (byte) 0x5C,
90 (byte) 0x82, (byte) 0x0B, (byte) 0x51, (byte) 0xBF, (byte) 0x24, (byte) 0x61, (byte) 0x7F, (byte) 0x17,
91 (byte) 0x72, (byte) 0x45, (byte) 0x38, (byte) 0x50, (byte) 0x90, (byte) 0x9C, (byte) 0xE1, (byte) 0xE8,
92 (byte) 0x2D };
93 assertEquals(bz2.length, destination.length());
94
95 // check the compressed contents
96 try (FileInputStream fis = new FileInputStream(destination)) {
97 final byte[] actualBz2 = new byte[bz2.length];
98 int n = 0;
99 int offset = 0;
100 do {
101 n = fis.read(actualBz2, offset, actualBz2.length - offset);
102 offset += n;
103 } while (offset < actualBz2.length);
104 assertArrayEquals("Compressed data corrupt", bz2, actualBz2);
105 }
106 destination.delete();
107
108 // uncompress
109 try (BZip2CompressorInputStream bzin = new BZip2CompressorInputStream(new ByteArrayInputStream(bz2))) {
110 final StringBuilder sb = new StringBuilder();
111 final byte[] buf = new byte[1024];
112 int n = 0;
113 while ((n = bzin.read(buf, 0, buf.length)) > -1) {
114 sb.append(new String(buf, 0, n));
115 }
116 assertEquals(LINE1 + LINE2 + LINE3, sb.toString());
117 }
118 }
119 }
5151 @Test
5252 public void testRename1() throws Exception {
5353 final File file = new File("target/fileRename/fileRename.log");
54 final PrintStream pos = new PrintStream(file);
55 for (int i = 0; i < 100; ++i) {
56 pos.println("This is line " + i);
54 try (final PrintStream pos = new PrintStream(file)) {
55 for (int i = 0; i < 100; ++i) {
56 pos.println("This is line " + i);
57 }
5758 }
58 pos.close();
5959
6060 final File dest = new File("target/fileRename/newFile.log");
6161 final FileRenameAction action = new FileRenameAction(file, dest, false);
6767 @Test
6868 public void testEmpty() throws Exception {
6969 final File file = new File("target/fileRename/fileRename.log");
70 final PrintStream pos = new PrintStream(file);
71 pos.close();
70 try (final PrintStream pos = new PrintStream(file)) {
71 // do nothing
72 }
7273
7374 final File dest = new File("target/fileRename/newFile.log");
7475 final FileRenameAction action = new FileRenameAction(file, dest, false);
8182 @Test
8283 public void testNoParent() throws Exception {
8384 final File file = new File("fileRename.log");
84 final PrintStream pos = new PrintStream(file);
85 for (int i = 0; i < 100; ++i) {
86 pos.println("This is line " + i);
85 try (final PrintStream pos = new PrintStream(file)) {
86 for (int i = 0; i < 100; ++i) {
87 pos.println("This is line " + i);
88 }
8789 }
88 pos.close();
8990
9091 final File dest = new File("newFile.log");
9192 try {
1818 import java.io.File;
1919 import java.util.List;
2020 import org.apache.logging.log4j.EventLogger;
21 import org.apache.logging.log4j.LogManager;
2221 import org.apache.logging.log4j.core.LogEvent;
2322 import org.apache.logging.log4j.core.LoggerContext;
2423 import org.apache.logging.log4j.core.config.Configuration;
4443 @BeforeClass
4544 public static void setupClass() {
4645 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
47 ctx = (LoggerContext) LogManager.getContext(false);
46 ctx = LoggerContext.getContext(false);
4847 config = ctx.getConfiguration();
4948 listAppender = (ListAppender) config.getAppender("List");
5049 final File file = new File("target/rolling1/rollingtest-Unknown.log");
1818 import java.io.File;
1919 import java.util.List;
2020 import org.apache.logging.log4j.EventLogger;
21 import org.apache.logging.log4j.LogManager;
2221 import org.apache.logging.log4j.core.LogEvent;
2322 import org.apache.logging.log4j.core.LoggerContext;
2423 import org.apache.logging.log4j.core.config.Configuration;
4443 @BeforeClass
4544 public static void setupClass() {
4645 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
47 ctx = (LoggerContext) LogManager.getContext(false);
46 ctx = LoggerContext.getContext(false);
4847 config = ctx.getConfiguration();
4948 listAppender = (ListAppender) config.getAppender("List");
5049 final File file = new File("target/rolling1/rollingtest-Unknown.log");
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.appender.routing;
17
18 import org.apache.logging.log4j.EventLogger;
19 import org.apache.logging.log4j.core.LogEvent;
20 import org.apache.logging.log4j.junit.CleanFiles;
21 import org.apache.logging.log4j.junit.LoggerContextRule;
22 import org.apache.logging.log4j.message.StructuredDataMessage;
23 import org.apache.logging.log4j.test.appender.ListAppender;
24 import org.junit.After;
25 import org.junit.Before;
26 import org.junit.Rule;
27 import org.junit.Test;
28
29 import java.io.File;
30 import java.util.List;
31
32 import static org.junit.Assert.assertNotNull;
33 import static org.junit.Assert.assertTrue;
34
35 /**
36 *
37 */
38 public class PropertiesRoutingAppenderTest {
39 private static final String CONFIG = "log4j-routing.properties";
40 private static final String UNKNOWN_LOG_FILE = "target/rolling1/rollingtestProps-Unknown.log";
41 private static final String ALERT_LOG_FILE = "target/routing1/routingtestProps-Alert.log";
42 private static final String ACTIVITY_LOG_FILE = "target/routing1/routingtestProps-Activity.log";
43
44 private ListAppender app;
45
46 @Rule
47 public LoggerContextRule init = new LoggerContextRule(CONFIG);
48
49 @Rule
50 public CleanFiles files = new CleanFiles(UNKNOWN_LOG_FILE, ALERT_LOG_FILE, ACTIVITY_LOG_FILE);
51
52 @Before
53 public void setUp() throws Exception {
54 this.app = this.init.getListAppender("List");
55 }
56
57 @After
58 public void tearDown() throws Exception {
59 this.app.clear();
60 }
61
62 @Test
63 public void routingTest() {
64 StructuredDataMessage msg = new StructuredDataMessage("Test", "This is a test", "Service");
65 EventLogger.logEvent(msg);
66 final List<LogEvent> list = app.getEvents();
67 assertNotNull("No events generated", list);
68 assertTrue("Incorrect number of events. Expected 1, got " + list.size(), list.size() == 1);
69 msg = new StructuredDataMessage("Test", "This is a test", "Alert");
70 EventLogger.logEvent(msg);
71 File file = new File(ALERT_LOG_FILE);
72 assertTrue("Alert file was not created", file.exists());
73 msg = new StructuredDataMessage("Test", "This is a test", "Activity");
74 EventLogger.logEvent(msg);
75 file = new File(ACTIVITY_LOG_FILE);
76 assertTrue("Activity file was not created", file.exists());
77 }
78 }
2121 import org.apache.logging.log4j.EventLogger;
2222 import org.apache.logging.log4j.core.LogEvent;
2323 import org.apache.logging.log4j.junit.CleanFiles;
24 import org.apache.logging.log4j.junit.InitialLoggerContext;
24 import org.apache.logging.log4j.junit.LoggerContextRule;
2525 import org.apache.logging.log4j.message.StructuredDataMessage;
2626 import org.apache.logging.log4j.test.appender.ListAppender;
2727 import org.junit.After;
4343 private ListAppender app;
4444
4545 @Rule
46 public InitialLoggerContext init = new InitialLoggerContext(CONFIG);
46 public LoggerContextRule init = new LoggerContextRule(CONFIG);
4747
4848 @Rule
4949 public CleanFiles files = new CleanFiles(UNKNOWN_LOG_FILE, ALERT_LOG_FILE, ACTIVITY_LOG_FILE);
1515 */
1616 package org.apache.logging.log4j.core.appender.routing;
1717
18 import static org.junit.Assert.assertNotNull;
19 import static org.junit.Assert.assertTrue;
20
1821 import java.io.File;
1922
2023 import javax.naming.Context;
2225 import javax.naming.NamingException;
2326
2427 import org.apache.logging.log4j.EventLogger;
25 import org.apache.logging.log4j.junit.InitialLoggerContext;
28 import org.apache.logging.log4j.junit.LoggerContextRule;
2629 import org.apache.logging.log4j.message.StructuredDataMessage;
2730 import org.apache.logging.log4j.test.appender.ListAppender;
2831 import org.junit.After;
2932 import org.junit.Before;
30 import org.junit.Rule;
33 import org.junit.ClassRule;
3134 import org.junit.Test;
3235 import org.mockejb.jndi.MockContextFactory;
33
34 import static org.junit.Assert.*;
3536
3637 /**
3738 * RoutingAppenderWithJndiTest
4243 private ListAppender listAppender1;
4344 private ListAppender listAppender2;
4445
45 @Rule
46 public InitialLoggerContext init = new InitialLoggerContext("log4j-routing-by-jndi.xml");
46 @ClassRule
47 public static LoggerContextRule init = new LoggerContextRule("log4j-routing-by-jndi.xml");
4748
4849 @Before
4950 public void before() throws NamingException {
5051 MockContextFactory.setAsInitial();
51 listAppender1 = (ListAppender) this.init.getAppender("List1");
52 listAppender2 = (ListAppender) this.init.getAppender("List2");
52 listAppender1 = (ListAppender) RoutingAppenderWithJndiTest.init.getAppender("List1");
53 listAppender2 = (ListAppender) RoutingAppenderWithJndiTest.init.getAppender("List2");
5354 }
5455
5556 @After
2121 import org.apache.logging.log4j.EventLogger;
2222 import org.apache.logging.log4j.core.LogEvent;
2323 import org.apache.logging.log4j.junit.CleanFiles;
24 import org.apache.logging.log4j.junit.InitialLoggerContext;
24 import org.apache.logging.log4j.junit.LoggerContextRule;
2525 import org.apache.logging.log4j.message.StructuredDataMessage;
2626 import org.apache.logging.log4j.test.appender.ListAppender;
2727 import org.junit.After;
4040 private ListAppender app;
4141
4242 @Rule
43 public InitialLoggerContext init = new InitialLoggerContext("log4j-routing3.xml");
43 public LoggerContextRule init = new LoggerContextRule("log4j-routing3.xml");
4444
4545 @Rule
4646 public CleanFiles files = new CleanFiles(LOG_FILE);
2121
2222 import org.apache.logging.log4j.LogManager;
2323 import org.apache.logging.log4j.Logger;
24 import org.apache.logging.log4j.core.LifeCycle;
24 import org.apache.logging.log4j.core.CoreLoggerContexts;
2525 import org.apache.logging.log4j.core.config.ConfigurationFactory;
2626 import org.junit.BeforeClass;
2727 import org.junit.Test;
3838
3939 @Test
4040 public void testFlushAtEndOfBatch() throws Exception {
41 final File f = new File("target", "AsyncLoggerConfigAutoFlushTest.log");
42 assertTrue("Deleted old file before test", !f.exists() || f.delete());
41 final File file = new File("target", "AsyncLoggerConfigAutoFlushTest.log");
42 assertTrue("Deleted old file before test", !file.exists() || file.delete());
4343
4444 final Logger log = LogManager.getLogger("com.foo.Bar");
4545 final String msg = "Message flushed with immediate flush=false";
4646 log.info(msg);
47 ((LifeCycle) LogManager.getContext()).stop(); // stop async thread
48
49 final BufferedReader reader = new BufferedReader(new FileReader(f));
47 CoreLoggerContexts.stopLoggerContext(file); // stop async thread
48 final BufferedReader reader = new BufferedReader(new FileReader(file));
5049 final String line1 = reader.readLine();
5150 reader.close();
52 f.delete();
51 file.delete();
5352 assertNotNull("line1", line1);
5453 assertTrue("line1 correct", line1.contains(msg));
5554 }
2121
2222 import org.apache.logging.log4j.LogManager;
2323 import org.apache.logging.log4j.Logger;
24 import org.apache.logging.log4j.core.LifeCycle;
24 import org.apache.logging.log4j.core.CoreLoggerContexts;
25 import org.apache.logging.log4j.core.config.AppenderRef;
2526 import org.apache.logging.log4j.core.config.ConfigurationFactory;
27 import org.apache.logging.log4j.core.config.DefaultConfiguration;
28 import org.apache.logging.log4j.core.config.LoggerConfig;
2629 import org.junit.BeforeClass;
2730 import org.junit.Test;
2831
3235
3336 @BeforeClass
3437 public static void beforeClass() {
35 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY,
36 "AsyncLoggerConfigTest.xml");
38 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, "AsyncLoggerConfigTest.xml");
3739 }
3840
3941 @Test
4042 public void testAdditivity() throws Exception {
41 final File f = new File("target", "AsyncLoggerConfigTest.log");
42 assertTrue("Deleted old file before test", !f.exists() || f.delete());
43
43 final File file = new File("target", "AsyncLoggerConfigTest.log");
44 assertTrue("Deleted old file before test", !file.exists() || file.delete());
45
4446 final Logger log = LogManager.getLogger("com.foo.Bar");
4547 final String msg = "Additive logging: 2 for the price of 1!";
4648 log.info(msg);
47 ((LifeCycle) LogManager.getContext()).stop(); // stop async thread
48
49 final BufferedReader reader = new BufferedReader(new FileReader(f));
49 CoreLoggerContexts.stopLoggerContext(file); // stop async thread
50
51 final BufferedReader reader = new BufferedReader(new FileReader(file));
5052 final String line1 = reader.readLine();
5153 final String line2 = reader.readLine();
5254 reader.close();
53 f.delete();
55 file.delete();
5456 assertNotNull("line1", line1);
5557 assertNotNull("line2", line2);
5658 assertTrue("line1 correct", line1.contains(msg));
5759 assertTrue("line2 correct", line2.contains(msg));
5860
5961 final String location = "testAdditivity";
60 assertTrue("location",
61 line1.contains(location) || line2.contains(location));
62 assertTrue("location", line1.contains(location) || line2.contains(location));
63 }
64
65 @Test
66 public void testIncludeLocationDefaultsToFalse() {
67 final LoggerConfig rootLoggerConfig =
68 AsyncLoggerConfig.RootLogger.createLogger(
69 null, "INFO", null, new AppenderRef[0], null, new DefaultConfiguration(), null);
70 assertFalse("Include location should default to false for async logggers",
71 rootLoggerConfig.isIncludeLocation());
72
73 final LoggerConfig loggerConfig =
74 AsyncLoggerConfig.createLogger(
75 null, "INFO", "com.foo.Bar", null, new AppenderRef[0], null, new DefaultConfiguration(),
76 null);
77 assertFalse("Include location should default to false for async logggers",
78 loggerConfig.isIncludeLocation());
6279 }
6380 }
2121
2222 import org.apache.logging.log4j.LogManager;
2323 import org.apache.logging.log4j.Logger;
24 import org.apache.logging.log4j.core.LifeCycle;
2524 import org.apache.logging.log4j.core.LoggerContext;
25 import org.apache.logging.log4j.core.CoreLoggerContexts;
2626 import org.apache.logging.log4j.core.config.ConfigurationFactory;
2727 import org.junit.BeforeClass;
2828 import org.junit.Test;
3939 public void testConsecutiveReconfigure() throws Exception {
4040 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY,
4141 "AsyncLoggerConfigTest2.xml");
42 final File f = new File("target", "AsyncLoggerConfigTest2.log");
43 assertTrue("Deleted old file before test", !f.exists() || f.delete());
42 final File file = new File("target", "AsyncLoggerConfigTest2.log");
43 assertTrue("Deleted old file before test", !file.exists() || file.delete());
4444
4545 final Logger log = LogManager.getLogger("com.foo.Bar");
4646 final String msg = "Message before reconfig";
4747 log.info(msg);
4848
49 final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
49 final LoggerContext ctx = LoggerContext.getContext(false);
5050 ctx.reconfigure();
5151 ctx.reconfigure();
5252
5353 final String msg2 = "Message after reconfig";
5454 log.info(msg2);
55 ((LifeCycle) LogManager.getContext()).stop(); // stop async thread
55 CoreLoggerContexts.stopLoggerContext(file); // stop async thread
5656
57 final BufferedReader reader = new BufferedReader(new FileReader(f));
57 final BufferedReader reader = new BufferedReader(new FileReader(file));
5858 final String line1 = reader.readLine();
5959 final String line2 = reader.readLine();
6060 reader.close();
61 f.delete();
61 file.delete();
6262 assertNotNull("line1", line1);
6363 assertNotNull("line2", line2);
6464 assertTrue("line1 " + line1, line1.contains(msg));
1818 import org.apache.logging.log4j.Level;
1919 import org.apache.logging.log4j.LogManager;
2020 import org.apache.logging.log4j.Logger;
21 import org.apache.logging.log4j.core.LifeCycle;
21 import org.apache.logging.log4j.core.CoreLoggerContexts;
2222 import org.apache.logging.log4j.core.config.ConfigurationFactory;
2323 import org.apache.logging.log4j.message.SimpleMessage;
2424 import org.apache.logging.log4j.spi.AbstractLogger;
3636 public void testNoErrorIfLogAfterShutdown() throws Exception {
3737 final Logger log = LogManager.getLogger("com.foo.Bar");
3838 log.info("some message");
39 ((LifeCycle) LogManager.getContext()).stop(); // stop async thread
39 CoreLoggerContexts.stopLoggerContext(); // stop async thread
4040
4141 // call the #logMessage() method to bypass the isEnabled check:
4242 // before the LOG4J2-639 fix this would throw a NPE
1515 */
1616 package org.apache.logging.log4j.core.async;
1717
18 import org.apache.logging.log4j.LogManager;
1918 import org.apache.logging.log4j.Logger;
20 import org.apache.logging.log4j.core.LifeCycle;
19 import org.apache.logging.log4j.core.CoreLoggerContexts;
2120 import org.apache.logging.log4j.core.LoggerContext;
2221 import org.junit.Test;
2322
3130 new LoggerContext("a"), "a", null);
3231 assertTrue(logger instanceof AsyncLogger);
3332
34 ((LifeCycle) LogManager.getContext()).stop(); // stop async thread
33 CoreLoggerContexts.stopLoggerContext(); // stop async thread
3534 }
3635 }
2121
2222 import org.apache.logging.log4j.LogManager;
2323 import org.apache.logging.log4j.Logger;
24 import org.apache.logging.log4j.core.LifeCycle;
24 import org.apache.logging.log4j.core.CoreLoggerContexts;
2525 import org.apache.logging.log4j.core.config.ConfigurationFactory;
2626 import org.apache.logging.log4j.core.util.Constants;
2727 import org.apache.logging.log4j.util.Strings;
4848
4949 @Test
5050 public void testAsyncLogWritesToLog() throws Exception {
51 final File f = new File("target", "AsyncLoggerLocationTest.log");
51 final File file = new File("target", "AsyncLoggerLocationTest.log");
5252 // System.out.println(f.getAbsolutePath());
53 f.delete();
53 file.delete();
5454 final Logger log = LogManager.getLogger("com.foo.Bar");
5555 final String msg = "Async logger msg with location";
5656 log.info(msg);
57 ((LifeCycle) LogManager.getContext()).stop(); // stop async thread
57 CoreLoggerContexts.stopLoggerContext(file); // stop async thread
5858
59 final BufferedReader reader = new BufferedReader(new FileReader(f));
59 final BufferedReader reader = new BufferedReader(new FileReader(file));
6060 final String line1 = reader.readLine();
6161 reader.close();
62 f.delete();
62 file.delete();
6363 assertNotNull("line1", line1);
6464 assertTrue("line1 correct", line1.contains(msg));
6565
2121
2222 import org.apache.logging.log4j.LogManager;
2323 import org.apache.logging.log4j.Logger;
24 import org.apache.logging.log4j.core.LifeCycle;
24 import org.apache.logging.log4j.core.CoreLoggerContexts;
2525 import org.apache.logging.log4j.core.config.ConfigurationFactory;
2626 import org.apache.logging.log4j.core.util.Constants;
27 import org.apache.logging.log4j.core.util.DummyNanoClock;
2728 import org.apache.logging.log4j.util.Strings;
2829 import org.junit.AfterClass;
2930 import org.junit.BeforeClass;
4849
4950 @Test
5051 public void testAsyncLogWritesToLog() throws Exception {
51 final File f = new File("target", "AsyncLoggerTest.log");
52 final File file = new File("target", "AsyncLoggerTest.log");
5253 // System.out.println(f.getAbsolutePath());
53 f.delete();
54 file.delete();
5455 final Logger log = LogManager.getLogger("com.foo.Bar");
5556 final String msg = "Async logger msg";
5657 log.info(msg, new InternalError("this is not a real error"));
57 ((LifeCycle) LogManager.getContext()).stop(); // stop async thread
58 CoreLoggerContexts.stopLoggerContext(file); // stop async thread
5859
59 final BufferedReader reader = new BufferedReader(new FileReader(f));
60 final BufferedReader reader = new BufferedReader(new FileReader(file));
6061 final String line1 = reader.readLine();
6162 reader.close();
62 f.delete();
63 file.delete();
6364 assertNotNull("line1", line1);
6465 assertTrue("line1 correct", line1.contains(msg));
6566
6667 final String location = "testAsyncLogWritesToLog";
6768 assertTrue("no location", !line1.contains(location));
6869 }
70
71 @Test
72 public void testNanoClockInitiallyDummy() {
73 assertTrue(AsyncLogger.getNanoClock() instanceof DummyNanoClock);
74 }
6975
7076 }
2121
2222 import org.apache.logging.log4j.LogManager;
2323 import org.apache.logging.log4j.Logger;
24 import org.apache.logging.log4j.core.LifeCycle;
24 import org.apache.logging.log4j.core.CoreLoggerContexts;
2525 import org.apache.logging.log4j.core.config.ConfigurationFactory;
2626 import org.apache.logging.log4j.core.util.Constants;
2727 import org.apache.logging.log4j.util.Strings;
4848
4949 @Test
5050 public void testAsyncLogUsesCachedThreadName() throws Exception {
51 final File f = new File("target", "AsyncLoggerTest.log");
51 final File file = new File("target", "AsyncLoggerTest.log");
5252 // System.out.println(f.getAbsolutePath());
53 f.delete();
53 file.delete();
5454 final Logger log = LogManager.getLogger("com.foo.Bar");
5555 final String msg = "Async logger msg";
5656 log.info(msg);
5757 Thread.currentThread().setName("MODIFIED-THREADNAME");
5858 log.info(msg);
59 ((LifeCycle) LogManager.getContext()).stop(); // stop async thread
59 CoreLoggerContexts.stopLoggerContext(file); // stop async thread
6060
61 final BufferedReader reader = new BufferedReader(new FileReader(f));
61 final BufferedReader reader = new BufferedReader(new FileReader(file));
6262 final String line1 = reader.readLine();
6363 final String line2 = reader.readLine();
6464 // System.out.println(line1);
6565 // System.out.println(line2);
6666 reader.close();
67 f.delete();
67 file.delete();
6868 assertNotNull("line1", line1);
6969 assertNotNull("line2", line2);
7070 assertTrue("line1", line1.endsWith(" INFO c.f.Bar [main] Async logger msg "));
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.async;
17
18 import java.io.BufferedReader;
19 import java.io.File;
20 import java.io.FileReader;
21 import java.util.concurrent.TimeUnit;
22
23 import org.apache.logging.log4j.LogManager;
24 import org.apache.logging.log4j.Logger;
25 import org.apache.logging.log4j.core.CoreLoggerContexts;
26 import org.apache.logging.log4j.core.config.ConfigurationFactory;
27 import org.apache.logging.log4j.core.util.Constants;
28 import org.apache.logging.log4j.core.util.DummyNanoClock;
29 import org.apache.logging.log4j.core.util.SystemNanoClock;
30 import org.apache.logging.log4j.util.Strings;
31 import org.junit.AfterClass;
32 import org.junit.BeforeClass;
33 import org.junit.Test;
34
35 import static org.junit.Assert.*;
36
37 public class AsyncLoggerTestNanoTime {
38
39 @BeforeClass
40 public static void beforeClass() {
41 System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR,
42 AsyncLoggerContextSelector.class.getName());
43 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY,
44 "NanoTimeToFileTest.xml");
45 }
46
47 @AfterClass
48 public static void afterClass() {
49 System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR, Strings.EMPTY);
50 }
51
52 @Test
53 public void testAsyncLogUsesNanoTimeClock() throws Exception {
54 final File file = new File("target", "NanoTimeToFileTest.log");
55 // System.out.println(f.getAbsolutePath());
56 file.delete();
57 final Logger log = LogManager.getLogger("com.foo.Bar");
58 final long before = System.nanoTime();
59 log.info("Use actual System.nanoTime()");
60 assertTrue("using SystemNanoClock", AsyncLogger.getNanoClock() instanceof SystemNanoClock);
61
62 final long DUMMYNANOTIME = 123;
63 AsyncLogger.setNanoClock(new DummyNanoClock(DUMMYNANOTIME));
64 log.info("Use dummy nano clock");
65 assertTrue("using SystemNanoClock", AsyncLogger.getNanoClock() instanceof DummyNanoClock);
66
67 CoreLoggerContexts.stopLoggerContext(file); // stop async thread
68
69 final BufferedReader reader = new BufferedReader(new FileReader(file));
70 final String line1 = reader.readLine();
71 final String line2 = reader.readLine();
72 // System.out.println(line1);
73 // System.out.println(line2);
74 reader.close();
75 file.delete();
76
77 assertNotNull("line1", line1);
78 assertNotNull("line2", line2);
79 final String[] line1Parts = line1.split(" AND ");
80 assertEquals("Use actual System.nanoTime()", line1Parts[2]);
81 assertEquals(line1Parts[0], line1Parts[1]);
82 long loggedNanoTime = Long.parseLong(line1Parts[0]);
83 assertTrue("used system nano time", loggedNanoTime - before < TimeUnit.SECONDS.toNanos(1));
84
85 final String[] line2Parts = line2.split(" AND ");
86 assertEquals("Use dummy nano clock", line2Parts[2]);
87 assertEquals(String.valueOf(DUMMYNANOTIME), line2Parts[0]);
88 assertEquals(String.valueOf(DUMMYNANOTIME), line2Parts[1]);
89 }
90
91 }
2121
2222 import org.apache.logging.log4j.LogManager;
2323 import org.apache.logging.log4j.Logger;
24 import org.apache.logging.log4j.core.LifeCycle;
24 import org.apache.logging.log4j.core.CoreLoggerContexts;
2525 import org.apache.logging.log4j.core.config.ConfigurationFactory;
2626 import org.apache.logging.log4j.core.util.Constants;
2727 import org.apache.logging.log4j.util.Strings;
4949
5050 @Test
5151 public void testAsyncLogUsesCurrentThreadName() throws Exception {
52 final File f = new File("target", "AsyncLoggerTest.log");
52 final File file = new File("target", "AsyncLoggerTest.log");
5353 // System.out.println(f.getAbsolutePath());
54 f.delete();
54 file.delete();
5555 final Logger log = LogManager.getLogger("com.foo.Bar");
5656 final String msg = "Async logger msg";
5757 log.info(msg);
5858 Thread.currentThread().setName("MODIFIED-THREADNAME");
5959 log.info(msg);
60 ((LifeCycle) LogManager.getContext()).stop(); // stop async thread
60 CoreLoggerContexts.stopLoggerContext(file); // stop async thread
6161
62 final BufferedReader reader = new BufferedReader(new FileReader(f));
62 final BufferedReader reader = new BufferedReader(new FileReader(file));
6363 final String line1 = reader.readLine();
6464 final String line2 = reader.readLine();
6565 // System.out.println(line1);
6666 // System.out.println(line2);
6767 reader.close();
68 f.delete();
68 file.delete();
6969 assertNotNull("line1", line1);
7070 assertNotNull("line2", line2);
7171 assertTrue("line1", line1.endsWith(" INFO c.f.Bar [main] Async logger msg "));
2222 import org.apache.logging.log4j.LogManager;
2323 import org.apache.logging.log4j.Logger;
2424 import org.apache.logging.log4j.ThreadContext;
25 import org.apache.logging.log4j.core.LifeCycle;
25 import org.apache.logging.log4j.core.CoreLoggerContexts;
2626 import org.apache.logging.log4j.core.config.ConfigurationFactory;
2727 import org.apache.logging.log4j.core.util.Constants;
2828 import org.apache.logging.log4j.util.Strings;
4949
5050 @Test
5151 public void testAsyncLogWritesToLog() throws Exception {
52 final File f = new File("target", "AsyncLoggerTest.log");
52 final File file = new File("target", "AsyncLoggerTest.log");
5353 // System.out.println(f.getAbsolutePath());
54 f.delete();
54 file.delete();
5555
5656 ThreadContext.push("stackvalue");
5757 ThreadContext.put("KEY", "mapvalue");
5959 final Logger log = LogManager.getLogger("com.foo.Bar");
6060 final String msg = "Async logger msg";
6161 log.info(msg, new InternalError("this is not a real error"));
62 ((LifeCycle) LogManager.getContext()).stop(); // stop async thread
62 CoreLoggerContexts.stopLoggerContext(file); // stop async thread
6363
64 final BufferedReader reader = new BufferedReader(new FileReader(f));
64 final BufferedReader reader = new BufferedReader(new FileReader(file));
6565 final String line1 = reader.readLine();
6666 reader.close();
67 f.delete();
67 file.delete();
6868 assertNotNull("line1", line1);
6969 assertTrue("line1 correct", line1.contains(msg));
7070
2424
2525 import org.apache.logging.log4j.LogManager;
2626 import org.apache.logging.log4j.Logger;
27 import org.apache.logging.log4j.core.LifeCycle;
27 import org.apache.logging.log4j.core.CoreLoggerContexts;
2828 import org.apache.logging.log4j.core.config.ConfigurationFactory;
2929 import org.apache.logging.log4j.core.util.Clock;
3030 import org.apache.logging.log4j.core.util.ClockFactory;
6464 @Test
6565 public void testAsyncLogWritesToLog() throws Exception {
6666
67 final File f = new File("target", "AsyncLoggerTimestampMessageTest.log");
67 final File file = new File("target", "AsyncLoggerTimestampMessageTest.log");
6868 // System.out.println(f.getAbsolutePath());
69 f.delete();
69 file.delete();
7070 final Logger log = LogManager.getLogger("com.foo.Bar");
7171 log.info(new TimeMsg("Async logger msg with embedded timestamp", 123456789000L));
72 ((LifeCycle) LogManager.getContext()).stop(); // stop async thread
72 CoreLoggerContexts.stopLoggerContext(file); // stop async thread
7373
74 final BufferedReader reader = new BufferedReader(new FileReader(f));
74 final BufferedReader reader = new BufferedReader(new FileReader(file));
7575 final String line1 = reader.readLine();
7676 reader.close();
77 f.delete();
77 file.delete();
7878 assertNotNull(line1);
7979 assertTrue("line1 correct", line1.equals("123456789000 Async logger msg with embedded timestamp"));
8080 }
1818 import org.apache.logging.log4j.Level;
1919 import org.apache.logging.log4j.LogManager;
2020 import org.apache.logging.log4j.Logger;
21 import org.apache.logging.log4j.core.LifeCycle;
21 import org.apache.logging.log4j.core.CoreLoggerContexts;
2222 import org.apache.logging.log4j.core.config.ConfigurationFactory;
2323 import org.apache.logging.log4j.core.util.Constants;
2424 import org.apache.logging.log4j.message.SimpleMessage;
5151 final Logger log = LogManager.getLogger("com.foo.Bar");
5252 final String msg = "Async logger msg";
5353 log.info(msg, new InternalError("this is not a real error"));
54 ((LifeCycle) LogManager.getContext()).stop(); // stop async thread
54 CoreLoggerContexts.stopLoggerContext(); // stop async thread
5555
5656 // call the #logMessage() method to bypass the isEnabled check:
5757 // before the LOG4J2-639 fix this would throw a NPE
4141 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY,
4242 "AsyncLoggersWithAsyncAppenderTest.xml");
4343 System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR, AsyncLoggerContextSelector.class.getName());
44 ctx = (LoggerContext) LogManager.getContext(false);
44 ctx = LoggerContext.getContext(false);
4545 config = ctx.getConfiguration();
4646 listAppender = (ListAppender) config.getAppender("List");
4747 }
4141 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY,
4242 "AsyncLoggersWithAsyncLoggerConfigTest.xml");
4343 System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR, AsyncLoggerContextSelector.class.getName());
44 ctx = (LoggerContext) LogManager.getContext(false);
44 ctx = LoggerContext.getContext(false);
4545 config = ctx.getConfiguration();
4646 listAppender = (ListAppender) config.getAppender("List");
4747 }
2323 import org.apache.logging.log4j.Logger;
2424 import org.apache.logging.log4j.core.util.FileUtils;
2525 import org.apache.logging.log4j.junit.CleanFiles;
26 import org.apache.logging.log4j.junit.InitialLoggerContext;
27 import org.junit.Rule;
26 import org.apache.logging.log4j.junit.LoggerContextRule;
27 import org.junit.ClassRule;
2828 import org.junit.Test;
2929 import org.junit.rules.RuleChain;
3030
3838 private static final String LOG = "target/" + ISSUE + ".log";
3939 private static final String RESOURCE = "classpath:" + ISSUE_CONFIG;
4040
41 @Rule
42 public RuleChain rules = RuleChain.outerRule(new CleanFiles(LOG)).around(new InitialLoggerContext(RESOURCE));
41 @ClassRule
42 public static RuleChain rules = RuleChain.outerRule(new CleanFiles(LOG)).around(new LoggerContextRule(RESOURCE));
4343
4444 @Test
4545 public void testLog4j2_807() throws InterruptedException, URISyntaxException {
5757 final String threadName = null;
5858 final StackTraceElement location = null;
5959 final long currentTimeMillis = 0;
60 final long nanoTime = 1;
6061 evt.setValues(null, loggerName, marker, fqcn, level, data, t, map,
61 contextStack, threadName, location, currentTimeMillis);
62 contextStack, threadName, location, currentTimeMillis, nanoTime);
6263 assertEquals(Level.OFF, evt.getLevel());
6364 }
6465
7677 final String threadName = null;
7778 final StackTraceElement location = null;
7879 final long currentTimeMillis = 0;
80 final long nanoTime = 1;
7981 evt.setValues(null, loggerName, marker, fqcn, level, data, t, map,
80 contextStack, threadName, location, currentTimeMillis);
82 contextStack, threadName, location, currentTimeMillis, nanoTime);
8183 assertNotNull(evt.getMessage());
8284 }
8385
9597 final String threadName = null;
9698 final StackTraceElement location = null;
9799 final long currentTimeMillis = 123;
100 final long nanoTime = 1;
98101 evt.setValues(null, loggerName, marker, fqcn, level, data, t, map,
99 contextStack, threadName, location, currentTimeMillis);
102 contextStack, threadName, location, currentTimeMillis, nanoTime);
100103 assertEquals(123, evt.getTimeMillis());
101104 }
102105
114117 final String threadName = "main";
115118 final StackTraceElement location = null;
116119 final long currentTimeMillis = 12345;
120 final long nanoTime = 1;
117121 evt.setValues(null, loggerName, marker, fqcn, level, data, t, map,
118 contextStack, threadName, location, currentTimeMillis);
122 contextStack, threadName, location, currentTimeMillis, nanoTime);
119123
120124 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
121125 final ObjectOutputStream out = new ObjectOutputStream(baos);
146150 final Level level = Level.TRACE;
147151 final Message data = new SimpleMessage("message");
148152 final Throwable t = new InternalError("not a real error");
149 final Map<String, String> map = new HashMap<String, String>();
153 final Map<String, String> map = new HashMap<>();
150154 map.put("key", "value");
151155 final ContextStack contextStack = new MutableThreadContextStack(Arrays.asList("a", "b"));
152156 final String threadName = "main";
153157 final StackTraceElement location = null;
154158 final long currentTimeMillis = 12345;
159 final long nanoTime = 1;
155160 evt.setValues(null, loggerName, marker, fqcn, level, data, t, map,
156 contextStack, threadName, location, currentTimeMillis);
161 contextStack, threadName, location, currentTimeMillis, nanoTime);
157162
158163 final LogEvent actual = evt.createMemento();
159164 assertEquals(evt.getLoggerName(), actual.getLoggerName());
1616 package org.apache.logging.log4j.core.async.perftest;
1717
1818 import java.io.File;
19 import java.util.concurrent.TimeUnit;
1920
2021 import com.lmax.disruptor.collections.Histogram;
2122
3637
3738 // warmup at least 2 rounds and at most 1 minute
3839 final Histogram warmupHist = PerfTest.createHistogram();
39 final long stop = System.currentTimeMillis() + (60 * 1000);
40 final long stop = System.nanoTime() + TimeUnit.MINUTES.toNanos(1);
4041 final Runnable run1 = new Runnable() {
4142 @Override
4243 public void run() {
4344 for (int i = 0; i < 10; i++) {
4445 final int LINES = PerfTest.throughput ? 50000 : 200000;
4546 runTest(runner, LINES, null, warmupHist, 2);
46 if (i > 0 && System.currentTimeMillis() >= stop) {
47 if (i > 0 && System.nanoTime() - stop >= 0) {
4748 return;
4849 }
4950 }
1919 import java.io.IOException;
2020 import java.nio.charset.Charset;
2121 import java.util.Arrays;
22 import java.util.concurrent.TimeUnit;
2223
2324 import org.apache.logging.log4j.core.util.Loader;
2425
107108 // warmup at least 10 seconds
108109 final int LINES = 50000;
109110 int iterations = 0;
110 final long stop = System.currentTimeMillis() + (10 * 1000); // 10 seconds
111 final long stop = System.nanoTime() + TimeUnit.SECONDS.toNanos(10);
111112 do {
112113 runTest(runner, LINES, null, warmupHist, 1);
113114 iterations++;
114 } while (System.currentTimeMillis() < stop);
115 } while (System.nanoTime() - stop < 0);
115116
116117 printf("Warmup complete in %.1f seconds (%d iterations)%n", (System.nanoTime() - t1)
117118 / (1000.0 * 1000.0 * 1000.0), iterations);
6464 }
6565
6666 List<String> processArguments(final String java) {
67 final List<String> args = new ArrayList<String>();
67 final List<String> args = new ArrayList<>();
6868 args.add(java);
6969 args.add("-server");
7070 args.add("-Xms1g");
150150 long pct99_99;
151151 double latencyRowCount;
152152 int throughputRowCount;
153 private long averageOpsPerSec; // Do not make final. Compile fails on Java 6.
153 private final long averageOpsPerSec; // Do not make final. Compile fails on Java 6.
154154
155155 // example line: avg=828 99%=1118 99.99%=5028 Count=3125
156156 public Stats(final String raw) {
217217 + System.getProperty("AsyncLogger.ThreadNameStrategy", "CACHED");
218218
219219 final long start = System.nanoTime();
220 final List<Setup> tests = new ArrayList<PerfTestDriver.Setup>();
220 final List<Setup> tests = new ArrayList<>();
221221 // includeLocation=false
222222 tests.add(s("perf3PlainNoLoc.xml", LOG20, "Loggers all async",
223223 ALL_ASYNC, SYSCLOCK, THREADNAME));
5050 }
5151 }
5252
53 private final Map<String, Map<String, Stats>> results = new TreeMap<String, Map<String, Stats>>();
53 private final Map<String, Map<String, Stats>> results = new TreeMap<>();
5454
5555 public PerfTestResultFormatter() {
5656 }
138138 final Stats stats = new Stats(throughput, avg, pct99, pct99_99);
139139 Map<String, Stats> map = results.get(key.trim());
140140 if (map == null) {
141 map = new TreeMap<String, Stats>(sort());
141 map = new TreeMap<>(sort());
142142 results.put(key.trim(), map);
143143 }
144144 String subKey = sub.trim();
1717
1818 import org.apache.logging.log4j.LogManager;
1919 import org.apache.logging.log4j.Logger;
20 import org.apache.logging.log4j.core.LifeCycle;
21
20 import org.apache.logging.log4j.core.CoreLoggerContexts;
2221 import com.lmax.disruptor.collections.Histogram;
2322
2423 public class RunLog4j2 implements IPerfTestRunner {
6059
6160 @Override
6261 public void shutdown() {
63 ((LifeCycle) LogManager.getContext()).stop(); // stop async thread
62 CoreLoggerContexts.stopLoggerContext(); // stop async thread
6463 }
6564
6665
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.config;
18
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.fail;
22
23 import org.apache.logging.log4j.core.appender.RollingFileAppender;
24 import org.apache.logging.log4j.core.appender.rolling.CompositeTriggeringPolicy;
25 import org.apache.logging.log4j.core.appender.rolling.SizeBasedTriggeringPolicy;
26 import org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy;
27 import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
28 import org.apache.logging.log4j.junit.LoggerContextRule;
29 import org.junit.Rule;
30 import org.junit.Test;
31
32 public abstract class AbstractLog4j2_1100Test {
33
34 @Rule
35 public LoggerContextRule context = new LoggerContextRule(getConfigurationResource());
36
37 protected abstract String getConfigurationResource();
38
39 @Test
40 public void test() {
41 final Configuration configuration = context.getConfiguration();
42 assertNotNull(configuration);
43 final RollingFileAppender appender = configuration.getAppender("File");
44 assertNotNull(appender);
45 final CompositeTriggeringPolicy compositeTriggeringPolicy = appender.getTriggeringPolicy();
46 assertNotNull(compositeTriggeringPolicy);
47 final TriggeringPolicy[] triggeringPolicies = compositeTriggeringPolicy.getTriggeringPolicies();
48 SizeBasedTriggeringPolicy sizeBasedTriggeringPolicy = null;
49 TimeBasedTriggeringPolicy timeBasedTriggeringPolicy = null;
50 for (TriggeringPolicy triggeringPolicy : triggeringPolicies) {
51 if (triggeringPolicy instanceof TimeBasedTriggeringPolicy) {
52 timeBasedTriggeringPolicy = (TimeBasedTriggeringPolicy) triggeringPolicy;
53 assertEquals(7, timeBasedTriggeringPolicy.getInterval());
54 }
55 if (triggeringPolicy instanceof SizeBasedTriggeringPolicy) {
56 sizeBasedTriggeringPolicy = (SizeBasedTriggeringPolicy) triggeringPolicy;
57 assertEquals(100 * 1024 * 1024, sizeBasedTriggeringPolicy.getMaxFileSize());
58 }
59 }
60 if (timeBasedTriggeringPolicy == null) {
61 fail("Missing TimeBasedTriggeringPolicy");
62 }
63 if (sizeBasedTriggeringPolicy == null) {
64 fail("Missing SizeBasedTriggeringPolicy");
65 }
66 }
67 }
1818 import java.io.File;
1919 import java.util.Map;
2020
21 import org.apache.logging.log4j.LogManager;
2221 import org.apache.logging.log4j.core.LoggerContext;
2322 import org.apache.logging.log4j.core.config.xml.XmlConfiguration;
2423 import org.apache.logging.log4j.status.StatusLogger;
4140 final File file = new File(STATUS_LOG);
4241 file.delete();
4342 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
44 final LoggerContext ctx = (LoggerContext) LogManager.getContext();
43 final LoggerContext ctx = LoggerContext.getContext();
4544 final Configuration config = ctx.getConfiguration();
4645 if (config instanceof XmlConfiguration) {
4746 final String name = config.getName();
5655 @AfterClass
5756 public static void cleanupClass() {
5857 System.clearProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY);
59 final LoggerContext ctx = (LoggerContext) LogManager.getContext();
58 final LoggerContext ctx = LoggerContext.getContext();
6059 ctx.reconfigure();
6160 StatusLogger.getLogger().reset();
6261 final File file = new File(STATUS_LOG);
10099 public void testAdvertisementsRemovedOnConfigStop() {
101100 verifyExpectedEntriesAdvertised(InMemoryAdvertiser.getAdvertisedEntries());
102101
103 final LoggerContext ctx = (LoggerContext) LogManager.getContext();
102 final LoggerContext ctx = LoggerContext.getContext();
104103 ctx.stop();
105104
106105 final Map<Object, Map<String, String>> entries = InMemoryAdvertiser.getAdvertisedEntries();
114113 public void testAdvertisementsAddedOnReconfigAfterStop() {
115114 verifyExpectedEntriesAdvertised(InMemoryAdvertiser.getAdvertisedEntries());
116115
117 final LoggerContext ctx = (LoggerContext) LogManager.getContext();
116 final LoggerContext ctx = LoggerContext.getContext();
118117 ctx.stop();
119118
120119 final Map<Object, Map<String, String>> entries = InMemoryAdvertiser.getAdvertisedEntries();
3131 import org.apache.logging.log4j.core.LoggerContext;
3232 import org.apache.logging.log4j.core.filter.ThreadContextMapFilter;
3333 import org.apache.logging.log4j.junit.CleanFiles;
34 import org.apache.logging.log4j.junit.InitialLoggerContext;
34 import org.apache.logging.log4j.junit.LoggerContextRule;
3535 import org.apache.logging.log4j.util.Strings;
3636 import org.junit.Before;
3737 import org.junit.Rule;
6262 @Rule
6363 public TestRule rules;
6464
65 private final InitialLoggerContext init;
65 private final LoggerContextRule init;
6666
6767 private LoggerContext ctx;
6868
7070
7171 public ConfigurationTest(final String configFileName, final String logFileName) {
7272 this.logFileName = logFileName;
73 this.init = new InitialLoggerContext(configFileName);
73 this.init = new LoggerContextRule(configFileName);
7474 rules = RuleChain.outerRule(new CleanFiles(logFileName)).around(this.init);
7575 }
7676
9898 assertThat(appenders.size(), is(equalTo(3)));
9999 }
100100
101 @Test
102 public void testGetLoggerConfigEmpty() throws Exception {
103 final Configuration config = this.ctx.getConfiguration();
104 assertEquals(config.getRootLogger(), config.getLoggerConfig(Strings.EMPTY));
105 }
106
107 @Test(expected = NullPointerException.class)
108 public void testGetLoggerConfigNull() throws Exception {
109 final Configuration config = this.ctx.getConfiguration();
110 assertEquals(config.getRootLogger(), config.getLoggerConfig(null));
111 }
112
101113 @Test
102114 public void testLogger() throws Exception {
103115 final Logger logger = this.ctx.getLogger(LOGGER_NAME);
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config;
17
18 import java.io.File;
19
20 import org.apache.logging.log4j.core.LoggerContext;
21 import org.junit.Assert;
22 import org.junit.Test;
23
24 public class ConfiguratorTest {
25
26 @Test
27 public void testInitializeFromAbsoluteFilePath() {
28 final String path = new File("src/test/resources/log4j-list.xml").getAbsolutePath();
29 testInitializeFromFilePath(path);
30 }
31
32 @Test
33 public void testInitializeFromRelativeFilePath() {
34 final String path = new File("src/test/resources/log4j-list.xml").toString();
35 testInitializeFromFilePath(path);
36 }
37
38 private void testInitializeFromFilePath(String path) {
39 final LoggerContext loggerContext = Configurator.initialize(getClass().getName(), null, path);
40 try {
41 Assert.assertNotNull(loggerContext.getConfiguration().getAppender("List"));
42 } finally {
43 loggerContext.stop();
44 }
45 }
46 }
2626 import org.apache.logging.log4j.core.appender.FileAppender;
2727 import org.apache.logging.log4j.core.config.xml.XmlConfiguration;
2828 import org.apache.logging.log4j.core.layout.PatternLayout;
29 import org.apache.logging.log4j.junit.InitialLoggerContext;
29 import org.apache.logging.log4j.junit.LoggerContextRule;
3030 import org.apache.logging.log4j.status.StatusConsoleListener;
3131 import org.apache.logging.log4j.status.StatusListener;
3232 import org.apache.logging.log4j.status.StatusLogger;
5555 }
5656
5757 @Rule
58 public InitialLoggerContext init = new InitialLoggerContext("log4j-props.xml");
58 public LoggerContextRule init = new LoggerContextRule("log4j-props.xml");
5959
6060 @Before
6161 public void setUp() throws Exception {
1818 import java.io.File;
1919
2020 import org.apache.logging.log4j.junit.CleanFiles;
21 import org.apache.logging.log4j.junit.InitialLoggerContext;
21 import org.apache.logging.log4j.junit.LoggerContextRule;
2222 import org.junit.Rule;
2323 import org.junit.Test;
2424 import org.junit.rules.RuleChain;
3737 private static final String STATUS_LOG = "target/status.log";
3838
3939 @Rule
40 public RuleChain rules = RuleChain.outerRule(new CleanFiles(STATUS_LOG)).around(new InitialLoggerContext(CONFIG));
40 public RuleChain rules = RuleChain.outerRule(new CleanFiles(STATUS_LOG)).around(new LoggerContextRule(CONFIG));
4141
4242 @Test
4343 public void testConfig() {
2323
2424 @Plugin(name = "memory", category = "Core", elementType = "advertiser", printObject = false)
2525 public class InMemoryAdvertiser implements Advertiser {
26 private static Map<Object, Map<String, String>> properties = new HashMap<Object, Map<String, String>>();
26 private static Map<Object, Map<String, String>> properties = new HashMap<>();
2727
2828 public static Map<Object, Map<String, String>> getAdvertisedEntries()
2929 {
30 final Map<Object, Map<String, String>> result = new HashMap<Object, Map<String, String>>();
30 final Map<Object, Map<String, String>> result = new HashMap<>();
3131 result.putAll(properties);
3232 return result;
3333 }
3535 @Override
3636 public Object advertise(final Map<String, String> newEntry) {
3737 final Object object = new Object();
38 properties.put(object, new HashMap<String, String>(newEntry));
38 properties.put(object, new HashMap<>(newEntry));
3939 return object;
4040 }
4141
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.config;
18
19 public class JiraLog4j2_1100JsonTest extends AbstractLog4j2_1100Test {
20
21 @Override
22 protected String getConfigurationResource() {
23 return "LOG4J2-1100/log4j2.json";
24 }
25
26 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.config;
18
19 public class JiraLog4j2_1100XmlTest extends AbstractLog4j2_1100Test {
20
21 @Override
22 protected String getConfigurationResource() {
23 return "LOG4J2-1100/log4j2.xml";
24 }
25
26 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.config;
18
19 import org.junit.Ignore;
20
21 @Ignore
22 public class JiraLog4j2_1100YamlBadTest extends AbstractLog4j2_1100Test {
23
24 @Override
25 protected String getConfigurationResource() {
26 return "LOG4J2-1100/log4j2-good.yaml";
27 }
28
29 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.config;
18
19 public class JiraLog4j2_1100YamlGoodTest extends AbstractLog4j2_1100Test {
20
21 @Override
22 protected String getConfigurationResource() {
23 return "LOG4J2-1100/log4j2-good.yaml";
24 }
25
26 }
2121 import org.apache.logging.log4j.Logger;
2222 import org.apache.logging.log4j.core.Appender;
2323 import org.apache.logging.log4j.core.LoggerContext;
24 import org.apache.logging.log4j.junit.InitialLoggerContext;
24 import org.apache.logging.log4j.junit.LoggerContextRule;
2525 import org.junit.Rule;
2626 import org.junit.Test;
2727 import org.junit.runner.RunWith;
3737 public class MissingRootLoggerTest {
3838
3939 @Rule
40 public InitialLoggerContext context = new InitialLoggerContext("missingRootLogger.xml");
40 public LoggerContextRule context = new LoggerContextRule("missingRootLogger.xml");
4141
4242 @Test
4343 public void testMissingRootLogger() throws Exception {
1919
2020 import org.apache.logging.log4j.LogManager;
2121 import org.apache.logging.log4j.Logger;
22 import org.apache.logging.log4j.junit.InitialLoggerContext;
22 import org.apache.logging.log4j.junit.LoggerContextRule;
2323 import org.apache.logging.log4j.message.ThreadDumpMessage;
2424 import org.junit.Rule;
2525 import org.junit.Test;
3232 public class ReconfigurationDeadlockTest {
3333
3434 @Rule
35 public InitialLoggerContext init = new InitialLoggerContext("reconfiguration-deadlock.xml");
35 public LoggerContextRule init = new LoggerContextRule("reconfiguration-deadlock.xml");
3636 private static final int THREAD_COUNT = 5;
3737 private static final boolean[] finished = new boolean[THREAD_COUNT];
3838 private static LoggerThread[] threads = new LoggerThread[THREAD_COUNT];
2020 import java.io.InputStream;
2121 import java.io.Serializable;
2222 import java.util.Map;
23 import java.util.concurrent.TimeUnit;
2324
2425 import org.apache.logging.log4j.Level;
2526 import org.apache.logging.log4j.LogManager;
2829 import org.apache.logging.log4j.core.Filter;
2930 import org.apache.logging.log4j.core.Layout;
3031 import org.apache.logging.log4j.core.LoggerContext;
32 import org.apache.logging.log4j.core.appender.ConsoleAppender;
33 import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
34 import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
35 import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
36 import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
3137 import org.apache.logging.log4j.core.filter.CompositeFilter;
3238 import org.apache.logging.log4j.core.layout.PatternLayout;
3339 import org.junit.After;
232238 assertNotNull("Appenders map should not be null.", map);
233239 assertThat(map, hasSize(greaterThan(0)));
234240 assertThat("Wrong configuration", map, hasKey("List"));
235
236 Thread.sleep(500);
241
242 // Sleep and check
243 Thread.sleep(50);
244 if (!file.setLastModified(System.currentTimeMillis())) {
245 Thread.sleep(500);
246 }
237247 assertTrue("setLastModified should have succeeded.", file.setLastModified(System.currentTimeMillis()));
248 TimeUnit.SECONDS.sleep(FileConfigurationMonitor.MIN_INTERVAL + 1);
238249 for (int i = 0; i < 17; ++i) {
239250 logger.debug("Test message " + i);
240251 }
241 Thread.sleep(100);
252
253 // Sleep and check
254 Thread.sleep(50);
255 if (is(theInstance(config)).matches(ctx.getConfiguration())) {
256 Thread.sleep(500);
257 }
242258 final Configuration newConfig = ctx.getConfiguration();
243259 assertThat("Configuration not reset", newConfig, is(not(theInstance(config))));
244260 Configurator.shutdown(ctx);
343359 assertThat(config.getAppenders(), hasSize(equalTo(2)));
344360 }
345361
362 @Test
363 public void testBuilder() throws Exception {
364 ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
365 builder.setStatusLevel(Level.ERROR);
366 builder.setConfigurationName("BuilderTest");
367 builder.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.NEUTRAL)
368 .addAttribute("level", Level.DEBUG));
369 AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE").addAttribute("target",
370 ConsoleAppender.Target.SYSTEM_OUT);
371 appenderBuilder.add(builder.newLayout("PatternLayout").
372 addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable"));
373 appenderBuilder.add(builder.newFilter("MarkerFilter", Filter.Result.DENY,
374 Filter.Result.NEUTRAL).addAttribute("marker", "FLOW"));
375 builder.add(appenderBuilder);
376 builder.add(builder.newLogger("org.apache.logging.log4j", Level.DEBUG).
377 add(builder.newAppenderRef("Stdout")).
378 addAttribute("additivity", false));
379 builder.add(builder.newRootLogger(Level.ERROR).add(builder.newAppenderRef("Stdout")));
380 ctx = Configurator.initialize(builder.build());
381 final Configuration config = ctx.getConfiguration();
382 assertNotNull("No configuration", config);
383 assertEquals("Unexpected Configuration", "BuilderTest", config.getName());
384 assertThat(config.getAppenders(), hasSize(equalTo(1)));
385 }
386
346387 }
3131 import org.apache.logging.log4j.core.LoggerContext;
3232 import org.apache.logging.log4j.core.filter.ThreadContextMapFilter;
3333 import org.apache.logging.log4j.junit.CleanFiles;
34 import org.apache.logging.log4j.junit.InitialLoggerContext;
34 import org.apache.logging.log4j.junit.LoggerContextRule;
3535 import org.apache.logging.log4j.util.Strings;
3636 import org.junit.Before;
3737 import org.junit.Rule;
6565 @Rule
6666 public TestRule rules;
6767
68 private final InitialLoggerContext init;
68 private final LoggerContextRule init;
6969
7070 private LoggerContext ctx;
7171
7373
7474 public XIncludeTest(final String configFileName, final String logFileName) {
7575 this.logFileName = logFileName;
76 this.init = new InitialLoggerContext(configFileName);
76 this.init = new LoggerContextRule(configFileName);
7777 this.rules = RuleChain.outerRule(new CleanFiles(logFileName)).around(this.init);
7878 }
7979
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder;
17
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertFalse;
20 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.assertTrue;
22
23 import java.util.Map;
24
25 import org.apache.logging.log4j.LogManager;
26 import org.apache.logging.log4j.Logger;
27 import org.apache.logging.log4j.core.Appender;
28 import org.apache.logging.log4j.core.Filter;
29 import org.apache.logging.log4j.core.LifeCycle;
30 import org.apache.logging.log4j.core.LoggerContext;
31 import org.apache.logging.log4j.core.config.Configuration;
32 import org.apache.logging.log4j.core.config.ConfigurationFactory;
33 import org.apache.logging.log4j.core.config.Configurator;
34 import org.apache.logging.log4j.core.config.LoggerConfig;
35 import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
36 import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
37 import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
38 import org.apache.logging.log4j.core.filter.ThresholdFilter;
39 import org.junit.Test;
40
41 /**
42 *
43 */
44 public class ConfigurationAssemblerTest {
45
46 @Test
47 public void testBuildConfiguration() throws Exception {
48 final ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
49 CustomConfigurationFactory.addTestFixtures("config name", builder);
50 Configuration configuration = builder.build();
51 Configurator.initialize(configuration);
52 validate(configuration);
53 }
54
55 @Test
56 public void testCustomConfigurationFactory() throws Exception {
57 try {
58 System.setProperty(ConfigurationFactory.CONFIGURATION_FACTORY_PROPERTY,
59 "org.apache.logging.log4j.core.config.builder.CustomConfigurationFactory");
60 Configuration config = ((LoggerContext) LogManager.getContext(false)).getConfiguration();
61 validate(config);
62 } finally {
63 System.getProperties().remove(ConfigurationFactory.CONFIGURATION_FACTORY_PROPERTY);
64 }
65 }
66
67 private void validate(Configuration config) {
68 assertNotNull(config);
69 assertNotNull(config.getName());
70 assertFalse(config.getName().isEmpty());
71 assertNotNull("No configuration created", config);
72 assertEquals("Incorrect State: " + config.getState(), config.getState(), LifeCycle.State.STARTED);
73 Map<String, Appender> appenders = config.getAppenders();
74 assertNotNull(appenders);
75 assertTrue("Incorrect number of Appenders: " + appenders.size(), appenders.size() == 1);
76 Map<String, LoggerConfig> loggers = config.getLoggers();
77 assertNotNull(loggers);
78 assertTrue("Incorrect number of LoggerConfigs: " + loggers.size(), loggers.size() == 2);
79 Filter filter = config.getFilter();
80 assertNotNull("No Filter", filter);
81 assertTrue("Not a Threshold Filter", filter instanceof ThresholdFilter);
82 Logger logger = LogManager.getLogger(getClass());
83 logger.info("Welcome to Log4j!");
84 }
85 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.builder;
17
18 import org.apache.logging.log4j.Level;
19 import org.apache.logging.log4j.core.Filter;
20 import org.apache.logging.log4j.core.appender.ConsoleAppender;
21 import org.apache.logging.log4j.core.config.Configuration;
22 import org.apache.logging.log4j.core.config.ConfigurationFactory;
23 import org.apache.logging.log4j.core.config.ConfigurationSource;
24 import org.apache.logging.log4j.core.config.builder.api.AppenderComponentBuilder;
25 import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
26 import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
27
28 import java.net.URI;
29
30 /**
31 * Normally this would be a plugin. However, we don't want it used for everything so it will be defined
32 * via a system property.
33 */
34 //@Plugin(name = "CustomConfigurationFactory", category = ConfigurationFactory.CATEGORY)
35 //@Order(50)
36 public class CustomConfigurationFactory extends ConfigurationFactory {
37
38 static Configuration addTestFixtures(final String name, ConfigurationBuilder<BuiltConfiguration> builder) {
39 builder.setConfigurationName(name);
40 builder.setStatusLevel(Level.ERROR);
41 builder.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.NEUTRAL)
42 .addAttribute("level", Level.DEBUG));
43 AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE").addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
44 appenderBuilder.add(builder.newLayout("PatternLayout").
45 addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable"));
46 appenderBuilder.add(builder.newFilter("MarkerFilter", Filter.Result.DENY,
47 Filter.Result.NEUTRAL).addAttribute("marker", "FLOW"));
48 builder.add(appenderBuilder);
49 builder.add(builder.newLogger("org.apache.logging.log4j", Level.DEBUG).
50 add(builder.newAppenderRef("Stdout")).
51 addAttribute("additivity", false));
52 builder.add(builder.newRootLogger(Level.ERROR).add(builder.newAppenderRef("Stdout")));
53 return builder.build();
54 }
55
56 @Override
57 public Configuration getConfiguration(ConfigurationSource source) {
58 return getConfiguration(source.toString(), null);
59 }
60
61 @Override
62 public Configuration getConfiguration(final String name, final URI configLocation) {
63 ConfigurationBuilder<BuiltConfiguration> builder = newConfigurationBuilder();
64 return addTestFixtures(name, builder);
65 }
66
67 @Override
68 protected String[] getSupportedTypes() {
69 return new String[] {"*"};
70 }
71 }
2222 import java.net.URI;
2323 import java.net.URL;
2424 import java.nio.charset.Charset;
25 import java.nio.charset.StandardCharsets;
2526 import java.security.Provider;
2627 import java.security.Security;
2728 import java.util.Arrays;
3132 import org.apache.logging.log4j.core.Filter;
3233 import org.apache.logging.log4j.core.layout.GelfLayout;
3334 import org.apache.logging.log4j.core.net.Facility;
34 import org.apache.logging.log4j.core.util.Charsets;
3535 import org.junit.Test;
3636 import org.junit.runner.RunWith;
3737 import org.junit.runners.Parameterized;
148148 { "Base64:cGxlYXN1cmUu", "pleasure.".getBytes("US-ASCII"), null, byte[].class },
149149 // JRE
150150 // JRE Charset
151 { "UTF-8", Charsets.UTF_8, null, Charset.class },
151 { "UTF-8", StandardCharsets.UTF_8, null, Charset.class },
152152 { "ASCII", Charset.forName("ASCII"), "UTF-8", Charset.class },
153 { "Not a real charset", Charsets.UTF_8, "UTF-8", Charset.class },
154 { null, Charsets.UTF_8, "UTF-8", Charset.class },
153 { "Not a real charset", StandardCharsets.UTF_8, "UTF-8", Charset.class },
154 { null, StandardCharsets.UTF_8, "UTF-8", Charset.class },
155155 { null, null, null, Charset.class },
156156 // JRE File
157157 { "c:/temp", new File("c:/temp"), null, File.class },
9191 private void compile(final File f) throws IOException {
9292 // set up compiler
9393 final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
94 final DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
95 final StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
96 final Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(f));
94 final DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
95 final List<String> errors = new ArrayList<>();
96 try (final StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null)) {
97 final Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(Arrays
98 .asList(f));
9799
98 // compile generated source
99 // (switch off annotation processing: no need to create Log4j2Plugins.dat)
100 final List<String> options = Arrays.asList("-proc:none");
101 compiler.getTask(null, fileManager, diagnostics, options, null, compilationUnits).call();
100 // compile generated source
101 // (switch off annotation processing: no need to create Log4j2Plugins.dat)
102 final List<String> options = Arrays.asList("-proc:none");
103 compiler.getTask(null, fileManager, diagnostics, options, null, compilationUnits).call();
102104
103 // check we don't have any compilation errors
104 final List<String> errors = new ArrayList<String>();
105 for (final Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
106 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
107 errors.add(String.format("Compile error: %s%n", diagnostic.getMessage(Locale.getDefault())));
105 // check we don't have any compilation errors
106 for (final Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
107 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
108 errors.add(String.format("Compile error: %s%n", diagnostic.getMessage(Locale.getDefault())));
109 }
108110 }
109111 }
110 fileManager.close();
111112 assertTrue(errors.toString(), errors.isEmpty());
112113 }
113114 }
1616
1717 package org.apache.logging.log4j.core.config.plugins.util;
1818
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertTrue;
21
22 import java.io.UnsupportedEncodingException;
23 import java.net.MalformedURLException;
24 import java.net.URISyntaxException;
1925 import java.net.URL;
2026
2127 import org.junit.Ignore;
2228 import org.junit.Test;
23
24 import static org.junit.Assert.*;
2529
2630 /**
2731 * Tests the ResolverUtil class.
3741
3842 @Test
3943 public void testExtractPathFromJarUrlNotDecodedIfFileExists() throws Exception {
40 final String existingFile = "/log4j+config+with+plus+characters.xml";
44 testExtractPathFromJarUrlNotDecodedIfFileExists("/log4j+config+with+plus+characters.xml");
45 }
46
47 private void testExtractPathFromJarUrlNotDecodedIfFileExists(final String existingFile)
48 throws MalformedURLException, UnsupportedEncodingException, URISyntaxException {
4149 URL url = ResolverUtilTest.class.getResource(existingFile);
4250 if (!url.getProtocol().equals("jar")) {
4351 // create fake jar: URL that resolves to existing file
4553 }
4654 final String actual = new ResolverUtil().extractPath(url);
4755 assertTrue("should not be decoded: " + actual, actual.endsWith(existingFile));
56 }
57
58 @Test
59 public void testFileFromUriWithSpacesAndPlusCharactersInName() throws Exception {
60 final String existingFile = "/s p a c e s/log4j+config+with+plus+characters.xml";
61 testExtractPathFromJarUrlNotDecodedIfFileExists(existingFile);
4862 }
4963
5064 @Test
1515 */
1616 package org.apache.logging.log4j.core.config.plugins.validation;
1717
18 import java.util.Objects;
19
1820 import org.apache.logging.log4j.core.config.plugins.Plugin;
1921 import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
2022 import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
2123 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
2224 import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
23 import org.apache.logging.log4j.core.util.Assert;
2425
2526 /**
2627 *
3132 private final String name;
3233
3334 public ValidatingPlugin(final String name) {
34 this.name = Assert.requireNonNull(name, "name");
35 this.name = Objects.requireNonNull(name, "name");
3536 }
3637
3738 public String getName() {
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.properties;
17
18 import org.apache.logging.log4j.LogManager;
19 import org.apache.logging.log4j.Logger;
20 import org.apache.logging.log4j.core.Appender;
21 import org.apache.logging.log4j.core.Filter;
22 import org.apache.logging.log4j.core.LifeCycle;
23 import org.apache.logging.log4j.core.LoggerContext;
24 import org.apache.logging.log4j.core.config.Configuration;
25 import org.apache.logging.log4j.core.config.ConfigurationFactory;
26 import org.apache.logging.log4j.core.config.LoggerConfig;
27 import org.apache.logging.log4j.core.filter.ThresholdFilter;
28 import org.junit.Test;
29
30 import java.util.Map;
31
32 import static org.junit.Assert.assertEquals;
33 import static org.junit.Assert.assertNotNull;
34 import static org.junit.Assert.assertTrue;
35
36 /**
37 *
38 */
39 public class PropertiesConfigurationTest {
40
41 @Test
42 public void testPropertiesConfiguration() {
43 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, "target/test-classes/log4j2-properties.properties");
44 Configuration config = ((LoggerContext)LogManager.getContext(false)).getConfiguration();
45 assertNotNull("No configuration created", config);
46 assertEquals("Incorrect State: " + config.getState(), config.getState(), LifeCycle.State.STARTED);
47 Map<String, Appender> appenders = config.getAppenders();
48 assertNotNull(appenders);
49 assertTrue("Incorrect number of Appenders: " + appenders.size(), appenders.size() == 1);
50 Map<String, LoggerConfig> loggers = config.getLoggers();
51 assertNotNull(loggers);
52 assertTrue("Incorrect number of LoggerConfigs: " + loggers.size(), loggers.size() == 2);
53 Filter filter = config.getFilter();
54 assertNotNull("No Filter", filter);
55 assertTrue("Not a Threshold Filter", filter instanceof ThresholdFilter);
56 Logger logger = LogManager.getLogger(getClass());
57 logger.info("Welcome to Log4j!");
58 }
59 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.config.properties;
17
18 import org.apache.logging.log4j.LogManager;
19 import org.apache.logging.log4j.Logger;
20 import org.apache.logging.log4j.core.Appender;
21 import org.apache.logging.log4j.core.Filter;
22 import org.apache.logging.log4j.core.LifeCycle;
23 import org.apache.logging.log4j.core.LoggerContext;
24 import org.apache.logging.log4j.core.config.Configuration;
25 import org.apache.logging.log4j.core.config.ConfigurationFactory;
26 import org.apache.logging.log4j.core.config.LoggerConfig;
27 import org.apache.logging.log4j.core.filter.ThresholdFilter;
28 import org.junit.Test;
29
30 import java.util.Map;
31
32 import static org.junit.Assert.assertEquals;
33 import static org.junit.Assert.assertNotNull;
34 import static org.junit.Assert.assertTrue;
35
36 /**
37 *
38 */
39 public class RollingFilePropertiesTest {
40 @Test
41 public void testPropertiesConfiguration() {
42 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, "target/test-classes/log4j-rolling.properties");
43 Configuration config = ((LoggerContext) LogManager.getContext(false)).getConfiguration();
44 assertNotNull("No configuration created", config);
45 assertEquals("Incorrect State: " + config.getState(), config.getState(), LifeCycle.State.STARTED);
46 Map<String, Appender> appenders = config.getAppenders();
47 assertNotNull(appenders);
48 assertTrue("Incorrect number of Appenders: " + appenders.size(), appenders.size() == 3);
49 Map<String, LoggerConfig> loggers = config.getLoggers();
50 assertNotNull(loggers);
51 assertTrue("Incorrect number of LoggerConfigs: " + loggers.size(), loggers.size() == 2);
52 Filter filter = config.getFilter();
53 assertNotNull("No Filter", filter);
54 assertTrue("Not a Threshold Filter", filter instanceof ThresholdFilter);
55 Logger logger = LogManager.getLogger(getClass());
56 logger.info("Welcome to Log4j!");
57 }
58 }
1515 */
1616 package org.apache.logging.log4j.core.config.xml;
1717
18 import org.apache.logging.log4j.LogManager;
1918 import org.apache.logging.log4j.core.LoggerContext;
2019 import org.apache.logging.log4j.core.config.Configuration;
2120 import org.apache.logging.log4j.core.config.ConfigurationFactory;
3736 @AfterClass
3837 public static void cleanupClass() {
3938 System.clearProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY);
40 final LoggerContext ctx = (LoggerContext) LogManager.getContext();
39 final LoggerContext ctx = LoggerContext.getContext();
4140 ctx.reconfigure();
4241 StatusLogger.getLogger().reset();
4342 }
4544 @Test
4645 public void testNoProps() {
4746 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
48 final LoggerContext ctx = (LoggerContext) LogManager.getContext();
47 final LoggerContext ctx = LoggerContext.getContext();
4948 ctx.reconfigure();
5049 final Configuration config = ctx.getConfiguration();
5150 assertTrue("Configuration is not an XmlConfiguration", config instanceof XmlConfiguration);
5756 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG1);
5857 System.setProperty(Constants.LOG4J_DEFAULT_STATUS_LEVEL, "WARN");
5958 try {
60 final LoggerContext ctx = (LoggerContext) LogManager.getContext();
59 final LoggerContext ctx = LoggerContext.getContext();
6160 ctx.reconfigure();
6261 final Configuration config = ctx.getConfiguration();
6362 assertTrue("Configuration is not an XmlConfiguration", config instanceof XmlConfiguration);
7170 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
7271 System.setProperty("log4j.level", "warn");
7372 try {
74 final LoggerContext ctx = (LoggerContext) LogManager.getContext();
73 final LoggerContext ctx = LoggerContext.getContext();
7574 ctx.reconfigure();
7675 final Configuration config = ctx.getConfiguration();
7776 assertTrue("Configuration is not an XmlConfiguration", config instanceof XmlConfiguration);
8786 System.setProperty("log4j.level", "warn");
8887 System.setProperty("log.level", "warn");
8988 try {
90 final LoggerContext ctx = (LoggerContext) LogManager.getContext();
89 final LoggerContext ctx = LoggerContext.getContext();
9190 ctx.reconfigure();
9291 final Configuration config = ctx.getConfiguration();
9392 assertTrue("Configuration is not an XmlConfiguration", config instanceof XmlConfiguration);
1919
2020 import org.apache.logging.log4j.LogManager;
2121 import org.apache.logging.log4j.Logger;
22 import org.apache.logging.log4j.junit.InitialLoggerContext;
22 import org.apache.logging.log4j.junit.LoggerContextRule;
2323 import org.apache.logging.log4j.test.appender.ListAppender;
2424 import org.junit.BeforeClass;
2525 import org.junit.Rule;
3939 private static final String CONFIG = "log4j-loggerprops.xml";
4040
4141 @Rule
42 public final InitialLoggerContext context = new InitialLoggerContext(CONFIG);
42 public final LoggerContextRule context = new LoggerContextRule(CONFIG);
4343
4444 @BeforeClass
4545 public static void setupClass() {
0 /* Licensed to the Apache Software Foundation (ASF) under one
1 * or more contributor license agreements. See the NOTICE file
2 * distributed with this work for additional information
3 * regarding copyright ownership. The ASF licenses this file
4 * to you under the Apache License, Version 2.0 (the
5 * "License"); you may not use this file except in compliance
6 * with the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing,
11 * software distributed under the License is distributed on an
12 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 * KIND, either express or implied. See the License for the
14 * specific language governing permissions and limitations
15 * under the License.
16 */
17 package org.apache.logging.log4j.core.filter;
18
19 import static org.hamcrest.Matchers.greaterThan;
20 import static org.hamcrest.Matchers.is;
21 import static org.junit.Assert.assertThat;
22
23 import java.util.concurrent.Delayed;
24 import java.util.concurrent.TimeUnit;
25
26 import org.junit.Test;
27
28 /**
29 * Unit test for <code>BurstFilter</code>.
30 */
31 public class BurstFilterLogDelayTest {
32
33 @Test
34 public void testCompareToOverflow() {
35 // no overflow, but close
36 final Delayed d1 = BurstFilter.createLogDelay(Long.MAX_VALUE - TimeUnit.SECONDS.toNanos(10) - System.nanoTime());
37
38 // Overflow
39 final Delayed d2 = BurstFilter.createLogDelay(Long.MAX_VALUE + TimeUnit.SECONDS.toNanos(10) - System.nanoTime());
40
41 assertThat(d2, is(greaterThan(d1)));
42 }
43
44 }
1919 import java.util.List;
2020
2121 import org.apache.logging.log4j.Logger;
22 import org.apache.logging.log4j.junit.InitialLoggerContext;
22 import org.apache.logging.log4j.junit.LoggerContextRule;
2323 import org.apache.logging.log4j.test.appender.ListAppender;
2424 import org.junit.Before;
2525 import org.junit.ClassRule;
3434 private static final String CONFIG = "log4j-burst.xml";
3535
3636 @ClassRule
37 public static InitialLoggerContext context = new InitialLoggerContext(CONFIG);
37 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
3838
3939 @Before
4040 public void setUp() throws Exception {
2323 import java.util.Map;
2424
2525 import org.apache.logging.log4j.Level;
26 import org.apache.logging.log4j.LogManager;
2726 import org.apache.logging.log4j.ThreadContext;
2827 import org.apache.logging.log4j.core.Filter;
2928 import org.apache.logging.log4j.core.LogEvent;
4443
4544 @After
4645 public void cleanup() {
47 final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
46 final LoggerContext ctx = LoggerContext.getContext(false);
4847 ctx.reconfigure();
4948 StatusLogger.getLogger().reset();
5049 }
6564 ThreadContext.clearMap();
6665 ThreadContext.put("userid", "JohnDoe");
6766 ThreadContext.put("organization", "apache");
68 LogEvent event = new Log4jLogEvent(null, null, null, Level.DEBUG, new SimpleMessage("Test"), null);
67 LogEvent event = Log4jLogEvent.newBuilder().setLevel(Level.DEBUG).setMessage(new SimpleMessage("Test")).build();
6968 assertSame(Filter.Result.DENY, filter.filter(event));
70 event = new Log4jLogEvent(null, null, null, Level.ERROR, new SimpleMessage("Test"), null);
69 event = Log4jLogEvent.newBuilder().setLevel(Level.ERROR).setMessage(new SimpleMessage("Test")).build();
7170 assertSame(Filter.Result.NEUTRAL, filter.filter(event));
7271 ThreadContext.clearMap();
7372 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.filter;
17
18 import org.apache.logging.log4j.Level;
19 import org.apache.logging.log4j.core.Filter;
20 import org.apache.logging.log4j.core.LogEvent;
21 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
22 import org.apache.logging.log4j.message.SimpleMessage;
23 import org.junit.Test;
24
25 import static org.junit.Assert.*;
26
27 /**
28 *
29 */
30 public class LevelRangeFilterTest {
31
32 @Test
33 public void testLevels() {
34 final LevelRangeFilter filter = LevelRangeFilter.createFilter(Level.ERROR, Level.INFO, null, null);
35 filter.start();
36 assertTrue(filter.isStarted());
37 assertSame(Filter.Result.DENY, filter.filter(null, Level.DEBUG, null, null, (Throwable) null));
38 assertSame(Filter.Result.NEUTRAL, filter.filter(null, Level.ERROR, null, null, (Throwable) null));
39 LogEvent event = Log4jLogEvent.newBuilder() //
40 .setLevel(Level.DEBUG) //
41 .setMessage(new SimpleMessage("Test")) //
42 .build();
43 assertSame(Filter.Result.DENY, filter.filter(event));
44 event = Log4jLogEvent.newBuilder() //
45 .setLevel(Level.ERROR) //
46 .setMessage(new SimpleMessage("Test")) //
47 .build();
48 assertSame(Filter.Result.NEUTRAL, filter.filter(event));
49 }
50 }
4343
4444 @After
4545 public void cleanup() {
46 final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
46 final LoggerContext ctx = LoggerContext.getContext(false);
4747 ctx.reconfigure();
4848 StatusLogger.getLogger().reset();
4949 }
9090 assertTrue("Map does not contain key eventId", map.containsKey("eventId"));
9191 assertEquals("List does not contain 2 elements", 2, map.get("eventId").size());
9292 final Logger logger = LogManager.getLogger(MapFilterTest.class);
93 final Map<String, String> eventMap = new HashMap<String, String>();
93 final Map<String, String> eventMap = new HashMap<>();
9494 eventMap.put("eventId", "Login");
9595 logger.debug(new MapMessage(eventMap));
9696 final Appender app = config.getAppender("LIST");
4545 assertSame(Filter.Result.NEUTRAL, filter.filter(null, null, child, null, (Throwable) null));
4646 assertSame(Filter.Result.NEUTRAL, filter.filter(null, null, grandChild, null, (Throwable) null));
4747 filter.stop();
48 LogEvent event = new Log4jLogEvent(null, grandChild, null, Level.DEBUG, new SimpleMessage("Test"), null);
48 LogEvent event = Log4jLogEvent.newBuilder() //
49 .setMarker(grandChild) //
50 .setLevel(Level.DEBUG) //
51 .setMessage(new SimpleMessage("Hello, world!")).build();
4952 assertSame(Filter.Result.NEUTRAL, filter.filter(event));
5053 filter = MarkerFilter.createFilter("Child", null, null);
5154 filter.start();
5255 assertSame(Filter.Result.NEUTRAL, filter.filter(event));
53 event = new Log4jLogEvent(null, sibling, null, Level.DEBUG, new SimpleMessage("Test"), null);
56 event = Log4jLogEvent.newBuilder() //
57 .setMarker(sibling) //
58 .setLevel(Level.DEBUG) //
59 .setMessage(new SimpleMessage("Hello, world!")).build();
5460 assertSame(Filter.Result.DENY, filter.filter(event));
5561 filter.stop();
5662 }
4949 assertSame(Filter.Result.NEUTRAL,
5050 filter.filter(null, Level.DEBUG, null, "This is a test message", (Throwable) null));
5151 assertSame(Filter.Result.DENY, filter.filter(null, Level.ERROR, null, "This is not a test", (Throwable) null));
52 LogEvent event = new Log4jLogEvent(null, null, null, Level.DEBUG, new SimpleMessage("Another test message"),
53 null);
52 LogEvent event = Log4jLogEvent.newBuilder() //
53 .setLevel(Level.DEBUG) //
54 .setMessage(new SimpleMessage("Another test message")) //
55 .build();
5456 assertSame(Filter.Result.NEUTRAL, filter.filter(event));
55 event = new Log4jLogEvent(null, null, null, Level.ERROR, new SimpleMessage("test"), null);
57 event = Log4jLogEvent.newBuilder() //
58 .setLevel(Level.ERROR) //
59 .setMessage(new SimpleMessage("test")) //
60 .build();
5661 assertSame(Filter.Result.DENY, filter.filter(event));
5762 filter = RegexFilter.createFilter(null, null, false, null, null);
5863 assertNull(filter);
3636 assertTrue(filter.isStarted());
3737 assertSame(Filter.Result.DENY, filter.filter(null, Level.DEBUG, null, null, (Throwable) null));
3838 assertSame(Filter.Result.NEUTRAL, filter.filter(null, Level.ERROR, null, null, (Throwable) null));
39 LogEvent event = new Log4jLogEvent(null, null, null, Level.DEBUG, new SimpleMessage("Test"), null);
39 LogEvent event = Log4jLogEvent.newBuilder() //
40 .setLevel(Level.DEBUG) //
41 .setMessage(new SimpleMessage("Test")) //
42 .build();
4043 assertSame(Filter.Result.DENY, filter.filter(event));
41 event = new Log4jLogEvent(null, null, null, Level.ERROR, new SimpleMessage("Test"), null);
44 event = Log4jLogEvent.newBuilder() //
45 .setLevel(Level.ERROR) //
46 .setMessage(new SimpleMessage("Test")) //
47 .build();
4248 assertSame(Filter.Result.NEUTRAL, filter.filter(event));
4349 }
4450 }
3939 final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("America/LosAngeles"));
4040 cal.set(Calendar.HOUR_OF_DAY, 2);
4141 long tod = cal.getTimeInMillis();
42 LogEvent event = new Log4jLogEvent(null, null, null, null, null, null, null, null, null, null, tod);
42 LogEvent event = Log4jLogEvent.newBuilder().setTimeMillis(tod).build();
4343 assertSame(Filter.Result.NEUTRAL, filter.filter(null, Level.ERROR, null, null, (Throwable) null));
4444 assertSame(Filter.Result.NEUTRAL, filter.filter(event));
4545 cal.roll(Calendar.DAY_OF_MONTH, true);
4646 tod = cal.getTimeInMillis();
47 event = new Log4jLogEvent(null, null, null, null, null, null, null, null, null, null, tod);
47 event = Log4jLogEvent.newBuilder().setTimeMillis(tod).build();
4848 assertSame(Filter.Result.NEUTRAL, filter.filter(event));
4949 cal.set(Calendar.HOUR_OF_DAY, 4);
5050 tod = cal.getTimeInMillis();
51 event = new Log4jLogEvent(null, null, null, null, null, null, null, null, null, null, tod);
51 event = Log4jLogEvent.newBuilder().setTimeMillis(tod).build();
5252 assertSame(Filter.Result.DENY, filter.filter(event));
5353 }
5454 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.impl;
17
18 import java.io.BufferedReader;
19 import java.io.File;
20 import java.io.FileReader;
21 import java.util.concurrent.TimeUnit;
22
23 import org.apache.logging.log4j.LogManager;
24 import org.apache.logging.log4j.Logger;
25 import org.apache.logging.log4j.core.CoreLoggerContexts;
26 import org.apache.logging.log4j.core.config.ConfigurationFactory;
27 import org.apache.logging.log4j.core.util.Constants;
28 import org.apache.logging.log4j.core.util.DummyNanoClock;
29 import org.apache.logging.log4j.core.util.SystemNanoClock;
30 import org.apache.logging.log4j.util.Strings;
31 import org.junit.AfterClass;
32 import org.junit.BeforeClass;
33 import org.junit.Test;
34
35 import static org.junit.Assert.*;
36
37 public class Log4jLogEventNanoTimeTest {
38
39 @BeforeClass
40 public static void beforeClass() {
41 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY,
42 "NanoTimeToFileTest.xml");
43 }
44
45 @AfterClass
46 public static void afterClass() {
47 System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR, Strings.EMPTY);
48 }
49
50 @Test
51 public void testLog4jLogEventUsesNanoTimeClock() throws Exception {
52 final File file = new File("target", "NanoTimeToFileTest.log");
53 // System.out.println(f.getAbsolutePath());
54 file.delete();
55 final Logger log = LogManager.getLogger("com.foo.Bar");
56 final long before = System.nanoTime();
57 log.info("Use actual System.nanoTime()");
58 assertTrue("using SystemNanoClock", Log4jLogEvent.getNanoClock() instanceof SystemNanoClock);
59
60 final long DUMMYNANOTIME = 123;
61 Log4jLogEvent.setNanoClock(new DummyNanoClock(DUMMYNANOTIME));
62 log.info("Use dummy nano clock");
63 assertTrue("using SystemNanoClock", Log4jLogEvent.getNanoClock() instanceof DummyNanoClock);
64
65 CoreLoggerContexts.stopLoggerContext(file); // stop async thread
66
67 final BufferedReader reader = new BufferedReader(new FileReader(file));
68 final String line1 = reader.readLine();
69 final String line2 = reader.readLine();
70 // System.out.println(line1);
71 // System.out.println(line2);
72 reader.close();
73 file.delete();
74
75 assertNotNull("line1", line1);
76 assertNotNull("line2", line2);
77 final String[] line1Parts = line1.split(" AND ");
78 assertEquals("Use actual System.nanoTime()", line1Parts[2]);
79 assertEquals(line1Parts[0], line1Parts[1]);
80 long loggedNanoTime = Long.parseLong(line1Parts[0]);
81 assertTrue("used system nano time", loggedNanoTime - before < TimeUnit.SECONDS.toNanos(1));
82
83 final String[] line2Parts = line2.split(" AND ");
84 assertEquals("Use dummy nano clock", line2Parts[2]);
85 assertEquals(String.valueOf(DUMMYNANOTIME), line2Parts[0]);
86 assertEquals(String.valueOf(DUMMYNANOTIME), line2Parts[1]);
87 }
88
89 }
2020 import java.io.IOException;
2121 import java.io.ObjectInputStream;
2222 import java.io.ObjectOutputStream;
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.Map;
2326
2427 import javax.xml.bind.DatatypeConverter;
2528
2629 import org.apache.logging.log4j.Level;
2730 import org.apache.logging.log4j.Marker;
31 import org.apache.logging.log4j.MarkerManager;
32 import org.apache.logging.log4j.ThreadContext;
33 import org.apache.logging.log4j.ThreadContext.ContextStack;
34 import org.apache.logging.log4j.core.LogEvent;
2835 import org.apache.logging.log4j.core.util.Clock;
2936 import org.apache.logging.log4j.core.util.ClockFactory;
3037 import org.apache.logging.log4j.core.util.ClockFactoryTest;
38 import org.apache.logging.log4j.core.util.DummyNanoClock;
3139 import org.apache.logging.log4j.message.Message;
40 import org.apache.logging.log4j.message.ObjectMessage;
3241 import org.apache.logging.log4j.message.SimpleMessage;
3342 import org.apache.logging.log4j.util.Strings;
3443 import org.junit.AfterClass;
6675
6776 @Test
6877 public void testJavaIoSerializable() throws Exception {
69 final Log4jLogEvent evt = new Log4jLogEvent("some.test", null, Strings.EMPTY, Level.INFO, new SimpleMessage(
70 "abc"), null);
78 final Log4jLogEvent evt = Log4jLogEvent.newBuilder() //
79 .setLoggerName("some.test") //
80 .setLoggerFqcn(Strings.EMPTY) //
81 .setLevel(Level.INFO) //
82 .setMessage(new SimpleMessage("abc")) //
83 .build();
7184
7285 final byte[] binary = serialize(evt);
7386 final Log4jLogEvent evt2 = deserialize(binary);
90103 @Test
91104 public void testJavaIoSerializableWithThrown() throws Exception {
92105 final Error thrown = new InternalError("test error");
93 final Log4jLogEvent evt = new Log4jLogEvent("some.test", null, Strings.EMPTY, Level.INFO, new SimpleMessage(
94 "abc"), thrown);
106 final Log4jLogEvent evt = Log4jLogEvent.newBuilder() //
107 .setLoggerName("some.test") //
108 .setLoggerFqcn(Strings.EMPTY) //
109 .setLevel(Level.INFO) //
110 .setMessage(new SimpleMessage("abc")) //
111 .setThrown(thrown) //
112 .build();
95113
96114 final byte[] binary = serialize(evt);
97115 final Log4jLogEvent evt2 = deserialize(binary);
173191
174192 @Test
175193 public void testNullLevelReplacedWithOFF() throws Exception {
176 final Marker marker = null;
177 final Throwable t = null;
178194 final Level NULL_LEVEL = null;
179 final Log4jLogEvent evt = new Log4jLogEvent("some.test", marker, Strings.EMPTY, NULL_LEVEL, new SimpleMessage(
180 "abc"), t);
195 final Log4jLogEvent evt = Log4jLogEvent.newBuilder().setLevel(NULL_LEVEL).build();
181196 assertEquals(Level.OFF, evt.getLevel());
182197 }
183198
184199 @Test
185200 public void testTimestampGeneratedByClock() {
186 final Marker marker = null;
187 final Throwable t = null;
188 final Level NULL_LEVEL = null;
189 final Log4jLogEvent evt = new Log4jLogEvent("some.test", marker, Strings.EMPTY, NULL_LEVEL, new SimpleMessage(
190 "abc"), t);
201 final LogEvent evt = Log4jLogEvent.newBuilder().build();
191202 assertEquals(FixedTimeClock.FIXED_TIME, evt.getTimeMillis());
192
203 }
204
205 @Test
206 public void testInitiallyDummyNanoClock() {
207 assertTrue(Log4jLogEvent.getNanoClock() instanceof DummyNanoClock);
208 assertEquals("initial dummy nanotime", 0, Log4jLogEvent.getNanoClock().nanoTime());
209 }
210
211 @Test
212 public void testNanoTimeGeneratedByNanoClock() {
213 Log4jLogEvent.setNanoClock(new DummyNanoClock(123));
214 verifyNanoTimeWithAllConstructors(123);
215 Log4jLogEvent.setNanoClock(new DummyNanoClock(87654));
216 verifyNanoTimeWithAllConstructors(87654);
217 }
218
219 @SuppressWarnings("deprecation")
220 private void verifyNanoTimeWithAllConstructors(long expected) {
221 assertEquals(expected, Log4jLogEvent.getNanoClock().nanoTime());
222
223 assertEquals("No-arg constructor", expected, new Log4jLogEvent().getNanoTime());
224 assertEquals("1-arg constructor", expected, new Log4jLogEvent(98).getNanoTime());
225 assertEquals("6-arg constructor", expected, new Log4jLogEvent("l", null, "a", null, null, null).getNanoTime());
226 assertEquals("7-arg constructor", expected, new Log4jLogEvent("l", null, "a", null, null, null, null)
227 .getNanoTime());
228 assertEquals("11-arg constructor", expected, new Log4jLogEvent("l", null, "a", null, null, null, null, null,
229 null, null, 0).getNanoTime());
230 assertEquals("12-arg factory method", expected, Log4jLogEvent.createEvent("l", null, "a", null, null, null,
231 null, null, null, null, null, 0).getNanoTime());
232 }
233
234 @Test
235 public void testBuilderCorrectlyCopiesAllEventAttributes() {
236 final Map<String, String> contextMap = new HashMap<String, String>();
237 contextMap.put("A", "B");
238 final ContextStack contextStack = ThreadContext.getImmutableStack();
239 final Exception exception = new Exception("test");
240 final Marker marker = MarkerManager.getMarker("EVENTTEST");
241 final Message message = new SimpleMessage("foo");
242 final StackTraceElement stackTraceElement = new StackTraceElement("A", "B", "file", 123);
243 final String fqcn = "qualified";
244 final String name = "Ceci n'est pas une pipe";
245 final String threadName = "threadName";
246 final Log4jLogEvent event = Log4jLogEvent.newBuilder() //
247 .setContextMap(contextMap) //
248 .setContextStack(contextStack) //
249 .setEndOfBatch(true) //
250 .setIncludeLocation(true) //
251 .setLevel(Level.FATAL) //
252 .setLoggerFqcn(fqcn) //
253 .setLoggerName(name) //
254 .setMarker(marker) //
255 .setMessage(message) //
256 .setNanoTime(1234567890L) //
257 .setSource(stackTraceElement) //
258 .setThreadName(threadName) //
259 .setThrown(exception) //
260 .setTimeMillis(987654321L)
261 .build();
262
263 assertSame(contextMap, event.getContextMap());
264 assertSame(contextStack, event.getContextStack());
265 assertEquals(true, event.isEndOfBatch());
266 assertEquals(true, event.isIncludeLocation());
267 assertSame(Level.FATAL, event.getLevel());
268 assertSame(fqcn, event.getLoggerFqcn());
269 assertSame(name, event.getLoggerName());
270 assertSame(marker, event.getMarker());
271 assertSame(message, event.getMessage());
272 assertEquals(1234567890L, event.getNanoTime());
273 assertSame(stackTraceElement, event.getSource());
274 assertSame(threadName, event.getThreadName());
275 assertSame(exception, event.getThrown());
276 assertEquals(987654321L, event.getTimeMillis());
277
278 LogEvent event2 = new Log4jLogEvent.Builder(event).build();
279 assertEquals("copy constructor builder", event2, event);
280 assertEquals("same hashCode", event2.hashCode(), event.hashCode());
281 }
282
283 @Test
284 public void testEquals() {
285 final Map<String, String> contextMap = new HashMap<String, String>();
286 contextMap.put("A", "B");
287 ThreadContext.push("first");
288 final ContextStack contextStack = ThreadContext.getImmutableStack();
289 final Exception exception = new Exception("test");
290 final Marker marker = MarkerManager.getMarker("EVENTTEST");
291 final Message message = new SimpleMessage("foo");
292 final StackTraceElement stackTraceElement = new StackTraceElement("A", "B", "file", 123);
293 final String fqcn = "qualified";
294 final String name = "Ceci n'est pas une pipe";
295 final String threadName = "threadName";
296 final Log4jLogEvent event = Log4jLogEvent.newBuilder() //
297 .setContextMap(contextMap) //
298 .setContextStack(contextStack) //
299 .setEndOfBatch(true) //
300 .setIncludeLocation(true) //
301 .setLevel(Level.FATAL) //
302 .setLoggerFqcn(fqcn) //
303 .setLoggerName(name) //
304 .setMarker(marker) //
305 .setMessage(message) //
306 .setNanoTime(1234567890L) //
307 .setSource(stackTraceElement) //
308 .setThreadName(threadName) //
309 .setThrown(exception) //
310 .setTimeMillis(987654321L)
311 .build();
312
313 assertSame(contextMap, event.getContextMap());
314 assertSame(contextStack, event.getContextStack());
315 assertEquals(true, event.isEndOfBatch());
316 assertEquals(true, event.isIncludeLocation());
317 assertSame(Level.FATAL, event.getLevel());
318 assertSame(fqcn, event.getLoggerFqcn());
319 assertSame(name, event.getLoggerName());
320 assertSame(marker, event.getMarker());
321 assertSame(message, event.getMessage());
322 assertEquals(1234567890L, event.getNanoTime());
323 assertSame(stackTraceElement, event.getSource());
324 assertSame(threadName, event.getThreadName());
325 assertSame(exception, event.getThrown());
326 assertEquals(987654321L, event.getTimeMillis());
327
328 final LogEvent event2 = builder(event).build();
329 assertEquals("copy constructor builder", event2, event);
330 assertEquals("same hashCode", event2.hashCode(), event.hashCode());
331
332 assertSame(contextMap, event2.getContextMap());
333 assertSame(contextStack, event2.getContextStack());
334 assertEquals(true, event2.isEndOfBatch());
335 assertEquals(true, event2.isIncludeLocation());
336 assertSame(Level.FATAL, event2.getLevel());
337 assertSame(fqcn, event2.getLoggerFqcn());
338 assertSame(name, event2.getLoggerName());
339 assertSame(marker, event2.getMarker());
340 assertSame(message, event2.getMessage());
341 assertEquals(1234567890L, event2.getNanoTime());
342 assertSame(stackTraceElement, event2.getSource());
343 assertSame(threadName, event2.getThreadName());
344 assertSame(exception, event2.getThrown());
345 assertEquals(987654321L, event2.getTimeMillis());
346
347 final Map<String, String> differentMap = Collections.emptyMap();
348 different("different contextMap", builder(event).setContextMap(differentMap), event);
349 different("null contextMap", builder(event).setContextMap(null), event);
350
351 ThreadContext.push("abc");
352 final ContextStack contextStack2 = ThreadContext.getImmutableStack();
353 different("different contextStack", builder(event).setContextStack(contextStack2), event);
354 different("null contextStack", builder(event).setContextStack(null), event);
355
356 different("different EndOfBatch", builder(event).setEndOfBatch(false), event);
357 different("different IncludeLocation", builder(event).setIncludeLocation(false), event);
358
359 different("different level", builder(event).setLevel(Level.INFO), event);
360 different("null level", builder(event).setLevel(null), event);
361
362 different("different fqcn", builder(event).setLoggerFqcn("different"), event);
363 different("null fqcn", builder(event).setLoggerFqcn(null), event);
364
365 different("different name", builder(event).setLoggerName("different"), event);
366 try { // TODO null logger name throws NPE in equals. Use Objects.requireNonNull in constructor?
367 different("null name", builder(event).setLoggerName(null), event);
368 fail("Expected NullPointerException");
369 } catch (NullPointerException ok) {
370 }
371
372 different("different marker", builder(event).setMarker(MarkerManager.getMarker("different")), event);
373 different("null marker", builder(event).setMarker(null), event);
374
375 different("different message", builder(event).setMessage(new ObjectMessage("different")), event);
376 try { // TODO null message throws NPE in equals(). Use Objects.requireNonNull in constructor?
377 different("null message", builder(event).setMessage(null), event);
378 fail("Expected NullPointerException");
379 } catch (NullPointerException ok) {
380 }
381
382 different("different nanoTime", builder(event).setNanoTime(135), event);
383 different("different milliTime", builder(event).setTimeMillis(137), event);
384
385 final StackTraceElement stack2 = new StackTraceElement("XXX", "YYY", "file", 123);
386 different("different source", builder(event).setSource(stack2), event);
387 different("null source", builder(event).setSource(null), event);
388
389 different("different threadname", builder(event).setThreadName("different"), event);
390 different("null threadname", builder(event).setThreadName(null), event);
391
392 different("different exception", builder(event).setThrown(new Error("Boo!")), event);
393 different("null exception", builder(event).setThrown(null), event);
394 }
395
396 private static Log4jLogEvent.Builder builder(LogEvent event) {
397 return new Log4jLogEvent.Builder(event);
398 }
399
400 private void different(String reason, Log4jLogEvent.Builder builder, LogEvent event) {
401 final LogEvent other = builder.build();
402 assertNotEquals(reason, other, event);
403 assertNotEquals(reason + " hashCode", other.hashCode(), event.hashCode());
193404 }
194405 }
1818 import static org.junit.Assert.assertArrayEquals;
1919 import static org.junit.Assert.assertEquals;
2020 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.assertTrue;
2122 import static org.junit.Assert.fail;
2223
2324 import java.io.ByteArrayInputStream;
144145
145146 assertEquals(proxy.getExtendedStackTraceAsString(), proxy2.getExtendedStackTraceAsString());
146147 }
148
149 @Test
150 public void testSerialization_getExtendedStackTraceAsStringWithNestedThrowableDepth1() throws Exception {
151 final Throwable throwable = new RuntimeException(new IllegalArgumentException("This is a test"));
152 testSerialization_getExtendedStackTraceAsStringWithNestedThrowable(throwable);
153 }
154
155 @Test
156 public void testSerialization_getExtendedStackTraceAsStringWithNestedThrowableDepth2() throws Exception {
157 final Throwable throwable = new RuntimeException(
158 new IllegalArgumentException("This is a test", new IOException("level 2")));
159 testSerialization_getExtendedStackTraceAsStringWithNestedThrowable(throwable);
160 }
161
162 @Test
163 public void testSerialization_getExtendedStackTraceAsStringWithNestedThrowableDepth3() throws Exception {
164 final Throwable throwable = new RuntimeException(new IllegalArgumentException("level 1",
165 new IOException("level 2", new IllegalStateException("level 3"))));
166 testSerialization_getExtendedStackTraceAsStringWithNestedThrowable(throwable);
167 }
168
169 private void testSerialization_getExtendedStackTraceAsStringWithNestedThrowable(final Throwable throwable) throws Exception {
170 final ThrowableProxy proxy = new ThrowableProxy(throwable);
171 final byte[] binary = serialize(proxy);
172 final ThrowableProxy proxy2 = deserialize(binary);
173
174 assertEquals(proxy.getExtendedStackTraceAsString(), proxy2.getExtendedStackTraceAsString());
175 }
147176
148177 @Test
149178 public void testSerializationWithUnknownThrowable() throws Exception {
169198
170199 @Test
171200 public void testStack() {
172 final Map<String, ThrowableProxy.CacheEntry> map = new HashMap<String, ThrowableProxy.CacheEntry>();
173 final Stack<Class<?>> stack = new Stack<Class<?>>();
201 final Map<String, ThrowableProxy.CacheEntry> map = new HashMap<>();
202 final Stack<Class<?>> stack = new Stack<>();
174203 final Throwable throwable = new IllegalStateException("This is a test");
175204 final ThrowableProxy proxy = new ThrowableProxy(throwable);
176205 final ExtendedStackTraceElement[] callerPackageData = proxy.toExtendedStackTrace(stack, map, null,
185214 */
186215 @Test
187216 public void testStackWithUnloadableClass() throws Exception {
188 final Stack<Class<?>> stack = new Stack<Class<?>>();
189 final Map<String, ThrowableProxy.CacheEntry> map = new HashMap<String, ThrowableProxy.CacheEntry>();
217 final Stack<Class<?>> stack = new Stack<>();
218 final Map<String, ThrowableProxy.CacheEntry> map = new HashMap<>();
190219
191220 final String runtimeExceptionThrownAtUnloadableClass_base64 = "rO0ABXNyABpqYXZhLmxhbmcuUnVudGltZUV4Y2VwdGlvbp5fBkcKNIPlAgAAeHIAE2phdmEubGFuZy5FeGNlcHRpb27Q/R8+GjscxAIAAHhyABNqYXZhLmxhbmcuVGhyb3dhYmxl1cY1Jzl3uMsDAANMAAVjYXVzZXQAFUxqYXZhL2xhbmcvVGhyb3dhYmxlO0wADWRldGFpbE1lc3NhZ2V0ABJMamF2YS9sYW5nL1N0cmluZztbAApzdGFja1RyYWNldAAeW0xqYXZhL2xhbmcvU3RhY2tUcmFjZUVsZW1lbnQ7eHBxAH4ABnB1cgAeW0xqYXZhLmxhbmcuU3RhY2tUcmFjZUVsZW1lbnQ7AkYqPDz9IjkCAAB4cAAAAAFzcgAbamF2YS5sYW5nLlN0YWNrVHJhY2VFbGVtZW50YQnFmiY23YUCAARJAApsaW5lTnVtYmVyTAAOZGVjbGFyaW5nQ2xhc3NxAH4ABEwACGZpbGVOYW1lcQB+AARMAAptZXRob2ROYW1lcQB+AAR4cAAAAAZ0ADxvcmcuYXBhY2hlLmxvZ2dpbmcubG9nNGouY29yZS5pbXBsLkZvcmNlTm9EZWZDbGFzc0ZvdW5kRXJyb3J0AB5Gb3JjZU5vRGVmQ2xhc3NGb3VuZEVycm9yLmphdmF0AARtYWlueA==";
192221 final byte[] binaryDecoded = DatatypeConverter
198227
199228 subject.toExtendedStackTrace(stack, map, null, throwable.getStackTrace());
200229 }
230
231 /**
232 * Tests LOG4J2-934.
233 */
234 @Test
235 public void testCircularSuppressedExceptions() {
236 final Exception e1 = new Exception();
237 final Exception e2 = new Exception();
238 e2.addSuppressed(e1);
239 e1.addSuppressed(e2);
240 LogManager.getLogger().error("Error", e1);
241 }
242
243 @Test
244 public void testSuppressedExceptions() {
245 final Exception e = new Exception("Root exception");
246 e.addSuppressed(new IOException("Suppressed #1"));
247 e.addSuppressed(new IOException("Suppressed #2"));
248 LogManager.getLogger().error("Error", e);
249 final ThrowableProxy proxy = new ThrowableProxy(e);
250 final String extendedStackTraceAsString = proxy.getExtendedStackTraceAsString();
251 assertTrue(extendedStackTraceAsString.contains("\tSuppressed: java.io.IOException: Suppressed #1"));
252 assertTrue(extendedStackTraceAsString.contains("\tSuppressed: java.io.IOException: Suppressed #1"));
253 }
254
255 @Test
256 public void testCauseSuppressedExceptions() {
257 final Exception cause = new Exception("Nested exception");
258 cause.addSuppressed(new IOException("Suppressed #1"));
259 cause.addSuppressed(new IOException("Suppressed #2"));
260 LogManager.getLogger().error("Error", new Exception(cause));
261 final ThrowableProxy proxy = new ThrowableProxy(new Exception("Root exception", cause));
262 final String extendedStackTraceAsString = proxy.getExtendedStackTraceAsString();
263 assertTrue(extendedStackTraceAsString.contains("\tSuppressed: java.io.IOException: Suppressed #1"));
264 assertTrue(extendedStackTraceAsString.contains("\tSuppressed: java.io.IOException: Suppressed #1"));
265 }
266
267 /**
268 * Tests LOG4J2-934.
269 */
270 @Test
271 public void testCircularSuppressedNestedException() {
272 final Exception e1 = new Exception();
273 final Exception e2 = new Exception(e1);
274 e2.addSuppressed(e1);
275 e1.addSuppressed(e2);
276 LogManager.getLogger().error("Error", e1);
277 }
278
279 /**
280 * .
281 */
282 @Test
283 public void testCircularCauseExceptions() {
284 final Exception e1 = new Exception();
285 final Exception e2 = new Exception(e1);
286 e1.initCause(e2);
287 LogManager.getLogger().error("Error", e1);
288 }
201289 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.layout;
17
18 import static org.junit.Assert.assertEquals;
19
20 import java.nio.charset.StandardCharsets;
21 import java.util.List;
22 import java.util.Map;
23
24 import org.apache.commons.csv.CSVFormat;
25 import org.apache.logging.log4j.Level;
26 import org.apache.logging.log4j.ThreadContext;
27 import org.apache.logging.log4j.core.Appender;
28 import org.apache.logging.log4j.core.BasicConfigurationFactory;
29 import org.apache.logging.log4j.core.Logger;
30 import org.apache.logging.log4j.core.LoggerContext;
31 import org.apache.logging.log4j.core.config.ConfigurationFactory;
32 import org.apache.logging.log4j.test.appender.ListAppender;
33 import org.junit.AfterClass;
34 import org.junit.Assert;
35 import org.junit.BeforeClass;
36 import org.junit.Test;
37
38 /**
39 * Tests {@link AbstractCsvLayout}.
40 *
41 * @since 2.4
42 */
43 public class CsvLogEventLayoutTest {
44 static ConfigurationFactory cf = new BasicConfigurationFactory();
45
46 @AfterClass
47 public static void cleanupClass() {
48 ConfigurationFactory.removeConfigurationFactory(cf);
49 ThreadContext.clearAll();
50 }
51
52 @BeforeClass
53 public static void setupClass() {
54 ThreadContext.clearAll();
55 ConfigurationFactory.setConfigurationFactory(cf);
56 final LoggerContext ctx = LoggerContext.getContext();
57 ctx.reconfigure();
58 }
59
60 private final LoggerContext ctx = LoggerContext.getContext();
61
62 private final Logger root = ctx.getLogger("");
63
64 @Test
65 public void testCustomCharset() {
66 final AbstractCsvLayout layout = CsvLogEventLayout.createLayout("Excel", null, null, null, null, null, null,
67 StandardCharsets.UTF_16, null, null);
68 assertEquals("text/csv; charset=UTF-16", layout.getContentType());
69 }
70
71 @Test
72 public void testDefaultCharset() {
73 final AbstractCsvLayout layout = CsvLogEventLayout.createDefaultLayout();
74 assertEquals(StandardCharsets.UTF_8, layout.getCharset());
75 }
76
77 @Test
78 public void testDefaultContentType() {
79 final AbstractCsvLayout layout = CsvLogEventLayout.createDefaultLayout();
80 assertEquals("text/csv; charset=UTF-8", layout.getContentType());
81 }
82
83 private void testLayout(final CSVFormat format) {
84 final AbstractCsvLayout layout = CsvLogEventLayout.createLayout(format);
85 final Map<String, Appender> appenders = root.getAppenders();
86 for (final Appender appender : appenders.values()) {
87 root.removeAppender(appender);
88 }
89 // set up appender
90 final ListAppender appender = new ListAppender("List", null, layout, true, false);
91 appender.start();
92
93 // set appender on root and set level to debug
94 root.addAppender(appender);
95 root.setLevel(Level.DEBUG);
96
97 root.debug("one={}, two={}, three={}", 1, 2, 3);
98 root.info("Hello");
99 appender.stop();
100
101 final List<String> list = appender.getMessages();
102 final String event0 = list.get(0);
103 final char del = format.getDelimiter();
104 Assert.assertTrue(event0, event0.contains(del + "DEBUG" + del));
105 final String quote = del == ',' ? "\"" : "";
106 Assert.assertTrue(event0, event0.contains(del + quote + "one=1, two=2, three=3" + quote + del));
107 final String event1 = list.get(1);
108 Assert.assertTrue(event1, event1.contains(del + "INFO" + del));
109 }
110
111 @Test
112 public void testLayoutDefault() throws Exception {
113 testLayout(CSVFormat.DEFAULT);
114 }
115
116 @Test
117 public void testLayoutExcel() throws Exception {
118 testLayout(CSVFormat.EXCEL);
119 }
120
121 @Test
122 public void testLayoutMySQL() throws Exception {
123 testLayout(CSVFormat.MYSQL);
124 }
125
126 @Test
127 public void testLayoutRFC4180() throws Exception {
128 testLayout(CSVFormat.RFC4180);
129 }
130
131 @Test
132 public void testLayoutTab() throws Exception {
133 testLayout(CSVFormat.TDF);
134 }
135 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.layout;
17
18 import static org.junit.Assert.assertEquals;
19
20 import java.nio.charset.StandardCharsets;
21 import java.util.List;
22 import java.util.Map;
23
24 import org.apache.commons.csv.CSVFormat;
25 import org.apache.logging.log4j.Level;
26 import org.apache.logging.log4j.ThreadContext;
27 import org.apache.logging.log4j.core.Appender;
28 import org.apache.logging.log4j.core.BasicConfigurationFactory;
29 import org.apache.logging.log4j.core.Logger;
30 import org.apache.logging.log4j.core.LoggerContext;
31 import org.apache.logging.log4j.core.config.ConfigurationFactory;
32 import org.apache.logging.log4j.message.ObjectArrayMessage;
33 import org.apache.logging.log4j.test.appender.ListAppender;
34 import org.junit.AfterClass;
35 import org.junit.Assert;
36 import org.junit.BeforeClass;
37 import org.junit.Test;
38
39 /**
40 * Tests {@link AbstractCsvLayout}.
41 *
42 * @since 2.4
43 */
44 public class CsvParameterLayoutTest {
45 static ConfigurationFactory cf = new BasicConfigurationFactory();
46
47 @AfterClass
48 public static void cleanupClass() {
49 ConfigurationFactory.removeConfigurationFactory(cf);
50 ThreadContext.clearAll();
51 }
52
53 @BeforeClass
54 public static void setupClass() {
55 ThreadContext.clearAll();
56 ConfigurationFactory.setConfigurationFactory(cf);
57 final LoggerContext ctx = LoggerContext.getContext();
58 ctx.reconfigure();
59 }
60
61 private final LoggerContext ctx = LoggerContext.getContext();
62
63 private final Logger root = ctx.getLogger("");
64
65 @Test
66 public void testCustomCharset() {
67 final AbstractCsvLayout layout = CsvParameterLayout.createLayout("Excel", null, null, null, null, null, null,
68 StandardCharsets.UTF_16, null, null);
69 assertEquals("text/csv; charset=UTF-16", layout.getContentType());
70 }
71
72 @Test
73 public void testDefaultCharset() {
74 final AbstractCsvLayout layout = CsvParameterLayout.createDefaultLayout();
75 assertEquals(StandardCharsets.UTF_8, layout.getCharset());
76 }
77
78 @Test
79 public void testDefaultContentType() {
80 final AbstractCsvLayout layout = CsvParameterLayout.createDefaultLayout();
81 assertEquals("text/csv; charset=UTF-8", layout.getContentType());
82 }
83
84 private void testLayoutNormalApi(final AbstractCsvLayout layout, boolean messageApi) throws Exception {
85 final Map<String, Appender> appenders = root.getAppenders();
86 for (final Appender appender : appenders.values()) {
87 root.removeAppender(appender);
88 }
89 // set up appender
90 final ListAppender appender = new ListAppender("List", null, layout, true, false);
91 appender.start();
92
93 // set appender on root and set level to debug
94 root.addAppender(appender);
95 root.setLevel(Level.DEBUG);
96
97 // output messages
98 if (messageApi) {
99 logDebugObjectArrayMessage();
100 } else {
101 logDebugNormalApi();
102 }
103
104 appender.stop();
105
106 final List<String> list = appender.getMessages();
107 final char d = layout.getFormat().getDelimiter();
108 Assert.assertEquals("1" + d + "2" + d + "3", list.get(0));
109 Assert.assertEquals("2" + d + "3", list.get(1));
110 Assert.assertEquals("5" + d + "6", list.get(2));
111 Assert.assertEquals("7" + d + "8" + d + "9" + d + "10", list.get(3));
112 }
113
114 private void logDebugNormalApi() {
115 root.debug(null, 1, 2, 3);
116 root.debug(null, 2, 3);
117 root.debug(null, 5, 6);
118 root.debug(null, 7, 8, 9, 10);
119 }
120
121 private void logDebugObjectArrayMessage() {
122 root.debug(new ObjectArrayMessage(1, 2, 3));
123 root.debug(new ObjectArrayMessage(2, 3));
124 root.debug(new ObjectArrayMessage(5, 6));
125 root.debug(new ObjectArrayMessage(7, 8, 9, 10));
126 }
127
128 @Test
129 public void testLayoutDefaultNormal() throws Exception {
130 testLayoutNormalApi(CsvParameterLayout.createDefaultLayout(), false);
131 }
132
133 @Test
134 public void testLayoutDefaultObjectArrayMessage() throws Exception {
135 testLayoutNormalApi(CsvParameterLayout.createDefaultLayout(), true);
136 }
137
138 @Test
139 public void testLayoutTab() throws Exception {
140 testLayoutNormalApi(CsvParameterLayout.createLayout(CSVFormat.TDF), true);
141 }
142 }
2626
2727 import org.apache.commons.io.IOUtils;
2828 import org.apache.logging.log4j.Level;
29 import org.apache.logging.log4j.LogManager;
3029 import org.apache.logging.log4j.ThreadContext;
3130 import org.apache.logging.log4j.core.Appender;
3231 import org.apache.logging.log4j.core.BasicConfigurationFactory;
6968 public static void setupClass() {
7069 ThreadContext.clearAll();
7170 ConfigurationFactory.setConfigurationFactory(configFactory);
72 final LoggerContext ctx = (LoggerContext) LogManager.getContext();
71 final LoggerContext ctx = LoggerContext.getContext();
7372 ctx.reconfigure();
7473 }
7574
76 LoggerContext ctx = (LoggerContext) LogManager.getContext();
75 LoggerContext ctx = LoggerContext.getContext();
7776
7877 Logger root = ctx.getLogger("");
7978
1515 */
1616 package org.apache.logging.log4j.core.layout;
1717
18 import java.nio.charset.StandardCharsets;
1819 import java.util.List;
1920 import java.util.Map;
2021
2122 import org.apache.logging.log4j.Level;
22 import org.apache.logging.log4j.LogManager;
2323 import org.apache.logging.log4j.ThreadContext;
2424 import org.apache.logging.log4j.core.Appender;
2525 import org.apache.logging.log4j.core.BasicConfigurationFactory;
2626 import org.apache.logging.log4j.core.Logger;
2727 import org.apache.logging.log4j.core.LoggerContext;
2828 import org.apache.logging.log4j.core.config.ConfigurationFactory;
29 import org.apache.logging.log4j.core.util.Charsets;
3029 import org.apache.logging.log4j.test.appender.ListAppender;
3130 import org.junit.AfterClass;
3231 import org.junit.BeforeClass;
3837 *
3938 */
4039 public class HtmlLayoutTest {
41 LoggerContext ctx = (LoggerContext) LogManager.getContext();
40 LoggerContext ctx = LoggerContext.getContext();
4241 Logger root = ctx.getLogger("");
4342
4443 static ConfigurationFactory cf = new BasicConfigurationFactory();
4746 public static void setupClass() {
4847 ThreadContext.clearAll();
4948 ConfigurationFactory.setConfigurationFactory(cf);
50 final LoggerContext ctx = (LoggerContext) LogManager.getContext();
49 final LoggerContext ctx = LoggerContext.getContext();
5150 ctx.reconfigure();
5251 }
5352
8079 @Test
8180 public void testDefaultCharset() {
8281 final HtmlLayout layout = HtmlLayout.createDefaultLayout();
83 assertEquals(Charsets.UTF_8, layout.getCharset());
82 assertEquals(StandardCharsets.UTF_8, layout.getCharset());
8483 }
8584
8685 /**
1515 */
1616 package org.apache.logging.log4j.core.layout;
1717
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertNull;
20 import static org.junit.Assert.assertTrue;
21
22 import java.nio.charset.StandardCharsets;
1823 import java.util.List;
1924 import java.util.Map;
2025
2126 import org.apache.logging.log4j.Level;
22 import org.apache.logging.log4j.LogManager;
2327 import org.apache.logging.log4j.ThreadContext;
2428 import org.apache.logging.log4j.core.Appender;
2529 import org.apache.logging.log4j.core.BasicConfigurationFactory;
2832 import org.apache.logging.log4j.core.config.ConfigurationFactory;
2933 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
3034 import org.apache.logging.log4j.core.jackson.Log4jJsonObjectMapper;
31 import org.apache.logging.log4j.core.util.Charsets;
32 import org.apache.logging.log4j.core.util.Throwables;
3335 import org.apache.logging.log4j.message.SimpleMessage;
3436 import org.apache.logging.log4j.spi.AbstractLogger;
3537 import org.apache.logging.log4j.test.appender.ListAppender;
38 import org.apache.logging.log4j.util.Strings;
3639 import org.junit.AfterClass;
3740 import org.junit.Assert;
3841 import org.junit.BeforeClass;
3942 import org.junit.Test;
40
41 import static org.junit.Assert.*;
4243
4344 /**
4445 * Tests the JsonLayout class.
5859 public static void setupClass() {
5960 ThreadContext.clearAll();
6061 ConfigurationFactory.setConfigurationFactory(cf);
61 final LoggerContext ctx = (LoggerContext) LogManager.getContext();
62 final LoggerContext ctx = LoggerContext.getContext();
6263 ctx.reconfigure();
6364 }
6465
65 LoggerContext ctx = (LoggerContext) LogManager.getContext();
66 LoggerContext ctx = LoggerContext.getContext();
6667
6768 Logger rootLogger = this.ctx.getLogger("");
6869
6970 private void checkAt(final String expected, final int lineIndex, final List<String> list) {
7071 final String trimedLine = list.get(lineIndex).trim();
71 assertTrue("Incorrect line index " + lineIndex + ": \"" + trimedLine + '"', trimedLine.equals(expected));
72 assertTrue("Incorrect line index " + lineIndex + ": " + Strings.dquote(trimedLine), trimedLine.equals(expected));
7273 }
7374
7475 private void checkContains(final String expected, final List<String> list) {
100101 assertTrue(str, str.contains(DQUOTE + name + DQUOTE + propSep));
101102 }
102103
103 private void testAllFeatures(final boolean includeSource, final boolean compact, boolean eventEol, final boolean includeContext)
104 private void testAllFeatures(final boolean includeSource, final boolean compact, final boolean eventEol, final boolean includeContext)
104105 throws Exception {
105106 final Log4jLogEvent expected = LogEventFixtures.createLogEvent();
106107 final AbstractJacksonLayout layout = JsonLayout.createLayout(includeSource,
107 includeContext, false, compact, eventEol, Charsets.UTF_8);
108 includeContext, false, compact, eventEol, StandardCharsets.UTF_8);
108109 final String str = layout.toSerializable(expected);
109110 // System.out.println(str);
110111 final String propSep = this.toPropertySeparator(compact);
141142 this.checkPropertyName("commonElementCount", compact, str);
142143 this.checkPropertyName("localizedMessage", compact, str);
143144 this.checkPropertyName("extendedStackTrace", compact, str);
144 if (Throwables.isGetSuppressedAvailable()) {
145 this.checkPropertyName("suppressed", compact, str);
146 }
145 this.checkPropertyName("suppressed", compact, str);
147146 this.checkPropertyName("loggerFqcn", compact, str);
148147 this.checkPropertyName("endOfBatch", compact, str);
149148 if (includeContext) {
167166 @Test
168167 public void testDefaultCharset() {
169168 final AbstractJacksonLayout layout = JsonLayout.createDefaultLayout();
170 assertEquals(Charsets.UTF_8, layout.getCharset());
169 assertEquals(StandardCharsets.UTF_8, layout.getCharset());
171170 }
172171
173172 @Test
251250
252251 @Test
253252 public void testLayoutLoggerName() throws Exception {
254 final AbstractJacksonLayout layout = JsonLayout.createLayout(false, false, false, true, false, Charsets.UTF_8);
255 final Log4jLogEvent expected = Log4jLogEvent.createEvent("a.B", null, "f.q.c.n", Level.DEBUG,
256 new SimpleMessage("M"), null, null, null, null, "threadName", null, 1);
253 final AbstractJacksonLayout layout = JsonLayout.createLayout(false, false, false, true, false, StandardCharsets.UTF_8);
254 final Log4jLogEvent expected = Log4jLogEvent.newBuilder() //
255 .setLoggerName("a.B") //
256 .setLoggerFqcn("f.q.c.n") //
257 .setLevel(Level.DEBUG) //
258 .setMessage(new SimpleMessage("M")) //
259 .setThreadName("threadName") //
260 .setTimeMillis(1).build();
257261 final String str = layout.toSerializable(expected);
258262 assertTrue(str, str.contains("\"loggerName\":\"a.B\""));
259263 final Log4jLogEvent actual = new Log4jJsonObjectMapper().readValue(str, Log4jLogEvent.class);
2626 import org.apache.logging.log4j.core.LogEvent;
2727 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
2828 import org.apache.logging.log4j.core.impl.ThrowableProxy;
29 import org.apache.logging.log4j.core.util.Throwables;
3029 import org.apache.logging.log4j.message.SimpleMessage;
3130 import org.apache.logging.log4j.spi.DefaultThreadContextStack;
3231
5352 sourceHelper.fillInStackTrace();
5453 final StackTraceElement source = sourceHelper.getStackTrace()[0];
5554 final IOException ioException = new IOException("testIOEx", cause);
56 Throwables.addSuppressed(ioException, new IndexOutOfBoundsException("I am suppressed exception 1"));
57 Throwables.addSuppressed(ioException, new IndexOutOfBoundsException("I am suppressed exception 2"));
55 ioException.addSuppressed(new IndexOutOfBoundsException("I am suppressed exception 1"));
56 ioException.addSuppressed(new IndexOutOfBoundsException("I am suppressed exception 2"));
5857 final ThrowableProxy throwableProxy = new ThrowableProxy(ioException);
59 final Map<String, String> contextMap = new HashMap<String, String>();
58 final Map<String, String> contextMap = new HashMap<>();
6059 contextMap.put("MDC.A", "A_Value");
6160 contextMap.put("MDC.B", "B_Value");
6261 final DefaultThreadContextStack contextStack = new DefaultThreadContextStack(true);
6362 contextStack.clear();
6463 contextStack.push("stack_msg1");
6564 contextStack.add("stack_msg2");
66 final Log4jLogEvent expected = Log4jLogEvent.createEvent("a.B", cMarker, "f.q.c.n", Level.DEBUG,
67 new SimpleMessage("Msg"), ioException, throwableProxy, contextMap, contextStack, "MyThreadName", source,
68 1);
65 final Log4jLogEvent expected = Log4jLogEvent.newBuilder() //
66 .setLoggerName("a.B") //
67 .setMarker(cMarker) //
68 .setLoggerFqcn("f.q.c.n") //
69 .setLevel(Level.DEBUG) //
70 .setMessage(new SimpleMessage("Msg")) //
71 .setThrown(ioException) //
72 .setThrownProxy(throwableProxy) //
73 .setContextMap(contextMap) //
74 .setContextStack(contextStack) //
75 .setThreadName("MyThreadName") //
76 .setSource(source) //
77 .setTimeMillis(1).build();
6978 // validate event?
7079 return expected;
7180 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.layout;
18
19 import java.util.List;
20
21 import org.apache.logging.log4j.Logger;
22 import org.apache.logging.log4j.core.appender.FileAppender;
23 import org.apache.logging.log4j.core.lookup.MainMapLookup;
24 import org.apache.logging.log4j.junit.LoggerContextRule;
25 import org.apache.logging.log4j.test.appender.ListAppender;
26 import org.junit.Assert;
27 import org.junit.ClassRule;
28 import org.junit.Test;
29
30 /**
31 * Tests LOG4j2-962.
32 */
33 public class PatternLayoutMainMapLookupTest {
34
35 static {
36 // Must be set before Log4j writes the header to the appenders.
37 MainMapLookup.setMainArguments("value0", "value1", "value2");
38 }
39
40 @ClassRule
41 public static LoggerContextRule context = new LoggerContextRule("log4j2-962.xml");
42
43 @Test
44 public void testFileName() {
45 FileAppender fileApp = (FileAppender) context.getRequiredAppender("File");
46 final String name = fileApp.getFileName();
47 Assert.assertEquals("target/value0.log", name);
48 }
49
50 @Test
51 public void testHeader() {
52 ListAppender listApp = context.getListAppender("List");
53 Logger logger = context.getLogger(this.getClass().getName());
54 logger.info("Hello World");
55 final List<String> messages = listApp.getMessages();
56 Assert.assertFalse(messages.isEmpty());
57 Assert.assertEquals("Header: value0", messages.get(0));
58 listApp.stop();
59 Assert.assertEquals("Footer: value1", messages.get(2));
60 }
61
62 }
1515 */
1616 package org.apache.logging.log4j.core.layout;
1717
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertNotNull;
20 import static org.junit.Assert.assertTrue;
21
1822 import java.nio.charset.Charset;
23 import java.nio.charset.StandardCharsets;
1924
2025 import org.apache.logging.log4j.Level;
21 import org.apache.logging.log4j.LogManager;
2226 import org.apache.logging.log4j.ThreadContext;
2327 import org.apache.logging.log4j.core.BasicConfigurationFactory;
2428 import org.apache.logging.log4j.core.LogEvent;
2630 import org.apache.logging.log4j.core.LoggerContext;
2731 import org.apache.logging.log4j.core.config.ConfigurationFactory;
2832 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
29 import org.apache.logging.log4j.core.util.Charsets;
33 import org.apache.logging.log4j.core.lookup.MainMapLookup;
3034 import org.apache.logging.log4j.message.SimpleMessage;
35 import org.apache.logging.log4j.util.Strings;
3136 import org.junit.After;
3237 import org.junit.BeforeClass;
3338 import org.junit.Test;
34
35 import static org.junit.Assert.*;
3639
3740 /**
3841 *
5154 @BeforeClass
5255 public static void setupClass() {
5356 ConfigurationFactory.setConfigurationFactory(cf);
54 final LoggerContext ctx = (LoggerContext) LogManager.getContext();
57 final LoggerContext ctx = LoggerContext.getContext();
5558 ctx.reconfigure();
5659 }
60
61 LoggerContext ctx = LoggerContext.getContext();
62
63 Logger root = ctx.getLogger("");
5764
5865 @After
5966 public void after() {
6067 ThreadContext.clearMap();
61
62 }
63
64 LoggerContext ctx = (LoggerContext) LogManager.getContext();
65
66 Logger root = ctx.getLogger("");
67
68 @Test
69 public void testMdcPattern1() throws Exception {
70 testMdcPattern("%m : %X", "Hello : {}", false);
71 }
72
73 @Test
74 public void testMdcPattern2() throws Exception {
75 testMdcPattern("%m : %X{key1}", "Hello : value1", true);
76 }
77
78 @Test
79 public void testMdcPattern3() throws Exception {
80 testMdcPattern("%m : %X{key2}", "Hello : value2", true);
81 }
82
83 @Test
84 public void testMdcPattern4() throws Exception {
85 testMdcPattern("%m : %X{key3}", "Hello : ", true);
86 }
87
88 @Test
89 public void testMdcPattern5() throws Exception {
90 testMdcPattern("%m : %X{key1}, %X{key2}, %X{key3}", "Hello : value1, value2, ", true);
91 }
92
93 private void testMdcPattern(final String patternStr, final String expectedStr, final boolean useThreadContext) throws Exception {
94 final PatternLayout layout = PatternLayout.newBuilder().withPattern(patternStr)
95 .withConfiguration(ctx.getConfiguration()).build();
96 if (useThreadContext) {
97 ThreadContext.put("key1", "value1");
98 ThreadContext.put("key2", "value2");
99 }
100 final LogEvent event = new Log4jLogEvent(this.getClass().getName(), null,
101 "org.apache.logging.log4j.core.Logger", Level.INFO, new SimpleMessage("Hello"), null);
102 final byte[] result = layout.toByteArray(event);
103 assertEquals(expectedStr, new String(result));
104 }
105
106 @Test
107 public void testRegex() throws Exception {
108 final PatternLayout layout = PatternLayout.newBuilder().withPattern(regexPattern)
109 .withConfiguration(ctx.getConfiguration()).build();
110 final LogEvent event = new Log4jLogEvent(this.getClass().getName(), null,
111 "org.apache.logging.log4j.core.Logger", Level.INFO, new SimpleMessage("Hello, world!"), null);
112 final byte[] result = layout.toByteArray(event);
113 assertEquals("org/apache/logging/log4j/core/layout/PatternLayoutTest Hello, world!", new String(result));
114 }
115
116 private void testUnixTime(final String pattern) throws Exception {
117 final PatternLayout layout = PatternLayout.newBuilder().withPattern(pattern + " %m")
118 .withConfiguration(ctx.getConfiguration()).build();
119 final LogEvent event1 = new Log4jLogEvent(this.getClass().getName(), null,
120 "org.apache.logging.log4j.core.Logger", Level.INFO, new SimpleMessage("Hello, world 1!"), null);
121 final byte[] result1 = layout.toByteArray(event1);
122 assertEquals(event1.getTimeMillis() + " Hello, world 1!", new String(result1));
123 // System.out.println("event1=" + event1.getMillis());
124 final LogEvent event2 = new Log4jLogEvent(this.getClass().getName(), null,
125 "org.apache.logging.log4j.core.Logger", Level.INFO, new SimpleMessage("Hello, world 2!"), null);
126 final byte[] result2 = layout.toByteArray(event2);
127 assertEquals(event2.getTimeMillis() + " Hello, world 2!", new String(result2));
128 // System.out.println("event2=" + event2.getMillis());
129 }
130
131 @Test
132 public void testUnixTime() throws Exception {
133 final PatternLayout layout = PatternLayout.newBuilder().withPattern("%d{UNIX} %m")
134 .withConfiguration(ctx.getConfiguration()).build();
135 final LogEvent event1 = new Log4jLogEvent(this.getClass().getName(), null,
136 "org.apache.logging.log4j.core.Logger", Level.INFO, new SimpleMessage("Hello, world 1!"), null);
137 final byte[] result1 = layout.toByteArray(event1);
138 assertEquals(event1.getTimeMillis() / 1000 + " Hello, world 1!", new String(result1));
139 // System.out.println("event1=" + event1.getTimeMillis() / 1000);
140 final LogEvent event2 = new Log4jLogEvent(this.getClass().getName(), null,
141 "org.apache.logging.log4j.core.Logger", Level.INFO, new SimpleMessage("Hello, world 2!"), null);
142 final byte[] result2 = layout.toByteArray(event2);
143 assertEquals(event2.getTimeMillis() / 1000 + " Hello, world 2!", new String(result2));
144 // System.out.println("event2=" + event2.getTimeMillis() / 1000);
145 }
146
147 @Test
148 public void testUnixTimeMillis() throws Exception {
149 final PatternLayout layout = PatternLayout.newBuilder().withPattern("%d{UNIX_MILLIS} %m")
150 .withConfiguration(ctx.getConfiguration()).build();
151 final LogEvent event1 = new Log4jLogEvent(this.getClass().getName(), null,
152 "org.apache.logging.log4j.core.Logger", Level.INFO, new SimpleMessage("Hello, world 1!"), null);
153 final byte[] result1 = layout.toByteArray(event1);
154 assertEquals(event1.getTimeMillis() + " Hello, world 1!", new String(result1));
155 // System.out.println("event1=" + event1.getTimeMillis());
156 final LogEvent event2 = new Log4jLogEvent(this.getClass().getName(), null,
157 "org.apache.logging.log4j.core.Logger", Level.INFO, new SimpleMessage("Hello, world 2!"), null);
158 final byte[] result2 = layout.toByteArray(event2);
159 assertEquals(event2.getTimeMillis() + " Hello, world 2!", new String(result2));
160 // System.out.println("event2=" + event2.getTimeMillis());
68 }
69
70 @Test
71 public void testHeaderFooterJavaLookup() throws Exception {
72 // % does not work here.
73 final String pattern = "%d{UNIX} MyApp%n${java:version}%n${java:runtime}%n${java:vm}%n${java:os}%n${java:hw}";
74 final PatternLayout layout = PatternLayout.newBuilder().withConfiguration(ctx.getConfiguration())
75 .withHeader("Header: " + pattern).withFooter("Footer: " + pattern).build();
76 final byte[] header = layout.getHeader();
77 assertNotNull("No header", header);
78 final String headerStr = new String(header);
79 assertTrue(headerStr, headerStr.contains("Header: "));
80 assertTrue(headerStr, headerStr.contains("Java version "));
81 assertTrue(headerStr, headerStr.contains("(build "));
82 assertTrue(headerStr, headerStr.contains(" from "));
83 assertTrue(headerStr, headerStr.contains(" architecture: "));
84 //
85 final byte[] footer = layout.getFooter();
86 assertNotNull("No footer", footer);
87 final String footerStr = new String(footer);
88 assertTrue(footerStr, footerStr.contains("Footer: "));
89 assertTrue(footerStr, footerStr.contains("Java version "));
90 assertTrue(footerStr, footerStr.contains("(build "));
91 assertTrue(footerStr, footerStr.contains(" from "));
92 assertTrue(footerStr, footerStr.contains(" architecture: "));
93 }
94
95 /**
96 * Tests LOG4J2-962.
97 */
98 @Test
99 public void testHeaderFooterMainLookup() {
100 MainMapLookup.setMainArguments("value0", "value1", "value2");
101 final PatternLayout layout = PatternLayout.newBuilder().withConfiguration(ctx.getConfiguration())
102 .withHeader("${main:0}").withFooter("${main:2}").build();
103 final byte[] header = layout.getHeader();
104 assertNotNull("No header", header);
105 final String headerStr = new String(header);
106 assertTrue(headerStr, headerStr.contains("value0"));
107 //
108 final byte[] footer = layout.getFooter();
109 assertNotNull("No footer", footer);
110 final String footerStr = new String(footer);
111 assertTrue(footerStr, footerStr.contains("value2"));
161112 }
162113
163114 @Test
169120 ThreadContext.put("footer", "Hello world Footer");
170121 final byte[] header = layout.getHeader();
171122 assertNotNull("No header", header);
172 assertTrue("expected \"Hello world Header\", actual \"" + new String(header) + '"',
123 assertTrue("expected \"Hello world Header\", actual " + Strings.dquote(new String(header)),
173124 new String(header).equals(new String("Hello world Header")));
174125 }
175126
176 @Test
177 public void testHeaderFooterJavaLookup() throws Exception {
178 // % does not work here.
179 final String pattern = "%d{UNIX} MyApp%n${java:version}%n${java:runtime}%n${java:vm}%n${java:os}%n${java:hw}";
180 final PatternLayout layout = PatternLayout.newBuilder().withConfiguration(ctx.getConfiguration())
181 .withHeader(pattern).withFooter(pattern).build();
182 final byte[] header = layout.getHeader();
183 assertNotNull("No header", header);
184 final String headerStr = new String(header);
185 assertTrue(headerStr, headerStr.contains("Java version "));
186 assertTrue(headerStr, headerStr.contains("(build "));
187 assertTrue(headerStr, headerStr.contains(" from "));
188 assertTrue(headerStr, headerStr.contains(" architecture: "));
189 //
190 final byte[] footer = layout.getFooter();
191 assertNotNull("No header", footer);
192 final String footerStr = new String(header);
193 assertTrue(footerStr, footerStr.contains("Java version "));
194 assertTrue(footerStr, footerStr.contains("(build "));
195 assertTrue(footerStr, footerStr.contains(" from "));
196 assertTrue(footerStr, footerStr.contains(" architecture: "));
127 private void testMdcPattern(final String patternStr, final String expectedStr, final boolean useThreadContext)
128 throws Exception {
129 final PatternLayout layout = PatternLayout.newBuilder().withPattern(patternStr)
130 .withConfiguration(ctx.getConfiguration()).build();
131 if (useThreadContext) {
132 ThreadContext.put("key1", "value1");
133 ThreadContext.put("key2", "value2");
134 }
135 final LogEvent event = Log4jLogEvent.newBuilder() //
136 .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
137 .setLevel(Level.INFO) //
138 .setMessage(new SimpleMessage("Hello")).build();
139 final byte[] result = layout.toByteArray(event);
140 assertEquals(expectedStr, new String(result));
141 }
142
143 @Test
144 public void testMdcPattern1() throws Exception {
145 testMdcPattern("%m : %X", "Hello : {}", false);
146 }
147
148 @Test
149 public void testMdcPattern2() throws Exception {
150 testMdcPattern("%m : %X{key1}", "Hello : value1", true);
151 }
152
153 @Test
154 public void testMdcPattern3() throws Exception {
155 testMdcPattern("%m : %X{key2}", "Hello : value2", true);
156 }
157
158 @Test
159 public void testMdcPattern4() throws Exception {
160 testMdcPattern("%m : %X{key3}", "Hello : ", true);
161 }
162
163 @Test
164 public void testMdcPattern5() throws Exception {
165 testMdcPattern("%m : %X{key1}, %X{key2}, %X{key3}", "Hello : value1, value2, ", true);
166 }
167
168 @Test
169 public void testRegex() throws Exception {
170 final PatternLayout layout = PatternLayout.newBuilder().withPattern(regexPattern)
171 .withConfiguration(ctx.getConfiguration()).build();
172 final LogEvent event = Log4jLogEvent.newBuilder() //
173 .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
174 .setLevel(Level.INFO) //
175 .setMessage(new SimpleMessage("Hello, world!")).build();
176 final byte[] result = layout.toByteArray(event);
177 assertEquals("org/apache/logging/log4j/core/layout/PatternLayoutTest Hello, world!", new String(result));
197178 }
198179
199180 @Test
200181 public void testSpecialChars() throws Exception {
201182 final PatternLayout layout = PatternLayout.newBuilder().withPattern("\\\\%level\\t%msg\\n\\t%logger\\r\\n\\f")
202183 .withConfiguration(ctx.getConfiguration()).build();
203 final LogEvent event = new Log4jLogEvent(this.getClass().getName(), null,
204 "org.apache.logging.log4j.core.Logger", Level.INFO, new SimpleMessage("Hello, world!"), null);
184 final LogEvent event = Log4jLogEvent.newBuilder() //
185 .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
186 .setLevel(Level.INFO) //
187 .setMessage(new SimpleMessage("Hello, world!")).build();
205188 final byte[] result = layout.toByteArray(event);
206189 assertEquals("\\INFO\tHello, world!\n\torg.apache.logging.log4j.core.layout.PatternLayoutTest\r\n\f",
207190 new String(result));
208191 }
209192
210193 @Test
194 public void testUnixTime() throws Exception {
195 final PatternLayout layout = PatternLayout.newBuilder().withPattern("%d{UNIX} %m")
196 .withConfiguration(ctx.getConfiguration()).build();
197 final LogEvent event1 = Log4jLogEvent.newBuilder() //
198 .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
199 .setLevel(Level.INFO) //
200 .setMessage(new SimpleMessage("Hello, world 1!")).build();
201 final byte[] result1 = layout.toByteArray(event1);
202 assertEquals(event1.getTimeMillis() / 1000 + " Hello, world 1!", new String(result1));
203 // System.out.println("event1=" + event1.getTimeMillis() / 1000);
204 final LogEvent event2 = Log4jLogEvent.newBuilder() //
205 .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
206 .setLevel(Level.INFO) //
207 .setMessage(new SimpleMessage("Hello, world 2!")).build();
208 final byte[] result2 = layout.toByteArray(event2);
209 assertEquals(event2.getTimeMillis() / 1000 + " Hello, world 2!", new String(result2));
210 // System.out.println("event2=" + event2.getTimeMillis() / 1000);
211 }
212
213 private void testUnixTime(final String pattern) throws Exception {
214 final PatternLayout layout = PatternLayout.newBuilder().withPattern(pattern + " %m")
215 .withConfiguration(ctx.getConfiguration()).build();
216 final LogEvent event1 = Log4jLogEvent.newBuilder() //
217 .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
218 .setLevel(Level.INFO) //
219 .setMessage(new SimpleMessage("Hello, world 1!")).build();
220 final byte[] result1 = layout.toByteArray(event1);
221 assertEquals(event1.getTimeMillis() + " Hello, world 1!", new String(result1));
222 // System.out.println("event1=" + event1.getMillis());
223 final LogEvent event2 = Log4jLogEvent.newBuilder() //
224 .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
225 .setLevel(Level.INFO) //
226 .setMessage(new SimpleMessage("Hello, world 2!")).build();
227 final byte[] result2 = layout.toByteArray(event2);
228 assertEquals(event2.getTimeMillis() + " Hello, world 2!", new String(result2));
229 // System.out.println("event2=" + event2.getMillis());
230 }
231
232 @Test
233 public void testUnixTimeMillis() throws Exception {
234 final PatternLayout layout = PatternLayout.newBuilder().withPattern("%d{UNIX_MILLIS} %m")
235 .withConfiguration(ctx.getConfiguration()).build();
236 final LogEvent event1 = Log4jLogEvent.newBuilder() //
237 .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
238 .setLevel(Level.INFO) //
239 .setMessage(new SimpleMessage("Hello, world 1!")).build();
240 final byte[] result1 = layout.toByteArray(event1);
241 assertEquals(event1.getTimeMillis() + " Hello, world 1!", new String(result1));
242 // System.out.println("event1=" + event1.getTimeMillis());
243 final LogEvent event2 = Log4jLogEvent.newBuilder() //
244 .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
245 .setLevel(Level.INFO) //
246 .setMessage(new SimpleMessage("Hello, world 2!")).build();
247 final byte[] result2 = layout.toByteArray(event2);
248 assertEquals(event2.getTimeMillis() + " Hello, world 2!", new String(result2));
249 // System.out.println("event2=" + event2.getTimeMillis());
250 }
251
252 @Test
211253 public void testUsePlatformDefaultIfNoCharset() throws Exception {
212254 final PatternLayout layout = PatternLayout.newBuilder().withPattern("%m")
213255 .withConfiguration(ctx.getConfiguration()).build();
217259 @Test
218260 public void testUseSpecifiedCharsetIfExists() throws Exception {
219261 final PatternLayout layout = PatternLayout.newBuilder().withPattern("%m")
220 .withConfiguration(ctx.getConfiguration()).withCharset(Charsets.UTF_8).build();
221 assertEquals(Charsets.UTF_8, layout.getCharset());
262 .withConfiguration(ctx.getConfiguration()).withCharset(StandardCharsets.UTF_8).build();
263 assertEquals(StandardCharsets.UTF_8, layout.getCharset());
222264 }
223265 }
2020 import java.util.Locale;
2121
2222 import org.apache.logging.log4j.Level;
23 import org.apache.logging.log4j.LogManager;
2423 import org.apache.logging.log4j.MarkerManager;
2524 import org.apache.logging.log4j.ThreadContext;
2625 import org.apache.logging.log4j.core.Appender;
4241 import static org.junit.Assert.*;
4342
4443 public class Rfc5424LayoutTest {
45 LoggerContext ctx = (LoggerContext) LogManager.getContext();
44 LoggerContext ctx = LoggerContext.getContext();
4645 Logger root = ctx.getLogger("");
4746
4847
6463 ThreadContext.clearAll();
6564 StatusLogger.getLogger().setLevel(Level.OFF);
6665 ConfigurationFactory.setConfigurationFactory(cf);
67 final LoggerContext ctx = (LoggerContext) LogManager.getContext();
66 final LoggerContext ctx = LoggerContext.getContext();
6867 ctx.reconfigure();
6968 }
7069
2525 import java.util.Map;
2626
2727 import org.apache.logging.log4j.Level;
28 import org.apache.logging.log4j.LogManager;
2928 import org.apache.logging.log4j.LoggingException;
3029 import org.apache.logging.log4j.ThreadContext;
3130 import org.apache.logging.log4j.core.Appender;
4847 */
4948 public class SerializedLayoutTest {
5049 private static final String DAT_PATH = "target/test-classes/serializedEvent.dat";
51 LoggerContext ctx = (LoggerContext) LogManager.getContext();
50 LoggerContext ctx = LoggerContext.getContext();
5251 Logger root = ctx.getLogger("");
5352
5453 static ConfigurationFactory cf = new BasicConfigurationFactory();
5756 public static void setupClass() {
5857 ThreadContext.clearAll();
5958 ConfigurationFactory.setConfigurationFactory(cf);
60 final LoggerContext ctx = (LoggerContext) LogManager.getContext();
59 final LoggerContext ctx = LoggerContext.getContext();
6160 ctx.reconfigure();
6261 }
6362
144143 public void testSerialization() throws Exception {
145144 final SerializedLayout layout = SerializedLayout.createLayout();
146145 final Throwable throwable = new LoggingException("Test");
147 final LogEvent event = new Log4jLogEvent(this.getClass().getName(), null,
148 "org.apache.logging.log4j.core.Logger", Level.INFO, new SimpleMessage("Hello, world!"), throwable);
146 final LogEvent event = Log4jLogEvent.newBuilder() //
147 .setLoggerName(this.getClass().getName()) //
148 .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
149 .setLevel(Level.INFO) //
150 .setMessage(new SimpleMessage("Hello, world!")) //
151 .setThrown(throwable) //
152 .build();
149153 final byte[] result = layout.toByteArray(event);
150154 assertNotNull(result);
151155 final FileOutputStream fos = new FileOutputStream(DAT_PATH);
159163 testSerialization();
160164 final File file = new File(DAT_PATH);
161165 final FileInputStream fis = new FileInputStream(file);
162 final ObjectInputStream ois = new ObjectInputStream(fis);
163 final LogEvent event = (LogEvent) ois.readObject();
164 assertNotNull(event);
166 try (final ObjectInputStream ois = new ObjectInputStream(fis) ) {
167 final LogEvent event = (LogEvent) ois.readObject();
168 assertNotNull(event);
169 }
165170 }
166171 }
1919 import java.util.Locale;
2020
2121 import org.apache.logging.log4j.Level;
22 import org.apache.logging.log4j.LogManager;
2322 import org.apache.logging.log4j.MarkerManager;
2423 import org.apache.logging.log4j.ThreadContext;
2524 import org.apache.logging.log4j.core.Appender;
4039 *
4140 */
4241 public class SyslogLayoutTest {
43 LoggerContext ctx = (LoggerContext) LogManager.getContext();
42 LoggerContext ctx = LoggerContext.getContext();
4443 Logger root = ctx.getLogger("");
4544
4645
5655 public static void setupClass() {
5756 ThreadContext.clearAll();
5857 ConfigurationFactory.setConfigurationFactory(cf);
59 final LoggerContext ctx = (LoggerContext) LogManager.getContext();
58 final LoggerContext ctx = LoggerContext.getContext();
6059 ctx.reconfigure();
6160 }
6261
1616 package org.apache.logging.log4j.core.layout;
1717
1818 import java.io.IOException;
19 import java.nio.charset.StandardCharsets;
1920 import java.util.List;
2021 import java.util.Map;
2122
2223 import org.apache.logging.log4j.Level;
23 import org.apache.logging.log4j.LogManager;
2424 import org.apache.logging.log4j.Marker;
2525 import org.apache.logging.log4j.MarkerManager;
2626 import org.apache.logging.log4j.ThreadContext;
3131 import org.apache.logging.log4j.core.config.ConfigurationFactory;
3232 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
3333 import org.apache.logging.log4j.core.jackson.Log4jXmlObjectMapper;
34 import org.apache.logging.log4j.core.util.Charsets;
35 import org.apache.logging.log4j.core.util.Throwables;
3634 import org.apache.logging.log4j.message.SimpleMessage;
3735 import org.apache.logging.log4j.spi.AbstractLogger;
3836 import org.apache.logging.log4j.test.appender.ListAppender;
6462 public static void setupClass() {
6563 ThreadContext.clearAll();
6664 ConfigurationFactory.setConfigurationFactory(cf);
67 final LoggerContext ctx = (LoggerContext) LogManager.getContext();
65 final LoggerContext ctx = LoggerContext.getContext();
6866 ctx.reconfigure();
6967 }
7068
71 LoggerContext ctx = (LoggerContext) LogManager.getContext();
69 LoggerContext ctx = LoggerContext.getContext();
7270
7371 Logger rootLogger = this.ctx.getLogger("");
7472
119117 private void testAllFeatures(final boolean includeSource, final boolean compact, final boolean includeContext) throws IOException,
120118 JsonParseException, JsonMappingException {
121119 final Log4jLogEvent expected = LogEventFixtures.createLogEvent();
122 final XmlLayout layout = XmlLayout.createLayout(includeSource, includeContext, false, compact, Charsets.UTF_8);
120 final XmlLayout layout = XmlLayout.createLayout(includeSource, includeContext, false, compact, StandardCharsets.UTF_8);
123121 final String str = layout.toSerializable(expected);
124122 // System.out.println(str);
125123 assertEquals(str, !compact, str.contains("\n"));
166164 this.checkAttributeName("message", compact, str);
167165 this.checkAttributeName("localizedMessage", compact, str);
168166 this.checkElementName("ExtendedStackTrace", compact, str, false, true);
169 if (Throwables.isGetSuppressedAvailable()) {
170 this.checkElementName("Suppressed", compact, str, false, true);
171 }
167 this.checkElementName("Suppressed", compact, str, false, true);
172168 this.checkAttributeName("loggerFqcn", compact, str);
173169 this.checkAttributeName("endOfBatch", compact, str);
174170 if (includeContext) {
192188 @Test
193189 public void testDefaultCharset() {
194190 final XmlLayout layout = XmlLayout.createDefaultLayout();
195 assertEquals(Charsets.UTF_8, layout.getCharset());
191 assertEquals(StandardCharsets.UTF_8, layout.getCharset());
196192 }
197193
198194 /**
255251 @Test
256252 public void testLayoutLoggerName() {
257253 final XmlLayout layout = XmlLayout.createLayout(false, true, true, false, null);
258 final Log4jLogEvent event = Log4jLogEvent.createEvent("a.B", null, "f.q.c.n", Level.DEBUG,
259 new SimpleMessage("M"), null, null, null, null, "threadName", null, 1);
254 final Log4jLogEvent event = Log4jLogEvent.newBuilder() //
255 .setLoggerName("a.B") //
256 .setLoggerFqcn("f.q.c.n") //
257 .setLevel(Level.DEBUG) //
258 .setMessage(new SimpleMessage("M")) //
259 .setThreadName("threadName") //
260 .setTimeMillis(1).build();
260261 final String str = layout.toSerializable(event);
261262 assertTrue(str, str.contains("loggerName=\"a.B\""));
262263 }
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16
17 -->
18 <Configuration status="DEBUG" name="TestCustomLevels">
19
20 <CustomLevels>
21 <CustomLevel name="DIAG" intLevel="350" />
22 <CustomLevel name="NOTICE" intLevel="450" />
23 <CustomLevel name="VERBOSE" intLevel="550" />
24 </CustomLevels>
25
26 <Appenders>
27 <Console name="STDOUT">
28 <PatternLayout pattern="%m%n"/>
29 </Console>
30 <List name="List1"/>
31 </Appenders>
32
33 <Loggers>
34 <Root level="DEBUG">
35 <AppenderRef ref="STDOUT"/>
36 <AppenderRef ref="List1"/>
37 </Root>
38 </Loggers>
39
40 </Configuration>
2020 import org.apache.logging.log4j.LogManager;
2121 import org.apache.logging.log4j.Logger;
2222 import org.apache.logging.log4j.ThreadContext;
23 import org.apache.logging.log4j.junit.InitialLoggerContext;
23 import org.apache.logging.log4j.junit.LoggerContextRule;
2424 import org.junit.Rule;
2525 import org.junit.Test;
2626 import org.junit.rules.RuleChain;
3838 private static final String TESTKEY = "TestKey";
3939 private static final String TESTVAL = "TestValue";
4040
41 private final InitialLoggerContext context = new InitialLoggerContext("ContextMapLookupTest.xml");
41 private final LoggerContextRule context = new LoggerContextRule("ContextMapLookupTest.xml");
4242
4343 @Rule
4444 public RuleChain chain = RuleChain.outerRule(new TestRule() {
6767
6868 @Test
6969 public void testLookup() {
70 final Map<String, String> map = new HashMap<String, String>();
70 final Map<String, String> map = new HashMap<>();
7171 map.put(TESTKEY, TESTVAL);
7272 final StrLookup lookup = new Interpolator(new MapLookup(map));
7373 ThreadContext.put(TESTKEY, TESTVAL);
0 /*
1 * Copyright 2015 Apache Software Foundation.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 package org.apache.logging.log4j.core.lookup;
16
17 import static org.apache.logging.log4j.core.lookup.Log4jLookup.KEY_CONFIG_LOCATION;
18 import static org.apache.logging.log4j.core.lookup.Log4jLookup.KEY_CONFIG_PARENT_LOCATION;
19 import static org.easymock.EasyMock.expect;
20 import static org.easymock.EasyMock.replay;
21 import static org.easymock.EasyMock.verify;
22 import static org.junit.Assert.assertEquals;
23
24 import java.net.URI;
25 import java.net.URISyntaxException;
26
27 import org.apache.logging.log4j.core.LoggerContext;
28 import org.apache.logging.log4j.core.impl.ContextAnchor;
29 import org.easymock.EasyMock;
30 import org.junit.After;
31 import org.junit.Before;
32 import org.junit.Test;
33
34 /**
35 *
36 */
37 public class Log4jLookupTest {
38
39 private LoggerContext mockCtx = null;
40
41 @Before
42 public void setup() throws URISyntaxException {
43 this.mockCtx = EasyMock.createMock(LoggerContext.class);
44 expect(mockCtx.getConfigLocation()).andReturn(new URI("/a/b/c/d/e/log4j2.xml"));
45 ContextAnchor.THREAD_CONTEXT.set(mockCtx);
46
47 replay(mockCtx);
48 }
49
50 @After
51 public void cleanup() {
52 verify(mockCtx);
53
54 ContextAnchor.THREAD_CONTEXT.set(null);
55 this.mockCtx = null;
56 }
57
58 @Test
59 public void lookupConfigLocation() {
60 final StrLookup log4jLookup = new Log4jLookup();
61 final String value = log4jLookup.lookup(KEY_CONFIG_LOCATION);
62 assertEquals("/a/b/c/d/e/log4j2.xml", value);
63 }
64
65 @Test
66 public void lookupConfigParentLocation() {
67 final StrLookup log4jLookup = new Log4jLookup();
68 final String value = log4jLookup.lookup(KEY_CONFIG_PARENT_LOCATION);
69 assertEquals("/a/b/c/d/e", value);
70 }
71 }
0 /*
1 * Copyright 2015 Apache Software Foundation.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 package org.apache.logging.log4j.core.lookup;
16
17 import static org.apache.logging.log4j.core.lookup.Log4jLookup.KEY_CONFIG_LOCATION;
18 import static org.apache.logging.log4j.core.lookup.Log4jLookup.KEY_CONFIG_PARENT_LOCATION;
19 import static org.easymock.EasyMock.expect;
20 import static org.easymock.EasyMock.replay;
21 import static org.easymock.EasyMock.verify;
22 import static org.junit.Assert.assertEquals;
23
24 import java.io.File;
25
26 import org.apache.logging.log4j.core.LoggerContext;
27 import org.apache.logging.log4j.core.impl.ContextAnchor;
28 import org.easymock.EasyMock;
29 import org.junit.After;
30 import org.junit.Before;
31 import org.junit.Test;
32
33 /**
34 *
35 */
36 public class Log4jLookupWithSpacesTest {
37
38 private LoggerContext mockCtx = null;
39
40 @Before
41 public void setup() {
42 this.mockCtx = EasyMock.createMock(LoggerContext.class);
43 expect(mockCtx.getConfigLocation()).andReturn(new File("/a a/b b/c c/d d/e e/log4j2 file.xml").toURI());
44 ContextAnchor.THREAD_CONTEXT.set(mockCtx);
45
46 replay(mockCtx);
47 }
48
49 @After
50 public void cleanup() {
51 verify(mockCtx);
52
53 ContextAnchor.THREAD_CONTEXT.set(null);
54 this.mockCtx = null;
55 }
56
57 @Test
58 public void lookupConfigLocation_withSpaces() {
59 final StrLookup log4jLookup = new Log4jLookup();
60 final String value = log4jLookup.lookup(KEY_CONFIG_LOCATION);
61 assertEquals(new File("/a a/b b/c c/d d/e e/log4j2 file.xml").toURI().getPath(), value);
62 }
63
64 @Test
65 public void lookupConfigParentLocation_withSpaces() {
66 final StrLookup log4jLookup = new Log4jLookup();
67 final String value = log4jLookup.lookup(KEY_CONFIG_PARENT_LOCATION);
68 assertEquals(new File("/a a/b b/c c/d d/e e").toURI().getPath(), value);
69 }
70 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.lookup;
17
18 import org.apache.logging.log4j.LogManager;
19 import org.apache.logging.log4j.core.LoggerContext;
20 import org.apache.logging.log4j.core.config.Configurator;
21
22 /**
23 * Tests {@link org.apache.logging.log4j.core.lookup.MainMapLookup#MAIN_SINGLETON} from the command line, not a real JUnit
24 * test.
25 *
26 * From an IDE or CLI: --file foo.txt
27 *
28 * @since 2.4
29 */
30 public class MainInputArgumentsLookupTest {
31
32 public static void main(final String[] args) {
33 MainMapLookup.setMainArguments(args);
34 final LoggerContext ctx = Configurator.initialize(MainInputArgumentsLookupTest.class.getName(),
35 "target/test-classes/log4j-lookup-main.xml");
36 try {
37 LogManager.getLogger().error("this is an error message");
38 } finally {
39 Configurator.shutdown(ctx);
40 }
41 }
42
43 }
3535
3636 @Test
3737 public void testMap() {
38 final HashMap<String, String> map = new HashMap<String, String>();
38 final HashMap<String, String> map = new HashMap<>();
3939 map.put("A", "B");
4040 final MapLookup lookup = new MapLookup(map);
4141 assertEquals(null, lookup.lookup(null));
5454 MapLookup.setMainArguments(new String[] {
5555 "--file",
5656 "foo.txt" });
57 final MapLookup lookup = MapLookup.MAIN_SINGLETON;
57 final MapLookup lookup = MainMapLookup.MAIN_SINGLETON;
5858 assertEquals(null, lookup.lookup(null));
5959 assertEquals(null, lookup.lookup("X"));
6060 assertEquals("--file", lookup.lookup("0"));
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.lookup;
17
18 import java.io.File;
19 import java.io.IOException;
20
21 import org.apache.commons.io.FileUtils;
22 import org.apache.logging.log4j.LogManager;
23 import org.apache.logging.log4j.Logger;
24 import org.apache.logging.log4j.Marker;
25 import org.apache.logging.log4j.MarkerManager;
26 import org.apache.logging.log4j.junit.LoggerContextRule;
27 import org.junit.Assert;
28 import org.junit.ClassRule;
29 import org.junit.Test;
30
31 /**
32 * Tests {@link MarkerLookup} with a configuration file.
33 *
34 * @since 2.4
35 */
36 public class MarkerLookupConfigTest {
37
38 @ClassRule
39 public static LoggerContextRule context = new LoggerContextRule("log4j-marker-lookup.yaml");
40 public static final Marker PAYLOAD = MarkerManager.getMarker("PAYLOAD");
41 private static final String PAYLOAD_LOG = "Message in payload.log";
42
43 public static final Marker PERFORMANCE = MarkerManager.getMarker("PERFORMANCE");
44
45 private static final String PERFORMANCE_LOG = "Message in performance.log";
46 public static final Marker SQL = MarkerManager.getMarker("SQL");
47 private static final String SQL_LOG = "Message in sql.log";
48
49 @Test
50 public void test() throws IOException {
51 final Logger logger = LogManager.getLogger();
52 logger.info(SQL, SQL_LOG);
53 logger.info(PAYLOAD, PAYLOAD_LOG);
54 logger.info(PERFORMANCE, PERFORMANCE_LOG);
55 {
56 final String log = FileUtils.readFileToString(new File("target/logs/sql.log"));
57 Assert.assertTrue(log.contains(SQL_LOG));
58 Assert.assertFalse(log.contains(PAYLOAD_LOG));
59 Assert.assertFalse(log.contains(PERFORMANCE_LOG));
60 }
61 {
62 final String log = FileUtils.readFileToString(new File("target/logs/payload.log"));
63 Assert.assertFalse(log.contains(SQL_LOG));
64 Assert.assertTrue(log.contains(PAYLOAD_LOG));
65 Assert.assertFalse(log.contains(PERFORMANCE_LOG));
66 }
67 {
68 final String log = FileUtils.readFileToString(new File("target/logs/performance.log"));
69 Assert.assertFalse(log.contains(SQL_LOG));
70 Assert.assertFalse(log.contains(PAYLOAD_LOG));
71 Assert.assertTrue(log.contains(PERFORMANCE_LOG));
72 }
73 }
74 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.lookup;
17
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertNull;
20
21 import org.apache.logging.log4j.Level;
22 import org.apache.logging.log4j.Marker;
23 import org.apache.logging.log4j.MarkerManager;
24 import org.apache.logging.log4j.core.LogEvent;
25 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
26 import org.apache.logging.log4j.message.SimpleMessage;
27 import org.junit.Test;
28
29 /**
30 * Tests {@link MarkerLookup}.
31 *
32 * @since 2.4
33 */
34 public class MarkerLookupTest {
35
36 private static final String ABSENT_MARKER_NAME = "NONE";
37 private final String markerName = "MarkerLookupTest";
38 private final StrLookup strLookup = new MarkerLookup();
39
40 @Test
41 public void testLookupEventExistant() {
42 final Marker marker = MarkerManager.getMarker(markerName);
43 final LogEvent event = Log4jLogEvent.newBuilder() //
44 .setLoggerName(this.getClass().getName()) //
45 .setMarker(marker) //
46 .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
47 .setLevel(Level.INFO) //
48 .setMessage(new SimpleMessage("Hello, world!")).build();
49 final String value = strLookup.lookup(event, marker.getName());
50 assertEquals(markerName, value);
51 }
52
53 @Test
54 public void testLookupEventNonExistant() {
55 final LogEvent event = Log4jLogEvent.newBuilder() //
56 .setLoggerName(this.getClass().getName()) //
57 .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
58 .setLevel(Level.INFO) //
59 .setMessage(new SimpleMessage("Hello, world!")).build();
60 final String value = strLookup.lookup(event, ABSENT_MARKER_NAME);
61 assertNull(value);
62 }
63
64 @Test
65 public void testLookupEventNonExistantKey() {
66 final Marker marker = MarkerManager.getMarker(markerName);
67 final LogEvent event = Log4jLogEvent.newBuilder() //
68 .setLoggerName(this.getClass().getName()) //
69 .setMarker(marker) //
70 .setLoggerFqcn("org.apache.logging.log4j.core.Logger") //
71 .setLevel(Level.INFO) //
72 .setMessage(new SimpleMessage("Hello, world!")).build();
73 final String value = strLookup.lookup(event, ABSENT_MARKER_NAME);
74 assertEquals(markerName, value);
75 }
76
77 @Test
78 public void testLookupEventNullNonExistant() {
79 final String value = strLookup.lookup(null, ABSENT_MARKER_NAME);
80 assertNull(value);
81 }
82
83 @Test
84 public void testLookupExistant() {
85 final String value = strLookup.lookup(MarkerManager.getMarker(markerName).getName());
86 assertEquals(markerName, value);
87 }
88
89 @Test
90 public void testLookupNonExistant() {
91 final String value = strLookup.lookup(ABSENT_MARKER_NAME);
92 assertNull(value);
93 }
94
95 }
4747
4848 @Test
4949 public void testLookup() {
50 final Map<String, String> map = new HashMap<String, String>();
50 final Map<String, String> map = new HashMap<>();
5151 map.put(TESTKEY, TESTVAL);
5252 final StrLookup lookup = new Interpolator(new MapLookup(map));
5353 final StrSubstitutor subst = new StrSubstitutor(lookup);
3535 @Test
3636 public void testLookup() {
3737 final Message msg = new StructuredDataMessage("Test", "This is a test", "Audit");
38 final LogEvent event = new Log4jLogEvent(null, null, null, Level.DEBUG, msg, null);
38 final LogEvent event = Log4jLogEvent.newBuilder().setLevel(Level.DEBUG).setMessage(msg).build();
3939 final StrLookup lookup = new StructuredDataLookup();
4040 String value = lookup.lookup(event, TESTKEY);
4141 assertEquals(TESTVAL, value);
2828
2929 import org.apache.logging.log4j.Logger;
3030 import org.apache.logging.log4j.core.appender.AppenderLoggingException;
31 import org.apache.logging.log4j.junit.InitialLoggerContext;
31 import org.apache.logging.log4j.junit.LoggerContextRule;
3232 import org.apache.logging.log4j.test.AvailablePortFinder;
3333 import org.junit.ClassRule;
3434 import org.junit.Ignore;
4343 private static final String CONFIG = "log4j-socket2.xml";
4444
4545 @ClassRule
46 public static InitialLoggerContext context = new InitialLoggerContext(CONFIG);
46 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
4747
4848 @Test
4949 public void testSocket() throws Exception {
2525 import org.apache.logging.log4j.Logger;
2626 import org.apache.logging.log4j.core.appender.AppenderLoggingException;
2727 import org.apache.logging.log4j.core.util.Constants;
28 import org.apache.logging.log4j.junit.InitialLoggerContext;
28 import org.apache.logging.log4j.junit.LoggerContextRule;
2929 import org.apache.logging.log4j.test.AvailablePortFinder;
3030 import org.junit.ClassRule;
3131 import org.junit.Ignore;
4646 "................................................................" + Constants.LINE_SEPARATOR;
4747
4848 @ClassRule
49 public static InitialLoggerContext context = new InitialLoggerContext(CONFIG);
49 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
5050
5151 @Test
5252 public void testReconnect() throws Exception {
5353
54 final List<String> list = new ArrayList<String>();
54 final List<String> list = new ArrayList<>();
5555 TestSocketServer server = new TestSocketServer(list);
5656 server.start();
5757 Thread.sleep(300);
2323
2424 import org.apache.logging.log4j.Logger;
2525 import org.apache.logging.log4j.core.appender.AppenderLoggingException;
26 import org.apache.logging.log4j.junit.InitialLoggerContext;
26 import org.apache.logging.log4j.junit.LoggerContextRule;
2727 import org.apache.logging.log4j.test.AvailablePortFinder;
2828 import org.junit.ClassRule;
2929 import org.junit.Ignore;
3838 private static final String CONFIG = "log4j-socket.xml";
3939
4040 @ClassRule
41 public static InitialLoggerContext context = new InitialLoggerContext(CONFIG);
41 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
4242
4343 @Test
4444 public void testConnect() throws Exception {
2525
2626 public MockSyslogServer(final int numberOfMessagesToReceive, final int port) {
2727 this.numberOfMessagesToReceive = numberOfMessagesToReceive;
28 this.messageList = new ArrayList<String>();
28 this.messageList = new ArrayList<>();
2929 this.port = port;
3030 }
3131
3232 public class MockTlsSyslogServer extends MockSyslogServer {
3333 private final SSLServerSocket serverSocket;
3434 private SSLSocket clientSocket;
35 private final List<String> messageList = new ArrayList<String>();
35 private final List<String> messageList = new ArrayList<>();
3636 private TlsSyslogInputStreamReaderBase syslogReader;
3737
3838 private TlsSyslogMessageFormat messageFormat = TlsSyslogMessageFormat.SYSLOG;
2222 import java.util.Map;
2323
2424 import org.apache.logging.log4j.Level;
25 import org.apache.logging.log4j.LogManager;
2625 import org.apache.logging.log4j.core.Appender;
2726 import org.apache.logging.log4j.core.Filter;
2827 import org.apache.logging.log4j.core.Layout;
6867 private static final String MESSAGE = "This is test message";
6968
7069 private static final String MESSAGE_2 = "This is test message 2";
71
70
71 private static final String MESSAGE_WITH_SPECIAL_CHARS = "{This}\n[is]\"n\"a\"\r\ntrue:\n\ttest,\nmessage";
72
7273 static final int PORT_NUM = AvailablePortFinder.getNextAvailable();
7374
7475 static final String PORT = String.valueOf(PORT_NUM);
7576
76 private final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
77 private final LoggerContext ctx = LoggerContext.getContext(false);
7778
7879 private final boolean expectLengthException;
7980
157158 testServer(m1, m2);
158159 }
159160 }
161
162
163 @Test
164 public void testMessagesWithSpecialChars() throws Exception {
165 testServer(MESSAGE_WITH_SPECIAL_CHARS);
166 }
167
160168
161169 private void testServer(final int size) throws Exception {
162170 final String[] messages = new String[size];
2020 import java.io.Serializable;
2121 import java.nio.charset.Charset;
2222
23 import org.apache.logging.log4j.LogManager;
2423 import org.apache.logging.log4j.core.Filter;
2524 import org.apache.logging.log4j.core.Layout;
2625 import org.apache.logging.log4j.core.LoggerContext;
5655
5756 @BeforeClass
5857 public static void setupClass() throws Exception {
59 ((LoggerContext) LogManager.getContext(false)).reconfigure();
58 (LoggerContext.getContext(false)).reconfigure();
6059 initServerSocketFactory();
6160 // Use a large buffer just to test the code, the UDP test uses a tiny buffer
62 server = new SecureTcpSocketServer<InputStream>(PORT_NUM, new XmlInputStreamLogEventBridge(1024 * 100,
61 server = new SecureTcpSocketServer<>(PORT_NUM, new XmlInputStreamLogEventBridge(1024 * 100,
6362 Charset.defaultCharset()), sslConfig);
6463 thread = server.startNewThread();
6564 }
1818 import java.io.IOException;
1919 import java.io.InputStream;
2020
21 import org.apache.logging.log4j.LogManager;
2221 import org.apache.logging.log4j.core.Layout;
2322 import org.apache.logging.log4j.core.LoggerContext;
2423 import org.junit.AfterClass;
3029
3130 @BeforeClass
3231 public static void setupClass() throws Exception {
33 ((LoggerContext) LogManager.getContext(false)).reconfigure();
32 (LoggerContext.getContext(false)).reconfigure();
3433 server = TcpSocketServer.createJsonSocketServer(PORT_NUM);
3534 thread = server.startNewThread();
3635 }
1919 import java.io.ObjectInputStream;
2020 import java.io.Serializable;
2121
22 import org.apache.logging.log4j.LogManager;
2322 import org.apache.logging.log4j.core.Layout;
2423 import org.apache.logging.log4j.core.LoggerContext;
2524 import org.junit.AfterClass;
3130
3231 @BeforeClass
3332 public static void setupClass() throws Exception {
34 ((LoggerContext) LogManager.getContext(false)).reconfigure();
33 (LoggerContext.getContext(false)).reconfigure();
3534 server = TcpSocketServer.createSerializedSocketServer(PORT_NUM);
3635 thread = server.startNewThread();
3736 }
1919 import java.io.InputStream;
2020 import java.nio.charset.Charset;
2121
22 import org.apache.logging.log4j.LogManager;
2322 import org.apache.logging.log4j.core.Layout;
2423 import org.apache.logging.log4j.core.LoggerContext;
2524 import org.junit.AfterClass;
3130
3231 @BeforeClass
3332 public static void setupClass() throws Exception {
34 ((LoggerContext) LogManager.getContext(false)).reconfigure();
33 (LoggerContext.getContext(false)).reconfigure();
3534 // Use a large buffer just to test the code, the UDP test uses a tiny buffer
36 server = new TcpSocketServer<InputStream>(PORT_NUM, new XmlInputStreamLogEventBridge(1024 * 100,
35 server = new TcpSocketServer<>(PORT_NUM, new XmlInputStreamLogEventBridge(1024 * 100,
3736 Charset.defaultCharset()));
3837 thread = server.startNewThread();
3938 }
1818 import java.io.InputStream;
1919 import java.io.Serializable;
2020
21 import org.apache.logging.log4j.LogManager;
2221 import org.apache.logging.log4j.core.Layout;
2322 import org.apache.logging.log4j.core.LoggerContext;
2423 import org.junit.AfterClass;
3029
3130 @BeforeClass
3231 public static void setupClass() throws Exception {
33 ((LoggerContext) LogManager.getContext(false)).reconfigure();
32 (LoggerContext.getContext(false)).reconfigure();
3433 server = UdpSocketServer.createJsonSocketServer(PORT_NUM);
3534 thread = server.startNewThread();
3635 }
1818 import java.io.ObjectInputStream;
1919 import java.io.Serializable;
2020
21 import org.apache.logging.log4j.LogManager;
2221 import org.apache.logging.log4j.core.Layout;
2322 import org.apache.logging.log4j.core.LoggerContext;
2423 import org.junit.AfterClass;
3029
3130 @BeforeClass
3231 public static void setupClass() throws Exception {
33 ((LoggerContext) LogManager.getContext(false)).reconfigure();
32 (LoggerContext.getContext(false)).reconfigure();
3433 server = UdpSocketServer.createSerializedSocketServer(PORT_NUM);
3534 thread = server.startNewThread();
3635 }
1919 import java.io.Serializable;
2020 import java.nio.charset.Charset;
2121
22 import org.apache.logging.log4j.LogManager;
2322 import org.apache.logging.log4j.core.Layout;
2423 import org.apache.logging.log4j.core.LoggerContext;
2524 import org.junit.AfterClass;
3130
3231 @BeforeClass
3332 public static void setupClass() throws Exception {
34 ((LoggerContext) LogManager.getContext(false)).reconfigure();
33 (LoggerContext.getContext(false)).reconfigure();
3534 // Use a tiny buffer just to test the code, the TCP test uses a large buffer
36 server = new UdpSocketServer<InputStream>(PORT_NUM, new XmlInputStreamLogEventBridge(100,
35 server = new UdpSocketServer<>(PORT_NUM, new XmlInputStreamLogEventBridge(100,
3736 Charset.defaultCharset()));
3837 thread = server.startNewThread();
3938 }
3232 public void emptyConfigurationDoesntCauseNullSSLSocketFactory() {
3333 final SslConfiguration sc = SslConfiguration.createSSLConfiguration(null, null, null);
3434 final SSLSocketFactory factory = sc.getSslSocketFactory();
35 Assert.assertTrue(factory != null);
35 Assert.assertNotNull(factory);
3636 }
3737
3838 @Test
4040 final SslConfiguration sc = SslConfiguration.createSSLConfiguration(null, null, null);
4141 final SSLSocketFactory factory = sc.getSslSocketFactory();
4242 final SSLSocket clientSocket = (SSLSocket) factory.createSocket(TLS_TEST_HOST, TLS_TEST_PORT);
43 Assert.assertTrue(true);
43 clientSocket.close();
44 Assert.assertNotNull(clientSocket);
4445 }
4546
46 @Test(expected = IOException.class)
47 @Test
4748 public void connectionFailsWithoutValidServerCertificate() throws IOException, StoreConfigurationException {
4849 final TrustStoreConfiguration tsc = new TrustStoreConfiguration(TestConstants.TRUSTSTORE_FILE, null, null, null);
4950 final SslConfiguration sc = SslConfiguration.createSSLConfiguration(null, null, tsc);
5051 final SSLSocketFactory factory = sc.getSslSocketFactory();
5152 final SSLSocket clientSocket = (SSLSocket) factory.createSocket(TLS_TEST_HOST, TLS_TEST_PORT);
52 final OutputStream os = clientSocket.getOutputStream();
53 os.write("GET config/login_verify2?".getBytes());
54 Assert.assertTrue(false);
53 try {
54 final OutputStream os = clientSocket.getOutputStream();
55 try {
56 os.write("GET config/login_verify2?".getBytes());
57 Assert.fail("Expected IOException");
58 } catch (final IOException e) {
59 // Expected, do nothing.
60 } finally {
61 os.close();
62 }
63 } finally {
64 clientSocket.close();
65 }
5566 }
5667
5768 @Test
5970 final KeyStoreConfiguration ksc = new KeyStoreConfiguration(TestConstants.KEYSTORE_FILE, null, null, null);
6071 final SslConfiguration sslConf = SslConfiguration.createSSLConfiguration(null, ksc, null);
6172 final SSLSocketFactory factory = sslConf.getSslSocketFactory();
62 Assert.assertTrue(true);
73 Assert.assertNotNull(factory);
6374 }
6475 }
2626 public void equalsWithNotNullValues() {
2727 final String location = "/to/the/file.jks";
2828 final String password = "changeit";
29 final StoreConfiguration<Object> a = new StoreConfiguration<Object>(location, password);
30 final StoreConfiguration<Object> b = new StoreConfiguration<Object>(location, password);
29 final StoreConfiguration<Object> a = new StoreConfiguration<>(location, password);
30 final StoreConfiguration<Object> b = new StoreConfiguration<>(location, password);
3131
3232 Assert.assertTrue(a.equals(b));
3333 Assert.assertTrue(b.equals(a));
3737 public void equalsWithNullAndNotNullValues() {
3838 final String location = "/to/the/file.jks";
3939 final String password = "changeit";
40 final StoreConfiguration<Object> a = new StoreConfiguration<Object>(location, password);
41 final StoreConfiguration<Object> b = new StoreConfiguration<Object>(null, null);
40 final StoreConfiguration<Object> a = new StoreConfiguration<>(location, password);
41 final StoreConfiguration<Object> b = new StoreConfiguration<>(null, null);
4242
4343 Assert.assertTrue(a.equals(b));
4444 Assert.assertTrue(b.equals(a));
4646
4747 @Test
4848 public void equalsWithNullValues() {
49 final StoreConfiguration<Object> a = new StoreConfiguration<Object>(null, null);
50 final StoreConfiguration<Object> b = new StoreConfiguration<Object>(null, null);
49 final StoreConfiguration<Object> a = new StoreConfiguration<>(null, null);
50 final StoreConfiguration<Object> b = new StoreConfiguration<>(null, null);
5151
5252 Assert.assertTrue(a.equals(b));
5353 Assert.assertTrue(b.equals(a));
8585
8686 private void calculateNextMessageLength() {
8787 final byte[] length = Arrays.copyOfRange(lengthBuffer, 0, position);
88 nextMessageLength = new Integer(new String(length));
88 nextMessageLength = Integer.parseInt(new String(length));
8989 }
9090 }
4242 }
4343
4444 private static ArrayList<String> generateMessages(final int numberOfMessages, final String charSet) {
45 final ArrayList<String> messageList = new ArrayList<String>(numberOfMessages);
45 final ArrayList<String> messageList = new ArrayList<>(numberOfMessages);
4646 for (int i = 0; i < numberOfMessages; i++) {
4747 final String message = createRandomMessage(charSet);
4848 messageList.add(message);
1818 import java.util.List;
1919
2020 import org.apache.logging.log4j.Logger;
21 import org.apache.logging.log4j.junit.InitialLoggerContext;
21 import org.apache.logging.log4j.junit.LoggerContextRule;
2222 import org.apache.logging.log4j.test.appender.ListAppender;
2323 import org.junit.ClassRule;
2424 import org.junit.Test;
2828 public class CallerInformationTest {
2929
3030 @ClassRule
31 public static InitialLoggerContext context = new InitialLoggerContext("log4j2-calling-class.xml");
31 public static LoggerContextRule context = new LoggerContextRule("log4j2-calling-class.xml");
3232
3333 @Test
3434 public void testClassLogger() throws Exception {
2020
2121 import org.apache.logging.log4j.core.AbstractLogEvent;
2222 import org.apache.logging.log4j.core.LogEvent;
23 import org.apache.logging.log4j.core.util.datetime.FixedDateFormat;
2324 import org.junit.Test;
2425
2526 import static org.junit.Assert.*;
2627
2728 public class DatePatternConverterTest {
2829
29 private static final String[] ISO8601_FORMAT = { DatePatternConverter.ISO8601_FORMAT };
30 /**
31 * SimpleTimePattern for DEFAULT.
32 */
33 private static final String DEFAULT_PATTERN = FixedDateFormat.FixedFormat.DEFAULT.getPattern();
34
35 /**
36 * ISO8601 string literal.
37 */
38 private static final String ISO8601_FORMAT = FixedDateFormat.FixedFormat.ISO8601.name();
39
40 private static final String[] ISO8601_FORMAT_OPTIONS = { ISO8601_FORMAT };
3041
3142 @Test
3243 public void testNewInstanceAllowsNullParameter() {
4758 @Test
4859 public void testFormatLogEventStringBuilderIso8601() {
4960 final LogEvent event = new MyLogEvent();
50 final DatePatternConverter converter = DatePatternConverter.newInstance(ISO8601_FORMAT);
61 final DatePatternConverter converter = DatePatternConverter.newInstance(ISO8601_FORMAT_OPTIONS);
5162 final StringBuilder sb = new StringBuilder();
5263 converter.format(event, sb);
5364
89100
90101 @Test
91102 public void testFormatDateStringBuilderIso8601() {
92 final DatePatternConverter converter = DatePatternConverter.newInstance(ISO8601_FORMAT);
103 final DatePatternConverter converter = DatePatternConverter.newInstance(ISO8601_FORMAT_OPTIONS);
93104 final StringBuilder sb = new StringBuilder();
94105 converter.format(date(2001, 1, 1), sb);
95106
96107 final String expected = "2001-02-01T14:15:16,123";
108 assertEquals(expected, sb.toString());
109 }
110
111 @Test
112 public void testFormatDateStringBuilderOriginalPattern() {
113 final String[] pattern = { "yyyy/MM/dd HH-mm-ss.SSS" };
114 final DatePatternConverter converter = DatePatternConverter.newInstance(pattern);
115 final StringBuilder sb = new StringBuilder();
116 converter.format(date(2001, 1, 1), sb);
117
118 final String expected = "2001/02/01 14-15-16.123";
97119 assertEquals(expected, sb.toString());
98120 }
99121
109131
110132 @Test
111133 public void testFormatStringBuilderObjectArrayIso8601() {
112 final DatePatternConverter converter = DatePatternConverter.newInstance(ISO8601_FORMAT);
134 final DatePatternConverter converter = DatePatternConverter.newInstance(ISO8601_FORMAT_OPTIONS);
113135 final StringBuilder sb = new StringBuilder();
114136 converter.format(sb, date(2001, 1, 1), date(2002, 2, 2), date(2003, 3, 3));
115137
125147 }
126148
127149 @Test
128 public void testGetPatternReturnsCorrectDefault() {
129 assertEquals(DatePatternConverter.DEFAULT_PATTERN, DatePatternConverter.newInstance(null).getPattern());
150 public void testGetPatternReturnsDefaultForNullOptions() {
151 assertEquals(DEFAULT_PATTERN, DatePatternConverter.newInstance(null).getPattern());
152 }
153
154 @Test
155 public void testGetPatternReturnsDefaultForEmptyOptionsArray() {
156 assertEquals(DEFAULT_PATTERN, DatePatternConverter.newInstance(new String[0]).getPattern());
157 }
158
159 @Test
160 public void testGetPatternReturnsDefaultForSingleNullElementOptionsArray() {
161 assertEquals(DEFAULT_PATTERN, DatePatternConverter.newInstance(new String[1]).getPattern());
162 }
163
164 @Test
165 public void testGetPatternReturnsDefaultForTwoNullElementsOptionsArray() {
166 assertEquals(DEFAULT_PATTERN, DatePatternConverter.newInstance(new String[2]).getPattern());
167 }
168
169 @Test
170 public void testGetPatternReturnsDefaultForInvalidPattern() {
171 final String[] invalid = { "ABC I am not a valid date pattern" };
172 assertEquals(DEFAULT_PATTERN, DatePatternConverter.newInstance(invalid).getPattern());
173 }
174
175 @Test
176 public void testGetPatternReturnsNullForUnix() {
177 final String[] options = { "UNIX" };
178 assertNull(DatePatternConverter.newInstance(options).getPattern());
179 }
180
181 @Test
182 public void testGetPatternReturnsNullForUnixMillis() {
183 final String[] options = { "UNIX_MILLIS" };
184 assertNull(DatePatternConverter.newInstance(options).getPattern());
130185 }
131186
132187 }
1616 package org.apache.logging.log4j.core.pattern;
1717
1818 import org.apache.logging.log4j.Level;
19 import org.apache.logging.log4j.LogManager;
2019 import org.apache.logging.log4j.core.LogEvent;
2120 import org.apache.logging.log4j.core.LoggerContext;
2221 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
3231
3332 @Test
3433 public void testReplacement() {
35 final LogEvent event = new Log4jLogEvent(EncodingPatternConverterTest.class.getName(), null, null, Level.DEBUG,
36 new SimpleMessage("Test \r\n<div class=\"test\">this</div> & <div class='test'>that</div>"), null);
34 final LogEvent event = Log4jLogEvent.newBuilder() //
35 .setLoggerName(EncodingPatternConverterTest.class.getName()) //
36 .setLevel(Level.DEBUG) //
37 .setMessage(new SimpleMessage("Test \r\n<div class=\"test\">this</div> & <div class='test'>that</div>"))
38 .build();
3739 final StringBuilder sb = new StringBuilder();
38 final LoggerContext ctx = (LoggerContext) LogManager.getContext();
40 final LoggerContext ctx = LoggerContext.getContext();
3941 final String[] options = new String[]{"%msg"};
4042 final EncodingPatternConverter converter = EncodingPatternConverter
4143 .newInstance(ctx.getConfiguration(), options);
1515 */
1616 package org.apache.logging.log4j.core.pattern;
1717
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertTrue;
20
1821 import java.io.PrintWriter;
1922 import java.io.StringWriter;
2023
2124 import org.apache.logging.log4j.Level;
2225 import org.apache.logging.log4j.core.LogEvent;
2326 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
27 import org.apache.logging.log4j.core.impl.ThrowableProxy;
2428 import org.apache.logging.log4j.message.SimpleMessage;
2529 import org.apache.logging.log4j.util.Strings;
2630 import org.junit.Test;
27
28 import static org.junit.Assert.*;
2931
3032 /**
3133 *
3335 public class ExtendedThrowablePatternConverterTest {
3436
3537 @Test
38 public void testDeserializedLogEventWithThrowableProxyButNoThrowable() {
39 final ExtendedThrowablePatternConverter converter = ExtendedThrowablePatternConverter.newInstance(null);
40 final Throwable originalThrowable = new Exception("something bad happened");
41 final ThrowableProxy throwableProxy = new ThrowableProxy(originalThrowable);
42 final Throwable deserializedThrowable = null;
43 final Log4jLogEvent event = Log4jLogEvent.newBuilder() //
44 .setLoggerName("testLogger") //
45 .setLoggerFqcn(this.getClass().getName()) //
46 .setLevel(Level.DEBUG) //
47 .setMessage(new SimpleMessage("")) //
48 .setThrown(deserializedThrowable) //
49 .setThrownProxy(throwableProxy) //
50 .setTimeMillis(0).build();
51 final StringBuilder sb = new StringBuilder();
52 converter.format(event, sb);
53 final String result = sb.toString();
54 assertTrue(result, result.contains(originalThrowable.getMessage()));
55 assertTrue(result, result.contains(originalThrowable.getStackTrace()[0].getMethodName()));
56 }
57
58 @Test
59 public void testFiltering() {
60 final String packages = "filters(org.junit, org.apache.maven, sun.reflect, java.lang.reflect)";
61 final String[] options = {packages};
62 final ExtendedThrowablePatternConverter converter = ExtendedThrowablePatternConverter.newInstance(options);
63 final Throwable cause = new NullPointerException("null pointer");
64 final Throwable parent = new IllegalArgumentException("IllegalArgument", cause);
65 final LogEvent event = Log4jLogEvent.newBuilder() //
66 .setLoggerName("testLogger") //
67 .setLoggerFqcn(this.getClass().getName()) //
68 .setLevel(Level.DEBUG) //
69 .setMessage(new SimpleMessage("test exception")) //
70 .setThrown(parent).build();
71 final StringBuilder sb = new StringBuilder();
72 converter.format(event, sb);
73 final String result = sb.toString();
74 assertTrue("No suppressed lines", result.contains(" suppressed "));
75 }
76
77 @Test
3678 public void testFull() {
3779 final ExtendedThrowablePatternConverter converter = ExtendedThrowablePatternConverter.newInstance(null);
3880 final Throwable cause = new NullPointerException("null pointer");
3981 final Throwable parent = new IllegalArgumentException("IllegalArgument", cause);
40 final LogEvent event = new Log4jLogEvent("testLogger", null, this.getClass().getName(), Level.DEBUG,
41 new SimpleMessage("test exception"), parent);
82 final LogEvent event = Log4jLogEvent.newBuilder() //
83 .setLoggerName("testLogger") //
84 .setLoggerFqcn(this.getClass().getName()) //
85 .setLevel(Level.DEBUG) //
86 .setMessage(new SimpleMessage("test exception")) //
87 .setThrown(parent).build();
4288 final StringBuilder sb = new StringBuilder();
4389 converter.format(event, sb);
4490 final StringWriter sw = new StringWriter();
4995 final String expected = sw.toString().replaceAll("\r", Strings.EMPTY);
5096 assertEquals(expected, result);
5197 }
52
53 @Test
54 public void testFiltering() {
55 final String packages = "filters(org.junit, org.apache.maven, sun.reflect, java.lang.reflect)";
56 final String[] options = {packages};
57 final ExtendedThrowablePatternConverter converter = ExtendedThrowablePatternConverter.newInstance(options);
58 final Throwable cause = new NullPointerException("null pointer");
59 final Throwable parent = new IllegalArgumentException("IllegalArgument", cause);
60 final LogEvent event = new Log4jLogEvent("testLogger", null, this.getClass().getName(), Level.DEBUG,
61 new SimpleMessage("test exception"), parent);
62 final StringBuilder sb = new StringBuilder();
63 converter.format(event, sb);
64 final String result = sb.toString();
65 assertTrue("No suppressed lines", result.contains(" suppressed "));
66 }
6798 }
1818 import java.util.List;
1919
2020 import org.apache.logging.log4j.Logger;
21 import org.apache.logging.log4j.junit.InitialLoggerContext;
21 import org.apache.logging.log4j.junit.LoggerContextRule;
2222 import org.apache.logging.log4j.test.appender.ListAppender;
2323 import org.junit.Before;
2424 import org.junit.ClassRule;
3333 private ListAppender app;
3434
3535 @ClassRule
36 public static InitialLoggerContext context = new InitialLoggerContext("log4j-throwablefilter.xml");
36 public static LoggerContextRule context = new LoggerContextRule("log4j-throwablefilter.xml");
3737
3838 @Before
3939 public void setUp() throws Exception {
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.pattern;
17
18 import static org.junit.Assert.assertEquals;
19
20 import org.junit.Test;
21
22 /**
23 * Testing FormattingInfo.
24 */
25 public class FormattingInfoTest {
26
27 @Test
28 public void testFormatTruncateFromBeginning() {
29 final StringBuilder message = new StringBuilder("Hello, world");
30
31 final FormattingInfo formattingInfo = new FormattingInfo(false, 0, 5, true);
32 formattingInfo.format(0, message);
33
34 assertEquals("world", message.toString());
35 }
36
37 @Test
38 public void testFormatTruncateFromEnd() {
39 final StringBuilder message = new StringBuilder("Hello, world");
40
41 final FormattingInfo formattingInfo = new FormattingInfo(false, 0, 5, false);
42 formattingInfo.format(0, message);
43
44 assertEquals("Hello", message.toString());
45 }
46
47 @Test
48 public void testFormatTruncateFromEndGivenFieldStart() {
49 final StringBuilder message = new StringBuilder("2015-03-09 11:49:28,295; INFO org.apache.logging.log4j.PatternParserTest");
50
51 final FormattingInfo formattingInfo = new FormattingInfo(false, 0, 5, false);
52 formattingInfo.format(31, message);
53
54 assertEquals("2015-03-09 11:49:28,295; INFO org.a", message.toString());
55 }
56 }
3131
3232 private void testLevelLength(final int length, final String debug, final String warn) {
3333 final Message msg = new SimpleMessage("Hello");
34 LogEvent event = new Log4jLogEvent("MyLogger", null, null, Level.DEBUG, msg, null);
34 LogEvent event = Log4jLogEvent.newBuilder() //
35 .setLoggerName("MyLogger") //
36 .setLevel(Level.DEBUG) //
37 .setMessage(msg).build();
3538 final StringBuilder sb = new StringBuilder();
3639 LevelPatternConverter converter = LevelPatternConverter.newInstance(null);
3740 converter.format(event, sb);
4144 sb.setLength(0);
4245 converter.format(event, sb);
4346 assertEquals(debug, sb.toString());
44 event = new Log4jLogEvent("MyLogger", null, null, Level.WARN, msg, null);
47 event = Log4jLogEvent.newBuilder() //
48 .setLoggerName("MyLogger") //
49 .setLevel(Level.WARN) //
50 .setMessage(msg).build();
4551 sb.setLength(0);
4652 converter.format(event, sb);
4753 assertEquals(warn, sb.toString());
7076 @Test
7177 public void testLevelLowerCase() {
7278 final Message msg = new SimpleMessage("Hello");
73 LogEvent event = new Log4jLogEvent("MyLogger", null, null, Level.DEBUG, msg, null);
79 LogEvent event = Log4jLogEvent.newBuilder() //
80 .setLoggerName("MyLogger") //
81 .setLevel(Level.DEBUG) //
82 .setMessage(msg).build();
7483 final StringBuilder sb = new StringBuilder();
7584 LevelPatternConverter converter = LevelPatternConverter.newInstance(null);
7685 converter.format(event, sb);
8089 sb.setLength(0);
8190 converter.format(event, sb);
8291 assertEquals("debug", sb.toString());
83 event = new Log4jLogEvent("MyLogger", null, null, Level.WARN, msg, null);
92 event = Log4jLogEvent.newBuilder() //
93 .setLoggerName("MyLogger") //
94 .setLevel(Level.WARN) //
95 .setMessage(msg).build();
8496 sb.setLength(0);
8597 converter.format(event, sb);
8698 assertEquals("warn", sb.toString());
89101 @Test
90102 public void testLevelMap() {
91103 final Message msg = new SimpleMessage("Hello");
92 LogEvent event = new Log4jLogEvent("MyLogger", null, null, Level.DEBUG, msg, null);
104 LogEvent event = Log4jLogEvent.newBuilder() //
105 .setLoggerName("MyLogger") //
106 .setLevel(Level.DEBUG) //
107 .setMessage(msg).build();
93108 final StringBuilder sb = new StringBuilder();
94109 LevelPatternConverter converter = LevelPatternConverter.newInstance(null);
95110 converter.format(event, sb);
99114 sb.setLength(0);
100115 converter.format(event, sb);
101116 assertEquals("Debug", sb.toString());
102 event = new Log4jLogEvent("MyLogger", null, null, Level.WARN, msg, null);
117 event = Log4jLogEvent.newBuilder() //
118 .setLoggerName("MyLogger") //
119 .setLevel(Level.WARN) //
120 .setMessage(msg).build();
103121 sb.setLength(0);
104122 converter.format(event, sb);
105123 assertEquals("Warning", sb.toString());
108126 @Test
109127 public void testLevelMapWithLength() {
110128 final Message msg = new SimpleMessage("Hello");
111 LogEvent event = new Log4jLogEvent("MyLogger", null, null, Level.DEBUG, msg, null);
129 LogEvent event = Log4jLogEvent.newBuilder() //
130 .setLoggerName("MyLogger") //
131 .setLevel(Level.DEBUG) //
132 .setMessage(msg).build();
112133 final StringBuilder sb = new StringBuilder();
113134 LevelPatternConverter converter = LevelPatternConverter.newInstance(null);
114135 converter.format(event, sb);
118139 sb.setLength(0);
119140 converter.format(event, sb);
120141 assertEquals("DE", sb.toString());
121 event = new Log4jLogEvent("MyLogger", null, null, Level.WARN, msg, null);
142 event = Log4jLogEvent.newBuilder() //
143 .setLoggerName("MyLogger") //
144 .setLevel(Level.WARN) //
145 .setMessage(msg).build();
122146 sb.setLength(0);
123147 converter.format(event, sb);
124148 assertEquals("Warning", sb.toString());
127151 @Test
128152 public void testLevelMapWithLengthAndLowerCase() {
129153 final Message msg = new SimpleMessage("Hello");
130 LogEvent event = new Log4jLogEvent("MyLogger", null, null, Level.DEBUG, msg, null);
154 LogEvent event = Log4jLogEvent.newBuilder() //
155 .setLoggerName("MyLogger") //
156 .setLevel(Level.DEBUG) //
157 .setMessage(msg).build();
131158 final StringBuilder sb = new StringBuilder();
132159 LevelPatternConverter converter = LevelPatternConverter.newInstance(null);
133160 converter.format(event, sb);
137164 sb.setLength(0);
138165 converter.format(event, sb);
139166 assertEquals("de", sb.toString());
140 event = new Log4jLogEvent("MyLogger", null, null, Level.WARN, msg, null);
167 event = Log4jLogEvent.newBuilder() //
168 .setLoggerName("MyLogger") //
169 .setLevel(Level.WARN) //
170 .setMessage(msg).build();
141171 sb.setLength(0);
142172 converter.format(event, sb);
143173 assertEquals("Warning", sb.toString());
3636 msg.put("verb", "love");
3737 msg.put("object", "Log4j");
3838 final MapPatternConverter converter = MapPatternConverter.newInstance(null);
39 final LogEvent event = new Log4jLogEvent("MyLogger", null, null, Level.DEBUG, msg, null);
39 final LogEvent event = Log4jLogEvent.newBuilder() //
40 .setLoggerName("MyLogger") //
41 .setLevel(Level.DEBUG) //
42 .setMessage(msg) //
43 .build();
4044 final StringBuilder sb = new StringBuilder();
4145 converter.format(event, sb);
4246 final String str = sb.toString();
5660 msg.put("verb", "love");
5761 msg.put("object", "Log4j");
5862 final MapPatternConverter converter = MapPatternConverter.newInstance(new String[] {"object"});
59 final LogEvent event = new Log4jLogEvent("MyLogger", null, null, Level.DEBUG, msg, null);
63 final LogEvent event = Log4jLogEvent.newBuilder() //
64 .setLoggerName("MyLogger") //
65 .setLevel(Level.DEBUG) //
66 .setMessage(msg) //
67 .build();
6068 final StringBuilder sb = new StringBuilder();
6169 converter.format(event, sb);
6270 final String str = sb.toString();
3737 final Message msg = new StructuredDataMessage("Test", "This is a test", "Audit");
3838 final Marker eventMarker = MarkerManager.getMarker("EVENT");
3939 final Marker auditMarker = MarkerManager.getMarker("AUDIT").setParents(eventMarker);
40 final LogEvent event = new Log4jLogEvent("MyLogger", auditMarker, null, Level.DEBUG, msg, null);
40 final LogEvent event = Log4jLogEvent.newBuilder().setLoggerName("MyLogger").setMarker(auditMarker)
41 .setLevel(Level.DEBUG).setMessage(msg).build();
4142 final StringBuilder sb = new StringBuilder();
4243 final MarkerPatternConverter converter = MarkerPatternConverter.newInstance(null);
4344 converter.format(event, sb);
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.pattern;
17
18 import org.apache.logging.log4j.Level;
19 import org.apache.logging.log4j.ThreadContext;
20 import org.apache.logging.log4j.core.LogEvent;
21 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
22 import org.apache.logging.log4j.message.Message;
23 import org.apache.logging.log4j.message.SimpleMessage;
24 import org.junit.Test;
25
26 import static org.junit.Assert.*;
27
28 /**
29 *
30 */
31 public class MdcPatternConverterTest {
32
33 @Test
34 public void testConverter() {
35
36 final Message msg = new SimpleMessage("Hello");
37 ThreadContext.put("subject", "I");
38 ThreadContext.put("verb", "love");
39 ThreadContext.put("object", "Log4j");
40 final MdcPatternConverter converter = MdcPatternConverter.newInstance(null);
41 final LogEvent event = Log4jLogEvent.newBuilder() //
42 .setLoggerName("MyLogger") //
43 .setLevel(Level.DEBUG) //
44 .setMessage(msg) //
45 .build();
46 final StringBuilder sb = new StringBuilder();
47 converter.format(event, sb);
48 final String str = sb.toString();
49 final String expected = "{object=Log4j, subject=I, verb=love}";
50 assertTrue("Incorrect result. Expected " + expected + ", actual " + str, str.equals(expected));
51 }
52
53 @Test
54 public void testConverterWithKey() {
55
56 final Message msg = new SimpleMessage("Hello");
57 final String [] options = new String[] {"object"};
58 ThreadContext.put("subject", "I");
59 ThreadContext.put("verb", "love");
60 ThreadContext.put("object", "Log4j");
61 final MdcPatternConverter converter = MdcPatternConverter.newInstance(options);
62 final LogEvent event = Log4jLogEvent.newBuilder() //
63 .setLoggerName("MyLogger") //
64 .setLevel(Level.DEBUG) //
65 .setMessage(msg) //
66 .build();
67 final StringBuilder sb = new StringBuilder();
68 converter.format(event, sb);
69 final String str = sb.toString();
70 final String expected = "Log4j";
71 assertEquals(expected, str);
72 }
73
74 @Test
75 public void testConverterWithKeys() {
76
77 final Message msg = new SimpleMessage("Hello");
78 final String [] options = new String[] {"object, subject"};
79 ThreadContext.put("subject", "I");
80 ThreadContext.put("verb", "love");
81 ThreadContext.put("object", "Log4j");
82 final MdcPatternConverter converter = MdcPatternConverter.newInstance(options);
83 final LogEvent event = Log4jLogEvent.newBuilder() //
84 .setLoggerName("MyLogger") //
85 .setLevel(Level.DEBUG) //
86 .setMessage(msg) //
87 .build();
88 final StringBuilder sb = new StringBuilder();
89 converter.format(event, sb);
90 final String str = sb.toString();
91 final String expected = "{object=Log4j, subject=I}";
92 assertEquals(expected, str);
93 }
94 }
95
3535 public void testPattern() throws Exception {
3636 final MessagePatternConverter converter = MessagePatternConverter.newInstance(null, null);
3737 Message msg = new SimpleMessage("Hello!");
38 LogEvent event = new Log4jLogEvent("MyLogger", null, null, Level.DEBUG, msg, null);
38 LogEvent event = Log4jLogEvent.newBuilder() //
39 .setLoggerName("MyLogger") //
40 .setLevel(Level.DEBUG) //
41 .setMessage(msg).build();
3942 StringBuilder sb = new StringBuilder();
4043 converter.format(event, sb);
4144 assertEquals("Unexpected result", "Hello!", sb.toString());
42 event = new Log4jLogEvent("MyLogger", null, null, Level.DEBUG, null, null);
45 event = Log4jLogEvent.newBuilder() //
46 .setLoggerName("MyLogger") //
47 .setLevel(Level.DEBUG) //
48 .setMessage(null).build();
4349 sb = new StringBuilder();
4450 converter.format(event, sb);
4551 assertEquals("Incorrect length: " + sb.length(), 0, sb.length());
4652 msg = new SimpleMessage(null);
47 event = new Log4jLogEvent("MyLogger", null, null, Level.DEBUG, msg, null);
53 event = Log4jLogEvent.newBuilder() //
54 .setLoggerName("MyLogger") //
55 .setLevel(Level.DEBUG) //
56 .setMessage(msg).build();
4857 sb = new StringBuilder();
4958 converter.format(event, sb);
5059 assertEquals("Incorrect length: " + sb.length(), 4, sb.length());
5665 final Configuration config = new DefaultConfiguration();
5766 final MessagePatternConverter converter = MessagePatternConverter.newInstance(config, null);
5867 Message msg = new SimpleMessage("Hello!");
59 LogEvent event = new Log4jLogEvent("MyLogger", null, null, Level.DEBUG, msg, null);
68 LogEvent event = Log4jLogEvent.newBuilder() //
69 .setLoggerName("MyLogger") //
70 .setLevel(Level.DEBUG) //
71 .setMessage(msg).build();
6072 StringBuilder sb = new StringBuilder();
6173 converter.format(event, sb);
6274 assertEquals("Unexpected result", "Hello!", sb.toString());
63 event = new Log4jLogEvent("MyLogger", null, null, Level.DEBUG, null, null);
75 event = Log4jLogEvent.newBuilder() //
76 .setLoggerName("MyLogger") //
77 .setLevel(Level.DEBUG) //
78 .setMessage(null).build();
6479 sb = new StringBuilder();
6580 converter.format(event, sb);
6681 assertEquals("Incorrect length: " + sb.length(), 0, sb.length());
6782 msg = new SimpleMessage(null);
68 event = new Log4jLogEvent("MyLogger", null, null, Level.DEBUG, msg, null);
83 event = Log4jLogEvent.newBuilder() //
84 .setLoggerName("MyLogger") //
85 .setLevel(Level.DEBUG) //
86 .setMessage(msg).build();
6987 sb = new StringBuilder();
7088 converter.format(event, sb);
7189 assertEquals("Incorrect length: " + sb.length(), 4, sb.length());
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.pattern;
17
18 import org.apache.logging.log4j.core.LogEvent;
19 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
20 import org.junit.Test;
21
22 import static org.junit.Assert.*;
23
24 /**
25 *
26 */
27 public class NanoTimePatternConverterTest {
28
29 @Test
30 public void testConverterAppendsLogEventNanoTimeToStringBuilder() {
31 final LogEvent event = Log4jLogEvent.newBuilder() //
32 .setNanoTime(1234567).build();
33 final StringBuilder sb = new StringBuilder();
34 final NanoTimePatternConverter converter = NanoTimePatternConverter.newInstance(null);
35 converter.format(event, sb);
36 assertEquals("1234567", sb.toString());
37 }
38 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.pattern;
17
18 import java.util.List;
19
20 import org.apache.logging.log4j.Logger;
21 import org.apache.logging.log4j.core.util.Constants;
22 import org.apache.logging.log4j.junit.LoggerContextRule;
23 import org.apache.logging.log4j.test.appender.ListAppender;
24 import org.junit.Before;
25 import org.junit.Rule;
26 import org.junit.Test;
27
28 import static org.junit.Assert.assertEquals;
29 import static org.junit.Assert.assertNotNull;
30 import static org.junit.Assert.assertTrue;
31
32 public class NoConsoleNoAnsiTest {
33
34 private static final String EXPECTED =
35 "ERROR LoggerTest o.a.l.l.c.p.NoConsoleNoAnsiTest org.apache.logging.log4j.core.pattern.NoConsoleNoAnsiTest"
36 + Constants.LINE_SEPARATOR;
37
38 @Rule
39 public LoggerContextRule init = new LoggerContextRule("log4j2-console-noConsoleNoAnsi.xml");
40
41 private Logger logger;
42 private ListAppender app;
43
44 @Before
45 public void setUp() throws Exception {
46 this.logger = this.init.getLogger("LoggerTest");
47 this.app = this.init.getListAppender("List").clear();
48 }
49
50 @Test
51 public void testReplacement() {
52 logger.error(this.getClass().getName());
53
54 final List<String> msgs = app.getMessages();
55 assertNotNull(msgs);
56 assertEquals("Incorrect number of messages. Should be 1 is " + msgs.size(), 1, msgs.size());
57 assertTrue("Replacement failed - expected ending " + EXPECTED + ", actual " + msgs.get(0), msgs.get(0).endsWith(EXPECTED));
58 }
59
60 }
2121 import java.util.Map;
2222
2323 import org.apache.logging.log4j.Level;
24 import org.apache.logging.log4j.LogManager;
2524 import org.apache.logging.log4j.MarkerManager;
2625 import org.apache.logging.log4j.core.LogEvent;
2726 import org.apache.logging.log4j.core.Logger;
2827 import org.apache.logging.log4j.core.LoggerContext;
2928 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
3029 import org.apache.logging.log4j.core.util.Constants;
30 import org.apache.logging.log4j.core.util.NanoClockFactory;
3131 import org.apache.logging.log4j.message.SimpleMessage;
3232 import org.junit.Before;
3333 import org.junit.Test;
4141
4242 static String OUTPUT_FILE = "output/PatternParser";
4343 static String WITNESS_FILE = "witness/PatternParser";
44 LoggerContext ctx = (LoggerContext) LogManager.getContext();
44 LoggerContext ctx = LoggerContext.getContext();
4545 Logger root = ctx.getLogger("");
4646
4747 private static String msgPattern = "%m%n";
5353
5454 private static String badPattern = "[%d{yyyyMMdd HH:mm:ss,SSS] %-5p [%c{10}] - %m%n";
5555 private static String customPattern = "[%d{yyyyMMdd HH:mm:ss,SSS}] %-5p [%-25.25c{1}:%-4L] - %m%n";
56 private static String patternTruncateFromEnd = "%d; %-5p %5.-5c %m%n";
57 private static String patternTruncateFromBeginning = "%d; %-5p %5.5c %m%n";
5658 private static String nestedPatternHighlight =
5759 "%highlight{%d{dd MMM yyyy HH:mm:ss,SSS}{GMT+0} [%t] %-5level: %msg%n%throwable}";
5860
8991 public void testCustomPattern() {
9092 final List<PatternFormatter> formatters = parser.parse(customPattern);
9193 assertNotNull(formatters);
92 final Map<String, String> mdc = new HashMap<String, String>();
94 final Map<String, String> mdc = new HashMap<>();
9395 mdc.put("loginId", "Fred");
9496 final Throwable t = new Throwable();
9597 final StackTraceElement[] elements = t.getStackTrace();
96 final LogEvent event = new Log4jLogEvent("org.apache.logging.log4j.PatternParserTest", MarkerManager.getMarker("TEST"),
97 Logger.class.getName(), Level.INFO, new SimpleMessage("Hello, world"), null,
98 mdc, null, "Thread1", elements[0], System.currentTimeMillis());
99 final StringBuilder buf = new StringBuilder();
100 for (final PatternFormatter formatter : formatters) {
101 formatter.format(event, buf);
102 }
103 final String str = buf.toString();
104 final String expected = "INFO [PatternParserTest :95 ] - Hello, world" + Constants.LINE_SEPARATOR;
98 final Log4jLogEvent event = Log4jLogEvent.newBuilder() //
99 .setLoggerName("org.apache.logging.log4j.PatternParserTest") //
100 .setMarker(MarkerManager.getMarker("TEST")) //
101 .setLoggerFqcn(Logger.class.getName()) //
102 .setLevel(Level.INFO) //
103 .setMessage(new SimpleMessage("Hello, world")) //
104 .setContextMap(mdc) //
105 .setThreadName("Thread1") //
106 .setSource(elements[0])
107 .setTimeMillis(System.currentTimeMillis()).build();
108 final StringBuilder buf = new StringBuilder();
109 for (final PatternFormatter formatter : formatters) {
110 formatter.format(event, buf);
111 }
112 final String str = buf.toString();
113 final String expected = "INFO [PatternParserTest :97 ] - Hello, world" + Constants.LINE_SEPARATOR;
105114 assertTrue("Expected to end with: " + expected + ". Actual: " + str, str.endsWith(expected));
106115 }
116
117 @Test
118 public void testPatternTruncateFromBeginning() {
119 final List<PatternFormatter> formatters = parser.parse(patternTruncateFromBeginning);
120 assertNotNull(formatters);
121 final LogEvent event = Log4jLogEvent.newBuilder() //
122 .setLoggerName("org.apache.logging.log4j.PatternParserTest") //
123 .setLoggerFqcn(Logger.class.getName()) //
124 .setLevel(Level.INFO) //
125 .setMessage(new SimpleMessage("Hello, world")) //
126 .setThreadName("Thread1") //
127 .setTimeMillis(System.currentTimeMillis()) //
128 .build();
129 final StringBuilder buf = new StringBuilder();
130 for (final PatternFormatter formatter : formatters) {
131 formatter.format(event, buf);
132 }
133 final String str = buf.toString();
134 final String expected = "INFO rTest Hello, world" + Constants.LINE_SEPARATOR;
135 assertTrue("Expected to end with: " + expected + ". Actual: " + str, str.endsWith(expected));
136 }
137
138 @Test
139 public void testPatternTruncateFromEnd() {
140 final List<PatternFormatter> formatters = parser.parse(patternTruncateFromEnd);
141 assertNotNull(formatters);
142 final LogEvent event = Log4jLogEvent.newBuilder() //
143 .setLoggerName("org.apache.logging.log4j.PatternParserTest") //
144 .setLoggerFqcn(Logger.class.getName()) //
145 .setLevel(Level.INFO) //
146 .setMessage(new SimpleMessage("Hello, world")) //
147 .setThreadName("Thread1") //
148 .setTimeMillis(System.currentTimeMillis()) //
149 .build();
150 final StringBuilder buf = new StringBuilder();
151 for (final PatternFormatter formatter : formatters) {
152 formatter.format(event, buf);
153 }
154 final String str = buf.toString();
155 final String expected = "INFO org.a Hello, world" + Constants.LINE_SEPARATOR;
156 assertTrue("Expected to end with: " + expected + ". Actual: " + str, str.endsWith(expected));
157 }
158
107159
108160 @Test
109161 public void testBadPattern() {
116168 assertNotNull(formatters);
117169 final Throwable t = new Throwable();
118170 final StackTraceElement[] elements = t.getStackTrace();
119 final LogEvent event = new Log4jLogEvent("a.b.c", null,
120 Logger.class.getName(), Level.INFO, new SimpleMessage("Hello, world"), null,
121 null, null, "Thread1", elements[0], timestamp);
171 final LogEvent event = Log4jLogEvent.newBuilder() //
172 .setLoggerName("a.b.c") //
173 .setLoggerFqcn(Logger.class.getName()) //
174 .setLevel(Level.INFO) //
175 .setMessage(new SimpleMessage("Hello, world")) //
176 .setThreadName("Thread1") //
177 .setSource(elements[0]) //
178 .setTimeMillis(timestamp) //
179 .build();
122180 final StringBuilder buf = new StringBuilder();
123181 for (final PatternFormatter formatter : formatters) {
124182 formatter.format(event, buf);
145203 assertNotNull(formatters);
146204 final Throwable t = new Throwable();
147205 final StackTraceElement[] stackTraceElement = t.getStackTrace();
148 final LogEvent event = new Log4jLogEvent("org.apache.logging.log4j.PatternParserTest",
149 MarkerManager.getMarker("TEST"), Logger.class.getName(), level, new SimpleMessage("Hello, world"),
150 null, null, null, "Thread1", /*stackTraceElement[0]*/null, System.currentTimeMillis());
206 final LogEvent event = Log4jLogEvent.newBuilder() //
207 .setLoggerName("org.apache.logging.log4j.PatternParserTest") //
208 .setMarker(MarkerManager.getMarker("TEST")) //
209 .setLoggerFqcn(Logger.class.getName()) //
210 .setLevel(level) //
211 .setMessage(new SimpleMessage("Hello, world")) //
212 .setThreadName("Thread1") //
213 .setSource(/*stackTraceElement[0]*/ null) //
214 .setTimeMillis(System.currentTimeMillis()) //
215 .build();
151216 final StringBuilder buf = new StringBuilder();
152217 for (final PatternFormatter formatter : formatters) {
153218 formatter.format(event, buf);
157222 assertTrue("Expected to start with: " + expectedStart + ". Actual: " + str, str.startsWith(expectedStart));
158223 assertTrue("Expected to end with: \"" + expectedEnd + "\". Actual: \"" + str, str.endsWith(expectedEnd));
159224 }
160
225
226 @Test
227 public void testNanoPatternShort() {
228 final List<PatternFormatter> formatters = parser.parse("%N");
229 assertNotNull(formatters);
230 assertEquals(1, formatters.size());
231 assertTrue(formatters.get(0).getConverter() instanceof NanoTimePatternConverter);
232 }
233
234 @Test
235 public void testNanoPatternLong() {
236 final List<PatternFormatter> formatters = parser.parse("%nano");
237 assertNotNull(formatters);
238 assertEquals(1, formatters.size());
239 assertTrue(formatters.get(0).getConverter() instanceof NanoTimePatternConverter);
240 }
241
242 @Test
243 public void testNanoPatternShortChangesNanoClockFactoryMode() {
244 parser.parse("%m");
245 assertEquals(NanoClockFactory.Mode.Dummy, NanoClockFactory.getMode());
246 parser.parse("%nano");
247 assertEquals(NanoClockFactory.Mode.System, NanoClockFactory.getMode());
248 }
249
250 @Test
251 public void testNanoPatternLongChangesNanoClockFactoryMode() {
252 parser.parse("%m");
253 assertEquals(NanoClockFactory.Mode.Dummy, NanoClockFactory.getMode());
254 parser.parse("%N");
255 assertEquals(NanoClockFactory.Mode.System, NanoClockFactory.getMode());
256 }
161257 }
5454 cal.set(Calendar.HOUR_OF_DAY, 13);
5555 cal.set(Calendar.MINUTE, 24);
5656 cal.set(Calendar.SECOND, 59);
57 parse(pattern, convert, buf, cal.getTime(), new Integer(3));
57 parse(pattern, convert, buf, cal.getTime(), 3);
5858
5959 assertEquals("13-24-59 \\t---", buf.toString());
6060 }
6161
6262 private void parse(final String pattern, final boolean convert, final StringBuilder buf, final Date date, final int i) {
6363 final PatternParser parser0 = new PatternParser(null, "Converter", null);
64 final List<PatternConverter> converters = new ArrayList<PatternConverter>();
65 final List<FormattingInfo> fields = new ArrayList<FormattingInfo>();
64 final List<PatternConverter> converters = new ArrayList<>();
65 final List<FormattingInfo> fields = new ArrayList<>();
6666 parser0.parse(pattern, converters, fields, false, convert);
6767 final FormattingInfo[] infoArray = new FormattingInfo[fields.size()];
6868 final FormattingInfo[] patternFields = fields.toArray(infoArray);
1616 package org.apache.logging.log4j.core.pattern;
1717
1818 import org.apache.logging.log4j.Level;
19 import org.apache.logging.log4j.LogManager;
2019 import org.apache.logging.log4j.ThreadContext;
2120 import org.apache.logging.log4j.core.LogEvent;
2221 import org.apache.logging.log4j.core.LoggerContext;
3534 @Test
3635 public void testReplacement() {
3736 ThreadContext.put("MyKey", "Apache");
38 final LogEvent event = new Log4jLogEvent(RegexReplacementConverterTest.class.getName(), null, null,
39 Level.DEBUG, new SimpleMessage("This is a test"), null);
37 final LogEvent event = Log4jLogEvent.newBuilder() //
38 .setLoggerName(RegexReplacementConverterTest.class.getName()) //
39 .setLevel(Level.DEBUG) //
40 .setMessage(new SimpleMessage("This is a test")) //
41 .build();
4042 final StringBuilder sb = new StringBuilder();
41 final LoggerContext ctx = (LoggerContext) LogManager.getContext();
43 final LoggerContext ctx = LoggerContext.getContext();
4244 final String[] options = new String[] {
4345 "%logger %msg%n", "\\.", "/"
4446 };
1919
2020 import org.apache.logging.log4j.ThreadContext;
2121 import org.apache.logging.log4j.core.util.Constants;
22 import org.apache.logging.log4j.junit.InitialLoggerContext;
22 import org.apache.logging.log4j.junit.LoggerContextRule;
2323 import org.apache.logging.log4j.test.appender.ListAppender;
2424 import org.junit.After;
2525 import org.junit.Before;
3939 private static final String EXPECTED = "/RegexReplacementTest" + Constants.LINE_SEPARATOR;
4040
4141 @ClassRule
42 public static InitialLoggerContext context = new InitialLoggerContext(CONFIG);
42 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
4343
4444 @Before
4545 public void setUp() throws Exception {
3333 final RootThrowablePatternConverter converter = RootThrowablePatternConverter.newInstance(null);
3434 final Throwable cause = new NullPointerException("null pointer");
3535 final Throwable parent = new IllegalArgumentException("IllegalArgument", cause);
36 final LogEvent event = new Log4jLogEvent("testLogger", null, this.getClass().getName(), Level.DEBUG,
37 new SimpleMessage("test exception"), parent);
36 final LogEvent event = Log4jLogEvent.newBuilder() //
37 .setLoggerName("testLogger") //
38 .setLoggerFqcn(this.getClass().getName()) //
39 .setLevel(Level.DEBUG) //
40 .setMessage(new SimpleMessage("test exception")) //
41 .setThrown(parent).build();
3842 final StringBuilder sb = new StringBuilder();
3943 converter.format(event, sb);
4044 final String result = sb.toString();
6165 } catch (final IllegalArgumentException e) {
6266 parent = e;
6367 }
64 final LogEvent event = new Log4jLogEvent("testLogger", null, this.getClass().getName(), Level.DEBUG,
65 new SimpleMessage("test exception"), parent);
68 final LogEvent event = Log4jLogEvent.newBuilder() //
69 .setLoggerName("testLogger") //
70 .setLoggerFqcn(this.getClass().getName()) //
71 .setLevel(Level.DEBUG) //
72 .setMessage(new SimpleMessage("test exception")) //
73 .setThrown(parent).build();
6674 final StringBuilder sb = new StringBuilder();
6775 converter.format(event, sb);
6876 final String result = sb.toString();
1818 import java.util.List;
1919
2020 import org.apache.logging.log4j.Logger;
21 import org.apache.logging.log4j.junit.InitialLoggerContext;
21 import org.apache.logging.log4j.junit.LoggerContextRule;
2222 import org.apache.logging.log4j.test.appender.ListAppender;
2323 import org.junit.Before;
2424 import org.junit.ClassRule;
3434 private static ListAppender app;
3535
3636 @ClassRule
37 public static InitialLoggerContext context = new InitialLoggerContext(CONFIG);
37 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
3838
3939 @Before
4040 public void setUp() throws Exception {
1919
2020 import org.apache.logging.log4j.Logger;
2121 import org.apache.logging.log4j.core.util.Constants;
22 import org.apache.logging.log4j.junit.InitialLoggerContext;
22 import org.apache.logging.log4j.junit.LoggerContextRule;
2323 import org.apache.logging.log4j.test.appender.ListAppender;
2424 import org.junit.Before;
2525 import org.junit.Rule;
3737 + Constants.LINE_SEPARATOR;
3838
3939 @Rule
40 public InitialLoggerContext init = new InitialLoggerContext("log4j-style.xml");
40 public LoggerContextRule init = new LoggerContextRule("log4j-style.xml");
4141
4242 private Logger logger;
4343 private ListAppender app;
5858 } catch (final IllegalArgumentException e) {
5959 parent = e;
6060 }
61 final LogEvent event = new Log4jLogEvent("testLogger", null, this.getClass().getName(), Level.DEBUG,
62 new SimpleMessage("test exception"), parent);
61 final LogEvent event = Log4jLogEvent.newBuilder() //
62 .setLoggerName("testLogger") //
63 .setLoggerFqcn(this.getClass().getName()) //
64 .setLevel(Level.DEBUG) //
65 .setMessage(new SimpleMessage("test exception")) //
66 .setThrown(parent).build();
6367 final StringBuilder sb = new StringBuilder();
6468 converter.format(event, sb);
6569 final String result = sb.toString();
7579 final ThrowablePatternConverter converter = ThrowablePatternConverter.newInstance(options);
7680 final Throwable cause = new NullPointerException("null pointer");
7781 final Throwable parent = new IllegalArgumentException("IllegalArgument", cause);
78 final LogEvent event = new Log4jLogEvent("testLogger", null, this.getClass().getName(), Level.DEBUG,
79 new SimpleMessage("test exception"), parent);
82 final LogEvent event = Log4jLogEvent.newBuilder() //
83 .setLoggerName("testLogger") //
84 .setLoggerFqcn(this.getClass().getName()) //
85 .setLevel(Level.DEBUG) //
86 .setMessage(new SimpleMessage("test exception")) //
87 .setThrown(parent).build();
8088 final StringBuilder sb = new StringBuilder();
8189 converter.format(event, sb);
8290 final String result = sb.toString();
8997 final ThrowablePatternConverter converter = ThrowablePatternConverter.newInstance(options);
9098 final Throwable cause = new NullPointerException("null pointer");
9199 final Throwable parent = new IllegalArgumentException("IllegalArgument", cause);
92 final LogEvent event = new Log4jLogEvent("testLogger", null, this.getClass().getName(), Level.DEBUG,
93 new SimpleMessage("test exception"), parent);
100 final LogEvent event = Log4jLogEvent.newBuilder() //
101 .setLoggerName("testLogger") //
102 .setLoggerFqcn(this.getClass().getName()) //
103 .setLevel(Level.DEBUG) //
104 .setMessage(new SimpleMessage("test exception")) //
105 .setThrown(parent).build();
94106 final StringBuilder sb = new StringBuilder();
95107 converter.format(event, sb);
96108 final String result = sb.toString();
106118 final StackTraceElement top = parent.getStackTrace()[0];
107119 final int expectedLineNumber = top.getLineNumber();
108120
109 final LogEvent event = new Log4jLogEvent("testLogger", null, this.getClass().getName(), Level.DEBUG,
110 new SimpleMessage("test exception"), parent);
121 final LogEvent event = Log4jLogEvent.newBuilder() //
122 .setLoggerName("testLogger") //
123 .setLoggerFqcn(this.getClass().getName()) //
124 .setLevel(Level.DEBUG) //
125 .setMessage(new SimpleMessage("test exception")) //
126 .setThrown(parent).build();
111127 final StringBuilder sb = new StringBuilder();
112128 converter.format(event, sb);
113129 final String result = sb.toString();
119135 final String[] options = { "short.localizedMessage" };
120136 final ThrowablePatternConverter converter = ThrowablePatternConverter.newInstance(options);
121137 final Throwable parent = new LocalizedException();
122 final LogEvent event = new Log4jLogEvent("testLogger", null, this.getClass().getName(), Level.DEBUG,
123 new SimpleMessage("test exception"), parent);
138 final LogEvent event = Log4jLogEvent.newBuilder() //
139 .setLoggerName("testLogger") //
140 .setLoggerFqcn(this.getClass().getName()) //
141 .setLevel(Level.DEBUG) //
142 .setMessage(new SimpleMessage("test exception")) //
143 .setThrown(parent).build();
124144 final StringBuilder sb = new StringBuilder();
125145 converter.format(event, sb);
126146 final String result = sb.toString();
133153 final ThrowablePatternConverter converter = ThrowablePatternConverter.newInstance(options);
134154 final Throwable cause = new NullPointerException("null pointer");
135155 final Throwable parent = new IllegalArgumentException("IllegalArgument", cause);
136 final LogEvent event = new Log4jLogEvent("testLogger", null, this.getClass().getName(), Level.DEBUG,
137 new SimpleMessage("test exception"), parent);
156 final LogEvent event = Log4jLogEvent.newBuilder() //
157 .setLoggerName("testLogger") //
158 .setLoggerFqcn(this.getClass().getName()) //
159 .setLevel(Level.DEBUG) //
160 .setMessage(new SimpleMessage("test exception")) //
161 .setThrown(parent).build();
138162 final StringBuilder sb = new StringBuilder();
139163 converter.format(event, sb);
140164 final String result = sb.toString();
147171 final ThrowablePatternConverter converter = ThrowablePatternConverter.newInstance(options);
148172 final Throwable cause = new NullPointerException("null pointer");
149173 final Throwable parent = new IllegalArgumentException("IllegalArgument", cause);
150 final LogEvent event = new Log4jLogEvent("testLogger", null, this.getClass().getName(), Level.DEBUG,
151 new SimpleMessage("test exception"), parent);
174 final LogEvent event = Log4jLogEvent.newBuilder() //
175 .setLoggerName("testLogger") //
176 .setLoggerFqcn(this.getClass().getName()) //
177 .setLevel(Level.DEBUG) //
178 .setMessage(new SimpleMessage("test exception")) //
179 .setThrown(parent).build();
152180 final StringBuilder sb = new StringBuilder();
153181 converter.format(event, sb);
154182 final String result = sb.toString();
1818 import java.util.List;
1919
2020 import org.apache.logging.log4j.Logger;
21 import org.apache.logging.log4j.junit.InitialLoggerContext;
21 import org.apache.logging.log4j.junit.LoggerContextRule;
2222 import org.apache.logging.log4j.test.appender.ListAppender;
2323 import org.junit.Before;
2424 import org.junit.ClassRule;
3434 private static ListAppender app;
3535
3636 @ClassRule
37 public static InitialLoggerContext context = new InitialLoggerContext(CONFIG);
37 public static LoggerContextRule context = new LoggerContextRule(CONFIG);
3838
3939 @Before
4040 public void setUp() throws Exception {
2121 import java.net.URL;
2222 import java.net.URLConnection;
2323
24 import org.apache.commons.io.IOUtils;
2425 import org.apache.logging.log4j.core.util.Closer;
2526 import org.apache.logging.log4j.core.util.Throwables;
2627 import org.apache.logging.log4j.util.LoaderUtil;
27 import sun.misc.IOUtils;
2828
2929 /**
3030 * ClassLoader that loads class in this package (or sub-package) by hand, otherwise delegating to the TCCL.
5656 final URLConnection uc = resource.openConnection();
5757 final int len = uc.getContentLength();
5858 final InputStream in = new BufferedInputStream(uc.getInputStream());
59 byte[] bytecode;
59 final byte[] bytecode = new byte[len];
6060 try {
61 // laziness means using sun.misc
62 bytecode = IOUtils.readFully(in, len, true);
61 IOUtils.readFully(in, bytecode);
6362 } finally {
6463 Closer.closeSilently(in);
6564 }
3636 import org.apache.logging.log4j.LogManager;
3737 import org.apache.logging.log4j.Marker;
3838 import org.apache.logging.log4j.TestLogger;
39 import org.apache.logging.log4j.core.tools.Generate;
4039 import org.apache.logging.log4j.message.Message;
4140 import org.apache.logging.log4j.message.MessageFactory;
41 import org.apache.logging.log4j.util.MessageSupplier;
42 import org.apache.logging.log4j.util.Supplier;
4243 import org.junit.BeforeClass;
4344 import org.junit.Test;
4445
6162 final String src = Generate.generateSource(CLASSNAME, levels, Generate.Type.CUSTOM);
6263 final File f = new File("target/test-classes/org/myorg/MyCustomLogger.java");
6364 f.getParentFile().mkdirs();
64 final FileOutputStream out = new FileOutputStream(f);
65 out.write(src.getBytes(Charset.defaultCharset()));
66 out.close();
65 try (final FileOutputStream out = new FileOutputStream(f)) {
66 out.write(src.getBytes(Charset.defaultCharset()));
67 }
6768
6869 // set up compiler
6970 final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
70 final DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
71 final StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
72 final Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(f));
71 final DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
72 final List<String> errors = new ArrayList<>();
73 try (final StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null)) {
74 final Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(Arrays
75 .asList(f));
7376
74 // compile generated source
75 compiler.getTask(null, fileManager, diagnostics, null, null, compilationUnits).call();
77 // compile generated source
78 compiler.getTask(null, fileManager, diagnostics, null, null, compilationUnits).call();
7679
77 // check we don't have any compilation errors
78 final List<String> errors = new ArrayList<String>();
79 for (final Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
80 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
81 errors.add(String.format("Compile error: %s%n", diagnostic.getMessage(Locale.getDefault())));
80 // check we don't have any compilation errors
81 for (final Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
82 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
83 errors.add(String.format("Compile error: %s%n", diagnostic.getMessage(Locale.getDefault())));
84 }
8285 }
8386 }
84 fileManager.close();
8587 assertTrue(errors.toString(), errors.isEmpty());
8688
8789 // load the compiled class
115117 cls.getDeclaredMethod(name, String.class, Throwable.class);
116118 cls.getDeclaredMethod(name, String.class, Object[].class);
117119 cls.getDeclaredMethod(name, Marker.class, String.class, Object[].class);
120
121 // 2.4 lambda support
122 cls.getDeclaredMethod(name, Marker.class, MessageSupplier.class);
123 cls.getDeclaredMethod(name, Marker.class, MessageSupplier.class, Throwable.class);
124 cls.getDeclaredMethod(name, Marker.class, String.class, Supplier[].class);
125 cls.getDeclaredMethod(name, Marker.class, Supplier.class);
126 cls.getDeclaredMethod(name, Marker.class, Supplier.class, Throwable.class);
127 cls.getDeclaredMethod(name, MessageSupplier.class);
128 cls.getDeclaredMethod(name, MessageSupplier.class, Throwable.class);
129 cls.getDeclaredMethod(name, String.class, Supplier[].class);
130 cls.getDeclaredMethod(name, Supplier.class);
131 cls.getDeclaredMethod(name, Supplier.class, Throwable.class);
118132 }
119133
120134 // now see if it actually works...
4040 import org.apache.logging.log4j.message.Message;
4141 import org.apache.logging.log4j.message.MessageFactory;
4242 import org.apache.logging.log4j.spi.ExtendedLogger;
43 import org.apache.logging.log4j.util.MessageSupplier;
44 import org.apache.logging.log4j.util.Supplier;
4345 import org.junit.BeforeClass;
4446 import org.junit.Test;
4547
6870
6971 // set up compiler
7072 final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
71 final DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
73 final DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
7274 final StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
7375 final Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(f));
7476
7678 compiler.getTask(null, fileManager, diagnostics, null, null, compilationUnits).call();
7779
7880 // check we don't have any compilation errors
79 final List<String> errors = new ArrayList<String>();
81 final List<String> errors = new ArrayList<>();
8082 for (final Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
8183 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
8284 errors.add(String.format("Compile error: %s%n", diagnostic.getMessage(Locale.getDefault())));
116118 cls.getDeclaredMethod(name, String.class, Throwable.class);
117119 cls.getDeclaredMethod(name, String.class, Object[].class);
118120 cls.getDeclaredMethod(name, Marker.class, String.class, Object[].class);
121
122 // 2.4 lambda support
123 cls.getDeclaredMethod(name, Marker.class, MessageSupplier.class);
124 cls.getDeclaredMethod(name, Marker.class, MessageSupplier.class, Throwable.class);
125 cls.getDeclaredMethod(name, Marker.class, String.class, Supplier[].class);
126 cls.getDeclaredMethod(name, Marker.class, Supplier.class);
127 cls.getDeclaredMethod(name, Marker.class, Supplier.class, Throwable.class);
128 cls.getDeclaredMethod(name, MessageSupplier.class);
129 cls.getDeclaredMethod(name, MessageSupplier.class, Throwable.class);
130 cls.getDeclaredMethod(name, String.class, Supplier[].class);
131 cls.getDeclaredMethod(name, Supplier.class);
132 cls.getDeclaredMethod(name, Supplier.class, Throwable.class);
119133 }
120134
121135 // now see if it actually works...
+0
-65
log4j-core/src/test/java/org/apache/logging/log4j/core/util/CharsetsTest.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.util;
18
19 import java.nio.charset.Charset;
20 import java.nio.charset.IllegalCharsetNameException;
21
22 import org.junit.Test;
23
24 import static org.junit.Assert.*;
25
26 public class CharsetsTest {
27
28 @Test
29 public void testReturnDefaultIfNameIsNull() {
30 final Charset actual = Charsets.getSupportedCharset(null);
31 assertSame(Charset.defaultCharset(), actual);
32 }
33
34 @Test
35 public void testReturnDefaultIfNameIsUnsupported() {
36 final Charset actual = Charsets.getSupportedCharset("INeedMoreSupport");
37 assertSame(Charset.defaultCharset(), actual);
38 }
39
40 @Test(expected = IllegalCharsetNameException.class)
41 public void testThrowsExceptionIfNameIsIllegal() {
42 final Charset actual = Charsets.getSupportedCharset("spaces not allowed");
43 assertSame(Charset.defaultCharset(), actual);
44 }
45
46 @Test
47 public void testReturnRequestedCharsetIfSupported() {
48 // See http://docs.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html
49 // for a list of required charsets.
50 final Charset actual1 = Charsets.getSupportedCharset("UTF-8");
51 assertSame(Charset.forName("UTF-8"), actual1);
52
53 final Charset actual2 = Charsets.getSupportedCharset("ISO-8859-1");
54 assertSame(Charset.forName("ISO-8859-1"), actual2);
55
56 // This part of the test is NOT portable across all Java platforms.
57 // There is no guarantee that KOI8-R is on any given platform
58 if (Charset.isSupported("KOI8-R")) {
59 final Charset actual3 = Charsets.getSupportedCharset("KOI8-R");
60 assertSame(Charset.forName("KOI8-R"), actual3);
61 }
62 }
63
64 }
3232 resetClock(AsyncLogger.class);
3333 }
3434
35 public static void resetClock(Class<?> clazz) throws IllegalAccessException {
35 public static void resetClock(final Class<?> clazz) throws IllegalAccessException {
3636 System.clearProperty(ClockFactory.PROPERTY_NAME);
37 Field field = FieldUtils.getField(clazz, "clock", true);
37 final Field field = FieldUtils.getField(clazz, "CLOCK", true);
3838 FieldUtils.removeFinalModifier(field, true);
3939 FieldUtils.writeStaticField(field, ClockFactory.getClock(), false);
4040 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.util;
18
19 import org.junit.Test;
20
21 import static org.junit.Assert.*;
22
23 /**
24 * Tests the DummyNanoClock.
25 */
26 public class DummyNanoClockTest {
27
28 @Test
29 public void testReturnsZeroByDefault() {
30 assertEquals(0, new DummyNanoClock().nanoTime());
31 }
32
33 @Test
34 public void testReturnsConstructorValue() {
35 assertEquals(123, new DummyNanoClock(123).nanoTime());
36 }
37
38 }
1616
1717 package org.apache.logging.log4j.core.util;
1818
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertNull;
23 import static org.junit.Assert.assertTrue;
24
1925 import java.io.File;
2026 import java.net.URI;
21 import java.net.URISyntaxException;
2227
2328 import org.junit.Test;
24
25 import static org.junit.Assert.*;
2629
2730 /**
2831 * Tests the FileUtils class.
2932 */
3033 public class FileUtilsTest {
3134
35 private static final String LOG4J_CONFIG_WITH_PLUS = "log4j+config+with+plus+characters.xml";
36
3237 @Test
3338 public void testFileFromUriWithPlusCharactersInName() throws Exception {
3439 final String config = "target/test-classes/log4j+config+with+plus+characters.xml";
3540 final URI uri = new URI(config);
3641 final File file = FileUtils.fileFromUri(uri);
37 assertEquals("log4j+config+with+plus+characters.xml", file.getName());
42 assertEquals(LOG4J_CONFIG_WITH_PLUS, file.getName());
3843 assertTrue("file exists", file.exists());
3944 }
4045
4146 @Test
42 public void testFileFromUriWithPlusCharactersConvertedToSpacesIfFileDoesNotExist()
43 throws Exception {
47 public void testFileFromUriWithSpacesAndPlusCharactersInName() throws Exception {
48 final String config = "target/test-classes/s%20p%20a%20c%20e%20s/log4j%2Bconfig%2Bwith%2Bplus%2Bcharacters.xml";
49 final URI uri = new URI(config);
50 final File file = FileUtils.fileFromUri(uri);
51 assertEquals(LOG4J_CONFIG_WITH_PLUS, file.getName());
52 assertTrue("file exists", file.exists());
53 }
54
55 /**
56 * Helps figure out why {@link #testFileFromUriWithPlusCharactersInName()} fails in Jenkins but asserting different
57 * parts of the implementation of {@link FileUtils#fileFromUri(URI)}.
58 */
59 @Test
60 public void testFileExistsWithPlusCharactersInName() throws Exception {
61 final String config = "target/test-classes/log4j+config+with+plus+characters.xml";
62 final File file = new File(config);
63 assertEquals(LOG4J_CONFIG_WITH_PLUS, file.getName());
64 assertTrue("file exists", file.exists());
65 //
66 final URI uri1 = new URI(config);
67 assertNull(uri1.getScheme());
68 //
69 final URI uri2 = new File(uri1.getPath()).toURI();
70 assertNotNull(uri2);
71 assertTrue("URI \"" + uri2 + "\" does not end with \"" + LOG4J_CONFIG_WITH_PLUS + "\"", uri2.toString()
72 .endsWith(LOG4J_CONFIG_WITH_PLUS));
73 //
74 final String fileName = uri2.toURL().getFile();
75 assertTrue("File name \"" + fileName + "\" does not end with \"" + LOG4J_CONFIG_WITH_PLUS + "\"",
76 fileName.endsWith(LOG4J_CONFIG_WITH_PLUS));
77 }
78
79 @Test
80 public void testFileFromUriWithPlusCharactersConvertedToSpacesIfFileDoesNotExist() throws Exception {
4481 final String config = "NON-EXISTING-PATH/this+file+does+not+exist.xml";
4582 final URI uri = new URI(config);
4683 final File file = FileUtils.fileFromUri(uri);
4885 assertFalse("file does not exist", file.exists());
4986 }
5087
51 @Test
52 public void testGetCorrectedFilePathUriWithoutBackslashes() throws URISyntaxException {
53 final String config = "file:///path/to/something/on/unix";
54 final URI uri = FileUtils.getCorrectedFilePathUri(config);
55
56 assertNotNull("The URI should not be null.", uri);
57 assertEquals("The URI is not correct.", "file:///path/to/something/on/unix", uri.toString());
58 }
59
60 @Test
61 public void testGetCorrectedFilePathUriWithBackslashes() throws URISyntaxException {
62 final String config = "file:///D:\\path\\to\\something/on/windows";
63 final URI uri = FileUtils.getCorrectedFilePathUri(config);
64
65 assertNotNull("The URI should not be null.", uri);
66 assertEquals("The URI is not correct.", "file:///D:/path/to/something/on/windows", uri.toString());
67 }
6888 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.util;
18
19 import org.junit.Test;
20
21 import static org.junit.Assert.*;
22
23 /**
24 * Tests the NanoClockFactory.
25 */
26 public class NanoClockFactoryTest {
27
28 @Test
29 public void testDefaultModeIsDummy() {
30 assertEquals(NanoClockFactory.Mode.Dummy, NanoClockFactory.getMode());
31 }
32
33 @Test
34 public void testModeIsMutable() {
35 assertEquals(NanoClockFactory.Mode.Dummy, NanoClockFactory.getMode());
36 NanoClockFactory.setMode(NanoClockFactory.Mode.System);
37 assertEquals(NanoClockFactory.Mode.System, NanoClockFactory.getMode());
38
39 NanoClockFactory.setMode(NanoClockFactory.Mode.Dummy);
40 assertEquals(NanoClockFactory.Mode.Dummy, NanoClockFactory.getMode());
41 }
42
43 @Test
44 public void testModeDeterminesGeneratedClockType() {
45 NanoClockFactory.setMode(NanoClockFactory.Mode.Dummy);
46 assertEquals(NanoClockFactory.Mode.Dummy, NanoClockFactory.getMode());
47 assertTrue("dummy", NanoClockFactory.createNanoClock() instanceof DummyNanoClock);
48
49 NanoClockFactory.setMode(NanoClockFactory.Mode.System);
50 assertEquals(NanoClockFactory.Mode.System, NanoClockFactory.getMode());
51 assertTrue("system", NanoClockFactory.createNanoClock() instanceof SystemNanoClock);
52
53 NanoClockFactory.setMode(NanoClockFactory.Mode.Dummy);
54 assertEquals(NanoClockFactory.Mode.Dummy, NanoClockFactory.getMode());
55 assertTrue("dummy again", NanoClockFactory.createNanoClock() instanceof DummyNanoClock);
56
57 NanoClockFactory.setMode(NanoClockFactory.Mode.System);
58 assertEquals(NanoClockFactory.Mode.System, NanoClockFactory.getMode());
59 assertTrue("system", NanoClockFactory.createNanoClock() instanceof SystemNanoClock);
60
61 NanoClockFactory.setMode(NanoClockFactory.Mode.Dummy);
62 assertTrue("dummy again2", NanoClockFactory.createNanoClock() instanceof DummyNanoClock);
63 }
64 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.util;
18
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertNotNull;
21
22 import java.net.URI;
23 import java.net.URISyntaxException;
24
25 import org.junit.Assume;
26 import org.junit.Test;
27
28 public class NetUtilsTest {
29
30 private static final boolean IS_WINDOWS = System.getProperty("os.name").startsWith("Windows");
31
32 @Test
33 public void testToUriWithoutBackslashes() throws URISyntaxException {
34 final String config = "file:///path/to/something/on/unix";
35 final URI uri = NetUtils.toURI(config);
36
37 assertNotNull("The URI should not be null.", uri);
38 assertEquals("The URI is not correct.", "file:///path/to/something/on/unix", uri.toString());
39 }
40
41 @Test
42 public void testToUriWindowsWithBackslashes() throws URISyntaxException {
43 Assume.assumeTrue(IS_WINDOWS);
44 final String config = "file:///D:\\path\\to\\something/on/windows";
45 final URI uri = NetUtils.toURI(config);
46
47 assertNotNull("The URI should not be null.", uri);
48 assertEquals("The URI is not correct.", "file:///D:/path/to/something/on/windows", uri.toString());
49 }
50
51 @Test
52 public void testToUriWindowsAbsolutePath() throws URISyntaxException {
53 Assume.assumeTrue(IS_WINDOWS);
54 final String config = "D:\\path\\to\\something\\on\\windows";
55 final URI uri = NetUtils.toURI(config);
56
57 assertNotNull("The URI should not be null.", uri);
58 assertEquals("The URI is not correct.", "file:/D:/path/to/something/on/windows", uri.toString());
59 }
60
61 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.core.util;
17
18 import org.apache.logging.log4j.util.PropertiesUtil;
19 import org.junit.Test;
20
21 import java.io.FileInputStream;
22 import java.util.Properties;
23
24 import static org.junit.Assert.assertNotNull;
25 import static org.junit.Assert.assertTrue;
26
27 /**
28 *
29 */
30 public class PropertiesUtilTest {
31
32 @Test
33 public void testSubset() throws Exception {
34 Properties props = new Properties();
35 props.load(new FileInputStream("target/test-classes/log4j2-properties.properties"));
36 Properties subset = PropertiesUtil.extractSubset(props, "appender.Stdout.filter.marker");
37 assertNotNull("No subset returned", subset);
38 assertTrue("Incorrect number of items. Expected 4, actual " + subset.size(), subset.size() == 4);
39 assertTrue("Missing propertu", subset.containsKey("type"));
40 }
41 }
2323 import org.apache.logging.log4j.core.LoggerContext;
2424 import org.apache.logging.log4j.core.impl.Log4jContextFactory;
2525 import org.apache.logging.log4j.core.selector.ContextSelector;
26 import org.apache.logging.log4j.junit.InitialLoggerContext;
26 import org.apache.logging.log4j.junit.LoggerContextRule;
2727 import org.apache.logging.log4j.status.StatusLogger;
2828 import org.junit.BeforeClass;
2929 import org.junit.Rule;
3737 public class ShutdownCallbackRegistryTest {
3838
3939 @Rule
40 public final InitialLoggerContext ctx = new InitialLoggerContext("ShutdownCallbackRegistryTest.xml");
40 public final LoggerContextRule ctx = new LoggerContextRule("ShutdownCallbackRegistryTest.xml");
4141
4242 @BeforeClass
4343 public static void setUpClass() throws Exception {
5858
5959 public static class Registry implements ShutdownCallbackRegistry {
6060 private static final Logger LOGGER = StatusLogger.getLogger();
61 private static final Collection<Cancellable> CALLBACKS = new ConcurrentLinkedQueue<Cancellable>();
61 private static final Collection<Cancellable> CALLBACKS = new ConcurrentLinkedQueue<>();
6262
6363 @Override
6464 public Cancellable addShutdownCallback(final Runnable callback) {
+0
-71
log4j-core/src/test/java/org/apache/logging/log4j/core/util/StandardCharsetsTest.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.util;
18
19 import java.nio.ByteBuffer;
20 import java.nio.CharBuffer;
21 import java.nio.charset.Charset;
22 import java.util.Arrays;
23 import java.util.Collection;
24
25 import org.junit.Test;
26 import org.junit.runner.RunWith;
27 import org.junit.runners.Parameterized;
28
29 import static org.junit.Assert.*;
30
31 @RunWith(Parameterized.class)
32 public class StandardCharsetsTest {
33
34 private final String charsetName;
35 private final Charset expectedCharset;
36
37 public StandardCharsetsTest(final String charsetName, final Charset expectedCharset) {
38 this.charsetName = charsetName;
39 this.expectedCharset = expectedCharset;
40 }
41
42 @Parameterized.Parameters
43 public static Collection<Object[]> data() {
44 return Arrays.asList(
45 new Object[][]{
46 { "US-ASCII", Charsets.US_ASCII },
47 { "ISO-8859-1", Charsets.ISO_8859_1 },
48 { "UTF-8", Charsets.UTF_8 },
49 { "UTF-16BE", Charsets.UTF_16BE },
50 { "UTF-16LE", Charsets.UTF_16LE },
51 { "UTF-16", Charsets.UTF_16 }
52 }
53 );
54 }
55
56 @Test
57 public void testSupportsStandardCharset() throws Exception {
58 assertTrue(Charset.isSupported(charsetName));
59 assertSame(expectedCharset, Charsets.getSupportedCharset(charsetName));
60 }
61
62 @Test
63 public void testCharsetTranslatesProperly() throws Exception {
64 final String expected = "This string contains only ASCII characters to test all the standard charsets";
65 final ByteBuffer encoded = expectedCharset.encode(expected);
66 final CharBuffer decoded = expectedCharset.decode(encoded);
67 final String actual = decoded.toString();
68 assertEquals(expected, actual);
69 }
70 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.util;
18
19 import java.util.concurrent.TimeUnit;
20
21 import org.junit.Test;
22
23 import static org.junit.Assert.*;
24
25 /**
26 * Tests the SystemNanoClock.
27 */
28 public class SystemNanoClockTest {
29
30 @Test
31 public void testReturnsSystemNanoTime() {
32 final NanoClock clock = new SystemNanoClock();
33 final long expected = System.nanoTime();
34 final long actual = clock.nanoTime();
35 assertTrue("smal difference", actual - expected < TimeUnit.SECONDS.toNanos(1));
36 }
37
38 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.core.util.datetime;
18
19 import java.text.SimpleDateFormat;
20 import java.util.Date;
21 import java.util.concurrent.TimeUnit;
22
23 import org.apache.logging.log4j.core.util.datetime.FixedDateFormat.FixedFormat;
24 import org.junit.Test;
25
26 import static org.junit.Assert.*;
27
28 /**
29 * Tests the FixedDateFormat class.
30 */
31 public class FixedDateFormatTest {
32
33 @Test
34 public void testFixedFormat_getDatePatternNullIfNoDateInPattern() {
35 assertNull(FixedFormat.ABSOLUTE.getDatePattern());
36 assertNull(FixedFormat.ABSOLUTE_PERIOD.getDatePattern());
37 }
38
39 @Test
40 public void testFixedFormat_getDatePatternLengthZeroIfNoDateInPattern() {
41 assertEquals(0, FixedFormat.ABSOLUTE.getDatePatternLength());
42 assertEquals(0, FixedFormat.ABSOLUTE_PERIOD.getDatePatternLength());
43 }
44
45 @Test
46 public void testFixedFormat_getFastDateFormatNullIfNoDateInPattern() {
47 assertNull(FixedFormat.ABSOLUTE.getFastDateFormat());
48 assertNull(FixedFormat.ABSOLUTE_PERIOD.getFastDateFormat());
49 }
50
51 @Test
52 public void testFixedFormat_getDatePatternReturnsDatePatternIfExists() {
53 assertEquals("yyyyMMdd", FixedFormat.COMPACT.getDatePattern());
54 assertEquals("yyyy-MM-dd ", FixedFormat.DEFAULT.getDatePattern());
55 }
56
57 @Test
58 public void testFixedFormat_getDatePatternLengthReturnsDatePatternLength() {
59 assertEquals("yyyyMMdd".length(), FixedFormat.COMPACT.getDatePatternLength());
60 assertEquals("yyyy-MM-dd ".length(), FixedFormat.DEFAULT.getDatePatternLength());
61 }
62
63 @Test
64 public void testFixedFormat_getFastDateFormatNonNullIfDateInPattern() {
65 assertNotNull(FixedFormat.COMPACT.getFastDateFormat());
66 assertNotNull(FixedFormat.DEFAULT.getFastDateFormat());
67 assertEquals("yyyyMMdd", FixedFormat.COMPACT.getFastDateFormat().getPattern());
68 assertEquals("yyyy-MM-dd ", FixedFormat.DEFAULT.getFastDateFormat().getPattern());
69 }
70
71 @Test
72 public void testCreateIfSupported_nonNullIfNameMatches() {
73 for (final FixedDateFormat.FixedFormat format : FixedDateFormat.FixedFormat.values()) {
74 final String[] options = {format.name()};
75 assertNotNull(format.name(), FixedDateFormat.createIfSupported(options));
76 }
77 }
78
79 @Test
80 public void testCreateIfSupported_nonNullIfPatternMatches() {
81 for (final FixedDateFormat.FixedFormat format : FixedDateFormat.FixedFormat.values()) {
82 final String[] options = {format.getPattern()};
83 assertNotNull(format.name(), FixedDateFormat.createIfSupported(options));
84 }
85 }
86
87 @Test
88 public void testCreateIfSupported_nullIfNameDoesNotMatch() {
89 final String[] options = {"DEFAULT3"};
90 assertNull("DEFAULT3", FixedDateFormat.createIfSupported(options));
91 }
92
93 @Test
94 public void testCreateIfSupported_nullIfPatternDoesNotMatch() {
95 final String[] options = {"y M d H m s"};
96 assertNull("y M d H m s", FixedDateFormat.createIfSupported(options));
97 }
98
99 @Test
100 public void testCreateIfSupported_defaultIfOptionsArrayNull() {
101 final FixedDateFormat fmt = FixedDateFormat.createIfSupported((String[]) null);
102 assertEquals(FixedFormat.DEFAULT.getPattern(), fmt.getFormat());
103 }
104
105 @Test
106 public void testCreateIfSupported_defaultIfOptionsArrayEmpty() {
107 final FixedDateFormat fmt = FixedDateFormat.createIfSupported(new String[0]);
108 assertEquals(FixedFormat.DEFAULT.getPattern(), fmt.getFormat());
109 }
110
111 @Test
112 public void testCreateIfSupported_defaultIfOptionsArrayWithSingleNullElement() {
113 final FixedDateFormat fmt = FixedDateFormat.createIfSupported(new String[1]);
114 assertEquals(FixedFormat.DEFAULT.getPattern(), fmt.getFormat());
115 }
116
117 @Test
118 public void testCreateIfSupported_nullIfOptionsArrayHasTwoElements() {
119 final String[] options = {FixedDateFormat.FixedFormat.ABSOLUTE.getPattern(), "+08:00"};
120 assertNull("timezone", FixedDateFormat.createIfSupported(options));
121 }
122
123 @Test(expected=NullPointerException.class)
124 public void testConstructorDisallowsNull() {
125 new FixedDateFormat(null);
126 }
127
128 @Test
129 public void testGetFormatReturnsConstructorFixedFormatPattern() {
130 final FixedDateFormat format = new FixedDateFormat(FixedDateFormat.FixedFormat.ABSOLUTE);
131 assertSame(FixedDateFormat.FixedFormat.ABSOLUTE.getPattern(), format.getFormat());
132 }
133
134 @Test
135 public void testFormatLong() {
136 final long now = System.currentTimeMillis();
137 final long start = now - TimeUnit.HOURS.toMillis(25);
138 final long end = now + TimeUnit.HOURS.toMillis(25);
139 for (final FixedFormat format : FixedFormat.values()) {
140 final SimpleDateFormat simpleDF = new SimpleDateFormat(format.getPattern());
141 final FixedDateFormat customTF = new FixedDateFormat(format);
142 for (long time = start; time < end; time += 12345) {
143 final String actual = customTF.format(time);
144 final String expected = simpleDF.format(new Date(time));
145 assertEquals(format + "/" + time, expected, actual);
146 }
147 }
148 }
149
150 @Test
151 public void testFormatLong_goingBackInTime() {
152 final long now = System.currentTimeMillis();
153 final long start = now - TimeUnit.HOURS.toMillis(25);
154 final long end = now + TimeUnit.HOURS.toMillis(25);
155 for (final FixedFormat format : FixedFormat.values()) {
156 final SimpleDateFormat simpleDF = new SimpleDateFormat(format.getPattern());
157 final FixedDateFormat customTF = new FixedDateFormat(format);
158 for (long time = end; time > start; time -= 12345) {
159 final String actual = customTF.format(time);
160 final String expected = simpleDF.format(new Date(time));
161 assertEquals(format + "/" + time, expected, actual);
162 }
163 }
164 }
165
166 @Test
167 public void testFormatLongCharArrayInt() {
168 final long now = System.currentTimeMillis();
169 final long start = now - TimeUnit.HOURS.toMillis(25);
170 final long end = now + TimeUnit.HOURS.toMillis(25);
171 final char[] buffer = new char[128];
172 for (final FixedFormat format : FixedFormat.values()) {
173 final SimpleDateFormat simpleDF = new SimpleDateFormat(format.getPattern());
174 final FixedDateFormat customTF = new FixedDateFormat(format);
175 for (long time = start; time < end; time += 12345) {
176 final int length = customTF.format(time, buffer, 23);
177 final String actual = new String(buffer, 23, length);
178 final String expected = simpleDF.format(new Date(time));
179 assertEquals(format + "/" + time, expected, actual);
180 }
181 }
182 }
183
184 @Test
185 public void testFormatLongCharArrayInt_goingBackInTime() {
186 final long now = System.currentTimeMillis();
187 final long start = now - TimeUnit.HOURS.toMillis(25);
188 final long end = now + TimeUnit.HOURS.toMillis(25);
189 final char[] buffer = new char[128];
190 for (final FixedFormat format : FixedFormat.values()) {
191 final SimpleDateFormat simpleDF = new SimpleDateFormat(format.getPattern());
192 final FixedDateFormat customTF = new FixedDateFormat(format);
193 for (long time = end; time > start; time -= 12345) {
194 final int length = customTF.format(time, buffer, 23);
195 final String actual = new String(buffer, 23, length);
196 final String expected = simpleDF.format(new Date(time));
197 assertEquals(format + "/" + time, expected, actual);
198 }
199 }
200 }
201
202 }
3737 }
3838
3939 public CleanFiles(final String... fileNames) {
40 this.files = new ArrayList<File>(fileNames.length);
40 this.files = new ArrayList<>(fileNames.length);
4141 for (final String fileName : fileNames) {
4242 this.files.add(new File(fileName));
4343 }
+0
-144
log4j-core/src/test/java/org/apache/logging/log4j/junit/InitialLoggerContext.java less more
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.junit;
17
18 import org.apache.logging.log4j.Level;
19 import org.apache.logging.log4j.core.Appender;
20 import org.apache.logging.log4j.core.Logger;
21 import org.apache.logging.log4j.core.LoggerContext;
22 import org.apache.logging.log4j.core.config.Configuration;
23 import org.apache.logging.log4j.core.config.Configurator;
24 import org.apache.logging.log4j.status.StatusLogger;
25 import org.apache.logging.log4j.test.appender.ListAppender;
26 import org.junit.rules.TestRule;
27 import org.junit.runner.Description;
28 import org.junit.runners.model.Statement;
29
30 import static org.junit.Assert.*;
31
32 /**
33 * JUnit {@link TestRule} for constructing a new LoggerContext using a specified configuration file.
34 * If the system property {@code EBUG} is set (e.g., through the command line option {@code -DEBUG}), then the
35 * StatusLogger will be set to the debug level. This allows for more debug messages as the StatusLogger will be in the
36 * error level until a configuration file has been read and parsed into a tree of Nodes.
37 */
38 public class InitialLoggerContext implements TestRule {
39
40 private final String configLocation;
41
42 private LoggerContext context;
43
44 private String testClassName;
45
46 public InitialLoggerContext(final String configLocation) {
47 this.configLocation = configLocation;
48 }
49
50 @Override
51 public Statement apply(final Statement base, final Description description) {
52 // Hack: Using -DEBUG as a JVM param sets a property called "EBUG"...
53 if (System.getProperties().containsKey("EBUG")) {
54 StatusLogger.getLogger().setLevel(Level.DEBUG);
55 }
56 testClassName = description.getClassName();
57 return new Statement() {
58 @Override
59 public void evaluate() throws Throwable {
60 context = Configurator.initialize(
61 description.getDisplayName(),
62 description.getTestClass().getClassLoader(),
63 configLocation
64 );
65 try {
66 base.evaluate();
67 } finally {
68 Configurator.shutdown(context);
69 StatusLogger.getLogger().reset();
70 }
71 }
72 };
73 }
74
75 /**
76 * Gets the current LoggerContext associated with this rule.
77 * @return the current LoggerContext.
78 */
79 public LoggerContext getContext() {
80 return context;
81 }
82
83 /**
84 * Gets a named Logger using the test class's name from this LoggerContext.
85 * @return the test class's named Logger.
86 */
87 public Logger getLogger() {
88 return context.getLogger(testClassName);
89 }
90
91 /**
92 * Gets a named Logger in this LoggerContext.
93 *
94 * @param name the name of the Logger to look up or create.
95 * @return the named Logger.
96 */
97 public Logger getLogger(final String name) {
98 return context.getLogger(name);
99 }
100
101 /**
102 * Gets the associated Configuration for the configuration file this was constructed with.
103 * @return this LoggerContext's Configuration.
104 */
105 public Configuration getConfiguration() {
106 return context.getConfiguration();
107 }
108
109 /**
110 * Gets a named Appender for this LoggerContext.
111 * @param name the name of the Appender to look up.
112 * @return the named Appender or {@code null} if it wasn't defined in the configuration.
113 */
114 public Appender getAppender(final String name) {
115 return getConfiguration().getAppenders().get(name);
116 }
117
118 /**
119 * Gets a named Appender or throws an exception for this LoggerContext.
120 * @param name the name of the Appender to look up.
121 * @return the named Appender.
122 * @throws AssertionError if the Appender doesn't exist.
123 */
124 public Appender getRequiredAppender(final String name) {
125 final Appender appender = getAppender(name);
126 assertNotNull("Appender named " + name + " was null.", appender);
127 return appender;
128 }
129
130 /**
131 * Gets a named ListAppender or throws an exception for this LoggerContext.
132 * @param name the name of the ListAppender to look up.
133 * @return the named ListAppender.
134 * @throws AssertionError if the named ListAppender doesn't exist or isn't a ListAppender.
135 */
136 public ListAppender getListAppender(final String name) {
137 final Appender appender = getAppender(name);
138 if (appender instanceof ListAppender) {
139 return (ListAppender) appender;
140 }
141 throw new AssertionError("No ListAppender named " + name + " found.");
142 }
143 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.junit;
17
18 import org.apache.logging.log4j.Level;
19 import org.apache.logging.log4j.core.Appender;
20 import org.apache.logging.log4j.core.Logger;
21 import org.apache.logging.log4j.core.LoggerContext;
22 import org.apache.logging.log4j.core.config.Configuration;
23 import org.apache.logging.log4j.core.config.Configurator;
24 import org.apache.logging.log4j.status.StatusLogger;
25 import org.apache.logging.log4j.test.appender.ListAppender;
26 import org.junit.rules.TestRule;
27 import org.junit.runner.Description;
28 import org.junit.runners.model.Statement;
29
30 import static org.junit.Assert.*;
31
32 /**
33 * JUnit {@link TestRule} for constructing a new LoggerContext using a specified configuration file.
34 * If the system property {@code EBUG} is set (e.g., through the command line option {@code -DEBUG}), then the
35 * StatusLogger will be set to the debug level. This allows for more debug messages as the StatusLogger will be in the
36 * error level until a configuration file has been read and parsed into a tree of Nodes.
37 */
38 public class LoggerContextRule implements TestRule {
39
40 private final String configLocation;
41
42 private LoggerContext context;
43
44 private String testClassName;
45
46 public LoggerContextRule(final String configLocation) {
47 this.configLocation = configLocation;
48 }
49
50 @Override
51 public Statement apply(final Statement base, final Description description) {
52 // Hack: Using -DEBUG as a JVM param sets a property called "EBUG"...
53 if (System.getProperties().containsKey("EBUG")) {
54 StatusLogger.getLogger().setLevel(Level.DEBUG);
55 }
56 testClassName = description.getClassName();
57 return new Statement() {
58 @Override
59 public void evaluate() throws Throwable {
60 context = Configurator.initialize(
61 description.getDisplayName(),
62 description.getTestClass().getClassLoader(),
63 configLocation
64 );
65 try {
66 base.evaluate();
67 } finally {
68 Configurator.shutdown(context);
69 StatusLogger.getLogger().reset();
70 }
71 }
72 };
73 }
74
75 /**
76 * Gets the current LoggerContext associated with this rule.
77 * @return the current LoggerContext.
78 */
79 public LoggerContext getContext() {
80 return context;
81 }
82
83 /**
84 * Gets a named Logger using the test class's name from this LoggerContext.
85 * @return the test class's named Logger.
86 */
87 public Logger getLogger() {
88 return context.getLogger(testClassName);
89 }
90
91 /**
92 * Gets a named Logger in this LoggerContext.
93 *
94 * @param name the name of the Logger to look up or create.
95 * @return the named Logger.
96 */
97 public Logger getLogger(final String name) {
98 return context.getLogger(name);
99 }
100
101 /**
102 * Gets the associated Configuration for the configuration file this was constructed with.
103 * @return this LoggerContext's Configuration.
104 */
105 public Configuration getConfiguration() {
106 return context.getConfiguration();
107 }
108
109 /**
110 * Gets a named Appender for this LoggerContext.
111 * @param name the name of the Appender to look up.
112 * @return the named Appender or {@code null} if it wasn't defined in the configuration.
113 */
114 public Appender getAppender(final String name) {
115 return getConfiguration().getAppenders().get(name);
116 }
117
118 /**
119 * Gets a named Appender for this LoggerContext.
120 * @param <T> The target Appender class
121 * @param name the name of the Appender to look up.
122 * @param cls The target Appender class
123 * @return the named Appender or {@code null} if it wasn't defined in the configuration.
124 */
125 public <T extends Appender> T getAppender(final String name, Class<T> cls) {
126 return cls.cast(getConfiguration().getAppenders().get(name));
127 }
128
129 /**
130 * Gets a named Appender or throws an exception for this LoggerContext.
131 * @param name the name of the Appender to look up.
132 * @return the named Appender.
133 * @throws AssertionError if the Appender doesn't exist.
134 */
135 public Appender getRequiredAppender(final String name) {
136 final Appender appender = getAppender(name);
137 assertNotNull("Appender named " + name + " was null.", appender);
138 return appender;
139 }
140
141 /**
142 * Gets a named Appender or throws an exception for this LoggerContext.
143 * @param <T> The target Appender class
144 * @param name the name of the Appender to look up.
145 * @param cls The target Appender class
146 * @return the named Appender.
147 * @throws AssertionError if the Appender doesn't exist.
148 */
149 public <T extends Appender> T getRequiredAppender(final String name, Class<T> cls) {
150 final T appender = getAppender(name, cls);
151 assertNotNull("Appender named " + name + " was null.", appender);
152 return appender;
153 }
154
155 /**
156 * Gets a named ListAppender or throws an exception for this LoggerContext.
157 * @param name the name of the ListAppender to look up.
158 * @return the named ListAppender.
159 * @throws AssertionError if the named ListAppender doesn't exist or isn't a ListAppender.
160 */
161 public ListAppender getListAppender(final String name) {
162 final Appender appender = getAppender(name);
163 if (appender instanceof ListAppender) {
164 return (ListAppender) appender;
165 }
166 throw new AssertionError("No ListAppender named " + name + " found.");
167 }
168 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.test.appender;
17
18 import org.apache.logging.log4j.LogManager;
19 import org.apache.logging.log4j.Logger;
20 import org.apache.logging.log4j.LoggingException;
21 import org.apache.logging.log4j.core.LogEvent;
22 import org.apache.logging.log4j.core.appender.AbstractAppender;
23 import org.apache.logging.log4j.core.config.plugins.Plugin;
24 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
25 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
26
27 /**
28 *
29 */
30 @Plugin(name="Deadlock", category ="Core",elementType="appender",printObject=true)
31 public class DeadlockAppender extends AbstractAppender {
32
33 private WorkerThread thread = null;
34
35 private DeadlockAppender(final String name) {
36 super(name, null, null, false);
37 thread = new WorkerThread();
38 }
39
40 @Override
41 public void start() {
42 super.start();
43
44 }
45
46 @Override
47 public void stop() {
48 super.stop();
49 thread.start();
50 try {
51 thread.join();
52 } catch (final Exception ex) {
53 System.out.println("Thread interrupted");
54 }
55 }
56
57 @Override
58 public void append(final LogEvent event) {
59 throw new LoggingException("Always fail");
60 }
61
62 @PluginFactory
63 public static DeadlockAppender createAppender(@PluginAttribute("name") final String name) {
64 if (name == null) {
65 LOGGER.error("A name for the Appender must be specified");
66 return null;
67 }
68
69 return new DeadlockAppender(name);
70 }
71
72 private class WorkerThread extends Thread {
73
74 @Override
75 public void run() {
76 final Logger logger = LogManager.getLogger("org.apache.logging.log4j.test.WorkerThread");
77 logger.debug("Worker is running");
78 }
79 }
80 }
3535
3636 boolean fail = true;
3737
38 private final List<LogEvent> events = new ArrayList<LogEvent>();
38 private final List<LogEvent> events = new ArrayList<>();
3939
4040 private FailOnceAppender(final String name) {
4141 super(name, null, null, false);
4646 if (fail) {
4747 fail = false;
4848 throw new LoggingException("Always fail");
49 } else {
50 events.add(event);
5149 }
50 events.add(event);
5251 }
5352
5453 public List<LogEvent> getEvents() {
55 final List<LogEvent> list = new ArrayList<LogEvent>(events);
54 final List<LogEvent> list = new ArrayList<>(events);
5655 events.clear();
5756 return list;
5857 }
3131 private static final long serialVersionUID = 1L;
3232
3333 public InMemoryAppender(final String name, final Layout<? extends Serializable> layout, final CompositeFilter filters,
34 final boolean ignoreExceptions) {
35 super(name, layout, filters, ignoreExceptions, true, new InMemoryManager(name, layout));
34 final boolean ignoreExceptions, final boolean writeHeader) {
35 super(name, layout, filters, ignoreExceptions, true, new InMemoryManager(name, layout, writeHeader));
3636 }
3737
3838 @Override
4242
4343 static class InMemoryManager extends OutputStreamManager {
4444
45 public InMemoryManager(final String name, final Layout<? extends Serializable> layout) {
46 super(new ByteArrayOutputStream(), name, layout);
45 public InMemoryManager(final String name, final Layout<? extends Serializable> layout,
46 final boolean writeHeader) {
47 super(new ByteArrayOutputStream(), name, layout, writeHeader);
4748 }
4849
4950 @Override
2020 import java.util.Collections;
2121 import java.util.List;
2222
23 import org.apache.logging.log4j.LogManager;
2423 import org.apache.logging.log4j.core.Filter;
2524 import org.apache.logging.log4j.core.Layout;
2625 import org.apache.logging.log4j.core.LogEvent;
3635 /**
3736 * This appender is primarily used for testing. Use in a real environment is discouraged as the
3837 * List could eventually grow to cause an OutOfMemoryError.
39 * @see org.apache.logging.log4j.junit.InitialLoggerContext#getListAppender(String) ILC.getListAppender
38 * @see org.apache.logging.log4j.junit.LoggerContextRule#getListAppender(String) ILC.getListAppender
4039 */
4140 @Plugin(name = "List", category = "Core", elementType = "appender", printObject = true)
4241 public class ListAppender extends AbstractAppender {
4544
4645 // Use CopyOnWriteArrayList?
4746
48 private final List<LogEvent> events = new ArrayList<LogEvent>();
47 private final List<LogEvent> events = new ArrayList<>();
4948
50 private final List<String> messages = new ArrayList<String>();
49 private final List<String> messages = new ArrayList<>();
5150
52 private final List<byte[]> data = new ArrayList<byte[]>();
51 private final List<byte[]> data = new ArrayList<>();
5352
5453 private final boolean newLine;
5554
178177 *
179178 * @param name the name of the ListAppender
180179 * @return the named ListAppender or {@code null} if it does not exist
181 * @see org.apache.logging.log4j.junit.InitialLoggerContext#getListAppender(String)
180 * @see org.apache.logging.log4j.junit.LoggerContextRule#getListAppender(String)
182181 */
183182 public static ListAppender getListAppender(final String name) {
184 return ((ListAppender) ((LoggerContext) LogManager.getContext(false)).getConfiguration().getAppender(name));
183 return ((ListAppender) (LoggerContext.getContext(false)).getConfiguration().getAppender(name));
185184 }
186185 }
1616 package org.apache.logging.log4j.test.layout;
1717
1818 import java.nio.charset.Charset;
19 import java.nio.charset.StandardCharsets;
1920
2021 import org.apache.logging.log4j.core.LogEvent;
2122 import org.apache.logging.log4j.core.config.plugins.Plugin;
2223 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
2324 import org.apache.logging.log4j.core.layout.AbstractStringLayout;
24 import org.apache.logging.log4j.core.util.Charsets;
2525 import org.apache.logging.log4j.core.util.Constants;
2626
2727 /**
5050 */
5151 @PluginFactory
5252 public static BasicLayout createLayout() {
53 return new BasicLayout(Charsets.UTF_8);
53 return new BasicLayout(StandardCharsets.UTF_8);
5454 }
5555 }
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 ~ Licensed to the Apache Software Foundation (ASF) under one or more
3 ~ contributor license agreements. See the NOTICE file distributed with
4 ~ this work for additional information regarding copyright ownership.
5 ~ The ASF licenses this file to You under the Apache license, Version 2.0
6 ~ (the "License"); you may not use this file except in compliance with
7 ~ the License. You may obtain a copy of the License at
8 ~
9 ~ http://www.apache.org/licenses/LICENSE-2.0
10 ~
11 ~ Unless required by applicable law or agreed to in writing, software
12 ~ distributed under the License is distributed on an "AS IS" BASIS,
13 ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ~ See the license for the specific language governing permissions and
15 ~ limitations under the license.
16 -->
17 <Configuration name="JeroMQAppenderTest" status="TRACE">
18 <Appenders>
19 <JeroMQ name="JeroMQAppender">
20 <Property name="endpoint">tcp://*:5556</Property>
21 <Property name="endpoint">ipc://info-topic</Property>
22 </JeroMQ>
23 </Appenders>
24 <Loggers>
25 <Root level="info">
26 <AppenderRef ref="JeroMQAppender"/>
27 </Root>
28 </Loggers>
29 </Configuration>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 ~ Licensed to the Apache Software Foundation (ASF) under one or more
3 ~ contributor license agreements. See the NOTICE file distributed with
4 ~ this work for additional information regarding copyright ownership.
5 ~ The ASF licenses this file to You under the Apache license, Version 2.0
6 ~ (the "License"); you may not use this file except in compliance with
7 ~ the License. You may obtain a copy of the License at
8 ~
9 ~ http://www.apache.org/licenses/LICENSE-2.0
10 ~
11 ~ Unless required by applicable law or agreed to in writing, software
12 ~ distributed under the License is distributed on an "AS IS" BASIS,
13 ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ~ See the license for the specific language governing permissions and
15 ~ limitations under the license.
16 -->
17 <Configuration name="KafkaAppenderTest" status="OFF">
18 <Appenders>
19 <Kafka name="KafkaAppender" topic="kafka-topic">
20 <Property name="bootstrap.servers">localhost:9092</Property>
21 </Kafka>
22 <Kafka name="KafkaAppenderWithLayout" topic="kafka-topic">
23 <PatternLayout pattern="[%m]"/>
24 <Property name="bootstrap.servers">localhost:9092</Property>
25 </Kafka>
26 </Appenders>
27 <Loggers>
28 <Root level="info">
29 <AppenderRef ref="KafkaAppender"/>
30 <AppenderRef ref="KafkaAppenderWithLayout"/>
31 </Root>
32 </Loggers>
33 </Configuration>
0 Configuration:
1 status: trace
2
3 Appenders:
4 Console:
5 - name: Console
6 target: SYSTEM_OUT
7 PatternLayout:
8 Pattern: "%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"
9 RollingFile:
10 - name: File
11 fileName: "${sys:user.home}/.btat/btat.log"
12 filePattern: "${sys:user.home}/.btat/logs/btat-%d{yyyy-MM}-%i.log.gz"
13 PatternLayout:
14 Pattern: "%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"
15 Policies:
16 - TimeBasedTriggeringPolicy:
17 interval: 7
18 - SizeBasedTriggeringPolicy:
19 size: 100 MB
20 DefaultRolloverStrategy:
21 max: 20
22
23 Loggers:
24 Root:
25 level: info
26 AppenderRef:
27 - ref: Console
28 - ref: File
29
0 Configuration:
1 status: trace
2
3 Appenders:
4 Console:
5 - name: Console
6 target: SYSTEM_OUT
7 PatternLayout:
8 Pattern: "%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"
9 RollingFile:
10 - name: File
11 fileName: "${sys:user.home}/.btat/btat.log"
12 filePattern: "${sys:user.home}/.btat/logs/btat-%d{yyyy-MM}-%i.log.gz"
13 PatternLayout:
14 Pattern: "%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"
15 Policies:
16 TimeBasedTriggeringPolicy:
17 interval: 7
18 SizeBasedTriggeringPolicy:
19 size: 100 MB
20 DefaultRolloverStrategy:
21 max: 20
22
23 Loggers:
24 Root:
25 level: info
26 AppenderRef:
27 - ref: Console
28 - ref: File
29
0 {
1 "configuration": {
2 "status": "warn",
3 "appenders": {
4 "Console": {
5 "name": "Console",
6 "target": "SYSTEM_OUT",
7 "PatternLayout": {
8 "pattern": "%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"
9 }
10 },
11 "RollingFile": {
12 "name": "File",
13 "fileName": "${sys:user.home}/.btat/btat.log",
14 "filePattern": "${sys:user.home}/.btat/logs/btat-%d{yyyy-MM}-%i.log.gz",
15 "PatternLayout": {
16 "pattern": "%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"
17 },
18 "Policies": {
19 "TimeBasedTriggeringPolicy": {
20 "interval": "7"
21 },
22 "SizeBasedTriggeringPolicy": {
23 "size": "100 MB"
24 }
25 },
26 "DefaultRolloverStrategy": {
27 "max": "20"
28 }
29 }
30 },
31 "loggers": {
32 "Root": {
33 "level": "info",
34 "AppenderRef": [
35 { "ref": "Console" },
36 { "ref": "File" }
37 ]
38 }
39 }
40 }
41 }
0 <?xml version="1.0" encoding="UTF-8"?>
1 <Configuration status="WARN">
2 <Appenders>
3 <Console name="Console" target="SYSTEM_OUT">
4 <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
5 </Console>
6 <RollingFile name="File" fileName="${sys:user.home}/.btat/btat.log" filePattern="${sys:user.home}/.btat/logs/btat-%d{yyyy-MM}-%i.log.gz">
7 <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
8 <Policies>
9 <TimeBasedTriggeringPolicy interval="7" />
10 <SizeBasedTriggeringPolicy size="100 MB"/>
11 </Policies>
12 <DefaultRolloverStrategy max="20" />
13 </RollingFile>
14 </Appenders>
15 <Loggers>
16 <Root level="info">
17 <AppenderRef ref="Console"/>
18 <AppenderRef ref="File"/>
19 </Root>
20 </Loggers>
21 </Configuration>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <Configuration status="ERROR">
2 <Appenders>
3 <RandomAccessFile name="RandomAccessFile" fileName="target/NanoTimeToFileTest.log"
4 immediateFlush="true" append="false">
5 <PatternLayout>
6 <Pattern>%N AND %nano AND %m%n</Pattern>
7 </PatternLayout>
8 </RandomAccessFile>
9 </Appenders>
10
11 <Loggers>
12 <Root level="info" includeLocation="false">
13 <AppenderRef ref="RandomAccessFile"/>
14 </Root>
15 </Loggers>
16 </Configuration>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16
17 -->
18 <Configuration status="DEBUG" name="TestCustomLevels">
19
20 <CustomLevels>
21 <CustomLevel name="DIAG" intLevel="350" />
22 <CustomLevel name="NOTICE" intLevel="450" />
23 <CustomLevel name="VERBOSE" intLevel="550" />
24 </CustomLevels>
25
26 <Appenders>
27 <Console name="STDOUT">
28 <PatternLayout pattern="%m%n"/>
29 </Console>
30 <List name="List1"/>
31 </Appenders>
32
33 <Loggers>
34 <Root level="DEBUG">
35 <AppenderRef ref="STDOUT"/>
36 <AppenderRef ref="List1"/>
37 </Root>
38 </Loggers>
39
40 </Configuration>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16
17 -->
18 <Configuration status="DEBUG" name="TestCustomLevelsOverride">
19
20 <!-- Test overriding the int level of a standard level -->
21 <CustomLevels>
22 <CustomLevel name="WARN" intLevel="350" />
23 <CustomLevel name="INFO" intLevel="450" />
24 <CustomLevel name="DEBUG" intLevel="550" />
25 </CustomLevels>
26
27 <Appenders>
28 <Console name="STDOUT">
29 <PatternLayout pattern="%m%n"/>
30 </Console>
31 <List name="List1"/>
32 </Appenders>
33
34 <Loggers>
35 <Root level="DEBUG">
36 <AppenderRef ref="STDOUT"/>
37 <AppenderRef ref="List1"/>
38 </Root>
39 </Loggers>
40
41 </Configuration>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <Configuration status="trace" verbose="true">
2 <CustomLevels>
3 <CustomLevel name="INFOM1" intLevel="399" />
4 <CustomLevel name="INFOP1" intLevel="401" />
5 </CustomLevels>
6 <Appenders>
7 <File name="info" fileName="target/info.log">
8 <PatternLayout>
9 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
10 </PatternLayout>
11 <Filters>
12 <ThresholdFilter level="INFOM1" onMatch="DENY" onMismatch="NEUTRAL" />
13 <ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY" />
14 </Filters>
15 </File>
16 </Appenders>
17 <Loggers>
18 <Logger name="HelloWorld" level="ALL">
19 <AppenderRef ref="info" />
20 </Logger>
21 <Root>
22 </Root>
23 </Loggers>
24 </Configuration>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16
17 -->
18 <Configuration name="ConfigTest" status="OFF" monitorInterval="5">
19 <Appenders>
20 <Deadlock name="deadlock">
21 <PatternLayout pattern="%m%n"/>
22 </Deadlock>
23 </Appenders>
24 <Loggers>
25 <Root level="error">
26 <AppenderRef ref="deadlock"/>
27 </Root>
28 </Loggers>
29 </Configuration>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <Configuration status="WARN">
2 <Appenders>
3 <File name="root" fileName="${sys:user.home}/logs/windowsbug.log">
4 <PatternLayout>
5 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
6 </PatternLayout>
7 </File>
8 </Appenders>
9 <Loggers>
10 <Root level="info">
11 <AppenderRef ref="root" />
12 </Root>
13 </Loggers>
14 </Configuration>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 ~ Licensed to the Apache Software Foundation (ASF) under one or more
3 ~ contributor license agreements. See the NOTICE file distributed with
4 ~ this work for additional information regarding copyright ownership.
5 ~ The ASF licenses this file to You under the Apache License, Version 2.0
6 ~ (the "License"); you may not use this file except in compliance with
7 ~ the License. You may obtain a copy of the License at
8 ~
9 ~ http://www.apache.org/licenses/LICENSE-2.0
10 ~
11 ~ Unless required by applicable law or agreed to in writing, software
12 ~ distributed under the License is distributed on an "AS IS" BASIS,
13 ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ~ See the License for the specific language governing permissions and
15 ~ limitations under the License.
16 -->
17 <Configuration status="WARN">
18 <Appenders>
19 <List name="List">
20 <PatternLayout pattern="[%-5level] %c{1.} %msg%n" />
21 </List>
22 </Appenders>
23 <Loggers>
24 <Root level="debug">
25 <AppenderRef ref="List" />
26 </Root>
27 </Loggers>
28 </Configuration>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16
17 -->
18 <Configuration status="OFF">
19 <Appenders>
20 <Console name="Console" target="SYSTEM_OUT">
21 <PatternLayout pattern="%d [%t] [${main:1}][${main:-1}][${main:--file}] %-5level: %msg%n%throwable" />
22 </Console>
23 </Appenders>
24 <Loggers>
25 <Logger name="org.foo" level="DEBUG" />
26 <Root level="TRACE">
27 <AppenderRef ref="Console" />
28 </Root>
29 </Loggers>
30 </Configuration>
0 Configuration:
1 status: debug
2
3 Appenders:
4 Console:
5 RandomAccessFile:
6 - name: SQL_APPENDER
7 fileName: target/logs/sql.log
8 append: false
9 PatternLayout:
10 Pattern: "%d{ISO8601_BASIC} %-5level %logger{1} %X %msg%n"
11 - name: PAYLOAD_APPENDER
12 fileName: target/logs/payload.log
13 append: false
14 PatternLayout:
15 Pattern: "%d{ISO8601_BASIC} %-5level %logger{1} %X %msg%n"
16 - name: PERFORMANCE_APPENDER
17 fileName: target/logs/performance.log
18 append: false
19 PatternLayout:
20 Pattern: "%d{ISO8601_BASIC} %-5level %logger{1} %X %msg%n"
21
22 Routing:
23 name: ROUTING_APPENDER
24 Routes:
25 pattern: "$${marker:}"
26 Route:
27 - key: PERFORMANCE
28 ref: PERFORMANCE_APPENDER
29 - key: PAYLOAD
30 ref: PAYLOAD_APPENDER
31 - key: SQL
32 ref: SQL_APPENDER
33
34 Loggers:
35 Root:
36 level: trace
37 AppenderRef:
38 - ref: ROUTING_APPENDER
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16
17 -->
18 <Configuration status="OFF" name="XMLConfigTest">
19 <Properties>
20 <Property name="filename">target/rolling1/rollingtest.log</Property>
21 </Properties>
22 <ThresholdFilter level="debug"/>
23
24 <Appenders>
25 <Console name="STDOUT">
26 <PatternLayout pattern="%m%n"/>
27 </Console>
28 <RollingFile name="RollingFile" fileName="${filename}"
29 filePattern="target/rolling1/test1-$${date:MM-dd-yyyy}-%i.log.bz2">
30 <PatternLayout>
31 <Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
32 </PatternLayout>
33 <SizeBasedTriggeringPolicy size="500" />
34 <DefaultRolloverStrategy compressionLevel="9" />
35 </RollingFile>
36 <List name="List">
37 <ThresholdFilter level="error"/>
38 </List>
39 </Appenders>
40
41 <Loggers>
42 <Logger name="org.apache.logging.log4j.test1" level="debug" additivity="false">
43 <ThreadContextMapFilter>
44 <KeyValuePair key="test" value="123"/>
45 </ThreadContextMapFilter>
46 <AppenderRef ref="STDOUT"/>
47 </Logger>>
48
49 <Logger name="org.apache.logging.log4j.core.appender.rolling" level="debug" additivity="false">
50 <AppenderRef ref="RollingFile"/>
51 </Logger>>
52
53 <Root level="error">
54 <AppenderRef ref="STDOUT"/>
55 </Root>
56 </Loggers>
57
58 </Configuration>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16
17 -->
18 <Configuration status="OFF" name="XMLConfigTest">
19 <Properties>
20 <Property name="filename">target/rolling1/rollingtest.log</Property>
21 </Properties>
22 <ThresholdFilter level="debug"/>
23
24 <Appenders>
25 <Console name="STDOUT">
26 <PatternLayout pattern="%m%n"/>
27 </Console>
28 <RollingFile name="RollingFile" fileName="${filename}"
29 filePattern="target/rolling1/test1-$${date:MM-dd-yyyy}-%i.log.deflate">
30 <PatternLayout>
31 <Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
32 </PatternLayout>
33 <SizeBasedTriggeringPolicy size="500" />
34 <DefaultRolloverStrategy compressionLevel="9" />
35 </RollingFile>
36 <List name="List">
37 <ThresholdFilter level="error"/>
38 </List>
39 </Appenders>
40
41 <Loggers>
42 <Logger name="org.apache.logging.log4j.test1" level="debug" additivity="false">
43 <ThreadContextMapFilter>
44 <KeyValuePair key="test" value="123"/>
45 </ThreadContextMapFilter>
46 <AppenderRef ref="STDOUT"/>
47 </Logger>>
48
49 <Logger name="org.apache.logging.log4j.core.appender.rolling" level="debug" additivity="false">
50 <AppenderRef ref="RollingFile"/>
51 </Logger>>
52
53 <Root level="error">
54 <AppenderRef ref="STDOUT"/>
55 </Root>
56 </Loggers>
57
58 </Configuration>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16
17 -->
18 <Configuration status="OFF" name="XMLConfigTest">
19 <Properties>
20 <Property name="filename">target/rolling1/rollingtest.log</Property>
21 </Properties>
22 <ThresholdFilter level="debug"/>
23
24 <Appenders>
25 <Console name="STDOUT">
26 <PatternLayout pattern="%m%n"/>
27 </Console>
28 <RollingFile name="RollingFile" fileName="${filename}"
29 filePattern="target/rolling1/test1-$${date:MM-dd-yyyy}-%i.log.pack200">
30 <PatternLayout>
31 <Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
32 </PatternLayout>
33 <SizeBasedTriggeringPolicy size="500" />
34 <DefaultRolloverStrategy compressionLevel="9" />
35 </RollingFile>
36 <List name="List">
37 <ThresholdFilter level="error"/>
38 </List>
39 </Appenders>
40
41 <Loggers>
42 <Logger name="org.apache.logging.log4j.test1" level="debug" additivity="false">
43 <ThreadContextMapFilter>
44 <KeyValuePair key="test" value="123"/>
45 </ThreadContextMapFilter>
46 <AppenderRef ref="STDOUT"/>
47 </Logger>>
48
49 <Logger name="org.apache.logging.log4j.core.appender.rolling" level="debug" additivity="false">
50 <AppenderRef ref="RollingFile"/>
51 </Logger>>
52
53 <Root level="error">
54 <AppenderRef ref="STDOUT"/>
55 </Root>
56 </Loggers>
57
58 </Configuration>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16
17 -->
18 <Configuration status="OFF" name="XMLConfigTest">
19 <Properties>
20 <Property name="filename">target/rolling1/rollingtest.log</Property>
21 </Properties>
22 <ThresholdFilter level="debug"/>
23
24 <Appenders>
25 <Console name="STDOUT">
26 <PatternLayout pattern="%m%n"/>
27 </Console>
28 <RollingFile name="RollingFile" fileName="${filename}"
29 filePattern="target/rolling1/test1-$${date:MM-dd-yyyy}-%i.log.xy">
30 <PatternLayout>
31 <Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
32 </PatternLayout>
33 <SizeBasedTriggeringPolicy size="500" />
34 <DefaultRolloverStrategy compressionLevel="9" />
35 </RollingFile>
36 <List name="List">
37 <ThresholdFilter level="error"/>
38 </List>
39 </Appenders>
40
41 <Loggers>
42 <Logger name="org.apache.logging.log4j.test1" level="debug" additivity="false">
43 <ThreadContextMapFilter>
44 <KeyValuePair key="test" value="123"/>
45 </ThreadContextMapFilter>
46 <AppenderRef ref="STDOUT"/>
47 </Logger>>
48
49 <Logger name="org.apache.logging.log4j.core.appender.rolling" level="debug" additivity="false">
50 <AppenderRef ref="RollingFile"/>
51 </Logger>>
52
53 <Root level="error">
54 <AppenderRef ref="STDOUT"/>
55 </Root>
56 </Loggers>
57
58 </Configuration>
0 # Licensed to the Apache Software Foundation (ASF) under one or more
1 # contributor license agreements. See the NOTICE file distributed with
2 # this work for additional information regarding copyright ownership.
3 # The ASF licenses this file to You under the Apache License, Version 2.0
4 # (the "License"); you may not use this file except in compliance with
5 # the License. You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 status = error
16 name = PropertiesConfigTest
17
18 property.filename = target/rolling/rollingtest.log
19
20 filters = threshold
21
22 filter.threshold.type = ThresholdFilter
23 filter.threshold.level = debug
24
25 appenders = console, rolling, list
26
27 appender.console.type = Console
28 appender.console.name = STDOUT
29 appender.console.layout.type = PatternLayout
30 appender.console.layout.pattern = %m%n
31
32 appender.rolling.type = RollingFile
33 appender.rolling.name = RollingFile
34 appender.rolling.fileName = ${filename}
35 appender.rolling.filePattern = target/rolling2/test1-%d{MM-dd-yy-HH-mm-ss}-%i.log.gz
36 appender.rolling.layout.type = PatternLayout
37 appender.rolling.layout.pattern = %d %p %C{1.} [%t] %m%n
38 appender.rolling.policies.type = Policies
39 appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
40 appender.rolling.policies.time.interval = 2
41 appender.rolling.policies.time.modulate = true
42 appender.rolling.policies.size.type = SizeBasedTriggeringPolicy
43 appender.rolling.policies.size.size=100MB
44
45 appender.list.type = List
46 appender.list.name = List
47 appender.list.filters = threshold
48 appender.list.filter.threshold.type = ThresholdFilter
49 appender.list.filter.threshold.level = error
50
51 loggers = rolling
52
53 logger.rolling.name = org.apache.logging.log4j.core.appender.rolling
54 logger.rolling.level = debug
55 logger.rolling.additivity = false
56 logger.rolling.appenderRefs = rolling
57 logger.rolling.appenderRef.rolling.ref = RollingFile
58
59 rootLogger.level = info
60 rootLogger.appenderRefs = stdout
61 rootLogger.appenderRef.stdout.ref = STDOUT
0 # Licensed to the Apache Software Foundation (ASF) under one or more
1 # contributor license agreements. See the NOTICE file distributed with
2 # this work for additional information regarding copyright ownership.
3 # The ASF licenses this file to You under the Apache License, Version 2.0
4 # (the "License"); you may not use this file except in compliance with
5 # the License. You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 status = error
16 name = RoutingTest
17
18 property.filename = target/routing1/routingtestProps-$${sd:type}.log
19
20 filters = threshold
21
22 filter.threshold.type = ThresholdFilter
23 filter.threshold.level = debug
24
25 appenders = console, routing, list
26
27 appender.console.type = Console
28 appender.console.name = STDOUT
29 appender.console.layout.type = PatternLayout
30 appender.console.layout.pattern = %m%n
31
32 appender.routing.type = Routing
33 appender.routing.name = Routing
34 appender.routing.routes.type = Routes
35 appender.routing.routes.pattern = $${sd:type}
36 appender.routing.routes.route1.type = Route
37 appender.routing.routes.route1.rolling.type = RollingFile
38 appender.routing.routes.route1.rolling.name = Routing-${sd:type}
39 appender.routing.routes.route1.rolling.fileName = ${filename}
40 appender.routing.routes.route1.rolling.filePattern = target/routing1/test1-${sd:type}.%i.log.gz
41 appender.routing.routes.route1.rolling.layout.type = PatternLayout
42 appender.routing.routes.route1.rolling.layout.pattern = %d %p %C{1.} [%t] %m%n
43 appender.routing.routes.route1.rolling.policy.type = SizeBasedTriggeringPolicy
44 appender.routing.routes.route1.rolling.policy.size = 500
45 appender.routing.routes.route2.type = Route
46 appender.routing.routes.route2.ref = STDOUT
47 appender.routing.routes.route2.key = Audit
48 appender.routing.routes.route3.type = Route
49 appender.routing.routes.route3.ref = List
50 appender.routing.routes.route3.key = Service
51
52 appender.list.type = List
53 appender.list.name = List
54 appender.list.filters = threshold
55 appender.list.filter.threshold.type = ThresholdFilter
56 appender.list.filter.threshold.level = debug
57
58 loggers = event
59
60 logger.event.name = EventLogger
61 logger.event.level = info
62 logger.event.additivity = false
63 logger.event.appenderRefs = routing
64 logger.event.appenderRef.routing.ref = Routing
65
66 rootLogger.level = error
67 rootLogger.appenderRefs = stdout
68 rootLogger.appenderRef.stdout.ref = STDOUT
1919 <appender name="TestLogfile" class="org.apache.log4j.FileAppender">
2020 <param name="File" value="target/testlog4j.log"/>
2121 <param name="immediateFlush" value="false"/>
22 <param name="Append" value="false" />
2223 <layout class="org.apache.log4j.PatternLayout">
2324 <param name="ConversionPattern" value="%d %5p [%t] %c{1} %X{transactionId} - %m%n"/>
2425 </layout>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16
17 -->
18 <Configuration status="OFF">
19 <Appenders>
20 <Console name="Console" target="SYSTEM_OUT">
21 <PatternLayout noConsoleNoAnsi="true"
22 pattern="%style{%d}{white} %style{[%t]}{blue} %style{%-5level:}{yellow} %style{%msg%n%throwable{short}}{green}" />
23 </Console>
24 </Appenders>
25 <Loggers>
26 <Logger name="org.foo" level="DEBUG" />
27 <Root level="TRACE">
28 <AppenderRef ref="Console" />
29 </Root>
30 </Loggers>
31 </Configuration>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16
17 -->
18 <!-- https://issues.apache.org/jira/browse/LOG4J2-962 -->
19 <Configuration status="ALL">
20 <Appenders>
21 <List name="List">
22 <PatternLayout pattern="%d %msg%n" header="Header: ${main:0}" footer="Footer: ${main:1}" />
23 </List>
24 <File name="File" fileName="target/${main:0}.log" bufferedIO="false">
25 <PatternLayout>
26 <Pattern>%d %m%n</Pattern>
27 </PatternLayout>
28 </File>
29 </Appenders>
30 <Loggers>
31 <Root level="TRACE">
32 <AppenderRef ref="List" />
33 </Root>
34 </Loggers>
35 </Configuration>
2121 <PatternLayout pattern="%m%n"/>
2222 </Console>
2323 <List name="List2">
24 <PatternLayout pattern="${env:PATH} %m%n"/>
24 <PatternLayout pattern="%m%n"/>
2525 </List>
2626 <List name="List">
2727 </List>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16
17 -->
18 <Configuration status="WARN">
19 <Appenders>
20 <Console name="Console" target="SYSTEM_OUT">
21 <PatternLayout noConsoleNoAnsi="true" pattern="[%-5p] %d{yyyy/MM/dd HH:mm:ss} - %t - %c - %m%n" />
22 </Console>
23 </Appenders>
24 <Loggers>
25 <Logger name="org.foo" level="DEBUG" />
26 <Root level="TRACE">
27 <AppenderRef ref="Console" />
28 </Root>
29 </Loggers>
30 </Configuration>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16
17 -->
18 <Configuration status="OFF" name="NoConsoleNoAnsiTest">
19 <Appenders>
20 <List name="List">
21 <PatternLayout noConsoleNoAnsi="true">
22 <Pattern>%d %highlight{%p} %style{%logger}{bright,cyan} %C{1.} %msg%n</Pattern>
23 </PatternLayout>
24 </List>
25 </Appenders>
26
27 <Loggers>
28 <Root level="trace">
29 <AppenderRef ref="List"/>
30 </Root>
31 </Loggers>
32
33 </Configuration>
1818 <Configuration status="OFF">
1919 <Appenders>
2020 <Console name="Console" target="SYSTEM_OUT">
21 <PatternLayout pattern="%style{%d}{black} %style{[%t]}{blue} %style{%-5level:}{yellow} %style{%msg%n%throwable}{green}" />
21 <PatternLayout pattern="%style{%d}{white} %style{[%t]}{blue} %style{%-5level:}{yellow} %style{%msg%n%throwable}{green}" />
2222 </Console>
2323 </Appenders>
2424 <Loggers>
1818 <Configuration status="OFF">
1919 <Appenders>
2020 <Console name="Console" target="SYSTEM_OUT">
21 <PatternLayout pattern="%red{%d} %yellow{[%t]} %black{black} %blue{blue} %cyan{cyan} %magenta{magenta} %white{white} %green{%-5level:} %red{%msg%n%throwable}" />
21 <PatternLayout pattern="%red{%d} %yellow{[%t]} %black{white} %blue{blue} %cyan{cyan} %magenta{magenta} %white{white} %green{%-5level:} %red{%msg%n%throwable}" />
2222 </Console>
2323 </Appenders>
2424 <Loggers>
1919 <Appenders>
2020 <Console name="Console" target="SYSTEM_OUT">
2121 <PatternLayout noConsoleNoAnsi="true"
22 pattern="%style{%d}{black} %style{[%t]}{blue} %style{%-5level:}{yellow} %style{%msg%n%throwable}{green}" />
22 pattern="%style{%d}{white} %style{[%t]}{blue} %style{%-5level:}{yellow} %style{%msg%n%throwable}{green}" />
2323 </Console>
2424 </Appenders>
2525 <Loggers>
1717 -->
1818 <Configuration name="XMLPerfTest" status="OFF">
1919 <Appenders>
20 <File name="TestLogfile" fileName="target/testlog4j2.log" immediateFlush="false">
20 <File name="TestLogfile" fileName="target/testlog4j2.log" immediateFlush="false" append="false">
2121 <PatternLayout>
2222 <Pattern>%d %5p [%t] %c{1} %X{transactionId} - %m%n</Pattern>
2323 </PatternLayout>
0 # Licensed to the Apache Software Foundation (ASF) under one or more
1 # contributor license agreements. See the NOTICE file distributed with
2 # this work for additional information regarding copyright ownership.
3 # The ASF licenses this file to You under the Apache License, Version 2.0
4 # (the "License"); you may not use this file except in compliance with
5 # the License. You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 status = ERROR
16
17 filters = Threshold
18
19 filter.Threshold.type = ThresholdFilter
20 filter.Threshold.level = DEBUG
21
22 appenders = Stdout
23
24 appender.Stdout.type = Console
25 appender.Stdout.name = StdOut
26 appender.Stdout.target = SYSTEM_OUT
27 appender.Stdout.layout.type = PatternLayout
28 appender.Stdout.layout.pattern = %d [%t] %-5level: %msg%n%throwable
29 appender.Stdout.filters = marker
30 appender.Stdout.filter.marker.type = MarkerFilter
31 appender.Stdout.filter.marker.onMatch = DENY
32 appender.Stdout.filter.marker.onMisMatch = NEUTRAL
33 appender.Stdout.filter.marker.marker = FLOW
34
35 loggers = log4j
36
37 logger.log4j.name = org.apache.logging.log4j
38 logger.log4j.appenderRefs = console
39 logger.log4j.appenderRef.console.ref = StdOut
40 logger.log4j.level = DEBUG
41 logger.log4j.additivity = false
42
43 rootLogger.appenderRefs = console
44 rootLogger.appenderRef.console.ref = StdOut
45 rootLogger.level = ERROR
1717 <configuration>
1818 <appender name="TestLogfile" class="ch.qos.logback.core.FileAppender">
1919 <file>target/testlogback.log</file>
20 <append>false</append>
2021 <encoder>
2122 <immediateFlush>false</immediateFlush>
2223 <Pattern>%d %5p [%t] %c{0} %X{transactionId} - %m%n</Pattern>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16
17 -->
18 <Configuration status="OFF" name="XMLConfigTest">
19
20 <Appenders>
21 <List name="List">
22 </List>
23 </Appenders>
24 <Loggers>
25 <Root level="trace">
26 <AppenderRef ref="List"/>
27 </Root>
28 </Loggers>
29
30 </Configuration>
1919 <parent>
2020 <groupId>org.apache.logging.log4j</groupId>
2121 <artifactId>log4j</artifactId>
22 <version>2.2</version>
22 <version>2.4</version>
2323 <relativePath>../</relativePath>
2424 </parent>
2525 <artifactId>log4j-distribution</artifactId>
1919 <parent>
2020 <groupId>org.apache.logging.log4j</groupId>
2121 <artifactId>log4j</artifactId>
22 <version>2.2</version>
22 <version>2.4</version>
2323 <relativePath>../</relativePath>
2424 </parent>
2525 <artifactId>log4j-flume-ng</artifactId>
2525 */
2626 public class BatchEvent {
2727
28 private final List<Event> events = new ArrayList<Event>();
28 private final List<Event> events = new ArrayList<>();
2929
3030 public void addEvent(final Event event) {
3131 events.add(event);
246246 LOGGER.debug("No agents provided, using defaults");
247247 agents = new Agent[] {Agent.createAgent(null, null)};
248248 }
249 manager = FlumeAvroManager.getManager(name, agents, batchCount, retries, connectTimeoutMillis, reqTimeoutMillis);
249 manager = FlumeAvroManager.getManager(name, agents, batchCount, delayMillis, retries, connectTimeoutMillis, reqTimeoutMillis);
250250 break;
251251 case PERSISTENT:
252252 if (agents == null || agents.length == 0) {
262262 LOGGER.debug("No agents provided, using defaults");
263263 agents = new Agent[] {Agent.createAgent(null, null)};
264264 }
265 manager = FlumeAvroManager.getManager(name, agents, batchCount, retries, connectTimeoutMillis, reqTimeoutMillis);
265 manager = FlumeAvroManager.getManager(name, agents, batchCount, delayMillis, retries, connectTimeoutMillis, reqTimeoutMillis);
266266 }
267267
268268 if (manager == null) {
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.flume.appender;
17
18 import java.util.Properties;
19
20 import org.apache.flume.Event;
21 import org.apache.flume.api.RpcClient;
22 import org.apache.flume.api.RpcClientFactory;
23 import org.apache.logging.log4j.core.appender.AppenderLoggingException;
24 import org.apache.logging.log4j.core.appender.ManagerFactory;
25
26 /**
27 * Manager for FlumeAvroAppenders.
28 */
29 public class FlumeAvroManager extends AbstractFlumeManager {
30
31 private static final int MAX_RECONNECTS = 3;
32 private static final int MINIMUM_TIMEOUT = 1000;
33
34 private static AvroManagerFactory factory = new AvroManagerFactory();
35
36 private final Agent[] agents;
37
38 private final int batchSize;
39
40 private final int retries;
41
42 private final int connectTimeoutMillis;
43
44 private final int requestTimeoutMillis;
45
46 private final int current = 0;
47
48 private RpcClient rpcClient = null;
49
50 /**
51 * Constructor
52 * @param name The unique name of this manager.
53 * @param agents An array of Agents.
54 * @param batchSize The number of events to include in a batch.
55 * @param retries The number of times to retry connecting before giving up.
56 * @param connectTimeout The connection timeout in ms.
57 * @param requestTimeout The request timeout in ms.
58 *
59 */
60 protected FlumeAvroManager(final String name, final String shortName, final Agent[] agents, final int batchSize,
61 final int retries, final int connectTimeout, final int requestTimeout) {
62 super(name);
63 this.agents = agents;
64 this.batchSize = batchSize;
65 this.retries = retries;
66 this.connectTimeoutMillis = connectTimeout;
67 this.requestTimeoutMillis = requestTimeout;
68 this.rpcClient = connect(agents, retries, connectTimeout, requestTimeout);
69 }
70
71 /**
72 * Returns a FlumeAvroManager.
73 * @param name The name of the manager.
74 * @param agents The agents to use.
75 * @param batchSize The number of events to include in a batch.
76 * @param retries The number of times to retry connecting before giving up.
77 * @param connectTimeoutMillis The connection timeout in ms.
78 * @param requestTimeoutMillis The request timeout in ms.
79 * @return A FlumeAvroManager.
80 */
81 public static FlumeAvroManager getManager(final String name, final Agent[] agents, int batchSize,
82 final int retries, final int connectTimeoutMillis, final int requestTimeoutMillis) {
83 if (agents == null || agents.length == 0) {
84 throw new IllegalArgumentException("At least one agent is required");
85 }
86
87 if (batchSize <= 0) {
88 batchSize = 1;
89 }
90
91 final StringBuilder sb = new StringBuilder("FlumeAvro[");
92 boolean first = true;
93 for (final Agent agent : agents) {
94 if (!first) {
95 sb.append(',');
96 }
97 sb.append(agent.getHost()).append(':').append(agent.getPort());
98 first = false;
99 }
100 sb.append(']');
101 return getManager(sb.toString(), factory,
102 new FactoryData(name, agents, batchSize, retries, connectTimeoutMillis, requestTimeoutMillis));
103 }
104
105 /**
106 * Returns the agents.
107 * @return The agent array.
108 */
109 public Agent[] getAgents() {
110 return agents;
111 }
112
113 /**
114 * Returns the index of the current agent.
115 * @return The index for the current agent.
116 */
117 public int getCurrent() {
118 return current;
119 }
120
121 public int getRetries() {
122 return retries;
123 }
124
125 public int getConnectTimeoutMillis() {
126 return connectTimeoutMillis;
127 }
128
129 public int getRequestTimeoutMillis() {
130 return requestTimeoutMillis;
131 }
132
133 public int getBatchSize() {
134 return batchSize;
135 }
136
137 public synchronized void send(final BatchEvent events) {
138 if (rpcClient == null) {
139 rpcClient = connect(agents, retries, connectTimeoutMillis, requestTimeoutMillis);
140 }
141
142 if (rpcClient != null) {
143 try {
144 LOGGER.trace("Sending batch of {} events", events.getEvents().size());
145 rpcClient.appendBatch(events.getEvents());
146 } catch (final Exception ex) {
147 rpcClient.close();
148 rpcClient = null;
149 final String msg = "Unable to write to " + getName() + " at " + agents[current].getHost() + ':' +
150 agents[current].getPort();
151 LOGGER.warn(msg, ex);
152 throw new AppenderLoggingException("No Flume agents are available");
153 }
154 } else {
155 final String msg = "Unable to write to " + getName() + " at " + agents[current].getHost() + ':' +
156 agents[current].getPort();
157 LOGGER.warn(msg);
158 throw new AppenderLoggingException("No Flume agents are available");
159 }
160 }
161
162 @Override
163 public synchronized void send(final Event event) {
164 if (rpcClient == null) {
165 rpcClient = connect(agents, retries, connectTimeoutMillis, requestTimeoutMillis);
166 }
167
168 if (rpcClient != null) {
169 try {
170 rpcClient.append(event);
171 } catch (final Exception ex) {
172 rpcClient.close();
173 rpcClient = null;
174 final String msg = "Unable to write to " + getName() + " at " + agents[current].getHost() + ':' +
175 agents[current].getPort();
176 LOGGER.warn(msg, ex);
177 throw new AppenderLoggingException("No Flume agents are available");
178 }
179 } else {
180 final String msg = "Unable to write to " + getName() + " at " + agents[current].getHost() + ':' +
181 agents[current].getPort();
182 LOGGER.warn(msg);
183 throw new AppenderLoggingException("No Flume agents are available");
184 }
185 }
186
187 /**
188 * There is a very good chance that this will always return the first agent even if it isn't available.
189 * @param agents The list of agents to choose from
190 * @return The FlumeEventAvroServer.
191 */
192 private RpcClient connect(final Agent[] agents, int retries, final int connectTimeoutMillis, final int requestTimeoutMillis) {
193 try {
194 final Properties props = new Properties();
195
196 props.put("client.type", "default_failover");
197
198 int count = 1;
199 final StringBuilder sb = new StringBuilder();
200 for (final Agent agent : agents) {
201 if (sb.length() > 0) {
202 sb.append(' ');
203 }
204 final String hostName = "host" + count++;
205 props.put("hosts." + hostName, agent.getHost() + ':' + agent.getPort());
206 sb.append(hostName);
207 }
208 props.put("hosts", sb.toString());
209 if (batchSize > 0) {
210 props.put("batch-size", Integer.toString(batchSize));
211 }
212 if (retries > 1) {
213 if (retries > MAX_RECONNECTS) {
214 retries = MAX_RECONNECTS;
215 }
216 props.put("max-attempts", Integer.toString(retries * agents.length));
217 }
218 if (requestTimeoutMillis >= MINIMUM_TIMEOUT) {
219 props.put("request-timeout", Integer.toString(requestTimeoutMillis));
220 }
221 if (connectTimeoutMillis >= MINIMUM_TIMEOUT) {
222 props.put("connect-timeout", Integer.toString(connectTimeoutMillis));
223 }
224 return RpcClientFactory.getInstance(props);
225 } catch (final Exception ex) {
226 LOGGER.error("Unable to create Flume RPCClient: {}", ex.getMessage());
227 return null;
228 }
229 }
230
231 @Override
232 protected void releaseSub() {
233 if (rpcClient != null) {
234 try {
235 rpcClient.close();
236 } catch (final Exception ex) {
237 LOGGER.error("Attempt to close RPC client failed", ex);
238 }
239 }
240 rpcClient = null;
241 }
242
243 /**
244 * Factory data.
245 */
246 private static class FactoryData {
247 private final String name;
248 private final Agent[] agents;
249 private final int batchSize;
250 private final int retries;
251 private final int conntectTimeoutMillis;
252 private final int requestTimeoutMillis;
253
254 /**
255 * Constructor.
256 * @param name The name of the Appender.
257 * @param agents The agents.
258 * @param batchSize The number of events to include in a batch.
259 */
260 public FactoryData(final String name, final Agent[] agents, final int batchSize, final int retries,
261 final int connectTimeoutMillis, final int requestTimeoutMillis) {
262 this.name = name;
263 this.agents = agents;
264 this.batchSize = batchSize;
265 this.retries = retries;
266 this.conntectTimeoutMillis = connectTimeoutMillis;
267 this.requestTimeoutMillis = requestTimeoutMillis;
268 }
269 }
270
271 /**
272 * Avro Manager Factory.
273 */
274 private static class AvroManagerFactory implements ManagerFactory<FlumeAvroManager, FactoryData> {
275
276 /**
277 * Create the FlumeAvroManager.
278 * @param name The name of the entity to manage.
279 * @param data The data required to create the entity.
280 * @return The FlumeAvroManager.
281 */
282 @Override
283 public FlumeAvroManager createManager(final String name, final FactoryData data) {
284 try {
285
286 return new FlumeAvroManager(name, data.name, data.agents, data.batchSize, data.retries,
287 data.conntectTimeoutMillis, data.requestTimeoutMillis);
288 } catch (final Exception ex) {
289 LOGGER.error("Could not create FlumeAvroManager", ex);
290 }
291 return null;
292 }
293 }
294
295 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.flume.appender;
17
18 import java.util.Properties;
19
20 import org.apache.flume.Event;
21 import org.apache.flume.api.RpcClient;
22 import org.apache.flume.api.RpcClientFactory;
23 import org.apache.logging.log4j.core.appender.AppenderLoggingException;
24 import org.apache.logging.log4j.core.appender.ManagerFactory;
25
26 /**
27 * Manager for FlumeAvroAppenders.
28 */
29 public class FlumeAvroManager extends AbstractFlumeManager {
30
31 private static final int MAX_RECONNECTS = 3;
32 private static final int MINIMUM_TIMEOUT = 1000;
33
34 private static AvroManagerFactory factory = new AvroManagerFactory();
35
36 private final Agent[] agents;
37
38 private final int batchSize;
39
40 private final long delayNanos;
41 private final int delayMillis;
42
43 private final int retries;
44
45 private final int connectTimeoutMillis;
46
47 private final int requestTimeoutMillis;
48
49 private final int current = 0;
50
51 private RpcClient rpcClient = null;
52
53 private BatchEvent batchEvent = new BatchEvent();
54 private long nextSend = 0;
55
56 /**
57 * Constructor
58 * @param name The unique name of this manager.
59 * @param agents An array of Agents.
60 * @param batchSize The number of events to include in a batch.
61 * @param retries The number of times to retry connecting before giving up.
62 * @param connectTimeout The connection timeout in ms.
63 * @param requestTimeout The request timeout in ms.
64 *
65 */
66 protected FlumeAvroManager(final String name, final String shortName, final Agent[] agents, final int batchSize,
67 final int delayMillis, final int retries, final int connectTimeout, final int requestTimeout) {
68 super(name);
69 this.agents = agents;
70 this.batchSize = batchSize;
71 this.delayMillis = delayMillis;
72 this.delayNanos = delayMillis * 1000000;
73 this.retries = retries;
74 this.connectTimeoutMillis = connectTimeout;
75 this.requestTimeoutMillis = requestTimeout;
76 this.rpcClient = connect(agents, retries, connectTimeout, requestTimeout);
77 }
78
79 /**
80 * Returns a FlumeAvroManager.
81 * @param name The name of the manager.
82 * @param agents The agents to use.
83 * @param batchSize The number of events to include in a batch.
84 * @param delayMillis The number of milliseconds to wait before sending an incomplete batch.
85 * @param retries The number of times to retry connecting before giving up.
86 * @param connectTimeoutMillis The connection timeout in ms.
87 * @param requestTimeoutMillis The request timeout in ms.
88 * @return A FlumeAvroManager.
89 */
90 public static FlumeAvroManager getManager(final String name, final Agent[] agents, int batchSize, final int delayMillis,
91 final int retries, final int connectTimeoutMillis, final int requestTimeoutMillis) {
92 if (agents == null || agents.length == 0) {
93 throw new IllegalArgumentException("At least one agent is required");
94 }
95
96 if (batchSize <= 0) {
97 batchSize = 1;
98 }
99
100 final StringBuilder sb = new StringBuilder("FlumeAvro[");
101 boolean first = true;
102 for (final Agent agent : agents) {
103 if (!first) {
104 sb.append(',');
105 }
106 sb.append(agent.getHost()).append(':').append(agent.getPort());
107 first = false;
108 }
109 sb.append(']');
110 return getManager(sb.toString(), factory,
111 new FactoryData(name, agents, batchSize, delayMillis, retries, connectTimeoutMillis, requestTimeoutMillis));
112 }
113
114 /**
115 * Returns the agents.
116 * @return The agent array.
117 */
118 public Agent[] getAgents() {
119 return agents;
120 }
121
122 /**
123 * Returns the index of the current agent.
124 * @return The index for the current agent.
125 */
126 public int getCurrent() {
127 return current;
128 }
129
130 public int getRetries() {
131 return retries;
132 }
133
134 public int getConnectTimeoutMillis() {
135 return connectTimeoutMillis;
136 }
137
138 public int getRequestTimeoutMillis() {
139 return requestTimeoutMillis;
140 }
141
142 public int getBatchSize() {
143 return batchSize;
144 }
145
146 public int getDelayMillis() {
147 return delayMillis;
148 }
149
150 public synchronized void send(final BatchEvent events) {
151 if (rpcClient == null) {
152 rpcClient = connect(agents, retries, connectTimeoutMillis, requestTimeoutMillis);
153 }
154
155 if (rpcClient != null) {
156 try {
157 LOGGER.trace("Sending batch of {} events", events.getEvents().size());
158 rpcClient.appendBatch(events.getEvents());
159 } catch (final Exception ex) {
160 rpcClient.close();
161 rpcClient = null;
162 final String msg = "Unable to write to " + getName() + " at " + agents[current].getHost() + ':' +
163 agents[current].getPort();
164 LOGGER.warn(msg, ex);
165 throw new AppenderLoggingException("No Flume agents are available");
166 }
167 } else {
168 final String msg = "Unable to write to " + getName() + " at " + agents[current].getHost() + ':' +
169 agents[current].getPort();
170 LOGGER.warn(msg);
171 throw new AppenderLoggingException("No Flume agents are available");
172 }
173 }
174
175 @Override
176 public synchronized void send(final Event event) {
177 if (batchSize == 1) {
178 if (rpcClient == null) {
179 rpcClient = connect(agents, retries, connectTimeoutMillis, requestTimeoutMillis);
180 }
181
182 if (rpcClient != null) {
183 try {
184 rpcClient.append(event);
185 } catch (final Exception ex) {
186 rpcClient.close();
187 rpcClient = null;
188 final String msg = "Unable to write to " + getName() + " at " + agents[current].getHost() + ':' +
189 agents[current].getPort();
190 LOGGER.warn(msg, ex);
191 throw new AppenderLoggingException("No Flume agents are available");
192 }
193 } else {
194 final String msg = "Unable to write to " + getName() + " at " + agents[current].getHost() + ':' +
195 agents[current].getPort();
196 LOGGER.warn(msg);
197 throw new AppenderLoggingException("No Flume agents are available");
198 }
199 } else {
200 batchEvent.addEvent(event);
201 final int eventCount = batchEvent.getEvents().size();
202 if (eventCount == 1) {
203 nextSend = System.nanoTime() + delayNanos;
204 }
205 if (eventCount >= batchSize || System.nanoTime() >= nextSend) {
206 send(batchEvent);
207 batchEvent = new BatchEvent();
208 }
209 }
210 }
211
212 /**
213 * There is a very good chance that this will always return the first agent even if it isn't available.
214 * @param agents The list of agents to choose from
215 * @return The FlumeEventAvroServer.
216 */
217 private RpcClient connect(final Agent[] agents, int retries, final int connectTimeoutMillis, final int requestTimeoutMillis) {
218 try {
219 final Properties props = new Properties();
220
221 props.put("client.type", "default_failover");
222
223 int agentCount = 1;
224 final StringBuilder sb = new StringBuilder();
225 for (final Agent agent : agents) {
226 if (sb.length() > 0) {
227 sb.append(' ');
228 }
229 final String hostName = "host" + agentCount++;
230 props.put("hosts." + hostName, agent.getHost() + ':' + agent.getPort());
231 sb.append(hostName);
232 }
233 props.put("hosts", sb.toString());
234 if (batchSize > 0) {
235 props.put("batch-size", Integer.toString(batchSize));
236 }
237 if (retries > 1) {
238 if (retries > MAX_RECONNECTS) {
239 retries = MAX_RECONNECTS;
240 }
241 props.put("max-attempts", Integer.toString(retries * agents.length));
242 }
243 if (requestTimeoutMillis >= MINIMUM_TIMEOUT) {
244 props.put("request-timeout", Integer.toString(requestTimeoutMillis));
245 }
246 if (connectTimeoutMillis >= MINIMUM_TIMEOUT) {
247 props.put("connect-timeout", Integer.toString(connectTimeoutMillis));
248 }
249 return RpcClientFactory.getInstance(props);
250 } catch (final Exception ex) {
251 LOGGER.error("Unable to create Flume RPCClient: {}", ex.getMessage());
252 return null;
253 }
254 }
255
256 @Override
257 protected void releaseSub() {
258 if (rpcClient != null) {
259 try {
260 synchronized(this) {
261 try {
262 if (batchSize > 1 && batchEvent.getEvents().size() > 0) {
263 send(batchEvent);
264 }
265 } catch (final Exception ex) {
266 LOGGER.error("Error sending final batch: {}", ex.getMessage());
267 }
268 }
269 rpcClient.close();
270 } catch (final Exception ex) {
271 LOGGER.error("Attempt to close RPC client failed", ex);
272 }
273 }
274 rpcClient = null;
275 }
276
277 /**
278 * Factory data.
279 */
280 private static class FactoryData {
281 private final String name;
282 private final Agent[] agents;
283 private final int batchSize;
284 private final int delayMillis;
285 private final int retries;
286 private final int conntectTimeoutMillis;
287 private final int requestTimeoutMillis;
288
289 /**
290 * Constructor.
291 * @param name The name of the Appender.
292 * @param agents The agents.
293 * @param batchSize The number of events to include in a batch.
294 */
295 public FactoryData(final String name, final Agent[] agents, final int batchSize, final int delayMillis,
296 final int retries, final int connectTimeoutMillis, final int requestTimeoutMillis) {
297 this.name = name;
298 this.agents = agents;
299 this.batchSize = batchSize;
300 this.delayMillis = delayMillis;
301 this.retries = retries;
302 this.conntectTimeoutMillis = connectTimeoutMillis;
303 this.requestTimeoutMillis = requestTimeoutMillis;
304 }
305 }
306
307 /**
308 * Avro Manager Factory.
309 */
310 private static class AvroManagerFactory implements ManagerFactory<FlumeAvroManager, FactoryData> {
311
312 /**
313 * Create the FlumeAvroManager.
314 * @param name The name of the entity to manage.
315 * @param data The data required to create the entity.
316 * @return The FlumeAvroManager.
317 */
318 @Override
319 public FlumeAvroManager createManager(final String name, final FactoryData data) {
320 try {
321
322 return new FlumeAvroManager(name, data.name, data.agents, data.batchSize, data.delayMillis,
323 data.retries, data.conntectTimeoutMillis, data.requestTimeoutMillis);
324 } catch (final Exception ex) {
325 LOGGER.error("Could not create FlumeAvroManager", ex);
326 }
327 return null;
328 }
329 }
330
331 }
179179
180180 private Map<String, String> createProperties(final String name, final Agent[] agents,
181181 final Property[] properties, final int batchSize, String dataDir) {
182 final Map<String, String> props = new HashMap<String, String>();
182 final Map<String, String> props = new HashMap<>();
183183
184184 if ((agents == null || agents.length == 0) && (properties == null || properties.length == 0)) {
185185 LOGGER.error("No Flume configuration provided");
193193
194194 if (agents != null && agents.length > 0) {
195195
196 if (dataDir != null && dataDir.length() > 0) {
196 if (Strings.isNotEmpty(dataDir)) {
197197 if (dataDir.equals(IN_MEMORY)) {
198198 props.put("channel.type", "memory");
199199 } else {
6161
6262 private final LogEvent event;
6363
64 private final Map<String, String> contextMap = new HashMap<String, String>();
64 private final Map<String, String> contextMap = new HashMap<>();
6565
6666 private final boolean compress;
6767
101101 } else if (excludes != null) {
102102 final String[] array = excludes.split(Patterns.COMMA_SEPARATOR);
103103 if (array.length > 0) {
104 final List<String> list = new ArrayList<String>(array.length);
104 final List<String> list = new ArrayList<>(array.length);
105105 for (final String value : array) {
106106 list.add(value.trim());
107107 }
158158
159159 protected void addContextData(final String prefix, final Map<String, String> fields,
160160 final Map<String, String> context) {
161 final Map<String, String> map = new HashMap<String, String>();
161 final Map<String, String> map = new HashMap<>();
162162 for (final Map.Entry<String, String> entry : context.entrySet()) {
163163 if (entry.getKey() != null && entry.getValue() != null) {
164164 fields.put(prefix + entry.getKey(), entry.getValue());
181181 }
182182 if (compress) {
183183 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
184 try {
185 final GZIPOutputStream os = new GZIPOutputStream(baos);
184 try (GZIPOutputStream os = new GZIPOutputStream(baos)) {
186185 os.write(body);
187 os.close();
188186 } catch (final IOException ioe) {
189187 throw new LoggingException("Unable to compress message", ioe);
190188 }
267265 }
268266
269267 /**
268 * Returns the value of the running Java Virtual Machine's high-resolution time source when this event was created,
269 * or a dummy value if it is known that this value will not be used downstream.
270 * @return the event nanosecond timestamp.
271 */
272 @Override
273 public long getNanoTime() {
274 return event.getNanoTime();
275 }
276
277 /**
270278 * Returns the Throwable associated with the event, if any.
271279 * @return the Throwable.
272280 */
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.flume.appender;
17
18 import java.io.ByteArrayInputStream;
19 import java.io.ByteArrayOutputStream;
20 import java.io.DataInputStream;
21 import java.io.DataOutputStream;
22 import java.io.File;
23 import java.nio.charset.Charset;
24 import java.util.HashMap;
25 import java.util.Map;
26 import java.util.concurrent.Callable;
27 import java.util.concurrent.ExecutorService;
28 import java.util.concurrent.Executors;
29 import java.util.concurrent.Future;
30 import java.util.concurrent.ThreadFactory;
31 import java.util.concurrent.TimeUnit;
32 import java.util.concurrent.atomic.AtomicInteger;
33 import java.util.concurrent.atomic.AtomicLong;
34
35 import javax.crypto.Cipher;
36 import javax.crypto.SecretKey;
37
38 import org.apache.flume.Event;
39 import org.apache.flume.event.SimpleEvent;
40 import org.apache.logging.log4j.LoggingException;
41 import org.apache.logging.log4j.core.appender.ManagerFactory;
42 import org.apache.logging.log4j.core.config.Property;
43 import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
44 import org.apache.logging.log4j.core.config.plugins.util.PluginType;
45 import org.apache.logging.log4j.core.util.FileUtils;
46 import org.apache.logging.log4j.core.util.SecretKeyProvider;
47 import org.apache.logging.log4j.util.Strings;
48
49 import com.sleepycat.je.Cursor;
50 import com.sleepycat.je.CursorConfig;
51 import com.sleepycat.je.Database;
52 import com.sleepycat.je.DatabaseConfig;
53 import com.sleepycat.je.DatabaseEntry;
54 import com.sleepycat.je.Environment;
55 import com.sleepycat.je.EnvironmentConfig;
56 import com.sleepycat.je.LockConflictException;
57 import com.sleepycat.je.LockMode;
58 import com.sleepycat.je.OperationStatus;
59 import com.sleepycat.je.StatsConfig;
60 import com.sleepycat.je.Transaction;
61
62 /**
63 * Manager that persists data to Berkeley DB before passing it on to Flume.
64 */
65 public class FlumePersistentManager extends FlumeAvroManager {
66
67 /** Attribute name for the key provider. */
68 public static final String KEY_PROVIDER = "keyProvider";
69
70 private static final Charset UTF8 = Charset.forName("UTF-8");
71
72 private static final String DEFAULT_DATA_DIR = ".log4j/flumeData";
73
74 private static final int SHUTDOWN_WAIT = 60;
75
76 private static final int MILLIS_PER_SECOND = 1000;
77
78 private static final int LOCK_TIMEOUT_SLEEP_MILLIS = 500;
79
80 private static BDBManagerFactory factory = new BDBManagerFactory();
81
82 private final Database database;
83
84 private final Environment environment;
85
86 private final WriterThread worker;
87
88 private final Gate gate = new Gate();
89
90 private final SecretKey secretKey;
91
92 private final int delayMillis;
93
94 private final int lockTimeoutRetryCount;
95
96 private final ExecutorService threadPool;
97
98 private final AtomicLong dbCount = new AtomicLong();
99
100 /**
101 * Constructor
102 * @param name The unique name of this manager.
103 * @param shortName Original name for the Manager.
104 * @param agents An array of Agents.
105 * @param batchSize The number of events to include in a batch.
106 * @param retries The number of times to retry connecting before giving up.
107 * @param connectionTimeout The amount of time to wait for a connection to be established.
108 * @param requestTimeout The amount of time to wair for a response to a request.
109 * @param delay The amount of time to wait between retries.
110 * @param database The database to write to.
111 * @param environment The database environment.
112 * @param secretKey The SecretKey to use for encryption.
113 * @param lockTimeoutRetryCount The number of times to retry a lock timeout.
114 */
115 protected FlumePersistentManager(final String name, final String shortName, final Agent[] agents,
116 final int batchSize, final int retries, final int connectionTimeout,
117 final int requestTimeout, final int delay, final Database database,
118 final Environment environment, final SecretKey secretKey,
119 final int lockTimeoutRetryCount) {
120 super(name, shortName, agents, batchSize, retries, connectionTimeout, requestTimeout);
121 this.delayMillis = delay;
122 this.database = database;
123 this.environment = environment;
124 dbCount.set(database.count());
125 this.worker = new WriterThread(database, environment, this, gate, batchSize, secretKey, dbCount,
126 lockTimeoutRetryCount);
127 this.worker.start();
128 this.secretKey = secretKey;
129 this.threadPool = Executors.newCachedThreadPool(new DaemonThreadFactory());
130 this.lockTimeoutRetryCount = lockTimeoutRetryCount;
131 }
132
133
134 /**
135 * Returns a FlumeAvroManager.
136 * @param name The name of the manager.
137 * @param agents The agents to use.
138 * @param properties Properties to pass to the Manager.
139 * @param batchSize The number of events to include in a batch.
140 * @param retries The number of times to retry connecting before giving up.
141 * @param connectionTimeout The amount of time to wait to establish a connection.
142 * @param requestTimeout The amount of time to wait for a response to a request.
143 * @param delayMillis Amount of time to delay before delivering a batch.
144 * @param lockTimeoutRetryCount The number of times to retry after a lock timeout.
145 * @param dataDir The location of the Berkeley database.
146 * @return A FlumeAvroManager.
147 */
148 public static FlumePersistentManager getManager(final String name, final Agent[] agents,
149 final Property[] properties, int batchSize, final int retries,
150 final int connectionTimeout, final int requestTimeout,
151 final int delayMillis, final int lockTimeoutRetryCount,
152 final String dataDir) {
153 if (agents == null || agents.length == 0) {
154 throw new IllegalArgumentException("At least one agent is required");
155 }
156
157 if (batchSize <= 0) {
158 batchSize = 1;
159 }
160 final String dataDirectory = Strings.isEmpty(dataDir) ? DEFAULT_DATA_DIR : dataDir;
161
162 final StringBuilder sb = new StringBuilder("FlumePersistent[");
163 boolean first = true;
164 for (final Agent agent : agents) {
165 if (!first) {
166 sb.append(',');
167 }
168 sb.append(agent.getHost()).append(':').append(agent.getPort());
169 first = false;
170 }
171 sb.append(']');
172 sb.append(' ').append(dataDirectory);
173 return getManager(sb.toString(), factory, new FactoryData(name, agents, batchSize, retries,
174 connectionTimeout, requestTimeout, delayMillis, lockTimeoutRetryCount, dataDir, properties));
175 }
176
177 @Override
178 public void send(final Event event) {
179 if (worker.isShutdown()) {
180 throw new LoggingException("Unable to record event");
181 }
182
183 final Map<String, String> headers = event.getHeaders();
184 final byte[] keyData = headers.get(FlumeEvent.GUID).getBytes(UTF8);
185 try {
186 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
187 final DataOutputStream daos = new DataOutputStream(baos);
188 daos.writeInt(event.getBody().length);
189 daos.write(event.getBody(), 0, event.getBody().length);
190 daos.writeInt(event.getHeaders().size());
191 for (final Map.Entry<String, String> entry : headers.entrySet()) {
192 daos.writeUTF(entry.getKey());
193 daos.writeUTF(entry.getValue());
194 }
195 byte[] eventData = baos.toByteArray();
196 if (secretKey != null) {
197 final Cipher cipher = Cipher.getInstance("AES");
198 cipher.init(Cipher.ENCRYPT_MODE, secretKey);
199 eventData = cipher.doFinal(eventData);
200 }
201 final Future<Integer> future = threadPool.submit(new BDBWriter(keyData, eventData, environment, database,
202 gate, dbCount, getBatchSize(), lockTimeoutRetryCount));
203 boolean interrupted = false;
204 int count = 0;
205 do {
206 try {
207 future.get();
208 } catch (final InterruptedException ie) {
209 interrupted = true;
210 ++count;
211 }
212 } while (interrupted && count <= 1);
213
214 } catch (final Exception ex) {
215 throw new LoggingException("Exception occurred writing log event", ex);
216 }
217 }
218
219 @Override
220 protected void releaseSub() {
221 LOGGER.debug("Shutting down FlumePersistentManager");
222 worker.shutdown();
223 try {
224 worker.join(SHUTDOWN_WAIT * MILLIS_PER_SECOND);
225 } catch (final InterruptedException ie) {
226 // Ignore the exception and shutdown.
227 }
228 threadPool.shutdown();
229 try {
230 threadPool.awaitTermination(SHUTDOWN_WAIT, TimeUnit.SECONDS);
231 } catch (final InterruptedException ie) {
232 LOGGER.warn("PersistentManager Thread pool failed to shut down");
233 }
234 try {
235 worker.join();
236 } catch (final InterruptedException ex) {
237 LOGGER.debug("Interrupted while waiting for worker to complete");
238 }
239 try {
240 LOGGER.debug("FlumePersistenceManager dataset status: {}", database.getStats(new StatsConfig()));
241 database.close();
242 } catch (final Exception ex) {
243 LOGGER.warn("Failed to close database", ex);
244 }
245 try {
246 environment.cleanLog();
247 environment.close();
248 } catch (final Exception ex) {
249 LOGGER.warn("Failed to close environment", ex);
250 }
251 super.releaseSub();
252 }
253
254 private void doSend(final SimpleEvent event) {
255 LOGGER.debug("Sending event to Flume");
256 super.send(event);
257 }
258
259 /**
260 * Thread for writing to Berkeley DB to avoid having interrupts close the database.
261 */
262 private static class BDBWriter implements Callable<Integer> {
263 private final byte[] eventData;
264 private final byte[] keyData;
265 private final Environment environment;
266 private final Database database;
267 private final Gate gate;
268 private final AtomicLong dbCount;
269 private final long batchSize;
270 private final int lockTimeoutRetryCount;
271
272 public BDBWriter(final byte[] keyData, final byte[] eventData, final Environment environment,
273 final Database database, final Gate gate, final AtomicLong dbCount, final long batchSize,
274 final int lockTimeoutRetryCount) {
275 this.keyData = keyData;
276 this.eventData = eventData;
277 this.environment = environment;
278 this.database = database;
279 this.gate = gate;
280 this.dbCount = dbCount;
281 this.batchSize = batchSize;
282 this.lockTimeoutRetryCount = lockTimeoutRetryCount;
283 }
284
285 @Override
286 public Integer call() throws Exception {
287 final DatabaseEntry key = new DatabaseEntry(keyData);
288 final DatabaseEntry data = new DatabaseEntry(eventData);
289 Exception exception = null;
290 for (int retryIndex = 0; retryIndex < lockTimeoutRetryCount; ++retryIndex) {
291 Transaction txn = null;
292 try {
293 txn = environment.beginTransaction(null, null);
294 try {
295 database.put(txn, key, data);
296 txn.commit();
297 txn = null;
298 if (dbCount.incrementAndGet() >= batchSize) {
299 gate.open();
300 }
301 exception = null;
302 break;
303 } catch (final LockConflictException lce) {
304 exception = lce;
305 // Fall through and retry.
306 } catch (final Exception ex) {
307 if (txn != null) {
308 txn.abort();
309 }
310 throw ex;
311 } finally {
312 if (txn != null) {
313 txn.abort();
314 txn = null;
315 }
316 }
317 } catch (final LockConflictException lce) {
318 exception = lce;
319 if (txn != null) {
320 try {
321 txn.abort();
322 txn = null;
323 } catch (final Exception ex) {
324 LOGGER.trace("Ignoring exception while aborting transaction during lock conflict.");
325 }
326 }
327
328 }
329 try {
330 Thread.sleep(LOCK_TIMEOUT_SLEEP_MILLIS);
331 } catch (final InterruptedException ie) {
332 // Ignore the error
333 }
334 }
335 if (exception != null) {
336 throw exception;
337 }
338 return eventData.length;
339 }
340 }
341
342 /**
343 * Factory data.
344 */
345 private static class FactoryData {
346 private final String name;
347 private final Agent[] agents;
348 private final int batchSize;
349 private final String dataDir;
350 private final int retries;
351 private final int connectionTimeout;
352 private final int requestTimeout;
353 private final int delayMillis;
354 private final int lockTimeoutRetryCount;
355 private final Property[] properties;
356
357 /**
358 * Constructor.
359 * @param name The name of the Appender.
360 * @param agents The agents.
361 * @param batchSize The number of events to include in a batch.
362 * @param dataDir The directory for data.
363 */
364 public FactoryData(final String name, final Agent[] agents, final int batchSize, final int retries,
365 final int connectionTimeout, final int requestTimeout, final int delayMillis,
366 final int lockTimeoutRetryCount, final String dataDir, final Property[] properties) {
367 this.name = name;
368 this.agents = agents;
369 this.batchSize = batchSize;
370 this.dataDir = dataDir;
371 this.retries = retries;
372 this.connectionTimeout = connectionTimeout;
373 this.requestTimeout = requestTimeout;
374 this.delayMillis = delayMillis;
375 this.lockTimeoutRetryCount = lockTimeoutRetryCount;
376 this.properties = properties;
377 }
378 }
379
380 /**
381 * Avro Manager Factory.
382 */
383 private static class BDBManagerFactory implements ManagerFactory<FlumePersistentManager, FactoryData> {
384
385 /**
386 * Create the FlumeKratiManager.
387 * @param name The name of the entity to manage.
388 * @param data The data required to create the entity.
389 * @return The FlumeKratiManager.
390 */
391 @Override
392 public FlumePersistentManager createManager(final String name, final FactoryData data) {
393 SecretKey secretKey = null;
394 Database database = null;
395 Environment environment = null;
396
397 final Map<String, String> properties = new HashMap<String, String>();
398 if (data.properties != null) {
399 for (final Property property : data.properties) {
400 properties.put(property.getName(), property.getValue());
401 }
402 }
403
404 try {
405 final File dir = new File(data.dataDir);
406 FileUtils.mkdir(dir, true);
407 final EnvironmentConfig dbEnvConfig = new EnvironmentConfig();
408 dbEnvConfig.setTransactional(true);
409 dbEnvConfig.setAllowCreate(true);
410 dbEnvConfig.setLockTimeout(5, TimeUnit.SECONDS);
411 environment = new Environment(dir, dbEnvConfig);
412 final DatabaseConfig dbConfig = new DatabaseConfig();
413 dbConfig.setTransactional(true);
414 dbConfig.setAllowCreate(true);
415 database = environment.openDatabase(null, name, dbConfig);
416 } catch (final Exception ex) {
417 LOGGER.error("Could not create FlumePersistentManager", ex);
418 // For consistency, close database as well as environment even though it should never happen since the
419 // database is that last thing in the block above, but this does guard against a future line being
420 // inserted at the end that would bomb (like some debug logging).
421 if (database != null) {
422 database.close();
423 database = null;
424 }
425 if (environment != null) {
426 environment.close();
427 environment = null;
428 }
429 return null;
430 }
431
432 try {
433 String key = null;
434 for (final Map.Entry<String, String> entry : properties.entrySet()) {
435 if (entry.getKey().equalsIgnoreCase(KEY_PROVIDER)) {
436 key = entry.getValue();
437 break;
438 }
439 }
440 if (key != null) {
441 final PluginManager manager = new PluginManager("KeyProvider");
442 manager.collectPlugins();
443 final Map<String, PluginType<?>> plugins = manager.getPlugins();
444 if (plugins != null) {
445 boolean found = false;
446 for (final Map.Entry<String, PluginType<?>> entry : plugins.entrySet()) {
447 if (entry.getKey().equalsIgnoreCase(key)) {
448 found = true;
449 final Class<?> cl = entry.getValue().getPluginClass();
450 try {
451 final SecretKeyProvider provider = (SecretKeyProvider) cl.newInstance();
452 secretKey = provider.getSecretKey();
453 LOGGER.debug("Persisting events using SecretKeyProvider {}", cl.getName());
454 } catch (final Exception ex) {
455 LOGGER.error("Unable to create SecretKeyProvider {}, encryption will be disabled",
456 cl.getName());
457 }
458 break;
459 }
460 }
461 if (!found) {
462 LOGGER.error("Unable to locate SecretKey provider {}, encryption will be disabled", key);
463 }
464 } else {
465 LOGGER.error("Unable to locate SecretKey provider {}, encryption will be disabled", key);
466 }
467 }
468 } catch (final Exception ex) {
469 LOGGER.warn("Error setting up encryption - encryption will be disabled", ex);
470 }
471 return new FlumePersistentManager(name, data.name, data.agents, data.batchSize, data.retries,
472 data.connectionTimeout, data.requestTimeout, data.delayMillis, database, environment, secretKey,
473 data.lockTimeoutRetryCount);
474 }
475 }
476
477 /**
478 * Thread that sends data to Flume and pulls it from Berkeley DB.
479 */
480 private static class WriterThread extends Thread {
481 private volatile boolean shutdown = false;
482 private final Database database;
483 private final Environment environment;
484 private final FlumePersistentManager manager;
485 private final Gate gate;
486 private final SecretKey secretKey;
487 private final int batchSize;
488 private final AtomicLong dbCounter;
489 private final int lockTimeoutRetryCount;
490
491 public WriterThread(final Database database, final Environment environment,
492 final FlumePersistentManager manager, final Gate gate, final int batchsize,
493 final SecretKey secretKey, final AtomicLong dbCount, final int lockTimeoutRetryCount) {
494 this.database = database;
495 this.environment = environment;
496 this.manager = manager;
497 this.gate = gate;
498 this.batchSize = batchsize;
499 this.secretKey = secretKey;
500 this.setDaemon(true);
501 this.dbCounter = dbCount;
502 this.lockTimeoutRetryCount = lockTimeoutRetryCount;
503 }
504
505 public void shutdown() {
506 LOGGER.debug("Writer thread shutting down");
507 this.shutdown = true;
508 gate.open();
509 }
510
511 public boolean isShutdown() {
512 return shutdown;
513 }
514
515 @Override
516 public void run() {
517 LOGGER.trace("WriterThread started - batch size = " + batchSize + ", delayMillis = " + manager.delayMillis);
518 long nextBatchMillis = System.currentTimeMillis() + manager.delayMillis;
519 while (!shutdown) {
520 final long nowMillis = System.currentTimeMillis();
521 final long dbCount = database.count();
522 dbCounter.set(dbCount);
523 if (dbCount >= batchSize || dbCount > 0 && nextBatchMillis <= nowMillis) {
524 nextBatchMillis = nowMillis + manager.delayMillis;
525 try {
526 boolean errors = false;
527 final DatabaseEntry key = new DatabaseEntry();
528 final DatabaseEntry data = new DatabaseEntry();
529
530 gate.close();
531 OperationStatus status;
532 if (batchSize > 1) {
533 try {
534 errors = sendBatch(key, data);
535 } catch (final Exception ex) {
536 break;
537 }
538 } else {
539 Exception exception = null;
540 for (int retryIndex = 0; retryIndex < lockTimeoutRetryCount; ++retryIndex) {
541 exception = null;
542 Transaction txn = null;
543 Cursor cursor = null;
544 try {
545 txn = environment.beginTransaction(null, null);
546 cursor = database.openCursor(txn, null);
547 try {
548 status = cursor.getFirst(key, data, LockMode.RMW);
549 while (status == OperationStatus.SUCCESS) {
550 final SimpleEvent event = createEvent(data);
551 if (event != null) {
552 try {
553 manager.doSend(event);
554 } catch (final Exception ioe) {
555 errors = true;
556 LOGGER.error("Error sending event", ioe);
557 break;
558 }
559 try {
560 cursor.delete();
561 } catch (final Exception ex) {
562 LOGGER.error("Unable to delete event", ex);
563 }
564 }
565 status = cursor.getNext(key, data, LockMode.RMW);
566 }
567 if (cursor != null) {
568 cursor.close();
569 cursor = null;
570 }
571 txn.commit();
572 txn = null;
573 dbCounter.decrementAndGet();
574 exception = null;
575 break;
576 } catch (final LockConflictException lce) {
577 exception = lce;
578 // Fall through and retry.
579 } catch (final Exception ex) {
580 LOGGER.error("Error reading or writing to database", ex);
581 shutdown = true;
582 break;
583 } finally {
584 if (cursor != null) {
585 cursor.close();
586 cursor = null;
587 }
588 if (txn != null) {
589 txn.abort();
590 txn = null;
591 }
592 }
593 } catch (final LockConflictException lce) {
594 exception = lce;
595 if (cursor != null) {
596 try {
597 cursor.close();
598 cursor = null;
599 } catch (final Exception ex) {
600 LOGGER.trace("Ignored exception closing cursor during lock conflict.");
601 }
602 }
603 if (txn != null) {
604 try {
605 txn.abort();
606 txn = null;
607 } catch (final Exception ex) {
608 LOGGER.trace("Ignored exception aborting tx during lock conflict.");
609 }
610 }
611 }
612 try {
613 Thread.sleep(LOCK_TIMEOUT_SLEEP_MILLIS);
614 } catch (final InterruptedException ie) {
615 // Ignore the error
616 }
617 }
618 if (exception != null) {
619 LOGGER.error("Unable to read or update data base", exception);
620 }
621 }
622 if (errors) {
623 Thread.sleep(manager.delayMillis);
624 continue;
625 }
626 } catch (final Exception ex) {
627 LOGGER.warn("WriterThread encountered an exception. Continuing.", ex);
628 }
629 } else {
630 if (nextBatchMillis <= nowMillis) {
631 nextBatchMillis = nowMillis + manager.delayMillis;
632 }
633 try {
634 final long interval = nextBatchMillis - nowMillis;
635 gate.waitForOpen(interval);
636 } catch (final InterruptedException ie) {
637 LOGGER.warn("WriterThread interrupted, continuing");
638 } catch (final Exception ex) {
639 LOGGER.error("WriterThread encountered an exception waiting for work", ex);
640 break;
641 }
642 }
643 }
644
645 if (batchSize > 1 && database.count() > 0) {
646 final DatabaseEntry key = new DatabaseEntry();
647 final DatabaseEntry data = new DatabaseEntry();
648 try {
649 sendBatch(key, data);
650 } catch (final Exception ex) {
651 LOGGER.warn("Unable to write final batch");
652 }
653 }
654 LOGGER.trace("WriterThread exiting");
655 }
656
657 private boolean sendBatch(DatabaseEntry key, final DatabaseEntry data) throws Exception {
658 boolean errors = false;
659 OperationStatus status;
660 Cursor cursor = null;
661 try {
662 final BatchEvent batch = new BatchEvent();
663 for (int retryIndex = 0; retryIndex < lockTimeoutRetryCount; ++retryIndex) {
664 try {
665 cursor = database.openCursor(null, CursorConfig.DEFAULT);
666 status = cursor.getFirst(key, data, null);
667
668 for (int i = 0; status == OperationStatus.SUCCESS && i < batchSize; ++i) {
669 final SimpleEvent event = createEvent(data);
670 if (event != null) {
671 batch.addEvent(event);
672 }
673 status = cursor.getNext(key, data, null);
674 }
675 break;
676 } catch (final LockConflictException lce) {
677 if (cursor != null) {
678 try {
679 cursor.close();
680 cursor = null;
681 } catch (final Exception ex) {
682 LOGGER.trace("Ignored exception closing cursor during lock conflict.");
683 }
684 }
685 }
686 }
687
688 try {
689 manager.send(batch);
690 } catch (final Exception ioe) {
691 LOGGER.error("Error sending events", ioe);
692 errors = true;
693 }
694 if (!errors) {
695 if (cursor != null) {
696 cursor.close();
697 cursor = null;
698 }
699 Transaction txn = null;
700 Exception exception = null;
701 for (int retryIndex = 0; retryIndex < lockTimeoutRetryCount; ++retryIndex) {
702 try {
703 txn = environment.beginTransaction(null, null);
704 try {
705 for (final Event event : batch.getEvents()) {
706 try {
707 final Map<String, String> headers = event.getHeaders();
708 key = new DatabaseEntry(headers.get(FlumeEvent.GUID).getBytes(UTF8));
709 database.delete(txn, key);
710 } catch (final Exception ex) {
711 LOGGER.error("Error deleting key from database", ex);
712 }
713 }
714 txn.commit();
715 long count = dbCounter.get();
716 while (!dbCounter.compareAndSet(count, count - batch.getEvents().size())) {
717 count = dbCounter.get();
718 }
719 exception = null;
720 break;
721 } catch (final LockConflictException lce) {
722 exception = lce;
723 if (cursor != null) {
724 try {
725 cursor.close();
726 cursor = null;
727 } catch (final Exception ex) {
728 LOGGER.trace("Ignored exception closing cursor during lock conflict.");
729 }
730 }
731 if (txn != null) {
732 try {
733 txn.abort();
734 txn = null;
735 } catch (final Exception ex) {
736 LOGGER.trace("Ignored exception aborting transaction during lock conflict.");
737 }
738 }
739 } catch (final Exception ex) {
740 LOGGER.error("Unable to commit transaction", ex);
741 if (txn != null) {
742 txn.abort();
743 }
744 }
745 } catch (final LockConflictException lce) {
746 exception = lce;
747 if (cursor != null) {
748 try {
749 cursor.close();
750 cursor = null;
751 } catch (final Exception ex) {
752 LOGGER.trace("Ignored exception closing cursor during lock conflict.");
753 }
754 }
755 if (txn != null) {
756 try {
757 txn.abort();
758 txn = null;
759 } catch (final Exception ex) {
760 LOGGER.trace("Ignored exception aborting transaction during lock conflict.");
761 }
762 }
763 } finally {
764 if (cursor != null) {
765 cursor.close();
766 cursor = null;
767 }
768 if (txn != null) {
769 txn.abort();
770 txn = null;
771 }
772 }
773 try {
774 Thread.sleep(LOCK_TIMEOUT_SLEEP_MILLIS);
775 } catch (final InterruptedException ie) {
776 // Ignore the error
777 }
778 }
779 if (exception != null) {
780 LOGGER.error("Unable to delete events from data base", exception);
781 }
782 }
783 } catch (final Exception ex) {
784 LOGGER.error("Error reading database", ex);
785 shutdown = true;
786 throw ex;
787 } finally {
788 if (cursor != null) {
789 cursor.close();
790 }
791 }
792
793 return errors;
794 }
795
796 private SimpleEvent createEvent(final DatabaseEntry data) {
797 final SimpleEvent event = new SimpleEvent();
798 try {
799 byte[] eventData = data.getData();
800 if (secretKey != null) {
801 final Cipher cipher = Cipher.getInstance("AES");
802 cipher.init(Cipher.DECRYPT_MODE, secretKey);
803 eventData = cipher.doFinal(eventData);
804 }
805 final ByteArrayInputStream bais = new ByteArrayInputStream(eventData);
806 final DataInputStream dais = new DataInputStream(bais);
807 int length = dais.readInt();
808 final byte[] bytes = new byte[length];
809 dais.read(bytes, 0, length);
810 event.setBody(bytes);
811 length = dais.readInt();
812 final Map<String, String> map = new HashMap<String, String>(length);
813 for (int i = 0; i < length; ++i) {
814 final String headerKey = dais.readUTF();
815 final String value = dais.readUTF();
816 map.put(headerKey, value);
817 }
818 event.setHeaders(map);
819 return event;
820 } catch (final Exception ex) {
821 LOGGER.error("Error retrieving event", ex);
822 return null;
823 }
824 }
825
826 }
827
828 /**
829 * Factory that creates Daemon threads that can be properly shut down.
830 */
831 private static class DaemonThreadFactory implements ThreadFactory {
832 private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1);
833 private final ThreadGroup group;
834 private final AtomicInteger threadNumber = new AtomicInteger(1);
835 private final String namePrefix;
836
837 public DaemonThreadFactory() {
838 final SecurityManager securityManager = System.getSecurityManager();
839 group = securityManager != null ? securityManager.getThreadGroup() :
840 Thread.currentThread().getThreadGroup();
841 namePrefix = "DaemonPool-" + POOL_NUMBER.getAndIncrement() + "-thread-";
842 }
843
844 @Override
845 public Thread newThread(final Runnable r) {
846 final Thread thread = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
847 thread.setDaemon(true);
848 if (thread.getPriority() != Thread.NORM_PRIORITY) {
849 thread.setPriority(Thread.NORM_PRIORITY);
850 }
851 return thread;
852 }
853 }
854
855 /**
856 * An internal class.
857 */
858 private static class Gate {
859
860 private boolean isOpen = false;
861
862 public boolean isOpen() {
863 return isOpen;
864 }
865
866 public synchronized void open() {
867 isOpen = true;
868 notifyAll();
869 }
870
871 public synchronized void close() {
872 isOpen = false;
873 }
874
875 public synchronized void waitForOpen(final long timeout) throws InterruptedException {
876 wait(timeout);
877 }
878 }
879 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.flume.appender;
17
18 import java.io.ByteArrayInputStream;
19 import java.io.ByteArrayOutputStream;
20 import java.io.DataInputStream;
21 import java.io.DataOutputStream;
22 import java.io.File;
23 import java.nio.charset.Charset;
24 import java.util.HashMap;
25 import java.util.Map;
26 import java.util.concurrent.Callable;
27 import java.util.concurrent.ExecutorService;
28 import java.util.concurrent.Executors;
29 import java.util.concurrent.Future;
30 import java.util.concurrent.ThreadFactory;
31 import java.util.concurrent.TimeUnit;
32 import java.util.concurrent.atomic.AtomicInteger;
33 import java.util.concurrent.atomic.AtomicLong;
34
35 import javax.crypto.Cipher;
36 import javax.crypto.SecretKey;
37
38 import org.apache.flume.Event;
39 import org.apache.flume.event.SimpleEvent;
40 import org.apache.logging.log4j.LoggingException;
41 import org.apache.logging.log4j.core.appender.ManagerFactory;
42 import org.apache.logging.log4j.core.config.Property;
43 import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
44 import org.apache.logging.log4j.core.config.plugins.util.PluginType;
45 import org.apache.logging.log4j.core.util.FileUtils;
46 import org.apache.logging.log4j.core.util.SecretKeyProvider;
47 import org.apache.logging.log4j.util.Strings;
48
49 import com.sleepycat.je.Cursor;
50 import com.sleepycat.je.CursorConfig;
51 import com.sleepycat.je.Database;
52 import com.sleepycat.je.DatabaseConfig;
53 import com.sleepycat.je.DatabaseEntry;
54 import com.sleepycat.je.Environment;
55 import com.sleepycat.je.EnvironmentConfig;
56 import com.sleepycat.je.LockConflictException;
57 import com.sleepycat.je.LockMode;
58 import com.sleepycat.je.OperationStatus;
59 import com.sleepycat.je.StatsConfig;
60 import com.sleepycat.je.Transaction;
61
62 /**
63 * Manager that persists data to Berkeley DB before passing it on to Flume.
64 */
65 public class FlumePersistentManager extends FlumeAvroManager {
66
67 /** Attribute name for the key provider. */
68 public static final String KEY_PROVIDER = "keyProvider";
69
70 private static final Charset UTF8 = Charset.forName("UTF-8");
71
72 private static final String DEFAULT_DATA_DIR = ".log4j/flumeData";
73
74 private static final int SHUTDOWN_WAIT = 60;
75
76 private static final int MILLIS_PER_SECOND = 1000;
77
78 private static final int LOCK_TIMEOUT_SLEEP_MILLIS = 500;
79
80 private static BDBManagerFactory factory = new BDBManagerFactory();
81
82 private final Database database;
83
84 private final Environment environment;
85
86 private final WriterThread worker;
87
88 private final Gate gate = new Gate();
89
90 private final SecretKey secretKey;
91
92 private final int lockTimeoutRetryCount;
93
94 private final ExecutorService threadPool;
95
96 private final AtomicLong dbCount = new AtomicLong();
97
98 /**
99 * Constructor
100 * @param name The unique name of this manager.
101 * @param shortName Original name for the Manager.
102 * @param agents An array of Agents.
103 * @param batchSize The number of events to include in a batch.
104 * @param retries The number of times to retry connecting before giving up.
105 * @param connectionTimeout The amount of time to wait for a connection to be established.
106 * @param requestTimeout The amount of time to wair for a response to a request.
107 * @param delay The amount of time to wait between retries.
108 * @param database The database to write to.
109 * @param environment The database environment.
110 * @param secretKey The SecretKey to use for encryption.
111 * @param lockTimeoutRetryCount The number of times to retry a lock timeout.
112 */
113 protected FlumePersistentManager(final String name, final String shortName, final Agent[] agents,
114 final int batchSize, final int retries, final int connectionTimeout,
115 final int requestTimeout, final int delay, final Database database,
116 final Environment environment, final SecretKey secretKey,
117 final int lockTimeoutRetryCount) {
118 super(name, shortName, agents, batchSize, delay, retries, connectionTimeout, requestTimeout);
119 this.database = database;
120 this.environment = environment;
121 dbCount.set(database.count());
122 this.worker = new WriterThread(database, environment, this, gate, batchSize, secretKey, dbCount,
123 lockTimeoutRetryCount);
124 this.worker.start();
125 this.secretKey = secretKey;
126 this.threadPool = Executors.newCachedThreadPool(new DaemonThreadFactory());
127 this.lockTimeoutRetryCount = lockTimeoutRetryCount;
128 }
129
130
131 /**
132 * Returns a FlumeAvroManager.
133 * @param name The name of the manager.
134 * @param agents The agents to use.
135 * @param properties Properties to pass to the Manager.
136 * @param batchSize The number of events to include in a batch.
137 * @param retries The number of times to retry connecting before giving up.
138 * @param connectionTimeout The amount of time to wait to establish a connection.
139 * @param requestTimeout The amount of time to wait for a response to a request.
140 * @param delayMillis Amount of time to delay before delivering a batch.
141 * @param lockTimeoutRetryCount The number of times to retry after a lock timeout.
142 * @param dataDir The location of the Berkeley database.
143 * @return A FlumeAvroManager.
144 */
145 public static FlumePersistentManager getManager(final String name, final Agent[] agents,
146 final Property[] properties, int batchSize, final int retries,
147 final int connectionTimeout, final int requestTimeout,
148 final int delayMillis, final int lockTimeoutRetryCount,
149 final String dataDir) {
150 if (agents == null || agents.length == 0) {
151 throw new IllegalArgumentException("At least one agent is required");
152 }
153
154 if (batchSize <= 0) {
155 batchSize = 1;
156 }
157 final String dataDirectory = Strings.isEmpty(dataDir) ? DEFAULT_DATA_DIR : dataDir;
158
159 final StringBuilder sb = new StringBuilder("FlumePersistent[");
160 boolean first = true;
161 for (final Agent agent : agents) {
162 if (!first) {
163 sb.append(',');
164 }
165 sb.append(agent.getHost()).append(':').append(agent.getPort());
166 first = false;
167 }
168 sb.append(']');
169 sb.append(' ').append(dataDirectory);
170 return getManager(sb.toString(), factory, new FactoryData(name, agents, batchSize, retries,
171 connectionTimeout, requestTimeout, delayMillis, lockTimeoutRetryCount, dataDir, properties));
172 }
173
174 @Override
175 public void send(final Event event) {
176 if (worker.isShutdown()) {
177 throw new LoggingException("Unable to record event");
178 }
179
180 final Map<String, String> headers = event.getHeaders();
181 final byte[] keyData = headers.get(FlumeEvent.GUID).getBytes(UTF8);
182 try {
183 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
184 final DataOutputStream daos = new DataOutputStream(baos);
185 daos.writeInt(event.getBody().length);
186 daos.write(event.getBody(), 0, event.getBody().length);
187 daos.writeInt(event.getHeaders().size());
188 for (final Map.Entry<String, String> entry : headers.entrySet()) {
189 daos.writeUTF(entry.getKey());
190 daos.writeUTF(entry.getValue());
191 }
192 byte[] eventData = baos.toByteArray();
193 if (secretKey != null) {
194 final Cipher cipher = Cipher.getInstance("AES");
195 cipher.init(Cipher.ENCRYPT_MODE, secretKey);
196 eventData = cipher.doFinal(eventData);
197 }
198 final Future<Integer> future = threadPool.submit(new BDBWriter(keyData, eventData, environment, database,
199 gate, dbCount, getBatchSize(), lockTimeoutRetryCount));
200 boolean interrupted = false;
201 int ieCount = 0;
202 do {
203 try {
204 future.get();
205 } catch (final InterruptedException ie) {
206 interrupted = true;
207 ++ieCount;
208 }
209 } while (interrupted && ieCount <= 1);
210
211 } catch (final Exception ex) {
212 throw new LoggingException("Exception occurred writing log event", ex);
213 }
214 }
215
216 @Override
217 protected void releaseSub() {
218 LOGGER.debug("Shutting down FlumePersistentManager");
219 worker.shutdown();
220 try {
221 worker.join(SHUTDOWN_WAIT * MILLIS_PER_SECOND);
222 } catch (final InterruptedException ie) {
223 // Ignore the exception and shutdown.
224 }
225 threadPool.shutdown();
226 try {
227 threadPool.awaitTermination(SHUTDOWN_WAIT, TimeUnit.SECONDS);
228 } catch (final InterruptedException ie) {
229 LOGGER.warn("PersistentManager Thread pool failed to shut down");
230 }
231 try {
232 worker.join();
233 } catch (final InterruptedException ex) {
234 LOGGER.debug("Interrupted while waiting for worker to complete");
235 }
236 try {
237 LOGGER.debug("FlumePersistenceManager dataset status: {}", database.getStats(new StatsConfig()));
238 database.close();
239 } catch (final Exception ex) {
240 LOGGER.warn("Failed to close database", ex);
241 }
242 try {
243 environment.cleanLog();
244 environment.close();
245 } catch (final Exception ex) {
246 LOGGER.warn("Failed to close environment", ex);
247 }
248 super.releaseSub();
249 }
250
251 private void doSend(final SimpleEvent event) {
252 LOGGER.debug("Sending event to Flume");
253 super.send(event);
254 }
255
256 /**
257 * Thread for writing to Berkeley DB to avoid having interrupts close the database.
258 */
259 private static class BDBWriter implements Callable<Integer> {
260 private final byte[] eventData;
261 private final byte[] keyData;
262 private final Environment environment;
263 private final Database database;
264 private final Gate gate;
265 private final AtomicLong dbCount;
266 private final long batchSize;
267 private final int lockTimeoutRetryCount;
268
269 public BDBWriter(final byte[] keyData, final byte[] eventData, final Environment environment,
270 final Database database, final Gate gate, final AtomicLong dbCount, final long batchSize,
271 final int lockTimeoutRetryCount) {
272 this.keyData = keyData;
273 this.eventData = eventData;
274 this.environment = environment;
275 this.database = database;
276 this.gate = gate;
277 this.dbCount = dbCount;
278 this.batchSize = batchSize;
279 this.lockTimeoutRetryCount = lockTimeoutRetryCount;
280 }
281
282 @Override
283 public Integer call() throws Exception {
284 final DatabaseEntry key = new DatabaseEntry(keyData);
285 final DatabaseEntry data = new DatabaseEntry(eventData);
286 Exception exception = null;
287 for (int retryIndex = 0; retryIndex < lockTimeoutRetryCount; ++retryIndex) {
288 Transaction txn = null;
289 try {
290 txn = environment.beginTransaction(null, null);
291 try {
292 database.put(txn, key, data);
293 txn.commit();
294 txn = null;
295 if (dbCount.incrementAndGet() >= batchSize) {
296 gate.open();
297 }
298 exception = null;
299 break;
300 } catch (final LockConflictException lce) {
301 exception = lce;
302 // Fall through and retry.
303 } catch (final Exception ex) {
304 if (txn != null) {
305 txn.abort();
306 }
307 throw ex;
308 } finally {
309 if (txn != null) {
310 txn.abort();
311 txn = null;
312 }
313 }
314 } catch (final LockConflictException lce) {
315 exception = lce;
316 if (txn != null) {
317 try {
318 txn.abort();
319 txn = null;
320 } catch (final Exception ex) {
321 LOGGER.trace("Ignoring exception while aborting transaction during lock conflict.");
322 }
323 }
324
325 }
326 try {
327 Thread.sleep(LOCK_TIMEOUT_SLEEP_MILLIS);
328 } catch (final InterruptedException ie) {
329 // Ignore the error
330 }
331 }
332 if (exception != null) {
333 throw exception;
334 }
335 return eventData.length;
336 }
337 }
338
339 /**
340 * Factory data.
341 */
342 private static class FactoryData {
343 private final String name;
344 private final Agent[] agents;
345 private final int batchSize;
346 private final String dataDir;
347 private final int retries;
348 private final int connectionTimeout;
349 private final int requestTimeout;
350 private final int delayMillis;
351 private final int lockTimeoutRetryCount;
352 private final Property[] properties;
353
354 /**
355 * Constructor.
356 * @param name The name of the Appender.
357 * @param agents The agents.
358 * @param batchSize The number of events to include in a batch.
359 * @param dataDir The directory for data.
360 */
361 public FactoryData(final String name, final Agent[] agents, final int batchSize, final int retries,
362 final int connectionTimeout, final int requestTimeout, final int delayMillis,
363 final int lockTimeoutRetryCount, final String dataDir, final Property[] properties) {
364 this.name = name;
365 this.agents = agents;
366 this.batchSize = batchSize;
367 this.dataDir = dataDir;
368 this.retries = retries;
369 this.connectionTimeout = connectionTimeout;
370 this.requestTimeout = requestTimeout;
371 this.delayMillis = delayMillis;
372 this.lockTimeoutRetryCount = lockTimeoutRetryCount;
373 this.properties = properties;
374 }
375 }
376
377 /**
378 * Avro Manager Factory.
379 */
380 private static class BDBManagerFactory implements ManagerFactory<FlumePersistentManager, FactoryData> {
381
382 /**
383 * Create the FlumeKratiManager.
384 * @param name The name of the entity to manage.
385 * @param data The data required to create the entity.
386 * @return The FlumeKratiManager.
387 */
388 @Override
389 public FlumePersistentManager createManager(final String name, final FactoryData data) {
390 SecretKey secretKey = null;
391 Database database = null;
392 Environment environment = null;
393
394 final Map<String, String> properties = new HashMap<>();
395 if (data.properties != null) {
396 for (final Property property : data.properties) {
397 properties.put(property.getName(), property.getValue());
398 }
399 }
400
401 try {
402 final File dir = new File(data.dataDir);
403 FileUtils.mkdir(dir, true);
404 final EnvironmentConfig dbEnvConfig = new EnvironmentConfig();
405 dbEnvConfig.setTransactional(true);
406 dbEnvConfig.setAllowCreate(true);
407 dbEnvConfig.setLockTimeout(5, TimeUnit.SECONDS);
408 environment = new Environment(dir, dbEnvConfig);
409 final DatabaseConfig dbConfig = new DatabaseConfig();
410 dbConfig.setTransactional(true);
411 dbConfig.setAllowCreate(true);
412 database = environment.openDatabase(null, name, dbConfig);
413 } catch (final Exception ex) {
414 LOGGER.error("Could not create FlumePersistentManager", ex);
415 // For consistency, close database as well as environment even though it should never happen since the
416 // database is that last thing in the block above, but this does guard against a future line being
417 // inserted at the end that would bomb (like some debug logging).
418 if (database != null) {
419 database.close();
420 database = null;
421 }
422 if (environment != null) {
423 environment.close();
424 environment = null;
425 }
426 return null;
427 }
428
429 try {
430 String key = null;
431 for (final Map.Entry<String, String> entry : properties.entrySet()) {
432 if (entry.getKey().equalsIgnoreCase(KEY_PROVIDER)) {
433 key = entry.getValue();
434 break;
435 }
436 }
437 if (key != null) {
438 final PluginManager manager = new PluginManager("KeyProvider");
439 manager.collectPlugins();
440 final Map<String, PluginType<?>> plugins = manager.getPlugins();
441 if (plugins != null) {
442 boolean found = false;
443 for (final Map.Entry<String, PluginType<?>> entry : plugins.entrySet()) {
444 if (entry.getKey().equalsIgnoreCase(key)) {
445 found = true;
446 final Class<?> cl = entry.getValue().getPluginClass();
447 try {
448 final SecretKeyProvider provider = (SecretKeyProvider) cl.newInstance();
449 secretKey = provider.getSecretKey();
450 LOGGER.debug("Persisting events using SecretKeyProvider {}", cl.getName());
451 } catch (final Exception ex) {
452 LOGGER.error("Unable to create SecretKeyProvider {}, encryption will be disabled",
453 cl.getName());
454 }
455 break;
456 }
457 }
458 if (!found) {
459 LOGGER.error("Unable to locate SecretKey provider {}, encryption will be disabled", key);
460 }
461 } else {
462 LOGGER.error("Unable to locate SecretKey provider {}, encryption will be disabled", key);
463 }
464 }
465 } catch (final Exception ex) {
466 LOGGER.warn("Error setting up encryption - encryption will be disabled", ex);
467 }
468 return new FlumePersistentManager(name, data.name, data.agents, data.batchSize, data.retries,
469 data.connectionTimeout, data.requestTimeout, data.delayMillis, database, environment, secretKey,
470 data.lockTimeoutRetryCount);
471 }
472 }
473
474 /**
475 * Thread that sends data to Flume and pulls it from Berkeley DB.
476 */
477 private static class WriterThread extends Thread {
478 private volatile boolean shutdown = false;
479 private final Database database;
480 private final Environment environment;
481 private final FlumePersistentManager manager;
482 private final Gate gate;
483 private final SecretKey secretKey;
484 private final int batchSize;
485 private final AtomicLong dbCounter;
486 private final int lockTimeoutRetryCount;
487
488 public WriterThread(final Database database, final Environment environment,
489 final FlumePersistentManager manager, final Gate gate, final int batchsize,
490 final SecretKey secretKey, final AtomicLong dbCount, final int lockTimeoutRetryCount) {
491 this.database = database;
492 this.environment = environment;
493 this.manager = manager;
494 this.gate = gate;
495 this.batchSize = batchsize;
496 this.secretKey = secretKey;
497 this.setDaemon(true);
498 this.dbCounter = dbCount;
499 this.lockTimeoutRetryCount = lockTimeoutRetryCount;
500 }
501
502 public void shutdown() {
503 LOGGER.debug("Writer thread shutting down");
504 this.shutdown = true;
505 gate.open();
506 }
507
508 public boolean isShutdown() {
509 return shutdown;
510 }
511
512 @Override
513 public void run() {
514 LOGGER.trace("WriterThread started - batch size = " + batchSize + ", delayMillis = " + manager.getDelayMillis());
515 long nextBatchMillis = System.currentTimeMillis() + manager.getDelayMillis();
516 while (!shutdown) {
517 final long nowMillis = System.currentTimeMillis();
518 final long dbCount = database.count();
519 dbCounter.set(dbCount);
520 if (dbCount >= batchSize || dbCount > 0 && nextBatchMillis <= nowMillis) {
521 nextBatchMillis = nowMillis + manager.getDelayMillis();
522 try {
523 boolean errors = false;
524 final DatabaseEntry key = new DatabaseEntry();
525 final DatabaseEntry data = new DatabaseEntry();
526
527 gate.close();
528 OperationStatus status;
529 if (batchSize > 1) {
530 try {
531 errors = sendBatch(key, data);
532 } catch (final Exception ex) {
533 break;
534 }
535 } else {
536 Exception exception = null;
537 for (int retryIndex = 0; retryIndex < lockTimeoutRetryCount; ++retryIndex) {
538 exception = null;
539 Transaction txn = null;
540 Cursor cursor = null;
541 try {
542 txn = environment.beginTransaction(null, null);
543 cursor = database.openCursor(txn, null);
544 try {
545 status = cursor.getFirst(key, data, LockMode.RMW);
546 while (status == OperationStatus.SUCCESS) {
547 final SimpleEvent event = createEvent(data);
548 if (event != null) {
549 try {
550 manager.doSend(event);
551 } catch (final Exception ioe) {
552 errors = true;
553 LOGGER.error("Error sending event", ioe);
554 break;
555 }
556 try {
557 cursor.delete();
558 } catch (final Exception ex) {
559 LOGGER.error("Unable to delete event", ex);
560 }
561 }
562 status = cursor.getNext(key, data, LockMode.RMW);
563 }
564 if (cursor != null) {
565 cursor.close();
566 cursor = null;
567 }
568 txn.commit();
569 txn = null;
570 dbCounter.decrementAndGet();
571 exception = null;
572 break;
573 } catch (final LockConflictException lce) {
574 exception = lce;
575 // Fall through and retry.
576 } catch (final Exception ex) {
577 LOGGER.error("Error reading or writing to database", ex);
578 shutdown = true;
579 break;
580 } finally {
581 if (cursor != null) {
582 cursor.close();
583 cursor = null;
584 }
585 if (txn != null) {
586 txn.abort();
587 txn = null;
588 }
589 }
590 } catch (final LockConflictException lce) {
591 exception = lce;
592 if (cursor != null) {
593 try {
594 cursor.close();
595 cursor = null;
596 } catch (final Exception ex) {
597 LOGGER.trace("Ignored exception closing cursor during lock conflict.");
598 }
599 }
600 if (txn != null) {
601 try {
602 txn.abort();
603 txn = null;
604 } catch (final Exception ex) {
605 LOGGER.trace("Ignored exception aborting tx during lock conflict.");
606 }
607 }
608 }
609 try {
610 Thread.sleep(LOCK_TIMEOUT_SLEEP_MILLIS);
611 } catch (final InterruptedException ie) {
612 // Ignore the error
613 }
614 }
615 if (exception != null) {
616 LOGGER.error("Unable to read or update data base", exception);
617 }
618 }
619 if (errors) {
620 Thread.sleep(manager.getDelayMillis());
621 continue;
622 }
623 } catch (final Exception ex) {
624 LOGGER.warn("WriterThread encountered an exception. Continuing.", ex);
625 }
626 } else {
627 if (nextBatchMillis <= nowMillis) {
628 nextBatchMillis = nowMillis + manager.getDelayMillis();
629 }
630 try {
631 final long interval = nextBatchMillis - nowMillis;
632 gate.waitForOpen(interval);
633 } catch (final InterruptedException ie) {
634 LOGGER.warn("WriterThread interrupted, continuing");
635 } catch (final Exception ex) {
636 LOGGER.error("WriterThread encountered an exception waiting for work", ex);
637 break;
638 }
639 }
640 }
641
642 if (batchSize > 1 && database.count() > 0) {
643 final DatabaseEntry key = new DatabaseEntry();
644 final DatabaseEntry data = new DatabaseEntry();
645 try {
646 sendBatch(key, data);
647 } catch (final Exception ex) {
648 LOGGER.warn("Unable to write final batch");
649 }
650 }
651 LOGGER.trace("WriterThread exiting");
652 }
653
654 private boolean sendBatch(DatabaseEntry key, final DatabaseEntry data) throws Exception {
655 boolean errors = false;
656 OperationStatus status;
657 Cursor cursor = null;
658 try {
659 final BatchEvent batch = new BatchEvent();
660 for (int retryIndex = 0; retryIndex < lockTimeoutRetryCount; ++retryIndex) {
661 try {
662 cursor = database.openCursor(null, CursorConfig.DEFAULT);
663 status = cursor.getFirst(key, data, null);
664
665 for (int i = 0; status == OperationStatus.SUCCESS && i < batchSize; ++i) {
666 final SimpleEvent event = createEvent(data);
667 if (event != null) {
668 batch.addEvent(event);
669 }
670 status = cursor.getNext(key, data, null);
671 }
672 break;
673 } catch (final LockConflictException lce) {
674 if (cursor != null) {
675 try {
676 cursor.close();
677 cursor = null;
678 } catch (final Exception ex) {
679 LOGGER.trace("Ignored exception closing cursor during lock conflict.");
680 }
681 }
682 }
683 }
684
685 try {
686 manager.send(batch);
687 } catch (final Exception ioe) {
688 LOGGER.error("Error sending events", ioe);
689 errors = true;
690 }
691 if (!errors) {
692 if (cursor != null) {
693 cursor.close();
694 cursor = null;
695 }
696 Transaction txn = null;
697 Exception exception = null;
698 for (int retryIndex = 0; retryIndex < lockTimeoutRetryCount; ++retryIndex) {
699 try {
700 txn = environment.beginTransaction(null, null);
701 try {
702 for (final Event event : batch.getEvents()) {
703 try {
704 final Map<String, String> headers = event.getHeaders();
705 key = new DatabaseEntry(headers.get(FlumeEvent.GUID).getBytes(UTF8));
706 database.delete(txn, key);
707 } catch (final Exception ex) {
708 LOGGER.error("Error deleting key from database", ex);
709 }
710 }
711 txn.commit();
712 long count = dbCounter.get();
713 while (!dbCounter.compareAndSet(count, count - batch.getEvents().size())) {
714 count = dbCounter.get();
715 }
716 exception = null;
717 break;
718 } catch (final LockConflictException lce) {
719 exception = lce;
720 if (cursor != null) {
721 try {
722 cursor.close();
723 cursor = null;
724 } catch (final Exception ex) {
725 LOGGER.trace("Ignored exception closing cursor during lock conflict.");
726 }
727 }
728 if (txn != null) {
729 try {
730 txn.abort();
731 txn = null;
732 } catch (final Exception ex) {
733 LOGGER.trace("Ignored exception aborting transaction during lock conflict.");
734 }
735 }
736 } catch (final Exception ex) {
737 LOGGER.error("Unable to commit transaction", ex);
738 if (txn != null) {
739 txn.abort();
740 }
741 }
742 } catch (final LockConflictException lce) {
743 exception = lce;
744 if (cursor != null) {
745 try {
746 cursor.close();
747 cursor = null;
748 } catch (final Exception ex) {
749 LOGGER.trace("Ignored exception closing cursor during lock conflict.");
750 }
751 }
752 if (txn != null) {
753 try {
754 txn.abort();
755 txn = null;
756 } catch (final Exception ex) {
757 LOGGER.trace("Ignored exception aborting transaction during lock conflict.");
758 }
759 }
760 } finally {
761 if (cursor != null) {
762 cursor.close();
763 cursor = null;
764 }
765 if (txn != null) {
766 txn.abort();
767 txn = null;
768 }
769 }
770 try {
771 Thread.sleep(LOCK_TIMEOUT_SLEEP_MILLIS);
772 } catch (final InterruptedException ie) {
773 // Ignore the error
774 }
775 }
776 if (exception != null) {
777 LOGGER.error("Unable to delete events from data base", exception);
778 }
779 }
780 } catch (final Exception ex) {
781 LOGGER.error("Error reading database", ex);
782 shutdown = true;
783 throw ex;
784 } finally {
785 if (cursor != null) {
786 cursor.close();
787 }
788 }
789
790 return errors;
791 }
792
793 private SimpleEvent createEvent(final DatabaseEntry data) {
794 final SimpleEvent event = new SimpleEvent();
795 try {
796 byte[] eventData = data.getData();
797 if (secretKey != null) {
798 final Cipher cipher = Cipher.getInstance("AES");
799 cipher.init(Cipher.DECRYPT_MODE, secretKey);
800 eventData = cipher.doFinal(eventData);
801 }
802 final ByteArrayInputStream bais = new ByteArrayInputStream(eventData);
803 final DataInputStream dais = new DataInputStream(bais);
804 int length = dais.readInt();
805 final byte[] bytes = new byte[length];
806 dais.read(bytes, 0, length);
807 event.setBody(bytes);
808 length = dais.readInt();
809 final Map<String, String> map = new HashMap<>(length);
810 for (int i = 0; i < length; ++i) {
811 final String headerKey = dais.readUTF();
812 final String value = dais.readUTF();
813 map.put(headerKey, value);
814 }
815 event.setHeaders(map);
816 return event;
817 } catch (final Exception ex) {
818 LOGGER.error("Error retrieving event", ex);
819 return null;
820 }
821 }
822
823 }
824
825 /**
826 * Factory that creates Daemon threads that can be properly shut down.
827 */
828 private static class DaemonThreadFactory implements ThreadFactory {
829 private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1);
830 private final ThreadGroup group;
831 private final AtomicInteger threadNumber = new AtomicInteger(1);
832 private final String namePrefix;
833
834 public DaemonThreadFactory() {
835 final SecurityManager securityManager = System.getSecurityManager();
836 group = securityManager != null ? securityManager.getThreadGroup() :
837 Thread.currentThread().getThreadGroup();
838 namePrefix = "DaemonPool-" + POOL_NUMBER.getAndIncrement() + "-thread-";
839 }
840
841 @Override
842 public Thread newThread(final Runnable r) {
843 final Thread thread = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
844 thread.setDaemon(true);
845 if (thread.getPriority() != Thread.NORM_PRIORITY) {
846 thread.setPriority(Thread.NORM_PRIORITY);
847 }
848 return thread;
849 }
850 }
851
852 /**
853 * An internal class.
854 */
855 private static class Gate {
856
857 private boolean isOpen = false;
858
859 public boolean isOpen() {
860 return isOpen;
861 }
862
863 public synchronized void open() {
864 isOpen = true;
865 notifyAll();
866 }
867
868 public synchronized void close() {
869 isOpen = false;
870 }
871
872 public synchronized void waitForOpen(final long timeout) throws InterruptedException {
873 wait(timeout);
874 }
875 }
876 }
235235
236236 <section name="Requirements">
237237 <p>
238 The Flume Appender requires at least Java 6.
238 The Flume Appender requires the Log4J 2 API.
239239 </p>
240240 </section>
241241
8787 context.put("bind", "0.0.0.0");
8888 Configurables.configure(eventSource, context);
8989
90 final List<Channel> channels = new ArrayList<Channel>();
90 final List<Channel> channels = new ArrayList<>();
9191 channels.add(channel);
9292
9393 final ChannelSelector cs = new ReplicatingChannelSelector();
172172
173173 final Event event = channel.take();
174174 Assert.assertNotNull(event);
175 Assert.assertTrue("Channel contained event, but not expected message",
176 getBody(event).endsWith("Success"));
175 Assert.assertTrue("Channel contained event, but not expected message", getBody(event).endsWith("Success"));
177176 transaction.commit();
178177 transaction.close();
179178
216215 eventSource.stop();
217216 }
218217
218
219 @Test
220 public void testIncompleteBatch() throws IOException {
221 final Agent[] agents = new Agent[] { Agent.createAgent("localhost",
222 testPort) };
223 final FlumeAppender avroAppender = FlumeAppender.createAppender(agents,
224 null, "false", "Avro", null, "1000", "1000", "1", "500",
225 "avro", "false", null, null, null, null, null, "true", "10",
226 null, null, null, null);
227 avroAppender.start();
228 avroLogger.addAppender(avroAppender);
229 avroLogger.setLevel(Level.ALL);
230
231 Assert.assertNotNull(avroLogger);
232
233 avroLogger.info("Test message 0");
234
235 final Transaction transaction = channel.getTransaction();
236 transaction.begin();
237
238 Event event = channel.take();
239 Assert.assertNull("Received event", event);
240
241 try {
242 Thread.sleep(500);
243 } catch (final InterruptedException ie) {
244 }
245
246 avroLogger.info("Test message 1");
247 for (int i = 0; i < 2; ++i) {
248 event = channel.take();
249 Assert.assertNotNull("No event for item " + i, event);
250 Assert.assertTrue("Channel contained event, but not expected message",
251 getBody(event).endsWith("Test message " + i));
252 }
253 transaction.commit();
254 transaction.close();
255
256 eventSource.stop();
257 }
258
259 @Test
260 public void testIncompleteBatch2() throws IOException {
261 final Agent[] agents = new Agent[] { Agent.createAgent("localhost",
262 testPort) };
263 final FlumeAppender avroAppender = FlumeAppender.createAppender(agents,
264 null, "false", "Avro", null, "1000", "1000", "1", "500",
265 "avro", "false", null, null, null, null, null, "true", "10",
266 null, null, null, null);
267 avroAppender.start();
268 avroLogger.addAppender(avroAppender);
269 avroLogger.setLevel(Level.ALL);
270
271 Assert.assertNotNull(avroLogger);
272
273 avroLogger.info("Test message 0");
274
275 final Transaction transaction = channel.getTransaction();
276 transaction.begin();
277
278 avroLogger.info("Test message 1");
279 avroLogger.info("Test message 2");
280 avroAppender.stop();
281 for (int i = 0; i < 3; ++i) {
282 Event event = channel.take();
283 Assert.assertNotNull("No event for item " + i, event);
284 Assert.assertTrue("Channel contained event, but not expected message. Received : " + getBody(event),
285 getBody(event).endsWith("Test message " + i));
286 }
287 transaction.commit();
288 transaction.close();
289
290 eventSource.stop();
291 }
292
219293 @Test
220294 public void testBatch() throws IOException {
221295 final Agent[] agents = new Agent[] { Agent.createAgent("localhost",
347421
348422 Event event = channel.take();
349423 Assert.assertNotNull(event);
350 Assert.assertTrue("Channel contained event, but not expected message",
424 Assert.assertTrue("Channel contained event, but not expected message. Received : " + getBody(event),
351425 getBody(event).endsWith("Test message"));
352426 transaction.commit();
353427 transaction.close();
389463 }
390464
391465 private String getBody(final Event event) throws IOException {
466 if (event == null) {
467 return "";
468 }
392469 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
393470 final InputStream is = new GZIPInputStream(new ByteArrayInputStream(
394471 event.getBody()));
101101 primary = new EventCollector(primaryPort);
102102 alternate = new EventCollector(altPort);
103103 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
104 ctx = (LoggerContext) LogManager.getContext(false);
104 ctx = LoggerContext.getContext(false);
105105 ctx.reconfigure();
106106 }
107107
219219 return true;
220220 }
221221
222 return result &= file.delete();
222 return result && file.delete();
223223 }
224224
225225 private static class EventCollector implements AvroSourceProtocol {
226 private final LinkedBlockingQueue<AvroFlumeEvent> eventQueue = new LinkedBlockingQueue<AvroFlumeEvent>();
226 private final LinkedBlockingQueue<AvroFlumeEvent> eventQueue = new LinkedBlockingQueue<>();
227227
228228 private final NettyServer nettyServer;
229229
268268 }
269269
270270 private static Map<String, String> toStringMap(final Map<CharSequence, CharSequence> charSeqMap) {
271 final Map<String, String> stringMap = new HashMap<String, String>();
271 final Map<String, String> stringMap = new HashMap<>();
272272 for (final Map.Entry<CharSequence, CharSequence> entry : charSeqMap.entrySet()) {
273273 stringMap.put(entry.getKey().toString(), entry.getValue().toString());
274274 }
101101 primary = new EventCollector(primaryPort);
102102 alternate = new EventCollector(altPort);
103103 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
104 ctx = (LoggerContext) LogManager.getContext(false);
104 ctx = LoggerContext.getContext(false);
105105 ctx.reconfigure();
106106 }
107107
231231
232232 }
233233
234 private static boolean deleteFiles(final File file) {
235 boolean result = true;
236 if (file.isDirectory()) {
237
238 final File[] files = file.listFiles();
239 for (final File child : files) {
240 result &= deleteFiles(child);
241 }
242
243 } else if (!file.exists()) {
244 return true;
245 }
246
247 return result &= file.delete();
248 }
234 private static boolean deleteFiles(final File file) {
235 boolean result = true;
236 if (file.isDirectory()) {
237
238 final File[] files = file.listFiles();
239 if (files != null) {
240 for (final File child : files) {
241 result &= deleteFiles(child);
242 }
243 }
244
245 } else if (!file.exists()) {
246 return true;
247 }
248
249 return result && file.delete();
250 }
249251
250252 private static class EventCollector implements AvroSourceProtocol {
251 private final LinkedBlockingQueue<AvroFlumeEvent> eventQueue = new LinkedBlockingQueue<AvroFlumeEvent>();
253 private final LinkedBlockingQueue<AvroFlumeEvent> eventQueue = new LinkedBlockingQueue<>();
252254
253255 private final NettyServer nettyServer;
254256
294296 }
295297
296298 private static Map<String, String> toStringMap(final Map<CharSequence, CharSequence> charSeqMap) {
297 final Map<String, String> stringMap = new HashMap<String, String>();
299 final Map<String, String> stringMap = new HashMap<>();
298300 for (final Map.Entry<CharSequence, CharSequence> entry : charSeqMap.entrySet()) {
299301 stringMap.put(entry.getKey().toString(), entry.getValue().toString());
300302 }
103103 primary = new EventCollector(primaryPort);
104104 alternate = new EventCollector(altPort);
105105 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
106 ctx = (LoggerContext) LogManager.getContext(false);
106 ctx = LoggerContext.getContext(false);
107107 ctx.reconfigure();
108108 }
109109
370370
371371 }
372372
373 private static boolean deleteFiles(final File file) {
374 boolean result = true;
375 if (file.isDirectory()) {
376
377 final File[] files = file.listFiles();
378 for (final File child : files) {
379 result &= deleteFiles(child);
380 }
381
382 } else if (!file.exists()) {
383 return true;
384 }
385
386 return result &= file.delete();
387 }
373 private static boolean deleteFiles(final File file) {
374 boolean result = true;
375 if (file.isDirectory()) {
376
377 final File[] files = file.listFiles();
378 if (files != null) {
379 for (final File child : files) {
380 result &= deleteFiles(child);
381 }
382 }
383 } else if (!file.exists()) {
384 return true;
385 }
386
387 return result && file.delete();
388 }
388389
389390 private static class EventCollector implements AvroSourceProtocol {
390 private final LinkedBlockingQueue<AvroFlumeEvent> eventQueue = new LinkedBlockingQueue<AvroFlumeEvent>();
391 private final LinkedBlockingQueue<AvroFlumeEvent> eventQueue = new LinkedBlockingQueue<>();
391392
392393 private final NettyServer nettyServer;
393394
435436 }
436437
437438 private static Map<String, String> toStringMap(final Map<CharSequence, CharSequence> charSeqMap) {
438 final Map<String, String> stringMap = new HashMap<String, String>();
439 final Map<String, String> stringMap = new HashMap<>();
439440 for (final Map.Entry<CharSequence, CharSequence> entry : charSeqMap.entrySet()) {
440441 stringMap.put(entry.getKey().toString(), entry.getValue().toString());
441442 }
4343 import org.apache.flume.source.avro.AvroSourceProtocol;
4444 import org.apache.flume.source.avro.Status;
4545 import org.apache.logging.log4j.EventLogger;
46 import org.apache.logging.log4j.LogManager;
4746 import org.apache.logging.log4j.core.LoggerContext;
4847 import org.apache.logging.log4j.core.config.ConfigurationFactory;
4948 import org.apache.logging.log4j.message.StructuredDataMessage;
9998 primary = new EventCollector(primaryPort);
10099 alternate = new EventCollector(altPort);
101100 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
102 ctx = (LoggerContext) LogManager.getContext(false);
101 ctx = LoggerContext.getContext(false);
103102 ctx.reconfigure();
104103 }
105104
147146
148147 }
149148
150 private static boolean deleteFiles(final File file) {
151 boolean result = true;
152 if (file.isDirectory()) {
153
154 final File[] files = file.listFiles();
155 for (final File child : files) {
156 result &= deleteFiles(child);
157 }
158
159 } else if (!file.exists()) {
160 return true;
161 }
162
163 return result &= file.delete();
164 }
149 private static boolean deleteFiles(final File file) {
150 boolean result = true;
151 if (file.isDirectory()) {
152
153 final File[] files = file.listFiles();
154 if (files != null) {
155 for (final File child : files) {
156 result &= deleteFiles(child);
157 }
158 }
159 } else if (!file.exists()) {
160 return true;
161 }
162
163 return result && file.delete();
164 }
165165
166166 private static class EventCollector implements AvroSourceProtocol {
167 private final LinkedBlockingQueue<AvroFlumeEvent> eventQueue = new LinkedBlockingQueue<AvroFlumeEvent>();
167 private final LinkedBlockingQueue<AvroFlumeEvent> eventQueue = new LinkedBlockingQueue<>();
168168
169169 private final NettyServer nettyServer;
170170
209209 }
210210
211211 private static Map<String, String> toStringMap(final Map<CharSequence, CharSequence> charSeqMap) {
212 final Map<String, String> stringMap = new HashMap<String, String>();
212 final Map<String, String> stringMap = new HashMap<>();
213213 for (final Map.Entry<CharSequence, CharSequence> entry : charSeqMap.entrySet()) {
214214 stringMap.put(entry.getKey().toString(), entry.getValue().toString());
215215 }
1919 <parent>
2020 <groupId>org.apache.logging.log4j</groupId>
2121 <artifactId>log4j</artifactId>
22 <version>2.2</version>
22 <version>2.4</version>
2323 <relativePath>../</relativePath>
2424 </parent>
2525 <artifactId>log4j-iostreams</artifactId>
3636 </section>
3737 <section name="Requirements">
3838 <p>
39 The Log4j IOStreams API extension requires Java 6 and the Log4j API. This component was introduced in Log4j 2.1.
39 The Log4j IOStreams API extension requires the Log4j 2 API. This component was introduced in Log4j 2.1.
4040 </p>
4141 </section>
4242 <section name="Usage">
6868 out.close();
6969 replay(out);
7070
71 final OutputStream filteredOut =
71 try (final OutputStream filteredOut =
7272 IoBuilder.forLogger(getExtendedLogger())
7373 .filter(out)
7474 .setLevel(LEVEL)
75 .buildOutputStream();
76 filteredOut.flush();
77 filteredOut.close();
75 .buildOutputStream()) {
76 filteredOut.flush();
77 }
7878 verify(out);
7979 }
8080
6969 out.close();
7070 replay(out);
7171
72 final OutputStream filteredOut =
72 try (final OutputStream filteredOut =
7373 IoBuilder.forLogger(getExtendedLogger())
7474 .filter(out)
7575 .setLevel(LEVEL)
76 .buildOutputStream();
77 filteredOut.flush();
78 filteredOut.close();
76 .buildOutputStream()) {
77 filteredOut.flush();
78 }
7979 verify(out);
8080 }
8181
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.logging.log4j.io;
18
19 import java.util.List;
20
21 import org.apache.logging.log4j.Level;
22 import org.apache.logging.log4j.junit.InitialLoggerContext;
23 import org.apache.logging.log4j.spi.ExtendedLogger;
24 import org.junit.Before;
25 import org.junit.ClassRule;
26
27 import static org.hamcrest.core.StringStartsWith.startsWith;
28 import static org.junit.Assert.*;
29
30 public abstract class AbstractStreamTest {
31
32 protected static ExtendedLogger getExtendedLogger() {
33 return ctx.getLogger("UnitTestLogger");
34 }
35
36 protected final static String NEWLINE = System.getProperty("line.separator");
37 protected final static Level LEVEL = Level.ERROR;
38 protected final static String FIRST = "first";
39
40 protected final static String LAST = "last";
41
42 @ClassRule
43 public static InitialLoggerContext ctx = new InitialLoggerContext("log4j2-streams-unit-test.xml");
44
45 protected void assertMessages(final String... messages) {
46 final List<String> actualMsgs = ctx.getListAppender("UnitTest").getMessages();
47 assertEquals("Unexpected number of results.", messages.length, actualMsgs.size());
48 for (int i = 0; i < messages.length; i++) {
49 final String start = LEVEL.name() + ' ' + messages[i];
50 assertThat(actualMsgs.get(i), startsWith(start));
51 }
52 }
53
54 @Before
55 public void clearAppender() {
56 ctx.getListAppender("UnitTest").clear();
57 }
58 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.logging.log4j.io;
18
19 import java.util.List;
20
21 import org.apache.logging.log4j.Level;
22 import org.apache.logging.log4j.junit.LoggerContextRule;
23 import org.apache.logging.log4j.spi.ExtendedLogger;
24 import org.junit.Before;
25 import org.junit.ClassRule;
26
27 import static org.hamcrest.core.StringStartsWith.startsWith;
28 import static org.junit.Assert.*;
29
30 public abstract class AbstractStreamTest {
31
32 protected static ExtendedLogger getExtendedLogger() {
33 return ctx.getLogger("UnitTestLogger");
34 }
35
36 protected final static String NEWLINE = System.getProperty("line.separator");
37 protected final static Level LEVEL = Level.ERROR;
38 protected final static String FIRST = "first";
39
40 protected final static String LAST = "last";
41
42 @ClassRule
43 public static LoggerContextRule ctx = new LoggerContextRule("log4j2-streams-unit-test.xml");
44
45 protected void assertMessages(final String... messages) {
46 final List<String> actualMsgs = ctx.getListAppender("UnitTest").getMessages();
47 assertEquals("Unexpected number of results.", messages.length, actualMsgs.size());
48 for (int i = 0; i < messages.length; i++) {
49 final String start = LEVEL.name() + ' ' + messages[i];
50 assertThat(actualMsgs.get(i), startsWith(start));
51 }
52 }
53
54 @Before
55 public void clearAppender() {
56 ctx.getListAppender("UnitTest").clear();
57 }
58 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.logging.log4j.io;
17
18 import org.apache.logging.log4j.Level;
19 import org.apache.logging.log4j.core.Logger;
20 import org.apache.logging.log4j.junit.InitialLoggerContext;
21 import org.apache.logging.log4j.test.appender.ListAppender;
22 import org.junit.Before;
23 import org.junit.ClassRule;
24
25 import static org.junit.Assert.*;
26
27 public class IoBuilderCallerInfoTesting {
28
29 protected static Logger getExtendedLogger() {
30 return ctx.getLogger("ClassAndMethodLogger");
31 }
32
33 protected static Logger getLogger() {
34 return getExtendedLogger();
35 }
36
37 protected final static Level LEVEL = Level.WARN;
38
39 @ClassRule
40 public static InitialLoggerContext ctx = new InitialLoggerContext("log4j2-streams-calling-info.xml");
41
42 public void assertMessages(final String msg, final int size, final String methodName) {
43 final ListAppender appender = ctx.getListAppender("ClassAndMethod");
44 assertEquals(msg + ".size", size, appender.getMessages().size());
45 for (final String message : appender.getMessages()) {
46 assertEquals(msg + " has incorrect caller info", this.getClass().getName() + '.' + methodName, message);
47 }
48 }
49
50 @Before
51 public void clearAppender() {
52 ctx.getListAppender("ClassAndMethod").clear();
53 }
54 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.logging.log4j.io;
17
18 import org.apache.logging.log4j.Level;
19 import org.apache.logging.log4j.core.Logger;
20 import org.apache.logging.log4j.junit.LoggerContextRule;
21 import org.apache.logging.log4j.test.appender.ListAppender;
22 import org.junit.Before;
23 import org.junit.ClassRule;
24
25 import static org.junit.Assert.*;
26
27 public class IoBuilderCallerInfoTesting {
28
29 protected static Logger getExtendedLogger() {
30 return ctx.getLogger("ClassAndMethodLogger");
31 }
32
33 protected static Logger getLogger() {
34 return getExtendedLogger();
35 }
36
37 protected final static Level LEVEL = Level.WARN;
38
39 @ClassRule
40 public static LoggerContextRule ctx = new LoggerContextRule("log4j2-streams-calling-info.xml");
41
42 public void assertMessages(final String msg, final int size, final String methodName) {
43 final ListAppender appender = ctx.getListAppender("ClassAndMethod");
44 assertEquals(msg + ".size", size, appender.getMessages().size());
45 for (final String message : appender.getMessages()) {
46 assertEquals(msg + " has incorrect caller info", this.getClass().getName() + '.' + methodName, message);
47 }
48 }
49
50 @Before
51 public void clearAppender() {
52 ctx.getListAppender("ClassAndMethod").clear();
53 }
54 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.io;
17
18 import java.io.PrintStream;
19 import java.util.List;
20
21 import org.apache.logging.log4j.junit.InitialLoggerContext;
22 import org.apache.logging.log4j.test.appender.ListAppender;
23 import org.junit.Rule;
24 import org.junit.Test;
25
26 import static org.hamcrest.Matchers.empty;
27 import static org.hamcrest.Matchers.hasSize;
28 import static org.hamcrest.Matchers.not;
29 import static org.hamcrest.Matchers.startsWith;
30 import static org.junit.Assert.*;
31
32 public class IoBuilderTest {
33
34 @Rule
35 public InitialLoggerContext context = new InitialLoggerContext("log4j2-streams-calling-info.xml");
36
37 @Test
38 public void testNoArgBuilderCallerClassInfo() throws Exception {
39 final PrintStream ps = IoBuilder.forLogger().buildPrintStream();
40 ps.println("discarded");
41 final ListAppender app = context.getListAppender("IoBuilderTest");
42 final List<String> messages = app.getMessages();
43 assertThat(messages, not(empty()));
44 assertThat(messages, hasSize(1));
45 final String message = messages.get(0);
46 assertThat(message, startsWith(getClass().getName() + ".testNoArgBuilderCallerClassInfo"));
47 app.clear();
48 }
49 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.io;
17
18 import static org.hamcrest.Matchers.empty;
19 import static org.hamcrest.Matchers.hasSize;
20 import static org.hamcrest.Matchers.not;
21 import static org.hamcrest.Matchers.startsWith;
22 import static org.junit.Assert.assertThat;
23
24 import java.io.PrintStream;
25 import java.util.List;
26
27 import org.apache.logging.log4j.junit.LoggerContextRule;
28 import org.apache.logging.log4j.test.appender.ListAppender;
29 import org.junit.ClassRule;
30 import org.junit.Test;
31
32 public class IoBuilderTest {
33
34 @ClassRule
35 public static LoggerContextRule context = new LoggerContextRule("log4j2-streams-calling-info.xml");
36
37 @Test
38 public void testNoArgBuilderCallerClassInfo() throws Exception {
39 try (final PrintStream ps = IoBuilder.forLogger().buildPrintStream()) {
40 ps.println("discarded");
41 final ListAppender app = context.getListAppender("IoBuilderTest");
42 final List<String> messages = app.getMessages();
43 assertThat(messages, not(empty()));
44 assertThat(messages, hasSize(1));
45 final String message = messages.get(0);
46 assertThat(message, startsWith(getClass().getName() + ".testNoArgBuilderCallerClassInfo"));
47 app.clear();
48 }
49 }
50 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.io;
17
18 import java.io.PrintWriter;
19 import java.sql.Connection;
20 import java.sql.DriverManager;
21 import java.sql.SQLException;
22
23 import org.apache.logging.log4j.Level;
24 import org.apache.logging.log4j.junit.InitialLoggerContext;
25 import org.apache.logging.log4j.test.appender.ListAppender;
26 import org.apache.logging.log4j.util.Strings;
27 import org.h2.jdbcx.JdbcDataSource;
28 import org.junit.Assert;
29 import org.junit.Before;
30 import org.junit.ClassRule;
31 import org.junit.Ignore;
32 import org.junit.Test;
33
34 public class LoggerPrintWriterJdbcH2Test {
35 @ClassRule
36 public static InitialLoggerContext context = new InitialLoggerContext("log4j2-jdbc-driver-manager.xml");
37
38 private static final String H2_URL = "jdbc:h2:mem:Log4j";
39
40 private static final String PASSWORD = Strings.EMPTY;
41
42 private static final String USER_ID = "sa";
43
44 private ListAppender listAppender;
45
46 private PrintWriter createLoggerPrintWriter() {
47 return IoBuilder.forLogger(context.getLogger()).setLevel(Level.ALL).buildPrintWriter();
48 }
49
50 private ListAppender getListAppender() {
51 return listAppender;
52 }
53
54 protected Connection newConnection() throws SQLException {
55 return DriverManager.getConnection(H2_URL, USER_ID, PASSWORD);
56 }
57
58 private void setListAppender(final ListAppender listAppender) {
59 this.listAppender = listAppender;
60 }
61
62 @Before
63 public void setUp() throws Exception {
64 this.setListAppender(context.getListAppender("List").clear());
65 Assert.assertEquals(0, this.getListAppender().getMessages().size());
66 }
67
68 @Test
69 @Ignore("DataSource#setLogWriter() has no effect in H2, it uses its own internal logging and an SLF4J bridge.")
70 public void testDataSource_setLogWriter() throws SQLException {
71 final JdbcDataSource dataSource = new JdbcDataSource();
72 dataSource.setUrl(H2_URL);
73 dataSource.setUser(USER_ID);
74 dataSource.setPassword(PASSWORD);
75 dataSource.setLogWriter(createLoggerPrintWriter());
76 // dataSource.setLogWriter(new PrintWriter(new OutputStreamWriter(System.out)));
77 final Connection conn = dataSource.getConnection();
78 try {
79 conn.prepareCall("select 1");
80 } finally {
81 conn.close();
82 }
83 Assert.assertTrue(this.getListAppender().getMessages().size() > 0);
84 }
85
86 @Test
87 public void testDriverManager_setLogWriter() throws SQLException {
88 DriverManager.setLogWriter(createLoggerPrintWriter());
89 // DriverManager.setLogWriter(new PrintWriter(new OutputStreamWriter(System.out)));
90 try {
91 final Connection conn = this.newConnection();
92 try {
93 conn.rollback();
94 } finally {
95 conn.close();
96 }
97 } finally {
98 DriverManager.setLogWriter(null);
99 }
100 Assert.assertTrue(this.getListAppender().getMessages().size() > 0);
101 }
102 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.io;
17
18 import java.io.PrintWriter;
19 import java.sql.Connection;
20 import java.sql.DriverManager;
21 import java.sql.SQLException;
22
23 import org.apache.logging.log4j.Level;
24 import org.apache.logging.log4j.junit.LoggerContextRule;
25 import org.apache.logging.log4j.test.appender.ListAppender;
26 import org.apache.logging.log4j.util.Strings;
27 import org.h2.jdbcx.JdbcDataSource;
28 import org.junit.Assert;
29 import org.junit.Before;
30 import org.junit.ClassRule;
31 import org.junit.Ignore;
32 import org.junit.Test;
33
34 public class LoggerPrintWriterJdbcH2Test {
35
36 @ClassRule
37 public static LoggerContextRule context = new LoggerContextRule("log4j2-jdbc-driver-manager.xml");
38
39 private static final String H2_URL = "jdbc:h2:mem:Log4j";
40
41 private static final String PASSWORD = Strings.EMPTY;
42
43 private static final String USER_ID = "sa";
44
45 private ListAppender listAppender;
46
47 private PrintWriter createLoggerPrintWriter() {
48 return IoBuilder.forLogger(context.getLogger()).setLevel(Level.ALL).buildPrintWriter();
49 }
50
51 private ListAppender getListAppender() {
52 return listAppender;
53 }
54
55 protected Connection newConnection() throws SQLException {
56 return DriverManager.getConnection(H2_URL, USER_ID, PASSWORD);
57 }
58
59 private void setListAppender(final ListAppender listAppender) {
60 this.listAppender = listAppender;
61 }
62
63 @Before
64 public void setUp() throws Exception {
65 this.setListAppender(context.getListAppender("List").clear());
66 Assert.assertEquals(0, this.getListAppender().getMessages().size());
67 }
68
69 @Test
70 @Ignore("DataSource#setLogWriter() has no effect in H2, it uses its own internal logging and an SLF4J bridge.")
71 public void testDataSource_setLogWriter() throws SQLException {
72 final JdbcDataSource dataSource = new JdbcDataSource();
73 dataSource.setUrl(H2_URL);
74 dataSource.setUser(USER_ID);
75 dataSource.setPassword(PASSWORD);
76 dataSource.setLogWriter(createLoggerPrintWriter());
77 // dataSource.setLogWriter(new PrintWriter(new OutputStreamWriter(System.out)));
78 try (final Connection conn = dataSource.getConnection()) {
79 conn.prepareCall("select 1");
80 }
81 Assert.assertTrue(this.getListAppender().getMessages().size() > 0);
82 }
83
84 @Test
85 public void testDriverManager_setLogWriter() throws SQLException {
86 DriverManager.setLogWriter(createLoggerPrintWriter());
87 // DriverManager.setLogWriter(new PrintWriter(new OutputStreamWriter(System.out)));
88 try (final Connection conn = this.newConnection()) {
89 conn.rollback();
90 } finally {
91 DriverManager.setLogWriter(null);
92 }
93 Assert.assertTrue(this.getListAppender().getMessages().size() > 0);
94 }
95 }
1919 <parent>
2020 <groupId>org.apache.logging.log4j</groupId>
2121 <artifactId>log4j</artifactId>
22 <version>2.2</version>
22 <version>2.4</version>
2323 <relativePath>../</relativePath>
2424 </parent>
2525 <artifactId>log4j-jcl</artifactId>
3232
3333 private final LoggerAdapter<Log> adapter = new LogAdapter();
3434
35 private final ConcurrentMap<String, Object> attributes = new ConcurrentHashMap<String, Object>();
35 private final ConcurrentMap<String, Object> attributes = new ConcurrentHashMap<>();
3636
3737 @Override
3838 public Log getInstance(final String name) throws LogConfigurationException {
3333
3434 <section name="Requirements">
3535 <p>
36 The Commons Logging Bridge requires at least Java 6 and is dependent on the Log4j 2 API
36 The Commons Logging Bridge is dependent on the Log4j 2 API
3737 and Commons Logging.
3838 </p>
3939 </section>
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.jcl;
17
18 import java.util.List;
19
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
22 import org.apache.logging.log4j.junit.InitialLoggerContext;
23 import org.apache.logging.log4j.test.appender.ListAppender;
24 import org.junit.Rule;
25 import org.junit.Test;
26
27 import static org.junit.Assert.assertEquals;
28
29 public class CallerInformationTest {
30
31 // config from log4j-core test-jar
32 private static final String CONFIG = "log4j2-calling-class.xml";
33
34 @Rule
35 public final InitialLoggerContext ctx = new InitialLoggerContext(CONFIG);
36
37 @Test
38 public void testClassLogger() throws Exception {
39 final ListAppender app = ctx.getListAppender("Class").clear();
40 final Log logger = LogFactory.getLog("ClassLogger");
41 logger.info("Ignored message contents.");
42 logger.warn("Verifying the caller class is still correct.");
43 logger.error("Hopefully nobody breaks me!");
44 final List<String> messages = app.getMessages();
45 assertEquals("Incorrect number of messages.", 3, messages.size());
46 for (final String message : messages) {
47 assertEquals("Incorrect caller class name.", this.getClass().getName(), message);
48 }
49 }
50
51 @Test
52 public void testMethodLogger() throws Exception {
53 final ListAppender app = ctx.getListAppender("Method").clear();
54 final Log logger = LogFactory.getLog("MethodLogger");
55 logger.info("More messages.");
56 logger.warn("CATASTROPHE INCOMING!");
57 logger.error("ZOMBIES!!!");
58 logger.warn("brains~~~");
59 logger.info("Itchy. Tasty.");
60 final List<String> messages = app.getMessages();
61 assertEquals("Incorrect number of messages.", 5, messages.size());
62 for (final String message : messages) {
63 assertEquals("Incorrect caller method name.", "testMethodLogger", message);
64 }
65 }
66 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.jcl;
17
18 import static org.junit.Assert.assertEquals;
19
20 import java.util.List;
21
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24 import org.apache.logging.log4j.junit.LoggerContextRule;
25 import org.apache.logging.log4j.test.appender.ListAppender;
26 import org.junit.ClassRule;
27 import org.junit.Test;
28
29 public class CallerInformationTest {
30
31 // config from log4j-core test-jar
32 private static final String CONFIG = "log4j2-calling-class.xml";
33
34 @ClassRule
35 public static final LoggerContextRule ctx = new LoggerContextRule(CONFIG);
36
37 @Test
38 public void testClassLogger() throws Exception {
39 final ListAppender app = ctx.getListAppender("Class").clear();
40 final Log logger = LogFactory.getLog("ClassLogger");
41 logger.info("Ignored message contents.");
42 logger.warn("Verifying the caller class is still correct.");
43 logger.error("Hopefully nobody breaks me!");
44 final List<String> messages = app.getMessages();
45 assertEquals("Incorrect number of messages.", 3, messages.size());
46 for (final String message : messages) {
47 assertEquals("Incorrect caller class name.", this.getClass().getName(), message);
48 }
49 }
50
51 @Test
52 public void testMethodLogger() throws Exception {
53 final ListAppender app = ctx.getListAppender("Method").clear();
54 final Log logger = LogFactory.getLog("MethodLogger");
55 logger.info("More messages.");
56 logger.warn("CATASTROPHE INCOMING!");
57 logger.error("ZOMBIES!!!");
58 logger.warn("brains~~~");
59 logger.info("Itchy. Tasty.");
60 final List<String> messages = app.getMessages();
61 assertEquals("Incorrect number of messages.", 5, messages.size());
62 for (final String message : messages) {
63 assertEquals("Incorrect caller method name.", "testMethodLogger", message);
64 }
65 }
66 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.jcl;
17
18 import java.util.List;
19
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
22 import org.apache.logging.log4j.core.util.Constants;
23 import org.apache.logging.log4j.junit.InitialLoggerContext;
24 import org.apache.logging.log4j.test.appender.ListAppender;
25 import org.junit.Rule;
26 import org.junit.Test;
27
28 import static org.hamcrest.Matchers.equalTo;
29 import static org.hamcrest.Matchers.hasSize;
30 import static org.junit.Assert.*;
31
32 /**
33 *
34 */
35 public class LoggerTest {
36
37 private static final String CONFIG = "log4j-test1.xml";
38
39 @Rule
40 public final InitialLoggerContext context = new InitialLoggerContext(CONFIG);
41
42 @Test
43 public void testLog() {
44 final Log logger = LogFactory.getLog("LoggerTest");
45 logger.debug("Test message");
46 verify("List", "o.a.l.l.j.LoggerTest Test message MDC{}" + Constants.LINE_SEPARATOR);
47 logger.debug("Exception: " , new NullPointerException("Test"));
48 verify("List", "o.a.l.l.j.LoggerTest Exception: MDC{}" + Constants.LINE_SEPARATOR);
49 logger.info("Info Message");
50 verify("List", "o.a.l.l.j.LoggerTest Info Message MDC{}" + Constants.LINE_SEPARATOR);
51 logger.info("Info Message {}");
52 verify("List", "o.a.l.l.j.LoggerTest Info Message {} MDC{}" + Constants.LINE_SEPARATOR);
53 }
54
55 private void verify(final String name, final String expected) {
56 final ListAppender listApp = context.getListAppender(name);
57 final List<String> events = listApp.getMessages();
58 assertThat(events, hasSize(1));
59 final String actual = events.get(0);
60 assertThat(actual, equalTo(expected));
61 listApp.clear();
62 }
63
64 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.jcl;
17
18 import java.util.List;
19
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
22 import org.apache.logging.log4j.core.util.Constants;
23 import org.apache.logging.log4j.junit.LoggerContextRule;
24 import org.apache.logging.log4j.test.appender.ListAppender;
25 import org.junit.ClassRule;
26 import org.junit.Test;
27
28 import static org.hamcrest.Matchers.equalTo;
29 import static org.hamcrest.Matchers.hasSize;
30 import static org.junit.Assert.*;
31
32 /**
33 *
34 */
35 public class LoggerTest {
36
37 private static final String CONFIG = "log4j-test1.xml";
38
39 @ClassRule
40 public static final LoggerContextRule context = new LoggerContextRule(CONFIG);
41
42 @Test
43 public void testLog() {
44 final Log logger = LogFactory.getLog("LoggerTest");
45 logger.debug("Test message");
46 verify("List", "o.a.l.l.j.LoggerTest Test message MDC{}" + Constants.LINE_SEPARATOR);
47 logger.debug("Exception: " , new NullPointerException("Test"));
48 verify("List", "o.a.l.l.j.LoggerTest Exception: MDC{}" + Constants.LINE_SEPARATOR);
49 logger.info("Info Message");
50 verify("List", "o.a.l.l.j.LoggerTest Info Message MDC{}" + Constants.LINE_SEPARATOR);
51 logger.info("Info Message {}");
52 verify("List", "o.a.l.l.j.LoggerTest Info Message {} MDC{}" + Constants.LINE_SEPARATOR);
53 }
54
55 private void verify(final String name, final String expected) {
56 final ListAppender listApp = context.getListAppender(name);
57 final List<String> events = listApp.getMessages();
58 assertThat(events, hasSize(1));
59 final String actual = events.get(0);
60 assertThat(actual, equalTo(expected));
61 listApp.clear();
62 }
63
64 }
1919 <parent>
2020 <groupId>org.apache.logging.log4j</groupId>
2121 <artifactId>log4j</artifactId>
22 <version>2.2</version>
22 <version>2.4</version>
2323 <relativePath>../</relativePath>
2424 </parent>
2525 <artifactId>log4j-jmx-gui</artifactId>
1818 import java.io.IOException;
1919 import java.util.ArrayList;
2020 import java.util.List;
21 import java.util.Objects;
2122 import java.util.Set;
2223
2324 import javax.management.JMException;
3031 import org.apache.logging.log4j.core.jmx.LoggerContextAdminMBean;
3132 import org.apache.logging.log4j.core.jmx.Server;
3233 import org.apache.logging.log4j.core.jmx.StatusLoggerAdminMBean;
33 import org.apache.logging.log4j.core.util.Assert;
3434 import org.apache.logging.log4j.core.util.Closer;
3535
3636 /**
5252 * @throws IOException if the connection failed
5353 */
5454 public Client(final JMXConnector connector) throws MalformedObjectNameException, IOException {
55 this.connector = Assert.requireNonNull(connector, "JMXConnector");
55 this.connector = Objects.requireNonNull(connector, "JMXConnector");
5656 this.connector.connect();
5757 this.connection = connector.getMBeanServerConnection();
5858 init();
9191 * @throws JMException If a management error occurred
9292 */
9393 public List<LoggerContextAdminMBean> getLoggerContextAdmins() throws JMException, IOException {
94 final List<LoggerContextAdminMBean> result = new ArrayList<LoggerContextAdminMBean>();
94 final List<LoggerContextAdminMBean> result = new ArrayList<>();
9595 final Set<ObjectName> contextNames = find(LoggerContextAdminMBean.PATTERN);
9696 for (final ObjectName contextName : contextNames) {
9797 result.add(getLoggerContextAdmin(contextName));
2525 import java.io.StringWriter;
2626 import java.util.HashMap;
2727 import java.util.Map;
28 import java.util.Objects;
2829 import java.util.Properties;
30
2931 import javax.management.InstanceNotFoundException;
3032 import javax.management.JMException;
3133 import javax.management.ListenerNotFoundException;
5658 import org.apache.logging.log4j.core.jmx.LoggerContextAdminMBean;
5759 import org.apache.logging.log4j.core.jmx.Server;
5860 import org.apache.logging.log4j.core.jmx.StatusLoggerAdminMBean;
59 import org.apache.logging.log4j.core.util.Assert;
6061
6162 /**
6263 * Swing GUI that connects to a Java process via JMX and allows the user to view
7172 private static final long serialVersionUID = -253621277232291174L;
7273 private static final int INITIAL_STRING_WRITER_SIZE = 1024;
7374 private final Client client;
74 private final Map<ObjectName, Component> contextObjNameToTabbedPaneMap = new HashMap<ObjectName, Component>();
75 private final Map<ObjectName, JTextArea> statusLogTextAreaMap = new HashMap<ObjectName, JTextArea>();
75 private final Map<ObjectName, Component> contextObjNameToTabbedPaneMap = new HashMap<>();
76 private final Map<ObjectName, JTextArea> statusLogTextAreaMap = new HashMap<>();
7677 private JTabbedPane tabbedPaneContexts;
7778
7879 public ClientGui(final Client client) throws IOException, JMException {
79 this.client = Assert.requireNonNull(client, "client");
80 this.client = Objects.requireNonNull(client, "client");
8081 createWidgets();
8182 populateWidgets();
8283
274275 }
275276 final JMXServiceURL url = new JMXServiceURL(serviceUrl);
276277 final Properties props = System.getProperties();
277 final Map<String, String> paramMap = new HashMap<String, String>(props.size());
278 final Map<String, String> paramMap = new HashMap<>(props.size());
278279 for (final String key : props.stringPropertyNames()) {
279280 paramMap.put(key, props.getProperty(key));
280281 }
3333 try {
3434 final Client client = new Client(getContext().getMBeanServerConnection());
3535 final ClientGui gui = new ClientGui(client);
36 final Map<String, JPanel> result = new HashMap<String, JPanel>();
36 final Map<String, JPanel> result = new HashMap<>();
3737 result.put("Log4j2", gui);
3838 return result;
3939 } catch (final Throwable ex) {
3434
3535 <section name="Requirements">
3636 <p>
37 The JMX GUI requires at least Java 6 and is dependent on Log4j 2 Core.
37 The JMX GUI is dependent on Log4j 2 Core.
3838 </p>
3939 </section>
4040
1919 <parent>
2020 <artifactId>log4j</artifactId>
2121 <groupId>org.apache.logging.log4j</groupId>
22 <version>2.2</version>
22 <version>2.4</version>
2323 <relativePath>../</relativePath>
2424 </parent>
2525 <modelVersion>4.0.0</modelVersion>
8686 </instructions>
8787 </configuration>
8888 </plugin>
89 <plugin>
90 <groupId>org.apache.maven.plugins</groupId>
91 <artifactId>maven-surefire-plugin</artifactId>
92 <version>${surefire.plugin.version}</version>
93 <configuration>
94 <systemPropertyVariables>
95 <java.awt.headless>true</java.awt.headless>
96 </systemPropertyVariables>
97 <argLine>-Xms256m -Xmx1024m</argLine>
98 <forkCount>1</forkCount>
99 <reuseForks>false</reuseForks>
100 <excludes>
101 <exclude>${log4j.skip.test1}</exclude>
102 <exclude>${log4j.skip.test2}</exclude>
103 </excludes>
104 </configuration>
105 </plugin>
89106 </plugins>
90107 </build>
91108 <reporting>
4343
4444 @Override
4545 public void setLevel(final Level level) throws SecurityException {
46 super.doSetLevel(level); // checks permissions
4647 logger.setLevel(LevelTranslator.toLevel(level));
47 super.doSetLevel(level);
4848 }
4949
5050 /**
1616
1717 package org.apache.logging.log4j.jul;
1818
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.Comparator;
1922 import java.util.IdentityHashMap;
23 import java.util.List;
2024 import java.util.Map;
25 import java.util.concurrent.ConcurrentHashMap;
26 import java.util.concurrent.ConcurrentMap;
2127
2228 import org.apache.logging.log4j.Level;
2329
2430 /**
2531 * Default implementation of LevelConverter strategy.
26 *
32 * <p>
33 * Since 2.4, supports custom JUL levels by mapping them to their closest mapped neighbour.
34 * </p>
35 *
2736 * @since 2.1
2837 */
2938 public class DefaultLevelConverter implements LevelConverter {
3039
31 private final Map<java.util.logging.Level, Level> JDK_TO_LOG4J =
32 new IdentityHashMap<java.util.logging.Level, Level>(9);
33 private final Map<Level, java.util.logging.Level> LOG4J_TO_JDK =
34 new IdentityHashMap<Level, java.util.logging.Level>(10);
40 static final class JulLevelComparator implements Comparator<java.util.logging.Level> {
41 @Override
42 public int compare(final java.util.logging.Level level1, final java.util.logging.Level level2) {
43 return Integer.compare(level1.intValue(), level2.intValue());
44 }
45 }
46
47 private final ConcurrentMap<java.util.logging.Level, Level> julToLog4j = new ConcurrentHashMap<>(9);
48 private final Map<Level, java.util.logging.Level> log4jToJul = new IdentityHashMap<>(10);
49 private final List<java.util.logging.Level> sortedJulLevels = new ArrayList<>(9);
3550
3651 public DefaultLevelConverter() {
37 JDK_TO_LOG4J.put(java.util.logging.Level.OFF, Level.OFF);
38 JDK_TO_LOG4J.put(java.util.logging.Level.FINEST, LevelTranslator.FINEST);
39 JDK_TO_LOG4J.put(java.util.logging.Level.FINER, Level.TRACE);
40 JDK_TO_LOG4J.put(java.util.logging.Level.FINE, Level.DEBUG);
41 JDK_TO_LOG4J.put(java.util.logging.Level.CONFIG, LevelTranslator.CONFIG);
42 JDK_TO_LOG4J.put(java.util.logging.Level.INFO, Level.INFO);
43 JDK_TO_LOG4J.put(java.util.logging.Level.WARNING, Level.WARN);
44 JDK_TO_LOG4J.put(java.util.logging.Level.SEVERE, Level.ERROR);
45 JDK_TO_LOG4J.put(java.util.logging.Level.ALL, Level.ALL);
46 LOG4J_TO_JDK.put(Level.OFF, java.util.logging.Level.OFF);
47 LOG4J_TO_JDK.put(LevelTranslator.FINEST, java.util.logging.Level.FINEST);
48 LOG4J_TO_JDK.put(Level.TRACE, java.util.logging.Level.FINER);
49 LOG4J_TO_JDK.put(Level.DEBUG, java.util.logging.Level.FINE);
50 LOG4J_TO_JDK.put(LevelTranslator.CONFIG, java.util.logging.Level.CONFIG);
51 LOG4J_TO_JDK.put(Level.INFO, java.util.logging.Level.INFO);
52 LOG4J_TO_JDK.put(Level.WARN, java.util.logging.Level.WARNING);
53 LOG4J_TO_JDK.put(Level.ERROR, java.util.logging.Level.SEVERE);
54 LOG4J_TO_JDK.put(Level.FATAL, java.util.logging.Level.SEVERE);
55 LOG4J_TO_JDK.put(Level.ALL, java.util.logging.Level.ALL);
52 // Map JUL to Log4j
53 mapJulToLog4j(java.util.logging.Level.ALL, Level.ALL);
54 mapJulToLog4j(java.util.logging.Level.FINEST, LevelTranslator.FINEST);
55 mapJulToLog4j(java.util.logging.Level.FINER, Level.TRACE);
56 mapJulToLog4j(java.util.logging.Level.FINE, Level.DEBUG);
57 mapJulToLog4j(java.util.logging.Level.CONFIG, LevelTranslator.CONFIG);
58 mapJulToLog4j(java.util.logging.Level.INFO, Level.INFO);
59 mapJulToLog4j(java.util.logging.Level.WARNING, Level.WARN);
60 mapJulToLog4j(java.util.logging.Level.SEVERE, Level.ERROR);
61 mapJulToLog4j(java.util.logging.Level.OFF, Level.OFF);
62 // Map Log4j to JUL
63 mapLog4jToJul(Level.ALL, java.util.logging.Level.ALL);
64 mapLog4jToJul(LevelTranslator.FINEST, java.util.logging.Level.FINEST);
65 mapLog4jToJul(Level.TRACE, java.util.logging.Level.FINER);
66 mapLog4jToJul(Level.DEBUG, java.util.logging.Level.FINE);
67 mapLog4jToJul(LevelTranslator.CONFIG, java.util.logging.Level.CONFIG);
68 mapLog4jToJul(Level.INFO, java.util.logging.Level.INFO);
69 mapLog4jToJul(Level.WARN, java.util.logging.Level.WARNING);
70 mapLog4jToJul(Level.ERROR, java.util.logging.Level.SEVERE);
71 mapLog4jToJul(Level.FATAL, java.util.logging.Level.SEVERE);
72 mapLog4jToJul(Level.OFF, java.util.logging.Level.OFF);
73 // Sorted Java levels
74 sortedJulLevels.addAll(julToLog4j.keySet());
75 Collections.sort(sortedJulLevels, new JulLevelComparator());
76
77 }
78
79 private long distance(final java.util.logging.Level javaLevel, final java.util.logging.Level customJavaLevel) {
80 return Math.abs((long) customJavaLevel.intValue() - (long) javaLevel.intValue());
81 }
82
83 /*
84 * TODO consider making public for advanced configuration.
85 */
86 private void mapJulToLog4j(final java.util.logging.Level julLevel, final Level level) {
87 julToLog4j.put(julLevel, level);
88 }
89
90 /*
91 * TODO consider making public for advanced configuration.
92 */
93 private void mapLog4jToJul(final Level level, final java.util.logging.Level julLevel) {
94 log4jToJul.put(level, julLevel);
95 }
96
97 private Level nearestLevel(final java.util.logging.Level customJavaLevel) {
98 long prevDist = Long.MAX_VALUE;
99 java.util.logging.Level prevLevel = null;
100 for (final java.util.logging.Level mappedJavaLevel : sortedJulLevels) {
101 final long distance = distance(customJavaLevel, mappedJavaLevel);
102 if (distance > prevDist) {
103 return julToLog4j.get(prevLevel);
104 }
105 prevDist = distance;
106 prevLevel = mappedJavaLevel;
107 }
108 return julToLog4j.get(prevLevel);
109 }
110
111 @Override
112 public java.util.logging.Level toJavaLevel(final Level level) {
113 return log4jToJul.get(level);
56114 }
57115
58116 @Override
59117 public Level toLevel(final java.util.logging.Level javaLevel) {
60 return JDK_TO_LOG4J.get(javaLevel);
61 }
62
63 @Override
64 public java.util.logging.Level toJavaLevel(final Level level) {
65 return LOG4J_TO_JDK.get(level);
118 if (javaLevel == null) {
119 return null;
120 }
121 final Level level = julToLog4j.get(javaLevel);
122 if (level != null) {
123 return level;
124 }
125 final Level nearestLevel = nearestLevel(javaLevel);
126 julToLog4j.put(javaLevel, nearestLevel);
127 return nearestLevel;
66128 }
67129 }
3030 /**
3131 * Converts a JDK logging Level to a Log4j logging Level.
3232 *
33 * @param javaLevel JDK Level to convert.
33 * @param javaLevel JDK Level to convert, may be null per the JUL specification.
3434 * @return converted Level or {@code null} if the given level could not be converted.
3535 */
3636 Level toLevel(java.util.logging.Level javaLevel);
6464 /**
6565 * Converts a JDK logging Level to a Log4j logging Level.
6666 *
67 * @param level JDK Level to convert.
68 * @return converted Level.
67 * @param level JDK Level to convert, may be null per the JUL specification.
68 * @return converted Level or null
6969 */
7070 public static Level toLevel(final java.util.logging.Level level) {
7171 return LEVEL_CONVERTER.toLevel(level);
7171
7272 @Override
7373 public <T extends Throwable> T throwing(final T t) {
74 return throwing(FQCN, Level.ERROR, t);
74 return throwing(FQCN, LevelTranslator.toLevel(java.util.logging.Level.FINER), t);
7575 }
7676 }
3434 </section>
3535 <section name="Requirements">
3636 <p>
37 The JDK Logging Adapter requires at least Java 6 and is dependent on the Log4j API and optionally Log4j Core.
37 The JDK Logging Adapter is dependent on the Log4j API and optionally Log4j Core.
3838 </p>
3939 </section>
4040 <section name="Usage">
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.jul;
17
18 import java.util.List;
19 import java.util.logging.Logger;
20
21 import org.apache.logging.log4j.junit.InitialLoggerContext;
22 import org.apache.logging.log4j.test.appender.ListAppender;
23 import org.junit.AfterClass;
24 import org.junit.BeforeClass;
25 import org.junit.Rule;
26 import org.junit.Test;
27
28 import static org.junit.Assert.*;
29
30 public class CallerInformationTest {
31
32 // config from log4j-core test-jar
33 private static final String CONFIG = "log4j2-calling-class.xml";
34
35 @Rule
36 public final InitialLoggerContext ctx = new InitialLoggerContext(CONFIG);
37
38 @BeforeClass
39 public static void setUpClass() {
40 System.setProperty("java.util.logging.manager", LogManager.class.getName());
41 }
42
43 @AfterClass
44 public static void tearDownClass() {
45 System.clearProperty("java.util.logging.manager");
46 }
47
48 @Test
49 public void testClassLogger() throws Exception {
50 final ListAppender app = ctx.getListAppender("Class").clear();
51 final Logger logger = Logger.getLogger("ClassLogger");
52 logger.info("Ignored message contents.");
53 logger.warning("Verifying the caller class is still correct.");
54 logger.severe("Hopefully nobody breaks me!");
55 final List<String> messages = app.getMessages();
56 assertEquals("Incorrect number of messages.", 3, messages.size());
57 for (final String message : messages) {
58 assertEquals("Incorrect caller class name.", this.getClass().getName(), message);
59 }
60 }
61
62 @Test
63 public void testMethodLogger() throws Exception {
64 final ListAppender app = ctx.getListAppender("Method").clear();
65 final Logger logger = Logger.getLogger("MethodLogger");
66 logger.info("More messages.");
67 logger.warning("CATASTROPHE INCOMING!");
68 logger.severe("ZOMBIES!!!");
69 logger.warning("brains~~~");
70 logger.info("Itchy. Tasty.");
71 final List<String> messages = app.getMessages();
72 assertEquals("Incorrect number of messages.", 5, messages.size());
73 for (final String message : messages) {
74 assertEquals("Incorrect caller method name.", "testMethodLogger", message);
75 }
76 }
77 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.jul;
17
18 import java.util.List;
19 import java.util.logging.Logger;
20
21 import org.apache.logging.log4j.junit.LoggerContextRule;
22 import org.apache.logging.log4j.test.appender.ListAppender;
23 import org.junit.AfterClass;
24 import org.junit.BeforeClass;
25 import org.junit.Rule;
26 import org.junit.Test;
27
28 import static org.junit.Assert.*;
29
30 public class CallerInformationTest {
31
32 // config from log4j-core test-jar
33 private static final String CONFIG = "log4j2-calling-class.xml";
34
35 @Rule
36 public final LoggerContextRule ctx = new LoggerContextRule(CONFIG);
37
38 @BeforeClass
39 public static void setUpClass() {
40 System.setProperty("java.util.logging.manager", LogManager.class.getName());
41 }
42
43 @AfterClass
44 public static void tearDownClass() {
45 System.clearProperty("java.util.logging.manager");
46 }
47
48 @Test
49 public void testClassLogger() throws Exception {
50 final ListAppender app = ctx.getListAppender("Class").clear();
51 final Logger logger = Logger.getLogger("ClassLogger");
52 logger.info("Ignored message contents.");
53 logger.warning("Verifying the caller class is still correct.");
54 logger.severe("Hopefully nobody breaks me!");
55 final List<String> messages = app.getMessages();
56 assertEquals("Incorrect number of messages.", 3, messages.size());
57 for (final String message : messages) {
58 assertEquals("Incorrect caller class name.", this.getClass().getName(), message);
59 }
60 }
61
62 @Test
63 public void testMethodLogger() throws Exception {
64 final ListAppender app = ctx.getListAppender("Method").clear();
65 final Logger logger = Logger.getLogger("MethodLogger");
66 logger.info("More messages.");
67 logger.warning("CATASTROPHE INCOMING!");
68 logger.severe("ZOMBIES!!!");
69 logger.warning("brains~~~");
70 logger.info("Itchy. Tasty.");
71 final List<String> messages = app.getMessages();
72 assertEquals("Incorrect number of messages.", 5, messages.size());
73 for (final String message : messages) {
74 assertEquals("Incorrect caller method name.", "testMethodLogger", message);
75 }
76 }
77 }
1717 package org.apache.logging.log4j.jul;
1818
1919 import static org.hamcrest.Matchers.equalTo;
20 import static org.hamcrest.Matchers.is;
2021 import static org.junit.Assert.assertThat;
2122
2223 import java.util.logging.Level;
2324 import java.util.logging.Logger;
2425
2526 import org.apache.logging.log4j.test.appender.ListAppender;
27 import org.apache.logging.log4j.util.Strings;
2628 import org.junit.After;
2729 import org.junit.AfterClass;
2830 import org.junit.Before;
6062 }
6163
6264 @Test
65 public void testRootSetLevelToNull() throws Exception {
66 final Logger rootLogger = Logger.getLogger(Strings.EMPTY);
67 assertThat(rootLogger.getLevel(), equalTo(Level.SEVERE));
68 assertThat(rootLogger.isLoggable(Level.SEVERE), is(true));
69 // null test
70 rootLogger.setLevel(null);
71 assertThat(rootLogger.getLevel(), equalTo(null));
72 assertThat(rootLogger.isLoggable(Level.SEVERE), is(true));
73 // now go back to a different one
74 rootLogger.setLevel(Level.INFO);
75 assertThat(rootLogger.getLevel(), equalTo(Level.INFO));
76 assertThat(rootLogger.isLoggable(Level.FINE), is(false));
77 }
78
79 @Test
6380 public void testSetLevel() throws Exception {
6481 final Logger childLogger = Logger.getLogger(LOGGER_NAME + ".Child");
6582 assertThat(childLogger.getLevel(), equalTo(Level.FINE));
7188 logger.setLevel(Level.FINE);
7289 assertThat(logger.getLevel(), equalTo(Level.FINE));
7390 assertThat(childLogger.getLevel(), equalTo(Level.FINE));
91 assertThat(childLogger.isLoggable(Level.ALL), is(false));
7492 }
93
94 @Test
95 public void testSetLevelToNull() throws Exception {
96 final Logger childLogger = Logger.getLogger(LOGGER_NAME + ".NullChild");
97 assertThat(childLogger.getLevel(), equalTo(Level.FINE));
98 assertThat(childLogger.isLoggable(Level.FINE), is(true));
99 childLogger.setLevel(Level.SEVERE);
100 assertThat(childLogger.getLevel(), equalTo(Level.SEVERE));
101 assertThat(childLogger.isLoggable(Level.FINE), is(false));
102 // null test
103 childLogger.setLevel(null);
104 assertThat(childLogger.getLevel(), equalTo(null));
105 assertThat(childLogger.isLoggable(Level.FINE), is(true));
106 // now go back
107 childLogger.setLevel(Level.SEVERE);
108 assertThat(childLogger.getLevel(), equalTo(Level.SEVERE));
109 assertThat(childLogger.isLoggable(Level.FINE), is(false));
110 }
111
75112 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.jul;
17
18 import org.apache.logging.log4j.Level;
19 import org.junit.Assert;
20 import org.junit.Test;
21
22 /**
23 * Tests {@link DefaultLevelConverter} for custom JUL levels.
24 *
25 * @since 2.4
26 */
27 public class DefaultLevelConverterCustomJulLevelsTest {
28
29 static class CustomLevel extends java.util.logging.Level {
30
31 private static final long serialVersionUID = 1L;
32
33 static CustomLevel ALL_P_1 = new CustomLevel("ALL_P_1", java.util.logging.Level.ALL.intValue() + 1);
34
35 static CustomLevel FINEST_P_1 = new CustomLevel("FINEST_P_1", java.util.logging.Level.FINEST.intValue() + 1);
36 static CustomLevel FINEST_M_1 = new CustomLevel("FINEST_M_1", java.util.logging.Level.FINEST.intValue() - 1);
37
38 static CustomLevel FINER_P_1 = new CustomLevel("FINER_P_1", java.util.logging.Level.FINER.intValue() + 1);
39 static CustomLevel FINER_M_1 = new CustomLevel("FINER_M_1", java.util.logging.Level.FINER.intValue() - 1);
40
41 static CustomLevel FINE_P_1 = new CustomLevel("FINE_P_1", java.util.logging.Level.FINE.intValue() + 1);
42 static CustomLevel FINE_M_1 = new CustomLevel("FINE_M_1", java.util.logging.Level.FINE.intValue() - 1);
43
44 static CustomLevel CONFIG_P_1 = new CustomLevel("CONFIG_P_1", java.util.logging.Level.CONFIG.intValue() + 1);
45 static CustomLevel CONFIG_M_1 = new CustomLevel("CONFIG_M_1", java.util.logging.Level.CONFIG.intValue() - 1);
46
47 static CustomLevel INFO_P_1 = new CustomLevel("INFO_P_1", java.util.logging.Level.INFO.intValue() + 1);
48 static CustomLevel INFO_M_1 = new CustomLevel("INFO_M_1", java.util.logging.Level.INFO.intValue() - 1);
49
50 static CustomLevel WARNING_P_1 = new CustomLevel("WARNING_P_1", java.util.logging.Level.WARNING.intValue() + 1);
51 static CustomLevel WARNING_M_1 = new CustomLevel("WARNING_M_1", java.util.logging.Level.WARNING.intValue() - 1);
52
53 static CustomLevel SEVERE_P_1 = new CustomLevel("SEVERE_P_1", java.util.logging.Level.SEVERE.intValue() + 1);
54 static CustomLevel SEVERE_M_1 = new CustomLevel("SEVERE_M_1", java.util.logging.Level.SEVERE.intValue() - 1);
55
56 static CustomLevel OFF_M_1 = new CustomLevel("OFF_M_1", java.util.logging.Level.OFF.intValue() - 1);
57
58 protected CustomLevel(final String name, final int value) {
59 super(name, value);
60 }
61 }
62
63 private final DefaultLevelConverter converter = new DefaultLevelConverter();
64
65 @Test
66 public void testCustomJulLevelNearAll() {
67 // Sanity check:
68 Assert.assertEquals(Level.ALL, converter.toLevel(java.util.logging.Level.ALL));
69 // Test:
70 Assert.assertEquals(Level.ALL, converter.toLevel(CustomLevel.ALL_P_1));
71 }
72
73 @Test
74 public void testCustomJulLevelNearFinest() {
75 // Sanity check:
76 Assert.assertEquals(LevelTranslator.FINEST, converter.toLevel(java.util.logging.Level.FINEST));
77 // Test:
78 Assert.assertEquals(LevelTranslator.FINEST, converter.toLevel(CustomLevel.FINEST_P_1));
79 Assert.assertEquals(LevelTranslator.FINEST, converter.toLevel(CustomLevel.FINEST_M_1));
80 }
81
82 @Test
83 public void testCustomJulLevelNearFiner() {
84 // Sanity check:
85 Assert.assertEquals(Level.TRACE, converter.toLevel(java.util.logging.Level.FINER));
86 // Test:
87 Assert.assertEquals(Level.TRACE, converter.toLevel(CustomLevel.FINER_P_1));
88 Assert.assertEquals(Level.TRACE, converter.toLevel(CustomLevel.FINER_M_1));
89 }
90
91 @Test
92 public void testCustomJulLevelNearFine() {
93 // Sanity check:
94 Assert.assertEquals(Level.DEBUG, converter.toLevel(java.util.logging.Level.FINE));
95 // Test:
96 Assert.assertEquals(Level.DEBUG, converter.toLevel(CustomLevel.FINE_P_1));
97 Assert.assertEquals(Level.DEBUG, converter.toLevel(CustomLevel.FINE_M_1));
98 }
99
100 @Test
101 public void testCustomJulLevelNearConfig() {
102 // Sanity check:
103 Assert.assertEquals(LevelTranslator.CONFIG, converter.toLevel(java.util.logging.Level.CONFIG));
104 // Test:
105 Assert.assertEquals(LevelTranslator.CONFIG, converter.toLevel(CustomLevel.CONFIG_P_1));
106 Assert.assertEquals(LevelTranslator.CONFIG, converter.toLevel(CustomLevel.CONFIG_M_1));
107 }
108
109 @Test
110 public void testCustomJulLevelNearInfo() {
111 // Sanity check:
112 Assert.assertEquals(Level.INFO, converter.toLevel(java.util.logging.Level.INFO));
113 // Test:
114 Assert.assertEquals(Level.INFO, converter.toLevel(CustomLevel.INFO_P_1));
115 Assert.assertEquals(Level.INFO, converter.toLevel(CustomLevel.INFO_M_1));
116 }
117
118 @Test
119 public void testCustomJulLevelNearWarning() {
120 // Sanity check:
121 Assert.assertEquals(Level.WARN, converter.toLevel(java.util.logging.Level.WARNING));
122 // Test:
123 Assert.assertEquals(Level.WARN, converter.toLevel(CustomLevel.WARNING_P_1));
124 Assert.assertEquals(Level.WARN, converter.toLevel(CustomLevel.WARNING_M_1));
125 }
126
127 @Test
128 public void testCustomJulLevelNearSevere() {
129 // Sanity check:
130 Assert.assertEquals(Level.ERROR, converter.toLevel(java.util.logging.Level.SEVERE));
131 // Test:
132 Assert.assertEquals(Level.ERROR, converter.toLevel(CustomLevel.SEVERE_P_1));
133 Assert.assertEquals(Level.ERROR, converter.toLevel(CustomLevel.SEVERE_M_1));
134 }
135
136 @Test
137 public void testCustomJulLevelNearOff() {
138 // Sanity check:
139 Assert.assertEquals(Level.OFF, converter.toLevel(java.util.logging.Level.OFF));
140 // Test:
141 Assert.assertEquals(Level.OFF, converter.toLevel(CustomLevel.OFF_M_1));
142 }
143 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.jul;
17
18 import org.junit.Assert;
19 import org.junit.Test;
20
21 public class DefaultLevelConverterTest {
22
23 /**
24 * (LOG4J2-1108) NullPointerException when passing null to java.util.logging.Logger.setLevel().
25 */
26 @Test
27 public void testJulSetNull() {
28 Assert.assertEquals(null, new DefaultLevelConverter().toLevel(null));
29 }
30 }
0 /.classpath
1 /.project
2 /.settings/
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
18 <modelVersion>4.0.0</modelVersion>
19 <parent>
20 <groupId>org.apache.logging.log4j</groupId>
21 <artifactId>log4j</artifactId>
22 <version>2.4</version>
23 <relativePath>../</relativePath>
24 </parent>
25 <artifactId>log4j-liquibase</artifactId>
26 <packaging>jar</packaging>
27 <name>Apache Log4j Liquibase Binding</name>
28 <description>The Apache Log4j Liquibase binding to Log4j 2 Core</description>
29 <properties>
30 <log4jParentDir>${basedir}/..</log4jParentDir>
31 <docLabel>Liquibase Documentation</docLabel>
32 <projectDir>/liquibase</projectDir>
33 </properties>
34 <dependencies>
35 <dependency>
36 <groupId>org.apache.logging.log4j</groupId>
37 <artifactId>log4j-api</artifactId>
38 </dependency>
39 <dependency>
40 <groupId>org.liquibase</groupId>
41 <artifactId>liquibase-core</artifactId>
42 </dependency>
43 <dependency>
44 <groupId>org.apache.logging.log4j</groupId>
45 <artifactId>log4j-api</artifactId>
46 <type>test-jar</type>
47 <scope>test</scope>
48 </dependency>
49 <dependency>
50 <groupId>org.apache.commons</groupId>
51 <artifactId>commons-lang3</artifactId>
52 <scope>test</scope>
53 </dependency>
54 <dependency>
55 <groupId>org.apache.logging.log4j</groupId>
56 <artifactId>log4j-core</artifactId>
57 <scope>test</scope>
58 </dependency>
59 <dependency>
60 <groupId>org.apache.logging.log4j</groupId>
61 <artifactId>log4j-core</artifactId>
62 <type>test-jar</type>
63 <scope>test</scope>
64 </dependency>
65 <dependency>
66 <groupId>junit</groupId>
67 <artifactId>junit</artifactId>
68 <scope>test</scope>
69 </dependency>
70 </dependencies>
71 <build>
72 <plugins>
73 <plugin>
74 <groupId>org.apache.maven.plugins</groupId>
75 <artifactId>maven-surefire-plugin</artifactId>
76 <configuration>
77 <excludes>
78 <exclude>**/*Test.java</exclude>
79 </excludes>
80 </configuration>
81 <executions>
82 <execution>
83 <id>default-tests</id>
84 <phase>test</phase>
85 <goals>
86 <goal>test</goal>
87 </goals>
88 <configuration>
89 <includes>
90 <include>**/*Test.java</include>
91 </includes>
92 <excludes>
93 <exclude>**/OptionalTest.java</exclude>
94 </excludes>
95 </configuration>
96 </execution>
97 <execution>
98 <id>test-optional</id>
99 <phase>test</phase>
100 <goals>
101 <goal>test</goal>
102 </goals>
103 <configuration>
104 <excludes>
105 <exclude>**/LoggerTest.java</exclude>
106 <exclude>**/MarkerTest.java</exclude>
107 <exclude>**/SerializeTest.java</exclude>
108 </excludes>
109 <includes>
110 <include>**/OptionalTest.java</include>
111 </includes>
112 </configuration>
113 </execution>
114 </executions>
115 </plugin>
116 <!-- Include the standard NOTICE and LICENSE -->
117 <plugin>
118 <groupId>org.apache.maven.plugins</groupId>
119 <artifactId>maven-remote-resources-plugin</artifactId>
120 <executions>
121 <execution>
122 <goals>
123 <goal>process</goal>
124 </goals>
125 <configuration>
126 <skip>false</skip>
127 </configuration>
128 </execution>
129 </executions>
130 </plugin>
131 <plugin>
132 <groupId>org.apache.felix</groupId>
133 <artifactId>maven-bundle-plugin</artifactId>
134 <configuration>
135 <instructions>
136 <Export-Package>
137 liquibase.ext.logging.log4j2
138 </Export-Package>
139 </instructions>
140 </configuration>
141 </plugin>
142 </plugins>
143 </build>
144 <reporting>
145 <plugins>
146 <plugin>
147 <groupId>org.apache.maven.plugins</groupId>
148 <artifactId>maven-changes-plugin</artifactId>
149 <version>${changes.plugin.version}</version>
150 <reportSets>
151 <reportSet>
152 <reports>
153 <report>changes-report</report>
154 </reports>
155 </reportSet>
156 </reportSets>
157 <configuration>
158 <issueLinkTemplate>%URL%/show_bug.cgi?id=%ISSUE%</issueLinkTemplate>
159 <useJql>true</useJql>
160 </configuration>
161 </plugin>
162 <plugin>
163 <groupId>org.apache.maven.plugins</groupId>
164 <artifactId>maven-checkstyle-plugin</artifactId>
165 <version>${checkstyle.plugin.version}</version>
166 <configuration>
167 <!--<propertiesLocation>${vfs.parent.dir}/checkstyle.properties</propertiesLocation> -->
168 <configLocation>${log4jParentDir}/checkstyle.xml</configLocation>
169 <suppressionsLocation>${log4jParentDir}/checkstyle-suppressions.xml</suppressionsLocation>
170 <enableRulesSummary>false</enableRulesSummary>
171 <propertyExpansion>basedir=${basedir}</propertyExpansion>
172 <propertyExpansion>licensedir=${log4jParentDir}/checkstyle-header.txt</propertyExpansion>
173 </configuration>
174 </plugin>
175 <plugin>
176 <groupId>org.apache.maven.plugins</groupId>
177 <artifactId>maven-javadoc-plugin</artifactId>
178 <version>${javadoc.plugin.version}</version>
179 <configuration>
180 <bottom><![CDATA[<p align="center">Copyright &#169; {inceptionYear}-{currentYear} {organizationName}. All Rights Reserved.<br />
181 Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, the Apache Logging project logo,
182 and the Apache Log4j logo are trademarks of The Apache Software Foundation.</p>]]></bottom>
183 <!-- module link generation is completely broken in the javadoc plugin for a multi-module non-aggregating
184 project -->
185 <detectOfflineLinks>false</detectOfflineLinks>
186 <linksource>true</linksource>
187 </configuration>
188 <reportSets>
189 <reportSet>
190 <id>non-aggregate</id>
191 <reports>
192 <report>javadoc</report>
193 </reports>
194 </reportSet>
195 </reportSets>
196 </plugin>
197 <plugin>
198 <groupId>org.codehaus.mojo</groupId>
199 <artifactId>findbugs-maven-plugin</artifactId>
200 <version>${findbugs.plugin.version}</version>
201 <configuration>
202 <fork>true</fork>
203 <jvmArgs>-Duser.language=en</jvmArgs>
204 <threshold>Normal</threshold>
205 <effort>Default</effort>
206 <excludeFilterFile>${log4jParentDir}/findbugs-exclude-filter.xml</excludeFilterFile>
207 </configuration>
208 </plugin>
209 <plugin>
210 <groupId>org.apache.maven.plugins</groupId>
211 <artifactId>maven-jxr-plugin</artifactId>
212 <version>${jxr.plugin.version}</version>
213 <reportSets>
214 <reportSet>
215 <id>non-aggregate</id>
216 <reports>
217 <report>jxr</report>
218 </reports>
219 </reportSet>
220 <reportSet>
221 <id>aggregate</id>
222 <reports>
223 <report>aggregate</report>
224 </reports>
225 </reportSet>
226 </reportSets>
227 </plugin>
228 <plugin>
229 <groupId>org.apache.maven.plugins</groupId>
230 <artifactId>maven-pmd-plugin</artifactId>
231 <version>${pmd.plugin.version}</version>
232 <configuration>
233 <targetJdk>${maven.compile.target}</targetJdk>
234 </configuration>
235 </plugin>
236 </plugins>
237 </reporting>
238 </project>
239
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package liquibase.ext.logging.log4j2;
17
18 import liquibase.logging.core.AbstractLogger;
19
20 import org.apache.logging.log4j.Level;
21 import org.apache.logging.log4j.LogManager;
22 import org.apache.logging.log4j.spi.ExtendedLogger;
23
24 /**
25 * Logs Liquibase messages to Log4j 2.x.
26 * <p>
27 * This class must be in the {@code liquibase} package in order for the Liquibase plugin discovery mechanism to work.
28 * </p>
29 */
30 public class Log4j2Logger extends AbstractLogger {
31
32 private static final String FQCN = Log4j2Logger.class.getName();
33
34 private ExtendedLogger logger;
35
36 @Override
37 public void debug(final String message) {
38 logger.logIfEnabled(FQCN, Level.DEBUG, null, buildMessage(message));
39 }
40
41 @Override
42 public void debug(final String message, final Throwable e) {
43 logger.logIfEnabled(FQCN, Level.DEBUG, null, buildMessage(message), e);
44 }
45
46 @Override
47 public int getPriority() {
48 return PRIORITY_DATABASE;
49 }
50
51 @Override
52 public void info(final String message) {
53 logger.logIfEnabled(FQCN, Level.INFO, null, buildMessage(message));
54 }
55
56 @Override
57 public void info(final String message, final Throwable e) {
58 logger.logIfEnabled(FQCN, Level.INFO, null, buildMessage(message), e);
59 }
60
61 @Override
62 public void setLogLevel(final String logLevel, final String logFile) {
63 setLogLevel(logLevel);
64 // ignore logFile
65 }
66
67 @Override
68 public void setName(final String name) {
69 logger = LogManager.getContext(false).getLogger(name);
70 }
71
72 @Override
73 public void severe(final String message) {
74 logger.logIfEnabled(FQCN, Level.ERROR, null, buildMessage(message));
75 }
76
77 @Override
78 public void severe(final String message, final Throwable e) {
79 logger.logIfEnabled(FQCN, Level.ERROR, null, buildMessage(message), e);
80 }
81
82 @Override
83 public void warning(final String message) {
84 logger.logIfEnabled(FQCN, Level.WARN, null, buildMessage(message));
85 }
86
87 @Override
88 public void warning(final String message, final Throwable e) {
89 logger.logIfEnabled(FQCN, Level.WARN, null, buildMessage(message), e);
90 }
91
92 }
0 <!--
1 Licensed to the Apache Software Foundation (ASF) under one or more
2 contributor license agreements. See the NOTICE file distributed with
3 this work for additional information regarding copyright ownership.
4 The ASF licenses this file to You under the Apache License, Version 2.0
5 (the "License"); you may not use this file except in compliance with
6 the License. You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15
16 -->
17 <project name="Apache Log4j Liquibase Binding"
18 xmlns="http://maven.apache.org/DECORATION/1.4.0"
19 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20 xsi:schemaLocation="http://maven.apache.org/DECORATION/1.4.0 http://maven.apache.org/xsd/decoration-1.4.0.xsd">
21 <body>
22 <links>
23 <item name="Apache" href="http://www.apache.org/" />
24 <item name="Logging Services" href="http://logging.apache.org/"/>
25 <item name="Log4j" href="../index.html"/>
26 </links>
27
28 <!-- Component-specific reports -->
29 <menu ref="reports"/>
30
31 <!-- Overall Project Info -->
32 <menu name="Log4j Project Information" img="icon-info-sign">
33 <item name="Dependencies" href="../dependencies.html" />
34 <item name="Dependency Convergence" href="../dependency-convergence.html" />
35 <item name="Dependency Management" href="../dependency-management.html" />
36 <item name="Project Team" href="../team-list.html" />
37 <item name="Mailing Lists" href="../mail-lists.html" />
38 <item name="Issue Tracking" href="../issue-tracking.html" />
39 <item name="Project License" href="../license.html" />
40 <item name="Source Repository" href="../source-repository.html" />
41 <item name="Project Summary" href="../project-summary.html" />
42 </menu>
43
44 <menu name="Log4j Project Reports" img="icon-cog">
45 <item name="Changes Report" href="../changes-report.html" />
46 <item name="JIRA Report" href="../jira-report.html" />
47 <item name="Surefire Report" href="../surefire-report.html" />
48 <item name="RAT Report" href="../rat-report.html" />
49 </menu>
50 </body>
51 </project>
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17
18 <document>
19 <properties>
20 <title>Log4j 2 Liquibase Binding</title>
21 <author email="mikael@staldal.nu">Mikael St�ldal</author>
22 </properties>
23
24 <body>
25 <section name="Log4j 2 Liquibase Binding">
26
27 <p>
28 The Log4j 2 Liquibase Binding enables <a href="http://www.liquibase.org/">Liquibase</a> to log via Log4j 2.
29 </p>
30
31 </section>
32
33 <section name="Requirements">
34 <p>
35 The Log4j 2 Liquibase Binding has a dependency
36 on the Log4j 2 API as well as the Liquibase core.
37 </p>
38 </section>
39
40 <section name="Usage">
41 <p>
42 Including this module will automatically make Liquibase log via Log4j 2, due the the plugin auto discovery mechanism of Liquibase.
43 </p>
44 </section>
45
46 </body>
47 </document>
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package liquibase.ext.logging.log4j2;
17
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertNotNull;
20 import static org.junit.Assert.assertTrue;
21
22 import java.util.List;
23
24 import liquibase.logging.Logger;
25
26 import org.apache.logging.log4j.core.util.Constants;
27 import org.apache.logging.log4j.test.appender.ListAppender;
28 import org.junit.After;
29 import org.junit.BeforeClass;
30 import org.junit.Test;
31
32 public class LoggingTest {
33
34 private static final String NAME = "LoggerName";
35
36 static Logger logger;
37
38 @BeforeClass
39 public static void setupClass() {
40 logger = new Log4j2Logger();
41 logger.setName(NAME);
42 logger.setLogLevel("debug", null);
43 }
44
45 @Test
46 public void debug() {
47 logger.debug("Debug message");
48 verify(NAME + " " + getClass().getName() + " DEBUG Debug message" + Constants.LINE_SEPARATOR);
49 }
50
51 @Test
52 public void info() {
53 logger.info("Info message");
54 verify(NAME + " " + getClass().getName() + " INFO Info message" + Constants.LINE_SEPARATOR);
55 }
56
57 @Test
58 public void warning() {
59 logger.warning("Warning message");
60 verify(NAME + " " + getClass().getName() + " WARN Warning message" + Constants.LINE_SEPARATOR);
61 }
62
63 @Test
64 public void severe() {
65 logger.severe("Severe message");
66 verify(NAME + " " + getClass().getName() + " ERROR Severe message" + Constants.LINE_SEPARATOR);
67 }
68
69 @Test
70 public void severeStacktrace() {
71 logger.severe("Severe message with stacktrace", new RuntimeException("thrown error"));
72 verify(NAME + " " + getClass().getName() + " ERROR Severe message with stacktrace" + Constants.LINE_SEPARATOR
73 + "java.lang.RuntimeException: thrown error");
74 }
75
76 private void verify(final String expected) {
77 final ListAppender listApp = ListAppender.getListAppender("List");
78 assertNotNull("Missing Appender", listApp);
79 final List<String> events = listApp.getMessages();
80 assertTrue("Incorrect number of messages. Expected 1 Actual " + events.size(), events.size() == 1);
81 final String actual = events.get(0);
82 assertEquals("Incorrect message. Expected " + expected + ". Actual " + actual, expected, actual);
83 listApp.clear();
84 }
85
86 @After
87 public void cleanup() {
88 ListAppender.getListAppender("List").clear();
89 }
90 }
0 <?xml version="1.0" encoding="UTF-8"?>
1 <configuration status="error">
2 <Appenders>
3 <List name="List">
4 <PatternLayout pattern="%c %C %p %m%n%ex{1}"/>
5 </List>
6 </Appenders>
7
8 <Loggers>
9 <Root level="DEBUG">
10 <AppenderRef ref="List"/>
11 </Root>
12 </Loggers>
13 </configuration>
1919 <parent>
2020 <artifactId>log4j</artifactId>
2121 <groupId>org.apache.logging.log4j</groupId>
22 <version>2.2</version>
22 <version>2.4</version>
2323 </parent>
2424 <modelVersion>4.0.0</modelVersion>
2525
3131 private final Map<String, Object> map;
3232
3333 public DefaultNoSqlObject() {
34 this.map = new HashMap<String, Object>();
34 this.map = new HashMap<>();
3535 }
3636
3737 @Override
5151
5252 @Override
5353 public void set(final String field, final NoSqlObject<Map<String, Object>>[] values) {
54 final List<Map<String, Object>> list = new ArrayList<Map<String, Object>>(values.length);
54 final List<Map<String, Object>> list = new ArrayList<>(values.length);
5555 for (final NoSqlObject<Map<String, Object>> value : values) {
5656 list.add(value.unwrap());
5757 }
2727 /**
2828 * This Appender writes logging events to a NoSQL database using a configured NoSQL provider. It requires
2929 * implementations of {@link NoSqlObject}, {@link NoSqlConnection}, and {@link NoSqlProvider} to "know" how to write
30 * events to the chosen NoSQL database. Two provider implementations are provided: MongoDB
31 * (org.mongodb:mongo-java-driver:2.11.1 or newer must be on the classpath) and Apache CouchDB
32 * (org.lightcouch:lightcouch:0.0.5 or newer must be on the classpath). For examples on how to write your own NoSQL
33 * provider, see the simple source code for the MongoDB and CouchDB providers.
34 *
30 * events to the chosen NoSQL database.
31 *
32 * <p>
33 * Two provider implementations are provided:
34 * </p>
35 * <ul>
36 * <li>
37 * MongoDB (org.mongodb:mongo-java-driver:2.11.1 or newer must be on the classpath)</li>
38 * <li>
39 * Apache CouchDB (org.lightcouch:lightcouch:0.0.5 or newer must be on the classpath).</li>
40 * </ul>
41 * <p>
42 * For examples on how to write your own NoSQL provider, see the simple source code for the MongoDB and CouchDB
43 * providers.
44 * </p>
45 *
3546 * @see NoSqlObject
3647 * @see NoSqlConnection
3748 * @see NoSqlProvider
2222 import org.apache.logging.log4j.nosql.appender.DefaultNoSqlObject;
2323 import org.apache.logging.log4j.nosql.appender.NoSqlConnection;
2424 import org.apache.logging.log4j.nosql.appender.NoSqlObject;
25 import org.apache.logging.log4j.util.Strings;
2526 import org.lightcouch.CouchDbClient;
2627 import org.lightcouch.Response;
2728
5051 public void insertObject(final NoSqlObject<Map<String, Object>> object) {
5152 try {
5253 final Response response = this.client.save(object.unwrap());
53 if (response.getError() != null && response.getError().length() > 0) {
54 if (Strings.isNotEmpty(response.getError())) {
5455 throw new AppenderLoggingException("Failed to write log event to CouchDB due to error: " +
5556 response.getError() + '.');
5657 }
9090 @PluginAttribute("factoryMethodName") final String factoryMethodName) {
9191 CouchDbClient client;
9292 String description;
93 if (factoryClassName != null && factoryClassName.length() > 0 &&
94 factoryMethodName != null && factoryMethodName.length() > 0) {
93 if (Strings.isNotEmpty(factoryClassName) && Strings.isNotEmpty(factoryMethodName)) {
9594 try {
9695 final Class<?> factoryClass = Loader.loadClass(factoryClassName);
9796 final Method method = factoryClass.getMethod(factoryMethodName);
127126 e);
128127 return null;
129128 }
130 } else if (databaseName != null && databaseName.length() > 0) {
129 } else if (Strings.isNotEmpty(databaseName)) {
131130 if (protocol != null && protocol.length() > 0) {
132131 protocol = protocol.toLowerCase();
133132 if (!protocol.equals("http") && !protocol.equals("https")) {
118118 } catch (final MongoException e) {
119119 LOGGER.error("Failed to authenticate against MongoDB: " + e.getMessage(), e);
120120 } catch (final IllegalStateException e) {
121 LOGGER.error("Factory-supplied MongoDB database connection already authenticated with different" +
122 "credentials but lost connection.", e);
121 LOGGER.error(
122 "Factory-supplied MongoDB database connection already authenticated with different credentials but lost connection.",
123 e);
123124 }
124125 }
125126 }
180180 + NameUtil.md5(password + MongoDbProvider.class.getName());
181181 MongoDbConnection.authenticate(database, username, password);
182182 } else {
183 LOGGER.error("The database is not already authenticated so you must supply a username and password "
184 + "for the MongoDB provider.");
185 return null;
183 try {
184 database.getCollectionNames(); // Check if the database actually requires authentication
185 } catch (final Exception e) {
186 LOGGER.error("The database is not already authenticated so you must supply a username and password for the MongoDB provider.", e);
187 return null;
188 }
186189 }
187190 }
188191
7676
7777 <section name="Requirements">
7878 <p>
79 The NoSQL Appenders requires at least Java 6.
79 The NoSQL Appenders is dependent on the Log4j 2 API and implementation.
8080 </p>
8181 </section>
8282
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.nosql.appender;
17
18 import org.apache.logging.log4j.LogManager;
19 import org.apache.logging.log4j.Logger;
20 import org.apache.logging.log4j.junit.LoggerContextRule;
21 import org.junit.ClassRule;
22 import org.junit.Ignore;
23 import org.junit.Test;
24
25 @Ignore("Requires a running MongoDB server")
26 public class MongoDbTest {
27
28 @ClassRule
29 public static LoggerContextRule context = new LoggerContextRule("log4j2-mongodb.xml");
30
31 @Test
32 public void test() {
33 final Logger logger = LogManager.getLogger();
34 logger.info("Hello log");
35 }
36 }
166166 verify(this.provider, this.connection);
167167 reset(this.provider, this.connection);
168168
169 final Capture<NoSqlObject<Map<String, Object>>> capture = new Capture<NoSqlObject<Map<String, Object>>>();
169 final Capture<NoSqlObject<Map<String, Object>>> capture = new Capture<>();
170170
171171 final LogEvent event = createStrictMock(LogEvent.class);
172172 final Message message = createStrictMock(Message.class);
253253 verify(this.provider, this.connection);
254254 reset(this.provider, this.connection);
255255
256 final Capture<NoSqlObject<Map<String, Object>>> capture = new Capture<NoSqlObject<Map<String, Object>>>();
256 final Capture<NoSqlObject<Map<String, Object>>> capture = new Capture<>();
257257
258258 final RuntimeException exception = new RuntimeException("This is something cool!");
259 final Map<String, String> context = new HashMap<String, String>();
259 final Map<String, String> context = new HashMap<>();
260260 context.put("hello", "world");
261261 context.put("user", "pass");
262262
388388 verify(this.provider, this.connection);
389389 reset(this.provider, this.connection);
390390
391 final Capture<NoSqlObject<Map<String, Object>>> capture = new Capture<NoSqlObject<Map<String, Object>>>();
391 final Capture<NoSqlObject<Map<String, Object>>> capture = new Capture<>();
392392
393393 final IOException exception1 = new IOException("This is the cause.");
394394 final SQLException exception2 = new SQLException("This is the result.", exception1);
395 final Map<String, String> context = new HashMap<String, String>();
395 final Map<String, String> context = new HashMap<>();
396396 context.put("hello", "world");
397397 context.put("user", "pass");
398398
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16
17 -->
18 <Configuration status="error">
19 <Appenders>
20 <NoSql name="MongoDbAppender">
21 <MongoDb databaseName="test" collectionName="applog" server="localhost" />
22 </NoSql>
23 </Appenders>
24 <Loggers>
25 <Root level="ALL">
26 <AppenderRef ref="MongoDbAppender" />
27 </Root>
28 </Loggers>
29 </Configuration>
1919 <parent>
2020 <artifactId>log4j</artifactId>
2121 <groupId>org.apache.logging.log4j</groupId>
22 <version>2.2</version>
22 <version>2.4</version>
2323 <relativePath>../</relativePath>
2424 </parent>
2525
3838 <docLabel>Apache Log4J Performance Tests</docLabel>
3939 <projectDir>/log4j-perf</projectDir>
4040 <jmh.version>1.1.1</jmh.version>
41 <javac.target>1.6</javac.target>
41 <javac.target>1.7</javac.target>
4242 <uberjar.name>benchmarks</uberjar.name>
4343 </properties>
4444
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.perf.jmh;
17
18 import java.util.concurrent.ConcurrentHashMap;
19 import java.util.concurrent.CopyOnWriteArrayList;
20 import java.util.concurrent.CopyOnWriteArraySet;
21
22 import org.openjdk.jmh.annotations.Benchmark;
23 import org.openjdk.jmh.annotations.Scope;
24 import org.openjdk.jmh.annotations.Setup;
25 import org.openjdk.jmh.annotations.State;
26 import org.openjdk.jmh.infra.Blackhole;
27
28 // ============================== HOW TO RUN THIS TEST: ====================================
29 //
30 // In sampling mode (latency test):
31 // java -jar log4j-perf/target/benchmarks.jar ".*CollectionsBenchmark.*" -i 10 -f 1 -wi 5 -bm sample -tu ns
32 //
33 // Multi-threading test:
34 // java -jar benchmarks.jar ".*CollectionsBenchmark.*" -i 10 -f 1 -wi 5 -bm sample -tu ns -t 4
35 //
36 // Usage help:
37 // java -jar log4j-perf/target/benchmarks.jar -help
38 //
39 @State(Scope.Benchmark)
40 public class CollectionsBenchmark {
41 private ConcurrentHashMap<String, Long> map1 = new ConcurrentHashMap<String, Long>();
42 private CopyOnWriteArraySet<Long> arraySet1 = new CopyOnWriteArraySet<Long>();
43 private CopyOnWriteArrayList<Long> arrayList1 = new CopyOnWriteArrayList<Long>();
44 private ConcurrentHashMap<String, Long> map3 = new ConcurrentHashMap<String, Long>();
45 private CopyOnWriteArraySet<Long> arraySet3 = new CopyOnWriteArraySet<Long>();
46 private CopyOnWriteArrayList<Long> arrayList3 = new CopyOnWriteArrayList<Long>();
47
48 @Setup
49 public void setup() {
50 for (int i = 0; i < 3; i++) {
51 map3.put(String.valueOf(i), Long.valueOf(i));
52 arraySet3.add(Long.valueOf(i));
53 arrayList3.add(Long.valueOf(i));
54 }
55 map1.put(String.valueOf(1), Long.valueOf(1));
56 arraySet1.add(Long.valueOf(1));
57 arrayList1.add(Long.valueOf(1));
58 }
59
60 @Benchmark
61 public void testBaseline(final Blackhole bh) {
62 }
63
64 @Benchmark
65 public long iterMap1Element() {
66 long total = 0;
67 for (Long value : map1.values()) {
68 total += value;
69 }
70 return total;
71 }
72
73 @Benchmark
74 public long iterArraySet1Element() {
75 long total = 0;
76 for (Long value : arraySet1) {
77 total += value;
78 }
79 return total;
80 }
81
82 @Benchmark
83 public long iterArrayList1Element() {
84 long total = 0;
85 for (Long value : arrayList1) {
86 total += value;
87 }
88 return total;
89 }
90
91 @Benchmark
92 public long iterMap3Elements() {
93 long total = 0;
94 for (Long value : map3.values()) {
95 total += value;
96 }
97 return total;
98 }
99
100 @Benchmark
101 public long iterArraySet3Element() {
102 long total = 0;
103 for (Long value : arraySet3) {
104 total += value;
105 }
106 return total;
107 }
108
109 @Benchmark
110 public long iterArrayList3Element() {
111 long total = 0;
112 for (Long value : arrayList3) {
113 total += value;
114 }
115 return total;
116 }
117 }
4949 log4jLogger = LogManager.getLogger(DebugDisabledBenchmark.class);
5050 slf4jLogger = LoggerFactory.getLogger(DebugDisabledBenchmark.class);
5151 log4jClassicLogger = org.apache.log4j.Logger.getLogger(DebugDisabledBenchmark.class);
52 j = new Integer(2);
52 j = Integer.valueOf(2);
5353 }
5454
5555 @TearDown
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.perf.jmh;
18
19 import org.apache.logging.log4j.LogManager;
20 import org.apache.logging.log4j.Logger;
21 import org.openjdk.jmh.annotations.Benchmark;
22 import org.openjdk.jmh.annotations.BenchmarkMode;
23 import org.openjdk.jmh.annotations.Mode;
24 import org.openjdk.jmh.annotations.OutputTimeUnit;
25 import org.openjdk.jmh.annotations.Scope;
26 import org.openjdk.jmh.annotations.Setup;
27 import org.openjdk.jmh.annotations.State;
28 import org.openjdk.jmh.annotations.TearDown;
29 import org.slf4j.LoggerFactory;
30
31 import java.io.File;
32 import java.util.concurrent.TimeUnit;
33
34 /**
35 * Benchmarks Log4j 2, Log4j 1, and Logback using the DEBUG level which is enabled for this test. The configuration
36 * for each uses a FileAppender
37 */
38 // HOW TO RUN THIS TEST
39 // java -jar target/benchmarks.jar ".*FileAppenderBenchmark.*" -f 1 -i 5 -wi 5 -bm sample -tu ns
40 @State(Scope.Thread)
41 public class FileAppenderBenchmark {
42 Logger log4j2Logger;
43 Logger log4j2RandomLogger;
44 org.slf4j.Logger slf4jLogger;
45 org.apache.log4j.Logger log4j1Logger;
46 int j;
47
48 @Setup
49 public void setUp() {
50 System.setProperty("log4j.configurationFile", "log4j2-perf.xml");
51 System.setProperty("log4j.configuration", "log4j12-perf.xml");
52 System.setProperty("logback.configurationFile", "logback-perf.xml");
53
54 File logbackFile = new File("target/testlogback.log");
55 logbackFile.delete();
56 File log4jFile = new File ("target/testlog4j.log");
57 log4jFile.delete();
58 File log4j2File = new File ("target/testlog4j2.log");
59 log4j2File.delete();
60 File log4j2RAF = new File ("target/testRandomlog4j2.log");
61 log4j2RAF.delete();
62
63 log4j2Logger = LogManager.getLogger(FileAppenderBenchmark.class);
64 log4j2RandomLogger = LogManager.getLogger("TestRandom");
65 slf4jLogger = LoggerFactory.getLogger(FileAppenderBenchmark.class);
66 log4j1Logger = org.apache.log4j.Logger.getLogger(FileAppenderBenchmark.class);
67 j = 0;
68 }
69
70 @TearDown
71 public void tearDown() {
72 System.clearProperty("log4j.configurationFile");
73 System.clearProperty("log4j.configuration");
74 System.clearProperty("logback.configurationFile");
75
76 File logbackFile = new File("target/testlogback.log");
77 logbackFile.delete();
78 File log4jFile = new File ("target/testlog4j.log");
79 log4jFile.delete();
80 File log4jRandomFile = new File ("target/testRandomlog4j2.log");
81 log4jRandomFile.delete();
82 File log4j2File = new File ("target/testlog4j2.log");
83 log4j2File.delete();
84 }
85
86 @BenchmarkMode(Mode.Throughput)
87 @OutputTimeUnit(TimeUnit.MILLISECONDS)
88 @Benchmark
89 public boolean baseline() {
90 ++j;
91 return true;
92 }
93
94 @BenchmarkMode(Mode.Throughput)
95 @OutputTimeUnit(TimeUnit.MILLISECONDS)
96 @Benchmark
97 public void log4j2RAFStringConcatenation() {
98 log4j2RandomLogger.debug("This is a debug [" + ++j + "] message");
99 }
100
101
102 @BenchmarkMode(Mode.Throughput)
103 @OutputTimeUnit(TimeUnit.MILLISECONDS)
104 @Benchmark
105 public void log4j2StringConcatenation() {
106 log4j2Logger.debug("This is a debug [" + ++j + "] message");
107 }
108
109 @BenchmarkMode(Mode.Throughput)
110 @OutputTimeUnit(TimeUnit.MILLISECONDS)
111 @Benchmark
112 public void slf4jStringConcatenation() {
113 slf4jLogger.debug("This is a debug [" + ++j + "] message");
114 }
115
116 @BenchmarkMode(Mode.Throughput)
117 @OutputTimeUnit(TimeUnit.MILLISECONDS)
118 @Benchmark
119 public void log4j1StringConcatenation() {
120 log4j1Logger.debug("This is a debug [" + ++j + "] message");
121 }
122
123 @BenchmarkMode(Mode.Throughput)
124 @OutputTimeUnit(TimeUnit.MILLISECONDS)
125 @Benchmark
126 public void log4j2RAFParameterizedString() {
127 log4j2RandomLogger.debug("This is a debug [{}] message", ++j);
128 }
129
130 @BenchmarkMode(Mode.Throughput)
131 @OutputTimeUnit(TimeUnit.MILLISECONDS)
132 @Benchmark
133 public void log4j2ParameterizedString() {
134 log4j2Logger.debug("This is a debug [{}] message", ++j);
135 }
136
137 @BenchmarkMode(Mode.Throughput)
138 @OutputTimeUnit(TimeUnit.MILLISECONDS)
139 @Benchmark
140 public void slf4jParameterizedString() {
141 slf4jLogger.debug("This is a debug [{}] message", ++j);
142 }
143 }
6666 createTable(connectionH2, toCreateTableSqlStringH2("fmLogEntry"));
6767
6868 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, "log4j2-jdbc-appender.xml");
69 final LoggerContext context = (LoggerContext) LogManager.getContext(false);
69 final LoggerContext context = LoggerContext.getContext(false);
7070 if (context.getConfiguration() instanceof DefaultConfiguration) {
7171 context.reconfigure();
7272 }
133133
134134 @TearDown
135135 public void tearDown() throws SQLException {
136 final LoggerContext context = (LoggerContext) LogManager.getContext(false);
136 final LoggerContext context = LoggerContext.getContext(false);
137137 try {
138138 ((JdbcAppender) context.getConfiguration().getAppender("H2Appender")).getManager().release();
139139 ((JdbcAppender) context.getConfiguration().getAppender("HSQLDBAppender")).getManager().release();
6464 connectionH2 = getConnectionH2();
6565
6666 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, "log4j2-jpa-appender.xml");
67 final LoggerContext context = (LoggerContext) LogManager.getContext(false);
67 final LoggerContext context = LoggerContext.getContext(false);
6868 if (context.getConfiguration() instanceof DefaultConfiguration) {
6969 context.reconfigure();
7070 }
131131
132132 @TearDown
133133 public void tearDown() throws SQLException {
134 final LoggerContext context = (LoggerContext) LogManager.getContext(false);
134 final LoggerContext context = LoggerContext.getContext(false);
135135 try {
136136 ((JpaAppender) context.getConfiguration().getAppender("H2Appender")).getManager().release();
137137 ((JpaAppender) context.getConfiguration().getAppender("HSQLDBAppender")).getManager().release();
4545
4646 @Benchmark
4747 public LogEvent createLogEventWithoutException() {
48 return new Log4jLogEvent("a.b.c", null, "a.b.c", Level.INFO, MESSAGE, null);
48 return new Log4jLogEvent("a.b.c", null, "a.b.c", Level.INFO, MESSAGE, null, null);
4949 }
5050
5151 @Benchmark
7070
7171 @Benchmark
7272 public Serializable createSerializableLogEventProxyWithoutException() {
73 final Log4jLogEvent event = new Log4jLogEvent("a.b.c", null, "a.b.c", Level.INFO, MESSAGE, null);
73 final Log4jLogEvent event = new Log4jLogEvent("a.b.c", null, "a.b.c", Level.INFO, MESSAGE, null, null);
7474 return Log4jLogEvent.serialize(event, false);
7575 }
7676
7777 @Benchmark
7878 public Serializable createSerializableLogEventProxyWithException(final Blackhole bh) {
79 final Log4jLogEvent event = new Log4jLogEvent("a.b.c", null, "a.b.c", Level.INFO, MESSAGE, ERROR);
79 final Log4jLogEvent event = new Log4jLogEvent("a.b.c", null, "a.b.c", Level.INFO, MESSAGE, null, ERROR);
8080 return Log4jLogEvent.serialize(event, false);
8181 }
8282
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.perf.jmh;
17
18 import java.util.concurrent.CopyOnWriteArraySet;
19 import java.util.concurrent.atomic.AtomicBoolean;
20 import java.util.concurrent.atomic.AtomicInteger;
21 import java.util.concurrent.locks.Condition;
22 import java.util.concurrent.locks.Lock;
23 import java.util.concurrent.locks.ReentrantLock;
24
25 import org.apache.logging.log4j.Level;
26 import org.apache.logging.log4j.core.Filter;
27 import org.apache.logging.log4j.core.LogEvent;
28 import org.apache.logging.log4j.core.appender.AbstractAppender;
29 import org.apache.logging.log4j.core.config.AppenderControl;
30 import org.apache.logging.log4j.core.config.LoggerConfig;
31 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
32 import org.apache.logging.log4j.message.SimpleMessage;
33 import org.openjdk.jmh.annotations.Benchmark;
34 import org.openjdk.jmh.annotations.Scope;
35 import org.openjdk.jmh.annotations.Setup;
36 import org.openjdk.jmh.annotations.State;
37 import org.openjdk.jmh.infra.Blackhole;
38
39 // ============================== HOW TO RUN THIS TEST: ====================================
40 //
41 // In sampling mode (latency test):
42 // java -jar log4j-perf/target/benchmarks.jar ".*LoggerConfigBenchmark.*" -i 10 -f 1 -wi 5 -bm sample -tu ns
43 //
44 // Multi-threading test:
45 // java -jar benchmarks.jar ".*LoggerConfigBenchmark.*" -i 10 -f 1 -wi 5 -bm sample -tu ns -t 4
46 //
47 // Usage help:
48 // java -jar log4j-perf/target/benchmarks.jar -help
49 //
50 @State(Scope.Benchmark)
51 public class LoggerConfigBenchmark {
52
53 private CopyOnWriteArraySet<AppenderControl> appenderSet = new CopyOnWriteArraySet<AppenderControl>();
54 private volatile Filter filter = null;
55 private boolean additive = true;
56 private boolean includeLocation = true;
57 private LoggerConfig parent;
58 private final AtomicInteger counter = new AtomicInteger();
59 private final AtomicBoolean shutdown = new AtomicBoolean(false);
60 private final Lock shutdownLock = new ReentrantLock();
61 private final Condition noLogEvents = shutdownLock.newCondition(); // should only be used when shutdown == true
62 private final LogEvent LOGEVENT = createLogEventWithoutException();
63 private SimpleListAppender listAppender = new SimpleListAppender();
64
65 private static class SimpleListAppender extends AbstractAppender {
66 private static final long serialVersionUID = 1L;
67 private final AtomicInteger count = new AtomicInteger();
68
69 protected SimpleListAppender() {
70 super("list", null, null);
71 }
72
73 @Override
74 public void append(LogEvent event) {
75 count.incrementAndGet();
76 }
77
78 public int size() {
79 return count.get();
80 }
81 }
82
83 @Setup
84 public void setup() {
85
86 listAppender.start();
87 final AppenderControl control = new AppenderControl(listAppender, Level.ALL, null);
88 appenderSet.add(control);
89 }
90
91 @Benchmark
92 public void testBaseline(final Blackhole bh) {
93 }
94
95 private static LogEvent createLogEventWithoutException() {
96 return new Log4jLogEvent("a.b.c", null, "a.b.c", Level.INFO, new SimpleMessage("abc"), null, null);
97 }
98
99 @Benchmark
100 public int logWithCountersAndLock() {
101 log(LOGEVENT);
102 return listAppender.size();
103 }
104
105 @Benchmark
106 public int logWithCountersNoLocks() {
107 log2(LOGEVENT);
108 return listAppender.size();
109 }
110
111 @Benchmark
112 public int logWithoutCountersOrLocks() {
113 log3(LOGEVENT);
114 return listAppender.size();
115 }
116
117 @Benchmark
118 public int logWithCountersRetryAfterReconfig() {
119 log4WithCounterAndFlag(LOGEVENT);
120 return listAppender.size();
121 }
122
123 /**
124 * Logs an event.
125 *
126 * @param event The log event.
127 */
128 public void log(final LogEvent event) {
129 beforeLogEvent();
130 try {
131 if (!isFiltered(event)) {
132 processLogEvent(event);
133 }
134 } finally {
135 afterLogEvent();
136 }
137 }
138
139 /**
140 * Logs an event.
141 *
142 * @param event The log event.
143 */
144 public void log2(final LogEvent event) {
145 beforeLogEvent();
146 try {
147 if (!isFiltered(event)) {
148 processLogEvent(event);
149 }
150 } finally {
151 afterLogEvent2();
152 }
153 }
154
155 /**
156 * Logs an event.
157 *
158 * @param event The log event.
159 */
160 public void log3(final LogEvent event) {
161 if (!isFiltered(event)) {
162 processLogEvent(event);
163 }
164 }
165
166 volatile LoggerConfigBenchmark loggerConfig = this;
167
168 /**
169 * Logs an event.
170 *
171 * @param event The log event.
172 */
173 public void log4WithCounterAndFlag(final LogEvent event) {
174 LoggerConfigBenchmark local = loggerConfig;
175 while (!local.beforeLogEventCheckCounterPositive()) {
176 local = loggerConfig;
177 }
178 try {
179 local.log3(event);
180 } finally {
181 local.afterLogEvent2();
182 }
183 }
184
185 /**
186 * Determine if the LogEvent should be processed or ignored.
187 *
188 * @param event The LogEvent.
189 * @return true if the LogEvent should be processed.
190 */
191 public boolean isFiltered(final LogEvent event) {
192 return filter != null && filter.filter(event) == Filter.Result.DENY;
193 }
194
195 private void beforeLogEvent() {
196 counter.incrementAndGet();
197 }
198
199 private boolean beforeLogEventCheckCounterPositive() {
200 return counter.incrementAndGet() > 0;
201 }
202
203 private void afterLogEvent() {
204 if (counter.decrementAndGet() == 0) {
205 signalCompletionIfShutdown();
206 }
207 }
208
209 private void signalCompletionIfShutdown() {
210 final Lock lock = shutdownLock;
211 lock.lock();
212 try {
213 if (shutdown.get()) {
214 noLogEvents.signalAll();
215 }
216 } finally {
217 lock.unlock();
218 }
219 }
220
221 private void afterLogEvent2() {
222 if (counter.decrementAndGet() == 0 && shutdown.get()) {
223 signalCompletionIfShutdown();
224 }
225 }
226
227 private void processLogEvent(final LogEvent event) {
228 event.setIncludeLocation(isIncludeLocation());
229 callAppenders(event);
230 logParent(event);
231 }
232
233 public boolean isIncludeLocation() {
234 return includeLocation;
235 }
236
237 private void logParent(final LogEvent event) {
238 if (additive && parent != null) {
239 parent.log(event);
240 }
241 }
242
243 protected void callAppenders(final LogEvent event) {
244 for (final AppenderControl control : appenderSet) {
245 control.callAppender(event);
246 }
247 }
248
249 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.perf.jmh;
18
19 import java.util.concurrent.TimeUnit;
20
21 import org.openjdk.jmh.annotations.Benchmark;
22 import org.openjdk.jmh.annotations.BenchmarkMode;
23 import org.openjdk.jmh.annotations.Mode;
24 import org.openjdk.jmh.annotations.OutputTimeUnit;
25 import org.openjdk.jmh.annotations.Scope;
26 import org.openjdk.jmh.annotations.State;
27
28 /**
29 * From <a href="http://shipilev.net/blog/2014/nanotrusting-nanotime/">http://shipilev.net/blog/2014/nanotrusting-nanotime/</a>.
30 */
31 // ============================== HOW TO RUN THIS TEST: ====================================
32 //
33 // single thread:
34 // java -jar log4j-perf/target/benchmarks.jar ".*Nanotime.*" -f 1 -wi 5 -i 5
35 //
36 // multiple threads (for example, 4 threads):
37 // java -jar log4j-perf/target/benchmarks.jar ".*Nanotime.*" -f 1 -wi 5 -i 5 -t 4 -si true
38 //
39 // Usage help:
40 // java -jar log4j-perf/target/benchmarks.jar -help
41 //
42 @State(Scope.Benchmark)
43 public class NanotimeBenchmark {
44
45 public static void main(final String[] args) {
46 }
47
48 @Benchmark
49 @BenchmarkMode(Mode.SampleTime)
50 @OutputTimeUnit(TimeUnit.NANOSECONDS)
51 public void baseline() {
52 }
53
54 @Benchmark
55 @BenchmarkMode(Mode.SampleTime)
56 @OutputTimeUnit(TimeUnit.NANOSECONDS)
57 public long latency_nanotime() {
58 return System.nanoTime();
59 }
60
61 private long lastValue;
62
63 @Benchmark
64 @BenchmarkMode(Mode.SampleTime)
65 @OutputTimeUnit(TimeUnit.NANOSECONDS)
66 public long granularity_nanotime() {
67 long cur;
68 do {
69 cur = System.nanoTime();
70 } while (cur == lastValue);
71 lastValue = cur;
72 return cur;
73 }
74 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.perf.jmh;
18
19 import java.util.concurrent.TimeUnit;
20
21 import org.apache.logging.log4j.message.ParameterizedMessage;
22 import org.openjdk.jmh.annotations.Benchmark;
23 import org.openjdk.jmh.annotations.BenchmarkMode;
24 import org.openjdk.jmh.annotations.Mode;
25 import org.openjdk.jmh.annotations.OutputTimeUnit;
26 import org.openjdk.jmh.annotations.Scope;
27 import org.openjdk.jmh.annotations.State;
28
29 /**
30 */
31 // ============================== HOW TO RUN THIS TEST: ====================================
32 //
33 // single thread:
34 // java -jar log4j-perf/target/benchmarks.jar ".*ParameterizedMessage.*" -f 1 -wi 5 -i 10
35 //
36 // multiple threads (for example, 4 threads):
37 // java -jar log4j-perf/target/benchmarks.jar ".*Nanotime.*" -f 1 -wi 5 -i 10 -t 4 -si true
38 //
39 // Usage help:
40 // java -jar log4j-perf/target/benchmarks.jar -help
41 //
42 @State(Scope.Benchmark)
43 public class ParameterizedMessageBenchmark {
44 private static final char DELIM_START = '{';
45 private static final char DELIM_STOP = '}';
46 private static final char ESCAPE_CHAR = '\\';
47 private static final String[] ARGS = { "arg1", "arg2" };
48
49 public static void main(final String[] args) {
50 }
51
52 @Benchmark
53 @BenchmarkMode(Mode.SampleTime)
54 @OutputTimeUnit(TimeUnit.NANOSECONDS)
55 public String format() {
56 return format("pattern {} with {} two parameters and some text", ARGS);
57 }
58
59 @Benchmark
60 @BenchmarkMode(Mode.SampleTime)
61 @OutputTimeUnit(TimeUnit.NANOSECONDS)
62 public String format0() {
63 return format0("pattern {} with {} two parameters and some text", ARGS);
64 }
65
66 @Benchmark
67 @BenchmarkMode(Mode.SampleTime)
68 @OutputTimeUnit(TimeUnit.NANOSECONDS)
69 public String formatStringArgs() {
70 return ParameterizedMessage.format("pattern {} with {} two parameters and some text", ARGS);
71 }
72
73 @Benchmark
74 @BenchmarkMode(Mode.SampleTime)
75 @OutputTimeUnit(TimeUnit.NANOSECONDS)
76 public String format0_inlined2() {
77 return format0_inlined2("pattern {} with {} two parameters and some text", ARGS);
78 }
79 public static String format(final String messagePattern, final Object[] arguments) {
80 if (messagePattern == null || arguments == null || arguments.length == 0) {
81 return messagePattern;
82 }
83
84 final StringBuilder result = new StringBuilder();
85 int escapeCounter = 0;
86 int currentArgument = 0;
87 for (int i = 0; i < messagePattern.length(); i++) {
88 final char curChar = messagePattern.charAt(i);
89 if (curChar == ESCAPE_CHAR) {
90 escapeCounter++;
91 } else {
92 if (curChar == DELIM_START && i < messagePattern.length() - 1
93 && messagePattern.charAt(i + 1) == DELIM_STOP) {
94 // write escaped escape chars
95 final int escapedEscapes = escapeCounter / 2;
96 for (int j = 0; j < escapedEscapes; j++) {
97 result.append(ESCAPE_CHAR);
98 }
99
100 if (escapeCounter % 2 == 1) {
101 // i.e. escaped
102 // write escaped escape chars
103 result.append(DELIM_START);
104 result.append(DELIM_STOP);
105 } else {
106 // unescaped
107 if (currentArgument < arguments.length) {
108 result.append(arguments[currentArgument]);
109 } else {
110 result.append(DELIM_START).append(DELIM_STOP);
111 }
112 currentArgument++;
113 }
114 i++;
115 escapeCounter = 0;
116 continue;
117 }
118 // any other char beside ESCAPE or DELIM_START/STOP-combo
119 // write unescaped escape chars
120 if (escapeCounter > 0) {
121 for (int j = 0; j < escapeCounter; j++) {
122 result.append(ESCAPE_CHAR);
123 }
124 escapeCounter = 0;
125 }
126 result.append(curChar);
127 }
128 }
129 return result.toString();
130 }
131
132 // 259 bytes
133 public static String format0(final String messagePattern, final String[] arguments) {
134 if (messagePattern == null || arguments == null || arguments.length == 0) {
135 return messagePattern;
136 }
137
138 final int len = messagePattern.length();
139 final char[] result = new char[len + sumStringLengths(arguments)];
140 int pos = 0;
141 int escapeCounter = 0;
142 int currentArgument = 0;
143 for (int i = 0; i < len; i++) {
144 final char curChar = messagePattern.charAt(i);
145 if (curChar == ESCAPE_CHAR) {
146 escapeCounter++;
147 } else {
148 if (curChar == DELIM_START && i < len - 1 && messagePattern.charAt(i + 1) == DELIM_STOP) {
149 // write escaped escape chars
150 int escapedEscapes = escapeCounter >> 1; // divide by 2
151 while (escapedEscapes > 0) {
152 result[pos++] = ESCAPE_CHAR;
153 escapedEscapes--;
154 }
155
156 if ((escapeCounter & 1) == 1) {
157 // i.e. escaped
158 // write escaped escape chars
159 result[pos++] = DELIM_START;
160 result[pos++] = DELIM_STOP;
161 } else {
162 // unescaped
163 if (currentArgument < arguments.length) {
164 final String arg = arguments[currentArgument];
165 final int argLen = arg.length();
166 arg.getChars(0, argLen, result, pos);
167 pos += argLen;
168 } else {
169 result[pos++] = DELIM_START;
170 result[pos++] = DELIM_STOP;
171 }
172 currentArgument++;
173 }
174 i++;
175 escapeCounter = 0;
176 continue;
177 }
178 // any other char beside ESCAPE or DELIM_START/STOP-combo
179 // write unescaped escape chars
180 while (escapeCounter > 0) {
181 result[pos++] = ESCAPE_CHAR;
182 escapeCounter--;
183 }
184 result[pos++] = curChar;
185 }
186 }
187 return result.toString();
188 }
189
190 // 33 bytes
191 public static String format0_inlined2(final String messagePattern, final String[] arguments) {
192 int len = 0;
193 if (messagePattern == null || (len = messagePattern.length()) == 0 || arguments == null
194 || arguments.length == 0) {
195 return messagePattern;
196 }
197
198 return format0_inlined22(messagePattern, len, arguments);
199 }
200
201 // 157 bytes
202 private static String format0_inlined22(final String messagePattern, final int len, final String[] arguments) {
203 final char[] result = new char[len + sumStringLengths(arguments)];
204 int pos = 0;
205 int escapeCounter = 0;
206 int currentArgument = 0;
207 int i = 0;
208 for (; i < len - 1; i++) {
209 final char curChar = messagePattern.charAt(i);
210 if (curChar == ESCAPE_CHAR) {
211 escapeCounter++;
212 } else {
213 if (isDelimPair(messagePattern, i, curChar)) {
214 i++;
215
216 // write escaped escape chars
217 pos = format0_writeEscapedEscapeChars(escapeCounter, result, pos);
218
219 if (isOdd(escapeCounter)) {
220 // i.e. escaped
221 // write escaped escape chars
222 pos = format0_writeDelimPair(result, pos);
223 } else {
224 // unescaped
225 pos = format0_appendArg(arguments, currentArgument, result, pos);
226 currentArgument++;
227 }
228 } else {
229 pos = format0_handleLiteralChar(result, pos, escapeCounter, curChar);
230 }
231 escapeCounter = 0;
232 }
233 }
234 pos = format0_handleMaybeLastChar(messagePattern, len, result, pos, escapeCounter, i);
235 return new String(result, 0, pos);
236 }
237
238 /**
239 * Returns the sum of the lengths of all Strings in the specified array.
240 */
241 // 27 bytes
242 private static int sumStringLengths(String[] arguments) {
243 int result = 0;
244 for (int i = 0; i < arguments.length; i++) {
245 result += arguments[i].length();
246 }
247 return result;
248 }
249
250 // 22 bytes
251 private static boolean isDelimPair(final String messagePattern, int i, final char curChar) {
252 return curChar == DELIM_START && messagePattern.charAt(i + 1) == DELIM_STOP;
253 }
254
255 // 28 bytes
256 private static int format0_handleMaybeLastChar(final String messagePattern, final int len, final char[] result,
257 int pos, int escapeCounter, int i) {
258 if (i == len - 1) {
259 final char curChar = messagePattern.charAt(i);
260 pos = format0_handleLastChar(result, pos, escapeCounter, curChar);
261 }
262 return pos;
263 }
264
265 // 28 bytes
266 private static int format0_handleLastChar(final char[] result, int pos, int escapeCounter, final char curChar) {
267 if (curChar == ESCAPE_CHAR) {
268 pos = format0_writeUnescapedEscapeChars(escapeCounter + 1, result, pos);
269 } else {
270 pos = format0_handleLiteralChar(result, pos, escapeCounter, curChar);
271 }
272 return pos;
273 }
274
275 // 16 bytes
276 private static int format0_handleLiteralChar(final char[] result, int pos, int escapeCounter, final char curChar) {
277 // any other char beside ESCAPE or DELIM_START/STOP-combo
278 // write unescaped escape chars
279 pos = format0_writeUnescapedEscapeChars(escapeCounter, result, pos);
280 result[pos++] = curChar;
281 return pos;
282 }
283
284 // 18 bytes
285 private static int format0_writeDelimPair(final char[] result, int pos) {
286 result[pos++] = DELIM_START;
287 result[pos++] = DELIM_STOP;
288 return pos;
289 }
290
291 /**
292 * Returns {@code true} if the specified parameter is odd.
293 */
294 // 11 bytes
295 private static boolean isOdd(int number) {
296 return (number & 1) == 1;
297 }
298
299 // 11 bytes
300 private static int format0_writeEscapedEscapeChars(int escapeCounter, char[] result, int pos) {
301 final int escapedEscapes = escapeCounter >> 1; // divide by two
302 return format0_writeUnescapedEscapeChars(escapedEscapes, result, pos);
303 }
304
305 // 20 bytes
306 private static int format0_writeUnescapedEscapeChars(int escapeCounter, char[] result, int pos) {
307 while (escapeCounter > 0) {
308 result[pos++] = ESCAPE_CHAR;
309 escapeCounter--;
310 }
311 return pos;
312 }
313
314 // 25 bytes
315 private static int format0_appendArg(final String[] arguments, int currentArgument, final char[] result, int pos) {
316 if (currentArgument < arguments.length) {
317 pos = format0_appendArg0(arguments, currentArgument, result, pos);
318 } else {
319 pos = format0_writeDelimPair(result, pos);
320 }
321 return pos;
322 }
323
324 // 27 bytes
325 private static int format0_appendArg0(final String[] arguments, int currentArgument, final char[] result, int pos) {
326 final String arg = arguments[currentArgument];
327 final int argLen = arg.length();
328 arg.getChars(0, argLen, result, pos);
329 return pos + argLen;
330 }
331 }
5757 private static final String DEFAULT_ENCODING = CHARSET_DEFAULT.name();
5858 private static final String STRING_SHIFT_JIS = "SHIFT_JIS";
5959 private static final Charset CHARSET_SHIFT_JIS = Charset.forName(STRING_SHIFT_JIS);
60 private PatternLayout PATTERN_M = PatternLayout.createLayout("%m%n", null, null, CHARSET_DEFAULT, false, true, null, null);
61 private PatternLayout PATTERN_SPACE = PatternLayout.createLayout(" ", null, null, CHARSET_DEFAULT, false, true, null, null);
62 private PatternLayout PATTERN_M_C = PatternLayout.createLayout("%c %m%n", null, null, CHARSET_DEFAULT, false, true, null, null);
63 private PatternLayout PATTERN_M_C_D = PatternLayout.createLayout("%d %c %m%n", null, null, CHARSET_DEFAULT, false, true, null, null);
64 private PatternLayout PATTERN_M_D = PatternLayout.createLayout("%d %m%n", null, null, CHARSET_DEFAULT, false, true, null, null);
65 private PatternLayout PATTERN_M_EX = PatternLayout.createLayout("%m %ex%n", null, null, CHARSET_DEFAULT, false, true, null, null);
66 private PatternLayout PATTERN_M_D_EX = PatternLayout.createLayout("%d %m%ex%n", null, null, CHARSET_DEFAULT, false, true, null, null);
67 private PatternLayout PATTERN_M_C_D_EX = PatternLayout.createLayout("%d %c %m%ex%n", null, null, CHARSET_DEFAULT, false, true, null, null);
60 private final PatternLayout PATTERN_M = PatternLayout.createLayout("%m%n", null, null, CHARSET_DEFAULT, false, true, null, null);
61 private final PatternLayout PATTERN_SPACE = PatternLayout.createLayout(" ", null, null, CHARSET_DEFAULT, false, true, null, null);
62 private final PatternLayout PATTERN_M_C = PatternLayout.createLayout("%c %m%n", null, null, CHARSET_DEFAULT, false, true, null, null);
63 private final PatternLayout PATTERN_M_C_D = PatternLayout.createLayout("%d %c %m%n", null, null, CHARSET_DEFAULT, false, true, null, null);
64 private final PatternLayout PATTERN_M_D = PatternLayout.createLayout("%d %m%n", null, null, CHARSET_DEFAULT, false, true, null, null);
65 private final PatternLayout PATTERN_M_EX = PatternLayout.createLayout("%m %ex%n", null, null, CHARSET_DEFAULT, false, true, null, null);
66 private final PatternLayout PATTERN_M_D_EX = PatternLayout.createLayout("%d %m%ex%n", null, null, CHARSET_DEFAULT, false, true, null, null);
67 private final PatternLayout PATTERN_M_C_D_EX = PatternLayout.createLayout("%d %c %m%ex%n", null, null, CHARSET_DEFAULT, false, true, null, null);
6868
6969 private static LogEvent createLogEvent() {
70 Marker marker = null;
71 String fqcn = "com.mycom.myproject.mypackage.MyClass";
72 Level level = Level.DEBUG;
73 Message message = new SimpleMessage(STR);
74 Throwable t = null;
75 Map<String, String> mdc = null;
76 ContextStack ndc = null;
77 String threadName = null;
78 StackTraceElement location = null;
79 long timestamp = 12345678;
70 final Marker marker = null;
71 final String fqcn = "com.mycom.myproject.mypackage.MyClass";
72 final Level level = Level.DEBUG;
73 final Message message = new SimpleMessage(STR);
74 final Throwable t = null;
75 final Map<String, String> mdc = null;
76 final ContextStack ndc = null;
77 final String threadName = null;
78 final StackTraceElement location = null;
79 final long timestamp = 12345678;
8080
81 return new Log4jLogEvent("name(ignored)", marker, fqcn, level, message, t, mdc, ndc, threadName, location,
82 timestamp);
81 return Log4jLogEvent.newBuilder() //
82 .setLoggerName("name(ignored)") //
83 .setMarker(marker) //
84 .setLoggerFqcn(fqcn) //
85 .setLevel(level) //
86 .setMessage(message) //
87 .setThrown(t) //
88 .setContextMap(mdc) //
89 .setContextStack(ndc) //
90 .setThreadName(threadName) //
91 .setSource(location) //
92 .setTimeMillis(timestamp) //
93 .build();
8394 }
8495
8596 @Benchmark
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.perf.jmh;
18
19 import java.io.ByteArrayOutputStream;
20 import java.io.IOException;
21 import java.nio.charset.Charset;
22 import java.util.Map;
23
24 import org.apache.logging.log4j.Level;
25 import org.apache.logging.log4j.Marker;
26 import org.apache.logging.log4j.ThreadContext.ContextStack;
27 import org.apache.logging.log4j.core.LogEvent;
28 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
29 import org.apache.logging.log4j.core.layout.PatternLayout;
30 import org.apache.logging.log4j.message.Message;
31 import org.apache.logging.log4j.message.SimpleMessage;
32 import org.openjdk.jmh.annotations.Benchmark;
33 import org.openjdk.jmh.annotations.Scope;
34 import org.openjdk.jmh.annotations.Setup;
35 import org.openjdk.jmh.annotations.State;
36
37 import ch.qos.logback.classic.Logger;
38 import ch.qos.logback.classic.LoggerContext;
39 import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
40 import ch.qos.logback.classic.spi.ILoggingEvent;
41 import ch.qos.logback.classic.spi.LoggingEvent;
42
43 /**
44 * Compares Log4j2 with Logback PatternLayout performance.
45 */
46 // ============================== HOW TO RUN THIS TEST: ====================================
47 //
48 // single thread:
49 // java -jar log4j-perf/target/benchmarks.jar ".*PatternLayoutComparison.*" -f 1 -wi 10 -i 10 -tu ns -bm sample
50 //
51 // Usage help:
52 // java -jar log4j-perf/target/benchmarks.jar -help
53 //
54 @State(Scope.Thread)
55 public class PatternLayoutComparisonBenchmark {
56
57 final static String STR = "AB!(%087936DZYXQWEIOP$#^~-=/><nb"; // length=32
58 final static LogEvent LOG4J2EVENT = createLog4j2Event();
59 private static final Charset CHARSET_DEFAULT = Charset.defaultCharset();
60 private static final String LOG4JPATTERN = "%d %5p [%t] %c{1} %X{transactionId} - %m%n";
61 private final PatternLayout LOG4J2_PATTERN_LAYOUT = PatternLayout.createLayout(LOG4JPATTERN,
62 null, null, CHARSET_DEFAULT, false, true, null, null);
63
64 private static LogEvent createLog4j2Event() {
65 final Marker marker = null;
66 final String fqcn = "com.mycom.myproject.mypackage.MyClass";
67 final Level level = Level.DEBUG;
68 final Message message = new SimpleMessage(STR);
69 final Throwable t = null;
70 final Map<String, String> mdc = null;
71 final ContextStack ndc = null;
72 final String threadName = null;
73 final StackTraceElement location = null;
74 final long timestamp = 12345678;
75
76 return Log4jLogEvent.newBuilder() //
77 .setLoggerName("name(ignored)") //
78 .setMarker(marker) //
79 .setLoggerFqcn(fqcn) //
80 .setLevel(level) //
81 .setMessage(message) //
82 .setThrown(t) //
83 .setContextMap(mdc) //
84 .setContextStack(ndc) //
85 .setThreadName(threadName) //
86 .setSource(location) //
87 .setTimeMillis(timestamp) //
88 .build();
89 }
90
91 // Logback
92 private static final String LOGBACKPATTERN = "%d %5p [%t] %c{0} %X{transactionId} - %m%n";
93 private final PatternLayoutEncoder patternLayoutEncoder = new PatternLayoutEncoder();
94 private final LoggerContext context = new LoggerContext();
95 private final Logger logger = context.getLogger(PatternLayoutComparisonBenchmark.class);
96 private final ILoggingEvent LOGBACKEVENT = makeLoggingEvent(STR);
97 private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
98
99 @Setup
100 public void setUp() throws IOException {
101 patternLayoutEncoder.setPattern(LOGBACKPATTERN);
102 patternLayoutEncoder.setContext(context);
103 patternLayoutEncoder.start();
104 ((ch.qos.logback.classic.PatternLayout) patternLayoutEncoder.getLayout()).setOutputPatternAsHeader(false);
105 patternLayoutEncoder.init(baos);
106 }
107
108 ILoggingEvent makeLoggingEvent(String message) {
109 return new LoggingEvent(PatternLayoutComparisonBenchmark.class.getName(), logger,
110 ch.qos.logback.classic.Level.DEBUG, message, null, null);
111 }
112
113 @Benchmark
114 public byte[] logback() throws IOException {
115 baos.reset();
116 patternLayoutEncoder.doEncode(LOGBACKEVENT);
117 // patternLayoutEncoder.close();
118 return baos.toByteArray();
119 }
120
121 @Benchmark
122 public byte[] log4j2() {
123 return LOG4J2_PATTERN_LAYOUT.toByteArray(LOG4J2EVENT);
124 }
125
126 }
5050
5151 @Setup
5252 public void setup() {
53 final Configuration config = ((LoggerContext) LogManager.getContext()).getConfiguration();
53 final Configuration config = (LoggerContext.getContext()).getConfiguration();
5454 if (!DefaultConfiguration.DEFAULT_NAME.equals(config.getName())) {
5555 System.out.println("Configuration was " + config.getName());
56 ((LoggerContext) LogManager.getContext()).start(new DefaultConfiguration());
56 (LoggerContext.getContext()).start(new DefaultConfiguration());
5757 }
5858 logger = LogManager.getLogger(SimpleBenchmark.class.getName());
5959 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.perf.jmh;
18
19 import java.text.SimpleDateFormat;
20 import java.util.Date;
21 import java.util.concurrent.TimeUnit;
22 import java.util.concurrent.atomic.AtomicReference;
23
24 import org.apache.logging.log4j.core.util.datetime.FixedDateFormat;
25 import org.apache.logging.log4j.core.util.datetime.FastDateFormat;
26 import org.openjdk.jmh.annotations.Benchmark;
27 import org.openjdk.jmh.annotations.BenchmarkMode;
28 import org.openjdk.jmh.annotations.Mode;
29 import org.openjdk.jmh.annotations.OutputTimeUnit;
30 import org.openjdk.jmh.annotations.Scope;
31 import org.openjdk.jmh.annotations.State;
32
33 /**
34 * Tests performance of various DateFormatters in a thread-safe manner.
35 */
36 // ============================== HOW TO RUN THIS TEST: ====================================
37 //
38 // single thread:
39 // java -jar log4j-perf/target/benchmarks.jar ".*ThreadsafeDateFormat.*" -f 1 -wi 5 -i 10
40 //
41 // multiple threads (for example, 4 threads):
42 // java -jar log4j-perf/target/benchmarks.jar ".*ThreadsafeDateFormat.*" -f 1 -wi 5 -i 10 -t 4 -si true
43 //
44 // Usage help:
45 // java -jar log4j-perf/target/benchmarks.jar -help
46 //
47 @State(Scope.Benchmark)
48 public class ThreadsafeDateFormatBenchmark {
49
50 private final Date date = new Date();
51 private final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
52 private final ThreadLocal<SimpleDateFormat> threadLocalSDFormat = new ThreadLocal<SimpleDateFormat>() {
53 @Override
54 protected SimpleDateFormat initialValue() {
55 return new SimpleDateFormat("HH:mm:ss.SSS");
56 }
57 };
58
59 private final ThreadLocal<FormatterSimple> threadLocalCachedSDFormat = new ThreadLocal<FormatterSimple>() {
60 @Override
61 protected FormatterSimple initialValue() {
62 return new FormatterSimple();
63 }
64 };
65
66 private final FastDateFormat fastDateFormat = FastDateFormat.getInstance("HH:mm:ss.SSS");
67 private final FixedDateFormat fixedDateFormat = FixedDateFormat.createIfSupported("HH:mm:ss.SSS");
68 private final FormatterFixedReuseBuffer formatFixedReuseBuffer = new FormatterFixedReuseBuffer();
69
70 private class CachedTimeFastFormat {
71 private final long timestamp;
72 private final String formatted;
73
74 public CachedTimeFastFormat(final long timestamp) {
75 this.timestamp = timestamp;
76 this.formatted = fastDateFormat.format(timestamp);
77 }
78 }
79
80 private class CachedTimeFixedFmt {
81 private final long timestamp;
82 private final String formatted;
83
84 public CachedTimeFixedFmt(final long timestamp) {
85 this.timestamp = timestamp;
86 this.formatted = fixedDateFormat.format(timestamp);
87 }
88 }
89
90 private class FormatterSimple {
91 private final SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss.SSS");
92 private long timestamp;
93 private String formatted;
94
95 public FormatterSimple() {
96 this.timestamp = 0;
97 }
98
99 public String format(final long timestamp) {
100 if (timestamp != this.timestamp) {
101 this.timestamp = timestamp;
102 formatted = format.format(timestamp);
103 }
104 return formatted;
105 }
106 }
107
108 private class FormatterFixedReuseBuffer {
109 private final FixedDateFormat customFormat = FixedDateFormat.createIfSupported("HH:mm:ss.SSS");
110 private long timestamp;
111 private String formatted;
112 private final ThreadLocal<char[]> reusableBuffer = new ThreadLocal<char[]>() {
113 @Override
114 protected char[] initialValue() {
115 return new char[255];
116 }
117 };
118
119 public FormatterFixedReuseBuffer() {
120 this.timestamp = 0;
121 }
122
123 public String format(final long timestamp) {
124 if (timestamp != this.timestamp) {
125 this.timestamp = timestamp;
126 char[] buffer = reusableBuffer.get();
127 int len = customFormat.format(timestamp, buffer, 0);
128 formatted = new String(buffer, 0, len);
129 }
130 return formatted;
131 }
132 }
133
134 private final long currentTimestamp = 0;
135 private String cachedTime = null;
136
137 private final AtomicReference<CachedTimeFastFormat> cachedTimeFastFmt = new AtomicReference<>(new CachedTimeFastFormat(System.currentTimeMillis()));
138 private final AtomicReference<CachedTimeFixedFmt> cachedTimeFixedFmt = new AtomicReference<>(new CachedTimeFixedFmt(System.currentTimeMillis()));
139
140 public static void main(final String[] args) {
141 }
142
143 @Benchmark
144 @BenchmarkMode(Mode.SampleTime)
145 @OutputTimeUnit(TimeUnit.NANOSECONDS)
146 public void baseline() {
147 }
148
149 @Benchmark
150 @BenchmarkMode(Mode.SampleTime)
151 @OutputTimeUnit(TimeUnit.NANOSECONDS)
152 public String synchronizedSimpleDateFmt() {
153 final long timestamp = System.currentTimeMillis();
154 synchronized (simpleDateFormat) {
155 if (timestamp != currentTimestamp) {
156 cachedTime = simpleDateFormat.format(date);
157 }
158 return cachedTime;
159 }
160 }
161
162 @Benchmark
163 @BenchmarkMode(Mode.SampleTime)
164 @OutputTimeUnit(TimeUnit.NANOSECONDS)
165 public String threadLocalSimpleDateFmt() {
166 final long timestamp = System.currentTimeMillis();
167 return threadLocalSDFormat.get().format(timestamp);
168 }
169
170 @Benchmark
171 @BenchmarkMode(Mode.SampleTime)
172 @OutputTimeUnit(TimeUnit.NANOSECONDS)
173 public String cachedThrdLocalSimpleDateFmt() {
174 final long timestamp = System.currentTimeMillis();
175 return threadLocalCachedSDFormat.get().format(timestamp);
176 }
177
178 @Benchmark
179 @BenchmarkMode(Mode.SampleTime)
180 @OutputTimeUnit(TimeUnit.NANOSECONDS)
181 public String cachedThrdLocalCustomFormat() {
182 final long timestamp = System.currentTimeMillis();
183 return formatFixedReuseBuffer.format(timestamp);
184 }
185
186 @Benchmark
187 @BenchmarkMode(Mode.SampleTime)
188 @OutputTimeUnit(TimeUnit.NANOSECONDS)
189 public String fastDateFormat() {
190 return fastDateFormat.format(System.currentTimeMillis());
191 }
192
193 @Benchmark
194 @BenchmarkMode(Mode.SampleTime)
195 @OutputTimeUnit(TimeUnit.NANOSECONDS)
196 public String fixedDateFormat() {
197 return fixedDateFormat.format(System.currentTimeMillis());
198 }
199
200 @Benchmark
201 @BenchmarkMode(Mode.SampleTime)
202 @OutputTimeUnit(TimeUnit.NANOSECONDS)
203 public String atomicFastFormat() {
204 final long timestamp = System.currentTimeMillis();
205 final CachedTimeFastFormat current = cachedTimeFastFmt.get();
206 if (timestamp != current.timestamp) {
207 final CachedTimeFastFormat newTime = new CachedTimeFastFormat(timestamp);
208 if (cachedTimeFastFmt.compareAndSet(current, newTime)) {
209 return newTime.formatted;
210 } else {
211 return cachedTimeFastFmt.get().formatted;
212 }
213
214 }
215 return current.formatted;
216 }
217
218 @Benchmark
219 @BenchmarkMode(Mode.SampleTime)
220 @OutputTimeUnit(TimeUnit.NANOSECONDS)
221 public String atomicFixedFormat() {
222 final long timestamp = System.currentTimeMillis();
223 final CachedTimeFixedFmt current = cachedTimeFixedFmt.get();
224 if (timestamp != current.timestamp) {
225 final CachedTimeFixedFmt newTime = new CachedTimeFixedFmt(timestamp);
226 if (cachedTimeFixedFmt.compareAndSet(current, newTime)) {
227 return newTime.formatted;
228 } else {
229 return cachedTimeFixedFmt.get().formatted;
230 }
231
232 }
233 return current.formatted;
234 }
235 }
2222 import java.util.Date;
2323 import java.util.concurrent.TimeUnit;
2424
25 import org.apache.logging.log4j.core.util.Charsets;
25 import org.apache.logging.log4j.core.util.datetime.FixedDateFormat;
26 import org.apache.logging.log4j.core.util.datetime.FastDateFormat;
2627 import org.openjdk.jmh.annotations.Benchmark;
2728 import org.openjdk.jmh.annotations.BenchmarkMode;
2829 import org.openjdk.jmh.annotations.Mode;
3637 // ============================== HOW TO RUN THIS TEST: ====================================
3738 //
3839 // single thread:
39 // java -jar log4j-perf/target/benchmarks.jar ".*TimeFormat.*" -f 1 -wi 5 -i 5
40 // java -jar log4j-perf/target/benchmarks.jar ".*TimeFormat.*" -f 1 -wi 5 -i 10
4041 //
4142 // multiple threads (for example, 4 threads):
4243 // java -jar log4j-perf/target/benchmarks.jar ".*TimeFormat.*" -f 1 -wi 5 -i 5 -t 4 -si true
4445 // Usage help:
4546 // java -jar log4j-perf/target/benchmarks.jar -help
4647 //
47 @State(Scope.Thread)
48 @State(Scope.Benchmark)
4849 public class TimeFormatBenchmark {
4950
50 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
51 long midnightToday = 0;
52 long midnightTomorrow = 0;
51 ThreadLocal<SimpleDateFormat> threadLocalSimpleDateFormat = new ThreadLocal<SimpleDateFormat>() {
52 @Override
53 protected SimpleDateFormat initialValue() {
54 return new SimpleDateFormat("HH:mm:ss.SSS");
55 }
56 };
57 FastDateFormat fastDateFormat = FastDateFormat.getInstance("HH:mm:ss.SSS");
58 FixedDateFormat fixedDateFormat = FixedDateFormat.createIfSupported(new String[]{"ABSOLUTE"});
59 volatile long midnightToday = 0;
60 volatile long midnightTomorrow = 0;
5361
5462 @State(Scope.Thread)
5563 public static class BufferState {
56 ByteBuffer buffer = ByteBuffer.allocate(12);
64 final ByteBuffer buffer = ByteBuffer.allocate(12);
65 final StringBuilder stringBuilder = new StringBuilder(12);
66 final char[] charArray = new char[12];
5767 }
5868
5969 private long millisSinceMidnight(final long now) {
6070 if (now >= midnightTomorrow) {
61 midnightToday = calcMidnightMillis(0);
62 midnightTomorrow = calcMidnightMillis(1);
71 midnightToday = calcMidnightMillis(now, 0);
72 midnightTomorrow = calcMidnightMillis(now, 1);
6373 }
6474 return now - midnightToday;
6575 }
6676
67 private long calcMidnightMillis(final int addDays) {
68 // Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UCT"));
77 private long calcMidnightMillis(final long time, final int addDays) {
6978 final Calendar cal = Calendar.getInstance();
79 cal.setTimeInMillis(time);
7080 cal.set(Calendar.HOUR_OF_DAY, 0);
7181 cal.set(Calendar.MINUTE, 0);
7282 cal.set(Calendar.SECOND, 0);
7686 }
7787
7888 public static void main(final String[] args) {
79 System.out.println(new TimeFormatBenchmark().customFastFormatString(new BufferState()));
80 System.out.println(new TimeFormatBenchmark().customFormatString(new BufferState()));
81 }
82
83 @Benchmark
84 @BenchmarkMode(Mode.SampleTime)
85 @OutputTimeUnit(TimeUnit.NANOSECONDS)
86 public void baseline() {
87 }
88
89 @Benchmark
90 @BenchmarkMode(Mode.SampleTime)
91 @OutputTimeUnit(TimeUnit.NANOSECONDS)
92 public String simpleDateFormatString() {
93 return simpleDateFormat.format(new Date());
94 }
95
96 @Benchmark
97 @BenchmarkMode(Mode.SampleTime)
98 @OutputTimeUnit(TimeUnit.NANOSECONDS)
99 public int simpleDateFormatBytes(final BufferState state) {
100 final String str = simpleDateFormat.format(new Date());
101 final byte[] bytes = str.getBytes(Charsets.UTF_8);
102 state.buffer.clear();
103 state.buffer.put(bytes);
104 return state.buffer.position();
105 }
106
107 @Benchmark
108 @BenchmarkMode(Mode.SampleTime)
109 @OutputTimeUnit(TimeUnit.NANOSECONDS)
110 public String customFastFormatString(final BufferState state) {
111 state.buffer.clear();
112 fastFormat(System.currentTimeMillis(), state.buffer);
113 return new String(state.buffer.array(), 0, state.buffer.position(), Charsets.UTF_8);
114 }
115
116 @Benchmark
117 @BenchmarkMode(Mode.SampleTime)
118 @OutputTimeUnit(TimeUnit.NANOSECONDS)
119 public int customFastFormatBytes(final BufferState state) {
120 state.buffer.clear();
121 fastFormat(System.currentTimeMillis(), state.buffer);
122 return state.buffer.position();
123 }
124
125 @Benchmark
126 @BenchmarkMode(Mode.SampleTime)
127 @OutputTimeUnit(TimeUnit.NANOSECONDS)
128 public String customFormatString(final BufferState state) {
129 state.buffer.clear();
130 format(System.currentTimeMillis(), state.buffer);
131 return new String(state.buffer.array(), 0, state.buffer.position(), Charsets.UTF_8);
132 }
133
134 @Benchmark
135 @BenchmarkMode(Mode.SampleTime)
136 @OutputTimeUnit(TimeUnit.NANOSECONDS)
137 public int customFormatBytes(final BufferState state) {
138 state.buffer.clear();
139 format(System.currentTimeMillis(), state.buffer);
140 return state.buffer.position();
141 }
142
143 public ByteBuffer fastFormat(final long time, final ByteBuffer buffer) {
89 System.out.println(new TimeFormatBenchmark().fixedBitFiddlingReuseCharArray(new BufferState()));
90 System.out.println(new TimeFormatBenchmark().fixedFormatReuseStringBuilder(new BufferState()));
91 }
92
93 @Benchmark
94 @BenchmarkMode(Mode.SampleTime)
95 @OutputTimeUnit(TimeUnit.NANOSECONDS)
96 public String simpleDateFormat() {
97 return threadLocalSimpleDateFormat.get().format(new Date());
98 }
99
100 @Benchmark
101 @BenchmarkMode(Mode.SampleTime)
102 @OutputTimeUnit(TimeUnit.NANOSECONDS)
103 public String fastDateFormatCreateNewStringBuilder() {
104 return fastDateFormat.format(new Date());
105 }
106
107 @Benchmark
108 @BenchmarkMode(Mode.SampleTime)
109 @OutputTimeUnit(TimeUnit.NANOSECONDS)
110 public String fastDateFormatReuseStringBuilder(final BufferState state) {
111 state.stringBuilder.setLength(0);
112 fastDateFormat.format(new Date(), state.stringBuilder);
113 return new String(state.stringBuilder);
114 }
115
116 @Benchmark
117 @BenchmarkMode(Mode.SampleTime)
118 @OutputTimeUnit(TimeUnit.NANOSECONDS)
119 public String fixedBitFiddlingReuseCharArray(final BufferState state) {
120 final int len = formatCharArrayBitFiddling(System.currentTimeMillis(), state.charArray, 0);
121 return new String(state.charArray, 0, len);
122 }
123
124 @Benchmark
125 @BenchmarkMode(Mode.SampleTime)
126 @OutputTimeUnit(TimeUnit.NANOSECONDS)
127 public String fixedDateFormatCreateNewCharArray(final BufferState state) {
128 return fixedDateFormat.format(System.currentTimeMillis());
129 }
130
131 @Benchmark
132 @BenchmarkMode(Mode.SampleTime)
133 @OutputTimeUnit(TimeUnit.NANOSECONDS)
134 public String fixedDateFormatReuseCharArray(final BufferState state) {
135 final int len = fixedDateFormat.format(System.currentTimeMillis(), state.charArray, 0);
136 return new String(state.charArray, 0, len);
137 }
138
139 @Benchmark
140 @BenchmarkMode(Mode.SampleTime)
141 @OutputTimeUnit(TimeUnit.NANOSECONDS)
142 public String fixedFormatReuseStringBuilder(final BufferState state) {
143 state.stringBuilder.setLength(0);
144 formatStringBuilder(System.currentTimeMillis(), state.stringBuilder);
145 return new String(state.stringBuilder);
146 }
147
148 int formatCharArrayBitFiddling(final long time, final char[] buffer, int pos) {
144149 // Calculate values by getting the ms values first and do then
145150 // shave off the hour minute and second values with multiplications
146151 // and bit shifts instead of simple but expensive divisions.
162167 // Hour
163168 // 13/128 is nearly the same as /10 for values up to 65
164169 int temp = (hour * 13) >> 7;
165 buffer.put((byte) (temp + '0'));
166
167 // Do subtract to get remainder instead of doing % 10
168 buffer.put((byte) (hour - 10 * temp + '0'));
169 buffer.put((byte) ':');
170 buffer[pos++] = ((char) (temp + '0'));
171
172 // Do subtract to get remainder instead of doing % 10
173 buffer[pos++] = ((char) (hour - 10 * temp + '0'));
174 buffer[pos++] = ((char) ':');
170175
171176 // Minute
172177 // 13/128 is nearly the same as /10 for values up to 65
173178 temp = (minute * 13) >> 7;
174 buffer.put((byte) (temp + '0'));
175
176 // Do subtract to get remainder instead of doing % 10
177 buffer.put((byte) (minute - 10 * temp + '0'));
178 buffer.put((byte) ':');
179 buffer[pos++] = ((char) (temp + '0'));
180
181 // Do subtract to get remainder instead of doing % 10
182 buffer[pos++] = ((char) (minute - 10 * temp + '0'));
183 buffer[pos++] = ((char) ':');
179184
180185 // Second
181186 // 13/128 is nearly the same as /10 for values up to 65
182187 temp = (second * 13) >> 7;
183 buffer.put((byte) (temp + '0'));
184 buffer.put((byte) (second - 10 * temp + '0'));
185 buffer.put((byte) '.');
188 buffer[pos++] = ((char) (temp + '0'));
189 buffer[pos++] = ((char) (second - 10 * temp + '0'));
190 buffer[pos++] = ((char) '.');
186191
187192 // Millisecond
188193 // 41/4096 is nearly the same as /100
189194 temp = (ms * 41) >> 12;
190 buffer.put((byte) (temp + '0'));
195 buffer[pos++] = ((char) (temp + '0'));
191196
192197 ms -= 100 * temp;
193198 temp = (ms * 205) >> 11; // 205/2048 is nearly the same as /10
194 buffer.put((byte) (temp + '0'));
199 buffer[pos++] = ((char) (temp + '0'));
195200
196201 ms -= 10 * temp;
197 buffer.put((byte) (ms + '0'));
198 return buffer;
199 }
200
201 public ByteBuffer format(final long time, final ByteBuffer buffer) {
202 buffer[pos++] = ((char) (ms + '0'));
203 return pos;
204 }
205
206 StringBuilder formatStringBuilder(final long time, final StringBuilder buffer) {
202207 // Calculate values by getting the ms values first and do then
203208 // calculate the hour minute and second values divisions.
204209
217222
218223 // Hour
219224 int temp = hours / 10;
220 buffer.put((byte) (temp + '0'));
221
222 // Do subtract to get remainder instead of doing % 10
223 buffer.put((byte) (hours - 10 * temp + '0'));
224 buffer.put((byte) ':');
225 buffer.append((char) (temp + '0'));
226
227 // Do subtract to get remainder instead of doing % 10
228 buffer.append((char) (hours - 10 * temp + '0'));
229 buffer.append((char) ':');
225230
226231 // Minute
227232 temp = minutes / 10;
228 buffer.put((byte) (temp + '0'));
229
230 // Do subtract to get remainder instead of doing % 10
231 buffer.put((byte) (minutes - 10 * temp + '0'));
232 buffer.put((byte) ':');
233 buffer.append((char) (temp + '0'));
234
235 // Do subtract to get remainder instead of doing % 10
236 buffer.append((char) (minutes - 10 * temp + '0'));
237 buffer.append((char) ':');
233238
234239 // Second
235240 temp = seconds / 10;
236 buffer.put((byte) (temp + '0'));
237 buffer.put((byte) (seconds - 10 * temp + '0'));
238 buffer.put((byte) '.');
241 buffer.append((char) (temp + '0'));
242 buffer.append((char) (seconds - 10 * temp + '0'));
243 buffer.append((char) '.');
239244
240245 // Millisecond
241246 temp = ms / 100;
242 buffer.put((byte) (temp + '0'));
247 buffer.append((char) (temp + '0'));
243248
244249 ms -= 100 * temp;
245250 temp = ms / 10;
246 buffer.put((byte) (temp + '0'));
251 buffer.append((char) (temp + '0'));
247252
248253 ms -= 10 * temp;
249 buffer.put((byte) (ms + '0'));
254 buffer.append((char) (ms + '0'));
250255 return buffer;
251256 }
257
258 int formatCharArray(final long time, final char[] buffer, int pos) {
259 // Calculate values by getting the ms values first and do then
260 // calculate the hour minute and second values divisions.
261
262 // Get daytime in ms which does fit into an int
263 // int ms = (int) (time % 86400000);
264 int ms = (int) (millisSinceMidnight(time));
265
266 final int hours = ms / 3600000;
267 ms -= 3600000 * hours;
268
269 final int minutes = ms / 60000;
270 ms -= 60000 * minutes;
271
272 final int seconds = ms / 1000;
273 ms -= 1000 * seconds;
274
275 // Hour
276 int temp = hours / 10;
277 buffer[pos++] = ((char) (temp + '0'));
278
279 // Do subtract to get remainder instead of doing % 10
280 buffer[pos++] = ((char) (hours - 10 * temp + '0'));
281 buffer[pos++] = ((char) ':');
282
283 // Minute
284 temp = minutes / 10;
285 buffer[pos++] = ((char) (temp + '0'));
286
287 // Do subtract to get remainder instead of doing % 10
288 buffer[pos++] = ((char) (minutes - 10 * temp + '0'));
289 buffer[pos++] = ((char) ':');
290
291 // Second
292 temp = seconds / 10;
293 buffer[pos++] = ((char) (temp + '0'));
294 buffer[pos++] = ((char) (seconds - 10 * temp + '0'));
295 buffer[pos++] = ((char) '.');
296
297 // Millisecond
298 temp = ms / 100;
299 buffer[pos++] = ((char) (temp + '0'));
300
301 ms -= 100 * temp;
302 temp = ms / 10;
303 buffer[pos++] = ((char) (temp + '0'));
304
305 ms -= 10 * temp;
306 buffer[pos++] = ((char) (ms + '0'));
307 return pos;
308 }
252309 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16
17 package org.apache.logging.log4j.perf.jmh;
18
19 import java.util.concurrent.TimeUnit;
20
21 import org.openjdk.jmh.annotations.Benchmark;
22 import org.openjdk.jmh.annotations.BenchmarkMode;
23 import org.openjdk.jmh.annotations.Mode;
24 import org.openjdk.jmh.annotations.OutputTimeUnit;
25 import org.openjdk.jmh.annotations.Scope;
26 import org.openjdk.jmh.annotations.State;
27
28 /**
29 * Tests how expensive constructing a varargs array is.
30 */
31 // ============================== HOW TO RUN THIS TEST: ====================================
32 //
33 // single thread:
34 // java -jar log4j-perf/target/benchmarks.jar ".*Varargs.*" -f 1 -wi 5 -i 10
35 //
36 // multiple threads (for example, 4 threads):
37 // java -jar log4j-perf/target/benchmarks.jar ".*Varargs.*" -f 1 -wi 5 -i 10 -t 4 -si true
38 //
39 // Usage help:
40 // java -jar log4j-perf/target/benchmarks.jar -help
41 //
42 @State(Scope.Benchmark)
43 public class VarargsBenchmark {
44
45 public static void main(final String[] args) {
46 }
47
48 @Benchmark
49 @BenchmarkMode(Mode.SampleTime)
50 @OutputTimeUnit(TimeUnit.NANOSECONDS)
51 public void baseline() {
52 }
53
54 @Benchmark
55 @BenchmarkMode(Mode.SampleTime)
56 @OutputTimeUnit(TimeUnit.NANOSECONDS)
57 public long varargParams() {
58 return varargMethod("example {} {} {}", "one", "two", "three", "four");
59 }
60
61 @Benchmark
62 @BenchmarkMode(Mode.SampleTime)
63 @OutputTimeUnit(TimeUnit.NANOSECONDS)
64 public long individualParams() {
65 return individualArgMethod("example {} {} {}", "one", "two", "three");
66 }
67
68 private long varargMethod(String string, String... params) {
69 return string.length() + params.length;
70 }
71
72 private long individualArgMethod(String string, String param1, String param2, String param3) {
73 return string.length() + param1.length();
74 }
75 }
0 <!--
1 Licensed to the Apache Software Foundation (ASF) under one or more
2 contributor license agreements. See the NOTICE file distributed with
3 this work for additional information regarding copyright ownership.
4 The ASF licenses this file to You under the Apache License, Version 2.0
5 (the "License"); you may not use this file except in compliance with
6 the License. You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15
16 -->
17 <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
18 <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
19 <appender name="TestLogfile" class="org.apache.log4j.FileAppender">
20 <param name="File" value="target/testlog4j.log"/>
21 <param name="immediateFlush" value="false"/>
22 <layout class="org.apache.log4j.PatternLayout">
23 <param name="ConversionPattern" value="%d %5p [%t] %c{1} %X{transactionId} - %m%n"/>
24 </layout>
25 </appender>
26 <root>
27 <level value="debug"/>
28 <appender-ref ref="TestLogfile"/>
29 </root>
30 </log4j:configuration>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16
17 -->
18 <Configuration name="XMLPerfTest" status="error">
19 <Appenders>
20 <File name="TestLogfile" fileName="target/testlog4j2.log" immediateFlush="false">
21 <PatternLayout>
22 <Pattern>%d %5p [%t] %c{1} %X{transactionId} - %m%n</Pattern>
23 </PatternLayout>
24 </File>
25 <RandomAccessFile name="RandomAccessLogFile" fileName="target/testRandomlog4j2.log" immediateFlush="false">
26 <PatternLayout>
27 <Pattern>%d %5p [%t] %c{1} %X{transactionId} - %m%n</Pattern>
28 </PatternLayout>
29 </RandomAccessFile>
30 </Appenders>
31 <Loggers>
32 <Logger name="TestRandom" level="debug" additivity="false">
33 <AppenderRef ref="RandomAccessLogFile"/>
34 </Logger>
35 <Root level="debug">
36 <AppenderRef ref="TestLogfile"/>
37 </Root>
38 </Loggers>
39 </Configuration>
0 <!--
1 Licensed to the Apache Software Foundation (ASF) under one or more
2 contributor license agreements. See the NOTICE file distributed with
3 this work for additional information regarding copyright ownership.
4 The ASF licenses this file to You under the Apache License, Version 2.0
5 (the "License"); you may not use this file except in compliance with
6 the License. You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15
16 -->
17 <configuration>
18 <appender name="TestLogfile" class="ch.qos.logback.core.FileAppender">
19 <file>target/testlogback.log</file>
20 <encoder>
21 <immediateFlush>false</immediateFlush>
22 <Pattern>%d %5p [%t] %c{0} %X{transactionId} - %m%n</Pattern>
23 </encoder>
24 </appender>
25
26 <root level="debug">
27 <appender-ref ref="TestLogfile" />
28 </root>
29 </configuration>
00 /target/
11 /.project
2 /configuration/target/
3 /loggerProperties/target/
0 /.settings/
1 /.classpath
2 /.project
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
18 <modelVersion>4.0.0</modelVersion>
19 <parent>
20 <artifactId>log4j-samples</artifactId>
21 <groupId>org.apache.logging.log4j.samples</groupId>
22 <version>2.4</version>
23 </parent>
24 <artifactId>log4j-samples-configuration</artifactId>
25 <packaging>jar</packaging>
26 <name>Apache Log4j Samples: Configuration</name>
27 <url>http://maven.apache.org</url>
28 <properties>
29 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
30 </properties>
31 <dependencies>
32 <dependency>
33 <groupId>org.apache.logging.log4j</groupId>
34 <artifactId>log4j-api</artifactId>
35 </dependency>
36 <dependency>
37 <groupId>org.apache.logging.log4j</groupId>
38 <artifactId>log4j-core</artifactId>
39 </dependency>
40 <dependency>
41 <groupId>junit</groupId>
42 <artifactId>junit</artifactId>
43 <scope>test</scope>
44 </dependency>
45 </dependencies>
46 <build>
47 <plugins>
48 <plugin>
49 <groupId>org.apache.felix</groupId>
50 <artifactId>maven-bundle-plugin</artifactId>
51 </plugin>
52 </plugins>
53 </build>
54 </project>
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.configuration;
17
18 import org.apache.logging.log4j.Level;
19 import org.apache.logging.log4j.core.Appender;
20 import org.apache.logging.log4j.core.Layout;
21 import org.apache.logging.log4j.core.appender.ConsoleAppender;
22 import org.apache.logging.log4j.core.config.AbstractConfiguration;
23 import org.apache.logging.log4j.core.config.ConfigurationSource;
24 import org.apache.logging.log4j.core.config.LoggerConfig;
25 import org.apache.logging.log4j.core.layout.PatternLayout;
26 import org.apache.logging.log4j.util.PropertiesUtil;
27
28 import java.io.Serializable;
29
30 /**
31 * This Configuration is the same as the DefaultConfiguration but shows how a custom configuration can be built
32 * programmatically
33 */
34 public class CustomConfiguration extends AbstractConfiguration {
35
36 private static final long serialVersionUID = 1L;
37
38 /**
39 * The name of the default configuration.
40 */
41 public static final String CONFIG_NAME = "Custom";
42
43 /**
44 * The System Property used to specify the logging level.
45 */
46 public static final String DEFAULT_LEVEL = "org.apache.logging.log4j.level";
47 /**
48 * The default Pattern used for the default Layout.
49 */
50 public static final String DEFAULT_PATTERN = "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n";
51
52 public CustomConfiguration() {
53 this(ConfigurationSource.NULL_SOURCE);
54 }
55
56 /**
57 * Constructor to create the default configuration.
58 */
59 public CustomConfiguration(ConfigurationSource source) {
60 super(source);
61
62 setName(CONFIG_NAME);
63 final Layout<? extends Serializable> layout = PatternLayout.newBuilder()
64 .withPattern(DEFAULT_PATTERN)
65 .withConfiguration(this)
66 .build();
67 final Appender appender = ConsoleAppender.createDefaultAppenderForLayout(layout);
68 appender.start();
69 addAppender(appender);
70 final LoggerConfig root = getRootLogger();
71 root.addAppender(appender, null, null);
72
73 final String levelName = PropertiesUtil.getProperties().getStringProperty(DEFAULT_LEVEL);
74 final Level level = levelName != null && Level.valueOf(levelName) != null ?
75 Level.valueOf(levelName) : Level.ERROR;
76 root.setLevel(level);
77 }
78
79 @Override
80 protected void doConfigure() {
81 }
82 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.configuration;
17
18 import org.apache.logging.log4j.core.config.Configuration;
19 import org.apache.logging.log4j.core.config.ConfigurationFactory;
20 import org.apache.logging.log4j.core.config.ConfigurationSource;
21 import org.apache.logging.log4j.core.config.Order;
22 import org.apache.logging.log4j.core.config.plugins.Plugin;
23 import org.apache.logging.log4j.core.config.xml.XmlConfiguration;
24
25 import java.net.URI;
26
27 /**
28 * Factory to construct a CustomConfiguration.
29 */
30 @Plugin(name = "CustomConfigurationFactory", category = ConfigurationFactory.CATEGORY)
31 @Order(50)
32 public class CustomConfigurationFactory extends ConfigurationFactory {
33
34 /**
35 * Valid file extensions for XML files.
36 */
37 public static final String[] SUFFIXES = new String[] {"*"};
38
39 /**
40 * Returns the Configuration.
41 * @param source The InputSource.
42 * @return The Configuration.
43 */
44 @Override
45 public Configuration getConfiguration(final ConfigurationSource source) {
46 return new CustomConfiguration(source);
47 }
48
49 @Override
50 public Configuration getConfiguration(final String name, final URI configLocation) {
51 return new CustomConfiguration();
52 }
53
54 /**
55 * Returns the file suffixes for XML files.
56 * @return An array of File extensions.
57 */
58 @Override
59 public String[] getSupportedTypes() {
60 return SUFFIXES;
61 }
62 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.configuration;
17
18 import org.apache.logging.log4j.LogManager;
19 import org.apache.logging.log4j.Logger;
20 import org.junit.Test;
21
22 /**
23 *
24 */
25 public class CustomConfigurationTest {
26 private Logger logger = LogManager.getLogger(CustomConfiguration.class);
27
28 @Test
29 public void testLogging() {
30 logger.error("This is a test");
31 }
32 }
1919 <parent>
2020 <artifactId>log4j-samples</artifactId>
2121 <groupId>org.apache.logging.log4j.samples</groupId>
22 <version>2.2</version>
22 <version>2.4</version>
2323 </parent>
2424 <artifactId>log4j-samples-flume-common</artifactId>
2525 <packaging>jar</packaging>
2525 import org.apache.logging.log4j.ThreadContext;
2626 import org.apache.logging.log4j.samples.dto.AuditEvent;
2727 import org.apache.logging.log4j.samples.dto.RequestContext;
28 import org.apache.logging.log4j.util.Strings;
2829 import org.springframework.stereotype.Controller;
2930 import org.springframework.web.bind.annotation.RequestMapping;
3031 import org.springframework.web.bind.annotation.RequestMethod;
5657 @RequestParam(value = "threads", required = false, defaultValue = "1") final String threadCount,
5758 final HttpServletRequest servletRequest) {
5859 int numThreads = 1;
59 if (threadCount != null && threadCount.length() > 0) {
60 if (Strings.isNotEmpty(threadCount)) {
6061 try {
6162 numThreads = Integer.parseInt(threadCount);
6263 } catch (final Exception ex) {
6364 System.out.println("Invalid threadCount specified: " + threadCount);
6465 }
6566 }
66 if (interval != null && interval.length() > 0) {
67 if (Strings.isNotEmpty(interval)) {
6768 try {
6869 timeBase = Integer.parseInt(interval);
6970 } catch (final Exception ex) {
3333
3434 public static List<AuditEvent> getAllEvents(final String member) {
3535
36 final List<AuditEvent> events = new ArrayList<AuditEvent>();
36 final List<AuditEvent> events = new ArrayList<>();
3737
3838
3939 final Login login = LogEventFactory.getEvent(Login.class);
1919 <parent>
2020 <artifactId>log4j-samples</artifactId>
2121 <groupId>org.apache.logging.log4j.samples</groupId>
22 <version>2.2</version>
22 <version>2.4</version>
2323 </parent>
2424 <artifactId>log4j-samples-flume-embedded</artifactId>
2525 <packaging>war</packaging>
1919 <parent>
2020 <artifactId>log4j-samples</artifactId>
2121 <groupId>org.apache.logging.log4j.samples</groupId>
22 <version>2.2</version>
22 <version>2.4</version>
2323 </parent>
2424 <artifactId>log4j-samples-flume-remote</artifactId>
2525 <packaging>war</packaging>
0 /.settings/
1 /.classpath
2 /.project
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
18 <modelVersion>4.0.0</modelVersion>
19 <parent>
20 <artifactId>log4j-samples</artifactId>
21 <groupId>org.apache.logging.log4j.samples</groupId>
22 <version>2.4</version>
23 </parent>
24 <artifactId>log4j-samples-loggerProperties</artifactId>
25 <packaging>jar</packaging>
26 <name>Apache Log4j Samples: LoggerProperties</name>
27 <url>http://maven.apache.org</url>
28 <properties>
29 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
30 </properties>
31 <dependencies>
32 <dependency>
33 <groupId>org.apache.logging.log4j</groupId>
34 <artifactId>log4j-api</artifactId>
35 </dependency>
36 <dependency>
37 <groupId>org.apache.logging.log4j</groupId>
38 <artifactId>log4j-core</artifactId>
39 </dependency>
40 <dependency>
41 <groupId>junit</groupId>
42 <artifactId>junit</artifactId>
43 <scope>test</scope>
44 </dependency>
45 </dependencies>
46 <build>
47 <plugins>
48 <plugin>
49 <groupId>org.apache.felix</groupId>
50 <artifactId>maven-bundle-plugin</artifactId>
51 </plugin>
52 </plugins>
53 </build>
54 </project>
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.lookup;
17
18 import org.apache.logging.log4j.Logger;
19 import org.apache.logging.log4j.Marker;
20 import org.apache.logging.log4j.MarkerManager;
21 import org.apache.logging.log4j.core.LogEvent;
22 import org.apache.logging.log4j.core.config.plugins.Plugin;
23 import org.apache.logging.log4j.core.lookup.AbstractLookup;
24 import org.apache.logging.log4j.core.lookup.StrLookup;
25 import org.apache.logging.log4j.status.StatusLogger;
26
27 import java.lang.Override;
28 import java.util.Map;
29 import java.util.concurrent.ConcurrentHashMap;
30 import java.util.concurrent.ConcurrentMap;
31
32 /**
33 *
34 */
35
36 @Plugin(name = "custom", category = StrLookup.CATEGORY)
37 public class CustomLookup extends AbstractLookup {
38
39 private static final Logger LOGGER = StatusLogger.getLogger();
40 private static final Marker LOOKUP = MarkerManager.getMarker("LOOKUP");
41
42 private static ConcurrentMap<String, Map<String, String>> loggerProperties = new ConcurrentHashMap<>();
43
44 /**
45 * Looks up the value for the key using the data in the LogEvent.
46 * @param event The current LogEvent.
47 * @param key the key to be looked up, may be null
48 * @return The value associated with the key.
49 */
50 @Override
51 public String lookup(final LogEvent event, final String key) {
52 try {
53 Map<String, String> properties = loggerProperties.get(event.getLoggerName());
54 if (properties == null) {
55 return "";
56 }
57 if (key == null || key.length() == 0 || key.equals("*")) {
58 StringBuilder sb = new StringBuilder("{");
59 boolean first = true;
60 for (Map.Entry<String, String> entry : properties.entrySet()) {
61 if (!first) {
62 sb.append(", ");
63 }
64 sb.append(entry.getKey()).append("=").append(entry.getValue());
65 first = false;
66 }
67 sb.append("}");
68 return sb.toString();
69 } else {
70 return properties.get(key);
71 }
72 } catch (final Exception ex) {
73 LOGGER.warn(LOOKUP, "Error while getting property [{}].", key, ex);
74 return null;
75 }
76 }
77
78 public static void setLoggerProperties(String loggerName, Map<String, String> properties) {
79 loggerProperties.put(loggerName, properties);
80 }
81
82 }
83
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.lookup;
17
18 import org.apache.logging.log4j.message.MapMessage;
19
20 import java.util.Map;
21
22 /**
23 *
24 */
25 public class CustomMapMessage extends MapMessage {
26
27 private final String message;
28
29 public CustomMapMessage(String msg, Map<String, String> map) {
30 super(map);
31 this.message = msg;
32 }
33
34 @Override
35 public String getFormattedMessage(final String[] formats) {
36 if (message != null) {
37 return message;
38 }
39 return super.getFormattedMessage(formats);
40 }
41
42 @Override
43 public String getFormattedMessage() {
44 if (message != null) {
45 return message;
46 }
47 return super.getFormattedMessage();
48 }
49
50 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.lookup;
17
18 import org.apache.logging.log4j.Logger;
19 import org.apache.logging.log4j.Marker;
20 import org.apache.logging.log4j.MarkerManager;
21 import org.apache.logging.log4j.core.LogEvent;
22 import org.apache.logging.log4j.core.config.plugins.Plugin;
23 import org.apache.logging.log4j.core.lookup.AbstractLookup;
24 import org.apache.logging.log4j.core.lookup.StrLookup;
25 import org.apache.logging.log4j.message.MapMessage;
26 import org.apache.logging.log4j.message.Message;
27 import org.apache.logging.log4j.status.StatusLogger;
28
29 import java.util.Map;
30 import java.util.concurrent.ConcurrentHashMap;
31 import java.util.concurrent.ConcurrentMap;
32
33 /**
34 *
35 */
36
37 @Plugin(name = "mapMessage", category = StrLookup.CATEGORY)
38 public class MapMessageLookup extends AbstractLookup {
39
40 private static final Logger LOGGER = StatusLogger.getLogger();
41 private static final Marker LOOKUP = MarkerManager.getMarker("LOOKUP");
42
43 private static ConcurrentMap<String, Map<String, String>> loggerProperties = new ConcurrentHashMap<>();
44
45 /**
46 * Looks up the value for the key using the data in the LogEvent.
47 * @param event The current LogEvent.
48 * @param key the key to be looked up, may be null
49 * @return The value associated with the key.
50 */
51 @Override
52 public String lookup(final LogEvent event, final String key) {
53 Message msg = event.getMessage();
54 if (msg instanceof MapMessage) {
55 try {
56 Map<String, String> properties = ((MapMessage) msg).getData();
57 if (properties == null) {
58 return "";
59 }
60 if (key == null || key.length() == 0 || key.equals("*")) {
61 StringBuilder sb = new StringBuilder("{");
62 boolean first = true;
63 for (Map.Entry<String, String> entry : properties.entrySet()) {
64 if (!first) {
65 sb.append(", ");
66 }
67 sb.append(entry.getKey()).append("=").append(entry.getValue());
68 first = false;
69 }
70 sb.append("}");
71 return sb.toString();
72 } else {
73 return properties.get(key);
74 }
75 } catch (final Exception ex) {
76 LOGGER.warn(LOOKUP, "Error while getting property [{}].", key, ex);
77 return null;
78 }
79 } else {
80 return null;
81 }
82 }
83
84 public static void setLoggerProperties(String loggerName, Map<String, String> properties) {
85 loggerProperties.put(loggerName, properties);
86 }
87
88 }
89
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j;
17
18 import org.apache.logging.log4j.lookup.CustomLookup;
19 import org.apache.logging.log4j.lookup.CustomMapMessage;
20 import org.junit.Test;
21
22 import java.util.Map;
23 import java.util.concurrent.ConcurrentHashMap;
24
25 /**
26 * Created by rgoers on 8/2/15.
27 */
28 public class CustomPropertiesTest {
29
30 @Test
31 public void testProperties() throws Exception {
32 Logger logger = LogManager.getLogger("TestProperties");
33 Map<String, String> loggerProperties = new ConcurrentHashMap<>();
34 CustomLookup.setLoggerProperties("TestProperties", loggerProperties);
35 loggerProperties.put("key1", "CustomPropertiesTest");
36 loggerProperties.put("key2", "TestValue");
37 logger.debug("This is a test");
38 }
39
40 @Test
41 public void mapMessageProperties() throws Exception {
42 Logger logger = LogManager.getLogger("MapProperties");
43 Map<String, String> loggerProperties = new ConcurrentHashMap<>();
44 loggerProperties.put("key1", "CustomPropertiesTest");
45 loggerProperties.put("key2", "TestValue");
46 logger.debug(new CustomMapMessage("This is a test", loggerProperties));
47 }
48
49
50 }
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16
17 -->
18 <Configuration name="XMLPerfTest" status="error">
19 <Appenders>
20 <File name="TestLogfile" fileName="target/testlog4j2.log" immediateFlush="false">
21 <PatternLayout>
22 <Pattern>%d %5p [%t] %c{1} - %m%n</Pattern>
23 </PatternLayout>
24 </File>
25 <RandomAccessFile name="RandomAccessLogFile" fileName="target/testCustomlog4j2.log" immediateFlush="false">
26 <PatternLayout>
27 <Pattern>%d %5p [%t] %c{1} %X{key1} %X{key2} - %m%n</Pattern>
28 </PatternLayout>
29 </RandomAccessFile>
30 </Appenders>
31 <Loggers>
32 <Logger name="TestProperties" level="debug" additivity="false">
33 <Property name="key1">$${custom:key1}</Property>
34 <Property name="key2">$${custom:key2}</Property>
35 <AppenderRef ref="RandomAccessLogFile"/>
36 </Logger>
37 <Logger name="MapProperties" level="debug" additivity="false">
38 <Property name="key1">$${mapMessage:key1}</Property>
39 <Property name="key2">$${mapMessage:key2}</Property>
40 <AppenderRef ref="RandomAccessLogFile"/>
41 </Logger>
42
43 <Root level="debug">
44 <AppenderRef ref="TestLogfile"/>
45 </Root>
46 </Loggers>
47 </Configuration>
1919 <parent>
2020 <groupId>org.apache.logging.log4j</groupId>
2121 <artifactId>log4j</artifactId>
22 <version>2.2</version>
22 <version>2.4</version>
2323 <relativePath>../</relativePath>
2424 </parent>
2525 <groupId>org.apache.logging.log4j.samples</groupId>
8080 <module>flume-common</module>
8181 <module>flume-remote</module>
8282 <module>flume-embedded</module>
83 <module>configuration</module>
84 <module>loggerProperties</module>
8385 </modules>
8486 <build>
8587 <plugins>
1919 <parent>
2020 <groupId>org.apache.logging.log4j</groupId>
2121 <artifactId>log4j</artifactId>
22 <version>2.2</version>
22 <version>2.4</version>
2323 <relativePath>../</relativePath>
2424 </parent>
2525 <artifactId>log4j-slf4j-impl</artifactId>
4343 this.marker = marker;
4444 }
4545
46 public org.apache.logging.log4j.Marker getLog4jMarker() {
47 return marker;
48 }
49
5046 @Override
5147 public void add(final Marker marker) {
48 if (marker == null) {
49 throw new IllegalArgumentException();
50 }
5251 final Marker m = factory.getMarker(marker.getName());
5352 this.marker.addParents(((Log4jMarker)m).getLog4jMarker());
5453 }
5554
5655 @Override
57 public boolean remove(final Marker marker) {
58 return this.marker.remove(MarkerManager.getMarker(marker.getName()));
56 public boolean contains(final org.slf4j.Marker marker) {
57 if (marker == null) {
58 throw new IllegalArgumentException();
59 }
60 return this.marker.isInstanceOf(marker.getName());
61 }
62
63 @Override
64 public boolean contains(final String s) {
65 return s != null ? this.marker.isInstanceOf(s) : false;
66 }
67
68 @Override
69 public boolean equals(final Object obj) {
70 if (this == obj) {
71 return true;
72 }
73 if (obj == null) {
74 return false;
75 }
76 if (!(obj instanceof Log4jMarker)) {
77 return false;
78 }
79 final Log4jMarker other = (Log4jMarker) obj;
80 if (marker == null) {
81 if (other.marker != null) {
82 return false;
83 }
84 } else if (!marker.equals(other.marker)) {
85 return false;
86 }
87 return true;
88 }
89
90 public org.apache.logging.log4j.Marker getLog4jMarker() {
91 return marker;
5992 }
6093
6194 @Override
6497 }
6598
6699 @Override
67 public boolean hasReferences() {
68 return marker.hasParents();
69 }
70
71 @Override
72100 public boolean hasChildren() {
73101 return marker.hasParents();
74102 }
75103
76104 @Override
77 @SuppressWarnings("rawtypes")
78 public Iterator iterator() {
79 final List<Marker> parents = new ArrayList<Marker>();
80 for (final org.apache.logging.log4j.Marker m : this.marker.getParents()) {
105 public int hashCode() {
106 final int prime = 31;
107 int result = 1;
108 result = prime * result + ((marker == null) ? 0 : marker.hashCode());
109 return result;
110 }
111
112 @Override
113 public boolean hasReferences() {
114 return marker.hasParents();
115 }
116
117 @Override
118 public Iterator<Marker> iterator() {
119 final org.apache.logging.log4j.Marker[] log4jParents = this.marker.getParents();
120 final List<Marker> parents = new ArrayList<>(log4jParents.length);
121 for (final org.apache.logging.log4j.Marker m : log4jParents) {
81122 parents.add(factory.getMarker(m.getName()));
82123 }
83124 return parents.iterator();
84125 }
85126
86 @Override
87 public boolean contains(final org.slf4j.Marker marker) {
88 return this.marker.isInstanceOf(marker.getName());
89 }
90
91 @Override
92 public boolean contains(final String s) {
93 return this.marker.isInstanceOf(s);
94 }
127 @Override
128 public boolean remove(final Marker marker) {
129 return marker != null ? this.marker.remove(MarkerManager.getMarker(marker.getName())) : false;
130 }
95131 }
3434
3535 private static final Logger LOGGER = StatusLogger.getLogger();
3636
37 private final ConcurrentMap<String, Marker> markerMap = new ConcurrentHashMap<String, Marker>();
37 private final ConcurrentMap<String, Marker> markerMap = new ConcurrentHashMap<>();
3838
3939 /**
4040 * Returns a Log4j Marker that is compatible with SLF4J.
8888 final Collection<Marker> visited) {
8989 final org.apache.logging.log4j.Marker marker = MarkerManager.getMarker(original.getName());
9090 if (original.hasReferences()) {
91 final Iterator it = original.iterator();
91 final Iterator<Marker> it = original.iterator();
9292 while (it.hasNext()) {
93 final Marker next = (Marker) it.next();
93 final Marker next = it.next();
9494 if (visited.contains(next)) {
9595 LOGGER.warn("Found a cycle in Marker [{}]. Cycle will be broken.", next.getName());
9696 } else {
3333
3434 <section name="Requirements">
3535 <p>
36 The Log4j 2 SLF4J Binding requires at least Java 6 and has a dependency
36 The Log4j 2 SLF4J Binding has a dependency
3737 on the Log4j 2 API as well as the SLF4J API.
3838 </p>
3939 </section>
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.slf4j;
17
18 import java.util.List;
19
20 import org.apache.logging.log4j.junit.InitialLoggerContext;
21 import org.apache.logging.log4j.test.appender.ListAppender;
22 import org.junit.Rule;
23 import org.junit.Test;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 import static org.junit.Assert.assertEquals;
28
29 public class CallerInformationTest {
30
31 // config from log4j-core test-jar
32 private static final String CONFIG = "log4j2-calling-class.xml";
33
34 @Rule
35 public final InitialLoggerContext ctx = new InitialLoggerContext(CONFIG);
36
37 @Test
38 public void testClassLogger() throws Exception {
39 final ListAppender app = ctx.getListAppender("Class").clear();
40 final Logger logger = LoggerFactory.getLogger("ClassLogger");
41 logger.info("Ignored message contents.");
42 logger.warn("Verifying the caller class is still correct.");
43 logger.error("Hopefully nobody breaks me!");
44 final List<String> messages = app.getMessages();
45 assertEquals("Incorrect number of messages.", 3, messages.size());
46 for (final String message : messages) {
47 assertEquals("Incorrect caller class name.", this.getClass().getName(), message);
48 }
49 }
50
51 @Test
52 public void testMethodLogger() throws Exception {
53 final ListAppender app = ctx.getListAppender("Method").clear();
54 final Logger logger = LoggerFactory.getLogger("MethodLogger");
55 logger.info("More messages.");
56 logger.warn("CATASTROPHE INCOMING!");
57 logger.error("ZOMBIES!!!");
58 logger.warn("brains~~~");
59 logger.info("Itchy. Tasty.");
60 final List<String> messages = app.getMessages();
61 assertEquals("Incorrect number of messages.", 5, messages.size());
62 for (final String message : messages) {
63 assertEquals("Incorrect caller method name.", "testMethodLogger", message);
64 }
65 }
66 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.slf4j;
17
18 import static org.junit.Assert.assertEquals;
19
20 import java.util.List;
21
22 import org.apache.logging.log4j.junit.LoggerContextRule;
23 import org.apache.logging.log4j.test.appender.ListAppender;
24 import org.junit.ClassRule;
25 import org.junit.Test;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 public class CallerInformationTest {
30
31 // config from log4j-core test-jar
32 private static final String CONFIG = "log4j2-calling-class.xml";
33
34 @ClassRule
35 public static final LoggerContextRule ctx = new LoggerContextRule(CONFIG);
36
37 @Test
38 public void testClassLogger() throws Exception {
39 final ListAppender app = ctx.getListAppender("Class").clear();
40 final Logger logger = LoggerFactory.getLogger("ClassLogger");
41 logger.info("Ignored message contents.");
42 logger.warn("Verifying the caller class is still correct.");
43 logger.error("Hopefully nobody breaks me!");
44 final List<String> messages = app.getMessages();
45 assertEquals("Incorrect number of messages.", 3, messages.size());
46 for (final String message : messages) {
47 assertEquals("Incorrect caller class name.", this.getClass().getName(), message);
48 }
49 }
50
51 @Test
52 public void testMethodLogger() throws Exception {
53 final ListAppender app = ctx.getListAppender("Method").clear();
54 final Logger logger = LoggerFactory.getLogger("MethodLogger");
55 logger.info("More messages.");
56 logger.warn("CATASTROPHE INCOMING!");
57 logger.error("ZOMBIES!!!");
58 logger.warn("brains~~~");
59 logger.info("Itchy. Tasty.");
60 final List<String> messages = app.getMessages();
61 assertEquals("Incorrect number of messages.", 5, messages.size());
62 for (final String message : messages) {
63 assertEquals("Incorrect caller method name.", "testMethodLogger", message);
64 }
65 }
66 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.slf4j;
17
18 import org.apache.logging.log4j.Marker;
19 import org.apache.logging.log4j.MarkerManager;
20 import org.junit.Assert;
21 import org.junit.Test;
22
23 public class Log4jMarkerTest {
24
25 @Test
26 public void testEquals() {
27 final Marker markerA = MarkerManager.getMarker(Log4jMarkerTest.class.getName() + "-A");
28 final Marker markerB = MarkerManager.getMarker(Log4jMarkerTest.class.getName() + "-B");
29 final Log4jMarker marker1 = new Log4jMarker(markerA);
30 final Log4jMarker marker2 = new Log4jMarker(markerA);
31 final Log4jMarker marker3 = new Log4jMarker(markerB);
32 Assert.assertEquals(marker1, marker2);
33 Assert.assertNotEquals(marker1, null);
34 Assert.assertNotEquals(null, marker1);
35 Assert.assertNotEquals(marker1, marker3);
36 }
37 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.slf4j;
17
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertNotNull;
20 import static org.junit.Assert.assertTrue;
21
22 import java.util.List;
23 import java.util.Locale;
24
25 import org.apache.logging.log4j.core.util.Constants;
26 import org.apache.logging.log4j.junit.InitialLoggerContext;
27 import org.apache.logging.log4j.test.appender.ListAppender;
28 import org.junit.After;
29 import org.junit.Before;
30 import org.junit.ClassRule;
31 import org.junit.Test;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34 import org.slf4j.MDC;
35 import org.slf4j.Marker;
36 import org.slf4j.ext.EventData;
37 import org.slf4j.ext.EventLogger;
38 import org.slf4j.ext.XLogger;
39 import org.slf4j.ext.XLoggerFactory;
40 import org.slf4j.spi.LocationAwareLogger;
41
42 /**
43 *
44 */
45 public class LoggerTest {
46
47 private static final String CONFIG = "log4j-test1.xml";
48
49 @ClassRule
50 public static InitialLoggerContext ctx = new InitialLoggerContext(CONFIG);
51
52 Logger logger = LoggerFactory.getLogger("LoggerTest");
53 XLogger xlogger = XLoggerFactory.getXLogger("LoggerTest");
54
55 @Test
56 public void basicFlow() {
57 xlogger.entry();
58 verify("List", "o.a.l.s.LoggerTest entry MDC{}" + Constants.LINE_SEPARATOR);
59 xlogger.exit();
60 verify("List", "o.a.l.s.LoggerTest exit MDC{}" + Constants.LINE_SEPARATOR);
61 }
62
63 @Test
64 public void simpleFlow() {
65 xlogger.entry(CONFIG);
66 verify("List", "o.a.l.s.LoggerTest entry with (log4j-test1.xml) MDC{}" + Constants.LINE_SEPARATOR);
67 xlogger.exit(0);
68 verify("List", "o.a.l.s.LoggerTest exit with (0) MDC{}" + Constants.LINE_SEPARATOR);
69 }
70
71 @Test
72 public void throwing() {
73 xlogger.throwing(new IllegalArgumentException("Test Exception"));
74 verify("List", "o.a.l.s.LoggerTest throwing MDC{}" + Constants.LINE_SEPARATOR);
75 }
76
77 @Test
78 public void catching() {
79 try {
80 throw new NullPointerException();
81 } catch (final Exception e) {
82 xlogger.catching(e);
83 verify("List", "o.a.l.s.LoggerTest catching MDC{}" + Constants.LINE_SEPARATOR);
84 }
85 }
86
87 @Test
88 public void debug() {
89 logger.debug("Debug message");
90 verify("List", "o.a.l.s.LoggerTest Debug message MDC{}" + Constants.LINE_SEPARATOR);
91 }
92
93 @Test
94 public void debugNoParms() {
95 logger.debug("Debug message {}");
96 verify("List", "o.a.l.s.LoggerTest Debug message {} MDC{}" + Constants.LINE_SEPARATOR);
97 logger.debug("Debug message {}", (Object[]) null);
98 verify("List", "o.a.l.s.LoggerTest Debug message {} MDC{}" + Constants.LINE_SEPARATOR);
99 ((LocationAwareLogger)logger).log(null, Log4jLogger.class.getName(), LocationAwareLogger.DEBUG_INT,
100 "Debug message {}", null, null);
101 verify("List", "o.a.l.s.LoggerTest Debug message {} MDC{}" + Constants.LINE_SEPARATOR);
102 }
103
104
105 @Test
106 public void debugWithParms() {
107 logger.debug("Hello, {}", "World");
108 verify("List", "o.a.l.s.LoggerTest Hello, World MDC{}" + Constants.LINE_SEPARATOR);
109 }
110
111 @Test
112 public void mdc() {
113
114 MDC.put("TestYear", "2010");
115 logger.debug("Debug message");
116 verify("List", "o.a.l.s.LoggerTest Debug message MDC{TestYear=2010}" + Constants.LINE_SEPARATOR);
117 MDC.clear();
118 logger.debug("Debug message");
119 verify("List", "o.a.l.s.LoggerTest Debug message MDC{}" + Constants.LINE_SEPARATOR);
120 }
121
122 /**
123 * @see <a href="https://issues.apache.org/jira/browse/LOG4J2-793">LOG4J2-793</a>
124 */
125 @Test
126 public void supportsCustomSLF4JMarkers() {
127 final Marker marker = new CustomFlatMarker("TEST");
128 logger.debug(marker, "Test");
129 verify("List", "o.a.l.s.LoggerTest Test MDC{}" + Constants.LINE_SEPARATOR);
130 }
131
132 @Test
133 public void testRootLogger() {
134 final Logger l = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
135 assertNotNull("No Root Logger", l);
136 assertEquals(Logger.ROOT_LOGGER_NAME, l.getName());
137 }
138
139 @Test
140 public void doubleSubst() {
141 logger.debug("Hello, {}", "Log4j {}");
142 verify("List", "o.a.l.s.LoggerTest Hello, Log4j {} MDC{}" + Constants.LINE_SEPARATOR);
143 xlogger.debug("Hello, {}", "Log4j {}");
144 verify("List", "o.a.l.s.LoggerTest Hello, Log4j Log4j {} MDC{}" + Constants.LINE_SEPARATOR);
145 }
146
147 @Test
148 public void testEventLogger() {
149 MDC.put("loginId", "JohnDoe");
150 MDC.put("ipAddress", "192.168.0.120");
151 MDC.put("locale", Locale.US.getDisplayName());
152 final EventData data = new EventData();
153 data.setEventType("Transfer");
154 data.setEventId("Audit@18060");
155 data.setMessage("Transfer Complete");
156 data.put("ToAccount", "123456");
157 data.put("FromAccount", "123457");
158 data.put("Amount", "200.00");
159 EventLogger.logEvent(data);
160 MDC.clear();
161 verify("EventLogger", "o.a.l.s.LoggerTest Transfer [Audit@18060 Amount=\"200.00\" FromAccount=\"123457\" ToAccount=\"123456\"] Transfer Complete" + Constants.LINE_SEPARATOR);
162 }
163
164 private void verify(final String name, final String expected) {
165 final ListAppender listApp = ctx.getListAppender(name);
166 assertNotNull("Missing Appender", listApp);
167 final List<String> events = listApp.getMessages();
168 assertTrue("Incorrect number of messages. Expected 1 Actual " + events.size(), events.size()== 1);
169 final String actual = events.get(0);
170 assertEquals("Incorrect message. Expected " + expected + ". Actual " + actual, expected, actual);
171 listApp.clear();
172 }
173
174 @Before
175 @After
176 public void cleanup() {
177 MDC.clear();
178 ctx.getListAppender("List").clear();
179 ctx.getListAppender("EventLogger").clear();
180 }
181 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.slf4j;
17
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertNotNull;
20 import static org.junit.Assert.assertTrue;
21
22 import java.util.List;
23 import java.util.Locale;
24
25 import org.apache.logging.log4j.core.util.Constants;
26 import org.apache.logging.log4j.junit.LoggerContextRule;
27 import org.apache.logging.log4j.test.appender.ListAppender;
28 import org.junit.After;
29 import org.junit.Before;
30 import org.junit.ClassRule;
31 import org.junit.Test;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34 import org.slf4j.MDC;
35 import org.slf4j.Marker;
36 import org.slf4j.ext.EventData;
37 import org.slf4j.ext.EventLogger;
38 import org.slf4j.ext.XLogger;
39 import org.slf4j.ext.XLoggerFactory;
40 import org.slf4j.spi.LocationAwareLogger;
41
42 /**
43 *
44 */
45 public class LoggerTest {
46
47 private static final String CONFIG = "log4j-test1.xml";
48
49 @ClassRule
50 public static LoggerContextRule ctx = new LoggerContextRule(CONFIG);
51
52 Logger logger = LoggerFactory.getLogger("LoggerTest");
53 XLogger xlogger = XLoggerFactory.getXLogger("LoggerTest");
54
55 @Test
56 public void basicFlow() {
57 xlogger.entry();
58 verify("List", "o.a.l.s.LoggerTest entry MDC{}" + Constants.LINE_SEPARATOR);
59 xlogger.exit();
60 verify("List", "o.a.l.s.LoggerTest exit MDC{}" + Constants.LINE_SEPARATOR);
61 }
62
63 @Test
64 public void simpleFlow() {
65 xlogger.entry(CONFIG);
66 verify("List", "o.a.l.s.LoggerTest entry with (log4j-test1.xml) MDC{}" + Constants.LINE_SEPARATOR);
67 xlogger.exit(0);
68 verify("List", "o.a.l.s.LoggerTest exit with (0) MDC{}" + Constants.LINE_SEPARATOR);
69 }
70
71 @Test
72 public void throwing() {
73 xlogger.throwing(new IllegalArgumentException("Test Exception"));
74 verify("List", "o.a.l.s.LoggerTest throwing MDC{}" + Constants.LINE_SEPARATOR);
75 }
76
77 @Test
78 public void catching() {
79 try {
80 throw new NullPointerException();
81 } catch (final Exception e) {
82 xlogger.catching(e);
83 verify("List", "o.a.l.s.LoggerTest catching MDC{}" + Constants.LINE_SEPARATOR);
84 }
85 }
86
87 @Test
88 public void debug() {
89 logger.debug("Debug message");
90 verify("List", "o.a.l.s.LoggerTest Debug message MDC{}" + Constants.LINE_SEPARATOR);
91 }
92
93 @Test
94 public void debugNoParms() {
95 logger.debug("Debug message {}");
96 verify("List", "o.a.l.s.LoggerTest Debug message {} MDC{}" + Constants.LINE_SEPARATOR);
97 logger.debug("Debug message {}", (Object[]) null);
98 verify("List", "o.a.l.s.LoggerTest Debug message {} MDC{}" + Constants.LINE_SEPARATOR);
99 ((LocationAwareLogger)logger).log(null, Log4jLogger.class.getName(), LocationAwareLogger.DEBUG_INT,
100 "Debug message {}", null, null);
101 verify("List", "o.a.l.s.LoggerTest Debug message {} MDC{}" + Constants.LINE_SEPARATOR);
102 }
103
104
105 @Test
106 public void debugWithParms() {
107 logger.debug("Hello, {}", "World");
108 verify("List", "o.a.l.s.LoggerTest Hello, World MDC{}" + Constants.LINE_SEPARATOR);
109 }
110
111 @Test
112 public void mdc() {
113
114 MDC.put("TestYear", "2010");
115 logger.debug("Debug message");
116 verify("List", "o.a.l.s.LoggerTest Debug message MDC{TestYear=2010}" + Constants.LINE_SEPARATOR);
117 MDC.clear();
118 logger.debug("Debug message");
119 verify("List", "o.a.l.s.LoggerTest Debug message MDC{}" + Constants.LINE_SEPARATOR);
120 }
121
122 /**
123 * @see <a href="https://issues.apache.org/jira/browse/LOG4J2-793">LOG4J2-793</a>
124 */
125 @Test
126 public void supportsCustomSLF4JMarkers() {
127 final Marker marker = new CustomFlatMarker("TEST");
128 logger.debug(marker, "Test");
129 verify("List", "o.a.l.s.LoggerTest Test MDC{}" + Constants.LINE_SEPARATOR);
130 }
131
132 @Test
133 public void testRootLogger() {
134 final Logger l = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
135 assertNotNull("No Root Logger", l);
136 assertEquals(Logger.ROOT_LOGGER_NAME, l.getName());
137 }
138
139 @Test
140 public void doubleSubst() {
141 logger.debug("Hello, {}", "Log4j {}");
142 verify("List", "o.a.l.s.LoggerTest Hello, Log4j {} MDC{}" + Constants.LINE_SEPARATOR);
143 xlogger.debug("Hello, {}", "Log4j {}");
144 verify("List", "o.a.l.s.LoggerTest Hello, Log4j Log4j {} MDC{}" + Constants.LINE_SEPARATOR);
145 }
146
147 @Test
148 public void testEventLogger() {
149 MDC.put("loginId", "JohnDoe");
150 MDC.put("ipAddress", "192.168.0.120");
151 MDC.put("locale", Locale.US.getDisplayName());
152 final EventData data = new EventData();
153 data.setEventType("Transfer");
154 data.setEventId("Audit@18060");
155 data.setMessage("Transfer Complete");
156 data.put("ToAccount", "123456");
157 data.put("FromAccount", "123457");
158 data.put("Amount", "200.00");
159 EventLogger.logEvent(data);
160 MDC.clear();
161 verify("EventLogger", "o.a.l.s.LoggerTest Transfer [Audit@18060 Amount=\"200.00\" FromAccount=\"123457\" ToAccount=\"123456\"] Transfer Complete" + Constants.LINE_SEPARATOR);
162 }
163
164 private void verify(final String name, final String expected) {
165 final ListAppender listApp = ctx.getListAppender(name);
166 assertNotNull("Missing Appender", listApp);
167 final List<String> events = listApp.getMessages();
168 assertTrue("Incorrect number of messages. Expected 1 Actual " + events.size(), events.size()== 1);
169 final String actual = events.get(0);
170 assertEquals("Incorrect message. Expected " + expected + ". Actual " + actual, expected, actual);
171 listApp.clear();
172 }
173
174 @Before
175 @After
176 public void cleanup() {
177 MDC.clear();
178 ctx.getListAppender("List").clear();
179 ctx.getListAppender("EventLogger").clear();
180 }
181 }
1818 import org.apache.logging.log4j.Marker;
1919 import org.apache.logging.log4j.MarkerManager;
2020 import org.junit.After;
21 import org.junit.Assert;
2122 import org.junit.Before;
2223 import org.junit.Test;
2324
2829 */
2930 public class MarkerTest {
3031
31 private static final String PARENT_MARKER_NAME = MarkerTest.class.getSimpleName() + "-PARENT";
32 private static final String CHILD_MAKER_NAME = MarkerTest.class.getSimpleName() + "-TEST";
32 private static final String CHILD_MAKER_NAME = MarkerTest.class.getSimpleName() + "-TEST";
33 private static final String PARENT_MARKER_NAME = MarkerTest.class.getSimpleName() + "-PARENT";
3334
34 @Before
35 @After
36 public void clearMarkers() {
37 MarkerManager.clear();
38 }
35 @Before
36 @After
37 public void clearMarkers() {
38 MarkerManager.clear();
39 }
3940
40 @Test
41 public void testMarker() {
42 final org.slf4j.Marker slf4jMarker = org.slf4j.MarkerFactory.getMarker(CHILD_MAKER_NAME);
43 final org.slf4j.Marker slf4jParent = org.slf4j.MarkerFactory.getMarker(PARENT_MARKER_NAME);
44 slf4jMarker.add(slf4jParent);
45 final Marker log4jParent = MarkerManager.getMarker(PARENT_MARKER_NAME);
46 final Marker log4jMarker = MarkerManager.getMarker(CHILD_MAKER_NAME);
41 @Test
42 public void testAddMarker() {
43 final String childMakerName = CHILD_MAKER_NAME + "-AM";
44 final String parentMarkerName = PARENT_MARKER_NAME + "-AM";
45 final org.slf4j.Marker slf4jMarker = org.slf4j.MarkerFactory.getMarker(childMakerName);
46 final org.slf4j.Marker slf4jParent = org.slf4j.MarkerFactory.getMarker(parentMarkerName);
47 slf4jMarker.add(slf4jParent);
48 final Marker log4jParent = MarkerManager.getMarker(parentMarkerName);
49 final Marker log4jMarker = MarkerManager.getMarker(childMakerName);
4750
48 assertTrue("Incorrect Marker class", slf4jMarker instanceof Log4jMarker);
49 assertTrue(String.format("%s (log4jMarker=%s) is not an instance of %s (log4jParent=%s) in Log4j",
50 CHILD_MAKER_NAME, PARENT_MARKER_NAME, log4jMarker, log4jParent), log4jMarker.isInstanceOf(log4jParent));
51 assertTrue(String.format("%s (slf4jMarker=%s) is not an instance of %s (log4jParent=%s) in SLF4J",
52 CHILD_MAKER_NAME, PARENT_MARKER_NAME, slf4jMarker, slf4jParent), slf4jMarker.contains(slf4jParent));
53 }
51 assertTrue("Incorrect Marker class", slf4jMarker instanceof Log4jMarker);
52 assertTrue(String.format("%s (log4jMarker=%s) is not an instance of %s (log4jParent=%s) in Log4j",
53 childMakerName, parentMarkerName, log4jMarker, log4jParent), log4jMarker.isInstanceOf(log4jParent));
54 assertTrue(String.format("%s (slf4jMarker=%s) is not an instance of %s (log4jParent=%s) in SLF4J",
55 childMakerName, parentMarkerName, slf4jMarker, slf4jParent), slf4jMarker.contains(slf4jParent));
56 }
57
58 @Test
59 public void testAddNullMarker() {
60 final String childMarkerName = CHILD_MAKER_NAME + "-ANM";
61 final String parentMakerName = PARENT_MARKER_NAME + "-ANM";
62 final org.slf4j.Marker slf4jMarker = org.slf4j.MarkerFactory.getMarker(childMarkerName);
63 final org.slf4j.Marker slf4jParent = org.slf4j.MarkerFactory.getMarker(parentMakerName);
64 slf4jMarker.add(slf4jParent);
65 final Marker log4jParent = MarkerManager.getMarker(parentMakerName);
66 final Marker log4jMarker = MarkerManager.getMarker(childMarkerName);
67 final Log4jMarker log4jSlf4jParent = new Log4jMarker(log4jParent);
68 final Log4jMarker log4jSlf4jMarker = new Log4jMarker(log4jMarker);
69 final org.slf4j.Marker nullMarker = null;
70 try {
71 log4jSlf4jParent.add(nullMarker);
72 fail("Expected " + IllegalArgumentException.class.getName());
73 } catch (final IllegalArgumentException e) {
74 // expected
75 }
76 try {
77 log4jSlf4jMarker.add(nullMarker);
78 fail("Expected " + IllegalArgumentException.class.getName());
79 } catch (final IllegalArgumentException e) {
80 // expected
81 }
82 }
83
84 @Test
85 public void testAddSameMarker() {
86 final String childMarkerName = CHILD_MAKER_NAME + "-ASM";
87 final String parentMakerName = PARENT_MARKER_NAME + "-ASM";
88 final org.slf4j.Marker slf4jMarker = org.slf4j.MarkerFactory.getMarker(childMarkerName);
89 final org.slf4j.Marker slf4jParent = org.slf4j.MarkerFactory.getMarker(parentMakerName);
90 slf4jMarker.add(slf4jParent);
91 slf4jMarker.add(slf4jParent);
92 final Marker log4jParent = MarkerManager.getMarker(parentMakerName);
93 final Marker log4jMarker = MarkerManager.getMarker(childMarkerName);
94 assertTrue(String.format("%s (log4jMarker=%s) is not an instance of %s (log4jParent=%s) in Log4j",
95 childMarkerName, parentMakerName, log4jMarker, log4jParent), log4jMarker.isInstanceOf(log4jParent));
96 assertTrue(String.format("%s (slf4jMarker=%s) is not an instance of %s (log4jParent=%s) in SLF4J",
97 childMarkerName, parentMakerName, slf4jMarker, slf4jParent), slf4jMarker.contains(slf4jParent));
98 }
99
100 @Test
101 public void testEquals() {
102 final String childMarkerName = CHILD_MAKER_NAME + "-ASM";
103 final String parentMakerName = PARENT_MARKER_NAME + "-ASM";
104 final org.slf4j.Marker slf4jMarker = org.slf4j.MarkerFactory.getMarker(childMarkerName);
105 final org.slf4j.Marker slf4jMarker2 = org.slf4j.MarkerFactory.getMarker(childMarkerName);
106 final org.slf4j.Marker slf4jParent = org.slf4j.MarkerFactory.getMarker(parentMakerName);
107 slf4jMarker.add(slf4jParent);
108 final Marker log4jParent = MarkerManager.getMarker(parentMakerName);
109 final Marker log4jMarker = MarkerManager.getMarker(childMarkerName);
110 final Marker log4jMarker2 = MarkerManager.getMarker(childMarkerName);
111 assertEquals(log4jParent, log4jParent);
112 assertEquals(log4jMarker, log4jMarker);
113 assertEquals(log4jMarker, log4jMarker2);
114 assertEquals(slf4jMarker, slf4jMarker2);
115 assertNotEquals(log4jParent, log4jMarker);
116 assertNotEquals(log4jMarker, log4jParent);
117 }
118
119 @Test
120 public void testContainsNullMarker() {
121 final String childMarkerName = CHILD_MAKER_NAME + "-CM";
122 final String parentMakerName = PARENT_MARKER_NAME + "-CM";
123 final org.slf4j.Marker slf4jMarker = org.slf4j.MarkerFactory.getMarker(childMarkerName);
124 final org.slf4j.Marker slf4jParent = org.slf4j.MarkerFactory.getMarker(parentMakerName);
125 slf4jMarker.add(slf4jParent);
126 final Marker log4jParent = MarkerManager.getMarker(parentMakerName);
127 final Marker log4jMarker = MarkerManager.getMarker(childMarkerName);
128 final Log4jMarker log4jSlf4jParent = new Log4jMarker(log4jParent);
129 final Log4jMarker log4jSlf4jMarker = new Log4jMarker(log4jMarker);
130 final org.slf4j.Marker nullMarker = null;
131 try {
132 Assert.assertFalse(log4jSlf4jParent.contains(nullMarker));
133 fail("Expected " + IllegalArgumentException.class.getName());
134 } catch (final IllegalArgumentException e) {
135 // expected
136 }
137 try {
138 Assert.assertFalse(log4jSlf4jMarker.contains(nullMarker));
139 fail("Expected " + IllegalArgumentException.class.getName());
140 } catch (final IllegalArgumentException e) {
141 // expected
142 }
143 }
144
145 @Test
146 public void testContainsNullString() {
147 final String childMarkerName = CHILD_MAKER_NAME + "-CS";
148 final String parentMakerName = PARENT_MARKER_NAME + "-CS";
149 final org.slf4j.Marker slf4jMarker = org.slf4j.MarkerFactory.getMarker(childMarkerName);
150 final org.slf4j.Marker slf4jParent = org.slf4j.MarkerFactory.getMarker(parentMakerName);
151 slf4jMarker.add(slf4jParent);
152 final Marker log4jParent = MarkerManager.getMarker(parentMakerName);
153 final Marker log4jMarker = MarkerManager.getMarker(childMarkerName);
154 final Log4jMarker log4jSlf4jParent = new Log4jMarker(log4jParent);
155 final Log4jMarker log4jSlf4jMarker = new Log4jMarker(log4jMarker);
156 final String nullStr = null;
157 Assert.assertFalse(log4jSlf4jParent.contains(nullStr));
158 Assert.assertFalse(log4jSlf4jMarker.contains(nullStr));
159 }
160
161 @Test
162 public void testRemoveNullMarker() {
163 final String childMakerName = CHILD_MAKER_NAME + "-CM";
164 final String parentMakerName = PARENT_MARKER_NAME + "-CM";
165 final org.slf4j.Marker slf4jMarker = org.slf4j.MarkerFactory.getMarker(childMakerName);
166 final org.slf4j.Marker slf4jParent = org.slf4j.MarkerFactory.getMarker(parentMakerName);
167 slf4jMarker.add(slf4jParent);
168 final Marker log4jParent = MarkerManager.getMarker(parentMakerName);
169 final Marker log4jMarker = MarkerManager.getMarker(childMakerName);
170 final Log4jMarker log4jSlf4jParent = new Log4jMarker(log4jParent);
171 final Log4jMarker log4jSlf4jMarker = new Log4jMarker(log4jMarker);
172 final org.slf4j.Marker nullMarker = null;
173 Assert.assertFalse(log4jSlf4jParent.remove(nullMarker));
174 Assert.assertFalse(log4jSlf4jMarker.remove(nullMarker));
175 }
54176
55177 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.slf4j;
17
18 import java.util.List;
19
20 import org.apache.logging.log4j.core.util.Constants;
21 import org.apache.logging.log4j.junit.InitialLoggerContext;
22 import org.apache.logging.log4j.test.appender.ListAppender;
23 import org.junit.Before;
24 import org.junit.ClassRule;
25 import org.junit.Test;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28 import org.slf4j.MDC;
29 import org.slf4j.Marker;
30 import org.slf4j.MarkerFactory;
31
32 import static org.junit.Assert.*;
33
34 /**
35 *
36 */
37 public class OptionalTest {
38
39 private static final String CONFIG = "log4j-test1.xml";
40
41 @ClassRule
42 public static final InitialLoggerContext CTX = new InitialLoggerContext(CONFIG);
43
44 Logger logger = LoggerFactory.getLogger("EventLogger");
45 Marker marker = MarkerFactory.getMarker("EVENT");
46
47 @Test
48 public void testEventLogger() {
49 logger.info(marker, "This is a test");
50 MDC.clear();
51 verify("EventLogger", "o.a.l.s.OptionalTest This is a test" + Constants.LINE_SEPARATOR);
52 }
53
54 private void verify(final String name, final String expected) {
55 final ListAppender listApp = CTX.getListAppender(name);
56 final List<String> events = listApp.getMessages();
57 assertTrue("Incorrect number of messages. Expected 1 Actual " + events.size(), events.size()== 1);
58 final String actual = events.get(0);
59 assertEquals("Incorrect message. Expected " + expected + ". Actual " + actual, expected, actual);
60 listApp.clear();
61 }
62
63 @Before
64 public void cleanup() {
65 CTX.getListAppender("List").clear();
66 CTX.getListAppender("EventLogger").clear();
67 }
68 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.slf4j;
17
18 import java.util.List;
19
20 import org.apache.logging.log4j.core.util.Constants;
21 import org.apache.logging.log4j.junit.LoggerContextRule;
22 import org.apache.logging.log4j.test.appender.ListAppender;
23 import org.junit.Before;
24 import org.junit.ClassRule;
25 import org.junit.Test;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28 import org.slf4j.MDC;
29 import org.slf4j.Marker;
30 import org.slf4j.MarkerFactory;
31
32 import static org.junit.Assert.*;
33
34 /**
35 *
36 */
37 public class OptionalTest {
38
39 private static final String CONFIG = "log4j-test1.xml";
40
41 @ClassRule
42 public static final LoggerContextRule CTX = new LoggerContextRule(CONFIG);
43
44 Logger logger = LoggerFactory.getLogger("EventLogger");
45 Marker marker = MarkerFactory.getMarker("EVENT");
46
47 @Test
48 public void testEventLogger() {
49 logger.info(marker, "This is a test");
50 MDC.clear();
51 verify("EventLogger", "o.a.l.s.OptionalTest This is a test" + Constants.LINE_SEPARATOR);
52 }
53
54 private void verify(final String name, final String expected) {
55 final ListAppender listApp = CTX.getListAppender(name);
56 final List<String> events = listApp.getMessages();
57 assertTrue("Incorrect number of messages. Expected 1 Actual " + events.size(), events.size()== 1);
58 final String actual = events.get(0);
59 assertEquals("Incorrect message. Expected " + expected + ". Actual " + actual, expected, actual);
60 listApp.clear();
61 }
62
63 @Before
64 public void cleanup() {
65 CTX.getListAppender("List").clear();
66 CTX.getListAppender("EventLogger").clear();
67 }
68 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.slf4j;
17
18 import java.io.Serializable;
19
20 import org.apache.logging.log4j.junit.InitialLoggerContext;
21 import org.junit.ClassRule;
22 import org.junit.Test;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26 import static org.apache.logging.log4j.SerializableMatchers.serializesRoundTrip;
27 import static org.junit.Assert.*;
28
29 /**
30 *
31 */
32 public class SerializeTest {
33
34
35 private static final String CONFIG = "log4j-test1.xml";
36
37 @ClassRule
38 public static final InitialLoggerContext CTX = new InitialLoggerContext(CONFIG);
39
40 Logger logger = LoggerFactory.getLogger("LoggerTest");
41
42 @Test
43 public void testLogger() throws Exception {
44 assertThat((Serializable) logger, serializesRoundTrip());
45 }
46 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.slf4j;
17
18 import java.io.Serializable;
19
20 import org.apache.logging.log4j.junit.LoggerContextRule;
21 import org.junit.ClassRule;
22 import org.junit.Test;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26 import static org.apache.logging.log4j.SerializableMatchers.serializesRoundTrip;
27 import static org.junit.Assert.*;
28
29 /**
30 *
31 */
32 public class SerializeTest {
33
34 private static final String CONFIG = "log4j-test1.xml";
35
36 @ClassRule
37 public static final LoggerContextRule CTX = new LoggerContextRule(CONFIG);
38
39 Logger logger = LoggerFactory.getLogger("LoggerTest");
40
41 @Test
42 public void testLogger() throws Exception {
43 assertThat((Serializable) logger, serializesRoundTrip());
44 }
45 }
1919 <parent>
2020 <groupId>org.apache.logging.log4j</groupId>
2121 <artifactId>log4j</artifactId>
22 <version>2.2</version>
22 <version>2.4</version>
2323 <relativePath>../</relativePath>
2424 </parent>
2525 <artifactId>log4j-taglib</artifactId>
4040 protected void init() {
4141 super.init();
4242 if (this.attributes == null) {
43 this.attributes = new ArrayList<Object>();
43 this.attributes = new ArrayList<>();
4444 } else {
4545 this.attributes.clear();
4646 }
3535 // These were change to WeakHashMaps to avoid ClassLoader (memory) leak, something that's particularly
3636 // important in Servlet containers.
3737 private static final WeakHashMap<ServletContext, Log4jTaglibLoggerContext> CONTEXTS =
38 new WeakHashMap<ServletContext, Log4jTaglibLoggerContext>();
38 new WeakHashMap<>();
3939
4040 private final WeakHashMap<String, Log4jTaglibLogger> loggers =
41 new WeakHashMap<String, Log4jTaglibLogger>();
41 new WeakHashMap<>();
4242
4343 private final ServletContext servletContext;
4444
4949 this.message = null;
5050 this.marker = null;
5151 if (this.attributes == null) {
52 this.attributes = new ArrayList<Object>();
52 this.attributes = new ArrayList<>();
5353 } else {
5454 this.attributes.clear();
5555 }
3737 final class TagUtils {
3838 private static final StatusLogger LOGGER = StatusLogger.getLogger();
3939
40 private static final Set<Object> WARNED_FOR = new HashSet<Object>();
40 private static final Set<Object> WARNED_FOR = new HashSet<>();
4141
4242 private static final String LOGGER_SCOPE_ATTRIBUTE = "org.apache.logging.log4j.taglib.LOGGER_SCOPE_ATTRIBUTE";
4343
3737
3838 <section name="Requirements">
3939 <p>
40 The Log4j Tag Library requires at least Java 6, at least Servlet 2.5 (or Java EE 5), and at least
41 JSP 2.1 (or Java EE 5).
40 The Log4j Tag Library requires at least Servlet 2.5 (or Java EE 5), at least
41 JSP 2.1 (or Java EE 5), and is dependent on the Log4j 2 API.
4242 </p>
4343 <p>
4444 <b><em>Important Note!</em></b> For performance reasons, containers often ignore certain JARs known not to
4646 @BeforeClass
4747 public static void setUpClass() {
4848 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
49 final LoggerContext context = (LoggerContext) LogManager.getContext(false);
49 final LoggerContext context = LoggerContext.getContext(false);
5050 context.getConfiguration();
5151 }
5252
5353 @AfterClass
5454 public static void cleanUpClass() {
5555 System.clearProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY);
56 final LoggerContext context = (LoggerContext) LogManager.getContext(false);
56 final LoggerContext context = LoggerContext.getContext(false);
5757 context.reconfigure();
5858 StatusLogger.getLogger().reset();
5959 }
9595 }
9696
9797 private void verify(final String expected) {
98 final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
98 final LoggerContext ctx = LoggerContext.getContext(false);
9999 final Appender listApp = ctx.getConfiguration().getAppender("List");
100100 assertNotNull("Missing Appender", listApp);
101101 assertTrue("Not a ListAppender", listApp instanceof ListAppender);
4242 @BeforeClass
4343 public static void setUpClass() {
4444 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
45 final LoggerContext context = (LoggerContext) LogManager.getContext(false);
45 final LoggerContext context = LoggerContext.getContext(false);
4646 context.getConfiguration();
4747 }
4848
4949 @AfterClass
5050 public static void cleanUpClass() {
5151 System.clearProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY);
52 final LoggerContext context = (LoggerContext) LogManager.getContext(false);
52 final LoggerContext context = LoggerContext.getContext(false);
5353 context.reconfigure();
5454 StatusLogger.getLogger().reset();
5555 }
8080 }
8181
8282 private void verify(final String expected) {
83 final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
83 final LoggerContext ctx = LoggerContext.getContext(false);
8484 final Appender listApp = ctx.getConfiguration().getAppender("List");
8585 assertNotNull("Missing Appender", listApp);
8686 assertTrue("Not a ListAppender", listApp instanceof ListAppender);
4242 @BeforeClass
4343 public static void setUpClass() {
4444 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
45 final LoggerContext context = (LoggerContext) LogManager.getContext(false);
45 final LoggerContext context = LoggerContext.getContext(false);
4646 context.getConfiguration();
4747 }
4848
4949 @AfterClass
5050 public static void cleanUpClass() {
5151 System.clearProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY);
52 final LoggerContext context = (LoggerContext) LogManager.getContext(false);
52 final LoggerContext context = LoggerContext.getContext(false);
5353 context.reconfigure();
5454 StatusLogger.getLogger().reset();
5555 }
8787 }
8888
8989 private void verify(final String expected) {
90 final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
90 final LoggerContext ctx = LoggerContext.getContext(false);
9191 final Appender listApp = ctx.getConfiguration().getAppender("List");
9292 assertNotNull("Missing Appender", listApp);
9393 assertTrue("Not a ListAppender", listApp instanceof ListAppender);
4141 @BeforeClass
4242 public static void setUpClass() {
4343 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
44 final LoggerContext context = (LoggerContext) LogManager.getContext(false);
44 final LoggerContext context = LoggerContext.getContext(false);
4545 context.getConfiguration();
4646 }
4747
4848 @AfterClass
4949 public static void cleanUpClass() {
5050 System.clearProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY);
51 final LoggerContext context = (LoggerContext) LogManager.getContext(false);
51 final LoggerContext context = LoggerContext.getContext(false);
5252 context.reconfigure();
5353 StatusLogger.getLogger().reset();
5454 }
2020 import java.util.concurrent.TimeUnit;
2121
2222 import javax.servlet.jsp.tagext.BodyTag;
23 import javax.servlet.jsp.tagext.Tag;
2324
2425 import org.apache.logging.log4j.Level;
2526 import org.apache.logging.log4j.LogManager;
4748 @BeforeClass
4849 public static void setUpClass() {
4950 System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, CONFIG);
50 final LoggerContext context = (LoggerContext) LogManager.getContext(false);
51 final LoggerContext context = LoggerContext.getContext(false);
5152 context.getConfiguration();
5253 }
5354
5455 @AfterClass
5556 public static void cleanUpClass() {
5657 System.clearProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY);
57 final LoggerContext context = (LoggerContext) LogManager.getContext(false);
58 final LoggerContext context = LoggerContext.getContext(false);
5859 context.reconfigure();
5960 StatusLogger.getLogger().reset();
6061 }
128129
129130 this.tag.setMessage("Hello message for testDoEndTagStringMessageNoMarkerNoException");
130131
131 assertEquals("The return value is not correct.", BodyTag.EVAL_PAGE, this.tag.doEndTag());
132 assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag());
132133 verify("Hello message for testDoEndTagStringMessageNoMarkerNoException WARN M- E");
133134 }
134135
139140 this.tag.setMarker(MarkerManager.getMarker("E01"));
140141 this.tag.setMessage("Goodbye message for testDoEndTagStringMessageMarkerNoException");
141142
142 assertEquals("The return value is not correct.", BodyTag.EVAL_PAGE, this.tag.doEndTag());
143 assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag());
143144 verify("Goodbye message for testDoEndTagStringMessageMarkerNoException INFO M-E01 E");
144145 }
145146
150151 this.tag.setException(new Exception("This is a test"));
151152 this.tag.setMessage("Another message for testDoEndTagStringMessageNoMarkerException");
152153
153 assertEquals("The return value is not correct.", BodyTag.EVAL_PAGE, this.tag.doEndTag());
154 assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag());
154155 verify("Another message for testDoEndTagStringMessageNoMarkerException ERROR M- E java.lang.Exception: This is a test");
155156 }
156157
162163 this.tag.setMarker(MarkerManager.getMarker("F02"));
163164 this.tag.setMessage("Final message for testDoEndTagStringMessageMarkerException");
164165
165 assertEquals("The return value is not correct.", BodyTag.EVAL_PAGE, this.tag.doEndTag());
166 assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag());
166167 verify("Final message for testDoEndTagStringMessageMarkerException TRACE M-F02 E java.lang.RuntimeException: This is another test");
167168 }
168169
174175 this.tag.setDynamicAttribute(null, null, TimeUnit.HOURS);
175176 this.tag.setMessage("Test message with [{}] parameter of [{}]");
176177
177 assertEquals("The return value is not correct.", BodyTag.EVAL_PAGE, this.tag.doEndTag());
178 assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag());
178179 verify("Test message with [A] parameter of [HOURS] FATAL M- E");
179180
180181 }
189190 this.tag.setDynamicAttribute(null, null, TimeUnit.SECONDS);
190191 this.tag.setMessage("Final message with [{}] parameter of [{}]");
191192
192 assertEquals("The return value is not correct.", BodyTag.EVAL_PAGE, this.tag.doEndTag());
193 assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag());
193194 verify("Final message with [Z] parameter of [SECONDS] DEBUG M-N03 E java.lang.Error: This is the last test");
194195
195196 }
202203 logger.getMessageFactory().newMessage("First message for testDoEndTagMessageNoMarkerNoException")
203204 );
204205
205 assertEquals("The return value is not correct.", BodyTag.EVAL_PAGE, this.tag.doEndTag());
206 assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag());
206207 verify("First message for testDoEndTagMessageNoMarkerNoException INFO M- E");
207208 }
208209
215216 logger.getMessageFactory().newMessage("Another message for testDoEndTagMessageMarkerNoException")
216217 );
217218
218 assertEquals("The return value is not correct.", BodyTag.EVAL_PAGE, this.tag.doEndTag());
219 assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag());
219220 verify("Another message for testDoEndTagMessageMarkerNoException WARN M-E01 E");
220221 }
221222
228229 logger.getMessageFactory().newMessage("Third message for testDoEndTagMessageNoMarkerException")
229230 );
230231
231 assertEquals("The return value is not correct.", BodyTag.EVAL_PAGE, this.tag.doEndTag());
232 assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag());
232233 verify("Third message for testDoEndTagMessageNoMarkerException TRACE M- E java.lang.Exception: This is a test");
233234 }
234235
242243 logger.getMessageFactory().newMessage("Final message for testDoEndTagMessageMarkerException")
243244 );
244245
245 assertEquals("The return value is not correct.", BodyTag.EVAL_PAGE, this.tag.doEndTag());
246 assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag());
246247 verify("Final message for testDoEndTagMessageMarkerException ERROR M-F02 E java.lang.RuntimeException: " +
247248 "This is another test");
248249 }
253254
254255 this.tag.setMessage(new MyMessage("First message for testDoEndTagObjectNoMarkerNoException"));
255256
256 assertEquals("The return value is not correct.", BodyTag.EVAL_PAGE, this.tag.doEndTag());
257 assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag());
257258 verify("First message for testDoEndTagObjectNoMarkerNoException INFO M- E");
258259 }
259260
264265 this.tag.setMarker(MarkerManager.getMarker("E01"));
265266 this.tag.setMessage(new MyMessage("Another message for testDoEndTagObjectMarkerNoException"));
266267
267 assertEquals("The return value is not correct.", BodyTag.EVAL_PAGE, this.tag.doEndTag());
268 assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag());
268269 verify("Another message for testDoEndTagObjectMarkerNoException WARN M-E01 E");
269270 }
270271
275276 this.tag.setException(new Exception("This is a test"));
276277 this.tag.setMessage(new MyMessage("Third message for testDoEndTagObjectNoMarkerException"));
277278
278 assertEquals("The return value is not correct.", BodyTag.EVAL_PAGE, this.tag.doEndTag());
279 assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag());
279280 verify("Third message for testDoEndTagObjectNoMarkerException TRACE M- E java.lang.Exception: This is a test");
280281 }
281282
287288 this.tag.setMarker(MarkerManager.getMarker("F02"));
288289 this.tag.setMessage(new MyMessage("Final message for testDoEndTagObjectMarkerException"));
289290
290 assertEquals("The return value is not correct.", BodyTag.EVAL_PAGE, this.tag.doEndTag());
291 assertEquals("The return value is not correct.", Tag.EVAL_PAGE, this.tag.doEndTag());
291292 verify("Final message for testDoEndTagObjectMarkerException ERROR M-F02 E java.lang.RuntimeException: " +
292293 "This is another test");
293294 }
294295
295296 @SuppressWarnings("unchecked")
296297 private void verify(final String expected) {
297 final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
298 final LoggerContext ctx = LoggerContext.getContext(false);
298299 final Appender listApp = ctx.getConfiguration().getAppender("List");
299300 assertNotNull("Missing Appender", listApp);
300301 assertTrue("Not a ListAppender", listApp instanceof ListAppender);
1919 <parent>
2020 <groupId>org.apache.logging.log4j</groupId>
2121 <artifactId>log4j</artifactId>
22 <version>2.2</version>
22 <version>2.4</version>
2323 <relativePath>../</relativePath>
2424 </parent>
2525 <artifactId>log4j-to-slf4j</artifactId>
2727 *
2828 */
2929 public class SLF4JLoggerContext implements LoggerContext {
30 private final ConcurrentMap<String, SLF4JLogger> loggers = new ConcurrentHashMap<String, SLF4JLogger>();
30 private final ConcurrentMap<String, SLF4JLogger> loggers = new ConcurrentHashMap<>();
3131
3232 @Override
3333 public Object getExternalContext() {
3535
3636 <section name="Requirements">
3737 <p>
38 The Log4j 2 to SLF4J adapter requires at least Java 6.
38 The Log4j 2 to SLF4J adapter is dependent on the Log4j 2 API and the SLF4J API.
3939 </p>
4040 </section>
4141
1919 <parent>
2020 <artifactId>log4j</artifactId>
2121 <groupId>org.apache.logging.log4j</groupId>
22 <version>2.2</version>
22 <version>2.4</version>
2323 </parent>
2424 <modelVersion>4.0.0</modelVersion>
2525
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.web;
17
18 import java.net.URI;
19 import java.net.URL;
20 import java.util.Map;
21 import java.util.concurrent.ConcurrentHashMap;
22 import javax.servlet.ServletContext;
23
24 import org.apache.logging.log4j.LogManager;
25 import org.apache.logging.log4j.Logger;
26 import org.apache.logging.log4j.core.AbstractLifeCycle;
27 import org.apache.logging.log4j.core.LoggerContext;
28 import org.apache.logging.log4j.core.config.Configurator;
29 import org.apache.logging.log4j.core.impl.ContextAnchor;
30 import org.apache.logging.log4j.core.impl.Log4jContextFactory;
31 import org.apache.logging.log4j.core.lookup.Interpolator;
32 import org.apache.logging.log4j.core.lookup.StrSubstitutor;
33 import org.apache.logging.log4j.core.selector.ContextSelector;
34 import org.apache.logging.log4j.core.selector.NamedContextSelector;
35 import org.apache.logging.log4j.core.util.FileUtils;
36 import org.apache.logging.log4j.core.util.Loader;
37 import org.apache.logging.log4j.core.util.NetUtils;
38 import org.apache.logging.log4j.core.util.SetUtils;
39 import org.apache.logging.log4j.spi.LoggerContextFactory;
40 import org.apache.logging.log4j.status.StatusLogger;
41
42 /**
43 * This class initializes and deinitializes Log4j no matter how the initialization occurs.
44 */
45 final class Log4jWebInitializerImpl extends AbstractLifeCycle implements Log4jWebLifeCycle {
46
47 private static final Logger LOGGER = StatusLogger.getLogger();
48
49 private static final long serialVersionUID = 1L;
50
51 static {
52 if (Loader.isClassAvailable("org.apache.logging.log4j.core.web.JNDIContextFilter")) {
53 throw new IllegalStateException("You are using Log4j 2 in a web application with the old, extinct " +
54 "log4j-web artifact. This is not supported and could cause serious runtime problems. Please" +
55 "remove the log4j-web JAR file from your application.");
56 }
57 }
58
59 private final Map<String, String> map = new ConcurrentHashMap<String, String>();
60 private final StrSubstitutor substitutor = new StrSubstitutor(new Interpolator(map));
61 private final ServletContext servletContext;
62
63 private String name;
64 private NamedContextSelector namedContextSelector;
65 private LoggerContext loggerContext;
66
67 private Log4jWebInitializerImpl(final ServletContext servletContext) {
68 this.servletContext = servletContext;
69 this.map.put("hostName", NetUtils.getLocalHostname());
70 }
71
72 /**
73 * Initializes the Log4jWebLifeCycle attribute of a ServletContext. Those who wish to obtain this object should
74 * use the {@link org.apache.logging.log4j.web.WebLoggerContextUtils#getWebLifeCycle(javax.servlet.ServletContext)}
75 * method instead.
76 *
77 * @param servletContext the ServletContext to initialize
78 * @return a new Log4jWebLifeCycle
79 * @since 2.0.1
80 */
81 protected static Log4jWebInitializerImpl initialize(final ServletContext servletContext) {
82 final Log4jWebInitializerImpl initializer = new Log4jWebInitializerImpl(servletContext);
83 servletContext.setAttribute(SUPPORT_ATTRIBUTE, initializer);
84 return initializer;
85 }
86
87 @Override
88 public synchronized void start() {
89 if (this.isStopped() || this.isStopping()) {
90 throw new IllegalStateException("Cannot start this Log4jWebInitializerImpl after it was stopped.");
91 }
92
93 // only do this once
94 if (this.isInitialized()) {
95 super.setStarting();
96
97 this.name = this.substitutor.replace(this.servletContext.getInitParameter(LOG4J_CONTEXT_NAME));
98 final String location =
99 this.substitutor.replace(this.servletContext.getInitParameter(LOG4J_CONFIG_LOCATION));
100 final boolean isJndi =
101 "true".equalsIgnoreCase(this.servletContext.getInitParameter(IS_LOG4J_CONTEXT_SELECTOR_NAMED));
102
103 if (isJndi) {
104 this.initializeJndi(location);
105 } else {
106 this.initializeNonJndi(location);
107 }
108
109 this.servletContext.setAttribute(CONTEXT_ATTRIBUTE, this.loggerContext);
110 super.setStarted();
111 }
112 }
113
114 private void initializeJndi(final String location) {
115 final URI configLocation = getConfigURI(location);
116
117 if (this.name == null) {
118 throw new IllegalStateException("A log4jContextName context parameter is required");
119 }
120
121 LoggerContext context;
122 final LoggerContextFactory factory = LogManager.getFactory();
123 if (factory instanceof Log4jContextFactory) {
124 final ContextSelector selector = ((Log4jContextFactory) factory).getSelector();
125 if (selector instanceof NamedContextSelector) {
126 this.namedContextSelector = (NamedContextSelector) selector;
127 context = this.namedContextSelector.locateContext(this.name, this.servletContext, configLocation);
128 ContextAnchor.THREAD_CONTEXT.set(context);
129 if (context.isInitialized()) {
130 context.start();
131 }
132 ContextAnchor.THREAD_CONTEXT.remove();
133 } else {
134 LOGGER.warn("Potential problem: Selector is not an instance of NamedContextSelector.");
135 return;
136 }
137 } else {
138 LOGGER.warn("Potential problem: LoggerContextFactory is not an instance of Log4jContextFactory.");
139 return;
140 }
141 this.loggerContext = context;
142 LOGGER.debug("Created logger context for [{}] using [{}].", this.name, context.getClass().getClassLoader());
143 }
144
145 private void initializeNonJndi(final String location) {
146 if (this.name == null) {
147 this.name = this.servletContext.getServletContextName();
148 }
149
150 if (this.name == null && location == null) {
151 LOGGER.error("No Log4j context configuration provided. This is very unusual.");
152 return;
153 }
154
155 final URI uri = getConfigURI(location);
156 this.loggerContext = Configurator.initialize(this.name, this.getClassLoader(), uri, this.servletContext);
157 }
158
159 private URI getConfigURI(final String location) {
160 try {
161 String configLocation = location;
162 if (configLocation == null) {
163 final String[] paths = SetUtils.prefixSet(servletContext.getResourcePaths("/WEB-INF/"), "/WEB-INF/log4j2");
164 if (paths.length == 1) {
165 configLocation = paths[0];
166 } else if (paths.length > 1) {
167 final String prefix = "/WEB-INF/log4j2-" + this.name + ".";
168 boolean found = false;
169 for (final String str : paths) {
170 if (str.startsWith(prefix)) {
171 configLocation = str;
172 found = true;
173 break;
174 }
175 }
176 if (!found) {
177 configLocation = paths[0];
178 }
179 }
180 }
181 if (configLocation != null) {
182 final URL url = servletContext.getResource(configLocation);
183 if (url != null) {
184 return url.toURI();
185 }
186 }
187 } catch (final Exception ex) {
188 // Just try passing the location.
189 }
190 if (location != null) {
191 try {
192 return FileUtils.getCorrectedFilePathUri(location);
193 } catch (final Exception e) {
194 LOGGER.error("Unable to convert configuration location [{}] to a URI", location, e);
195 }
196 }
197 return null;
198 }
199
200 @Override
201 public synchronized void stop() {
202 if (!this.isStarted() && !this.isStopped()) {
203 throw new IllegalStateException("Cannot stop this Log4jWebInitializer because it has not started.");
204 }
205
206 // only do this once
207 if (this.isStarted()) {
208 this.setStopping();
209 if (this.loggerContext != null) {
210 LOGGER.debug("Removing LoggerContext for [{}].", this.name);
211 this.servletContext.removeAttribute(CONTEXT_ATTRIBUTE);
212 if (this.namedContextSelector != null) {
213 this.namedContextSelector.removeContext(this.name);
214 }
215 this.loggerContext.stop();
216 this.loggerContext.setExternalContext(null);
217 this.loggerContext = null;
218 }
219 this.setStopped();
220 }
221 }
222
223 @Override
224 public void setLoggerContext() {
225 if (this.loggerContext != null) {
226 ContextAnchor.THREAD_CONTEXT.set(this.loggerContext);
227 }
228 }
229
230 @Override
231 public void clearLoggerContext() {
232 ContextAnchor.THREAD_CONTEXT.remove();
233 }
234
235 @Override
236 public void wrapExecution(final Runnable runnable) {
237 this.setLoggerContext();
238
239 try {
240 runnable.run();
241 } finally {
242 this.clearLoggerContext();
243 }
244 }
245
246 private ClassLoader getClassLoader() {
247 try {
248 // if container is Servlet 3.0, use its getClassLoader method
249 // this may look odd, but the call below will throw NoSuchMethodError if user is on Servlet 2.5
250 // we compile against 3.0 to support Log4jServletContainerInitializer, but we don't require 3.0
251 return this.servletContext.getClassLoader();
252 } catch (final Throwable ignore) {
253 // otherwise, use this class's class loader
254 return Log4jWebInitializerImpl.class.getClassLoader();
255 }
256 }
257
258 }
0 /*
1 * Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache license, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the license for the specific language governing permissions and
14 * limitations under the license.
15 */
16 package org.apache.logging.log4j.web;
17
18 import java.net.URI;
19 import java.net.URL;
20 import java.util.Arrays;
21 import java.util.Map;
22 import java.util.concurrent.ConcurrentHashMap;
23
24 import javax.servlet.ServletContext;
25
26 import org.apache.logging.log4j.LogManager;
27 import org.apache.logging.log4j.core.AbstractLifeCycle;
28 import org.apache.logging.log4j.core.LoggerContext;
29 import org.apache.logging.log4j.core.config.Configurator;
30 import org.apache.logging.log4j.core.impl.ContextAnchor;
31 import org.apache.logging.log4j.core.impl.Log4jContextFactory;
32 import org.apache.logging.log4j.core.lookup.Interpolator;
33 import org.apache.logging.log4j.core.lookup.StrSubstitutor;
34 import org.apache.logging.log4j.core.selector.ContextSelector;
35 import org.apache.logging.log4j.core.selector.NamedContextSelector;
36 import org.apache.logging.log4j.core.util.Loader;
37 import org.apache.logging.log4j.core.util.NetUtils;
38 import org.apache.logging.log4j.core.util.SetUtils;
39 import org.apache.logging.log4j.spi.LoggerContextFactory;
40
41 /**
42 * This class initializes and deinitializes Log4j no matter how the initialization occurs.
43 */
44 final class Log4jWebInitializerImpl extends AbstractLifeCycle implements Log4jWebLifeCycle {
45
46 private static final String WEB_INF = "/WEB-INF/";
47
48 private static final long serialVersionUID = 1L;
49
50 static {
51 if (Loader.isClassAvailable("org.apache.logging.log4j.core.web.JNDIContextFilter")) {
52 throw new IllegalStateException("You are using Log4j 2 in a web application with the old, extinct "
53 + "log4j-web artifact. This is not supported and could cause serious runtime problems. Please"
54 + "remove the log4j-web JAR file from your application.");
55 }
56 }
57
58 private final Map<String, String> map = new ConcurrentHashMap<>();
59 private final StrSubstitutor substitutor = new StrSubstitutor(new Interpolator(map));
60 private final ServletContext servletContext;
61
62 private String name;
63 private NamedContextSelector namedContextSelector;
64 private LoggerContext loggerContext;
65
66 private Log4jWebInitializerImpl(final ServletContext servletContext) {
67 this.servletContext = servletContext;
68 this.map.put("hostName", NetUtils.getLocalHostname());
69 }
70
71 /**
72 * Initializes the Log4jWebLifeCycle attribute of a ServletContext. Those who wish to obtain this object should use
73 * the {@link org.apache.logging.log4j.web.WebLoggerContextUtils#getWebLifeCycle(javax.servlet.ServletContext)}
74 * method instead.
75 *
76 * @param servletContext
77 * the ServletContext to initialize
78 * @return a new Log4jWebLifeCycle
79 * @since 2.0.1
80 */
81 protected static Log4jWebInitializerImpl initialize(final ServletContext servletContext) {
82 final Log4jWebInitializerImpl initializer = new Log4jWebInitializerImpl(servletContext);
83 servletContext.setAttribute(SUPPORT_ATTRIBUTE, initializer);
84 return initializer;
85 }
86
87 @Override
88 public synchronized void start() {
89 if (this.isStopped() || this.isStopping()) {
90 throw new IllegalStateException("Cannot start this Log4jWebInitializerImpl after it was stopped.");
91 }
92
93 // only do this once
94 if (this.isInitialized()) {
95 super.setStarting();
96
97 this.name = this.substitutor.replace(this.servletContext.getInitParameter(LOG4J_CONTEXT_NAME));
98 final String location = this.substitutor.replace(this.servletContext
99 .getInitParameter(LOG4J_CONFIG_LOCATION));
100 final boolean isJndi = "true".equalsIgnoreCase(this.servletContext
101 .getInitParameter(IS_LOG4J_CONTEXT_SELECTOR_NAMED));
102
103 if (isJndi) {
104 this.initializeJndi(location);
105 } else {
106 this.initializeNonJndi(location);
107 }
108
109 this.servletContext.setAttribute(CONTEXT_ATTRIBUTE, this.loggerContext);
110 super.setStarted();
111 }
112 }
113
114 private void initializeJndi(final String location) {
115 final URI configLocation = getConfigURI(location);
116
117 if (this.name == null) {
118 throw new IllegalStateException("A log4jContextName context parameter is required");
119 }
120
121 LoggerContext context;
122 final LoggerContextFactory factory = LogManager.getFactory();
123 if (factory instanceof Log4jContextFactory) {
124 final ContextSelector selector = ((Log4jContextFactory) factory).getSelector();
125 if (selector instanceof NamedContextSelector) {
126 this.namedContextSelector = (NamedContextSelector) selector;
127 context = this.namedContextSelector.locateContext(this.name, this.servletContext, configLocation);
128 ContextAnchor.THREAD_CONTEXT.set(context);
129 if (context.isInitialized()) {
130 context.start();
131 }
132 ContextAnchor.THREAD_CONTEXT.remove();
133 } else {
134 LOGGER.warn("Potential problem: Selector is not an instance of NamedContextSelector.");
135 return;
136 }
137 } else {
138 LOGGER.warn("Potential problem: LoggerContextFactory is not an instance of Log4jContextFactory.");
139 return;
140 }
141 this.loggerContext = context;
142 LOGGER.debug("Created logger context for [{}] using [{}].", this.name, context.getClass().getClassLoader());
143 }
144
145 private void initializeNonJndi(final String location) {
146 if (this.name == null) {
147 this.name = this.servletContext.getServletContextName();
148 LOGGER.debug("Using the servlet context name \"{}\".", this.name);
149 }
150
151 if (this.name == null && location == null) {
152 LOGGER.error("No Log4j context configuration provided. This is very unusual.");
153 return;
154 }
155
156 final URI uri = getConfigURI(location);
157 this.loggerContext = Configurator.initialize(this.name, this.getClassLoader(), uri, this.servletContext);
158 }
159
160 private URI getConfigURI(final String location) {
161 try {
162 String configLocation = location;
163 if (configLocation == null) {
164 final String[] paths = SetUtils.prefixSet(servletContext.getResourcePaths(WEB_INF), WEB_INF + "log4j2");
165 LOGGER.debug("getConfigURI found resource paths {} in servletConext at [{}]", Arrays.toString(paths), WEB_INF);
166 if (paths.length == 1) {
167 configLocation = paths[0];
168 } else if (paths.length > 1) {
169 final String prefix = WEB_INF + "log4j2-" + this.name + ".";
170 boolean found = false;
171 for (final String str : paths) {
172 if (str.startsWith(prefix)) {
173 configLocation = str;
174 found = true;
175 break;
176 }
177 }
178 if (!found) {
179 configLocation = paths[0];
180 }
181 }
182 }
183 if (configLocation != null) {
184 final URL url = servletContext.getResource(configLocation);
185 if (url != null) {
186 final URI uri = url.toURI();
187 LOGGER.debug("getConfigURI found resource [{}] in servletConext at [{}]", uri, configLocation);
188 return uri;
189 }
190 }
191 } catch (final Exception ex) {
192 // Just try passing the location.
193 }
194 if (location != null) {
195 try {
196 final URI correctedFilePathUri = NetUtils.toURI(location);
197 LOGGER.debug("getConfigURI found [{}] in servletConext at [{}]", correctedFilePathUri, location);
198 return correctedFilePathUri;
199 } catch (final Exception e) {
200 LOGGER.error("Unable to convert configuration location [{}] to a URI", location, e);
201 }
202 }
203 return null;
204 }
205
206 @Override
207 public synchronized void stop() {
208 if (!this.isStarted() && !this.isStopped()) {
209 throw new IllegalStateException("Cannot stop this Log4jWebInitializer because it has not started.");
210 }
211
212 // only do this once
213 if (this.isStarted()) {
214 this.setStopping();
215 if (this.loggerContext != null) {
216 LOGGER.debug("Removing LoggerContext for [{}].", this.name);
217 this.servletContext.removeAttribute(CONTEXT_ATTRIBUTE);
218 if (this.namedContextSelector != null) {
219 this.namedContextSelector.removeContext(this.name);
220 }
221 this.loggerContext.stop();
222 this.loggerContext.setExternalContext(null);
223 this.loggerContext = null;
224 }
225 this.setStopped();
226 }
227 }
228
229 @Override
230 public void setLoggerContext() {
231 if (this.loggerContext != null) {
232 ContextAnchor.THREAD_CONTEXT.set(this.loggerContext);
233 }
234 }
235
236 @Override
237 public void clearLoggerContext() {
238 ContextAnchor.THREAD_CONTEXT.remove();
239 }
240
241 @Override
242 public void wrapExecution(final Runnable runnable) {
243 this.setLoggerContext();
244
245 try {
246 runnable.run();
247 } finally {
248 this.clearLoggerContext();
249 }
250 }
251
252 private ClassLoader getClassLoader() {
253 try {
254 // if container is Servlet 3.0, use its getClassLoader method
255 // this may look odd, but the call below will throw NoSuchMethodError if user is on Servlet 2.5
256 // we compile against 3.0 to support Log4jServletContainerInitializer, but we don't require 3.0
257 return this.servletContext.getClassLoader();
258 } catch (final Throwable ignore) {
259 // otherwise, use this class's class loader
260 return Log4jWebInitializerImpl.class.getClassLoader();
261 }
262 }
263
264 }
2222 import org.apache.logging.log4j.core.LogEvent;
2323 import org.apache.logging.log4j.core.config.plugins.Plugin;
2424 import org.apache.logging.log4j.core.lookup.AbstractLookup;
25 import org.apache.logging.log4j.util.Strings;
2526
2627 @Plugin(name = "web", category = "Lookup")
2728 public class WebLookup extends AbstractLookup {
101102 return ctx.getInitParameter(key);
102103 }
103104
104 ctx.log(getClass().getName() + " unable to resolve key '" + key + '\'');
105 ctx.log(getClass().getName() + " unable to resolve key " + Strings.quote(key));
105106 return null;
106107 }
107108 }
0 org.apache.logging.log4j.web.Log4jServletContainerInitializer
1 #
2 # See https://issues.apache.org/jira/browse/LOG4J2-890
3 # See https://issues.jboss.org/browse/WFLY-4458
4 #
5
06 #
17 # Licensed to the Apache Software Foundation (ASF) under one or more
28 # contributor license agreements. See the NOTICE file distributed with
1319 # See the license for the specific language governing permissions and
1420 # limitations under the license.
1521 #
16 org.apache.logging.log4j.web.Log4jServletContainerInitializer
5050
5151 <section name="Requirements">
5252 <p>
53 The Web module requires at least Java 6 and Servlet 2.5.
53 The Web module requires Servlet 2.5 and is dependent on the Log4j 2 API and implementation.
5454 </p>
5555 </section>
5656
2424
2525 import org.apache.logging.log4j.util.Strings;
2626 import org.easymock.Capture;
27 import org.easymock.EasyMock;
2728 import org.junit.After;
2829 import org.junit.Before;
2930 import org.junit.Test;
103104 public void testOnStartupWithServletVersion3_xEffectiveVersion3_x() throws Exception {
104105 final FilterRegistration.Dynamic registration = createStrictMock(FilterRegistration.Dynamic.class);
105106
106 final Capture<EventListener> listenerCapture = new Capture<EventListener>();
107 final Capture<Class<? extends Filter>> filterCapture = new Capture<Class<? extends Filter>>();
107 final Capture<EventListener> listenerCapture = EasyMock.newCapture();
108 final Capture<Class<? extends Filter>> filterCapture = EasyMock.newCapture();
108109
109110 expect(this.servletContext.getMajorVersion()).andReturn(3);
110111 expect(this.servletContext.getEffectiveMajorVersion()).andReturn(3);
139140
140141 @Test
141142 public void testOnStartupCanceledDueToPreExistingFilter() throws Exception {
142 final Capture<Class<? extends Filter>> filterCapture = new Capture<Class<? extends Filter>>();
143 final Capture<Class<? extends Filter>> filterCapture = EasyMock.newCapture();
143144
144145 expect(this.servletContext.getMajorVersion()).andReturn(3);
145146 expect(this.servletContext.getEffectiveMajorVersion()).andReturn(3);
159160 public void testOnStartupFailedDueToInitializerFailure() throws Exception {
160161 final FilterRegistration.Dynamic registration = createStrictMock(FilterRegistration.Dynamic.class);
161162
162 final Capture<Class<? extends Filter>> filterCapture = new Capture<Class<? extends Filter>>();
163 final Capture<Class<? extends Filter>> filterCapture = EasyMock.newCapture();
163164 final IllegalStateException exception = new IllegalStateException(Strings.EMPTY);
164165
165166 expect(this.servletContext.getMajorVersion()).andReturn(3);
2020 import org.apache.logging.log4j.core.LoggerContext;
2121 import org.apache.logging.log4j.core.impl.ContextAnchor;
2222 import org.easymock.Capture;
23 import org.easymock.EasyMock;
2324 import org.easymock.IAnswer;
2425 import org.junit.After;
2526 import org.junit.Before;
4243
4344 @Before
4445 public void setUp() {
45 final Capture<Log4jWebLifeCycle> initializerCapture = new Capture<Log4jWebLifeCycle>();
46 final Capture<Log4jWebLifeCycle> initializerCapture = EasyMock.newCapture();
4647
4748 this.servletContext = createStrictMock(ServletContext.class);
4849 expect(this.servletContext.getAttribute(Log4jWebSupport.SUPPORT_ATTRIBUTE)).andReturn(null);
103104
104105 @Test
105106 public void testInitializeWithNoParametersThenSetLoggerContextThenDeinitialize() throws Exception {
106 final Capture<Object> loggerContextCapture = new Capture<Object>();
107 final Capture<Object> loggerContextCapture = EasyMock.newCapture();
107108
108109 expect(this.servletContext.getInitParameter(Log4jWebSupport.LOG4J_CONTEXT_NAME)).andReturn(null);
109110 expect(this.servletContext.getInitParameter(Log4jWebSupport.LOG4J_CONFIG_LOCATION)).andReturn(null);
165166
166167 @Test
167168 public void testInitializeWithClassLoaderNoParametersThenSetLoggerContextThenDeinitialize() throws Exception {
168 final Capture<Object> loggerContextCapture = new Capture<Object>();
169 final Capture<Object> loggerContextCapture = EasyMock.newCapture();
169170
170171 expect(this.servletContext.getInitParameter(Log4jWebSupport.LOG4J_CONTEXT_NAME)).andReturn(null);
171172 expect(this.servletContext.getInitParameter(Log4jWebSupport.LOG4J_CONFIG_LOCATION)).andReturn(null);
228229
229230 @Test
230231 public void testInitializeIsIdempotent() throws Exception {
231 final Capture<Object> loggerContextCapture = new Capture<Object>();
232 final Capture<Object> loggerContextCapture = EasyMock.newCapture();
232233
233234 expect(this.servletContext.getInitParameter(Log4jWebSupport.LOG4J_CONTEXT_NAME)).andReturn(null);
234235 expect(this.servletContext.getInitParameter(Log4jWebSupport.LOG4J_CONFIG_LOCATION)).andReturn(null);
271272
272273 @Test
273274 public void testInitializeFailsAfterDeinitialize() throws Exception {
274 final Capture<Object> loggerContextCapture = new Capture<Object>();
275 final Capture<Object> loggerContextCapture = EasyMock.newCapture();
275276
276277 expect(this.servletContext.getInitParameter(Log4jWebSupport.LOG4J_CONTEXT_NAME)).andReturn(null);
277278 expect(this.servletContext.getInitParameter(Log4jWebSupport.LOG4J_CONFIG_LOCATION)).andReturn(null);
313314
314315 @Test
315316 public void testDeinitializeIsIdempotent() throws Exception {
316 final Capture<Object> loggerContextCapture = new Capture<Object>();
317 final Capture<Object> loggerContextCapture = EasyMock.newCapture();
317318
318319 expect(this.servletContext.getInitParameter(Log4jWebSupport.LOG4J_CONTEXT_NAME)).andReturn(null);
319320 expect(this.servletContext.getInitParameter(Log4jWebSupport.LOG4J_CONFIG_LOCATION)).andReturn(null);
369370
370371 @Test
371372 public void testInitializeUsingJndiSelector() throws Exception {
372 final Capture<Object> loggerContextCapture = new Capture<Object>();
373 final Capture<Object> loggerContextCapture = EasyMock.newCapture();
373374
374375 expect(this.servletContext.getInitParameter(Log4jWebSupport.LOG4J_CONTEXT_NAME)).andReturn("helloWorld6");
375376 expect(this.servletContext.getInitParameter(Log4jWebSupport.LOG4J_CONFIG_LOCATION)).andReturn(null);
420421
421422 @Test
422423 public void testWrapExecutionWithNoParameters() throws Exception {
423 final Capture<Object> loggerContextCapture = new Capture<Object>();
424 final Capture<Object> loggerContextCapture = EasyMock.newCapture();
424425
425426 expect(this.servletContext.getInitParameter(Log4jWebSupport.LOG4J_CONTEXT_NAME)).andReturn(null);
426427 expect(this.servletContext.getInitParameter(Log4jWebSupport.LOG4J_CONFIG_LOCATION)).andReturn(null);
2121 <artifactId>log4j</artifactId>
2222 <packaging>pom</packaging>
2323 <name>Apache Log4j 2</name>
24 <version>2.2</version>
24 <version>2.4</version>
2525 <parent>
2626 <groupId>org.apache</groupId>
2727 <artifactId>apache</artifactId>
5757 <roles>
5858 <role>PMC Member</role>
5959 </roles>
60 <timezone>America/New_York</timezone>
60 <timezone>America/Los_Angeles</timezone>
6161 </developer>
6262 <developer>
6363 <id>sdeboy</id>
108108 </roles>
109109 <timezone>America/Detroit</timezone>
110110 </developer>
111 <developer>
112 <id>mikes</id>
113 <name>Mikael Ståldal</name>
114 <email>mikes@apache.org</email>
115 <organization>Magine TV</organization>
116 <roles>
117 <role>Committer</role>
118 </roles>
119 <timezone>Europe/Stockholm</timezone>
120 </developer>
111121 </developers>
112122 <mailingLists>
113123 <mailingList>
144154 <connection>scm:git:http://git-wip-us.apache.org/repos/asf/logging-log4j2.git</connection>
145155 <developerConnection>scm:git:https://git-wip-us.apache.org/repos/asf/logging-log4j2.git</developerConnection>
146156 <url>https://git-wip-us.apache.org/repos/asf?p=logging-log4j2.git;a=summary</url>
147 <tag>log4j-2.2</tag>
157 <tag>log4j-2.4</tag>
148158 </scm>
149159 <organization>
150160 <name>Apache Software Foundation</name>
153163 <properties>
154164 <!-- make sure to update these for each release! -->
155165 <log4jParentDir>${basedir}</log4jParentDir>
156 <Log4jReleaseVersion>2.2</Log4jReleaseVersion>
157 <Log4jReleaseCount>eighteenth</Log4jReleaseCount>
166 <Log4jReleaseVersion>2.4</Log4jReleaseVersion>
167 <Log4jReleaseCount>eighth</Log4jReleaseCount>
158168 <Log4jReleaseManager>Ralph Goers</Log4jReleaseManager>
159169 <Log4jReleaseKey>B3D8E1BA</Log4jReleaseKey>
160170 <!-- <Log4jReleaseManager>Matt Sicker</Log4jReleaseManager>
161171 <Log4jReleaseKey>FA1C814D</Log4jReleaseKey> -->
162172 <!-- note that any properties you want available in velocity templates must not use periods! -->
163 <slf4jVersion>1.7.7</slf4jVersion>
164 <logbackVersion>1.1.2</logbackVersion>
173 <slf4jVersion>1.7.12</slf4jVersion>
174 <logbackVersion>1.1.3</logbackVersion>
165175 <jackson1Version>1.9.13</jackson1Version>
166 <jackson2Version>2.5.1</jackson2Version>
167 <springVersion>3.2.11.RELEASE</springVersion>
168 <flumeVersion>1.5.2</flumeVersion>
169 <disruptorVersion>3.3.0</disruptorVersion>
170 <compiler.plugin.version>3.2</compiler.plugin.version>
171 <pmd.plugin.version>3.3</pmd.plugin.version>
172 <findbugs.plugin.version>2.5.5</findbugs.plugin.version>
176 <jackson2Version>2.6.1</jackson2Version>
177 <springVersion>3.2.13.RELEASE</springVersion>
178 <flumeVersion>1.6.0</flumeVersion>
179 <disruptorVersion>3.3.2</disruptorVersion>
180 <compiler.plugin.version>3.3</compiler.plugin.version>
181 <pmd.plugin.version>3.5</pmd.plugin.version>
182 <findbugs.plugin.version>3.0.1</findbugs.plugin.version>
173183 <changes.plugin.version>2.11</changes.plugin.version>
174 <javadoc.plugin.version>2.10.1</javadoc.plugin.version>
184 <javadoc.plugin.version>2.10.3</javadoc.plugin.version>
175185 <!-- surefire.plugin.version 2.18 yields http://jira.codehaus.org/browse/SUREFIRE-1121, which is fixed in 2.18.1 -->
176 <surefire.plugin.version>2.17</surefire.plugin.version>
177 <failsafe.plugin.version>2.17</failsafe.plugin.version>
178 <checkstyle.plugin.version>2.13</checkstyle.plugin.version>
186 <surefire.plugin.version>2.18.1</surefire.plugin.version>
187 <failsafe.plugin.version>2.18.1</failsafe.plugin.version>
188 <checkstyle.plugin.version>2.16</checkstyle.plugin.version>
179189 <rat.plugin.version>0.11</rat.plugin.version>
180190 <pdf.plugin.version>1.2</pdf.plugin.version>
181 <cobertura.plugin.version>2.6</cobertura.plugin.version>
182 <release.plugin.version>2.5.1</release.plugin.version>
183 <scm.plugin.version>1.9.1</scm.plugin.version>
191 <cobertura.plugin.version>2.7</cobertura.plugin.version>
192 <release.plugin.version>2.5.2</release.plugin.version>
193 <scm.plugin.version>1.9.4</scm.plugin.version>
184194 <jxr.plugin.version>2.5</jxr.plugin.version>
185195 <clirr.plugin.version>2.6.1</clirr.plugin.version>
196 <site.plugin.version>3.4</site.plugin.version>
186197 <manifestfile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestfile>
187 <maven.compile.source>1.6</maven.compile.source>
188 <maven.compile.target>1.6</maven.compile.target>
198 <maven.compile.source>1.7</maven.compile.source>
199 <maven.compile.target>1.7</maven.compile.target>
189200 <docLabel>Site Documentation</docLabel>
190201 <projectDir />
191202 <commonsLoggingVersion>1.2</commonsLoggingVersion>
192203 <osgi.api.version>4.3.1</osgi.api.version>
193 <activemq.version>5.10.0</activemq.version>
204 <activemq.version>5.11.1</activemq.version>
194205 <!-- Allow Clirr severity to be overriden by the command-line option -DminSeverity=level -->
195206 <minSeverity>info</minSeverity>
196207 </properties>
241252 <dependency>
242253 <groupId>org.apache.felix</groupId>
243254 <artifactId>org.apache.felix.framework</artifactId>
244 <version>4.6.0</version>
255 <version>4.6.1</version>
245256 </dependency>
246257 <dependency>
247258 <groupId>org.apache.maven</groupId>
256267 <dependency>
257268 <groupId>org.apache.commons</groupId>
258269 <artifactId>commons-lang3</artifactId>
259 <version>3.3.2</version>
270 <version>3.4</version>
260271 </dependency>
261272 <dependency>
262273 <groupId>ch.qos.logback</groupId>
532543 <dependency>
533544 <groupId>com.sun.mail</groupId>
534545 <artifactId>javax.mail</artifactId>
535 <version>1.5.2</version>
546 <version>1.5.4</version>
536547 </dependency>
537548 <dependency>
538549 <groupId>org.jboss.spec.javax.jms</groupId>
557568 </exclusion>
558569 </exclusions>
559570 </dependency>
560 <dependency>
571 <dependency>
572 <groupId>org.apache.kafka</groupId>
573 <artifactId>kafka-clients</artifactId>
574 <version>0.8.2.1</version>
575 </dependency>
576 <dependency>
577 <groupId>org.zeromq</groupId>
578 <artifactId>jeromq</artifactId>
579 <version>0.3.5</version>
580 </dependency>
581 <dependency>
561582 <groupId>javax.servlet</groupId>
562583 <artifactId>servlet-api</artifactId>
563584 <version>2.5</version>
583604 <dependency>
584605 <groupId>org.easymock</groupId>
585606 <artifactId>easymock</artifactId>
586 <version>3.2</version>
607 <version>3.3.1</version>
587608 <scope>test</scope>
588609 </dependency>
589610 <dependency>
634655 <dependency>
635656 <groupId>org.hsqldb</groupId>
636657 <artifactId>hsqldb</artifactId>
637 <version>2.3.2</version>
658 <version>2.3.3</version>
638659 </dependency>
639660 <dependency>
640661 <groupId>com.h2database</groupId>
641662 <artifactId>h2</artifactId>
642 <version>1.3.175</version>
663 <version>1.3.176</version>
643664 </dependency>
644665 <dependency>
645666 <groupId>org.eclipse.persistence</groupId>
646667 <artifactId>org.eclipse.persistence.jpa</artifactId>
647 <version>2.5.2</version>
668 <version>2.6.0</version>
648669 </dependency>
649670 <dependency>
650671 <groupId>org.eclipse.persistence</groupId>
655676 <dependency>
656677 <groupId>org.mongodb</groupId>
657678 <artifactId>mongo-java-driver</artifactId>
658 <version>2.11.2</version>
679 <version>2.13.2</version>
659680 </dependency>
660681 <dependency>
661682 <groupId>org.lightcouch</groupId>
663684 <version>0.0.6</version>
664685 </dependency>
665686 <dependency>
687 <groupId>org.liquibase</groupId>
688 <artifactId>liquibase-core</artifactId>
689 <version>3.3.5</version>
690 </dependency>
691 <dependency>
666692 <groupId>net.javacrumbs.json-unit</groupId>
667693 <artifactId>json-unit</artifactId>
668 <version>1.1.6</version>
694 <version>1.5.5</version>
669695 <scope>test</scope>
670696 </dependency>
671697 <dependency>
673699 <artifactId>commons-io</artifactId>
674700 <version>2.4</version>
675701 <scope>test</scope>
702 </dependency>
703 <!-- Used for compressing to formats other than zip and gz -->
704 <dependency>
705 <groupId>org.apache.commons</groupId>
706 <artifactId>commons-compress</artifactId>
707 <version>1.10</version>
708 </dependency>
709 <!-- Used for the CSV layout -->
710 <dependency>
711 <groupId>org.apache.commons</groupId>
712 <artifactId>commons-csv</artifactId>
713 <version>1.2</version>
676714 </dependency>
677715 </dependencies>
678716 </dependencyManagement>
682720 <plugin>
683721 <groupId>org.apache.felix</groupId>
684722 <artifactId>maven-bundle-plugin</artifactId>
723 <!-- Using version 2.5.4 causes Jenkins to get compiler errors in log4j-perf. -->
685724 <version>2.5.3</version>
686725 <inherited>true</inherited>
687726 <extensions>true</extensions>
762801 <plugin>
763802 <groupId>org.apache.maven.plugins</groupId>
764803 <artifactId>maven-source-plugin</artifactId>
765 <version>2.3</version>
804 <version>2.4</version>
766805 <executions>
767806 <execution>
768807 <id>attach-sources</id>
831870 </plugin>
832871 <plugin>
833872 <artifactId>maven-resources-plugin</artifactId>
834 <version>2.6</version>
873 <version>2.7</version>
835874 <executions>
836875 <execution>
837876 <id>copy-sitecss</id>
902941 <plugin>
903942 <groupId>org.apache.maven.plugins</groupId>
904943 <artifactId>maven-site-plugin</artifactId>
905 <!-- Do not upgrade to versions 3.1, 3.2 or 3.3. 3.2 & 3.3 cause a NullPointerException in site:stage-deploy
906 and the site is broken in all of them. See http://jira.codehaus.org/browse/MSITE-695 -->
907 <version>3.0</version>
944 <version>${site.plugin.version}</version>
908945 <dependencies>
909946 <dependency>
910947 <groupId>org.apache.maven.wagon</groupId>
911948 <artifactId>wagon-ssh</artifactId>
912 <version>2.8</version>
949 <version>2.9</version>
913950 </dependency>
914951 </dependencies>
915952 <configuration>
9961033 <exclude>src/site/resources/js/jquery.min.js</exclude>
9971034 <!-- Generated files -->
9981035 <exclude>log4j-distribution/target/**/*</exclude>
1036 <exclude>velocity.log</exclude>
9991037 <!-- Other -->
10001038 <exclude>felix-cache/**</exclude>
10011039 </excludes>
10271065 <plugin>
10281066 <groupId>org.apache.maven.plugins</groupId>
10291067 <artifactId>maven-project-info-reports-plugin</artifactId>
1030 <version>2.7</version>
1068 <version>2.8</version>
10311069 <reportSets>
10321070 <reportSet>
10331071 <reports>
10471085 </reportSets>
10481086 <configuration>
10491087 <!-- you'd think these would be the defaults, right? -->
1088 <customBundle>${project.basedir}/src/site/custom/project-info-report.properties</customBundle>
10501089 <webAccessUrl>${project.scm.url}</webAccessUrl>
10511090 <anonymousConnection>${project.scm.connection}</anonymousConnection>
10521091 <developerConnection>${project.scm.developerConnection}</developerConnection>
11261165 <module>log4j-perf</module>
11271166 <module>log4j-iostreams</module>
11281167 <module>log4j-jul</module>
1168 <module>log4j-liquibase</module>
11291169 </modules>
11301170 <profiles>
11311171 <profile>
13341374 </plugins>
13351375 </build>
13361376 </profile>
1337 <profile>
1338 <id>jdk7</id>
1339 <activation>
1340 <jdk>[1.7,)</jdk>
1341 </activation>
1342 <properties>
1343 <findbugs.plugin.version>3.0.0</findbugs.plugin.version>
1344 </properties>
1345 </profile>
13461377 </profiles>
13471378 </project>
2525 many other modern features such as support for Markers, property substitution using Lookups, and asynchronous
2626 Loggers. In addition, Log4j 2 will not lose events while reconfiguring.
2727
28 This is the fifth GA release. It contains several bugfixes and new features.
28 This is the ${relCount} GA release. It contains several bugfixes and new features. As of this release
29 Log4j now requires a minimum of Java 7.
2930
3031 ## Hack to improve layout: replace all pairs of spaces with a single new-line
3132 $release.description.replaceAll(" ", "
130131 ## End of main loop
131132 #end
132133
133 Apache Log4j ${relVersion} requires a minimum of Java 6 to build and run. Future releases may require a minimum
134 of Java 7.
134 Apache Log4j ${relVersion} requires a minimum of Java 7 to build and run. Log4j 2.4 and greater requires Java 7,
135 version 2.3 required Java 6.
135136
136137 Basic compatibility with Log4j 1.x is provided through the log4j-1.2-api component, however it does not implement some of the
137138 very implementation specific classes and methods. The package names and Maven groupId have been changed to
2222 <title>Changes</title>
2323 </properties>
2424 <body>
25 <release version="2.4" date="2015-09-20" description="GA Release 2.4">
26 <action issue="LOG4J2-635" dev="rgoers" type="add">
27 Add support for configuration via Properties.
28 </action>
29 <action issue="LOG4J2-952" dev="rgoers" type="add">
30 Add ConfigurationBuilder.
31 </action>
32 <action issue="LOG4J2-1017" dev="ggregory" type="update">
33 Update Java platform from Java 6 to 7. From this version onwards, log4j 2 requires Java 7.
34 </action>
35 <action issue="LOG4J2-599" dev="rpopma" type="add">
36 Added support for Java 8 lambda expressions to lazily construct a log message only if
37 the requested log level is enabled.
38 </action>
39 <action issue="LOG4J2-1118" dev="rpopma" type="add">
40 Updated Logger wrapper generator tool to add Java 8 lambda support for custom log levels.
41 </action>
42 <action issue="LOG4J2-1107" dev="ggregory" type="add" due-to="Mikael Ståldal">
43 New Appender for Apache Kafka.
44 </action>
45 <action issue="LOG4J2-1113" dev="ggregory" type="add" due-to="Gary Gregory">
46 New publisher Appender for ZeroMQ (using JeroMQ).
47 </action>
48 <action issue="LOG4J2-1088" dev="ggregory" type="add" due-to="Gary Gregory">
49 Add Comma Separated Value (CSV) layouts for parameter and event logging.
50 </action>
51 <action issue="LOG4J2-812" dev="rgoers" type="update">
52 PatternLayout timestamp formatting performance improvement: replaced synchronized SimpleDateFormat with
53 Apache Commons FastDateFormat. This and better caching resulted in a ~3-30X faster timestamp formatting.
54 </action>
55 <action issue="LOG4J2-1097" dev="rpopma" type="update">
56 PatternLayout timestamp formatting performance improvement: predefined date formats (and variants using
57 a period '.' millisecond separator instead of ',') are now formatted ~2-10X faster than other date formats.
58 </action>
59 <action issue="LOG4J2-1096" dev="rpopma" type="update">
60 Improved performance of ParameterizedMessage::getFormattedMessage by ~2X.
61 </action>
62 <action issue="LOG4J2-1120" dev="rpopma" type="update">
63 LoggerConfig performance improvements: avoid unnecessary lock acquisition, use more efficient data structure.
64 </action>
65 <action issue="LOG4J2-1125" dev="rpopma" type="update">
66 PatternLayout performance improvement by caching and reusing a ThreadLocal StringBuilder.
67 </action>
68 <action issue="LOG4J2-1121" dev="rpopma" type="fix">
69 Fixed potential race condition on reconfiguration. Introduced ReliabilityStrategy to facilitate
70 switching between different mechanisms for preventing log events from being dropped on reconfiguration.
71 </action>
72 <action issue="LOG4J2-1114" dev="ggregory" type="update">
73 Add thread name to status logger layout.
74 </action>
75 <action issue="LOG4J2-1123" dev="ggregory" type="fix" due-to="Gary Gregory">
76 Core Configurator.initialize(String, ClassLoader, String) fails to work when config location is a file path.
77 </action>
78 <action issue="LOG4J2-1117" dev="ggregory" type="fix" due-to="Marcus Thiesen">
79 OutputStreamManager in ConsoleAppender leaking managers.
80 </action>
81 <action issue="LOG4J2-1044" dev="rgoers" type="fix">
82 Write pending events to Flume when the appender is stopped.
83 </action>
84 <action issue="LOG4J2-1108" dev="ggregory" type="fix" due-to="Mikael Ståldal">
85 NullPointerException when passing null to java.util.logging.Logger.setLevel().
86 </action>
87 <action issue="LOG4J2-1110" dev="ggregory" type="fix">
88 org.apache.logging.log4j.jul.CoreLogger.setLevel() checks for security permission too late.
89 </action>
90 <action dev="rpopma" type="remove">
91 Removed experimental interface LevelLogger which got committed to master by mistake.
92 </action>
93 <action issue="LOG4J2-1010" dev="rgoers" type="update">
94 Pass log event when interpolating logger properties.
95 </action>
96 <action issue="LOG4J2-1090" dev="ggregory" type="add">
97 Add Core Configurator APIs to change a logger's level.
98 </action>
99 <action issue="LOG4J2-1105" dev="ggregory" type="add" due-to="Gary Gregory">
100 Add API org.apache.logging.log4j.Level.isInRange(Level, Level).
101 </action>
102 <action issue="LOG4J2-1106" dev="ggregory" type="add" due-to="Gary Gregory">
103 Add a LevelRangeFilter class.
104 </action>
105 <action issue="LOG4J2-1076" dev="rpopma" type="add">
106 Added support for system nanosecond time in pattern layout.
107 </action>
108 <action issue="LOG4J2-1075" dev="rpopma" type="add">
109 Added support for compressing to bzip2 format on file rollover.
110 </action>
111 <action issue="LOG4J2-1077" dev="ggregory" type="add">
112 Support additional Apache Commons Compress compression formats on rollover: Deflate, Pack200, XY.
113 </action>
114 <action issue="LOG4J2-767" dev="ggregory" type="add" due-to="Mikael Ståldal">
115 New module for Liquibase integration.
116 </action>
117 <action issue="LOG4J2-1023" dev="ggregory" type="add" due-to="Mikael Ståldal">
118 New RewritePolicy for changing level of a log event.
119 </action>
120 <action issue="LOG4J2-1015" dev="ggregory" type="add" due-to="Daniel Marcotte">
121 Add a way to route messages based on the %marker in Layout for RoutingAppender.
122 </action>
123 <action issue="LOG4J2-1050" dev="ggregory" type="add" due-to="Adam Retter">
124 Add a Log4jLookup class to help write log files relative to log4j2.xml.
125 </action>
126 <action issue="LOG4J2-1057" dev="ggregory" type="add">
127 Add API org.apache.logging.log4j.LogManager.getFormatterLogger().
128 </action>
129 <action issue="LOG4J2-1066" dev="ggregory" type="add" due-to="Charles Allen">
130 Expose Log4jContextFactory's ShutdownCallbackRegistry.
131 </action>
132 <action issue="LOG4J2-1084" dev="ggregory" type="fix" due-to="Philipp Schneider">
133 Misleading StatusLogger WARN event in LogManager with java.util.Map.
134 </action>
135 <action issue="LOG4J2-1051" dev="ggregory" type="fix" due-to="Lukasz Lenart">
136 NoClassDefFoundError when starting app on Google App Engine.
137 </action>
138 <action issue="LOG4J2-684" dev="ggregory" type="fix" due-to="Joern Huxhorn, Mauro Molinari">
139 ExtendedThrowablePatternConverter does not print suppressed exceptions.
140 </action>
141 <action issue="LOG4J2-1069" dev="ggregory" type="fix" due-to="Sam Braam">
142 Improper handling of JSON escape chars when deserializing JSON log events.
143 </action>
144 <action issue="LOG4J2-1068" dev="ggregory" type="fix" due-to="Andy McMullan">
145 Exceptions not logged when using TcpSocketServer + SerializedLayout.
146 </action>
147 <action issue="LOG4J2-1067" dev="ggregory" type="fix" due-to="Sam Braam">
148 ThrowableProxy getExtendedStackTraceAsString throws NPE on deserialized nested exceptions.
149 </action>
150 <action issue="LOG4J2-1049" dev="rpopma" type="fix" due-to="Robert Schaft">
151 AsyncAppender now resets the thread interrupted flag after catching InterruptedException.
152 </action>
153 <action issue="LOG4J2-1048" dev="rpopma" type="fix" due-to="Nikhil">
154 FileConfigurationMonitor unnecessarily calls System.currentTimeMillis() causing high CPU usage.
155 </action>
156 <action issue="LOG4J2-1037" dev="ggregory" type="fix" due-to="Marc Dergacz">
157 Backward compatibility issue in log4j-1.2-api NDC pop() and peek().
158 </action>
159 <action issue="LOG4J2-1025" dev="ggregory" type="fix" due-to="Mikael Ståldal">
160 Custom java.util.logging.Level gives null Log4j Level and causes NPE.
161 </action>
162 <action issue="LOG4J2-1033" dev="ggregory" type="fix" due-to="Mikael Ståldal">
163 SimpleLogger creates unnecessary Map objects by calling ThreadContext.getContext() instead of getImmutableContext().
164 </action>
165 <action issue="LOG4J2-1026" dev="ggregory" type="fix">
166 HighlightConverter does not obey noConsoleNoAnsi.
167 </action>
168 <action issue="LOG4J2-1019" dev="ggregory" type="fix">
169 ZipCompressAction leaves files open until GC when an IO error takes place.
170 </action>
171 <action issue="LOG4J2-1020" dev="ggregory" type="fix">
172 GzCompressAction leaves files open until GC when an IO error takes place.
173 </action>
174 <action issue="LOG4J2-1038" dev="ggregory" type="fix" due-to="Gili">
175 Incorrect documentation for layout default charset.
176 </action>
177 <action issue="LOG4J2-1042" dev="ggregory" type="fix" due-to="Guillaume Turri">
178 Socket and Syslog appenders don't take timeout into account at startup.
179 </action>
180 <action issue="LOG4J2-934" dev="ggregory" type="fix" due-to="Kenneth Gendron">
181 Circular suppressed Exception throws StackOverflowError.
182 </action>
183 <action issue="LOG4J2-1046" dev="ggregory" type="fix" due-to="Kenneth Gendron">
184 Circular Exception cause throws StackOverflowError.
185 </action>
186 <action issue="LOG4J2-982" dev="ggregory" type="fix" due-to="Mikhail Mazurskiy">
187 Use System.nanoTime() to measure time intervals.
188 </action>
189 <action issue="LOG4J2-1045" dev="ggregory" type="fix" due-to="Günter Albrecht">
190 Externalize log4j2.xml via URL resource.
191 </action>
192 <action issue="LOG4J2-1058" dev="ggregory" type="fix" due-to="Daniel Branzea">
193 Log4jMarker#contains(String) does not respect org.slf4j.Marker contract.
194 </action>
195 <action issue="LOG4J2-1060" dev="ggregory" type="fix">
196 Log4jMarker#contains(Marker) does not respect org.slf4j.Marker contract.
197 </action>
198 <action issue="LOG4J2-1061" dev="ggregory" type="fix">
199 Log4jMarker#remove(Marker) does not respect org.slf4j.Marker contract.
200 </action>
201 <action issue="LOG4J2-1062" dev="ggregory" type="fix">
202 Log4jMarker#add(Marker) does not respect org.slf4j.Marker contract.
203 </action>
204 <action issue="LOG4J2-1064" dev="ggregory" type="fix">
205 org.apache.logging.slf4j.Log4jMarker does not implement org.slf4j.Marker.equals(Object) org.slf4j.Marker.hashCode().
206 </action>
207 <action issue="LOG4J2-889" dev="rpopma" type="fix" due-to="Maciej Karaś, Kenneth Leider">
208 Header in layout should not be written on application startup if appending to an existing file. Fixes LOG4J2-1030.
209 </action>
210 <action issue="LOG4J2-918" dev="rpopma" type="fix">
211 Clarify documentation for combining async with sync loggers.
212 </action>
213 <action issue="LOG4J2-1078" dev="ggregory" type="fix" due-to="Mikael Ståldal">
214 GelfLayout throws exception if some log event fields are null.
215 </action>
216 <action issue="LOG4J2-1044" dev="rgoers" type="update">
217 Support batchSize in FlumeAvroManager.
218 </action>
219 <action issue="LOG4J2-1065" dev="ggregory" type="update">
220 Define org.apache.logging.log4j.Marker.equals(Object) and org.apache.logging.log4j.Marker.hashCode().
221 </action>
222 <action issue="LOG4J2-1063" dev="ggregory" type="update">
223 Avoid creating temporary array object in org.apache.logging.slf4j.Log4jMarker.iterator().
224 </action>
225 <action issue="LOG4J2-890" dev="ggregory" type="update" due-to="Hassan Kalaldeh, Robert Andersson, Remko Popma">
226 log4j-web-2.1 should workaround a bug in JBOSS EAP 6.2.
227 </action>
228 <action issue="LOG4J2-403" dev="ggregory" type="update" due-to="Poorna Subhash P, Jeremy Lautman">
229 MongoDB appender, username and password should be optional.
230 </action>
231 <action issue="LOG4J2-1035" dev="ggregory" type="update">
232 Log4j2 tries to SystemClassLoader when running on Google AppEngine.
233 </action>
234 <action issue="LOG4J2-1022" dev="rgoers" type="update">
235 Allow a list of keys to be specified in the MDC pattern converter.
236 </action>
237 <action issue="LOG4J2-959" dev="ggregory" type="update">
238 Fix FindBugs DM_DEFAULT_ENCODING bug in SimpleLogger.logMessage() and simplify code.
239 </action>
240 <action issue="LOG4J2-1036" dev="ggregory" type="update">
241 Update Apache Flume from 1.5.2 to 1.6.0.
242 </action>
243 <action issue="LOG4J2-1041" dev="ggregory" type="update">
244 Update MongoDB driver from 2.11.2 to 2.13.2.
245 </action>
246 <action issue="LOG4J2-1018" dev="ggregory" type="update">
247 Update database tests from H2 1.3.175 to 1.3.176.
248 </action>
249 <action issue="LOG4J2-1070" dev="ggregory" type="update">
250 Update Java Mail from 1.5.2 to 1.5.4.
251 </action>
252 <action issue="LOG4J2-1079" dev="ggregory" type="update">
253 Update Jackson from 2.5.3 to 2.5.4.
254 </action>
255 <action issue="LOG4J2-1879" dev="ggregory" type="update">
256 Update Jackson from 2.5.4 to 2.6.0.
257 </action>
258 <action issue="LOG4J2-1092" dev="ggregory" type="update">
259 Update Jackson from 2.6.0 to 2.6.1.
260 </action>
261 <action issue="LOG4J2-1104" dev="ggregory" type="update">
262 Update Apache Commons Compress from 1.9 to 1.10.
263 </action>
264 </release>
265 <release version="2.3" date="2015-05-09" description="GA Release 2.3">
266 <action issue="LOG4J2-1009" dev="ggregory" type="fix" due-to="Mikael Ståldal">
267 Incorrectly defined compressionType parameter to GelfLayout.
268 </action>
269 <action issue="LOG4J2-1008" dev="ggregory" type="fix" due-to="Ralph Goers, Gary Gregory">
270 org.apache.logging.log4j.core.config.plugins.util.ResolverUtil.extractPath(URL) incorrectly converts '+' characters to spaces.
271 </action>
272 <action issue="LOG4J2-1007" dev="ggregory" type="fix" due-to="Ralph Goers, Gary Gregory">
273 org.apache.logging.log4j.core.util#fileFromUri(URI uri) incorrectly converts '+' characters to spaces.
274 </action>
275 <action issue="LOG4J2-1003" dev="ggregory" type="fix" due-to="Dan Armbrust">
276 JUL Logger.throwing is mis-mapped to ERROR when it should be TRACE.
277 </action>
278 <action issue="LOG4J2-965" dev="ggregory" type="fix" due-to="Khotyn Huang">
279 System.out no longer works after the Console appender and JANSI are initialized.
280 </action>
281 <action issue="LOG4J2-998" dev="ggregory" type="update" due-to="Mariano Gonzalez">
282 Make org.apache.logging.log4j.core.Logger#updateConfiguration protected.
283 </action>
284 <action issue="LOG4J2-995" dev="rgoers" type="update">
285 Move UTF-8 constant from Charsets to Constants class. Remove Charsets class.
286 </action>
287 <action issue="LOG4J2-993" dev="rgoers" type="fix">
288 Deadlock would occur if appender thread creates a new Logger during reconfiguration.
289 </action>
290 <action issue="LOG4J2-991" dev="rpopma" type="fix" due-to="Ryan Rupp">
291 Async root logger config should default includeLocation to false.
292 </action>
293 <action issue="LOG4J2-985" dev="rpopma" type="fix" due-to="Sean Dawson">
294 AbstractFilter should not implement equals() and hashCode().
295 </action>
296 <action issue="LOG4J2-984" dev="ggregory" type="add" due-to="Jonas Höpfner">
297 PatternLayout %highlight to support noConsoleNoAnsi like %style.
298 </action>
299 <action issue="LOG4J2-926" dev="ggregory" type="add" due-to="David Ohana">
300 Truncate from the end of text format modifier.
301 </action>
302 <action issue="LOG4J2-980" dev="ggregory" type="fix" due-to="Mikhail Mazurskiy">
303 Numerical overflow in BurstFilter not handled correctly.
304 </action>
305 <action issue="LOG4J2-981" dev="ggregory" type="fix" due-to="Mikhail Mazurskiy">
306 Incorrect unlock in ProviderUtil.
307 </action>
308 <action issue="LOG4J2-966" dev="ggregory" type="fix" due-to="Gary Gregory">
309 KeyStoreConfiguration.createKeyStoreConfiguration() ignores keyManagerFactoryAlgorithm.
310 </action>
311 <action issue="LOG4J2-976" dev="ggregory" type="fix" due-to="Matt Quinn">
312 Using monitorInterval with YAML config file format causes JSONParseException.
313 </action>
314 <action issue="LOG4J2-964" dev="ggregory" type="fix" due-to="Jonne Jyrylä">
315 StringFormattedMessage serialization is incorrect.
316 </action>
317 <action issue="LOG4J2-947" dev="ggregory" type="fix" due-to="Stefan Wehner">
318 A new StatusLoggerAdmin listener is added to StatusLogger every time the log is reconfigured.
319 </action>
320 <action issue="LOG4J2-968" dev="ggregory" type="fix" due-to="Paul D Johe">
321 SyslogLayout contains extra space.
322 </action>
323 <action issue="LOG4J2-967" dev="ggregory" type="fix" due-to="Stefan Wehner">
324 log4j2.component.properties not read for all properties.
325 </action>
326 <action issue="LOG4J2-971" dev="ggregory" type="fix" due-to="Paul D Johe">
327 Another bad priority in Syslog messages.
328 </action>
329 <action issue="LOG4J2-972" dev="ggregory" type="fix" due-to="Gary Gregory">
330 org.apache.logging.log4j.core.net.ssl.TlsSyslogInputStreamReader does not need to create temp Integer objects.
331 </action>
332 <action issue="LOG4J2-974" dev="ggregory" type="fix" due-to="Daniel Galán y Martins">
333 Typo in EventLogger documentation.
334 </action>
335 <action issue="LOG4J2-988" dev="ggregory" type="update" due-to="Gary Gregory">
336 Update LMAX Disruptor from 3.3.0 to 3.3.2.
337 </action>
338 <action issue="LOG4J2-987" dev="ggregory" type="update" due-to="Gary Gregory">
339 Migrate tests from Logback 1.1.2 to 1.1.3.
340 </action>
341 <action issue="LOG4J2-988" dev="ggregory" type="update" due-to="Gary Gregory">
342 Update tests to use ActiveMQ from 5.10 to 5.11.1.
343 </action>
344 <action issue="LOG4J2-1004" dev="ggregory" type="update">
345 Update Jackson from 2.5.1 to 2.5.3.
346 </action>
347 <action issue="LOG4J2-1005" dev="ggregory" type="update">
348 Update Slf4j from 1.7.7 to 1.7.12.
349 </action>
350 </release>
25351 <release version="2.2" date="2015-02-22" description="GA Release 2.2">
26352 <action issue="LOG4J2-938" dev="rpopma" type="fix" due-to="Mauro Molinari">
27353 (JMX) To avoid memory leaks when web applications are restarted, JMX notifications are sent from
29355 as before.
30356 </action>
31357 <action issue="LOG4J2-957" dev="ggregory" type="fix" due-to="fatih guleryuz">
32 Missing toUpperCase("Locale.ENGLISH").
358 Missing toUpperCase(Locale.ENGLISH).
33359 </action>
34360 <action issue="LOG4J2-956" dev="ggregory" type="fix" due-to="David Kellerman">
35361 Manual refers to Route "AppenderRef" attribute, should be "ref".
67393 Logging system fails to initialize if XInclude API is not available.
68394 </action>
69395 <action issue="LOG4J2-914" dev="ggregory" type="fix" due-to="Kaj Bjurman">
70 ThrowableProxy.getExtendedStackTraceAsString causes NullpointerException.
396 ThrowableProxy.getExtendedStackTraceAsString causes NullPointerException.
71397 </action>
72398 <action issue="LOG4J2-912" dev="ggregory" type="fix">
73399 XML configuration does not report full error message for XInclude parser configuration problems.
3030 *-------------------------+---------+----------+-----------+
3131 | | Mirrors | Checksum | Signature |
3232 *-------------------------+---------+----------+-----------+
33 | Apache Log4j 2 binary (tar.gz) | {{{http://www.apache.org/dyn/closer.cgi/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-bin.tar.gz} apache-log4j-${Log4jReleaseVersion}-bin.tar.gz}} | {{{https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-bin.tar.gz.md5} apache-log4j-${Log4jReleaseVersion}-bin.tar.gz.md5}} | {{{https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-bin.tar.gz.asc} apache-log4j-${Log4jReleaseVersion}-bin.tar.gz.asc}} |
33 | Apache Log4j 2 binary (tar.gz) | {{{http://www.apache.org/dyn/closer.lua/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-bin.tar.gz} apache-log4j-${Log4jReleaseVersion}-bin.tar.gz}} | {{{https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-bin.tar.gz.md5} apache-log4j-${Log4jReleaseVersion}-bin.tar.gz.md5}} | {{{https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-bin.tar.gz.asc} apache-log4j-${Log4jReleaseVersion}-bin.tar.gz.asc}} |
3434 *-------------------------+---------+----------+-----------+
35 | Apache Log4j 2 binary (zip) | {{{http://www.apache.org/dyn/closer.cgi/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-bin.zip} apache-log4j-${Log4jReleaseVersion}-bin.zip}} | {{{https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-bin.zip.md5} apache-log4j-${Log4jReleaseVersion}-bin.zip.md5}} | {{{https://www.apache.org/dist/logging/log42/apache-log4j-${Log4jReleaseVersion}-bin.zip.asc} apache-log4j-${Log4jReleaseVersion}-bin.zip.asc}} |
35 | Apache Log4j 2 binary (zip) | {{{http://www.apache.org/dyn/closer.lua/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-bin.zip} apache-log4j-${Log4jReleaseVersion}-bin.zip}} | {{{https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-bin.zip.md5} apache-log4j-${Log4jReleaseVersion}-bin.zip.md5}} | {{{https://www.apache.org/dist/logging/log42/apache-log4j-${Log4jReleaseVersion}-bin.zip.asc} apache-log4j-${Log4jReleaseVersion}-bin.zip.asc}} |
3636 *-------------------------+---------+----------+-----------+
37 | Apache Log4j 2 source (tar.gz) | {{{http://www.apache.org/dyn/closer.cgi/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-src.tar.gz} apache-log4j-${Log4jReleaseVersion}-src.tar.gz}} | {{{https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-src.tar.gz.md5} apache-log4j-${Log4jReleaseVersion}-src.tar.gz.md5}} | {{{https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-src.tar.gz.asc} apache-log4j-${Log4jReleaseVersion}-src.tar.gz.asc}} |
37 | Apache Log4j 2 source (tar.gz) | {{{http://www.apache.org/dyn/closer.lua/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-src.tar.gz} apache-log4j-${Log4jReleaseVersion}-src.tar.gz}} | {{{https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-src.tar.gz.md5} apache-log4j-${Log4jReleaseVersion}-src.tar.gz.md5}} | {{{https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-src.tar.gz.asc} apache-log4j-${Log4jReleaseVersion}-src.tar.gz.asc}} |
3838 *-------------------------+---------+----------+-----------+
39 | Apache Log4j 2 source (zip) | {{{http://www.apache.org/dyn/closer.cgi/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-src.zip} apache-log4j-${Log4jReleaseVersion}-src.zip}} | {{{https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-src.zip.md5} apache-log4j-${Log4jReleaseVersion}-src.zip.md5}} | {{{https://www.apache.org/dist/logging/log42/apache-log4j-${Log4jReleaseVersion}-src.zip.asc} apache-log4j-${Log4jReleaseVersion}-src.zip.asc}} |
39 | Apache Log4j 2 source (zip) | {{{http://www.apache.org/dyn/closer.lua/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-src.zip} apache-log4j-${Log4jReleaseVersion}-src.zip}} | {{{https://www.apache.org/dist/logging/log4j/${Log4jReleaseVersion}/apache-log4j-${Log4jReleaseVersion}-src.zip.md5} apache-log4j-${Log4jReleaseVersion}-src.zip.md5}} | {{{https://www.apache.org/dist/logging/log42/apache-log4j-${Log4jReleaseVersion}-src.zip.asc} apache-log4j-${Log4jReleaseVersion}-src.zip.asc}} |
4040 *-------------------------+---------+----------+-----------+
4141
4242 It is essential that you verify the integrity of the downloaded files using the PGP or MD5 signatures.
0 # Licensed to the Apache Software Foundation (ASF) under one
1 # or more contributor license agreements. See the NOTICE file
2 # distributed with this work for additional information
3 # regarding copyright ownership. The ASF licenses this file
4 # to you under the Apache License, Version 2.0 (the
5 # "License"); you may not use this file except in compliance
6 # with the License. You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing,
11 # software distributed under the License is distributed on an
12 # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13 # KIND, either express or implied. See the License for the
14 # specific language governing permissions and limitations
15 # under the License.
16
17 report.cim.access = Access
18 report.cim.anthill.intro = This project uses {Anthill, http://www.anthillpro.com/html/products/anthillos/}.
19 report.cim.bamboo.intro = This project uses {Bamboo, http://www.atlassian.com/software/bamboo/}.
20 report.cim.buildforge.intro = This project uses {Build Forge, http://www-306.ibm.com/software/awdtools/buildforge/enterprise/}.
21 report.cim.continuum.intro = This project uses {Continuum, http://continuum.apache.org/}.
22 report.cim.cruisecontrol.intro = This project uses {CruiseControl, http://cruisecontrol.sourceforge.net/}.
23 report.cim.description = This is a link to the definitions of all continuous integration processes that builds and tests code on a frequent, regular basis.
24 report.cim.general.intro = This project uses Continuous Integration System.
25 report.cim.hudson.intro = This project uses {Hudson, http://hudson-ci.org/}.
26 report.cim.jenkins.intro = This project uses {Jenkins, http://jenkins-ci.org/}.
27 report.cim.luntbuild.intro = This project uses {Luntbuild, http://luntbuild.javaforge.com/}.
28 report.cim.travis.intro = This project uses {Travis CI, https://travis-ci.org/}.
29 report.cim.name = Continuous Integration
30 report.cim.nocim = No continuous integration management system is defined. Please check back at a later date.
31 report.cim.notifiers.column.address = Address
32 report.cim.notifiers.column.configuration = Configuration
33 report.cim.notifiers.column.type = Type
34 report.cim.notifiers.intro = Configuration for notifying developers/users when a build is unsuccessful, including user information and notification mode.
35 report.cim.notifiers.nolist = No notifiers are defined. Please check back at a later date.
36 report.cim.notifiers.title = Notifiers
37 report.cim.nourl = No url to the continuous integration system is defined.
38 report.cim.overview.title = Overview
39 report.cim.title = Continuous Integration
40 report.cim.url = The following is a link to the continuous integration system used by the project:
41 report.dependencies.column.artifactId = ArtifactId
42 report.dependencies.column.classifier = Classifier
43 report.dependencies.column.description = Description
44 report.dependencies.column.groupId = GroupId
45 report.dependencies.column.license = License
46 report.dependencies.column.optional = Optional
47 report.dependencies.column.isOptional = Yes
48 report.dependencies.column.isNotOptional = No
49 report.dependencies.column.type = Type
50 report.dependencies.column.url = URL
51 report.dependencies.column.version = Version
52 report.dependencies.description = This document lists the project's dependencies and provides information on each dependency.
53 report.dependencies.file.details.cell.debuginformation.yes = Yes
54 report.dependencies.file.details.cell.debuginformation.no = No
55 report.dependencies.file.details.column.classes = Classes
56 report.dependencies.file.details.column.debuginformation = Debug Information
57 report.dependencies.file.details.column.entries = Entries
58 report.dependencies.file.details.column.file = Filename
59 report.dependencies.file.details.column.javaVersion = Java Version
60 report.dependencies.file.details.column.packages = Packages
61 report.dependencies.file.details.column.sealed = Sealed
62 report.dependencies.file.details.column.size = Size
63 report.dependencies.file.details.column.size.gb = GB
64 report.dependencies.file.details.column.size.mb = MB
65 report.dependencies.file.details.column.size.kb = kB
66 report.dependencies.file.details.columntitle.debuginformation = Indicates whether these dependencies have been compiled with debug information.
67 report.dependencies.file.details.title = Dependency File Details
68 report.dependencies.file.details.total = Total
69 report.dependencies.graph.tables.licenses = Licenses
70 report.dependencies.graph.tables.unknown = Unknown
71 report.dependencies.graph.title = Project Dependency Graph
72 report.dependencies.graph.tree.title = Dependency Tree
73 report.dependencies.intro.compile = The following is a list of compile dependencies for this project. These dependencies are required to compile and run the application:
74 report.dependencies.intro.provided = The following is a list of provided dependencies for this project. These dependencies are required to compile the application, but should be provided by default when using the library:
75 report.dependencies.intro.runtime = The following is a list of runtime dependencies for this project. These dependencies are required to run the application:
76 report.dependencies.intro.system = The following is a list of system dependencies for this project. These dependencies are required to compile the application:
77 report.dependencies.intro.test = The following is a list of test dependencies for this project. These dependencies are only required to compile and run unit tests for the application:
78 report.dependencies.name = Dependencies
79 report.dependencies.nolist = There are no dependencies for this project. It is a standalone application that does not depend on any other project.
80 report.dependencies.repo.locations.artifact.breakdown = Repository locations for each of the Dependencies.
81 report.dependencies.repo.locations.cell.release.disabled = No
82 report.dependencies.repo.locations.cell.release.enabled = Yes
83 report.dependencies.repo.locations.cell.snapshot.disabled = No
84 report.dependencies.repo.locations.cell.snapshot.enabled = Yes
85 report.dependencies.repo.locations.cell.blacklisted.disabled = No
86 report.dependencies.repo.locations.cell.blacklisted.enabled = Yes
87 report.dependencies.repo.locations.column.artifact = Artifact
88 report.dependencies.repo.locations.column.blacklisted = Blacklisted
89 report.dependencies.repo.locations.column.release = Release
90 report.dependencies.repo.locations.column.repoid = Repo ID
91 report.dependencies.repo.locations.column.snapshot = Snapshot
92 report.dependencies.repo.locations.column.url = URL
93 report.dependencies.repo.locations.title = Dependency Repository Locations
94 report.dependencies.title = Project Dependencies
95 report.dependencies.unnamed = Unnamed
96 report.dependencies.transitive.intro = The following is a list of transitive dependencies for this project. Transitive dependencies are the dependencies of the project dependencies.
97 report.dependencies.transitive.nolist = No transitive dependencies are required for this project.
98 report.dependencies.transitive.title = Project Transitive Dependencies
99 report.dependency-convergence.convergence.caption = Dependencies used in modules
100 report.dependency-convergence.convergence.single.caption = Dependencies used in this project
101 report.dependency-convergence.description = This document presents the convergence of dependency versions across the entire project, and its sub modules.
102 report.dependency-convergence.legend = Legend:
103 report.dependency-convergence.legend.different = At least one dependency has a differing version of the dependency or has SNAPSHOT dependencies.
104 report.dependency-convergence.legend.shared = All modules/dependencies share one version of the dependency.
105 report.dependency-convergence.name = Dependency Convergence
106 report.dependency-convergence.reactor.name = Reactor Dependency Convergence
107 report.dependency-convergence.reactor.title = Reactor Dependency Convergence
108 report.dependency-convergence.stats.artifacts = Number of unique artifacts (NOA):
109 report.dependency-convergence.stats.caption = Statistics:
110 report.dependency-convergence.stats.convergence = Convergence (NOD/NOA):
111 report.dependency-convergence.stats.dependencies = Number of dependencies (NOD):
112 report.dependency-convergence.stats.readyrelease = Ready for release (100 % convergence and no SNAPSHOTS):
113 report.dependency-convergence.stats.readyrelease.error = Error
114 report.dependency-convergence.stats.readyrelease.error.convergence = You do not have 100 % convergence.
115 report.dependency-convergence.stats.readyrelease.error.snapshots = You have SNAPSHOT dependencies.
116 report.dependency-convergence.stats.readyrelease.success = Success
117 report.dependency-convergence.stats.conflicting = Number of version-conflicting artifacts (NOC):
118 report.dependency-convergence.stats.snapshots = Number of SNAPSHOT artifacts (NOS):
119 report.dependency-convergence.stats.modules = Number of modules:
120 report.dependency-convergence.title = Dependency Convergence
121 report.dependency-info.name = Dependency Information
122 report.dependency-info.title = Dependency Information
123 report.dependency-info.description = This document describes how to to include this project as a dependency using various dependency management tools.
124 report.index.nodescription = There is currently no description associated with this project.
125 report.index.title = About
126 report.issuetracking.bugzilla.intro = This project uses {Bugzilla, http://www.bugzilla.org/}.
127 report.issuetracking.custom.intro = This project uses %issueManagementSystem% to manage its issues.
128 report.issuetracking.description = This document provides information on the issue management system used in this project.
129 report.issuetracking.general.intro = This project uses an Issue Management System to manage its issues.
130 report.issuetracking.intro = Issues, bugs, and feature requests should be submitted to the following issue tracking system for this project.
131 report.issuetracking.jira.intro = This project uses {JIRA, http://www.atlassian.com/software/jira}.
132 report.issuetracking.name = Issue Tracking
133 report.issuetracking.noissueManagement = No issue management system is defined. Please check back at a later date.
134 report.issuetracking.overview.title = Overview
135 report.issuetracking.scarab.intro = This project uses {Scarab, http://scarab.tigris.org/}.
136 report.issuetracking.title = Issue Tracking
137 report.license.description = This document lists the project license(s).
138 report.license.multiple = This project is provided under multiple licenses:
139 report.license.name = Project License
140 report.license.nolicense = No license is defined for this project.
141 report.license.overview.intro = Typically the licenses listed for the project are that of the project itself, and not of dependencies.
142 report.license.overview.title = Overview
143 report.license.originalText = [Original text]
144 report.license.copy = Copy of the license follows:
145 report.license.title = Project License
146 report.license.unnamed = Unnamed
147 report.mailing-lists.column.archive = Archive
148 report.mailing-lists.column.name = Name
149 report.mailing-lists.column.otherArchives = Other Archives
150 report.mailing-lists.column.post = Post
151 report.mailing-lists.column.subscribe = Subscribe
152 report.mailing-lists.column.unsubscribe = Unsubscribe
153 report.mailing-lists.description = This document provides subscription and archive information for this project's mailing lists.
154 report.mailing-lists.intro = We welcome you to join our mailing lists and let us know about your thoughts or ideas about Apache Log4j. \
155 <p>Note: These are public mailing lists and anything posted to these lists is archived and is visible to the the public, \
156 indexed by search engines, etc. Posts can only be removed in extraordinary circumstances, in accordance with Apache's <a href="http://www.apache.org/foundation/public-archives.html" class="externalLink">Public Forum Archive Policy</a>.\
157 </p>\
158 <p>\
159 These are the mailing lists that have been established for this project. For each list, there is a subscribe, unsubscribe, and an archive link.</p>\
160 <p>\
161 Questions related to the usage of Log4j components should be posted to the \
162 <a href="http://mail-archives.apache.org/mod_mbox/logging-log4j-user/" class="externalLink">User List</a>. \
163 <br>\
164 The <a href="http://mail-archives.apache.org/mod_mbox/logging-log4j-dev/" class="externalLink">Developer List</a> \
165 is for questions and discussion related to the development of Commons components.\
166 <br>\
167 Please do not cross-post; developers are also subscribed to the user list. \
168 Read the archives first in case your question has already been answered. \
169 If not, then subscribe to the appropriate list and post your question. \
170 </p>\
171 <p>
172 <strong>Note:</strong> please don't send patches or attachments to any of the mailing lists. \
173 Patches are best handled via the <i>Issue Tracking</i> system. \
174 Otherwise, please upload the file to a public server and include the URL in the mail. \
175 </p>\
176 <p>\
177 Please read the <a href="http://www.apache.org/foundation/public-archives.html" class="externalLink">Public Forum Archive Policy</a> \
178 and <a href="http://www.apache.org/dev/contrib-email-tips.html" class="externalLink">Tips for email contributors</a>. \
179 <br>\
180 For further information on Apache mailing lists please read \
181 <a href="http://www.apache.org/foundation/mailinglists.html" class="externalLink">General mailing list information</a> \
182 in particular the section entitled\
183 <a href="http://www.apache.org/foundation/mailinglists.html#subscribe" class="externalLink">Subscribing and Unsubscribing</a>\
184 </p>
185 report.mailing-lists.name = Mailing Lists
186 report.mailing-lists.nolist = There are no mailing lists currently associated with this project.
187 report.mailing-lists.title = Project Mailing Lists
188 report.scm.accessbehindfirewall.cvs.intro = For those developers who are stuck behind a corporate firewall, {CVSGrab, http://cvsgrab.sourceforge.net/} can use the viewcvs web interface to checkout the source code.
189 report.scm.accessbehindfirewall.general.intro = Refer to the documentation of the SCM used for more information about access behind a firewall.
190 report.scm.accessbehindfirewall.svn.intro = For those users who are stuck behind a corporate firewall which is blocking HTTP access to the Subversion repository, you can try to access it via the developer connection:
191 report.scm.accessbehindfirewall.title = Access from Behind a Firewall
192 report.scm.accessthroughtproxy.svn.intro1 = The Subversion client can go through a proxy, if you configure it to do so. First, edit your "servers" configuration file to indicate which proxy to use. The file's location depends on your operating system. On Linux or Unix it is located in the directory "~/.subversion". On Windows it is in "%APPDATA%\\Subversion". (Try "echo %APPDATA%", note this is a hidden directory.)
193 report.scm.accessthroughtproxy.svn.intro2 = There are comments in the file explaining what to do. If you don't have that file, get the latest Subversion client and run any command; this will cause the configuration directory and template files to be created.
194 report.scm.accessthroughtproxy.svn.intro3 = Example: Edit the 'servers' file and add something like:
195 report.scm.accessthroughtproxy.title = Access Through a Proxy
196 report.scm.anonymousaccess.cvs.intro = This project's CVS repository can be checked out through anonymous CVS with the following instruction set. When prompted for a password for anonymous, simply press the Enter key.
197 report.scm.anonymousaccess.general.intro = Refer to the documentation of the SCM used for more information about anonymously check out. The connection url is:
198 report.scm.anonymousaccess.git.intro = The source can be checked out anonymously from Git with this command (See {http://git-scm.com/docs/git-clone,http://git-scm.com/docs/git-clone}):
199 report.scm.anonymousaccess.hg.intro = The source can be checked out anonymously from Mercurial with this command (See {http://www.selenic.com/mercurial/hg.1.html#clone,http://www.selenic.com/mercurial/hg.1.html#clone}):
200 report.scm.anonymousaccess.svn.intro = The source can be checked out anonymously from Subversion with this command:
201 report.scm.anonymousaccess.title = Anonymous Access
202 report.scm.clearcase.intro = This project uses {ClearCase, http://www-306.ibm.com/software/awdtools/clearcase/} to manage its source code. Informations on ClearCase use can be found at {http://www.redbooks.ibm.com/redbooks/pdfs/sg246399.pdf, http://www.redbooks.ibm.com/redbooks/pdfs/sg246399.pdf}.
203 report.scm.cvs.intro = This project uses {Concurrent Versions System, http://www.cvshome.org/} to manage its source code. Instructions on CVS use can be found at {http://cvsbook.red-bean.com/, http://cvsbook.red-bean.com/}.
204 report.scm.description = This document lists ways to access the online source repository.
205 report.scm.devaccess.clearcase.intro = Only project developers can access the ClearCase tree via this method. Substitute username with the proper value.
206 report.scm.devaccess.cvs.intro = Only project developers can access the CVS tree via this method. Substitute username with the proper value.
207 report.scm.devaccess.general.intro = Refer to the documentation of the SCM used for more information about developer check out. The connection url is:
208 report.scm.devaccess.git.intro = Only project developers can access the Git tree via this method (See {http://git-scm.com/docs/git-clone,http://git-scm.com/docs/git-clone}).
209 report.scm.devaccess.hg.intro = Only project developers can access the Mercurial tree via this method (See {http://www.selenic.com/mercurial/hg.1.html#clone,http://www.selenic.com/mercurial/hg.1.html#clone}).
210 report.scm.devaccess.perforce.intro = Only project developers can access the Perforce tree via this method. Substitute username and password with the proper values.
211 report.scm.devaccess.starteam.intro = Only project developers can access the Starteam tree via this method. Substitute username with the proper value.
212 report.scm.devaccess.svn.intro1.https = Everyone can access the Subversion repository via HTTP, but committers must checkout the Subversion repository via HTTPS.
213 report.scm.devaccess.svn.intro1.other = Committers must checkout the Subversion repository.
214 report.scm.devaccess.svn.intro1.svn = Committers must checkout the Subversion repository via SVN.
215 report.scm.devaccess.svn.intro1.svnssh = Committers must checkout the Subversion repository via SVN+SSH.
216 report.scm.devaccess.svn.intro2 = To commit changes to the repository, execute the following command to commit your changes (svn will prompt you for your password):
217 report.scm.devaccess.title = Developer Access
218 report.scm.general.intro = This project uses a Source Content Management System to manage its source code.
219 report.scm.name = Source Repository
220 report.scm.noscm = No source configuration management system is defined. Please check back at a later date.
221 report.scm.overview.title = Overview
222 report.scm.git.intro = This project uses {Git, http://git-scm.com/} to manage its source code. Instructions on Git use can be found at {http://git-scm.com/documentation,http://git-scm.com/documentation}.
223 report.scm.hg.intro = This project uses {Mercurial, http://mercurial.selenic.com/wiki/} to manage its source code. Instructions on Mercurial use can be found at {http://hgbook.red-bean.com/read/, http://hgbook.red-bean.com/read/}.
224 report.scm.perforce.intro = This project uses {Perforce, http://www.perforce.com/} to manage its source code. Instructions on Perforce use can be found at {http://www.perforce.com/perforce/doc.051/manuals/cmdref/index.html, http://www.perforce.com/perforce/doc.051/manuals/cmdref/index.html}.
225 report.scm.starteam.intro = This project uses {Starteam, http://www.borland.com/us/products/starteam/} to manage its source code.
226 report.scm.svn.intro = This project uses {Subversion, http://subversion.apache.org/} to manage its source code. Instructions on Subversion use can be found at {http://svnbook.red-bean.com/, http://svnbook.red-bean.com/}.
227 report.scm.title = Source Repository
228 report.scm.webaccess.nourl = There is no browsable version of the source repository listed for this project. Please check back again later.
229 report.scm.webaccess.title = Web Browser Access
230 report.scm.webaccess.url = The following is a link to a browsable version of the source repository:
231 report.summary.build.artifactid = ArtifactId
232 report.summary.build.groupid = GroupId
233 report.summary.build.javaVersion = Java Version
234 report.summary.build.title = Build Information
235 report.summary.build.type = Type
236 report.summary.build.version = Version
237 report.summary.description = This document lists other related information of this project
238 report.summary.field = Field
239 report.summary.general.description = Description
240 report.summary.general.homepage = Homepage
241 report.summary.general.name = Name
242 report.summary.general.title = Project Information
243 report.summary.name = Project Summary
244 report.summary.organization.name = Name
245 report.summary.organization.title = Project Organization
246 report.summary.organization.url = URL
247 report.summary.noorganization = This project does not belong to an organization.
248 report.summary.title = Project Summary
249 report.summary.value = Value
250 report.summary.download = Download
251 report.team-list.contributors.actualtime = Actual Time (GMT)
252 report.team-list.contributors.email = Email
253 report.team-list.contributors.intro = The following additional people have contributed to this project through the way of suggestions, patches or documentation.
254 report.team-list.contributors.image = Image
255 report.team-list.contributors.name = Name
256 report.team-list.contributors.organization = Organization
257 report.team-list.contributors.organizationurl = Organization URL
258 report.team-list.contributors.properties = Properties
259 report.team-list.contributors.roles = Roles
260 report.team-list.contributors.timezone = Time Zone
261 report.team-list.contributors.title = Contributors
262 report.team-list.contributors.url = URL
263 report.team-list.description = This document provides information on the members of this project. These are the individuals who have contributed to the project in one form or another.
264 report.team-list.developers.actualtime = Actual Time (GMT)
265 report.team-list.developers.email = Email
266 report.team-list.developers.image = Image
267 report.team-list.developers.id = Id
268 report.team-list.developers.intro = The following is a list of developers with commit privileges that have directly contributed to the project in one way or another.
269 report.team-list.developers.name = Name
270 report.team-list.developers.organization = Organization
271 report.team-list.developers.organizationurl = Organization URL
272 report.team-list.developers.properties = Properties
273 report.team-list.developers.roles = Roles
274 report.team-list.developers.timezone = Time Zone
275 report.team-list.developers.title = Members
276 report.team-list.developers.url = URL
277 report.team-list.intro.description1 = A successful project requires many people to play many roles. Some members write code or documentation, while others are valuable as testers, submitting patches and suggestions.
278 report.team-list.intro.description2 = The team is comprised of Members and Contributors. Members have direct access to the source of a project and actively evolve the code-base. Contributors improve the project through submission of patches and suggestions to the Members. The number of Contributors to the project is unbounded. Get involved today. All contributions to the project are greatly appreciated.
279 report.team-list.intro.title = The Team
280 report.team-list.name = Project Team
281 report.team-list.nocontributor = There are no contributors listed for this project. Please check back again later.
282 report.team-list.nodeveloper = There are no developers working on this project.
283 report.team-list.title = Project Team
284 report.dependencyManagement.name = Dependency Management
285 report.dependencyManagement.description = This document lists the dependencies that are defined through dependencyManagement.
286 report.dependencyManagement.title = Project Dependency Management
287 report.dependencyManagement.nolist = There are no dependencies in the DependencyManagement of this project.
288 report.dependencyManagement.column.groupId = GroupId
289 report.dependencyManagement.column.artifactId = ArtifactId
290 report.dependencyManagement.column.version = Version
291 report.dependencyManagement.column.classifier = Classifier
292 report.dependencyManagement.column.type = Type
293 report.dependencyManagement.column.license = License
294 report.dependencyManagement.intro.compile = The following is a list of compile dependencies in the DependencyManagement of this project. These dependencies can be included in the submodules to compile and run the submodule:
295 report.dependencyManagement.intro.provided = The following is a list of provided dependencies in the DependencyManagement of this project. These dependencies can be included in the submodules to compile the submodule, but should be provided by default when using the library:
296 report.dependencyManagement.intro.runtime = The following is a list of runtime dependencies in the DependencyManagement of this project. These dependencies can be included in the submodules to run the submodule:
297 report.dependencyManagement.intro.system = The following is a list of system dependencies in the DependencyManagement of this project. These dependencies can be included in the submodules to compile the submodule:
298 report.dependencyManagement.intro.test = The following is a list of test dependencies in the DependencyManagement of this project. These dependencies can be included in the submodules to compile and run unit tests for the submodule:
299 report.pluginManagement.nolist = There are no plugins defined in the PluginManagement part of this project.
300 report.pluginManagement.name = Plugin Management
301 report.pluginManagement.description = This document lists the plugins that are defined through pluginManagement.
302 report.pluginManagement.title = Project Plugin Management
303 report.plugins.name = Project Plugins
304 report.plugins.description = This document lists the build plugins and the report plugins used by this project.
305 report.plugins.title = Project Build Plugins
306 report.plugins.report.title = Project Report Plugins
307 report.plugins.nolist = There are no plugins defined in the Build part of this project.
308 report.plugins.report.nolist = There are no plugins reports defined in the Reporting part of this project.
309 report.modules.nolist = There are no modules declared in this project.
310 report.modules.name = Project Modules
311 report.modules.description = This document lists the modules (sub-projects) of this project.
312 report.modules.title = Project Modules
313 report.modules.intro = This project has declared the following modules:
314 report.modules.header.name = Name
315 report.modules.header.description = Description
316 report.distributionManagement.name = Distribution Management
317 report.distributionManagement.description = This document provides informations on the distribution management of this project.
318 report.distributionManagement.title = Project Distribution Management
319 report.distributionManagement.nodistributionmanagement = No distribution management is defined for this project.
320 report.distributionManagement.overview.title = Overview
321 report.distributionManagement.overview.intro = The following is the distribution management information used by this project.
322 report.distributionManagement.downloadURL = Download URL
323 report.distributionManagement.repository = Repository
324 report.distributionManagement.snapshotRepository = Snapshot Repository
325 report.distributionManagement.site = Site
326 report.distributionManagement.relocation = Relocation
327 report.distributionManagement.field = Field
328 report.distributionManagement.value = Value
329 report.distributionManagement.relocation.groupid = GroupId
330 report.distributionManagement.relocation.artifactid = ArtifactId
331 report.distributionManagement.relocation.version = Version
332 report.distributionManagement.relocation.message = Message
470470 #googleAnalytics( $decoration.googleAnalyticsAccountId )
471471 </head>
472472 <body class="composite">
473 <img class="logo-left" src="$relativePath/images/ls-logo.jpg" alt="Apache logging services logo" />
473 <a href="https://logging.apache.org/">
474 <img class="logo-left" src="$relativePath/images/ls-logo.jpg" alt="Apache logging services logo" />
475 </a>
474476 <img class="logo-right" src="$relativePath/images/logo.jpg" alt="Apache log4j logo" />
475477 <div class="clear"></div>
476478
4242 </item>
4343 <item name="Runtime Dependencies" href="/runtime-dependencies.html"/>
4444 <item name="FAQ" href="/faq.html"/>
45 <item name="Articles" href="/articles.html"/>
4546 </menu>
4647
4748 <menu name="Manual" inherit="top" img="icon-book">
6566 <item name="Configuration Syntax" href="/manual/configuration.html#ConfigurationSyntax" />
6667 <item name="XML Syntax" href="/manual/configuration.html#XML"/>
6768 <item name="JSON Syntax" href="/manual/configuration.html#JSON"/>
69 <item name="Properties Syntax" href="/manual/configuration.html#Properties"/>
6870 <item name="Configuring Loggers" href="/manual/configuration.html#Loggers"/>
6971 <item name="Configuring Appenders" href="/manual/configuration.html#Appenders"/>
7072 <item name="Configuring Filters" href="/manual/configuration.html#Filters"/>
99101 <item name="Java" href="/manual/lookups.html#JavaLookup"/>
100102 <item name="JNDI" href="/manual/lookups.html#JndiLookup"/>
101103 <item name="JVM Arguments" href="/manual/lookups.html#JmxRuntimeInputArgumentsLookup"/>
104 <item name="Log4j Config" href="/manual/lookups.html#Log4jConfigLookup"/>
102105 <item name="Main Arguments" href="/manual/lookups.html#AppMainArgsLookup"/>
103106 <item name="Map" href="/manual/lookups.html#MapLookup"/>
104107 <item name="Structured Data" href="/manual/lookups.html#StructuredDataLookup"/>
127130 <item name="SMTP" href="/manual/appenders.html#SMTPAppender"/>
128131 <item name="Socket" href="/manual/appenders.html#SocketAppender"/>
129132 <item name="Syslog" href="/manual/appenders.html#SyslogAppender"/>
133 <item name="ZeroMQ" href="/manual/appenders.html#ZeroMQAppender"/>
130134 </item>
131135
132136 <item name="Layouts" href="/manual/layouts.html" collapse="true">
180184 </item>
181185
182186 <item name="Extending Log4j Configuration" href="/manual/customconfig.html" collapse="true">
183 <item name="ConfigurationFactory" href="/manual/customconfig.html#ConfigurationFactory"/>
184 <item name="Manual" href="/manual/customconfig.html#AddingToCurrent"/>
187 <item name="ConfigurationBuilder API" href="/manual/customconfig.html#ConfigurationBuilder"/>
188 <item name="Understanding ConfigurationFactory" href="/manual/customconfig.html#ConfigurationFactory"/>
189 <item name="Example" href="/manual/customconfig.html#Example"/>
190 <item name="Using Configurator" href="/manual/customconfig.html#Configurator"/>
191 <item name="Config File and Code" href="/manual/customconfig.html#Hybrid"/>
192 <item name="After Initialization" href="/manual/customconfig.html#AddingToCurrent"/>
185193 </item>
186194
187195 <item name="Custom Log Levels" href="/manual/customloglevels.html" collapse="true">
208216 <item name="Log4j Web Application Support" href="log4j-web/index.html"/>
209217 <item name="Log4j NoSQL support" href="log4j-nosql/index.html"/>
210218 <item name="Log4j IO Streams" href="log4j-iostreams/index.html"/>
219 <item name="Log4j Liquibase Binding" href="log4j-liquibase/index.html"/>
211220 </menu>
212221
213222 <menu name="Project Information" img="icon-info-sign">
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17
18 <document>
19 <properties>
20 <title>Articles</title>
21 <author email="ggregory@apache.org">Gary Gregory</author>
22 </properties>
23
24 <body>
25 <section name="Articles">
26 <p>
27 A collection of articles about Log4j 2.
28 </p>
29 <a name="English"/>
30 <subsection name="English">
31 <ul>
32 <li>
33 <a href="http://www.infoq.com/news/2015/09/interview-log4j-pmc">The Transition to a New Log4j: a Q&amp;A with Log4j's Project Management Committee</a>
34 (September 8, 2015)
35 </li>
36 <li>
37 <a href="http://www.infoq.com/news/2015/08/log4j-version-1-reaches-eol">Log4j Version 1 Reaches End of Life</a>
38 (August 26, 2015)
39 </li>
40 <li>
41 <a href="https://blogs.apache.org/foundation/entry/apache_logging_services_project_announces">Apache Logging Services Project Announces Log4j 1 End-Of-Life; Recommends Upgrade to Log4j 2</a>
42 (August 6, 2015)
43 </li>
44 <li>
45 <a href="https://www.innoq.com/en/blog/per-request-debugging-with-log4j2/">Per request debugging with Log4j 2 filters</a>
46 (May 8, 2015)
47 </li>
48 <li>
49 <a
50 href="http://www.journaldev.com/7128/apache-log4j-2-tutorial-configuration-levels-appenders-lookup-layouts-and-filters-example">Apache Log4j 2 Tutorial – Configuration, Levels, Appenders, Lookup, Layouts and
51 Filters Example</a>
52 (March 16, 2015)
53 </li>
54 <li>
55 <a href="http://blogs.mulesoft.com/dev/mule-dev/mule-3-6-asynchronous-logging/">Disrupting your Asynchronous Loggers</a>
56 (March 5, 2015)
57 </li>
58 <li>
59 <a href="http://andrew-flower.com/blog/Create_Custom_Log4j_Plugins">Extending Log4j2 - Creating Custom Log4j2 Plugins</a>
60 (February 20, 2015)
61 </li>
62 <li>
63 <a href="http://blogs.mulesoft.com/dev/mule-dev/mule-3-6-asynchronous-logging/">Asynchronous Logging in Mule 3.6</a>
64 (January 20, 2015)
65 </li>
66 <li>
67 <a href="http://www.infoq.com/news/2014/07/apache-log4j2">Apache Log4j 2.0 - Worth the Upgrade?</a>
68 (Jul 31, 2014)
69 </li>
70 <li>
71 <a href="http://tech.finn.no/2014/07/01/log4j2-in-production-making-it-fly/">Log4j 2 in Production – Making it Fly</a>
72 (July 2, 2014)
73 </li>
74 <li>
75 <a href="http://www.grobmeier.de/log4j-2-performance-close-to-insane-20072013.html">Log4j 2: Performance Close to Insane</a>
76 (July 20, 2013)
77 </li>
78 <li>
79 <a href="http://www.grobmeier.de/the-new-log4j-2-0-05122012.html">The New Log4j 2.0</a>
80 (December 5, 2012)
81 </li>
82 </ul>
83 </subsection>
84
85 <a name="German"/>
86 <subsection name="German">
87 <ul>
88 <li>
89 <a
90 href="https://www.innoq.com/en/articles/2015/01/logging-konsolidieren-log4j2/">Logging konsolidieren und Performance gewinnen</a>
91 (January 23, 2015)
92 </li>
93 </ul>
94 </subsection>
95
96 <a name="Japanese"/>
97 <subsection name="Japanese">
98 <ul>
99 <li>
100 <a
101 href="http://d.hatena.ne.jp/Kazuhira/20140628/1403959552">Log4j2を試してみる</a>
102 (June 28, 2014)
103 </li>
104 </ul>
105 </subsection>
106
107 <a name="Korean"/>
108 <subsection name="Korean">
109 <ul>
110 <li>
111 <a
112 href="http://www.egovframe.go.kr/wiki/doku.php?id=egovframework:rte3:fdl:%EC%84%A4%EC%A0%95_%ED%8C%8C%EC%9D%BC%EC%9D%84_%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94_%EB%B0%A9%EB%B2%95">Log4j 2 환경설정 [설정 파일 사용 시]</a>
113 (May 14, 2014)
114 </li>
115 </ul>
116 </subsection>
117 </section>
118
119 </body>
120 </document>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <document xmlns="http://maven.apache.org/XDOC/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
18 xsi:schemaLocation="http://maven.apache.org/XDOC/2.0 http://maven.apache.org/xsd/xdoc-2.0.xsd">
19
20 <properties>
21 <title>Releases</title>
22 </properties>
23
24 <body>
25 <section name="Release Change Logs">
26
27 <p><a href="jira-report.html#a1.0-alpha1">JIRA change log</a></p>
28 <p><a href="changes-report.html#a1.0-alpha1">Manual change log</a></p>
29
30 <p>Apache Log4j 2 is not compatible with the previous versions. Please have the following in mind
31 when upgrading to Log4j 2 in your project:</p>
32
33 <ul>
34 <li>Java 6 is required</li>
35 <li>The XML configuration has been simplified and is not compatible with Log4j 1.x</li>
36 <li>Configuration via property files is not supported.</li>
37 <li>Configuration via JSON or YAML is supported.</li>
38 <li>Although Log4j 2 is not directly compatible with Log4j 1.x a compatibility bridge
39 has been provided to reduce the need to make coding changes.</li>
40 </ul>
41
42 </section>
43 </body>
44 </document>
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17 <document xmlns="http://maven.apache.org/XDOC/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
18 xsi:schemaLocation="http://maven.apache.org/XDOC/2.0 http://maven.apache.org/xsd/xdoc-2.0.xsd">
19
20 <properties>
21 <title>Releases</title>
22 </properties>
23
24 <body>
25 <section name="Release Change Logs">
26
27 <p><a href="jira-report.html#a1.0-alpha1">JIRA change log</a></p>
28 <p><a href="changes-report.html#a1.0-alpha1">Manual change log</a></p>
29
30 <p>Apache Log4j 2 is not compatible with the previous versions. Please have the following in mind
31 when upgrading to Log4j 2 in your project:</p>
32
33 <ul>
34 <li>Log4j 2.4 and greater requires Java 7, versions 2.0-alpha1 to 2.3 required Java 6.</li>
35 <li>The XML configuration has been simplified and is not compatible with Log4j 1.x</li>
36 <li>Configuration via property files is not supported.</li>
37 <li>Configuration via JSON or YAML is supported.</li>
38 <li>Although Log4j 2 is not directly compatible with Log4j 1.x a compatibility bridge
39 has been provided to reduce the need to make coding changes.</li>
40 </ul>
41
42 </section>
43 </body>
44 </document>
2727 <li><a href="#which_jars">Which JAR files do I need?</a></li>
2828 <li><a href="#config_location">How do I specify the configuration file location?</a></li>
2929 <li><a href="#config_from_code">How do I configure log4j2 in code without a configuration file?</a></li>
30 <li><a href="#reconfig_from_code">How do I reconfigure log4j2 in code with a specific configuration file?</a></li>
31 <li><a href="#set_logger_level_from_code">How do I change a logger's level in code?</a></li>
32 <li><a href="#shutdown">How do I shut down log4j2 in code?</a></li>
3033 <li><a href="#config_sep_appender_level">How do I send log messages with different levels to different appenders?</a></li>
3134 <li><a href="#troubleshooting">How do I debug my configuration?</a></li>
3235 <li><a href="#separate_log_files">How do I dynamically write to separate log files?</a></li>
36 <li><a href="#reconfig_level_from_code">How do I set a logger's level programmatically?</a></li>
3337 <!--
3438 <li><a href="#custom_plugin">How do I get log4j2 to recognize my custom plugin?</a></li>
3539 -->
6569 (You can pass null for the class loader.)
6670 Be aware that this class is not part of the public API so your code may break with any minor release.</p>
6771
72 <a name="reconfig_from_code" />
73 <h4>How do I reconfigure log4j2 in code with a specific configuration file?</h4>
74 <p>See the below example.
75 Be aware that this LoggerContext class is not part of the public API so your code may break with any minor release.</p>
76 <pre class="prettyprint linenums">// import org.apache.logging.log4j.core.LoggerContext;
77
78 LoggerContext context = (org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false);
79 File file = new File("path/to/a/different/log4j2.xml");
80
81 // this will force a reconfiguration
82 context.setConfigLocation(file.toURI());
83 </pre>
84
85 <a name="set_logger_level_from_code" />
86 <h4>How do I change a logger's level in code?</h4>
87 <p>See the below example.
88 Be aware that these classes are not part of the public API so your code may break with any minor release.</p>
89 <pre class="prettyprint linenums">// import org.apache.logging.log4j.core.LoggerContext;
90 // import org.apache.logging.log4j.core.config.Configuration;
91 // import org.apache.logging.log4j.core.config.LoggerConfig;
92
93 LoggerContext context = (LoggerContext) LogManager.getContext(false);
94 Configuration config = context.getConfiguration();
95 LoggerConfig rootConfig = config.getLoggerConfig(LogManager.ROOT_LOGGER_NAME);
96 rootConfig.setLevel(Level.DEBUG);
97
98 // You could also specify the actual logger name as below
99 // and it will return the LoggerConfig used by the Logger.
100 LoggerConfig loggerConfig = config.getLoggerConfig("com.apache.test");
101 loggerConfig.setLevel(Level.TRACE);
102
103 // This causes all Loggers to refetch information from their LoggerConfig.
104 context.updateLoggers();
105 </pre>
106
107 <a name="shutdown" />
108 <h4>How do I shut down log4j2 in code?</h4>
109 <p>Normally there is no need to do this manually.
110 Each LoggerContext registers a shutdown hook that takes care of releasing resources
111 when the JVM exits (unless system property <code>log4j.shutdownHookEnabled</code>
112 is set to <code>false</code>).
113 Web applications should include the log4j-web
114 module in their classpath which disables the shutdown hook but instead
115 cleans up log4j resources when the web application is stopped.</p>
116 <p>However, if you need to manually shut down log4j, you can do so
117 as in the below example.
118 Be aware that these classes are not part of the public API so your code may break with any minor release.</p>
119 <pre class="prettyprint linenums">// import org.apache.logging.log4j.core.LoggerContext;
120 // import org.apache.logging.log4j.core.config.Configurator;
121
122 // get the current context
123 LoggerContext context = (LoggerContext) LogManager.getContext();
124 Configurator.shutdown(context);</pre>
125
68126 <a name="config_sep_appender_level" />
69127 <h4>How do I send log messages with different levels to different appenders?</h4>
70128 You don't need to declare separate loggers to achieve this.
168226 </Routes>
169227 </Routing>]]></pre>
170228
229 <a name="reconfig_level_from_code" />
230 <h4>How do I set a logger's level programmatically?</h4>
231 <p>You can set a logger's level with the class Configurator from Core module.
232 Be aware that the Configuration class is not part of the public API.</p>
233 <pre class="prettyprint linenums">// org.apache.logging.log4j.core.config.Configurator;
234
235 Configurator.setLevel("com.example.Foo", Level.DEBUG);
236
237 // You can also set the root logger:
238 Configurator.setRootLevel(Level.DEBUG);
239 </pre>
171240
172241 <!--
173242 <a name="custom_plugin" />
8787 Map, and data present in the event. Users can further customize the property providers by
8888 adding their own <a href="manual/lookups.html">Lookup</a> Plugin.
8989 </dd>
90 <dt>Java 8 Lambda Support</dt>
91 <dd>
92 Previously, if a log message was expensive to construct, you would often explicitly check if the
93 requested log level is enabled before constructing the message.
94 Client code running on Java 8 can benefit from Log4j's <a href="manual/api.html#LambdaSupport">lambda
95 support</a>. Since Log4j will not evaluate a lambda
96 expression if the requested log level is not enabled, the same effect can be achieved with less code.
97 </dd>
9098 </dl>
9199
92100 <subsection name="Documentation">
98106
99107 <subsection name="Requirements">
100108 <p>
101 Log4j 2 requires Java 6.
109 Log4j 2.4 and greater requires Java 7, versions 2.0-alpha1 to 2.3 required Java 6.
102110 Some features require optional dependencies; the documentation for these features specifies the
103111 dependencies.
104112 </p>
113113 logger.debug("Opening connection to {}...", someDataSource);
114114 logger.printf(Level.INFO, "Logging in user %1$s with birthday %2$tm %2$te,%2$tY", user.getName(), user.getBirthdayCalendar());
115115 </pre>
116
117 <a name="LambdaSupport"/>
118 <h4>Java 8 lambda support for lazy logging</h4>
119 <p>
120 In release 2.4, the <code>Logger</code> interface adds support for lambda expressions.
121 This allows client code to lazily log messages without explicitly checking if the requested log
122 level is enabled. For example, previously you would write:
123 </p>
124 <pre class="prettyprint linenums">// pre-Java 8 style optimization: explicitly check the log level
125 // to make sure the expensiveOperation() method is only called if necessary
126 if (logger.isTraceEnabled()) {
127 logger.trace(&quot;Some long-running operation returned {}&quot;, expensiveOperation());
128 }</pre>
129 <p>
130 With Java 8 you can achieve the same effect with a lambda expression.
131 You no longer need to explicitly check the log level:
132 </p>
133 <pre class="prettyprint linenums">// Java-8 style optimization: no need to explicitly check the log level:
134 // the lambda expression is not evaluated if the TRACE level is not enabled
135 logger.trace(&quot;Some long-running operation returned {}&quot;, () -> expensiveOperation());</pre>
136
116137 <h4>Logger Names</h4>
117138 <p>
118139 Most logging implementations use a hierarchical scheme for matching logger names with logging
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17
18 <document xmlns="http://maven.apache.org/XDOC/2.0"
19 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20 xsi:schemaLocation="http://maven.apache.org/XDOC/2.0 http://maven.apache.org/xsd/xdoc-2.0.xsd">
21 <properties>
22 <title>Log4j 2 Appenders</title>
23 <author email="rgoers@apache.org">Ralph Goers</author>
24 <author email="ggrgeory@apache.org">Gary Gregory</author>
25 <author email="nickwilliams@apache.org">Nick Williams</author>
26 </properties>
27
28 <body>
29 <section name="Appenders">
30 <p>
31 Appenders are responsible for delivering LogEvents to their destination. Every Appender must
32 implement the <a href="../log4j-core/apidocs/org/apache/logging/log4j/core/Appender.html">Appender</a>
33 interface. Most Appenders will extend
34 <a href="../log4j-core/apidocs/org/apache/logging/log4j/core/appender/AbstractAppender.html">AbstractAppender</a>
35 which adds <a href="../log4j-core/apidocs/org/apache/logging/log4j/core/LifeCycle.html">Lifecycle</a>
36 and <a href="../log4j-core/apidocs/org/apache/logging/log4j/core/filter/Filterable.html">Filterable</a>
37 support. Lifecycle allows components to finish initialization after configuration has completed and to
38 perform cleanup during shutdown. Filterable allows the component to have Filters attached to it which are
39 evaluated during event processing.
40 </p>
41 <p>
42 Appenders usually are only responsible for writing the event data to the target destination. In most cases
43 they delegate responsibility for formatting the event to a <a href="layouts.html">layout</a>. Some
44 appenders wrap other appenders so that they can modify the LogEvent, handle a failure in an Appender,
45 route the event to a subordinate Appender based on advanced Filter criteria or provide similar functionality
46 that does not directly format the event for viewing.
47 </p>
48 <p>
49 Appenders always have a name so that they can be referenced from Loggers.
50 </p>
51 <a name="AsyncAppender"/>
52 <subsection name="AsyncAppender">
53 <p>The AsyncAppender accepts references to other Appenders and causes LogEvents to be written to them
54 on a separate Thread. Note that exceptions while writing to those Appenders will be hidden from
55 the application. The AsyncAppender should be configured after the appenders it references to allow it
56 to shut down properly.</p>
57 <table>
58 <caption align="top">AsyncAppender Parameters</caption>
59 <tr>
60 <th>Parameter Name</th>
61 <th>Type</th>
62 <th>Description</th>
63 </tr>
64 <tr>
65 <td>AppenderRef</td>
66 <td>String</td>
67 <td>The name of the Appenders to invoke asynchronously. Multiple AppenderRef
68 elements can be configured.</td>
69 </tr>
70 <tr>
71 <td>blocking</td>
72 <td>boolean</td>
73 <td>If true, the appender will wait until there are free slots in the queue. If false, the event
74 will be written to the error appender if the queue is full. The default is true.</td>
75 </tr>
76 <tr>
77 <td>bufferSize</td>
78 <td>integer</td>
79 <td>Specifies the maximum number of events that can be queued. The default is 128.</td>
80 </tr>
81 <tr>
82 <td>errorRef</td>
83 <td>String</td>
84 <td>The name of the Appender to invoke if none of the appenders can be called, either due to errors
85 in the appenders or because the queue is full. If not specified then errors will be ignored.</td>
86 </tr>
87 <tr>
88 <td>filter</td>
89 <td>Filter</td>
90 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
91 may be used by using a CompositeFilter.</td>
92 </tr>
93 <tr>
94 <td>name</td>
95 <td>String</td>
96 <td>The name of the Appender.</td>
97 </tr>
98 <tr>
99 <td>ignoreExceptions</td>
100 <td>boolean</td>
101 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
102 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
103 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
104 <a href="#FailoverAppender">FailoverAppender</a>.</td>
105 </tr>
106 <tr>
107 <td>includeLocation</td>
108 <td>boolean</td>
109 <td>Extracting location is an expensive operation (it can make
110 logging 5 - 20 times slower). To improve performance, location is
111 not included by default when adding a log event to the queue.
112 You can change this by setting includeLocation="true".</td>
113 </tr>
114 </table>
115 <p>
116 A typical AsyncAppender configuration might look like:
117 </p>
118
119 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
120 <Configuration status="warn" name="MyApp" packages="">
121 <Appenders>
122 <File name="MyFile" fileName="logs/app.log">
123 <PatternLayout>
124 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
125 </PatternLayout>
126 </File>
127 <Async name="Async">
128 <AppenderRef ref="MyFile"/>
129 </Async>
130 </Appenders>
131 <Loggers>
132 <Root level="error">
133 <AppenderRef ref="Async"/>
134 </Root>
135 </Loggers>
136 </Configuration>]]></pre>
137 </subsection>
138 <a name="ConsoleAppender"/>
139 <subsection name="ConsoleAppender">
140 <p>
141 As one might expect, the ConsoleAppender writes its output to either System.err or System.out with System.err
142 being the default target. A Layout must be provided to format the LogEvent.
143 </p>
144 <table>
145 <caption align="top">ConsoleAppender Parameters</caption>
146 <tr>
147 <th>Parameter Name</th>
148 <th>Type</th>
149 <th>Description</th>
150 </tr>
151 <tr>
152 <td>filter</td>
153 <td>Filter</td>
154 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
155 may be used by using a CompositeFilter.</td>
156 </tr>
157 <tr>
158 <td>layout</td>
159 <td>Layout</td>
160 <td>The Layout to use to format the LogEvent. If no layout is supplied the default pattern layout
161 of "%m%n" will be used.</td>
162 </tr>
163 <tr>
164 <td>follow</td>
165 <td>boolean</td>
166 <td>Identifies whether the appender honors reassignments of System.out or System.err
167 via System.setOut or System.setErr made after configuration. Note that the follow
168 attribute cannot be used with Jansi on Windows.</td>
169 </tr>
170 <tr>
171 <td>name</td>
172 <td>String</td>
173 <td>The name of the Appender.</td>
174 </tr>
175 <tr>
176 <td>ignoreExceptions</td>
177 <td>boolean</td>
178 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
179 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
180 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
181 <a href="#FailoverAppender">FailoverAppender</a>.</td>
182 </tr>
183 <tr>
184 <td>target</td>
185 <td>String</td>
186 <td>Either "SYSTEM_OUT" or "SYSTEM_ERR". The default is "SYSTEM_ERR".</td>
187 </tr>
188 </table>
189 <p>
190 A typical Console configuration might look like:
191 </p>
192
193 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
194 <Configuration status="warn" name="MyApp" packages="">
195 <Appenders>
196 <Console name="STDOUT" target="SYSTEM_OUT">
197 <PatternLayout pattern="%m%n"/>
198 </Console>
199 </Appenders>
200 <Loggers>
201 <Root level="error">
202 <AppenderRef ref="STDOUT"/>
203 </Root>
204 </Loggers>
205 </Configuration>]]></pre>
206 </subsection>
207 <a name="FailoverAppender"/>
208 <subsection name="FailoverAppender">
209 <p>The FailoverAppender wraps a set of appenders. If the primary Appender fails the secondary appenders will be
210 tried in order until one succeeds or there are no more secondaries to try.</p>
211 <table>
212 <caption align="top">FailoverAppender Parameters</caption>
213 <tr>
214 <th>Parameter Name</th>
215 <th>Type</th>
216 <th>Description</th>
217 </tr>
218 <tr>
219 <td>filter</td>
220 <td>Filter</td>
221 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
222 may be used by using a CompositeFilter.</td>
223 </tr>
224 <tr>
225 <td>primary</td>
226 <td>String</td>
227 <td>The name of the primary Appender to use.</td>
228 </tr>
229 <tr>
230 <td>failovers</td>
231 <td>String[]</td>
232 <td>The names of the secondary Appenders to use.</td>
233 </tr>
234
235 <tr>
236 <td>name</td>
237 <td>String</td>
238 <td>The name of the Appender.</td>
239 </tr>
240 <tr>
241 <td>retryIntervalSeconds</td>
242 <td>integer</td>
243 <td>The number of seconds that should pass before retrying the primary Appender. The default is 60.</td>
244 </tr>
245 <tr>
246 <td>ignoreExceptions</td>
247 <td>boolean</td>
248 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
249 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
250 caller, instead.</td>
251 </tr>
252 <tr>
253 <td>target</td>
254 <td>String</td>
255 <td>Either "SYSTEM_OUT" or "SYSTEM_ERR". The default is "SYSTEM_ERR".</td>
256 </tr>
257 </table>
258 <p>
259 A Failover configuration might look like:
260 </p>
261
262 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
263 <Configuration status="warn" name="MyApp" packages="">
264 <Appenders>
265 <RollingFile name="RollingFile" fileName="logs/app.log" filePattern="logs/app-%d{MM-dd-yyyy}.log.gz"
266 ignoreExceptions="false">
267 <PatternLayout>
268 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
269 </PatternLayout>
270 <TimeBasedTriggeringPolicy />
271 </RollingFile>
272 <Console name="STDOUT" target="SYSTEM_OUT" ignoreExceptions="false">
273 <PatternLayout pattern="%m%n"/>
274 </Console>
275 <Failover name="Failover" primary="RollingFile">
276 <Failovers>
277 <AppenderRef ref="Console"/>
278 </Failovers>
279 </Failover>
280 </Appenders>
281 <Loggers>
282 <Root level="error">
283 <AppenderRef ref="Failover"/>
284 </Root>
285 </Loggers>
286 </Configuration>]]></pre>
287 </subsection>
288 <a name="FileAppender"/>
289 <subsection name="FileAppender">
290 <p>The FileAppender is an OutputStreamAppender that writes to the File named in the fileName parameter. The
291 FileAppender uses a FileManager (which extends OutputStreamManager) to actually perform the file I/O. While
292 FileAppenders from different Configurations cannot be shared, the FileManagers can be if the Manager is
293 accessible. For example, two web applications in a servlet container can have their own configuration and
294 safely write to the same file if Log4j is in a ClassLoader that is common to both of them.</p>
295 <table>
296 <caption align="top">FileAppender Parameters</caption>
297 <tr>
298 <th>Parameter Name</th>
299 <th>Type</th>
300 <th>Description</th>
301 </tr>
302 <tr>
303 <td>append</td>
304 <td>boolean</td>
305 <td>When true - the default, records will be appended to the end of the file. When set to false,
306 the file will be cleared before new records are written.</td>
307 </tr>
308 <tr>
309 <td>bufferedIO</td>
310 <td>boolean</td>
311 <td>When true - the default, records will be written to a buffer and the data will be written to
312 disk when the buffer is full or, if immediateFlush is set, when the record is written.
313 File locking cannot be used with bufferedIO. Performance tests have shown that using buffered I/O
314 significantly improves performance, even if immediateFlush is enabled.</td>
315 </tr>
316 <tr>
317 <td>bufferSize</td>
318 <td>int</td>
319 <td>When bufferedIO is true, this is the buffer size, the default is 8192 bytes.</td>
320 </tr>
321 <tr>
322 <td>filter</td>
323 <td>Filter</td>
324 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
325 may be used by using a CompositeFilter.</td>
326 </tr>
327 <tr>
328 <td>fileName</td>
329 <td>String</td>
330 <td>The name of the file to write to. If the file, or any of its parent directories, do not exist,
331 they will be created.</td>
332 </tr>
333 <tr>
334 <td>immediateFlush</td>
335 <td>boolean</td>
336 <td><p>When set to true - the default, each write will be followed by a flush.
337 This will guarantee the data is written
338 to disk but could impact performance.</p>
339 <p>Flushing after every write is only useful when using this
340 appender with synchronous loggers. Asynchronous loggers and
341 appenders will automatically flush at the end of a batch of events,
342 even if immediateFlush is set to false. This also guarantees
343 the data is written to disk but is more efficient.</p>
344 </td>
345 </tr>
346 <tr>
347 <td>layout</td>
348 <td>Layout</td>
349 <td>The Layout to use to format the LogEvent</td>
350 </tr>
351 <tr>
352 <td>locking</td>
353 <td>boolean</td>
354 <td>When set to true, I/O operations will occur only while the file lock is held allowing FileAppenders
355 in multiple JVMs and potentially multiple hosts to write to the same file simultaneously. This
356 will significantly impact performance so should be used carefully. Furthermore, on many systems
357 the file lock is "advisory" meaning that other applications can perform operations on the file
358 without acquiring a lock. The default value is false.</td>
359 </tr>
360
361 <tr>
362 <td>name</td>
363 <td>String</td>
364 <td>The name of the Appender.</td>
365 </tr>
366 <tr>
367 <td>ignoreExceptions</td>
368 <td>boolean</td>
369 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
370 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
371 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
372 <a href="#FailoverAppender">FailoverAppender</a>.</td>
373 </tr>
374 </table>
375 <p>
376 Here is a sample File configuration:
377 </p>
378
379 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
380 <Configuration status="warn" name="MyApp" packages="">
381 <Appenders>
382 <File name="MyFile" fileName="logs/app.log">
383 <PatternLayout>
384 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
385 </PatternLayout>
386 </File>
387 </Appenders>
388 <Loggers>
389 <Root level="error">
390 <AppenderRef ref="MyFile"/>
391 </Root>
392 </Loggers>
393 </Configuration>]]></pre>
394 </subsection>
395 <a name="FlumeAppender"/>
396 <subsection name="FlumeAppender">
397 <p><i>This is an optional component supplied in a separate jar.</i></p>
398 <p><a href="http://flume.apache.org/index.html">Apache Flume</a> is a distributed, reliable,
399 and available system for efficiently collecting, aggregating, and moving large amounts of log data
400 from many different sources to a centralized data store. The FlumeAppender takes LogEvents and sends
401 them to a Flume agent as serialized Avro events for consumption.</p>
402 <p>
403 The Flume Appender supports three modes of operation.
404 </p>
405 <ol>
406 <li>It can act as a remote Flume client which sends Flume events via Avro to a Flume Agent configured
407 with an Avro Source.</li>
408 <li>It can act as an embedded Flume Agent where Flume events pass directly into Flume for processing.</li>
409 <li>It can persist events to a local BerkeleyDB data store and then asynchronously send the events to
410 Flume, similar to the embedded Flume Agent but without most of the Flume dependencies.</li>
411 </ol>
412 <p>
413 Usage as an embedded agent will cause the messages to be directly passed to the Flume Channel and then
414 control will be immediately returned to the application. All interaction with remote agents will occur
415 asynchronously. Setting the "type" attribute to "Embedded" will force the use of the embedded agent. In
416 addition, configuring agent properties in the appender configuration will also cause the embedded agent
417 to be used.
418 </p>
419 <table>
420 <caption align="top">FlumeAppender Parameters</caption>
421 <tr>
422 <th>Parameter Name</th>
423 <th>Type</th>
424 <th>Description</th>
425 </tr>
426 <tr>
427 <td>agents</td>
428 <td>Agent[]</td>
429 <td>An array of Agents to which the logging events should be sent. If more than one agent is specified
430 the first Agent will be the primary and subsequent Agents will be used in the order specified as
431 secondaries should the primary Agent fail. Each Agent definition supplies the Agents host and port.
432 The specification of agents and properties are mutually exclusive. If both are configured an
433 error will result.</td>
434 </tr>
435 <tr>
436 <td>agentRetries</td>
437 <td>integer</td>
438 <td>The number of times the agent should be retried before failing to a secondary. This parameter is
439 ignored when type="persistent" is specified (agents are tried once before failing to the next).</td>
440 </tr>
441 <tr>
442 <td>batchSize</td>
443 <td>integer</td>
444 <td>Specifies the number of events that should be sent as a batch. The default is 1. <i>This
445 parameter only applies to the Flume Appender.</i></td>
446 </tr>
447 <tr>
448 <td>compress</td>
449 <td>boolean</td>
450 <td>When set to true the message body will be compressed using gzip</td>
451 </tr>
452 <tr>
453 <td>connectTimeoutMillis</td>
454 <td>integer</td>
455 <td>The number of milliseconds Flume will wait before timing out the connection.</td>
456 </tr>
457 <tr>
458 <td>dataDir</td>
459 <td>String</td>
460 <td>Directory where the Flume write ahead log should be written. Valid only when embedded is set
461 to true and Agent elements are used instead of Property elements.</td>
462 </tr>
463 <tr>
464 <td>filter</td>
465 <td>Filter</td>
466 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
467 may be used by using a CompositeFilter.</td>
468 </tr>
469 <tr>
470 <td>eventPrefix</td>
471 <td>String</td>
472 <td>The character string to prepend to each event attribute in order to distinguish it from MDC attributes.
473 The default is an empty string.</td>
474 </tr>
475 <tr>
476 <td>flumeEventFactory</td>
477 <td>FlumeEventFactory</td>
478 <td>Factory that generates the Flume events from Log4j events. The default factory is the
479 FlumeAvroAppender itself.</td>
480 </tr>
481 <tr>
482 <td>layout</td>
483 <td>Layout</td>
484 <td>The Layout to use to format the LogEvent. If no layout is specified RFC5424Layout will be used.</td>
485 </tr>
486 <tr>
487 <td>lockTimeoutRetries</td>
488 <td>integer</td>
489 <td>The number of times to retry if a LockConflictException occurs while writing to Berkeley DB. The
490 default is 5.</td>
491 </tr>
492 <tr>
493 <td>maxDelayMillis</td>
494 <td>integer</td>
495 <td>The maximum number of milliseconds to wait for batchSize events before publishing the batch.</td>
496 </tr>
497 <tr>
498 <td>mdcExcludes</td>
499 <td>String</td>
500 <td>A comma separated list of mdc keys that should be excluded from the FlumeEvent. This is mutually
501 exclusive with the mdcIncludes attribute.</td>
502 </tr>
503 <tr>
504 <td>mdcIncludes</td>
505 <td>String</td>
506 <td>A comma separated list of mdc keys that should be included in the FlumeEvent. Any keys in the MDC
507 not found in the list will be excluded. This option is mutually exclusive with the mdcExcludes
508 attribute.</td>
509 </tr>
510 <tr>
511 <td>mdcRequired</td>
512 <td>String</td>
513 <td>A comma separated list of mdc keys that must be present in the MDC. If a key is not present a
514 LoggingException will be thrown.</td>
515 </tr>
516 <tr>
517 <td>mdcPrefix</td>
518 <td>String</td>
519 <td>A string that should be prepended to each MDC key in order to distinguish it from event attributes.
520 The default string is "mdc:".</td>
521 </tr>
522 <tr>
523 <td>name</td>
524 <td>String</td>
525 <td>The name of the Appender.</td>
526 </tr>
527 <tr>
528 <td>properties</td>
529 <td>Property[]</td>
530 <td><p>One or more Property elements that are used to configure the Flume Agent. The properties must be
531 configured without the agent name (the appender name is used for this) and no sources can be
532 configured. Interceptors can be specified for the source using "sources.log4j-source.interceptors".
533 All other Flume configuration properties are allowed. Specifying both Agent and Property
534 elements will result in an error.</p>
535 <p>When used to configure in Persistent mode the valid properties are:</p>
536 <ol>
537 <li>"keyProvider" to specify the name of the plugin to provide the secret key for encryption.</li>
538 </ol>
539 </td>
540 </tr>
541 <tr>
542 <td>requestTimeoutMillis</td>
543 <td>integer</td>
544 <td>The number of milliseconds Flume will wait before timing out the request.</td>
545 </tr>
546 <tr>
547 <td>ignoreExceptions</td>
548 <td>boolean</td>
549 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
550 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
551 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
552 <a href="#FailoverAppender">FailoverAppender</a>.</td>
553 </tr>
554 <tr>
555 <td>type</td>
556 <td>enumeration</td>
557 <td>One of "Avro", "Embedded", or "Persistent" to indicate which variation of the Appender is desired.</td>
558 </tr>
559 </table>
560 <p>
561 A sample FlumeAppender configuration that is configured with a primary and a secondary agent,
562 compresses the body, and formats the body using the RFC5424Layout:
563 </p>
564
565 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
566 <Configuration status="warn" name="MyApp" packages="">
567 <Appenders>
568 <Flume name="eventLogger" compress="true">
569 <Agent host="192.168.10.101" port="8800"/>
570 <Agent host="192.168.10.102" port="8800"/>
571 <RFC5424Layout enterpriseNumber="18060" includeMDC="true" appName="MyApp"/>
572 </Flume>
573 </Appenders>
574 <Loggers>
575 <Root level="error">
576 <AppenderRef ref="eventLogger"/>
577 </Root>
578 </Loggers>
579 </Configuration>]]></pre>
580 <p>
581 A sample FlumeAppender configuration that is configured with a primary and a secondary agent,
582 compresses the body, formats the body using the RFC5424Layout, and persists encrypted events to disk:
583 </p>
584
585 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
586 <Configuration status="warn" name="MyApp" packages="">
587 <Appenders>
588 <Flume name="eventLogger" compress="true" type="persistent" dataDir="./logData">
589 <Agent host="192.168.10.101" port="8800"/>
590 <Agent host="192.168.10.102" port="8800"/>
591 <RFC5424Layout enterpriseNumber="18060" includeMDC="true" appName="MyApp"/>
592 <Property name="keyProvider">MySecretProvider</Property>
593 </Flume>
594 </Appenders>
595 <Loggers>
596 <Root level="error">
597 <AppenderRef ref="eventLogger"/>
598 </Root>
599 </Loggers>
600 </Configuration>]]></pre>
601 <p>
602 A sample FlumeAppender configuration that is configured with a primary and a secondary agent,
603 compresses the body, formats the body using RFC5424Layout and passes the events to an embedded Flume
604 Agent.
605 </p>
606 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
607 <Configuration status="warn" name="MyApp" packages="">
608 <Appenders>
609 <Flume name="eventLogger" compress="true" type="Embedded">
610 <Agent host="192.168.10.101" port="8800"/>
611 <Agent host="192.168.10.102" port="8800"/>
612 <RFC5424Layout enterpriseNumber="18060" includeMDC="true" appName="MyApp"/>
613 </Flume>
614 <Console name="STDOUT">
615 <PatternLayout pattern="%d [%p] %c %m%n"/>
616 </Console>
617 </Appenders>
618 <Loggers>
619 <Logger name="EventLogger" level="info">
620 <AppenderRef ref="eventLogger"/>
621 </Logger>
622 <Root level="warn">
623 <AppenderRef ref="STDOUT"/>
624 </Root>
625 </Loggers>
626 </Configuration>]]></pre>
627 <p>
628 A sample FlumeAppender configuration that is configured with a primary and a secondary agent using
629 Flume configuration properties, compresses the body, formats the body using RFC5424Layout and passes the
630 events to an embedded Flume Agent.
631 </p>
632 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
633 <Configuration status="error" name="MyApp" packages="">
634 <Appenders>
635 <Flume name="eventLogger" compress="true" type="Embedded">
636 <Property name="channels">file</Property>
637 <Property name="channels.file.type">file</Property>
638 <Property name="channels.file.checkpointDir">target/file-channel/checkpoint</Property>
639 <Property name="channels.file.dataDirs">target/file-channel/data</Property>
640 <Property name="sinks">agent1 agent2</Property>
641 <Property name="sinks.agent1.channel">file</Property>
642 <Property name="sinks.agent1.type">avro</Property>
643 <Property name="sinks.agent1.hostname">192.168.10.101</Property>
644 <Property name="sinks.agent1.port">8800</Property>
645 <Property name="sinks.agent1.batch-size">100</Property>
646 <Property name="sinks.agent2.channel">file</Property>
647 <Property name="sinks.agent2.type">avro</Property>
648 <Property name="sinks.agent2.hostname">192.168.10.102</Property>
649 <Property name="sinks.agent2.port">8800</Property>
650 <Property name="sinks.agent2.batch-size">100</Property>
651 <Property name="sinkgroups">group1</Property>
652 <Property name="sinkgroups.group1.sinks">agent1 agent2</Property>
653 <Property name="sinkgroups.group1.processor.type">failover</Property>
654 <Property name="sinkgroups.group1.processor.priority.agent1">10</Property>
655 <Property name="sinkgroups.group1.processor.priority.agent2">5</Property>
656 <RFC5424Layout enterpriseNumber="18060" includeMDC="true" appName="MyApp"/>
657 </Flume>
658 <Console name="STDOUT">
659 <PatternLayout pattern="%d [%p] %c %m%n"/>
660 </Console>
661 </Appenders>
662 <Loggers>
663 <Logger name="EventLogger" level="info">
664 <AppenderRef ref="eventLogger"/>
665 </Logger>
666 <Root level="warn">
667 <AppenderRef ref="STDOUT"/>
668 </Root>
669 </Loggers>
670 </Configuration>]]></pre>
671 </subsection>
672 <a name="JDBCAppender"/>
673 <subsection name="JDBCAppender">
674 <p>The JDBCAppender writes log events to a relational database table using standard JDBC. It can be configured
675 to obtain JDBC connections using a JNDI <code>DataSource</code> or a custom factory method. Whichever
676 approach you take, it <strong><em>must</em></strong> be backed by a connection pool. Otherwise, logging
677 performance will suffer greatly.</p>
678 <table>
679 <caption align="top">JDBCAppender Parameters</caption>
680 <tr>
681 <th>Parameter Name</th>
682 <th>Type</th>
683 <th>Description</th>
684 </tr>
685 <tr>
686 <td>name</td>
687 <td>String</td>
688 <td><em>Required.</em> The name of the Appender.</td>
689 </tr>
690 <tr>
691 <td>ignoreExceptions</td>
692 <td>boolean</td>
693 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
694 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
695 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
696 <a href="#FailoverAppender">FailoverAppender</a>.</td>
697 </tr>
698 <tr>
699 <td>filter</td>
700 <td>Filter</td>
701 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter may be
702 used by using a CompositeFilter.</td>
703 </tr>
704 <tr>
705 <td>bufferSize</td>
706 <td>int</td>
707 <td>If an integer greater than 0, this causes the appender to buffer log events and flush whenever the
708 buffer reaches this size.</td>
709 </tr>
710 <tr>
711 <td>connectionSource</td>
712 <td>ConnectionSource</td>
713 <td><em>Required.</em> The connections source from which database connections should be retrieved.</td>
714 </tr>
715 <tr>
716 <td>tableName</td>
717 <td>String</td>
718 <td><em>Required.</em> The name of the database table to insert log events into.</td>
719 </tr>
720 <tr>
721 <td>columnConfigs</td>
722 <td>ColumnConfig[]</td>
723 <td><em>Required.</em> Information about the columns that log event data should be inserted into and how
724 to insert that data. This is represented with multiple <code>&lt;Column&gt;</code> elements.</td>
725 </tr>
726 </table>
727 <p>When configuring the JDBCAppender, you must specify a <code>ConnectionSource</code> implementation from
728 which the Appender gets JDBC connections. You must use exactly one of the <code>&lt;DataSource&gt;</code>
729 or <code>&lt;ConnectionFactory&gt;</code> nested elements.</p>
730 <table>
731 <caption align="top">DataSource Parameters</caption>
732 <tr>
733 <th>Parameter Name</th>
734 <th>Type</th>
735 <th>Description</th>
736 </tr>
737 <tr>
738 <td>jndiName</td>
739 <td>String</td>
740 <td><em>Required.</em> The full, prefixed JNDI name that the <code>javax.sql.DataSource</code> is bound
741 to, such as <code>java:/comp/env/jdbc/LoggingDatabase</code>. The <code>DataSource</code> must be backed
742 by a connection pool; otherwise, logging will be very slow.</td>
743 </tr>
744 </table>
745 <table>
746 <caption align="top">ConnectionFactory Parameters</caption>
747 <tr>
748 <th>Parameter Name</th>
749 <th>Type</th>
750 <th>Description</th>
751 </tr>
752 <tr>
753 <td>class</td>
754 <td>Class</td>
755 <td><em>Required.</em> The fully qualified name of a class containing a static factory method for
756 obtaining JDBC connections.</td>
757 </tr>
758 <tr>
759 <td>method</td>
760 <td>Method</td>
761 <td><em>Required.</em> The name of a static factory method for obtaining JDBC connections. This method
762 must have no parameters and its return type must be either <code>java.sql.Connection</code> or
763 <code>DataSource</code>. If the method returns <code>Connection</code>s, it must obtain them from a
764 connection pool (and they will be returned to the pool when Log4j is done with them); otherwise, logging
765 will be very slow. If the method returns a <code>DataSource</code>, the <code>DataSource</code> will
766 only be retrieved once, and it must be backed by a connection pool for the same reasons.</td>
767 </tr>
768 </table>
769 <p>When configuring the JDBCAppender, use the nested <code>&lt;Column&gt;</code> elements to specify which
770 columns in the table should be written to and how to write to them. The JDBCAppender uses this information
771 to formulate a <code>PreparedStatement</code> to insert records without SQL injection vulnerability.</p>
772 <table>
773 <caption align="top">Column Parameters</caption>
774 <tr>
775 <th>Parameter Name</th>
776 <th>Type</th>
777 <th>Description</th>
778 </tr>
779 <tr>
780 <td>name</td>
781 <td>String</td>
782 <td><em>Required.</em> The name of the database column.</td>
783 </tr>
784 <tr>
785 <td>pattern</td>
786 <td>String</td>
787 <td>Use this attribute to insert a value or values from the log event in this column using a
788 <code>PatternLayout</code> pattern. Simply specify any legal pattern in this attribute. Either this
789 attribute, <code>literal</code>, or <code>isEventTimestamp="true"</code> must be specified, but not more
790 than one of these.</td>
791 </tr>
792 <tr>
793 <td>literal</td>
794 <td>String</td>
795 <td>Use this attribute to insert a literal value in this column. The value will be included directly in
796 the insert SQL, without any quoting (which means that if you want this to be a string, your value should
797 contain single quotes around it like this: <code>literal="'Literal String'"</code>). This is especially
798 useful for databases that don't support identity columns. For example, if you are using Oracle you could
799 specify <code>literal="NAME_OF_YOUR_SEQUENCE.NEXTVAL"</code> to insert a unique ID in an ID column.
800 Either this attribute, <code>pattern</code>, or <code>isEventTimestamp="true"</code> must be specified,
801 but not more than one of these.</td>
802 </tr>
803 <tr>
804 <td>isEventTimestamp</td>
805 <td>boolean</td>
806 <td>Use this attribute to insert the event timestamp in this column, which should be a SQL datetime. The
807 value will be inserted as a <code>java.sql.Types.TIMESTAMP</code>. Either this attribute (equal to
808 <code>true</code>), <code>pattern</code>, or <code>isEventTimestamp</code> must be specified, but not
809 more than one of these.</td>
810 </tr>
811 <tr>
812 <td>isUnicode</td>
813 <td>boolean</td>
814 <td>This attribute is ignored unless <code>pattern</code> is specified. If <code>true</code> or omitted
815 (default), the value will be inserted as unicode (<code>setNString</code> or <code>setNClob</code>).
816 Otherwise, the value will be inserted non-unicode (<code>setString</code> or <code>setClob</code>).</td>
817 </tr>
818 <tr>
819 <td>isClob</td>
820 <td>boolean</td>
821 <td>This attribute is ignored unless <code>pattern</code> is specified. Use this attribute to indicate
822 that the column stores Character Large Objects (CLOBs). If <code>true</code>, the value will be inserted
823 as a CLOB (<code>setClob</code> or <code>setNClob</code>). If <code>false</code> or omitted (default),
824 the value will be inserted as a VARCHAR or NVARCHAR (<code>setString</code> or <code>setNString</code>).
825 </td>
826 </tr>
827 </table>
828 <p>
829 Here are a couple sample configurations for the JDBCAppender, as well as a sample factory implementation
830 that uses Commons Pooling and Commons DBCP to pool database connections:
831 </p>
832
833 <pre class="prettyprint linenums lang-xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
834 <Configuration status="error">
835 <Appenders>
836 <JDBC name="databaseAppender" tableName="dbo.application_log">
837 <DataSource jndiName="java:/comp/env/jdbc/LoggingDataSource" />
838 <Column name="eventDate" isEventTimestamp="true" />
839 <Column name="level" pattern="%level" />
840 <Column name="logger" pattern="%logger" />
841 <Column name="message" pattern="%message" />
842 <Column name="exception" pattern="%ex{full}" />
843 </JDBC>
844 </Appenders>
845 <Loggers>
846 <Root level="warn">
847 <AppenderRef ref="databaseAppender"/>
848 </Root>
849 </Loggers>
850 </Configuration>]]></pre>
851
852 <pre class="prettyprint linenums lang-xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
853 <Configuration status="error">
854 <Appenders>
855 <JDBC name="databaseAppender" tableName="LOGGING.APPLICATION_LOG">
856 <ConnectionFactory class="net.example.db.ConnectionFactory" method="getDatabaseConnection" />
857 <Column name="EVENT_ID" literal="LOGGING.APPLICATION_LOG_SEQUENCE.NEXTVAL" />
858 <Column name="EVENT_DATE" isEventTimestamp="true" />
859 <Column name="LEVEL" pattern="%level" />
860 <Column name="LOGGER" pattern="%logger" />
861 <Column name="MESSAGE" pattern="%message" />
862 <Column name="THROWABLE" pattern="%ex{full}" />
863 </JDBC>
864 </Appenders>
865 <Loggers>
866 <Root level="warn">
867 <AppenderRef ref="databaseAppender"/>
868 </Root>
869 </Loggers>
870 </Configuration>]]></pre>
871 <pre class="prettyprint linenums lang-java"><![CDATA[package net.example.db;
872
873 import java.sql.Connection;
874 import java.sql.SQLException;
875 import java.util.Properties;
876
877 import javax.sql.DataSource;
878
879 import org.apache.commons.dbcp.DriverManagerConnectionFactory;
880 import org.apache.commons.dbcp.PoolableConnection;
881 import org.apache.commons.dbcp.PoolableConnectionFactory;
882 import org.apache.commons.dbcp.PoolingDataSource;
883 import org.apache.commons.pool.impl.GenericObjectPool;
884
885 public class ConnectionFactory {
886 private static interface Singleton {
887 final ConnectionFactory INSTANCE = new ConnectionFactory();
888 }
889
890 private final DataSource dataSource;
891
892 private ConnectionFactory() {
893 Properties properties = new Properties();
894 properties.setProperty("user", "logging");
895 properties.setProperty("password", "abc123"); // or get properties from some configuration file
896
897 GenericObjectPool<PoolableConnection> pool = new GenericObjectPool<PoolableConnection>();
898 DriverManagerConnectionFactory connectionFactory = new DriverManagerConnectionFactory(
899 "jdbc:mysql://example.org:3306/exampleDb", properties
900 );
901 new PoolableConnectionFactory(
902 connectionFactory, pool, null, "SELECT 1", 3, false, false, Connection.TRANSACTION_READ_COMMITTED
903 );
904
905 this.dataSource = new PoolingDataSource(pool);
906 }
907
908 public static Connection getDatabaseConnection() throws SQLException {
909 return Singleton.INSTANCE.dataSource.getConnection();
910 }
911 }]]></pre>
912 </subsection>
913 <a name="JMSAppender"/>
914 <!-- cool URLs don't change, so here are some old anchors -->
915 <a name="JMSQueueAppender"/>
916 <a name="JMSTopicAppender"/>
917 <subsection name="JMSAppender">
918 <p>The JMSAppender sends the formatted log event to a JMS Destination.</p>
919 <p>
920 Note that in Log4j 2.0, this appender was split into a JMSQueueAppender and a JMSTopicAppender. Starting
921 in Log4j 2.1, these appenders were combined into the JMSAppender which makes no distinction between queues
922 and topics. However, configurations written for 2.0 which use the <code>&lt;JMSQueue/&gt;</code> or
923 <code>&lt;JMSTopic/&gt;</code> elements will continue to work with the new <code>&lt;JMS/&gt;</code>
924 configuration element.
925 </p>
926 <table>
927 <caption align="top">JMSAppender Parameters</caption>
928 <tr>
929 <th>Parameter Name</th>
930 <th>Type</th>
931 <th>Description</th>
932 </tr>
933 <tr>
934 <td>factoryBindingName</td>
935 <td>String</td>
936 <td>The name to locate in the Context that provides the
937 <a class="javadoc" href="http://download.oracle.com/javaee/5/api/javax/jms/ConnectionFactory.html">ConnectionFactory</a>.
938 This can be any subinterface of <code>ConnectionFactory</code> as well. This attribute is required.
939 </td>
940 </tr>
941 <tr>
942 <td>factoryName</td>
943 <td>String</td>
944 <td>The fully qualified class name that should be used to define the Initial Context Factory as defined in
945 <a class="javadoc" href="http://download.oracle.com/javase/6/docs/api/javax/naming/Context.html#INITIAL_CONTEXT_FACTORY">INITIAL_CONTEXT_FACTORY</a>.
946 If no value is provided the
947 default InitialContextFactory will be used. If a factoryName is specified without a providerURL
948 a warning message will be logged as this is likely to cause problems.</td>
949 </tr>
950 <tr>
951 <td>filter</td>
952 <td>Filter</td>
953 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
954 may be used by using a CompositeFilter.</td>
955 </tr>
956 <tr>
957 <td>layout</td>
958 <td>Layout</td>
959 <td>
960 The Layout to use to format the LogEvent. If you do not specify a layout,
961 this appender will use a <a href="layouts.html#SerializedLayout">SerializedLayout</a>.
962 </td>
963 </tr>
964 <tr>
965 <td>name</td>
966 <td>String</td>
967 <td>The name of the Appender. Required.</td>
968 </tr>
969 <tr>
970 <td>password</td>
971 <td>String</td>
972 <td>The password to use to create the JMS connection.</td>
973 </tr>
974 <tr>
975 <td>providerURL</td>
976 <td>String</td>
977 <td>The URL of the provider to use as defined by
978 <a class="javadoc" href="http://download.oracle.com/javase/6/docs/api/javax/naming/Context.html#PROVIDER_URL">PROVIDER_URL</a>.
979 If this value is null the default system provider will be used.</td>
980 </tr>
981 <tr>
982 <td>destinationBindingName</td>
983 <td>String</td>
984 <td>
985 The name to use to locate the
986 <a class="javadoc" href="http://download.oracle.com/javaee/5/api/javax/jms/Destination.html">Destination</a>.
987 This can be a <code>Queue</code> or <code>Topic</code>, and as such, the attribute names
988 <code>queueBindingName</code> and <code>topicBindingName</code> are aliases to maintain compatibility
989 with the Log4j 2.0 JMS appenders.
990 </td>
991 </tr>
992 <tr>
993 <td>securityPrincipalName</td>
994 <td>String</td>
995 <td>The name of the identity of the Principal as specified by
996 <a class="javadoc" href="http://download.oracle.com/javase/6/docs/api/javax/naming/Context.html#SECURITY_PRINCIPAL">SECURITY_PRINCIPAL</a>.
997 If a securityPrincipalName is specified without securityCredentials a warning message will be
998 logged as this is likely to cause problems.</td>
999 </tr>
1000 <tr>
1001 <td>securityCredentials</td>
1002 <td>String</td>
1003 <td>The security credentials for the principal as specified by
1004 <a class="javadoc" href="http://download.oracle.com/javase/6/docs/api/javax/naming/Context.html#SECURITY_CREDENTIALS">SECURITY_CREDENTIALS</a>.
1005 </td>
1006 </tr>
1007 <tr>
1008 <td>ignoreExceptions</td>
1009 <td>boolean</td>
1010 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
1011 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
1012 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
1013 <a href="#FailoverAppender">FailoverAppender</a>.</td>
1014 </tr>
1015 <tr>
1016 <td>urlPkgPrefixes</td>
1017 <td>String</td>
1018 <td>A colon-separated list of package prefixes for the class name of the factory class that will create
1019 a URL context factory as defined by
1020 <a class="javadoc" href="http://download.oracle.com/javase/6/docs/api/javax/naming/Context.html#URL_PKG_PREFIXES">URL_PKG_PREFIXES</a>.
1021 </td>
1022 </tr>
1023 <tr>
1024 <td>userName</td>
1025 <td>String</td>
1026 <td>The user id used to create the JMS connection.</td>
1027 </tr>
1028 </table>
1029 <p>
1030 Here is a sample JMSAppender configuration:
1031 </p>
1032
1033 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
1034 <Configuration status="warn" name="MyApp">
1035 <Appenders>
1036 <JMS name="jmsQueue" destinationBindingName="MyQueue"
1037 factoryBindingName="MyQueueConnectionFactory"/>
1038 </Appenders>
1039 <Loggers>
1040 <Root level="error">
1041 <AppenderRef ref="jmsQueue"/>
1042 </Root>
1043 </Loggers>
1044 </Configuration>]]></pre>
1045 </subsection>
1046 <a name="JPAAppender"/>
1047 <subsection name="JPAAppender">
1048 <p>The JPAAppender writes log events to a relational database table using the Java Persistence API 2.1.
1049 It requires the API and a provider implementation be on the classpath. It also requires a decorated entity
1050 configured to persist to the table desired. The entity should either extend
1051 <code>org.apache.logging.log4j.core.appender.db.jpa.BasicLogEventEntity</code> (if you mostly want to
1052 use the default mappings) and provide at least an <code>@Id</code> property, or
1053 <code>org.apache.logging.log4j.core.appender.db.jpa.AbstractLogEventWrapperEntity</code> (if you want
1054 to significantly customize the mappings). See the Javadoc for these two classes for more information. You
1055 can also consult the source code of these two classes as an example of how to implement the entity.</p>
1056 <table>
1057 <caption align="top">JPAAppender Parameters</caption>
1058 <tr>
1059 <th>Parameter Name</th>
1060 <th>Type</th>
1061 <th>Description</th>
1062 </tr>
1063 <tr>
1064 <td>name</td>
1065 <td>String</td>
1066 <td><em>Required.</em> The name of the Appender.</td>
1067 </tr>
1068 <tr>
1069 <td>ignoreExceptions</td>
1070 <td>boolean</td>
1071 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
1072 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
1073 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
1074 <a href="#FailoverAppender">FailoverAppender</a>.</td>
1075 </tr>
1076 <tr>
1077 <td>filter</td>
1078 <td>Filter</td>
1079 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter may be
1080 used by using a CompositeFilter.</td>
1081 </tr>
1082 <tr>
1083 <td>bufferSize</td>
1084 <td>int</td>
1085 <td>If an integer greater than 0, this causes the appender to buffer log events and flush whenever the
1086 buffer reaches this size.</td>
1087 </tr>
1088 <tr>
1089 <td>entityClassName</td>
1090 <td>String</td>
1091 <td><em>Required.</em> The fully qualified name of the concrete LogEventWrapperEntity implementation that
1092 has JPA annotations mapping it to a database table.</td>
1093 </tr>
1094 <tr>
1095 <td>persistenceUnitName</td>
1096 <td>String</td>
1097 <td><em>Required.</em> The name of the JPA persistence unit that should be used for persisting log
1098 events.</td>
1099 </tr>
1100 </table>
1101 <p>
1102 Here is a sample configuration for the JPAAppender. The first XML sample is the Log4j configuration file,
1103 the second is the <code>persistence.xml</code> file. EclipseLink is assumed here, but any JPA 2.1 or higher
1104 provider will do. You should <em>always</em> create a <em>separate</em> persistence unit for logging, for
1105 two reasons. First, <code>&lt;shared-cache-mode&gt;</code> <em>must</em> be set to "NONE," which is usually
1106 not desired in normal JPA usage. Also, for performance reasons the logging entity should be isolated in its
1107 own persistence unit away from all other entities and you should use a non-JTA data source. Note that your
1108 persistence unit <em>must</em> also contain <code>&lt;class&gt;</code> elements for all of the
1109 <code>org.apache.logging.log4j.core.appender.db.jpa.converter</code> converter classes.
1110 </p>
1111
1112 <pre class="prettyprint linenums lang-xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
1113 <Configuration status="error">
1114 <Appenders>
1115 <JPA name="databaseAppender" persistenceUnitName="loggingPersistenceUnit"
1116 entityClassName="com.example.logging.JpaLogEntity" />
1117 </Appenders>
1118 <Loggers>
1119 <Root level="warn">
1120 <AppenderRef ref="databaseAppender"/>
1121 </Root>
1122 </Loggers>
1123 </Configuration>]]></pre>
1124
1125 <pre class="prettyprint linenums lang-xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
1126 <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
1127 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
1128 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
1129 http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
1130 version="2.1">
1131
1132 <persistence-unit name="loggingPersistenceUnit" transaction-type="RESOURCE_LOCAL">
1133 <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
1134 <class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapAttributeConverter</class>
1135 <class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapJsonAttributeConverter</class>
1136 <class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackAttributeConverter</class>
1137 <class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackJsonAttributeConverter</class>
1138 <class>org.apache.logging.log4j.core.appender.db.jpa.converter.MarkerAttributeConverter</class>
1139 <class>org.apache.logging.log4j.core.appender.db.jpa.converter.MessageAttributeConverter</class>
1140 <class>org.apache.logging.log4j.core.appender.db.jpa.converter.StackTraceElementAttributeConverter</class>
1141 <class>org.apache.logging.log4j.core.appender.db.jpa.converter.ThrowableAttributeConverter</class>
1142 <class>com.example.logging.JpaLogEntity</class>
1143 <non-jta-data-source>jdbc/LoggingDataSource</non-jta-data-source>
1144 <shared-cache-mode>NONE</shared-cache-mode>
1145 </persistence-unit>
1146
1147 </persistence>]]></pre>
1148
1149 <pre class="prettyprint linenums lang-java"><![CDATA[package com.example.logging;
1150 ...
1151 @Entity
1152 @Table(name="application_log", schema="dbo")
1153 public class JpaLogEntity extends BasicLogEventEntity {
1154 private static final long serialVersionUID = 1L;
1155 private long id = 0L;
1156
1157 public TestEntity() {
1158 super(null);
1159 }
1160 public TestEntity(LogEvent wrappedEvent) {
1161 super(wrappedEvent);
1162 }
1163
1164 @Id
1165 @GeneratedValue(strategy = GenerationType.IDENTITY)
1166 @Column(name = "id")
1167 public long getId() {
1168 return this.id;
1169 }
1170
1171 public void setId(long id) {
1172 this.id = id;
1173 }
1174
1175 // If you want to override the mapping of any properties mapped in BasicLogEventEntity,
1176 // just override the getters and re-specify the annotations.
1177 }]]></pre>
1178
1179 <pre class="prettyprint linenums lang-java"><![CDATA[package com.example.logging;
1180 ...
1181 @Entity
1182 @Table(name="application_log", schema="dbo")
1183 public class JpaLogEntity extends AbstractLogEventWrapperEntity {
1184 private static final long serialVersionUID = 1L;
1185 private long id = 0L;
1186
1187 public TestEntity() {
1188 super(null);
1189 }
1190 public TestEntity(LogEvent wrappedEvent) {
1191 super(wrappedEvent);
1192 }
1193
1194 @Id
1195 @GeneratedValue(strategy = GenerationType.IDENTITY)
1196 @Column(name = "logEventId")
1197 public long getId() {
1198 return this.id;
1199 }
1200
1201 public void setId(long id) {
1202 this.id = id;
1203 }
1204
1205 @Override
1206 @Enumerated(EnumType.STRING)
1207 @Column(name = "level")
1208 public Level getLevel() {
1209 return this.getWrappedEvent().getLevel();
1210 }
1211
1212 @Override
1213 @Column(name = "logger")
1214 public String getLoggerName() {
1215 return this.getWrappedEvent().getLoggerName();
1216 }
1217
1218 @Override
1219 @Column(name = "message")
1220 @Convert(converter = MyMessageConverter.class)
1221 public Message getMessage() {
1222 return this.getWrappedEvent().getMessage();
1223 }
1224 ...
1225 }]]></pre>
1226 </subsection>
1227 <a name="MemoryMappedFileAppender" />
1228 <subsection name="MemoryMappedFileAppender">
1229 <p><i>New since 2.1. Be aware that this is a new addition, and although it has been
1230 tested on several platforms, it does not have as much track record as the other file appenders.</i></p>
1231 <p>
1232 The MemoryMappedFileAppender maps a part of the specified file into memory
1233 and writes log events to this memory, relying on the operating system's
1234 virtual memory manager to synchronize the changes to the storage device.
1235 The main benefit of using memory mapped files is I/O performance. Instead of making system
1236 calls to write to disk, this appender can simply change the program's local memory,
1237 which is orders of magnitude faster. Also, in most operating systems the memory
1238 region mapped actually is the kernel's <a href="http://en.wikipedia.org/wiki/Page_cache">page
1239 cache</a> (file cache), meaning that no copies need to be created in user space.
1240 (TODO: performance tests that compare performance of this appender to
1241 RandomAccessFileAppender and FileAppender.)
1242 </p>
1243 <p>
1244 There is some overhead with mapping a file region into memory,
1245 especially very large regions (half a gigabyte or more).
1246 The default region size is 32 MB, which should strike a reasonable balance
1247 between the frequency and the duration of remap operations.
1248 (TODO: performance test remapping various sizes.)
1249 </p>
1250 <p>
1251 Similar to the FileAppender and the RandomAccessFileAppender,
1252 MemoryMappedFileAppender uses a MemoryMappedFileManager to actually perform the
1253 file I/O. While MemoryMappedFileAppender from different Configurations
1254 cannot be shared, the MemoryMappedFileManagers can be if the Manager is
1255 accessible. For example, two web applications in a servlet container can have
1256 their own configuration and safely write to the same file if Log4j
1257 is in a ClassLoader that is common to both of them.
1258 </p>
1259 <table>
1260 <caption align="top">MemoryMappedFileAppender Parameters</caption>
1261 <tr>
1262 <th>Parameter Name</th>
1263 <th>Type</th>
1264 <th>Description</th>
1265 </tr>
1266 <tr>
1267 <td>append</td>
1268 <td>boolean</td>
1269 <td>When true - the default, records will be appended to the end
1270 of the file. When set to false, the file will be cleared before
1271 new records are written.
1272 </td>
1273 </tr>
1274 <tr>
1275 <td>fileName</td>
1276 <td>String</td>
1277 <td>The name of the file to write to. If the file, or any of its
1278 parent directories, do not exist, they will be created.
1279 </td>
1280 </tr>
1281 <tr>
1282 <td>filters</td>
1283 <td>Filter</td>
1284 <td>A Filter to determine if the event should be handled by this
1285 Appender. More than one Filter may be used by using a CompositeFilter.
1286 </td>
1287 </tr>
1288 <tr>
1289 <td>immediateFlush</td>
1290 <td>boolean</td>
1291 <td>
1292 <p>When set to true, each write will be followed by a
1293 call to <a href="http://docs.oracle.com/javase/7/docs/api/java/nio/MappedByteBuffer.html#force()">MappedByteBuffer.force()</a>.
1294 This will guarantee the data is written to the storage device.
1295 </p>
1296 <p>The default for this parameter is <code>false</code>.
1297 This means that the data is written to the storage device even
1298 if the Java process crashes, but there may be data loss if the
1299 operating system crashes.</p>
1300 <p>Note that manually forcing a sync on every log event loses most
1301 of the performance benefits of using a memory mapped file.</p>
1302 <p>Flushing after every write is only useful when using this
1303 appender with synchronous loggers. Asynchronous loggers and
1304 appenders will automatically flush at the end of a batch of events,
1305 even if immediateFlush is set to false. This also guarantees
1306 the data is written to disk but is more efficient.
1307 </p>
1308 </td>
1309 </tr>
1310 <tr>
1311 <td>regionLength</td>
1312 <td>int</td>
1313 <td>The length of the mapped region, defaults to 32 MB
1314 (32 * 1024 * 1024 bytes). This parameter must be a value
1315 between 256 and 1,073,741,824 (1 GB or 2^30);
1316 values outside this range will be adjusted to the closest valid
1317 value.
1318 Log4j will round the specified value up to the nearest power of two.</td>
1319 </tr>
1320 <tr>
1321 <td>layout</td>
1322 <td>Layout</td>
1323 <td>The Layout to use to format the LogEvent</td>
1324 </tr>
1325 <tr>
1326 <td>name</td>
1327 <td>String</td>
1328 <td>The name of the Appender.</td>
1329 </tr>
1330 <tr>
1331 <td>ignoreExceptions</td>
1332 <td>boolean</td>
1333 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
1334 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
1335 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
1336 <a href="#FailoverAppender">FailoverAppender</a>.</td>
1337 </tr>
1338 </table>
1339 <p>
1340 Here is a sample MemoryMappedFile configuration:
1341 </p>
1342
1343 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
1344 <Configuration status="warn" name="MyApp" packages="">
1345 <Appenders>
1346 <MemoryMappedFile name="MyFile" fileName="logs/app.log">
1347 <PatternLayout>
1348 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
1349 </PatternLayout>
1350 </MemoryMappedFile>
1351 </Appenders>
1352 <Loggers>
1353 <Root level="error">
1354 <AppenderRef ref="MyFile"/>
1355 </Root>
1356 </Loggers>
1357 </Configuration>]]></pre>
1358 </subsection>
1359 <a name="NoSQLAppender"/>
1360 <subsection name="NoSQLAppender">
1361 <p>The NoSQLAppender writes log events to a NoSQL database using an internal lightweight provider interface.
1362 Provider implementations currently exist for MongoDB and Apache CouchDB, and writing a custom provider is
1363 quite simple.</p>
1364 <table>
1365 <caption align="top">NoSQLAppender Parameters</caption>
1366 <tr>
1367 <th>Parameter Name</th>
1368 <th>Type</th>
1369 <th>Description</th>
1370 </tr>
1371 <tr>
1372 <td>name</td>
1373 <td>String</td>
1374 <td><em>Required.</em> The name of the Appender.</td>
1375 </tr>
1376 <tr>
1377 <td>ignoreExceptions</td>
1378 <td>boolean</td>
1379 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
1380 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
1381 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
1382 <a href="#FailoverAppender">FailoverAppender</a>.</td>
1383 </tr>
1384 <tr>
1385 <td>filter</td>
1386 <td>Filter</td>
1387 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter may be
1388 used by using a CompositeFilter.</td>
1389 </tr>
1390 <tr>
1391 <td>bufferSize</td>
1392 <td>int</td>
1393 <td>If an integer greater than 0, this causes the appender to buffer log events and flush whenever the
1394 buffer reaches this size.</td>
1395 </tr>
1396 <tr>
1397 <td>NoSqlProvider</td>
1398 <td>NoSQLProvider&lt;C extends NoSQLConnection&lt;W, T extends NoSQLObject&lt;W&gt;&gt;&gt;</td>
1399 <td><em>Required.</em> The NoSQL provider that provides connections to the chosen NoSQL database.</td>
1400 </tr>
1401 </table>
1402 <p>You specify which NoSQL provider to use by specifying the appropriate configuration element within the
1403 <code>&lt;NoSql&gt;</code> element. The types currently supported are <code>&lt;MongoDb&gt;</code> and
1404 <code>&lt;CouchDb&gt;</code>. To create your own custom provider, read the JavaDoc for the
1405 <code>NoSQLProvider</code>, <code>NoSQLConnection</code>, and <code>NoSQLObject</code> classes and the
1406 documentation about creating Log4j plugins. We recommend you review the source code for the MongoDB and
1407 CouchDB providers as a guide for creating your own provider.</p>
1408 <table>
1409 <caption align="top">MongoDB Provider Parameters</caption>
1410 <tr>
1411 <th>Parameter Name</th>
1412 <th>Type</th>
1413 <th>Description</th>
1414 </tr>
1415 <tr>
1416 <td>collectionName</td>
1417 <td>String</td>
1418 <td><em>Required.</em> The name of the MongoDB collection to insert the events into.</td>
1419 </tr>
1420 <tr>
1421 <td>writeConcernConstant</td>
1422 <td>Field</td>
1423 <td>By default, the MongoDB provider inserts records with the instructions
1424 <code>com.mongodb.WriteConcern.ACKNOWLEDGED</code>. Use this optional attribute to specify the name of
1425 a constant other than <code>ACKNOWLEDGED</code>.</td>
1426 </tr>
1427 <tr>
1428 <td>writeConcernConstantClass</td>
1429 <td>Class</td>
1430 <td>If you specify <code>writeConcernConstant</code>, you can use this attribute to specify a class other
1431 than <code>com.mongodb.WriteConcern</code> to find the constant on (to create your own custom
1432 instructions).</td>
1433 </tr>
1434 <tr>
1435 <td>factoryClassName</td>
1436 <td>Class</td>
1437 <td>To provide a connection to the MongoDB database, you can use this attribute and
1438 <code>factoryMethodName</code> to specify a class and static method to get the connection from. The
1439 method must return a <code>com.mongodb.DB</code> or a <code>com.mongodb.MongoClient</code>. If the
1440 <code>DB</code> is not authenticated, you must also specify a <code>username</code> and
1441 <code>password</code>. If you use the factory method for providing a connection, you must not specify
1442 the <code>databaseName</code>, <code>server</code>, or <code>port</code> attributes.</td>
1443 </tr>
1444 <tr>
1445 <td>factoryMethodName</td>
1446 <td>Method</td>
1447 <td>See the documentation for attribute <code>factoryClassName</code>.</td>
1448 </tr>
1449 <tr>
1450 <td>databaseName</td>
1451 <td>String</td>
1452 <td>If you do not specify a <code>factoryClassName</code> and <code>factoryMethodName</code> for providing
1453 a MongoDB connection, you must specify a MongoDB database name using this attribute. You must also
1454 specify a <code>username</code> and <code>password</code>. You can optionally also specify a
1455 <code>server</code> (defaults to localhost), and a <code>port</code> (defaults to the default MongoDB
1456 port).</td>
1457 </tr>
1458 <tr>
1459 <td>server</td>
1460 <td>String</td>
1461 <td>See the documentation for attribute <code>databaseName</code>.</td>
1462 </tr>
1463 <tr>
1464 <td>port</td>
1465 <td>int</td>
1466 <td>See the documentation for attribute <code>databaseName</code>.</td>
1467 </tr>
1468 <tr>
1469 <td>username</td>
1470 <td>String</td>
1471 <td>See the documentation for attributes <code>databaseName</code> and <code>factoryClassName</code>.</td>
1472 </tr>
1473 <tr>
1474 <td>password</td>
1475 <td>String</td>
1476 <td>See the documentation for attributes <code>databaseName</code> and <code>factoryClassName</code>.</td>
1477 </tr>
1478 </table>
1479 <table>
1480 <caption align="top">CouchDB Provider Parameters</caption>
1481 <tr>
1482 <th>Parameter Name</th>
1483 <th>Type</th>
1484 <th>Description</th>
1485 </tr>
1486 <tr>
1487 <td>factoryClassName</td>
1488 <td>Class</td>
1489 <td>To provide a connection to the CouchDB database, you can use this attribute and
1490 <code>factoryMethodName</code> to specify a class and static method to get the connection from. The
1491 method must return a <code>org.lightcouch.CouchDbClient</code> or a
1492 <code>org.lightcouch.CouchDbProperties</code>. If you use the factory method for providing a connection,
1493 you must not specify the <code>databaseName</code>, <code>protocol</code>, <code>server</code>,
1494 <code>port</code>, <code>username</code>, or <code>password</code> attributes.</td>
1495 </tr>
1496 <tr>
1497 <td>factoryMethodName</td>
1498 <td>Method</td>
1499 <td>See the documentation for attribute <code>factoryClassName</code>.</td>
1500 </tr>
1501 <tr>
1502 <td>databaseName</td>
1503 <td>String</td>
1504 <td>If you do not specify a <code>factoryClassName</code> and <code>factoryMethodName</code> for providing
1505 a CouchDB connection, you must specify a CouchDB database name using this attribute. You must also
1506 specify a <code>username</code> and <code>password</code>. You can optionally also specify a
1507 <code>protocol</code> (defaults to http), <code>server</code> (defaults to localhost), and a
1508 <code>port</code> (defaults to 80 for http and 443 for https).</td>
1509 </tr>
1510 <tr>
1511 <td>protocol</td>
1512 <td>String</td>
1513 <td>Must either be "http" or "https." See the documentation for attribute <code>databaseName</code>.</td>
1514 </tr>
1515 <tr>
1516 <td>server</td>
1517 <td>String</td>
1518 <td>See the documentation for attribute <code>databaseName</code>.</td>
1519 </tr>
1520 <tr>
1521 <td>port</td>
1522 <td>int</td>
1523 <td>See the documentation for attribute <code>databaseName</code>.</td>
1524 </tr>
1525 <tr>
1526 <td>username</td>
1527 <td>String</td>
1528 <td>See the documentation for attributes <code>databaseName</code>.</td>
1529 </tr>
1530 <tr>
1531 <td>password</td>
1532 <td>String</td>
1533 <td>See the documentation for attributes <code>databaseName</code>.</td>
1534 </tr>
1535 </table>
1536 <p>
1537 Here are a few sample configurations for the NoSQLAppender:
1538 </p>
1539
1540 <pre class="prettyprint linenums lang-xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
1541 <Configuration status="error">
1542 <Appenders>
1543 <NoSql name="databaseAppender">
1544 <MongoDb databaseName="applicationDb" collectionName="applicationLog" server="mongo.example.org"
1545 username="loggingUser" password="abc123" />
1546 </NoSql>
1547 </Appenders>
1548 <Loggers>
1549 <Root level="warn">
1550 <AppenderRef ref="databaseAppender"/>
1551 </Root>
1552 </Loggers>
1553 </Configuration>]]></pre>
1554
1555 <pre class="prettyprint linenums lang-xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
1556 <Configuration status="error">
1557 <Appenders>
1558 <NoSql name="databaseAppender">
1559 <MongoDb collectionName="applicationLog" factoryClassName="org.example.db.ConnectionFactory"
1560 factoryMethodName="getNewMongoClient" />
1561 </NoSql>
1562 </Appenders>
1563 <Loggers>
1564 <Root level="warn">
1565 <AppenderRef ref="databaseAppender"/>
1566 </Root>
1567 </Loggers>
1568 </Configuration>]]></pre>
1569
1570 <pre class="prettyprint linenums lang-xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
1571 <Configuration status="error">
1572 <Appenders>
1573 <NoSql name="databaseAppender">
1574 <CouchDb databaseName="applicationDb" protocol="https" server="couch.example.org"
1575 username="loggingUser" password="abc123" />
1576 </NoSql>
1577 </Appenders>
1578 <Loggers>
1579 <Root level="warn">
1580 <AppenderRef ref="databaseAppender"/>
1581 </Root>
1582 </Loggers>
1583 </Configuration>]]></pre>
1584 <p>
1585 The following example demonstrates how log events are persisted in NoSQL databases if represented in a JSON
1586 format:
1587 </p>
1588 <pre class="prettyprint lang-javascript"><![CDATA[{
1589 "level": "WARN",
1590 "loggerName": "com.example.application.MyClass",
1591 "message": "Something happened that you might want to know about.",
1592 "source": {
1593 "className": "com.example.application.MyClass",
1594 "methodName": "exampleMethod",
1595 "fileName": "MyClass.java",
1596 "lineNumber": 81
1597 },
1598 "marker": {
1599 "name": "SomeMarker",
1600 "parent" {
1601 "name": "SomeParentMarker"
1602 }
1603 },
1604 "threadName": "Thread-1",
1605 "millis": 1368844166761,
1606 "date": "2013-05-18T02:29:26.761Z",
1607 "thrown": {
1608 "type": "java.sql.SQLException",
1609 "message": "Could not insert record. Connection lost.",
1610 "stackTrace": [
1611 { "className": "org.example.sql.driver.PreparedStatement$1", "methodName": "responder", "fileName": "PreparedStatement.java", "lineNumber": 1049 },
1612 { "className": "org.example.sql.driver.PreparedStatement", "methodName": "executeUpdate", "fileName": "PreparedStatement.java", "lineNumber": 738 },
1613 { "className": "com.example.application.MyClass", "methodName": "exampleMethod", "fileName": "MyClass.java", "lineNumber": 81 },
1614 { "className": "com.example.application.MainClass", "methodName": "main", "fileName": "MainClass.java", "lineNumber": 52 }
1615 ],
1616 "cause": {
1617 "type": "java.io.IOException",
1618 "message": "Connection lost.",
1619 "stackTrace": [
1620 { "className": "java.nio.channels.SocketChannel", "methodName": "write", "fileName": null, "lineNumber": -1 },
1621 { "className": "org.example.sql.driver.PreparedStatement$1", "methodName": "responder", "fileName": "PreparedStatement.java", "lineNumber": 1032 },
1622 { "className": "org.example.sql.driver.PreparedStatement", "methodName": "executeUpdate", "fileName": "PreparedStatement.java", "lineNumber": 738 },
1623 { "className": "com.example.application.MyClass", "methodName": "exampleMethod", "fileName": "MyClass.java", "lineNumber": 81 },
1624 { "className": "com.example.application.MainClass", "methodName": "main", "fileName": "MainClass.java", "lineNumber": 52 }
1625 ]
1626 }
1627 },
1628 "contextMap": {
1629 "ID": "86c3a497-4e67-4eed-9d6a-2e5797324d7b",
1630 "username": "JohnDoe"
1631 },
1632 "contextStack": [
1633 "topItem",
1634 "anotherItem",
1635 "bottomItem"
1636 ]
1637 }]]></pre>
1638 </subsection>
1639 <a name="OutputStreamAppender"/>
1640 <subsection name="OutputStreamAppender">
1641 <p>
1642 The OutputStreamAppender provides the base for many of the other Appenders such as the File and Socket
1643 appenders that write the event to an Output Stream. It cannot be directly configured. Support for
1644 immediateFlush and buffering is provided by the OutputStreamAppender. The OutputStreamAppender uses an
1645 OutputStreamManager to handle the actual I/O, allowing the stream to be shared by Appenders in multiple
1646 configurations.
1647 </p>
1648 </subsection>
1649 <a name="RandomAccessFileAppender" />
1650 <subsection name="RandomAccessFileAppender">
1651 <p><i>As of beta-9, the name of this appender has been changed from FastFile to
1652 RandomAccessFile. Configurations using the <code>FastFile</code> element
1653 no longer work and should be modified to use the <code>RandomAccessFile</code> element.</i></p>
1654 <p>
1655 The RandomAccessFileAppender is similar to the standard
1656 <a href="#FileAppender">FileAppender</a>
1657 except it is always buffered (this cannot be switched off)
1658 and internally it uses a
1659 <tt>ByteBuffer + RandomAccessFile</tt>
1660 instead of a
1661 <tt>BufferedOutputStream</tt>.
1662 We saw a 20-200% performance improvement compared to
1663 FileAppender with "bufferedIO=true" in our
1664 <a href="async.html#RandomAccessFileAppenderPerformance">measurements</a>.
1665 Similar to the FileAppender,
1666 RandomAccessFileAppender uses a RandomAccessFileManager to actually perform the
1667 file I/O. While RandomAccessFileAppender
1668 from different Configurations
1669 cannot be shared, the RandomAccessFileManagers can be if the Manager is
1670 accessible. For example, two web applications in a
1671 servlet container can have
1672 their own configuration and safely
1673 write to the same file if Log4j
1674 is in a ClassLoader that is common to
1675 both of them.
1676 </p>
1677 <table>
1678 <caption align="top">RandomAccessFileAppender Parameters</caption>
1679 <tr>
1680 <th>Parameter Name</th>
1681 <th>Type</th>
1682 <th>Description</th>
1683 </tr>
1684 <tr>
1685 <td>append</td>
1686 <td>boolean</td>
1687 <td>When true - the default, records will be appended to the end
1688 of the file. When set to false,
1689 the file will be cleared before
1690 new records are written.
1691 </td>
1692 </tr>
1693 <tr>
1694 <td>fileName</td>
1695 <td>String</td>
1696 <td>The name of the file to write to. If the file, or any of its
1697 parent directories, do not exist,
1698 they will be created.
1699 </td>
1700 </tr>
1701 <tr>
1702 <td>filters</td>
1703 <td>Filter</td>
1704 <td>A Filter to determine if the event should be handled by this
1705 Appender. More than one Filter
1706 may be used by using a CompositeFilter.
1707 </td>
1708 </tr>
1709 <tr>
1710 <td>immediateFlush</td>
1711 <td>boolean</td>
1712 <td>
1713 <p>
1714 When set to true - the default, each write will be followed by a flush.
1715 This will guarantee the data is written
1716 to disk but could impact performance.
1717 </p>
1718 <p>
1719 Flushing after every write is only useful when using this
1720 appender with synchronous loggers. Asynchronous loggers and
1721 appenders will automatically flush at the end of a batch of events,
1722 even if immediateFlush is set to false. This also guarantees
1723 the data is written to disk but is more efficient.
1724 </p>
1725 </td>
1726 </tr>
1727 <tr>
1728 <td>bufferSize</td>
1729 <td>int</td>
1730 <td>The buffer size, defaults to 262,144 bytes (256 * 1024).</td>
1731 </tr>
1732 <tr>
1733 <td>layout</td>
1734 <td>Layout</td>
1735 <td>The Layout to use to format the LogEvent</td>
1736 </tr>
1737 <tr>
1738 <td>name</td>
1739 <td>String</td>
1740 <td>The name of the Appender.</td>
1741 </tr>
1742 <tr>
1743 <td>ignoreExceptions</td>
1744 <td>boolean</td>
1745 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
1746 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
1747 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
1748 <a href="#FailoverAppender">FailoverAppender</a>.</td>
1749 </tr>
1750 </table>
1751 <p>
1752 Here is a sample RandomAccessFile configuration:
1753 </p>
1754
1755 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
1756 <Configuration status="warn" name="MyApp" packages="">
1757 <Appenders>
1758 <RandomAccessFile name="MyFile" fileName="logs/app.log">
1759 <PatternLayout>
1760 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
1761 </PatternLayout>
1762 </RandomAccessFile>
1763 </Appenders>
1764 <Loggers>
1765 <Root level="error">
1766 <AppenderRef ref="MyFile"/>
1767 </Root>
1768 </Loggers>
1769 </Configuration>]]></pre>
1770 </subsection>
1771 <a name="RewriteAppender"/>
1772 <subsection name="RewriteAppender">
1773 <p>
1774 The RewriteAppender allows the LogEvent to manipulated before it is processed by another Appender. This
1775 can be used to mask sensitive information such as passwords or to inject information into each event.
1776 The RewriteAppender must be configured with a <a href="RewritePolicy">RewritePolicy</a>. The
1777 RewriteAppender should be configured after any Appenders it references to allow it to shut down properly.
1778 </p>
1779 <table>
1780 <caption align="top">RewriteAppender Parameters</caption>
1781 <tr>
1782 <th>Parameter Name</th>
1783 <th>Type</th>
1784 <th>Description</th>
1785 </tr>
1786 <tr>
1787 <td>AppenderRef</td>
1788 <td>String</td>
1789 <td>The name of the Appenders to call after the LogEvent has been manipulated. Multiple AppenderRef
1790 elements can be configured.</td>
1791 </tr>
1792 <tr>
1793 <td>filter</td>
1794 <td>Filter</td>
1795 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
1796 may be used by using a CompositeFilter.</td>
1797 </tr>
1798 <tr>
1799 <td>name</td>
1800 <td>String</td>
1801 <td>The name of the Appender.</td>
1802 </tr>
1803 <tr>
1804 <td>rewritePolicy</td>
1805 <td>RewritePolicy</td>
1806 <td>The RewritePolicy that will manipulate the LogEvent.</td>
1807 </tr>
1808 <tr>
1809 <td>ignoreExceptions</td>
1810 <td>boolean</td>
1811 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
1812 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
1813 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
1814 <a href="#FailoverAppender">FailoverAppender</a>.</td>
1815 </tr>
1816 </table>
1817 <h4>RewritePolicy</h4>
1818 <p>
1819 RewritePolicy is an interface that allows implementations to inspect and possibly modify LogEvents
1820 before they are passed to Appender. RewritePolicy declares a single method named rewrite that must
1821 be implemented. The method is passed the LogEvent and can return the same event or create a new one.
1822 </p>
1823 <h5>MapRewritePolicy</h5>
1824 <p>
1825 MapRewritePolicy will evaluate LogEvents that contain a MapMessage and will add or update
1826 elements of the Map.
1827 </p>
1828 <table>
1829 <tr>
1830 <th>Parameter Name</th>
1831 <th>Type</th>
1832 <th>Description</th>
1833 </tr>
1834 <tr>
1835 <td>mode</td>
1836 <td>String</td>
1837 <td>"Add" or "Update"</td>
1838 </tr>
1839 <tr>
1840 <td>keyValuePair</td>
1841 <td>KeyValuePair[]</td>
1842 <td>An array of keys and their values.</td>
1843 </tr>
1844 </table>
1845 <p>
1846 The following configuration shows a RewriteAppender configured to add a product key and its value
1847 to the MapMessage.:
1848 </p>
1849
1850 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
1851 <Configuration status="warn" name="MyApp" packages="">
1852 <Appenders>
1853 <Console name="STDOUT" target="SYSTEM_OUT">
1854 <PatternLayout pattern="%m%n"/>
1855 </Console>
1856 <Rewrite name="rewrite">
1857 <AppenderRef ref="STDOUT"/>
1858 <MapRewritePolicy mode="Add">
1859 <KeyValuePair key="product" value="TestProduct"/>
1860 </MapRewritePolicy>
1861 </Rewrite>
1862 </Appenders>
1863 <Loggers>
1864 <Root level="error">
1865 <AppenderRef ref="Rewrite"/>
1866 </Root>
1867 </Loggers>
1868 </Configuration>]]></pre>
1869 <h5>PropertiesRewritePolicy</h5>
1870 <p>
1871 PropertiesRewritePolicy will add properties configured on the policy to the ThreadContext Map
1872 being logged. The properties will not be added to the actual ThreadContext Map. The property
1873 values may contain variables that will be evaluated when the configuration is processed as
1874 well as when the event is logged.
1875 </p>
1876 <table>
1877 <tr>
1878 <th>Parameter Name</th>
1879 <th>Type</th>
1880 <th>Description</th>
1881 </tr>
1882 <tr>
1883 <td>properties</td>
1884 <td>Property[]</td>
1885 <td>One of more Property elements to define the keys and values to be added to the ThreadContext Map.</td>
1886 </tr>
1887 </table>
1888 <p>
1889 The following configuration shows a RewriteAppender configured to add a product key and its value
1890 to the MapMessage.:
1891 </p>
1892
1893 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
1894 <Configuration status="warn" name="MyApp" packages="">
1895 <Appenders>
1896 <Console name="STDOUT" target="SYSTEM_OUT">
1897 <PatternLayout pattern="%m%n"/>
1898 </Console>
1899 <Rewrite name="rewrite">
1900 <AppenderRef ref="STDOUT"/>
1901 <PropertiesRewritePolicy>
1902 <Property name="user">${sys:user.name}</Property>
1903 <Property name="env">${sys:environment}</Property>
1904 </PropertiesRewritePolicy>
1905 </Rewrite>
1906 </Appenders>
1907 <Loggers>
1908 <Root level="error">
1909 <AppenderRef ref="Rewrite"/>
1910 </Root>
1911 </Loggers>
1912 </Configuration>]]></pre>
1913 </subsection>
1914 <a name="RollingFileAppender"/>
1915 <subsection name="RollingFileAppender">
1916 <p>The RollingFileAppender is an OutputStreamAppender that writes to the File named in the fileName parameter
1917 and rolls the file over according the TriggeringPolicy and the RolloverPolicy. The
1918 RollingFileAppender uses a RollingFileManager (which extends OutputStreamManager) to actually perform the
1919 file I/O and perform the rollover. While RolloverFileAppenders from different Configurations cannot be
1920 shared, the RollingFileManagers can be if the Manager is accessible. For example, two web applications in a
1921 servlet container can have their own configuration and safely
1922 write to the same file if Log4j is in a ClassLoader that is common to both of them.</p>
1923 <p>
1924 A RollingFileAppender requires a <a href="#TriggeringPolicies">TriggeringPolicy</a> and a
1925 <a href="#RolloverStrategies">RolloverStrategy</a>. The triggering policy determines if a rollover should
1926 be performed while the RolloverStrategy defines how the rollover should be done. If no RolloverStrategy
1927 is configured, RollingFileAppender will use the <a href="#DefaultRolloverStrategy">DefaultRolloverStrategy</a>.
1928 </p>
1929 <p>
1930 File locking is not supported by the RollingFileAppender.
1931 </p>
1932 <table>
1933 <caption align="top">RollingFileAppender Parameters</caption>
1934 <tr>
1935 <th>Parameter Name</th>
1936 <th>Type</th>
1937 <th>Description</th>
1938 </tr>
1939 <tr>
1940 <td>append</td>
1941 <td>boolean</td>
1942 <td>When true - the default, records will be appended to the end of the file. When set to false,
1943 the file will be cleared before new records are written.</td>
1944 </tr>
1945 <tr>
1946 <td>bufferedIO</td>
1947 <td>boolean</td>
1948 <td>When true - the default, records will be written to a buffer and the data will be written to
1949 disk when the buffer is full or, if immediateFlush is set, when the record is written.
1950 File locking cannot be used with bufferedIO. Performance tests have shown that using buffered I/O
1951 significantly improves performance, even if immediateFlush is enabled.</td>
1952 </tr>
1953 <tr>
1954 <td>bufferSize</td>
1955 <td>int</td>
1956 <td>When bufferedIO is true, this is the buffer size, the default is 8192 bytes.</td>
1957 </tr>
1958 <tr>
1959 <td>filter</td>
1960 <td>Filter</td>
1961 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
1962 may be used by using a CompositeFilter.</td>
1963 </tr>
1964 <tr>
1965 <td>fileName</td>
1966 <td>String</td>
1967 <td>The name of the file to write to. If the file, or any of its parent directories, do not exist,
1968 they will be created.</td>
1969 </tr>
1970 <tr>
1971 <td>filePattern</td>
1972 <td>String</td>
1973 <td>The pattern of the file name of the archived log file. The format of the pattern should is
1974 dependent on the RolloverPolicy that is used. The DefaultRolloverPolicy will accept both
1975 a date/time pattern compatible with
1976 <a href="http://download.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html">SimpleDateFormat</a>
1977 and and/or a %i which represents an integer counter. The pattern also supports interpolation at
1978 runtime so any of the Lookups (such as the <a href="./lookups.html#DateLookup">DateLookup</a> can
1979 be included in the pattern.</td>
1980 </tr>
1981 <tr>
1982 <td>immediateFlush</td>
1983 <td>boolean</td>
1984 <td><p>When set to true - the default, each write will be followed by a flush.
1985 This will guarantee the data is written
1986 to disk but could impact performance.</p>
1987 <p>Flushing after every write is only useful when using this
1988 appender with synchronous loggers. Asynchronous loggers and
1989 appenders will automatically flush at the end of a batch of events,
1990 even if immediateFlush is set to false. This also guarantees
1991 the data is written to disk but is more efficient.</p>
1992 </td>
1993 </tr>
1994 <tr>
1995 <td>layout</td>
1996 <td>Layout</td>
1997 <td>The Layout to use to format the LogEvent</td>
1998 </tr>
1999
2000 <tr>
2001 <td>name</td>
2002 <td>String</td>
2003 <td>The name of the Appender.</td>
2004 </tr>
2005 <tr>
2006 <td>policy</td>
2007 <td>TriggeringPolicy</td>
2008 <td>The policy to use to determine if a rollover should occur.</td>
2009 </tr>
2010 <tr>
2011 <td>strategy</td>
2012 <td>RolloverStrategy</td>
2013 <td>The strategy to use to determine the name and location of the archive file.</td>
2014 </tr>
2015 <tr>
2016 <td>ignoreExceptions</td>
2017 <td>boolean</td>
2018 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
2019 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
2020 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
2021 <a href="#FailoverAppender">FailoverAppender</a>.</td>
2022 </tr>
2023 </table>
2024 <a name="TriggeringPolicies"/>
2025 <h4>Triggering Policies</h4>
2026 <h5>Composite Triggering Policy</h5>
2027 <p>
2028 The <code>CompositeTriggeringPolicy</code> combines multiple triggering policies and returns true if
2029 any of the configured policies return true. The <code>CompositeTriggeringPolicy</code> is configured
2030 simply by wrapping other policies in a <code>Policies</code> element.
2031 </p>
2032 <p>
2033 For example, the following XML fragment defines policies that rollover the log when the JVM starts,
2034 when the log size reaches twenty megabytes, and when the current date no longer matches the log’s
2035 start date.
2036 </p>
2037 <pre class="prettyprint linenums"><![CDATA[<Policies>
2038 <OnStartupTriggeringPolicy />
2039 <SizeBasedTriggeringPolicy size="20 MB" />
2040 <TimeBasedTriggeringPolicy />
2041 </Policies>]]></pre>
2042 <h5>OnStartup Triggering Policy</h5>
2043 <p>
2044 The <code>OnStartupTriggeringPolicy</code> policy takes no parameters and causes a rollover if the log
2045 file is older than the current JVM's start time.
2046 </p>
2047 <p>
2048 <em>Google App Engine note:</em><br />
2049 When running in Google App Engine, the OnStartup policy causes a rollover if the log file is older
2050 than <em>the time when Log4J initialized</em>.
2051 (Google App Engine restricts access to certain classes so Log4J cannot determine JVM start time with
2052 <code>java.lang.management.ManagementFactory.getRuntimeMXBean().getStartTime()</code>
2053 and falls back to Log4J initialization time instead.)
2054 </p>
2055 <h5>SizeBased Triggering Policy</h5>
2056 <p>
2057 The <code>SizeBasedTriggeringPolicy</code> causes a rollover once the file has reached the specified
2058 size. The size can be specified in bytes, with the suffix KB, MB or GB, for example <code>20MB</code>.
2059 </p>
2060 <h5>TimeBased Triggering Policy</h5>
2061 <p>
2062 The <code>TimeBasedTriggeringPolicy</code> causes a rollover once the date/time pattern no longer
2063 applies to the active file. This policy accepts an <code>increment</code> attribute which indicates how
2064 frequently the rollover should occur based on the time pattern and a <code>modulate</code> boolean
2065 attribute.
2066 </p>
2067 <table>
2068 <caption align="top">TimeBasedTriggeringPolicy Parameters</caption>
2069 <tr>
2070 <th>Parameter Name</th>
2071 <th>Type</th>
2072 <th>Description</th>
2073 </tr>
2074 <tr>
2075 <td>interval</td>
2076 <td>integer</td>
2077 <td>How often a rollover should occur based on the most specific time unit in the date pattern.
2078 For example, with a date pattern with hours as the most specific item and and increment of 4 rollovers
2079 would occur every 4 hours.
2080 The default value is 1.</td>
2081 </tr>
2082 <tr>
2083 <td>modulate</td>
2084 <td>boolean</td>
2085 <td>Indicates whether the interval should be adjusted to cause the next rollover to occur on
2086 the interval boundary. For example, if the item is hours, the current hour is 3 am and the
2087 interval is 4 then then the first rollover will occur at 4 am and then next ones will occur at
2088 8 am, noon, 4pm, etc.</td>
2089 </tr>
2090 </table>
2091 <a name="RolloverStrategies"/>
2092 <h4>Rollover Strategies</h4>
2093 <a name="DefaultRolloverStrategy"/>
2094 <h5>Default Rollover Strategy</h5>
2095 <p>
2096 The default rollover strategy accepts both a date/time pattern and an integer from the filePattern
2097 attribute specified on the RollingFileAppender itself. If the date/time pattern
2098 is present it will be replaced with the current date and time values. If the pattern contains an integer
2099 it will be incremented on each rollover. If the pattern contains both a date/time and integer
2100 in the pattern the integer will be incremented until the result of the date/time pattern changes. If
2101 the file pattern ends with ".gz" or ".zip" the resulting archive will be compressed using the
2102 compression scheme that matches the suffix. The pattern may also contain lookup references that
2103 can be resolved at runtime such as is shown in the example below.
2104 </p>
2105 <p>The default rollover strategy supports two variations for incrementing the counter. The first is
2106 the "fixed window" strategy. To illustrate how it works, suppose that the min attribute is set to 1,
2107 the max attribute is set to 3, the file name is "foo.log", and the file name pattern is "foo-%i.log".
2108 </p>
2109
2110 <table>
2111 <tr>
2112 <th>Number of rollovers</th>
2113 <th>Active output target</th>
2114 <th>Archived log files</th>
2115 <th>Description</th>
2116 </tr>
2117 <tr>
2118 <td>0</td>
2119 <td>foo.log</td>
2120 <td>-</td>
2121 <td>All logging is going to the initial file.</td>
2122 </tr>
2123 <tr>
2124 <td>1</td>
2125 <td>foo.log</td>
2126 <td>foo-1.log</td>
2127 <td>During the first rollover foo.log is renamed to foo-1.log. A new foo.log file is created and
2128 starts being written to.</td>
2129 </tr>
2130 <tr>
2131 <td>2</td>
2132 <td>foo.log</td>
2133 <td>foo-1.log, foo-2.log</td>
2134 <td>During the second rollover foo-1.log is renamed to foo-2.log and foo.log is renamed to
2135 foo-1.log. A new foo.log file is created and starts being written to.</td>
2136 </tr>
2137 <tr>
2138 <td>3</td>
2139 <td>foo.log</td>
2140 <td>foo-1.log, foo-2.log, foo-3.log</td>
2141 <td>During the third rollover foo-2.log is renamed to foo-3.log, foo-1.log is renamed to foo-2.log and
2142 foo.log is renamed to foo-1.log. A new foo.log file is created and starts being written to.</td>
2143 </tr>
2144 <tr>
2145 <td>4</td>
2146 <td>foo.log</td>
2147 <td>foo-1.log, foo-2.log, foo-3.log</td>
2148 <td>In the fourth and subsequent rollovers, foo-3.log is deleted, foo-2.log is renamed to foo-3.log,
2149 foo-1.log is renamed to foo-2.log and foo.log is renamed to foo-1.log. A new foo.log file is
2150 created and starts being written to.</td>
2151 </tr>
2152 </table>
2153 <p>By way of contrast, when the the fileIndex attribute is set to "max" but all the other settings
2154 are the same the following actions will be performed.
2155 </p>
2156 <table>
2157 <tr>
2158 <th>Number of rollovers</th>
2159 <th>Active output target</th>
2160 <th>Archived log files</th>
2161 <th>Description</th>
2162 </tr>
2163 <tr>
2164 <td>0</td>
2165 <td>foo.log</td>
2166 <td>-</td>
2167 <td>All logging is going to the initial file.</td>
2168 </tr>
2169 <tr>
2170 <td>1</td>
2171 <td>foo.log</td>
2172 <td>foo-1.log</td>
2173 <td>During the first rollover foo.log is renamed to foo-1.log. A new foo.log file is created and
2174 starts being written to.</td>
2175 </tr>
2176 <tr>
2177 <td>2</td>
2178 <td>foo.log</td>
2179 <td>foo-1.log, foo-2.log</td>
2180 <td>During the second rollover foo.log is renamed to foo-2.log. A new foo.log file is created
2181 and starts being written to.</td>
2182 </tr>
2183 <tr>
2184 <td>3</td>
2185 <td>foo.log</td>
2186 <td>foo-1.log, foo-2.log, foo-3.log</td>
2187 <td>During the third rollover foo.log is renamed to foo-3.log. A new foo.log file is created and
2188 starts being written to.</td>
2189 </tr>
2190 <tr>
2191 <td>4</td>
2192 <td>foo.log</td>
2193 <td>foo-1.log, foo-2.log, foo-3.log</td>
2194 <td>In the fourth and subsequent rollovers, foo-1.log is deleted, foo-2.log is renamed to foo-1.log,
2195 foo-3.log is renamed to foo-2.log and foo.log is renamed to foo-3.log. A new foo.log file is
2196 created and starts being written to.</td>
2197 </tr>
2198 </table>
2199 <table>
2200 <caption align="top">DefaultRolloverStrategy Parameters</caption>
2201 <tr>
2202 <th>Parameter Name</th>
2203 <th>Type</th>
2204 <th>Description</th>
2205 </tr>
2206 <tr>
2207 <td>fileIndex</td>
2208 <td>String</td>
2209 <td>If set to "max" (the default), files with a higher index will be newer than files with a
2210 smaller index. If set to "min", file renaming and the counter will follow the Fixed Window strategy
2211 described above.</td>
2212 </tr>
2213 <tr>
2214 <td>min</td>
2215 <td>integer</td>
2216 <td>The minimum value of the counter. The default value is 1.</td>
2217 </tr>
2218 <tr>
2219 <td>max</td>
2220 <td>integer</td>
2221 <td>The maximum value of the counter. Once this values is reached older archives will be
2222 deleted on subsequent rollovers.</td>
2223 </tr>
2224 <tr>
2225 <td>compressionLevel</td>
2226 <td>integer</td>
2227 <td>
2228 Sets the compression level, 0-9, where 0 = none, 1 = best speed, through 9 = best compression.
2229 Only implemented for ZIP files.
2230 </td>
2231 </tr>
2232 </table>
2233
2234 <p>
2235 Below is a sample configuration that uses a RollingFileAppender with both the time and size based
2236 triggering policies, will create up to 7 archives on the same day (1-7) that are stored in a directory
2237 based on the current year and month, and will compress each
2238 archive using gzip:
2239 </p>
2240
2241 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2242 <Configuration status="warn" name="MyApp" packages="">
2243 <Appenders>
2244 <RollingFile name="RollingFile" fileName="logs/app.log"
2245 filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
2246 <PatternLayout>
2247 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
2248 </PatternLayout>
2249 <Policies>
2250 <TimeBasedTriggeringPolicy />
2251 <SizeBasedTriggeringPolicy size="250 MB"/>
2252 </Policies>
2253 </RollingFile>
2254 </Appenders>
2255 <Loggers>
2256 <Root level="error">
2257 <AppenderRef ref="RollingFile"/>
2258 </Root>
2259 </Loggers>
2260 </Configuration>]]></pre>
2261 <p>
2262 This second example shows a rollover strategy that will keep up to 20 files before removing them.
2263 </p>
2264 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2265 <Configuration status="warn" name="MyApp" packages="">
2266 <Appenders>
2267 <RollingFile name="RollingFile" fileName="logs/app.log"
2268 filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
2269 <PatternLayout>
2270 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
2271 </PatternLayout>
2272 <Policies>
2273 <TimeBasedTriggeringPolicy />
2274 <SizeBasedTriggeringPolicy size="250 MB"/>
2275 </Policies>
2276 <DefaultRolloverStrategy max="20"/>
2277 </RollingFile>
2278 </Appenders>
2279 <Loggers>
2280 <Root level="error">
2281 <AppenderRef ref="RollingFile"/>
2282 </Root>
2283 </Loggers>
2284 </Configuration>]]></pre>
2285 <p>
2286 Below is a sample configuration that uses a RollingFileAppender with both the time and size based
2287 triggering policies, will create up to 7 archives on the same day (1-7) that are stored in a directory
2288 based on the current year and month, and will compress each
2289 archive using gzip and will roll every 6 hours when the hour is divisible by 6:
2290 </p>
2291
2292 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2293 <Configuration status="warn" name="MyApp" packages="">
2294 <Appenders>
2295 <RollingFile name="RollingFile" fileName="logs/app.log"
2296 filePattern="logs/$${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}-%i.log.gz">
2297 <PatternLayout>
2298 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
2299 </PatternLayout>
2300 <Policies>
2301 <TimeBasedTriggeringPolicy interval="6" modulate="true"/>
2302 <SizeBasedTriggeringPolicy size="250 MB"/>
2303 </Policies>
2304 </RollingFile>
2305 </Appenders>
2306 <Loggers>
2307 <Root level="error">
2308 <AppenderRef ref="RollingFile"/>
2309 </Root>
2310 </Loggers>
2311 </Configuration>]]></pre>
2312 </subsection>
2313 <a name="RollingRandomAccessFileAppender" />
2314 <subsection name="RollingRandomAccessFileAppender">
2315 <p><i>As of beta-9, the name of this appender has been changed from FastRollingFile to
2316 RollingRandomAccessFile. Configurations using the <code>FastRollingFile</code> element
2317 no longer work and should be modified to use the <code>RollingRandomAccessFile</code> element.</i></p>
2318 <p>
2319 The RollingRandomAccessFileAppender is similar to the standard
2320 <a href="#RollingFileAppender">RollingFileAppender</a>
2321 except it is always buffered (this cannot be switched off)
2322 and
2323 internally it uses a
2324 <tt>ByteBuffer + RandomAccessFile</tt>
2325 instead of a
2326 <tt>BufferedOutputStream</tt>.
2327 We saw a 20-200% performance improvement compared to
2328 RollingFileAppender with "bufferedIO=true"
2329 in our
2330 <a href="async.html#RandomAccessFileAppenderPerformance">measurements</a>.
2331
2332 The RollingRandomAccessFileAppender writes
2333 to the File named in the
2334 fileName parameter
2335 and rolls the file over according the
2336 TriggeringPolicy
2337 and the RolloverPolicy.
2338
2339 Similar to the RollingFileAppender,
2340 RollingRandomAccessFileAppender uses a RollingRandomAccessFileManager
2341 to actually perform the
2342 file I/O and perform the rollover. While RollingRandomAccessFileAppender
2343 from different Configurations cannot be
2344 shared, the RollingRandomAccessFileManagers can be
2345 if the Manager is accessible.
2346 For example, two web applications in a servlet
2347 container can have their own configuration and safely write to the
2348 same file if Log4j is in a ClassLoader that is common to both of them.
2349 </p>
2350 <p>
2351 A RollingRandomAccessFileAppender requires a
2352 <a href="#TriggeringPolicies">TriggeringPolicy</a>
2353 and a
2354 <a href="#RolloverStrategies">RolloverStrategy</a>.
2355 The triggering policy determines if a rollover should
2356 be performed
2357 while the RolloverStrategy defines how the rollover
2358 should be done.
2359 If no RolloverStrategy
2360 is configured, RollingRandomAccessFileAppender will
2361 use the
2362 <a href="#DefaultRolloverStrategy">DefaultRolloverStrategy</a>.
2363 </p>
2364 <p>
2365 File locking is not supported by the RollingRandomAccessFileAppender.
2366 </p>
2367 <table>
2368 <caption align="top">RollingRandomAccessFileAppender Parameters</caption>
2369 <tr>
2370 <th>Parameter Name</th>
2371 <th>Type</th>
2372 <th>Description</th>
2373 </tr>
2374 <tr>
2375 <td>append</td>
2376 <td>boolean</td>
2377 <td>When true - the default, records will be appended to the end
2378 of the file. When set to false,
2379 the file will be cleared before
2380 new records are written.
2381 </td>
2382 </tr>
2383 <tr>
2384 <td>filter</td>
2385 <td>Filter</td>
2386 <td>A Filter to determine if the event should be handled by this
2387 Appender. More than one Filter
2388 may be used by using a
2389 CompositeFilter.
2390 </td>
2391 </tr>
2392 <tr>
2393 <td>fileName</td>
2394 <td>String</td>
2395 <td>The name of the file to write to. If the file, or any of its
2396 parent directories, do not exist,
2397 they will be created.
2398 </td>
2399 </tr>
2400 <tr>
2401 <td>filePattern</td>
2402 <td>String</td>
2403 <td>
2404 The pattern of the file name of the archived log file. The format
2405 of the pattern should is
2406 dependent on the RolloverPolicy that is
2407 used. The DefaultRolloverPolicy
2408 will accept both
2409 a date/time
2410 pattern compatible with
2411 <a
2412 href="http://download.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html">
2413 SimpleDateFormat</a>
2414
2415 and/or a %i which represents an integer counter. The pattern
2416 also supports interpolation at
2417 runtime so any of the Lookups (such
2418 as the
2419 <a href="./lookups.html#DateLookup">DateLookup</a>
2420 can
2421 be included in the pattern.
2422 </td>
2423 </tr>
2424 <tr>
2425 <td>immediateFlush</td>
2426 <td>boolean</td>
2427 <td><p>When set to true - the default, each write will be followed by a flush.
2428 This will guarantee the data is written
2429 to disk but could impact performance.</p>
2430 <p>Flushing after every write is only useful when using this
2431 appender with synchronous loggers. Asynchronous loggers and
2432 appenders will automatically flush at the end of a batch of events,
2433 even if immediateFlush is set to false. This also guarantees
2434 the data is written to disk but is more efficient.</p>
2435 </td>
2436 </tr>
2437 <tr>
2438 <td>bufferSize</td>
2439 <td>int</td>
2440 <td>The buffer size, defaults to 262,144 bytes (256 * 1024).</td>
2441 </tr>
2442 <tr>
2443 <td>layout</td>
2444 <td>Layout</td>
2445 <td>The Layout to use to format the LogEvent</td>
2446 </tr>
2447
2448 <tr>
2449 <td>name</td>
2450 <td>String</td>
2451 <td>The name of the Appender.</td>
2452 </tr>
2453 <tr>
2454 <td>policy</td>
2455 <td>TriggeringPolicy</td>
2456 <td>The policy to use to determine if a rollover should occur.
2457 </td>
2458 </tr>
2459 <tr>
2460 <td>strategy</td>
2461 <td>RolloverStrategy</td>
2462 <td>The strategy to use to determine the name and location of the
2463 archive file.
2464 </td>
2465 </tr>
2466 <tr>
2467 <td>ignoreExceptions</td>
2468 <td>boolean</td>
2469 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
2470 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
2471 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
2472 <a href="#FailoverAppender">FailoverAppender</a>.</td>
2473 </tr>
2474 </table>
2475 <a name="FRFA_TriggeringPolicies" />
2476 <h4>Triggering Policies</h4>
2477 <p>
2478 See
2479 <a href="#TriggeringPolicies">RollingFileAppender Triggering Policies</a>.
2480 </p>
2481 <a name="FRFA_RolloverStrategies" />
2482 <h4>Rollover Strategies</h4>
2483 <p>
2484 See
2485 <a href="#RolloverStrategies">RollingFileAppender Rollover Strategies</a>.
2486 </p>
2487
2488 <p>
2489 Below is a sample configuration that uses a RollingRandomAccessFileAppender
2490 with both the time and size based
2491 triggering policies, will create
2492 up to 7 archives on the same day (1-7) that
2493 are stored in a
2494 directory
2495 based on the current year and month, and will compress
2496 each
2497 archive using gzip:
2498 </p>
2499
2500 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2501 <Configuration status="warn" name="MyApp" packages="">
2502 <Appenders>
2503 <RollingRandomAccessFile name="RollingRandomAccessFile" fileName="logs/app.log"
2504 filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
2505 <PatternLayout>
2506 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
2507 </PatternLayout>
2508 <Policies>
2509 <TimeBasedTriggeringPolicy />
2510 <SizeBasedTriggeringPolicy size="250 MB"/>
2511 </Policies>
2512 </RollingRandomAccessFile>
2513 </Appenders>
2514 <Loggers>
2515 <Root level="error">
2516 <AppenderRef ref="RollingRandomAccessFile"/>
2517 </Root>
2518 </Loggers>
2519 </Configuration>]]></pre>
2520 <p>
2521 This second example shows a rollover strategy that will keep up to
2522 20 files before removing them.
2523 </p>
2524 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2525 <Configuration status="warn" name="MyApp" packages="">
2526 <Appenders>
2527 <RollingRandomAccessFile name="RollingRandomAccessFile" fileName="logs/app.log"
2528 filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
2529 <PatternLayout>
2530 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
2531 </PatternLayout>
2532 <Policies>
2533 <TimeBasedTriggeringPolicy />
2534 <SizeBasedTriggeringPolicy size="250 MB"/>
2535 </Policies>
2536 <DefaultRolloverStrategy max="20"/>
2537 </RollingRandomAccessFile>
2538 </Appenders>
2539 <Loggers>
2540 <Root level="error">
2541 <AppenderRef ref="RollingRandomAccessFile"/>
2542 </Root>
2543 </Loggers>
2544 </Configuration>]]></pre>
2545 <p>
2546 Below is a sample configuration that uses a RollingRandomAccessFileAppender
2547 with both the time and size based
2548 triggering policies, will create
2549 up to 7 archives on the same day (1-7) that
2550 are stored in a
2551 directory
2552 based on the current year and month, and will compress
2553 each
2554 archive using gzip and will roll every 6 hours when the hour is
2555 divisible
2556 by 6:
2557 </p>
2558
2559 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2560 <Configuration status="warn" name="MyApp" packages="">
2561 <Appenders>
2562 <RollingRandomAccessFile name="RollingRandomAccessFile" fileName="logs/app.log"
2563 filePattern="logs/$${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}-%i.log.gz">
2564 <PatternLayout>
2565 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
2566 </PatternLayout>
2567 <Policies>
2568 <TimeBasedTriggeringPolicy interval="6" modulate="true"/>
2569 <SizeBasedTriggeringPolicy size="250 MB"/>
2570 </Policies>
2571 </RollingRandomAccessFile>
2572 </Appenders>
2573 <Loggers>
2574 <Root level="error">
2575 <AppenderRef ref="RollingRandomAccessFile"/>
2576 </Root>
2577 </Loggers>
2578 </Configuration>]]></pre>
2579 </subsection>
2580 <a name="RoutingAppender"/>
2581 <subsection name="RoutingAppender">
2582 <p>
2583 The RoutingAppender evaluates LogEvents and then routes them to a subordinate Appender. The target
2584 Appender may be an appender previously configured and may be referenced by its name or the
2585 Appender can be dynamically created as needed. The RoutingAppender should be configured after any
2586 Appenders it references to allow it to shut down properly.
2587 </p>
2588 <table>
2589 <caption align="top">RoutingAppender Parameters</caption>
2590 <tr>
2591 <th>Parameter Name</th>
2592 <th>Type</th>
2593 <th>Description</th>
2594 </tr>
2595 <tr>
2596 <td>filter</td>
2597 <td>Filter</td>
2598 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
2599 may be used by using a CompositeFilter.</td>
2600 </tr>
2601 <tr>
2602 <td>name</td>
2603 <td>String</td>
2604 <td>The name of the Appender.</td>
2605 </tr>
2606 <tr>
2607 <td>rewritePolicy</td>
2608 <td>RewritePolicy</td>
2609 <td>The RewritePolicy that will manipulate the LogEvent.</td>
2610 </tr>
2611 <tr>
2612 <td>routes</td>
2613 <td>Routes</td>
2614 <td>Contains one or more Route declarations to identify the criteria for choosing Appenders.</td>
2615 </tr>
2616 <tr>
2617 <td>ignoreExceptions</td>
2618 <td>boolean</td>
2619 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
2620 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
2621 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
2622 <a href="#FailoverAppender">FailoverAppender</a>.</td>
2623 </tr>
2624 </table>
2625 <h4>Routes</h4>
2626 <p>
2627 The Routes element accepts a single, required attribute named "pattern". The pattern is evaluated
2628 against all the registered Lookups and the result is used to select a Route. Each Route may be
2629 configured with a key. If the key matches the result of evaluating the pattern then that Route
2630 will be selected. If no key is specified on a Route then that Route is the default. Only one Route
2631 can be configured as the default.
2632 </p>
2633 <p>
2634 Each Route must reference an Appender. If the Route contains a ref attribute then the
2635 Route will reference an Appender that was defined in the configuration. If the Route contains an
2636 Appender definition then an Appender will be created within the context of the RoutingAppender and
2637 will be reused each time a matching Appender name is referenced through a Route.
2638 </p>
2639 <p>
2640 Below is a sample configuration that uses a RoutingAppender to route all Audit events to
2641 a FlumeAppender and all other events will be routed to a RollingFileAppender that captures only
2642 the specific event type. Note that the AuditAppender was predefined while the RollingFileAppenders
2643 are created as needed.
2644 </p>
2645
2646 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2647 <Configuration status="warn" name="MyApp" packages="">
2648 <Appenders>
2649 <Flume name="AuditLogger" compress="true">
2650 <Agent host="192.168.10.101" port="8800"/>
2651 <Agent host="192.168.10.102" port="8800"/>
2652 <RFC5424Layout enterpriseNumber="18060" includeMDC="true" appName="MyApp"/>
2653 </Flume>
2654 <Routing name="Routing">
2655 <Routes pattern="$${sd:type}">
2656 <Route>
2657 <RollingFile name="Rolling-${sd:type}" fileName="${sd:type}.log"
2658 filePattern="${sd:type}.%i.log.gz">
2659 <PatternLayout>
2660 <pattern>%d %p %c{1.} [%t] %m%n</pattern>
2661 </PatternLayout>
2662 <SizeBasedTriggeringPolicy size="500" />
2663 </RollingFile>
2664 </Route>
2665 <Route ref="AuditLogger" key="Audit"/>
2666 </Routes>
2667 </Routing>
2668 </Appenders>
2669 <Loggers>
2670 <Root level="error">
2671 <AppenderRef ref="Routing"/>
2672 </Root>
2673 </Loggers>
2674 </Configuration>]]></pre>
2675 </subsection>
2676 <a name="SMTPAppender"/>
2677 <subsection name="SMTPAppender">
2678 <p>
2679 Sends an e-mail when a specific logging event occurs, typically on errors or fatal errors.
2680 </p>
2681 <p>
2682 The number of logging events delivered in this e-mail depend on the value of
2683 <b>BufferSize</b> option. The <code>SMTPAppender</code> keeps only the last
2684 <code>BufferSize</code> logging events in its cyclic buffer. This keeps
2685 memory requirements at a reasonable level while still delivering useful
2686 application context. All events in the buffer are included in the email.
2687 The buffer will contain the most recent events of level TRACE to WARN
2688 preceding the event that triggered the email.
2689 </p>
2690 <p>
2691 The default behavior is to trigger sending an email whenever an ERROR or higher
2692 severity event is logged and to format it as HTML. The circumstances on when the
2693 email is sent can be controlled by setting one or more filters on the Appender.
2694 As with other Appenders, the formatting can be controlled by specifying a Layout
2695 for the Appender.
2696 </p>
2697 <table>
2698 <caption align="top">SMTPAppender Parameters</caption>
2699 <tr>
2700 <th>Parameter Name</th>
2701 <th>Type</th>
2702 <th>Description</th>
2703 </tr>
2704 <tr>
2705 <td>bcc</td>
2706 <td>String</td>
2707 <td>The comma-separated list of BCC email addresses.</td>
2708 </tr>
2709 <tr>
2710 <td>cc</td>
2711 <td>String</td>
2712 <td>The comma-separated list of CC email addresses.</td>
2713 </tr>
2714 <tr>
2715 <td>bufferSize</td>
2716 <td>integer</td>
2717 <td>The maximum number of log events to be buffered for inclusion in the message. Defaults to 512.</td>
2718 </tr>
2719 <tr>
2720 <td>filter</td>
2721 <td>Filter</td>
2722 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
2723 may be used by using a CompositeFilter.
2724 </td>
2725 </tr>
2726 <tr>
2727 <td>from</td>
2728 <td>String</td>
2729 <td>The email address of the sender.</td>
2730 </tr>
2731 <tr>
2732 <td>layout</td>
2733 <td>Layout</td>
2734 <td>The Layout to use to format the LogEvent. The default is SerializedLayout.</td>
2735 </tr>
2736 <tr>
2737 <td>name</td>
2738 <td>String</td>
2739 <td>The name of the Appender.</td>
2740 </tr>
2741 <tr>
2742 <td>replyTo</td>
2743 <td>String</td>
2744 <td>The comma-separated list of reply-to email addresses.</td>
2745 </tr>
2746 <tr>
2747 <td>smtpDebug</td>
2748 <td>boolean</td>
2749 <td>When set to true enables session debugging on STDOUT. Defaults to false.</td>
2750 </tr>
2751 <tr>
2752 <td>smtpHost</td>
2753 <td>String</td>
2754 <td>The SMTP hostname to send to. This parameter is required.</td>
2755 </tr>
2756 <tr>
2757 <td>smtpPassword</td>
2758 <td>String</td>
2759 <td>The password required to authenticate against the SMTP server.</td>
2760 </tr>
2761 <tr>
2762 <td>smtpPort</td>
2763 <td>integer</td>
2764 <td>The SMTP port to send to. </td>
2765 </tr>
2766 <tr>
2767 <td>smtpProtocol</td>
2768 <td>String</td>
2769 <td>The SMTP transport protocol (such as "smtps", defaults to "smtp").</td>
2770 </tr>
2771 <tr>
2772 <td>smtpUsername</td>
2773 <td>String</td>
2774 <td>The username required to authenticate against the SMTP server.</td>
2775 </tr>
2776 <tr>
2777 <td>ignoreExceptions</td>
2778 <td>boolean</td>
2779 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
2780 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
2781 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
2782 <a href="#FailoverAppender">FailoverAppender</a>.</td>
2783 </tr>
2784 <tr>
2785 <td>to</td>
2786 <td>String</td>
2787 <td>The comma-separated list of recipient email addresses.</td>
2788 </tr>
2789 </table>
2790 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2791 <Configuration status="warn" name="MyApp" packages="">
2792 <Appenders>
2793 <SMTP name="Mail" subject="Error Log" to="errors@logging.apache.org" from="test@logging.apache.org"
2794 smtpHost="localhost" smtpPort="25" bufferSize="50">
2795 </SMTP>
2796 </Appenders>
2797 <Loggers>
2798 <Root level="error">
2799 <AppenderRef ref="Mail"/>
2800 </Root>
2801 </Loggers>
2802 </Configuration>]]></pre>
2803 </subsection>
2804 <a name="SocketAppender"/>
2805 <subsection name="SocketAppender">
2806 <p>
2807 The <code>SocketAppender</code> is an OutputStreamAppender that writes its output to a remote destination
2808 specified by a host and port. The data can be sent over either TCP or UDP and can be sent in any format.
2809 The default format is to send a Serialized LogEvent. Log4j 2 contains a SocketServer which is capable
2810 of receiving serialized LogEvents and routing them through the logging system on the server. You can optionally
2811 secure communication with SSL.
2812 </p>
2813 <table>
2814 <caption align="top"><code>SocketAppender</code> Parameters</caption>
2815 <tr>
2816 <th>Parameter Name</th>
2817 <th>Type</th>
2818 <th>Description</th>
2819 </tr>
2820 <tr>
2821 <td>name</td>
2822 <td>String</td>
2823 <td>The name of the Appender.</td>
2824 </tr>
2825 <tr>
2826 <td>host</td>
2827 <td>String</td>
2828 <td>The name or address of the system that is listening for log events. This parameter is required.</td>
2829 </tr>
2830 <tr>
2831 <td>port</td>
2832 <td>integer</td>
2833 <td>The port on the host that is listening for log events. This parameter must be specified.</td>
2834 </tr>
2835 <tr>
2836 <td>protocol</td>
2837 <td>String</td>
2838 <td>"TCP" (default), "SSL" or "UDP".</td>
2839 </tr>
2840 <tr>
2841 <td>SSL</td>
2842 <td>SslConfiguration</td>
2843 <td>Contains the configuration for the KeyStore and TrustStore.</td>
2844 </tr>
2845 <tr>
2846 <td>filter</td>
2847 <td>Filter</td>
2848 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
2849 may be used by using a CompositeFilter.</td>
2850 </tr>
2851 <tr>
2852 <td>immediateFail</td>
2853 <td>boolean</td>
2854 <td>When set to true, log events will not wait to try to reconnect and will fail immediately if the
2855 socket is not available.</td>
2856 </tr>
2857 <tr>
2858 <td>immediateFlush</td>
2859 <td>boolean</td>
2860 <td>When set to true - the default, each write will be followed by a flush.
2861 This will guarantee the data is written
2862 to disk but could impact performance.</td>
2863 </tr>
2864 <tr>
2865 <td>layout</td>
2866 <td>Layout</td>
2867 <td>The Layout to use to format the LogEvent. The default is SerializedLayout.</td>
2868 </tr>
2869 <tr>
2870 <td>reconnectionDelayMillis</td>
2871 <td>integer</td>
2872 <td>If set to a value greater than 0, after an error the SocketManager will attempt to reconnect to
2873 the server after waiting the specified number of milliseconds. If the reconnect fails then
2874 an exception will be thrown (which can be caught by the application if <code>ignoreExceptions</code> is
2875 set to <code>false</code>).</td>
2876 </tr>
2877 <tr>
2878 <td>connectTimeoutMillis</td>
2879 <td>integer</td>
2880 <td>The connect timeout in milliseconds. The default is 0 (infinite timeout, like Socket.connect()
2881 methods).</td>
2882 </tr>
2883 <tr>
2884 <td>ignoreExceptions</td>
2885 <td>boolean</td>
2886 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
2887 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
2888 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
2889 <a href="#FailoverAppender">FailoverAppender</a>.</td>
2890 </tr>
2891 </table>
2892
2893 <p>
2894 This is an unsecured TCP configuration:
2895 </p>
2896 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2897 <Configuration status="warn" name="MyApp" packages="">
2898 <Appenders>
2899 <Socket name="socket" host="localhost" port="9500">
2900 <SerializedLayout />
2901 </Socket>
2902 </Appenders>
2903 <Loggers>
2904 <Root level="error">
2905 <AppenderRef ref="socket"/>
2906 </Root>
2907 </Loggers>
2908 </Configuration>]]></pre>
2909
2910 <p>
2911 This is a secured SSL configuration:
2912 </p>
2913 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2914 <Configuration status="warn" name="MyApp" packages="">
2915 <Appenders>
2916 <Socket name="socket" host="localhost" port="9500">
2917 <SerializedLayout />
2918 <SSL>
2919 <KeyStore location="log4j2-keystore.jks" password="changeme"/>
2920 <TrustStore location="truststore.jks" password="changeme"/>
2921 </SSL>
2922 </Socket>
2923 </Appenders>
2924 <Loggers>
2925 <Root level="error">
2926 <AppenderRef ref="socket"/>
2927 </Root>
2928 </Loggers>
2929 </Configuration>]]></pre>
2930
2931 </subsection>
2932 <a name="SyslogAppender"/>
2933 <subsection name="SyslogAppender">
2934 <p>
2935 The <code>SyslogAppender</code> is a <code>SocketAppender</code> that writes its output to a remote destination
2936 specified by a host and port in a format that conforms with either the BSD Syslog format or the RFC 5424
2937 format. The data can be sent over either TCP or UDP.
2938 </p>
2939 <table>
2940 <caption align="top"><code>SyslogAppender</code> Parameters</caption>
2941 <tr>
2942 <th>Parameter Name</th>
2943 <th>Type</th>
2944 <th>Description</th>
2945 </tr>
2946 <tr>
2947 <td>advertise</td>
2948 <td>boolean</td>
2949 <td>Indicates whether the appender should be advertised.</td>
2950 </tr>
2951 <tr>
2952 <td>appName</td>
2953 <td>String</td>
2954 <td>The value to use as the APP-NAME in the RFC 5424 syslog record.</td>
2955 </tr>
2956 <tr>
2957 <td>charset</td>
2958 <td>String</td>
2959 <td>The character set to use when converting the syslog String to a byte array. The String must be
2960 a valid <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Charset</a>.
2961 If not specified, the default system Charset will be used.</td>
2962 </tr>
2963 <tr>
2964 <td>connectTimeoutMillis</td>
2965 <td>integer</td>
2966 <td>The connect timeout in milliseconds. The default is 0 (infinite timeout, like Socket.connect()
2967 methods).</td>
2968 </tr>
2969 <tr>
2970 <td>enterpriseNumber</td>
2971 <td>integer</td>
2972 <td>The IANA enterprise number as described in
2973 <a href="http://tools.ietf.org/html/rfc5424#section-7.2.2">RFC 5424</a></td>
2974 </tr>
2975 <tr>
2976 <td>filter</td>
2977 <td>Filter</td>
2978 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
2979 may be used by using a CompositeFilter.</td>
2980 </tr>
2981 <tr>
2982 <td>facility</td>
2983 <td>String</td>
2984 <td>The facility is used to try to classify the message. The facility option must be set to one of
2985 "KERN", "USER", "MAIL", "DAEMON", "AUTH", "SYSLOG", "LPR", "NEWS", "UUCP", "CRON", "AUTHPRIV",
2986 "FTP", "NTP", "AUDIT", "ALERT", "CLOCK", "LOCAL0", "LOCAL1", "LOCAL2", "LOCAL3", "LOCAL4", "LOCAL5",
2987 "LOCAL6", or "LOCAL7". These values may be specified as upper or lower case characters.</td>
2988 </tr>
2989 <tr>
2990 <td>format</td>
2991 <td>String</td>
2992 <td>If set to "RFC5424" the data will be formatted in accordance with RFC 5424. Otherwise, it will
2993 be formatted as a BSD Syslog record. Note that although BSD Syslog records are required to be
2994 1024 bytes or shorter the SyslogLayout does not truncate them. The RFC5424Layout also does not
2995 truncate records since the receiver must accept records of up to 2048 bytes and may accept records
2996 that are longer.</td>
2997 </tr>
2998 <tr>
2999 <td>host</td>
3000 <td>String</td>
3001 <td>The name or address of the system that is listening for log events. This parameter is required.</td>
3002 </tr>
3003 <tr>
3004 <td>id</td>
3005 <td>String</td>
3006 <td>The default structured data id to use when formatting according to RFC 5424. If the LogEvent contains
3007 a StructuredDataMessage the id from the Message will be used instead of this value.</td>
3008 </tr>
3009 <tr>
3010 <td>ignoreExceptions</td>
3011 <td>boolean</td>
3012 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
3013 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
3014 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
3015 <a href="#FailoverAppender">FailoverAppender</a>.</td>
3016 </tr>
3017 <tr>
3018 <td>immediateFail</td>
3019 <td>boolean</td>
3020 <td>When set to true, log events will not wait to try to reconnect and will fail immediately if the
3021 socket is not available.</td>
3022 </tr>
3023 <tr>
3024 <td>immediateFlush</td>
3025 <td>boolean</td>
3026 <td>When set to true - the default, each write will be followed by a flush.
3027 This will guarantee the data is written
3028 to disk but could impact performance.</td>
3029 </tr>
3030 <tr>
3031 <td>includeMDC</td>
3032 <td>boolean</td>
3033 <td>Indicates whether data from the ThreadContextMap will be included in the RFC 5424 Syslog record.
3034 Defaults to true.</td>
3035 </tr>
3036 <tr>
3037 <td>loggerFields</td>
3038 <td>List of KeyValuePairs</td>
3039 <td>Allows arbitrary PatternLayout patterns to be included as specified ThreadContext fields; no default
3040 specified. To use, include a &gt;LoggerFields&lt; nested element, containing one or more
3041 &gt;KeyValuePair&lt; elements. Each &gt;KeyValuePair&lt; must have a key attribute, which
3042 specifies the key name which will be used to identify the field within the MDC Structured Data element,
3043 and a value attribute, which specifies the PatternLayout pattern to use as the value.</td>
3044 </tr>
3045 <tr>
3046 <td>mdcExcludes</td>
3047 <td>String</td>
3048 <td>A comma separated list of mdc keys that should be excluded from the LogEvent. This is mutually
3049 exclusive with the mdcIncludes attribute. This attribute only applies to RFC 5424 syslog records.</td>
3050 </tr>
3051 <tr>
3052 <td>mdcIncludes</td>
3053 <td>String</td>
3054 <td>A comma separated list of mdc keys that should be included in the FlumeEvent. Any keys in the MDC
3055 not found in the list will be excluded. This option is mutually exclusive with the mdcExcludes
3056 attribute. This attribute only applies to RFC 5424 syslog records.</td>
3057 </tr>
3058 <tr>
3059 <td>mdcRequired</td>
3060 <td>String</td>
3061 <td>A comma separated list of mdc keys that must be present in the MDC. If a key is not present a
3062 LoggingException will be thrown. This attribute only applies to RFC 5424 syslog records.</td>
3063 </tr>
3064 <tr>
3065 <td>mdcPrefix</td>
3066 <td>String</td>
3067 <td>A string that should be prepended to each MDC key in order to distinguish it from event attributes.
3068 The default string is "mdc:". This attribute only applies to RFC 5424 syslog records.</td>
3069 </tr>
3070 <tr>
3071 <td>messageId</td>
3072 <td>String</td>
3073 <td>The default value to be used in the MSGID field of RFC 5424 syslog records. </td>
3074 </tr>
3075 <tr>
3076 <td>name</td>
3077 <td>String</td>
3078 <td>The name of the Appender.</td>
3079 </tr>
3080 <tr>
3081 <td>newLine</td>
3082 <td>boolean</td>
3083 <td>If true, a newline will be appended to the end of the syslog record. The default is false.</td>
3084 </tr>
3085 <tr>
3086 <td>port</td>
3087 <td>integer</td>
3088 <td>The port on the host that is listening for log events. This parameter must be specified.</td>
3089 </tr>
3090 <tr>
3091 <td>protocol</td>
3092 <td>String</td>
3093 <td>"TCP" or "UDP". This parameter is required.</td>
3094 </tr>
3095 <tr>
3096 <td>SSL</td>
3097 <td>SslConfiguration</td>
3098 <td>Contains the configuration for the KeyStore and TrustStore.</td>
3099 </tr>
3100 <tr>
3101 <td>reconnectionDelayMillis</td>
3102 <td>integer</td>
3103 <td>If set to a value greater than 0, after an error the SocketManager will attempt to reconnect to
3104 the server after waiting the specified number of milliseconds. If the reconnect fails then
3105 an exception will be thrown (which can be caught by the application if <code>ignoreExceptions</code> is
3106 set to <code>false</code>).</td>
3107 </tr>
3108 </table>
3109 <p>
3110 A sample syslogAppender configuration that is configured with two <code>SyslogAppender</code>s, one using the BSD
3111 format and one using RFC 5424.
3112 </p>
3113
3114 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
3115 <Configuration status="warn" name="MyApp" packages="">
3116 <Appenders>
3117 <Syslog name="bsd" host="localhost" port="514" protocol="TCP"/>
3118 <Syslog name="RFC5424" format="RFC5424" host="localhost" port="8514"
3119 protocol="TCP" appName="MyApp" includeMDC="true"
3120 facility="LOCAL0" enterpriseNumber="18060" newLine="true"
3121 messageId="Audit" id="App"/>
3122 </Appenders>
3123 <Loggers>
3124 <Logger name="com.mycorp" level="error">
3125 <AppenderRef ref="RFC5424"/>
3126 </Logger>
3127 <Root level="error">
3128 <AppenderRef ref="bsd"/>
3129 </Root>
3130 </Loggers>
3131 </Configuration>]]></pre>
3132
3133 <p>
3134 For SSL this appender writes its output to a remote destination specified by a host and port over SSL in
3135 a format that conforms with either the BSD Syslog format or the RFC 5424 format.
3136 </p>
3137
3138 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
3139 <Configuration status="warn" name="MyApp" packages="">
3140 <Appenders>
3141 <TLSSyslog name="bsd" host="localhost" port="6514">
3142 <SSL>
3143 <KeyStore location="log4j2-keystore.jks" password="changeme"/>
3144 <TrustStore location="truststore.jks" password="changeme"/>
3145 </SSL>
3146 </TLSSyslog>
3147 </Appenders>
3148 <Loggers>
3149 <Root level="error">
3150 <AppenderRef ref="bsd"/>
3151 </Root>
3152 </Loggers>
3153 </Configuration>]]></pre>
3154 </subsection>
3155
3156 </section>
3157 </body>
3158 </document>
0 <?xml version="1.0"?>
1 <!--
2 Licensed to the Apache Software Foundation (ASF) under one or more
3 contributor license agreements. See the NOTICE file distributed with
4 this work for additional information regarding copyright ownership.
5 The ASF licenses this file to You under the Apache License, Version 2.0
6 (the "License"); you may not use this file except in compliance with
7 the License. You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 -->
17
18 <document xmlns="http://maven.apache.org/XDOC/2.0"
19 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20 xsi:schemaLocation="http://maven.apache.org/XDOC/2.0 http://maven.apache.org/xsd/xdoc-2.0.xsd">
21 <properties>
22 <title>Log4j 2 Appenders</title>
23 <author email="rgoers@apache.org">Ralph Goers</author>
24 <author email="ggrgeory@apache.org">Gary Gregory</author>
25 <author email="nickwilliams@apache.org">Nick Williams</author>
26 </properties>
27
28 <body>
29 <section name="Appenders">
30 <p>
31 Appenders are responsible for delivering LogEvents to their destination. Every Appender must
32 implement the <a href="../log4j-core/apidocs/org/apache/logging/log4j/core/Appender.html">Appender</a>
33 interface. Most Appenders will extend
34 <a href="../log4j-core/apidocs/org/apache/logging/log4j/core/appender/AbstractAppender.html">AbstractAppender</a>
35 which adds <a href="../log4j-core/apidocs/org/apache/logging/log4j/core/LifeCycle.html">Lifecycle</a>
36 and <a href="../log4j-core/apidocs/org/apache/logging/log4j/core/filter/Filterable.html">Filterable</a>
37 support. Lifecycle allows components to finish initialization after configuration has completed and to
38 perform cleanup during shutdown. Filterable allows the component to have Filters attached to it which are
39 evaluated during event processing.
40 </p>
41 <p>
42 Appenders usually are only responsible for writing the event data to the target destination. In most cases
43 they delegate responsibility for formatting the event to a <a href="layouts.html">layout</a>. Some
44 appenders wrap other appenders so that they can modify the LogEvent, handle a failure in an Appender,
45 route the event to a subordinate Appender based on advanced Filter criteria or provide similar functionality
46 that does not directly format the event for viewing.
47 </p>
48 <p>
49 Appenders always have a name so that they can be referenced from Loggers.
50 </p>
51 <a name="AsyncAppender"/>
52 <subsection name="AsyncAppender">
53 <p>The AsyncAppender accepts references to other Appenders and causes LogEvents to be written to them
54 on a separate Thread. Note that exceptions while writing to those Appenders will be hidden from
55 the application. The AsyncAppender should be configured after the appenders it references to allow it
56 to shut down properly.</p>
57 <table>
58 <caption align="top">AsyncAppender Parameters</caption>
59 <tr>
60 <th>Parameter Name</th>
61 <th>Type</th>
62 <th>Description</th>
63 </tr>
64 <tr>
65 <td>AppenderRef</td>
66 <td>String</td>
67 <td>The name of the Appenders to invoke asynchronously. Multiple AppenderRef
68 elements can be configured.</td>
69 </tr>
70 <tr>
71 <td>blocking</td>
72 <td>boolean</td>
73 <td>If true, the appender will wait until there are free slots in the queue. If false, the event
74 will be written to the error appender if the queue is full. The default is true.</td>
75 </tr>
76 <tr>
77 <td>bufferSize</td>
78 <td>integer</td>
79 <td>Specifies the maximum number of events that can be queued. The default is 128.</td>
80 </tr>
81 <tr>
82 <td>errorRef</td>
83 <td>String</td>
84 <td>The name of the Appender to invoke if none of the appenders can be called, either due to errors
85 in the appenders or because the queue is full. If not specified then errors will be ignored.</td>
86 </tr>
87 <tr>
88 <td>filter</td>
89 <td>Filter</td>
90 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
91 may be used by using a CompositeFilter.</td>
92 </tr>
93 <tr>
94 <td>name</td>
95 <td>String</td>
96 <td>The name of the Appender.</td>
97 </tr>
98 <tr>
99 <td>ignoreExceptions</td>
100 <td>boolean</td>
101 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
102 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
103 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
104 <a href="#FailoverAppender">FailoverAppender</a>.</td>
105 </tr>
106 <tr>
107 <td>includeLocation</td>
108 <td>boolean</td>
109 <td>Extracting location is an expensive operation (it can make
110 logging 5 - 20 times slower). To improve performance, location is
111 not included by default when adding a log event to the queue.
112 You can change this by setting includeLocation="true".</td>
113 </tr>
114 </table>
115 <p>
116 A typical AsyncAppender configuration might look like:
117 </p>
118
119 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
120 <Configuration status="warn" name="MyApp" packages="">
121 <Appenders>
122 <File name="MyFile" fileName="logs/app.log">
123 <PatternLayout>
124 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
125 </PatternLayout>
126 </File>
127 <Async name="Async">
128 <AppenderRef ref="MyFile"/>
129 </Async>
130 </Appenders>
131 <Loggers>
132 <Root level="error">
133 <AppenderRef ref="Async"/>
134 </Root>
135 </Loggers>
136 </Configuration>]]></pre>
137 </subsection>
138 <a name="ConsoleAppender"/>
139 <subsection name="ConsoleAppender">
140 <p>
141 As one might expect, the ConsoleAppender writes its output to either System.err or System.out with System.err
142 being the default target. A Layout must be provided to format the LogEvent.
143 </p>
144 <table>
145 <caption align="top">ConsoleAppender Parameters</caption>
146 <tr>
147 <th>Parameter Name</th>
148 <th>Type</th>
149 <th>Description</th>
150 </tr>
151 <tr>
152 <td>filter</td>
153 <td>Filter</td>
154 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
155 may be used by using a CompositeFilter.</td>
156 </tr>
157 <tr>
158 <td>layout</td>
159 <td>Layout</td>
160 <td>The Layout to use to format the LogEvent. If no layout is supplied the default pattern layout
161 of "%m%n" will be used.</td>
162 </tr>
163 <tr>
164 <td>follow</td>
165 <td>boolean</td>
166 <td>Identifies whether the appender honors reassignments of System.out or System.err
167 via System.setOut or System.setErr made after configuration. Note that the follow
168 attribute cannot be used with Jansi on Windows.</td>
169 </tr>
170 <tr>
171 <td>name</td>
172 <td>String</td>
173 <td>The name of the Appender.</td>
174 </tr>
175 <tr>
176 <td>ignoreExceptions</td>
177 <td>boolean</td>
178 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
179 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
180 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
181 <a href="#FailoverAppender">FailoverAppender</a>.</td>
182 </tr>
183 <tr>
184 <td>target</td>
185 <td>String</td>
186 <td>Either "SYSTEM_OUT" or "SYSTEM_ERR". The default is "SYSTEM_ERR".</td>
187 </tr>
188 </table>
189 <p>
190 A typical Console configuration might look like:
191 </p>
192
193 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
194 <Configuration status="warn" name="MyApp" packages="">
195 <Appenders>
196 <Console name="STDOUT" target="SYSTEM_OUT">
197 <PatternLayout pattern="%m%n"/>
198 </Console>
199 </Appenders>
200 <Loggers>
201 <Root level="error">
202 <AppenderRef ref="STDOUT"/>
203 </Root>
204 </Loggers>
205 </Configuration>]]></pre>
206 </subsection>
207 <a name="FailoverAppender"/>
208 <subsection name="FailoverAppender">
209 <p>The FailoverAppender wraps a set of appenders. If the primary Appender fails the secondary appenders will be
210 tried in order until one succeeds or there are no more secondaries to try.</p>
211 <table>
212 <caption align="top">FailoverAppender Parameters</caption>
213 <tr>
214 <th>Parameter Name</th>
215 <th>Type</th>
216 <th>Description</th>
217 </tr>
218 <tr>
219 <td>filter</td>
220 <td>Filter</td>
221 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
222 may be used by using a CompositeFilter.</td>
223 </tr>
224 <tr>
225 <td>primary</td>
226 <td>String</td>
227 <td>The name of the primary Appender to use.</td>
228 </tr>
229 <tr>
230 <td>failovers</td>
231 <td>String[]</td>
232 <td>The names of the secondary Appenders to use.</td>
233 </tr>
234
235 <tr>
236 <td>name</td>
237 <td>String</td>
238 <td>The name of the Appender.</td>
239 </tr>
240 <tr>
241 <td>retryIntervalSeconds</td>
242 <td>integer</td>
243 <td>The number of seconds that should pass before retrying the primary Appender. The default is 60.</td>
244 </tr>
245 <tr>
246 <td>ignoreExceptions</td>
247 <td>boolean</td>
248 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
249 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
250 caller, instead.</td>
251 </tr>
252 <tr>
253 <td>target</td>
254 <td>String</td>
255 <td>Either "SYSTEM_OUT" or "SYSTEM_ERR". The default is "SYSTEM_ERR".</td>
256 </tr>
257 </table>
258 <p>
259 A Failover configuration might look like:
260 </p>
261
262 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
263 <Configuration status="warn" name="MyApp" packages="">
264 <Appenders>
265 <RollingFile name="RollingFile" fileName="logs/app.log" filePattern="logs/app-%d{MM-dd-yyyy}.log.gz"
266 ignoreExceptions="false">
267 <PatternLayout>
268 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
269 </PatternLayout>
270 <TimeBasedTriggeringPolicy />
271 </RollingFile>
272 <Console name="STDOUT" target="SYSTEM_OUT" ignoreExceptions="false">
273 <PatternLayout pattern="%m%n"/>
274 </Console>
275 <Failover name="Failover" primary="RollingFile">
276 <Failovers>
277 <AppenderRef ref="Console"/>
278 </Failovers>
279 </Failover>
280 </Appenders>
281 <Loggers>
282 <Root level="error">
283 <AppenderRef ref="Failover"/>
284 </Root>
285 </Loggers>
286 </Configuration>]]></pre>
287 </subsection>
288 <a name="FileAppender"/>
289 <subsection name="FileAppender">
290 <p>The FileAppender is an OutputStreamAppender that writes to the File named in the fileName parameter. The
291 FileAppender uses a FileManager (which extends OutputStreamManager) to actually perform the file I/O. While
292 FileAppenders from different Configurations cannot be shared, the FileManagers can be if the Manager is
293 accessible. For example, two web applications in a servlet container can have their own configuration and
294 safely write to the same file if Log4j is in a ClassLoader that is common to both of them.</p>
295 <table>
296 <caption align="top">FileAppender Parameters</caption>
297 <tr>
298 <th>Parameter Name</th>
299 <th>Type</th>
300 <th>Description</th>
301 </tr>
302 <tr>
303 <td>append</td>
304 <td>boolean</td>
305 <td>When true - the default, records will be appended to the end of the file. When set to false,
306 the file will be cleared before new records are written.</td>
307 </tr>
308 <tr>
309 <td>bufferedIO</td>
310 <td>boolean</td>
311 <td>When true - the default, records will be written to a buffer and the data will be written to
312 disk when the buffer is full or, if immediateFlush is set, when the record is written.
313 File locking cannot be used with bufferedIO. Performance tests have shown that using buffered I/O
314 significantly improves performance, even if immediateFlush is enabled.</td>
315 </tr>
316 <tr>
317 <td>bufferSize</td>
318 <td>int</td>
319 <td>When bufferedIO is true, this is the buffer size, the default is 8192 bytes.</td>
320 </tr>
321 <tr>
322 <td>filter</td>
323 <td>Filter</td>
324 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
325 may be used by using a CompositeFilter.</td>
326 </tr>
327 <tr>
328 <td>fileName</td>
329 <td>String</td>
330 <td>The name of the file to write to. If the file, or any of its parent directories, do not exist,
331 they will be created.</td>
332 </tr>
333 <tr>
334 <td>immediateFlush</td>
335 <td>boolean</td>
336 <td><p>When set to true - the default, each write will be followed by a flush.
337 This will guarantee the data is written
338 to disk but could impact performance.</p>
339 <p>Flushing after every write is only useful when using this
340 appender with synchronous loggers. Asynchronous loggers and
341 appenders will automatically flush at the end of a batch of events,
342 even if immediateFlush is set to false. This also guarantees
343 the data is written to disk but is more efficient.</p>
344 </td>
345 </tr>
346 <tr>
347 <td>layout</td>
348 <td>Layout</td>
349 <td>The Layout to use to format the LogEvent</td>
350 </tr>
351 <tr>
352 <td>locking</td>
353 <td>boolean</td>
354 <td>When set to true, I/O operations will occur only while the file lock is held allowing FileAppenders
355 in multiple JVMs and potentially multiple hosts to write to the same file simultaneously. This
356 will significantly impact performance so should be used carefully. Furthermore, on many systems
357 the file lock is "advisory" meaning that other applications can perform operations on the file
358 without acquiring a lock. The default value is false.</td>
359 </tr>
360
361 <tr>
362 <td>name</td>
363 <td>String</td>
364 <td>The name of the Appender.</td>
365 </tr>
366 <tr>
367 <td>ignoreExceptions</td>
368 <td>boolean</td>
369 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
370 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
371 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
372 <a href="#FailoverAppender">FailoverAppender</a>.</td>
373 </tr>
374 </table>
375 <p>
376 Here is a sample File configuration:
377 </p>
378
379 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
380 <Configuration status="warn" name="MyApp" packages="">
381 <Appenders>
382 <File name="MyFile" fileName="logs/app.log">
383 <PatternLayout>
384 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
385 </PatternLayout>
386 </File>
387 </Appenders>
388 <Loggers>
389 <Root level="error">
390 <AppenderRef ref="MyFile"/>
391 </Root>
392 </Loggers>
393 </Configuration>]]></pre>
394 </subsection>
395 <a name="FlumeAppender"/>
396 <subsection name="FlumeAppender">
397 <p><i>This is an optional component supplied in a separate jar.</i></p>
398 <p><a href="http://flume.apache.org/index.html">Apache Flume</a> is a distributed, reliable,
399 and available system for efficiently collecting, aggregating, and moving large amounts of log data
400 from many different sources to a centralized data store. The FlumeAppender takes LogEvents and sends
401 them to a Flume agent as serialized Avro events for consumption.</p>
402 <p>
403 The Flume Appender supports three modes of operation.
404 </p>
405 <ol>
406 <li>It can act as a remote Flume client which sends Flume events via Avro to a Flume Agent configured
407 with an Avro Source.</li>
408 <li>It can act as an embedded Flume Agent where Flume events pass directly into Flume for processing.</li>
409 <li>It can persist events to a local BerkeleyDB data store and then asynchronously send the events to
410 Flume, similar to the embedded Flume Agent but without most of the Flume dependencies.</li>
411 </ol>
412 <p>
413 Usage as an embedded agent will cause the messages to be directly passed to the Flume Channel and then
414 control will be immediately returned to the application. All interaction with remote agents will occur
415 asynchronously. Setting the "type" attribute to "Embedded" will force the use of the embedded agent. In
416 addition, configuring agent properties in the appender configuration will also cause the embedded agent
417 to be used.
418 </p>
419 <table>
420 <caption align="top">FlumeAppender Parameters</caption>
421 <tr>
422 <th>Parameter Name</th>
423 <th>Type</th>
424 <th>Description</th>
425 </tr>
426 <tr>
427 <td>agents</td>
428 <td>Agent[]</td>
429 <td>An array of Agents to which the logging events should be sent. If more than one agent is specified
430 the first Agent will be the primary and subsequent Agents will be used in the order specified as
431 secondaries should the primary Agent fail. Each Agent definition supplies the Agents host and port.
432 The specification of agents and properties are mutually exclusive. If both are configured an
433 error will result.</td>
434 </tr>
435 <tr>
436 <td>agentRetries</td>
437 <td>integer</td>
438 <td>The number of times the agent should be retried before failing to a secondary. This parameter is
439 ignored when type="persistent" is specified (agents are tried once before failing to the next).</td>
440 </tr>
441 <tr>
442 <td>batchSize</td>
443 <td>integer</td>
444 <td>Specifies the number of events that should be sent as a batch. The default is 1. <i>This
445 parameter only applies to the Flume Appender.</i></td>
446 </tr>
447 <tr>
448 <td>compress</td>
449 <td>boolean</td>
450 <td>When set to true the message body will be compressed using gzip</td>
451 </tr>
452 <tr>
453 <td>connectTimeoutMillis</td>
454 <td>integer</td>
455 <td>The number of milliseconds Flume will wait before timing out the connection.</td>
456 </tr>
457 <tr>
458 <td>dataDir</td>
459 <td>String</td>
460 <td>Directory where the Flume write ahead log should be written. Valid only when embedded is set
461 to true and Agent elements are used instead of Property elements.</td>
462 </tr>
463 <tr>
464 <td>filter</td>
465 <td>Filter</td>
466 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
467 may be used by using a CompositeFilter.</td>
468 </tr>
469 <tr>
470 <td>eventPrefix</td>
471 <td>String</td>
472 <td>The character string to prepend to each event attribute in order to distinguish it from MDC attributes.
473 The default is an empty string.</td>
474 </tr>
475 <tr>
476 <td>flumeEventFactory</td>
477 <td>FlumeEventFactory</td>
478 <td>Factory that generates the Flume events from Log4j events. The default factory is the
479 FlumeAvroAppender itself.</td>
480 </tr>
481 <tr>
482 <td>layout</td>
483 <td>Layout</td>
484 <td>The Layout to use to format the LogEvent. If no layout is specified RFC5424Layout will be used.</td>
485 </tr>
486 <tr>
487 <td>lockTimeoutRetries</td>
488 <td>integer</td>
489 <td>The number of times to retry if a LockConflictException occurs while writing to Berkeley DB. The
490 default is 5.</td>
491 </tr>
492 <tr>
493 <td>maxDelayMillis</td>
494 <td>integer</td>
495 <td>The maximum number of milliseconds to wait for batchSize events before publishing the batch.</td>
496 </tr>
497 <tr>
498 <td>mdcExcludes</td>
499 <td>String</td>
500 <td>A comma separated list of mdc keys that should be excluded from the FlumeEvent. This is mutually
501 exclusive with the mdcIncludes attribute.</td>
502 </tr>
503 <tr>
504 <td>mdcIncludes</td>
505 <td>String</td>
506 <td>A comma separated list of mdc keys that should be included in the FlumeEvent. Any keys in the MDC
507 not found in the list will be excluded. This option is mutually exclusive with the mdcExcludes
508 attribute.</td>
509 </tr>
510 <tr>
511 <td>mdcRequired</td>
512 <td>String</td>
513 <td>A comma separated list of mdc keys that must be present in the MDC. If a key is not present a
514 LoggingException will be thrown.</td>
515 </tr>
516 <tr>
517 <td>mdcPrefix</td>
518 <td>String</td>
519 <td>A string that should be prepended to each MDC key in order to distinguish it from event attributes.
520 The default string is "mdc:".</td>
521 </tr>
522 <tr>
523 <td>name</td>
524 <td>String</td>
525 <td>The name of the Appender.</td>
526 </tr>
527 <tr>
528 <td>properties</td>
529 <td>Property[]</td>
530 <td><p>One or more Property elements that are used to configure the Flume Agent. The properties must be
531 configured without the agent name (the appender name is used for this) and no sources can be
532 configured. Interceptors can be specified for the source using "sources.log4j-source.interceptors".
533 All other Flume configuration properties are allowed. Specifying both Agent and Property
534 elements will result in an error.</p>
535 <p>When used to configure in Persistent mode the valid properties are:</p>
536 <ol>
537 <li>"keyProvider" to specify the name of the plugin to provide the secret key for encryption.</li>
538 </ol>
539 </td>
540 </tr>
541 <tr>
542 <td>requestTimeoutMillis</td>
543 <td>integer</td>
544 <td>The number of milliseconds Flume will wait before timing out the request.</td>
545 </tr>
546 <tr>
547 <td>ignoreExceptions</td>
548 <td>boolean</td>
549 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
550 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
551 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
552 <a href="#FailoverAppender">FailoverAppender</a>.</td>
553 </tr>
554 <tr>
555 <td>type</td>
556 <td>enumeration</td>
557 <td>One of "Avro", "Embedded", or "Persistent" to indicate which variation of the Appender is desired.</td>
558 </tr>
559 </table>
560 <p>
561 A sample FlumeAppender configuration that is configured with a primary and a secondary agent,
562 compresses the body, and formats the body using the RFC5424Layout:
563 </p>
564
565 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
566 <Configuration status="warn" name="MyApp" packages="">
567 <Appenders>
568 <Flume name="eventLogger" compress="true">
569 <Agent host="192.168.10.101" port="8800"/>
570 <Agent host="192.168.10.102" port="8800"/>
571 <RFC5424Layout enterpriseNumber="18060" includeMDC="true" appName="MyApp"/>
572 </Flume>
573 </Appenders>
574 <Loggers>
575 <Root level="error">
576 <AppenderRef ref="eventLogger"/>
577 </Root>
578 </Loggers>
579 </Configuration>]]></pre>
580 <p>
581 A sample FlumeAppender configuration that is configured with a primary and a secondary agent,
582 compresses the body, formats the body using the RFC5424Layout, and persists encrypted events to disk:
583 </p>
584
585 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
586 <Configuration status="warn" name="MyApp" packages="">
587 <Appenders>
588 <Flume name="eventLogger" compress="true" type="persistent" dataDir="./logData">
589 <Agent host="192.168.10.101" port="8800"/>
590 <Agent host="192.168.10.102" port="8800"/>
591 <RFC5424Layout enterpriseNumber="18060" includeMDC="true" appName="MyApp"/>
592 <Property name="keyProvider">MySecretProvider</Property>
593 </Flume>
594 </Appenders>
595 <Loggers>
596 <Root level="error">
597 <AppenderRef ref="eventLogger"/>
598 </Root>
599 </Loggers>
600 </Configuration>]]></pre>
601 <p>
602 A sample FlumeAppender configuration that is configured with a primary and a secondary agent,
603 compresses the body, formats the body using RFC5424Layout and passes the events to an embedded Flume
604 Agent.
605 </p>
606 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
607 <Configuration status="warn" name="MyApp" packages="">
608 <Appenders>
609 <Flume name="eventLogger" compress="true" type="Embedded">
610 <Agent host="192.168.10.101" port="8800"/>
611 <Agent host="192.168.10.102" port="8800"/>
612 <RFC5424Layout enterpriseNumber="18060" includeMDC="true" appName="MyApp"/>
613 </Flume>
614 <Console name="STDOUT">
615 <PatternLayout pattern="%d [%p] %c %m%n"/>
616 </Console>
617 </Appenders>
618 <Loggers>
619 <Logger name="EventLogger" level="info">
620 <AppenderRef ref="eventLogger"/>
621 </Logger>
622 <Root level="warn">
623 <AppenderRef ref="STDOUT"/>
624 </Root>
625 </Loggers>
626 </Configuration>]]></pre>
627 <p>
628 A sample FlumeAppender configuration that is configured with a primary and a secondary agent using
629 Flume configuration properties, compresses the body, formats the body using RFC5424Layout and passes the
630 events to an embedded Flume Agent.
631 </p>
632 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
633 <Configuration status="error" name="MyApp" packages="">
634 <Appenders>
635 <Flume name="eventLogger" compress="true" type="Embedded">
636 <Property name="channels">file</Property>
637 <Property name="channels.file.type">file</Property>
638 <Property name="channels.file.checkpointDir">target/file-channel/checkpoint</Property>
639 <Property name="channels.file.dataDirs">target/file-channel/data</Property>
640 <Property name="sinks">agent1 agent2</Property>
641 <Property name="sinks.agent1.channel">file</Property>
642 <Property name="sinks.agent1.type">avro</Property>
643 <Property name="sinks.agent1.hostname">192.168.10.101</Property>
644 <Property name="sinks.agent1.port">8800</Property>
645 <Property name="sinks.agent1.batch-size">100</Property>
646 <Property name="sinks.agent2.channel">file</Property>
647 <Property name="sinks.agent2.type">avro</Property>
648 <Property name="sinks.agent2.hostname">192.168.10.102</Property>
649 <Property name="sinks.agent2.port">8800</Property>
650 <Property name="sinks.agent2.batch-size">100</Property>
651 <Property name="sinkgroups">group1</Property>
652 <Property name="sinkgroups.group1.sinks">agent1 agent2</Property>
653 <Property name="sinkgroups.group1.processor.type">failover</Property>
654 <Property name="sinkgroups.group1.processor.priority.agent1">10</Property>
655 <Property name="sinkgroups.group1.processor.priority.agent2">5</Property>
656 <RFC5424Layout enterpriseNumber="18060" includeMDC="true" appName="MyApp"/>
657 </Flume>
658 <Console name="STDOUT">
659 <PatternLayout pattern="%d [%p] %c %m%n"/>
660 </Console>
661 </Appenders>
662 <Loggers>
663 <Logger name="EventLogger" level="info">
664 <AppenderRef ref="eventLogger"/>
665 </Logger>
666 <Root level="warn">
667 <AppenderRef ref="STDOUT"/>
668 </Root>
669 </Loggers>
670 </Configuration>]]></pre>
671 </subsection>
672 <a name="JDBCAppender"/>
673 <subsection name="JDBCAppender">
674 <p>The JDBCAppender writes log events to a relational database table using standard JDBC. It can be configured
675 to obtain JDBC connections using a JNDI <code>DataSource</code> or a custom factory method. Whichever
676 approach you take, it <strong><em>must</em></strong> be backed by a connection pool. Otherwise, logging
677 performance will suffer greatly.</p>
678 <table>
679 <caption align="top">JDBCAppender Parameters</caption>
680 <tr>
681 <th>Parameter Name</th>
682 <th>Type</th>
683 <th>Description</th>
684 </tr>
685 <tr>
686 <td>name</td>
687 <td>String</td>
688 <td><em>Required.</em> The name of the Appender.</td>
689 </tr>
690 <tr>
691 <td>ignoreExceptions</td>
692 <td>boolean</td>
693 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
694 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
695 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
696 <a href="#FailoverAppender">FailoverAppender</a>.</td>
697 </tr>
698 <tr>
699 <td>filter</td>
700 <td>Filter</td>
701 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter may be
702 used by using a CompositeFilter.</td>
703 </tr>
704 <tr>
705 <td>bufferSize</td>
706 <td>int</td>
707 <td>If an integer greater than 0, this causes the appender to buffer log events and flush whenever the
708 buffer reaches this size.</td>
709 </tr>
710 <tr>
711 <td>connectionSource</td>
712 <td>ConnectionSource</td>
713 <td><em>Required.</em> The connections source from which database connections should be retrieved.</td>
714 </tr>
715 <tr>
716 <td>tableName</td>
717 <td>String</td>
718 <td><em>Required.</em> The name of the database table to insert log events into.</td>
719 </tr>
720 <tr>
721 <td>columnConfigs</td>
722 <td>ColumnConfig[]</td>
723 <td><em>Required.</em> Information about the columns that log event data should be inserted into and how
724 to insert that data. This is represented with multiple <code>&lt;Column&gt;</code> elements.</td>
725 </tr>
726 </table>
727 <p>When configuring the JDBCAppender, you must specify a <code>ConnectionSource</code> implementation from
728 which the Appender gets JDBC connections. You must use exactly one of the <code>&lt;DataSource&gt;</code>
729 or <code>&lt;ConnectionFactory&gt;</code> nested elements.</p>
730 <table>
731 <caption align="top">DataSource Parameters</caption>
732 <tr>
733 <th>Parameter Name</th>
734 <th>Type</th>
735 <th>Description</th>
736 </tr>
737 <tr>
738 <td>jndiName</td>
739 <td>String</td>
740 <td><em>Required.</em> The full, prefixed JNDI name that the <code>javax.sql.DataSource</code> is bound
741 to, such as <code>java:/comp/env/jdbc/LoggingDatabase</code>. The <code>DataSource</code> must be backed
742 by a connection pool; otherwise, logging will be very slow.</td>
743 </tr>
744 </table>
745 <table>
746 <caption align="top">ConnectionFactory Parameters</caption>
747 <tr>
748 <th>Parameter Name</th>
749 <th>Type</th>
750 <th>Description</th>
751 </tr>
752 <tr>
753 <td>class</td>
754 <td>Class</td>
755 <td><em>Required.</em> The fully qualified name of a class containing a static factory method for
756 obtaining JDBC connections.</td>
757 </tr>
758 <tr>
759 <td>method</td>
760 <td>Method</td>
761 <td><em>Required.</em> The name of a static factory method for obtaining JDBC connections. This method
762 must have no parameters and its return type must be either <code>java.sql.Connection</code> or
763 <code>DataSource</code>. If the method returns <code>Connection</code>s, it must obtain them from a
764 connection pool (and they will be returned to the pool when Log4j is done with them); otherwise, logging
765 will be very slow. If the method returns a <code>DataSource</code>, the <code>DataSource</code> will
766 only be retrieved once, and it must be backed by a connection pool for the same reasons.</td>
767 </tr>
768 </table>
769 <p>When configuring the JDBCAppender, use the nested <code>&lt;Column&gt;</code> elements to specify which
770 columns in the table should be written to and how to write to them. The JDBCAppender uses this information
771 to formulate a <code>PreparedStatement</code> to insert records without SQL injection vulnerability.</p>
772 <table>
773 <caption align="top">Column Parameters</caption>
774 <tr>
775 <th>Parameter Name</th>
776 <th>Type</th>
777 <th>Description</th>
778 </tr>
779 <tr>
780 <td>name</td>
781 <td>String</td>
782 <td><em>Required.</em> The name of the database column.</td>
783 </tr>
784 <tr>
785 <td>pattern</td>
786 <td>String</td>
787 <td>Use this attribute to insert a value or values from the log event in this column using a
788 <code>PatternLayout</code> pattern. Simply specify any legal pattern in this attribute. Either this
789 attribute, <code>literal</code>, or <code>isEventTimestamp="true"</code> must be specified, but not more
790 than one of these.</td>
791 </tr>
792 <tr>
793 <td>literal</td>
794 <td>String</td>
795 <td>Use this attribute to insert a literal value in this column. The value will be included directly in
796 the insert SQL, without any quoting (which means that if you want this to be a string, your value should
797 contain single quotes around it like this: <code>literal="'Literal String'"</code>). This is especially
798 useful for databases that don't support identity columns. For example, if you are using Oracle you could
799 specify <code>literal="NAME_OF_YOUR_SEQUENCE.NEXTVAL"</code> to insert a unique ID in an ID column.
800 Either this attribute, <code>pattern</code>, or <code>isEventTimestamp="true"</code> must be specified,
801 but not more than one of these.</td>
802 </tr>
803 <tr>
804 <td>isEventTimestamp</td>
805 <td>boolean</td>
806 <td>Use this attribute to insert the event timestamp in this column, which should be a SQL datetime. The
807 value will be inserted as a <code>java.sql.Types.TIMESTAMP</code>. Either this attribute (equal to
808 <code>true</code>), <code>pattern</code>, or <code>isEventTimestamp</code> must be specified, but not
809 more than one of these.</td>
810 </tr>
811 <tr>
812 <td>isUnicode</td>
813 <td>boolean</td>
814 <td>This attribute is ignored unless <code>pattern</code> is specified. If <code>true</code> or omitted
815 (default), the value will be inserted as unicode (<code>setNString</code> or <code>setNClob</code>).
816 Otherwise, the value will be inserted non-unicode (<code>setString</code> or <code>setClob</code>).</td>
817 </tr>
818 <tr>
819 <td>isClob</td>
820 <td>boolean</td>
821 <td>This attribute is ignored unless <code>pattern</code> is specified. Use this attribute to indicate
822 that the column stores Character Large Objects (CLOBs). If <code>true</code>, the value will be inserted
823 as a CLOB (<code>setClob</code> or <code>setNClob</code>). If <code>false</code> or omitted (default),
824 the value will be inserted as a VARCHAR or NVARCHAR (<code>setString</code> or <code>setNString</code>).
825 </td>
826 </tr>
827 </table>
828 <p>
829 Here are a couple sample configurations for the JDBCAppender, as well as a sample factory implementation
830 that uses Commons Pooling and Commons DBCP to pool database connections:
831 </p>
832
833 <pre class="prettyprint linenums lang-xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
834 <Configuration status="error">
835 <Appenders>
836 <JDBC name="databaseAppender" tableName="dbo.application_log">
837 <DataSource jndiName="java:/comp/env/jdbc/LoggingDataSource" />
838 <Column name="eventDate" isEventTimestamp="true" />
839 <Column name="level" pattern="%level" />
840 <Column name="logger" pattern="%logger" />
841 <Column name="message" pattern="%message" />
842 <Column name="exception" pattern="%ex{full}" />
843 </JDBC>
844 </Appenders>
845 <Loggers>
846 <Root level="warn">
847 <AppenderRef ref="databaseAppender"/>
848 </Root>
849 </Loggers>
850 </Configuration>]]></pre>
851
852 <pre class="prettyprint linenums lang-xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
853 <Configuration status="error">
854 <Appenders>
855 <JDBC name="databaseAppender" tableName="LOGGING.APPLICATION_LOG">
856 <ConnectionFactory class="net.example.db.ConnectionFactory" method="getDatabaseConnection" />
857 <Column name="EVENT_ID" literal="LOGGING.APPLICATION_LOG_SEQUENCE.NEXTVAL" />
858 <Column name="EVENT_DATE" isEventTimestamp="true" />
859 <Column name="LEVEL" pattern="%level" />
860 <Column name="LOGGER" pattern="%logger" />
861 <Column name="MESSAGE" pattern="%message" />
862 <Column name="THROWABLE" pattern="%ex{full}" />
863 </JDBC>
864 </Appenders>
865 <Loggers>
866 <Root level="warn">
867 <AppenderRef ref="databaseAppender"/>
868 </Root>
869 </Loggers>
870 </Configuration>]]></pre>
871 <pre class="prettyprint linenums lang-java"><![CDATA[package net.example.db;
872
873 import java.sql.Connection;
874 import java.sql.SQLException;
875 import java.util.Properties;
876
877 import javax.sql.DataSource;
878
879 import org.apache.commons.dbcp.DriverManagerConnectionFactory;
880 import org.apache.commons.dbcp.PoolableConnection;
881 import org.apache.commons.dbcp.PoolableConnectionFactory;
882 import org.apache.commons.dbcp.PoolingDataSource;
883 import org.apache.commons.pool.impl.GenericObjectPool;
884
885 public class ConnectionFactory {
886 private static interface Singleton {
887 final ConnectionFactory INSTANCE = new ConnectionFactory();
888 }
889
890 private final DataSource dataSource;
891
892 private ConnectionFactory() {
893 Properties properties = new Properties();
894 properties.setProperty("user", "logging");
895 properties.setProperty("password", "abc123"); // or get properties from some configuration file
896
897 GenericObjectPool<PoolableConnection> pool = new GenericObjectPool<PoolableConnection>();
898 DriverManagerConnectionFactory connectionFactory = new DriverManagerConnectionFactory(
899 "jdbc:mysql://example.org:3306/exampleDb", properties
900 );
901 new PoolableConnectionFactory(
902 connectionFactory, pool, null, "SELECT 1", 3, false, false, Connection.TRANSACTION_READ_COMMITTED
903 );
904
905 this.dataSource = new PoolingDataSource(pool);
906 }
907
908 public static Connection getDatabaseConnection() throws SQLException {
909 return Singleton.INSTANCE.dataSource.getConnection();
910 }
911 }]]></pre>
912 </subsection>
913 <a name="JMSAppender"/>
914 <!-- cool URLs don't change, so here are some old anchors -->
915 <a name="JMSQueueAppender"/>
916 <a name="JMSTopicAppender"/>
917 <subsection name="JMSAppender">
918 <p>The JMSAppender sends the formatted log event to a JMS Destination.</p>
919 <p>
920 Note that in Log4j 2.0, this appender was split into a JMSQueueAppender and a JMSTopicAppender. Starting
921 in Log4j 2.1, these appenders were combined into the JMSAppender which makes no distinction between queues
922 and topics. However, configurations written for 2.0 which use the <code>&lt;JMSQueue/&gt;</code> or
923 <code>&lt;JMSTopic/&gt;</code> elements will continue to work with the new <code>&lt;JMS/&gt;</code>
924 configuration element.
925 </p>
926 <table>
927 <caption align="top">JMSAppender Parameters</caption>
928 <tr>
929 <th>Parameter Name</th>
930 <th>Type</th>
931 <th>Description</th>
932 </tr>
933 <tr>
934 <td>factoryBindingName</td>
935 <td>String</td>
936 <td>The name to locate in the Context that provides the
937 <a class="javadoc" href="http://download.oracle.com/javaee/5/api/javax/jms/ConnectionFactory.html">ConnectionFactory</a>.
938 This can be any subinterface of <code>ConnectionFactory</code> as well. This attribute is required.
939 </td>
940 </tr>
941 <tr>
942 <td>factoryName</td>
943 <td>String</td>
944 <td>The fully qualified class name that should be used to define the Initial Context Factory as defined in
945 <a class="javadoc" href="http://download.oracle.com/javase/6/docs/api/javax/naming/Context.html#INITIAL_CONTEXT_FACTORY">INITIAL_CONTEXT_FACTORY</a>.
946 If no value is provided the
947 default InitialContextFactory will be used. If a factoryName is specified without a providerURL
948 a warning message will be logged as this is likely to cause problems.</td>
949 </tr>
950 <tr>
951 <td>filter</td>
952 <td>Filter</td>
953 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
954 may be used by using a CompositeFilter.</td>
955 </tr>
956 <tr>
957 <td>layout</td>
958 <td>Layout</td>
959 <td>
960 The Layout to use to format the LogEvent. If you do not specify a layout,
961 this appender will use a <a href="layouts.html#SerializedLayout">SerializedLayout</a>.
962 </td>
963 </tr>
964 <tr>
965 <td>name</td>
966 <td>String</td>
967 <td>The name of the Appender. Required.</td>
968 </tr>
969 <tr>
970 <td>password</td>
971 <td>String</td>
972 <td>The password to use to create the JMS connection.</td>
973 </tr>
974 <tr>
975 <td>providerURL</td>
976 <td>String</td>
977 <td>The URL of the provider to use as defined by
978 <a class="javadoc" href="http://download.oracle.com/javase/6/docs/api/javax/naming/Context.html#PROVIDER_URL">PROVIDER_URL</a>.
979 If this value is null the default system provider will be used.</td>
980 </tr>
981 <tr>
982 <td>destinationBindingName</td>
983 <td>String</td>
984 <td>
985 The name to use to locate the
986 <a class="javadoc" href="http://download.oracle.com/javaee/5/api/javax/jms/Destination.html">Destination</a>.
987 This can be a <code>Queue</code> or <code>Topic</code>, and as such, the attribute names
988 <code>queueBindingName</code> and <code>topicBindingName</code> are aliases to maintain compatibility
989 with the Log4j 2.0 JMS appenders.
990 </td>
991 </tr>
992 <tr>
993 <td>securityPrincipalName</td>
994 <td>String</td>
995 <td>The name of the identity of the Principal as specified by
996 <a class="javadoc" href="http://download.oracle.com/javase/6/docs/api/javax/naming/Context.html#SECURITY_PRINCIPAL">SECURITY_PRINCIPAL</a>.
997 If a securityPrincipalName is specified without securityCredentials a warning message will be
998 logged as this is likely to cause problems.</td>
999 </tr>
1000 <tr>
1001 <td>securityCredentials</td>
1002 <td>String</td>
1003 <td>The security credentials for the principal as specified by
1004 <a class="javadoc" href="http://download.oracle.com/javase/6/docs/api/javax/naming/Context.html#SECURITY_CREDENTIALS">SECURITY_CREDENTIALS</a>.
1005 </td>
1006 </tr>
1007 <tr>
1008 <td>ignoreExceptions</td>
1009 <td>boolean</td>
1010 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
1011 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
1012 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
1013 <a href="#FailoverAppender">FailoverAppender</a>.</td>
1014 </tr>
1015 <tr>
1016 <td>urlPkgPrefixes</td>
1017 <td>String</td>
1018 <td>A colon-separated list of package prefixes for the class name of the factory class that will create
1019 a URL context factory as defined by
1020 <a class="javadoc" href="http://download.oracle.com/javase/6/docs/api/javax/naming/Context.html#URL_PKG_PREFIXES">URL_PKG_PREFIXES</a>.
1021 </td>
1022 </tr>
1023 <tr>
1024 <td>userName</td>
1025 <td>String</td>
1026 <td>The user id used to create the JMS connection.</td>
1027 </tr>
1028 </table>
1029 <p>
1030 Here is a sample JMSAppender configuration:
1031 </p>
1032
1033 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
1034 <Configuration status="warn" name="MyApp">
1035 <Appenders>
1036 <JMS name="jmsQueue" destinationBindingName="MyQueue"
1037 factoryBindingName="MyQueueConnectionFactory"/>
1038 </Appenders>
1039 <Loggers>
1040 <Root level="error">
1041 <AppenderRef ref="jmsQueue"/>
1042 </Root>
1043 </Loggers>
1044 </Configuration>]]></pre>
1045 </subsection>
1046 <a name="JPAAppender"/>
1047 <subsection name="JPAAppender">
1048 <p>The JPAAppender writes log events to a relational database table using the Java Persistence API 2.1.
1049 It requires the API and a provider implementation be on the classpath. It also requires a decorated entity
1050 configured to persist to the table desired. The entity should either extend
1051 <code>org.apache.logging.log4j.core.appender.db.jpa.BasicLogEventEntity</code> (if you mostly want to
1052 use the default mappings) and provide at least an <code>@Id</code> property, or
1053 <code>org.apache.logging.log4j.core.appender.db.jpa.AbstractLogEventWrapperEntity</code> (if you want
1054 to significantly customize the mappings). See the Javadoc for these two classes for more information. You
1055 can also consult the source code of these two classes as an example of how to implement the entity.</p>
1056 <table>
1057 <caption align="top">JPAAppender Parameters</caption>
1058 <tr>
1059 <th>Parameter Name</th>
1060 <th>Type</th>
1061 <th>Description</th>
1062 </tr>
1063 <tr>
1064 <td>name</td>
1065 <td>String</td>
1066 <td><em>Required.</em> The name of the Appender.</td>
1067 </tr>
1068 <tr>
1069 <td>ignoreExceptions</td>
1070 <td>boolean</td>
1071 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
1072 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
1073 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
1074 <a href="#FailoverAppender">FailoverAppender</a>.</td>
1075 </tr>
1076 <tr>
1077 <td>filter</td>
1078 <td>Filter</td>
1079 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter may be
1080 used by using a CompositeFilter.</td>
1081 </tr>
1082 <tr>
1083 <td>bufferSize</td>
1084 <td>int</td>
1085 <td>If an integer greater than 0, this causes the appender to buffer log events and flush whenever the
1086 buffer reaches this size.</td>
1087 </tr>
1088 <tr>
1089 <td>entityClassName</td>
1090 <td>String</td>
1091 <td><em>Required.</em> The fully qualified name of the concrete LogEventWrapperEntity implementation that
1092 has JPA annotations mapping it to a database table.</td>
1093 </tr>
1094 <tr>
1095 <td>persistenceUnitName</td>
1096 <td>String</td>
1097 <td><em>Required.</em> The name of the JPA persistence unit that should be used for persisting log
1098 events.</td>
1099 </tr>
1100 </table>
1101 <p>
1102 Here is a sample configuration for the JPAAppender. The first XML sample is the Log4j configuration file,
1103 the second is the <code>persistence.xml</code> file. EclipseLink is assumed here, but any JPA 2.1 or higher
1104 provider will do. You should <em>always</em> create a <em>separate</em> persistence unit for logging, for
1105 two reasons. First, <code>&lt;shared-cache-mode&gt;</code> <em>must</em> be set to "NONE," which is usually
1106 not desired in normal JPA usage. Also, for performance reasons the logging entity should be isolated in its
1107 own persistence unit away from all other entities and you should use a non-JTA data source. Note that your
1108 persistence unit <em>must</em> also contain <code>&lt;class&gt;</code> elements for all of the
1109 <code>org.apache.logging.log4j.core.appender.db.jpa.converter</code> converter classes.
1110 </p>
1111
1112 <pre class="prettyprint linenums lang-xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
1113 <Configuration status="error">
1114 <Appenders>
1115 <JPA name="databaseAppender" persistenceUnitName="loggingPersistenceUnit"
1116 entityClassName="com.example.logging.JpaLogEntity" />
1117 </Appenders>
1118 <Loggers>
1119 <Root level="warn">
1120 <AppenderRef ref="databaseAppender"/>
1121 </Root>
1122 </Loggers>
1123 </Configuration>]]></pre>
1124
1125 <pre class="prettyprint linenums lang-xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
1126 <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
1127 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
1128 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
1129 http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
1130 version="2.1">
1131
1132 <persistence-unit name="loggingPersistenceUnit" transaction-type="RESOURCE_LOCAL">
1133 <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
1134 <class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapAttributeConverter</class>
1135 <class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapJsonAttributeConverter</class>
1136 <class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackAttributeConverter</class>
1137 <class>org.apache.logging.log4j.core.appender.db.jpa.converter.ContextStackJsonAttributeConverter</class>
1138 <class>org.apache.logging.log4j.core.appender.db.jpa.converter.MarkerAttributeConverter</class>
1139 <class>org.apache.logging.log4j.core.appender.db.jpa.converter.MessageAttributeConverter</class>
1140 <class>org.apache.logging.log4j.core.appender.db.jpa.converter.StackTraceElementAttributeConverter</class>
1141 <class>org.apache.logging.log4j.core.appender.db.jpa.converter.ThrowableAttributeConverter</class>
1142 <class>com.example.logging.JpaLogEntity</class>
1143 <non-jta-data-source>jdbc/LoggingDataSource</non-jta-data-source>
1144 <shared-cache-mode>NONE</shared-cache-mode>
1145 </persistence-unit>
1146
1147 </persistence>]]></pre>
1148
1149 <pre class="prettyprint linenums lang-java"><![CDATA[package com.example.logging;
1150 ...
1151 @Entity
1152 @Table(name="application_log", schema="dbo")
1153 public class JpaLogEntity extends BasicLogEventEntity {
1154 private static final long serialVersionUID = 1L;
1155 private long id = 0L;
1156
1157 public TestEntity() {
1158 super(null);
1159 }
1160 public TestEntity(LogEvent wrappedEvent) {
1161 super(wrappedEvent);
1162 }
1163
1164 @Id
1165 @GeneratedValue(strategy = GenerationType.IDENTITY)
1166 @Column(name = "id")
1167 public long getId() {
1168 return this.id;
1169 }
1170
1171 public void setId(long id) {
1172 this.id = id;
1173 }
1174
1175 // If you want to override the mapping of any properties mapped in BasicLogEventEntity,
1176 // just override the getters and re-specify the annotations.
1177 }]]></pre>
1178
1179 <pre class="prettyprint linenums lang-java"><![CDATA[package com.example.logging;
1180 ...
1181 @Entity
1182 @Table(name="application_log", schema="dbo")
1183 public class JpaLogEntity extends AbstractLogEventWrapperEntity {
1184 private static final long serialVersionUID = 1L;
1185 private long id = 0L;
1186
1187 public TestEntity() {
1188 super(null);
1189 }
1190 public TestEntity(LogEvent wrappedEvent) {
1191 super(wrappedEvent);
1192 }
1193
1194 @Id
1195 @GeneratedValue(strategy = GenerationType.IDENTITY)
1196 @Column(name = "logEventId")
1197 public long getId() {
1198 return this.id;
1199 }
1200
1201 public void setId(long id) {
1202 this.id = id;
1203 }
1204
1205 @Override
1206 @Enumerated(EnumType.STRING)
1207 @Column(name = "level")
1208 public Level getLevel() {
1209 return this.getWrappedEvent().getLevel();
1210 }
1211
1212 @Override
1213 @Column(name = "logger")
1214 public String getLoggerName() {
1215 return this.getWrappedEvent().getLoggerName();
1216 }
1217
1218 @Override
1219 @Column(name = "message")
1220 @Convert(converter = MyMessageConverter.class)
1221 public Message getMessage() {
1222 return this.getWrappedEvent().getMessage();
1223 }
1224 ...
1225 }]]></pre>
1226 </subsection>
1227 <a name="KafkaAppender"/>
1228 <subsection name="KafkaAppender">
1229 <p>The KafkaAppender log events to an Apache Kafka topic.</p>
1230 <table>
1231 <caption align="top">KafkaAppender Parameters</caption>
1232 <tr>
1233 <th>Parameter Name</th>
1234 <th>Type</th>
1235 <th>Description</th>
1236 </tr>
1237 <tr>
1238 <td>topic</td>
1239 <td>String</td>
1240 <td>The Kafka topic to use. Required.</td>
1241 </tr>
1242 <tr>
1243 <td>lilter</td>
1244 <td>Filter</td>
1245 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
1246 may be used by using a CompositeFilter.</td>
1247 </tr>
1248 <tr>
1249 <td>layout</td>
1250 <td>Layout</td>
1251 <td>
1252 The Layout to use to format the LogEvent. If you do not specify a layout,
1253 if not specified the <a class="javadoc" href="http://logging.apache.org/log4j/2.x/log4j-api/apidocs/org/apache/logging/log4j/message/Message.html#getFormattedMessage())">formatted message</a>
1254 as an UTF-8 encoded string will be sent to Kafka.
1255 </td>
1256 </tr>
1257 <tr>
1258 <td>name</td>
1259 <td>String</td>
1260 <td>The name of the Appender. Required.</td>
1261 </tr>
1262 <tr>
1263 <td>ignoreExceptions</td>
1264 <td>boolean</td>
1265 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
1266 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
1267 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
1268 <a href="#FailoverAppender">FailoverAppender</a>.</td>
1269 </tr>
1270 <tr>
1271 <td>properties</td>
1272 <td>Property</td>
1273 <td>
1274 You can set any properties in <a href="http://kafka.apache.org/documentation.html#newproducerconfigs">Kafka new producer properties</a>.
1275 You need to set the <code>bootstrap.servers</code> property, there are sensible default values for the others.
1276 </td>
1277 </tr>
1278 </table>
1279 <p>
1280 Here is a sample KafkaAppender configuration snippet:
1281 </p>
1282 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
1283 ...
1284 <Appenders>
1285 <Kafka name="Kafka" topic="log-test">
1286 <PatternLayout pattern="%date %message"/>
1287 <Property name="bootstrap.servers">localhost:9092</Property>
1288 </Kafka>
1289 </Appenders>]]></pre>
1290 <p>
1291 This appender is synchronous and will block until the record has been acknowledged by the Kafka server, timeout for this
1292 can be set with the <code>timeout.ms</code> property (defaults to 30 seconds). Wrap with
1293 <a href="http://logging.apache.org/log4j/2.x/manual/appenders.html#AsyncAppender">Async appender</a> to log asynchronously.
1294 </p>
1295 <p>
1296 This appender requires <a href="http://search.maven.org/#artifactdetails|org.apache.kafka|kafka-clients|0.8.2.1|jar">Kafka client library</a>
1297 </p>
1298 <p>
1299 <em>Note:</em>Make sure to not let <code>org.apache.kafka</code> log to a Kafka appender on DEBUG level,
1300 since that will cause recursive logging:
1301 </p>
1302 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
1303 ...
1304 <Loggers>
1305 <Root level="DEBUG">
1306 <AppenderRef ref="Kafka"/>
1307 </Root>
1308 <Logger name="org.apache.kafka" level="INFO" /> <!-- avoid recursive logging -->
1309 </Loggers>]]></pre>
1310 </subsection>
1311 <a name="MemoryMappedFileAppender" />
1312 <subsection name="MemoryMappedFileAppender">
1313 <p><i>New since 2.1. Be aware that this is a new addition, and although it has been
1314 tested on several platforms, it does not have as much track record as the other file appenders.</i></p>
1315 <p>
1316 The MemoryMappedFileAppender maps a part of the specified file into memory
1317 and writes log events to this memory, relying on the operating system's
1318 virtual memory manager to synchronize the changes to the storage device.
1319 The main benefit of using memory mapped files is I/O performance. Instead of making system
1320 calls to write to disk, this appender can simply change the program's local memory,
1321 which is orders of magnitude faster. Also, in most operating systems the memory
1322 region mapped actually is the kernel's <a href="http://en.wikipedia.org/wiki/Page_cache">page
1323 cache</a> (file cache), meaning that no copies need to be created in user space.
1324 (TODO: performance tests that compare performance of this appender to
1325 RandomAccessFileAppender and FileAppender.)
1326 </p>
1327 <p>
1328 There is some overhead with mapping a file region into memory,
1329 especially very large regions (half a gigabyte or more).
1330 The default region size is 32 MB, which should strike a reasonable balance
1331 between the frequency and the duration of remap operations.
1332 (TODO: performance test remapping various sizes.)
1333 </p>
1334 <p>
1335 Similar to the FileAppender and the RandomAccessFileAppender,
1336 MemoryMappedFileAppender uses a MemoryMappedFileManager to actually perform the
1337 file I/O. While MemoryMappedFileAppender from different Configurations
1338 cannot be shared, the MemoryMappedFileManagers can be if the Manager is
1339 accessible. For example, two web applications in a servlet container can have
1340 their own configuration and safely write to the same file if Log4j
1341 is in a ClassLoader that is common to both of them.
1342 </p>
1343 <table>
1344 <caption align="top">MemoryMappedFileAppender Parameters</caption>
1345 <tr>
1346 <th>Parameter Name</th>
1347 <th>Type</th>
1348 <th>Description</th>
1349 </tr>
1350 <tr>
1351 <td>append</td>
1352 <td>boolean</td>
1353 <td>When true - the default, records will be appended to the end
1354 of the file. When set to false, the file will be cleared before
1355 new records are written.
1356 </td>
1357 </tr>
1358 <tr>
1359 <td>fileName</td>
1360 <td>String</td>
1361 <td>The name of the file to write to. If the file, or any of its
1362 parent directories, do not exist, they will be created.
1363 </td>
1364 </tr>
1365 <tr>
1366 <td>filters</td>
1367 <td>Filter</td>
1368 <td>A Filter to determine if the event should be handled by this
1369 Appender. More than one Filter may be used by using a CompositeFilter.
1370 </td>
1371 </tr>
1372 <tr>
1373 <td>immediateFlush</td>
1374 <td>boolean</td>
1375 <td>
1376 <p>When set to true, each write will be followed by a
1377 call to <a href="http://docs.oracle.com/javase/7/docs/api/java/nio/MappedByteBuffer.html#force()">MappedByteBuffer.force()</a>.
1378 This will guarantee the data is written to the storage device.
1379 </p>
1380 <p>The default for this parameter is <code>false</code>.
1381 This means that the data is written to the storage device even
1382 if the Java process crashes, but there may be data loss if the
1383 operating system crashes.</p>
1384 <p>Note that manually forcing a sync on every log event loses most
1385 of the performance benefits of using a memory mapped file.</p>
1386 <p>Flushing after every write is only useful when using this
1387 appender with synchronous loggers. Asynchronous loggers and
1388 appenders will automatically flush at the end of a batch of events,
1389 even if immediateFlush is set to false. This also guarantees
1390 the data is written to disk but is more efficient.
1391 </p>
1392 </td>
1393 </tr>
1394 <tr>
1395 <td>regionLength</td>
1396 <td>int</td>
1397 <td>The length of the mapped region, defaults to 32 MB
1398 (32 * 1024 * 1024 bytes). This parameter must be a value
1399 between 256 and 1,073,741,824 (1 GB or 2^30);
1400 values outside this range will be adjusted to the closest valid
1401 value.
1402 Log4j will round the specified value up to the nearest power of two.</td>
1403 </tr>
1404 <tr>
1405 <td>layout</td>
1406 <td>Layout</td>
1407 <td>The Layout to use to format the LogEvent</td>
1408 </tr>
1409 <tr>
1410 <td>name</td>
1411 <td>String</td>
1412 <td>The name of the Appender.</td>
1413 </tr>
1414 <tr>
1415 <td>ignoreExceptions</td>
1416 <td>boolean</td>
1417 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
1418 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
1419 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
1420 <a href="#FailoverAppender">FailoverAppender</a>.</td>
1421 </tr>
1422 </table>
1423 <p>
1424 Here is a sample MemoryMappedFile configuration:
1425 </p>
1426
1427 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
1428 <Configuration status="warn" name="MyApp" packages="">
1429 <Appenders>
1430 <MemoryMappedFile name="MyFile" fileName="logs/app.log">
1431 <PatternLayout>
1432 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
1433 </PatternLayout>
1434 </MemoryMappedFile>
1435 </Appenders>
1436 <Loggers>
1437 <Root level="error">
1438 <AppenderRef ref="MyFile"/>
1439 </Root>
1440 </Loggers>
1441 </Configuration>]]></pre>
1442 </subsection>
1443 <a name="NoSQLAppender"/>
1444 <subsection name="NoSQLAppender">
1445 <p>The NoSQLAppender writes log events to a NoSQL database using an internal lightweight provider interface.
1446 Provider implementations currently exist for MongoDB and Apache CouchDB, and writing a custom provider is
1447 quite simple.</p>
1448 <table>
1449 <caption align="top">NoSQLAppender Parameters</caption>
1450 <tr>
1451 <th>Parameter Name</th>
1452 <th>Type</th>
1453 <th>Description</th>
1454 </tr>
1455 <tr>
1456 <td>name</td>
1457 <td>String</td>
1458 <td><em>Required.</em> The name of the Appender.</td>
1459 </tr>
1460 <tr>
1461 <td>ignoreExceptions</td>
1462 <td>boolean</td>
1463 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
1464 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
1465 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
1466 <a href="#FailoverAppender">FailoverAppender</a>.</td>
1467 </tr>
1468 <tr>
1469 <td>filter</td>
1470 <td>Filter</td>
1471 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter may be
1472 used by using a CompositeFilter.</td>
1473 </tr>
1474 <tr>
1475 <td>bufferSize</td>
1476 <td>int</td>
1477 <td>If an integer greater than 0, this causes the appender to buffer log events and flush whenever the
1478 buffer reaches this size.</td>
1479 </tr>
1480 <tr>
1481 <td>NoSqlProvider</td>
1482 <td>NoSQLProvider&lt;C extends NoSQLConnection&lt;W, T extends NoSQLObject&lt;W&gt;&gt;&gt;</td>
1483 <td><em>Required.</em> The NoSQL provider that provides connections to the chosen NoSQL database.</td>
1484 </tr>
1485 </table>
1486 <p>You specify which NoSQL provider to use by specifying the appropriate configuration element within the
1487 <code>&lt;NoSql&gt;</code> element. The types currently supported are <code>&lt;MongoDb&gt;</code> and
1488 <code>&lt;CouchDb&gt;</code>. To create your own custom provider, read the JavaDoc for the
1489 <code>NoSQLProvider</code>, <code>NoSQLConnection</code>, and <code>NoSQLObject</code> classes and the
1490 documentation about creating Log4j plugins. We recommend you review the source code for the MongoDB and
1491 CouchDB providers as a guide for creating your own provider.</p>
1492 <table>
1493 <caption align="top">MongoDB Provider Parameters</caption>
1494 <tr>
1495 <th>Parameter Name</th>
1496 <th>Type</th>
1497 <th>Description</th>
1498 </tr>
1499 <tr>
1500 <td>collectionName</td>
1501 <td>String</td>
1502 <td><em>Required.</em> The name of the MongoDB collection to insert the events into.</td>
1503 </tr>
1504 <tr>
1505 <td>writeConcernConstant</td>
1506 <td>Field</td>
1507 <td>By default, the MongoDB provider inserts records with the instructions
1508 <code>com.mongodb.WriteConcern.ACKNOWLEDGED</code>. Use this optional attribute to specify the name of
1509 a constant other than <code>ACKNOWLEDGED</code>.</td>
1510 </tr>
1511 <tr>
1512 <td>writeConcernConstantClass</td>
1513 <td>Class</td>
1514 <td>If you specify <code>writeConcernConstant</code>, you can use this attribute to specify a class other
1515 than <code>com.mongodb.WriteConcern</code> to find the constant on (to create your own custom
1516 instructions).</td>
1517 </tr>
1518 <tr>
1519 <td>factoryClassName</td>
1520 <td>Class</td>
1521 <td>To provide a connection to the MongoDB database, you can use this attribute and
1522 <code>factoryMethodName</code> to specify a class and static method to get the connection from. The
1523 method must return a <code>com.mongodb.DB</code> or a <code>com.mongodb.MongoClient</code>. If the
1524 <code>DB</code> is not authenticated, you must also specify a <code>username</code> and
1525 <code>password</code>. If you use the factory method for providing a connection, you must not specify
1526 the <code>databaseName</code>, <code>server</code>, or <code>port</code> attributes.</td>
1527 </tr>
1528 <tr>
1529 <td>factoryMethodName</td>
1530 <td>Method</td>
1531 <td>See the documentation for attribute <code>factoryClassName</code>.</td>
1532 </tr>
1533 <tr>
1534 <td>databaseName</td>
1535 <td>String</td>
1536 <td>If you do not specify a <code>factoryClassName</code> and <code>factoryMethodName</code> for providing
1537 a MongoDB connection, you must specify a MongoDB database name using this attribute. You must also
1538 specify a <code>username</code> and <code>password</code>. You can optionally also specify a
1539 <code>server</code> (defaults to localhost), and a <code>port</code> (defaults to the default MongoDB
1540 port).</td>
1541 </tr>
1542 <tr>
1543 <td>server</td>
1544 <td>String</td>
1545 <td>See the documentation for attribute <code>databaseName</code>.</td>
1546 </tr>
1547 <tr>
1548 <td>port</td>
1549 <td>int</td>
1550 <td>See the documentation for attribute <code>databaseName</code>.</td>
1551 </tr>
1552 <tr>
1553 <td>username</td>
1554 <td>String</td>
1555 <td>See the documentation for attributes <code>databaseName</code> and <code>factoryClassName</code>.</td>
1556 </tr>
1557 <tr>
1558 <td>password</td>
1559 <td>String</td>
1560 <td>See the documentation for attributes <code>databaseName</code> and <code>factoryClassName</code>.</td>
1561 </tr>
1562 </table>
1563 <table>
1564 <caption align="top">CouchDB Provider Parameters</caption>
1565 <tr>
1566 <th>Parameter Name</th>
1567 <th>Type</th>
1568 <th>Description</th>
1569 </tr>
1570 <tr>
1571 <td>factoryClassName</td>
1572 <td>Class</td>
1573 <td>To provide a connection to the CouchDB database, you can use this attribute and
1574 <code>factoryMethodName</code> to specify a class and static method to get the connection from. The
1575 method must return a <code>org.lightcouch.CouchDbClient</code> or a
1576 <code>org.lightcouch.CouchDbProperties</code>. If you use the factory method for providing a connection,
1577 you must not specify the <code>databaseName</code>, <code>protocol</code>, <code>server</code>,
1578 <code>port</code>, <code>username</code>, or <code>password</code> attributes.</td>
1579 </tr>
1580 <tr>
1581 <td>factoryMethodName</td>
1582 <td>Method</td>
1583 <td>See the documentation for attribute <code>factoryClassName</code>.</td>
1584 </tr>
1585 <tr>
1586 <td>databaseName</td>
1587 <td>String</td>
1588 <td>If you do not specify a <code>factoryClassName</code> and <code>factoryMethodName</code> for providing
1589 a CouchDB connection, you must specify a CouchDB database name using this attribute. You must also
1590 specify a <code>username</code> and <code>password</code>. You can optionally also specify a
1591 <code>protocol</code> (defaults to http), <code>server</code> (defaults to localhost), and a
1592 <code>port</code> (defaults to 80 for http and 443 for https).</td>
1593 </tr>
1594 <tr>
1595 <td>protocol</td>
1596 <td>String</td>
1597 <td>Must either be "http" or "https." See the documentation for attribute <code>databaseName</code>.</td>
1598 </tr>
1599 <tr>
1600 <td>server</td>
1601 <td>String</td>
1602 <td>See the documentation for attribute <code>databaseName</code>.</td>
1603 </tr>
1604 <tr>
1605 <td>port</td>
1606 <td>int</td>
1607 <td>See the documentation for attribute <code>databaseName</code>.</td>
1608 </tr>
1609 <tr>
1610 <td>username</td>
1611 <td>String</td>
1612 <td>See the documentation for attributes <code>databaseName</code>.</td>
1613 </tr>
1614 <tr>
1615 <td>password</td>
1616 <td>String</td>
1617 <td>See the documentation for attributes <code>databaseName</code>.</td>
1618 </tr>
1619 </table>
1620 <p>
1621 Here are a few sample configurations for the NoSQLAppender:
1622 </p>
1623
1624 <pre class="prettyprint linenums lang-xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
1625 <Configuration status="error">
1626 <Appenders>
1627 <NoSql name="databaseAppender">
1628 <MongoDb databaseName="applicationDb" collectionName="applicationLog" server="mongo.example.org"
1629 username="loggingUser" password="abc123" />
1630 </NoSql>
1631 </Appenders>
1632 <Loggers>
1633 <Root level="warn">
1634 <AppenderRef ref="databaseAppender"/>
1635 </Root>
1636 </Loggers>
1637 </Configuration>]]></pre>
1638
1639 <pre class="prettyprint linenums lang-xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
1640 <Configuration status="error">
1641 <Appenders>
1642 <NoSql name="databaseAppender">
1643 <MongoDb collectionName="applicationLog" factoryClassName="org.example.db.ConnectionFactory"
1644 factoryMethodName="getNewMongoClient" />
1645 </NoSql>
1646 </Appenders>
1647 <Loggers>
1648 <Root level="warn">
1649 <AppenderRef ref="databaseAppender"/>
1650 </Root>
1651 </Loggers>
1652 </Configuration>]]></pre>
1653
1654 <pre class="prettyprint linenums lang-xml"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
1655 <Configuration status="error">
1656 <Appenders>
1657 <NoSql name="databaseAppender">
1658 <CouchDb databaseName="applicationDb" protocol="https" server="couch.example.org"
1659 username="loggingUser" password="abc123" />
1660 </NoSql>
1661 </Appenders>
1662 <Loggers>
1663 <Root level="warn">
1664 <AppenderRef ref="databaseAppender"/>
1665 </Root>
1666 </Loggers>
1667 </Configuration>]]></pre>
1668 <p>
1669 The following example demonstrates how log events are persisted in NoSQL databases if represented in a JSON
1670 format:
1671 </p>
1672 <pre class="prettyprint lang-javascript"><![CDATA[{
1673 "level": "WARN",
1674 "loggerName": "com.example.application.MyClass",
1675 "message": "Something happened that you might want to know about.",
1676 "source": {
1677 "className": "com.example.application.MyClass",
1678 "methodName": "exampleMethod",
1679 "fileName": "MyClass.java",
1680 "lineNumber": 81
1681 },
1682 "marker": {
1683 "name": "SomeMarker",
1684 "parent" {
1685 "name": "SomeParentMarker"
1686 }
1687 },
1688 "threadName": "Thread-1",
1689 "millis": 1368844166761,
1690 "date": "2013-05-18T02:29:26.761Z",
1691 "thrown": {
1692 "type": "java.sql.SQLException",
1693 "message": "Could not insert record. Connection lost.",
1694 "stackTrace": [
1695 { "className": "org.example.sql.driver.PreparedStatement$1", "methodName": "responder", "fileName": "PreparedStatement.java", "lineNumber": 1049 },
1696 { "className": "org.example.sql.driver.PreparedStatement", "methodName": "executeUpdate", "fileName": "PreparedStatement.java", "lineNumber": 738 },
1697 { "className": "com.example.application.MyClass", "methodName": "exampleMethod", "fileName": "MyClass.java", "lineNumber": 81 },
1698 { "className": "com.example.application.MainClass", "methodName": "main", "fileName": "MainClass.java", "lineNumber": 52 }
1699 ],
1700 "cause": {
1701 "type": "java.io.IOException",
1702 "message": "Connection lost.",
1703 "stackTrace": [
1704 { "className": "java.nio.channels.SocketChannel", "methodName": "write", "fileName": null, "lineNumber": -1 },
1705 { "className": "org.example.sql.driver.PreparedStatement$1", "methodName": "responder", "fileName": "PreparedStatement.java", "lineNumber": 1032 },
1706 { "className": "org.example.sql.driver.PreparedStatement", "methodName": "executeUpdate", "fileName": "PreparedStatement.java", "lineNumber": 738 },
1707 { "className": "com.example.application.MyClass", "methodName": "exampleMethod", "fileName": "MyClass.java", "lineNumber": 81 },
1708 { "className": "com.example.application.MainClass", "methodName": "main", "fileName": "MainClass.java", "lineNumber": 52 }
1709 ]
1710 }
1711 },
1712 "contextMap": {
1713 "ID": "86c3a497-4e67-4eed-9d6a-2e5797324d7b",
1714 "username": "JohnDoe"
1715 },
1716 "contextStack": [
1717 "topItem",
1718 "anotherItem",
1719 "bottomItem"
1720 ]
1721 }]]></pre>
1722 </subsection>
1723 <a name="OutputStreamAppender"/>
1724 <subsection name="OutputStreamAppender">
1725 <p>
1726 The OutputStreamAppender provides the base for many of the other Appenders such as the File and Socket
1727 appenders that write the event to an Output Stream. It cannot be directly configured. Support for
1728 immediateFlush and buffering is provided by the OutputStreamAppender. The OutputStreamAppender uses an
1729 OutputStreamManager to handle the actual I/O, allowing the stream to be shared by Appenders in multiple
1730 configurations.
1731 </p>
1732 </subsection>
1733 <a name="RandomAccessFileAppender" />
1734 <subsection name="RandomAccessFileAppender">
1735 <p><i>As of beta-9, the name of this appender has been changed from FastFile to
1736 RandomAccessFile. Configurations using the <code>FastFile</code> element
1737 no longer work and should be modified to use the <code>RandomAccessFile</code> element.</i></p>
1738 <p>
1739 The RandomAccessFileAppender is similar to the standard
1740 <a href="#FileAppender">FileAppender</a>
1741 except it is always buffered (this cannot be switched off)
1742 and internally it uses a
1743 <tt>ByteBuffer + RandomAccessFile</tt>
1744 instead of a
1745 <tt>BufferedOutputStream</tt>.
1746 We saw a 20-200% performance improvement compared to
1747 FileAppender with "bufferedIO=true" in our
1748 <a href="async.html#RandomAccessFileAppenderPerformance">measurements</a>.
1749 Similar to the FileAppender,
1750 RandomAccessFileAppender uses a RandomAccessFileManager to actually perform the
1751 file I/O. While RandomAccessFileAppender
1752 from different Configurations
1753 cannot be shared, the RandomAccessFileManagers can be if the Manager is
1754 accessible. For example, two web applications in a
1755 servlet container can have
1756 their own configuration and safely
1757 write to the same file if Log4j
1758 is in a ClassLoader that is common to
1759 both of them.
1760 </p>
1761 <table>
1762 <caption align="top">RandomAccessFileAppender Parameters</caption>
1763 <tr>
1764 <th>Parameter Name</th>
1765 <th>Type</th>
1766 <th>Description</th>
1767 </tr>
1768 <tr>
1769 <td>append</td>
1770 <td>boolean</td>
1771 <td>When true - the default, records will be appended to the end
1772 of the file. When set to false,
1773 the file will be cleared before
1774 new records are written.
1775 </td>
1776 </tr>
1777 <tr>
1778 <td>fileName</td>
1779 <td>String</td>
1780 <td>The name of the file to write to. If the file, or any of its
1781 parent directories, do not exist,
1782 they will be created.
1783 </td>
1784 </tr>
1785 <tr>
1786 <td>filters</td>
1787 <td>Filter</td>
1788 <td>A Filter to determine if the event should be handled by this
1789 Appender. More than one Filter
1790 may be used by using a CompositeFilter.
1791 </td>
1792 </tr>
1793 <tr>
1794 <td>immediateFlush</td>
1795 <td>boolean</td>
1796 <td>
1797 <p>
1798 When set to true - the default, each write will be followed by a flush.
1799 This will guarantee the data is written
1800 to disk but could impact performance.
1801 </p>
1802 <p>
1803 Flushing after every write is only useful when using this
1804 appender with synchronous loggers. Asynchronous loggers and
1805 appenders will automatically flush at the end of a batch of events,
1806 even if immediateFlush is set to false. This also guarantees
1807 the data is written to disk but is more efficient.
1808 </p>
1809 </td>
1810 </tr>
1811 <tr>
1812 <td>bufferSize</td>
1813 <td>int</td>
1814 <td>The buffer size, defaults to 262,144 bytes (256 * 1024).</td>
1815 </tr>
1816 <tr>
1817 <td>layout</td>
1818 <td>Layout</td>
1819 <td>The Layout to use to format the LogEvent</td>
1820 </tr>
1821 <tr>
1822 <td>name</td>
1823 <td>String</td>
1824 <td>The name of the Appender.</td>
1825 </tr>
1826 <tr>
1827 <td>ignoreExceptions</td>
1828 <td>boolean</td>
1829 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
1830 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
1831 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
1832 <a href="#FailoverAppender">FailoverAppender</a>.</td>
1833 </tr>
1834 </table>
1835 <p>
1836 Here is a sample RandomAccessFile configuration:
1837 </p>
1838
1839 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
1840 <Configuration status="warn" name="MyApp" packages="">
1841 <Appenders>
1842 <RandomAccessFile name="MyFile" fileName="logs/app.log">
1843 <PatternLayout>
1844 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
1845 </PatternLayout>
1846 </RandomAccessFile>
1847 </Appenders>
1848 <Loggers>
1849 <Root level="error">
1850 <AppenderRef ref="MyFile"/>
1851 </Root>
1852 </Loggers>
1853 </Configuration>]]></pre>
1854 </subsection>
1855 <a name="RewriteAppender"/>
1856 <subsection name="RewriteAppender">
1857 <p>
1858 The RewriteAppender allows the LogEvent to manipulated before it is processed by another Appender. This
1859 can be used to mask sensitive information such as passwords or to inject information into each event.
1860 The RewriteAppender must be configured with a <a href="RewritePolicy">RewritePolicy</a>. The
1861 RewriteAppender should be configured after any Appenders it references to allow it to shut down properly.
1862 </p>
1863 <table>
1864 <caption align="top">RewriteAppender Parameters</caption>
1865 <tr>
1866 <th>Parameter Name</th>
1867 <th>Type</th>
1868 <th>Description</th>
1869 </tr>
1870 <tr>
1871 <td>AppenderRef</td>
1872 <td>String</td>
1873 <td>The name of the Appenders to call after the LogEvent has been manipulated. Multiple AppenderRef
1874 elements can be configured.</td>
1875 </tr>
1876 <tr>
1877 <td>filter</td>
1878 <td>Filter</td>
1879 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
1880 may be used by using a CompositeFilter.</td>
1881 </tr>
1882 <tr>
1883 <td>name</td>
1884 <td>String</td>
1885 <td>The name of the Appender.</td>
1886 </tr>
1887 <tr>
1888 <td>rewritePolicy</td>
1889 <td>RewritePolicy</td>
1890 <td>The RewritePolicy that will manipulate the LogEvent.</td>
1891 </tr>
1892 <tr>
1893 <td>ignoreExceptions</td>
1894 <td>boolean</td>
1895 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
1896 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
1897 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
1898 <a href="#FailoverAppender">FailoverAppender</a>.</td>
1899 </tr>
1900 </table>
1901 <h4>RewritePolicy</h4>
1902 <p>
1903 RewritePolicy is an interface that allows implementations to inspect and possibly modify LogEvents
1904 before they are passed to Appender. RewritePolicy declares a single method named rewrite that must
1905 be implemented. The method is passed the LogEvent and can return the same event or create a new one.
1906 </p>
1907 <h5>MapRewritePolicy</h5>
1908 <p>
1909 MapRewritePolicy will evaluate LogEvents that contain a MapMessage and will add or update
1910 elements of the Map.
1911 </p>
1912 <table>
1913 <tr>
1914 <th>Parameter Name</th>
1915 <th>Type</th>
1916 <th>Description</th>
1917 </tr>
1918 <tr>
1919 <td>mode</td>
1920 <td>String</td>
1921 <td>"Add" or "Update"</td>
1922 </tr>
1923 <tr>
1924 <td>keyValuePair</td>
1925 <td>KeyValuePair[]</td>
1926 <td>An array of keys and their values.</td>
1927 </tr>
1928 </table>
1929 <p>
1930 The following configuration shows a RewriteAppender configured to add a product key and its value
1931 to the MapMessage.:
1932 </p>
1933
1934 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
1935 <Configuration status="warn" name="MyApp" packages="">
1936 <Appenders>
1937 <Console name="STDOUT" target="SYSTEM_OUT">
1938 <PatternLayout pattern="%m%n"/>
1939 </Console>
1940 <Rewrite name="rewrite">
1941 <AppenderRef ref="STDOUT"/>
1942 <MapRewritePolicy mode="Add">
1943 <KeyValuePair key="product" value="TestProduct"/>
1944 </MapRewritePolicy>
1945 </Rewrite>
1946 </Appenders>
1947 <Loggers>
1948 <Root level="error">
1949 <AppenderRef ref="Rewrite"/>
1950 </Root>
1951 </Loggers>
1952 </Configuration>]]></pre>
1953 <h5>PropertiesRewritePolicy</h5>
1954 <p>
1955 PropertiesRewritePolicy will add properties configured on the policy to the ThreadContext Map
1956 being logged. The properties will not be added to the actual ThreadContext Map. The property
1957 values may contain variables that will be evaluated when the configuration is processed as
1958 well as when the event is logged.
1959 </p>
1960 <table>
1961 <tr>
1962 <th>Parameter Name</th>
1963 <th>Type</th>
1964 <th>Description</th>
1965 </tr>
1966 <tr>
1967 <td>properties</td>
1968 <td>Property[]</td>
1969 <td>One of more Property elements to define the keys and values to be added to the ThreadContext Map.</td>
1970 </tr>
1971 </table>
1972 <p>
1973 The following configuration shows a RewriteAppender configured to add a product key and its value
1974 to the MapMessage:
1975 </p>
1976 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
1977 <Configuration status="warn" name="MyApp" packages="">
1978 <Appenders>
1979 <Console name="STDOUT" target="SYSTEM_OUT">
1980 <PatternLayout pattern="%m%n"/>
1981 </Console>
1982 <Rewrite name="rewrite">
1983 <AppenderRef ref="STDOUT"/>
1984 <PropertiesRewritePolicy>
1985 <Property name="user">${sys:user.name}</Property>
1986 <Property name="env">${sys:environment}</Property>
1987 </PropertiesRewritePolicy>
1988 </Rewrite>
1989 </Appenders>
1990 <Loggers>
1991 <Root level="error">
1992 <AppenderRef ref="Rewrite"/>
1993 </Root>
1994 </Loggers>
1995 </Configuration>]]></pre>
1996 <h5>LoggerNameLevelRewritePolicy</h5>
1997 <p>
1998 You can use this policy to make loggers in third party code less chatty by changing event levels.
1999 The LoggerNameLevelRewritePolicy will rewrite log event levels for a given logger name prefix.
2000 You configure a LoggerNameLevelRewritePolicy with a logger name prefix and a pairs of levels,
2001 where a pair defines a source level and a target level.
2002 </p>
2003 <table>
2004 <tr>
2005 <th>Parameter Name</th>
2006 <th>Type</th>
2007 <th>Description</th>
2008 </tr>
2009 <tr>
2010 <td>loggerName</td>
2011 <td>String</td>
2012 <td>A logger name used as a prefix to test each event's logger name.</td>
2013 </tr>
2014 <tr>
2015 <td>LevelPair</td>
2016 <td>KeyValuePair[]</td>
2017 <td>An array of keys and their values, each key is a source level, each value a target level.</td>
2018 </tr>
2019 </table>
2020 <p>
2021 The following configuration shows a RewriteAppender configured to map level INFO to DEBUG and level
2022 WARN to INFO for all loggers that start with <code>com.foo.bar</code>.
2023 </p>
2024 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2025 <Configuration status="warn" name="MyApp">
2026 <Appenders>
2027 <Console name="STDOUT" target="SYSTEM_OUT">
2028 <PatternLayout pattern="%m%n"/>
2029 </Console>
2030 <Rewrite name="rewrite">
2031 <AppenderRef ref="STDOUT"/>
2032 <LoggerNameLevelRewritePolicy loggerName="com.foo.bar">
2033 <LevelPair key="INFO" value="DEBUG"/>
2034 <LevelPair key="WARN" value="INFO"/>
2035 </LoggerNameLevelRewritePolicy>
2036 </Rewrite>
2037 </Appenders>
2038 <Loggers>
2039 <Root level="error">
2040 <AppenderRef ref="Rewrite"/>
2041 </Root>
2042 </Loggers>
2043 </Configuration>]]></pre>
2044 </subsection>
2045 <a name="RollingFileAppender"/>
2046 <subsection name="RollingFileAppender">
2047 <p>The RollingFileAppender is an OutputStreamAppender that writes to the File named in the fileName parameter
2048 and rolls the file over according the TriggeringPolicy and the RolloverPolicy. The
2049 RollingFileAppender uses a RollingFileManager (which extends OutputStreamManager) to actually perform the
2050 file I/O and perform the rollover. While RolloverFileAppenders from different Configurations cannot be
2051 shared, the RollingFileManagers can be if the Manager is accessible. For example, two web applications in a
2052 servlet container can have their own configuration and safely
2053 write to the same file if Log4j is in a ClassLoader that is common to both of them.</p>
2054 <p>
2055 A RollingFileAppender requires a <a href="#TriggeringPolicies">TriggeringPolicy</a> and a
2056 <a href="#RolloverStrategies">RolloverStrategy</a>. The triggering policy determines if a rollover should
2057 be performed while the RolloverStrategy defines how the rollover should be done. If no RolloverStrategy
2058 is configured, RollingFileAppender will use the <a href="#DefaultRolloverStrategy">DefaultRolloverStrategy</a>.
2059 </p>
2060 <p>
2061 File locking is not supported by the RollingFileAppender.
2062 </p>
2063 <table>
2064 <caption align="top">RollingFileAppender Parameters</caption>
2065 <tr>
2066 <th>Parameter Name</th>
2067 <th>Type</th>
2068 <th>Description</th>
2069 </tr>
2070 <tr>
2071 <td>append</td>
2072 <td>boolean</td>
2073 <td>When true - the default, records will be appended to the end of the file. When set to false,
2074 the file will be cleared before new records are written.</td>
2075 </tr>
2076 <tr>
2077 <td>bufferedIO</td>
2078 <td>boolean</td>
2079 <td>When true - the default, records will be written to a buffer and the data will be written to
2080 disk when the buffer is full or, if immediateFlush is set, when the record is written.
2081 File locking cannot be used with bufferedIO. Performance tests have shown that using buffered I/O
2082 significantly improves performance, even if immediateFlush is enabled.</td>
2083 </tr>
2084 <tr>
2085 <td>bufferSize</td>
2086 <td>int</td>
2087 <td>When bufferedIO is true, this is the buffer size, the default is 8192 bytes.</td>
2088 </tr>
2089 <tr>
2090 <td>filter</td>
2091 <td>Filter</td>
2092 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
2093 may be used by using a CompositeFilter.</td>
2094 </tr>
2095 <tr>
2096 <td>fileName</td>
2097 <td>String</td>
2098 <td>The name of the file to write to. If the file, or any of its parent directories, do not exist,
2099 they will be created.</td>
2100 </tr>
2101 <tr>
2102 <td>filePattern</td>
2103 <td>String</td>
2104 <td>The pattern of the file name of the archived log file. The format of the pattern should is
2105 dependent on the RolloverPolicy that is used. The DefaultRolloverPolicy will accept both
2106 a date/time pattern compatible with
2107 <a href="http://download.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html">SimpleDateFormat</a>
2108 and and/or a %i which represents an integer counter. The pattern also supports interpolation at
2109 runtime so any of the Lookups (such as the <a href="./lookups.html#DateLookup">DateLookup</a> can
2110 be included in the pattern.</td>
2111 </tr>
2112 <tr>
2113 <td>immediateFlush</td>
2114 <td>boolean</td>
2115 <td><p>When set to true - the default, each write will be followed by a flush.
2116 This will guarantee the data is written
2117 to disk but could impact performance.</p>
2118 <p>Flushing after every write is only useful when using this
2119 appender with synchronous loggers. Asynchronous loggers and
2120 appenders will automatically flush at the end of a batch of events,
2121 even if immediateFlush is set to false. This also guarantees
2122 the data is written to disk but is more efficient.</p>
2123 </td>
2124 </tr>
2125 <tr>
2126 <td>layout</td>
2127 <td>Layout</td>
2128 <td>The Layout to use to format the LogEvent</td>
2129 </tr>
2130
2131 <tr>
2132 <td>name</td>
2133 <td>String</td>
2134 <td>The name of the Appender.</td>
2135 </tr>
2136 <tr>
2137 <td>policy</td>
2138 <td>TriggeringPolicy</td>
2139 <td>The policy to use to determine if a rollover should occur.</td>
2140 </tr>
2141 <tr>
2142 <td>strategy</td>
2143 <td>RolloverStrategy</td>
2144 <td>The strategy to use to determine the name and location of the archive file.</td>
2145 </tr>
2146 <tr>
2147 <td>ignoreExceptions</td>
2148 <td>boolean</td>
2149 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
2150 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
2151 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
2152 <a href="#FailoverAppender">FailoverAppender</a>.</td>
2153 </tr>
2154 </table>
2155 <a name="TriggeringPolicies"/>
2156 <h4>Triggering Policies</h4>
2157 <h5>Composite Triggering Policy</h5>
2158 <p>
2159 The <code>CompositeTriggeringPolicy</code> combines multiple triggering policies and returns true if
2160 any of the configured policies return true. The <code>CompositeTriggeringPolicy</code> is configured
2161 simply by wrapping other policies in a <code>Policies</code> element.
2162 </p>
2163 <p>
2164 For example, the following XML fragment defines policies that rollover the log when the JVM starts,
2165 when the log size reaches twenty megabytes, and when the current date no longer matches the log’s
2166 start date.
2167 </p>
2168 <pre class="prettyprint linenums"><![CDATA[<Policies>
2169 <OnStartupTriggeringPolicy />
2170 <SizeBasedTriggeringPolicy size="20 MB" />
2171 <TimeBasedTriggeringPolicy />
2172 </Policies>]]></pre>
2173 <h5>OnStartup Triggering Policy</h5>
2174 <p>
2175 The <code>OnStartupTriggeringPolicy</code> policy takes no parameters and causes a rollover if the log
2176 file is older than the current JVM's start time.
2177 </p>
2178 <p>
2179 <em>Google App Engine note:</em><br />
2180 When running in Google App Engine, the OnStartup policy causes a rollover if the log file is older
2181 than <em>the time when Log4J initialized</em>.
2182 (Google App Engine restricts access to certain classes so Log4J cannot determine JVM start time with
2183 <code>java.lang.management.ManagementFactory.getRuntimeMXBean().getStartTime()</code>
2184 and falls back to Log4J initialization time instead.)
2185 </p>
2186 <h5>SizeBased Triggering Policy</h5>
2187 <p>
2188 The <code>SizeBasedTriggeringPolicy</code> causes a rollover once the file has reached the specified
2189 size. The size can be specified in bytes, with the suffix KB, MB or GB, for example <code>20MB</code>.
2190 </p>
2191 <h5>TimeBased Triggering Policy</h5>
2192 <p>
2193 The <code>TimeBasedTriggeringPolicy</code> causes a rollover once the date/time pattern no longer
2194 applies to the active file. This policy accepts an <code>increment</code> attribute which indicates how
2195 frequently the rollover should occur based on the time pattern and a <code>modulate</code> boolean
2196 attribute.
2197 </p>
2198 <table>
2199 <caption align="top">TimeBasedTriggeringPolicy Parameters</caption>
2200 <tr>
2201 <th>Parameter Name</th>
2202 <th>Type</th>
2203 <th>Description</th>
2204 </tr>
2205 <tr>
2206 <td>interval</td>
2207 <td>integer</td>
2208 <td>How often a rollover should occur based on the most specific time unit in the date pattern.
2209 For example, with a date pattern with hours as the most specific item and and increment of 4 rollovers
2210 would occur every 4 hours.
2211 The default value is 1.</td>
2212 </tr>
2213 <tr>
2214 <td>modulate</td>
2215 <td>boolean</td>
2216 <td>Indicates whether the interval should be adjusted to cause the next rollover to occur on
2217 the interval boundary. For example, if the item is hours, the current hour is 3 am and the
2218 interval is 4 then then the first rollover will occur at 4 am and then next ones will occur at
2219 8 am, noon, 4pm, etc.</td>
2220 </tr>
2221 </table>
2222 <a name="RolloverStrategies"/>
2223 <h4>Rollover Strategies</h4>
2224 <a name="DefaultRolloverStrategy"/>
2225 <h5>Default Rollover Strategy</h5>
2226 <p>
2227 The default rollover strategy accepts both a date/time pattern and an integer from the filePattern
2228 attribute specified on the RollingFileAppender itself. If the date/time pattern
2229 is present it will be replaced with the current date and time values. If the pattern contains an integer
2230 it will be incremented on each rollover. If the pattern contains both a date/time and integer
2231 in the pattern the integer will be incremented until the result of the date/time pattern changes. If
2232 the file pattern ends with ".gz", ".zip", ".bz2", ".deflate", ".pack200", or ".xz" the resulting archive
2233 will be compressed using the compression scheme that matches the suffix. The formats bzip2, Deflate,
2234 Pack200 and XZ require <a href="http://commons.apache.org/proper/commons-compress/">Apache Commons Compress</a>.
2235 In addition, XZ requires <a href="http://tukaani.org/xz/java.html">XZ for Java</a>.
2236 The pattern may also contain lookup references that can be resolved at runtime such as is shown in the example
2237 below.
2238 </p>
2239 <p>The default rollover strategy supports two variations for incrementing the counter. The first is
2240 the "fixed window" strategy. To illustrate how it works, suppose that the min attribute is set to 1,
2241 the max attribute is set to 3, the file name is "foo.log", and the file name pattern is "foo-%i.log".
2242 </p>
2243
2244 <table>
2245 <tr>
2246 <th>Number of rollovers</th>
2247 <th>Active output target</th>
2248 <th>Archived log files</th>
2249 <th>Description</th>
2250 </tr>
2251 <tr>
2252 <td>0</td>
2253 <td>foo.log</td>
2254 <td>-</td>
2255 <td>All logging is going to the initial file.</td>
2256 </tr>
2257 <tr>
2258 <td>1</td>
2259 <td>foo.log</td>
2260 <td>foo-1.log</td>
2261 <td>During the first rollover foo.log is renamed to foo-1.log. A new foo.log file is created and
2262 starts being written to.</td>
2263 </tr>
2264 <tr>
2265 <td>2</td>
2266 <td>foo.log</td>
2267 <td>foo-1.log, foo-2.log</td>
2268 <td>During the second rollover foo-1.log is renamed to foo-2.log and foo.log is renamed to
2269 foo-1.log. A new foo.log file is created and starts being written to.</td>
2270 </tr>
2271 <tr>
2272 <td>3</td>
2273 <td>foo.log</td>
2274 <td>foo-1.log, foo-2.log, foo-3.log</td>
2275 <td>During the third rollover foo-2.log is renamed to foo-3.log, foo-1.log is renamed to foo-2.log and
2276 foo.log is renamed to foo-1.log. A new foo.log file is created and starts being written to.</td>
2277 </tr>
2278 <tr>
2279 <td>4</td>
2280 <td>foo.log</td>
2281 <td>foo-1.log, foo-2.log, foo-3.log</td>
2282 <td>In the fourth and subsequent rollovers, foo-3.log is deleted, foo-2.log is renamed to foo-3.log,
2283 foo-1.log is renamed to foo-2.log and foo.log is renamed to foo-1.log. A new foo.log file is
2284 created and starts being written to.</td>
2285 </tr>
2286 </table>
2287 <p>By way of contrast, when the the fileIndex attribute is set to "max" but all the other settings
2288 are the same the following actions will be performed.
2289 </p>
2290 <table>
2291 <tr>
2292 <th>Number of rollovers</th>
2293 <th>Active output target</th>
2294 <th>Archived log files</th>
2295 <th>Description</th>
2296 </tr>
2297 <tr>
2298 <td>0</td>
2299 <td>foo.log</td>
2300 <td>-</td>
2301 <td>All logging is going to the initial file.</td>
2302 </tr>
2303 <tr>
2304 <td>1</td>
2305 <td>foo.log</td>
2306 <td>foo-1.log</td>
2307 <td>During the first rollover foo.log is renamed to foo-1.log. A new foo.log file is created and
2308 starts being written to.</td>
2309 </tr>
2310 <tr>
2311 <td>2</td>
2312 <td>foo.log</td>
2313 <td>foo-1.log, foo-2.log</td>
2314 <td>During the second rollover foo.log is renamed to foo-2.log. A new foo.log file is created
2315 and starts being written to.</td>
2316 </tr>
2317 <tr>
2318 <td>3</td>
2319 <td>foo.log</td>
2320 <td>foo-1.log, foo-2.log, foo-3.log</td>
2321 <td>During the third rollover foo.log is renamed to foo-3.log. A new foo.log file is created and
2322 starts being written to.</td>
2323 </tr>
2324 <tr>
2325 <td>4</td>
2326 <td>foo.log</td>
2327 <td>foo-1.log, foo-2.log, foo-3.log</td>
2328 <td>In the fourth and subsequent rollovers, foo-1.log is deleted, foo-2.log is renamed to foo-1.log,
2329 foo-3.log is renamed to foo-2.log and foo.log is renamed to foo-3.log. A new foo.log file is
2330 created and starts being written to.</td>
2331 </tr>
2332 </table>
2333 <table>
2334 <caption align="top">DefaultRolloverStrategy Parameters</caption>
2335 <tr>
2336 <th>Parameter Name</th>
2337 <th>Type</th>
2338 <th>Description</th>
2339 </tr>
2340 <tr>
2341 <td>fileIndex</td>
2342 <td>String</td>
2343 <td>If set to "max" (the default), files with a higher index will be newer than files with a
2344 smaller index. If set to "min", file renaming and the counter will follow the Fixed Window strategy
2345 described above.</td>
2346 </tr>
2347 <tr>
2348 <td>min</td>
2349 <td>integer</td>
2350 <td>The minimum value of the counter. The default value is 1.</td>
2351 </tr>
2352 <tr>
2353 <td>max</td>
2354 <td>integer</td>
2355 <td>The maximum value of the counter. Once this values is reached older archives will be
2356 deleted on subsequent rollovers.</td>
2357 </tr>
2358 <tr>
2359 <td>compressionLevel</td>
2360 <td>integer</td>
2361 <td>
2362 Sets the compression level, 0-9, where 0 = none, 1 = best speed, through 9 = best compression.
2363 Only implemented for ZIP files.
2364 </td>
2365 </tr>
2366 </table>
2367
2368 <p>
2369 Below is a sample configuration that uses a RollingFileAppender with both the time and size based
2370 triggering policies, will create up to 7 archives on the same day (1-7) that are stored in a directory
2371 based on the current year and month, and will compress each
2372 archive using gzip:
2373 </p>
2374
2375 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2376 <Configuration status="warn" name="MyApp" packages="">
2377 <Appenders>
2378 <RollingFile name="RollingFile" fileName="logs/app.log"
2379 filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
2380 <PatternLayout>
2381 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
2382 </PatternLayout>
2383 <Policies>
2384 <TimeBasedTriggeringPolicy />
2385 <SizeBasedTriggeringPolicy size="250 MB"/>
2386 </Policies>
2387 </RollingFile>
2388 </Appenders>
2389 <Loggers>
2390 <Root level="error">
2391 <AppenderRef ref="RollingFile"/>
2392 </Root>
2393 </Loggers>
2394 </Configuration>]]></pre>
2395 <p>
2396 This second example shows a rollover strategy that will keep up to 20 files before removing them.
2397 </p>
2398 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2399 <Configuration status="warn" name="MyApp" packages="">
2400 <Appenders>
2401 <RollingFile name="RollingFile" fileName="logs/app.log"
2402 filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
2403 <PatternLayout>
2404 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
2405 </PatternLayout>
2406 <Policies>
2407 <TimeBasedTriggeringPolicy />
2408 <SizeBasedTriggeringPolicy size="250 MB"/>
2409 </Policies>
2410 <DefaultRolloverStrategy max="20"/>
2411 </RollingFile>
2412 </Appenders>
2413 <Loggers>
2414 <Root level="error">
2415 <AppenderRef ref="RollingFile"/>
2416 </Root>
2417 </Loggers>
2418 </Configuration>]]></pre>
2419 <p>
2420 Below is a sample configuration that uses a RollingFileAppender with both the time and size based
2421 triggering policies, will create up to 7 archives on the same day (1-7) that are stored in a directory
2422 based on the current year and month, and will compress each
2423 archive using gzip and will roll every 6 hours when the hour is divisible by 6:
2424 </p>
2425
2426 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2427 <Configuration status="warn" name="MyApp" packages="">
2428 <Appenders>
2429 <RollingFile name="RollingFile" fileName="logs/app.log"
2430 filePattern="logs/$${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}-%i.log.gz">
2431 <PatternLayout>
2432 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
2433 </PatternLayout>
2434 <Policies>
2435 <TimeBasedTriggeringPolicy interval="6" modulate="true"/>
2436 <SizeBasedTriggeringPolicy size="250 MB"/>
2437 </Policies>
2438 </RollingFile>
2439 </Appenders>
2440 <Loggers>
2441 <Root level="error">
2442 <AppenderRef ref="RollingFile"/>
2443 </Root>
2444 </Loggers>
2445 </Configuration>]]></pre>
2446 </subsection>
2447 <a name="RollingRandomAccessFileAppender" />
2448 <subsection name="RollingRandomAccessFileAppender">
2449 <p><i>As of beta-9, the name of this appender has been changed from FastRollingFile to
2450 RollingRandomAccessFile. Configurations using the <code>FastRollingFile</code> element
2451 no longer work and should be modified to use the <code>RollingRandomAccessFile</code> element.</i></p>
2452 <p>
2453 The RollingRandomAccessFileAppender is similar to the standard
2454 <a href="#RollingFileAppender">RollingFileAppender</a>
2455 except it is always buffered (this cannot be switched off)
2456 and
2457 internally it uses a
2458 <tt>ByteBuffer + RandomAccessFile</tt>
2459 instead of a
2460 <tt>BufferedOutputStream</tt>.
2461 We saw a 20-200% performance improvement compared to
2462 RollingFileAppender with "bufferedIO=true"
2463 in our
2464 <a href="async.html#RandomAccessFileAppenderPerformance">measurements</a>.
2465
2466 The RollingRandomAccessFileAppender writes
2467 to the File named in the
2468 fileName parameter
2469 and rolls the file over according the
2470 TriggeringPolicy
2471 and the RolloverPolicy.
2472
2473 Similar to the RollingFileAppender,
2474 RollingRandomAccessFileAppender uses a RollingRandomAccessFileManager
2475 to actually perform the
2476 file I/O and perform the rollover. While RollingRandomAccessFileAppender
2477 from different Configurations cannot be
2478 shared, the RollingRandomAccessFileManagers can be
2479 if the Manager is accessible.
2480 For example, two web applications in a servlet
2481 container can have their own configuration and safely write to the
2482 same file if Log4j is in a ClassLoader that is common to both of them.
2483 </p>
2484 <p>
2485 A RollingRandomAccessFileAppender requires a
2486 <a href="#TriggeringPolicies">TriggeringPolicy</a>
2487 and a
2488 <a href="#RolloverStrategies">RolloverStrategy</a>.
2489 The triggering policy determines if a rollover should
2490 be performed
2491 while the RolloverStrategy defines how the rollover
2492 should be done.
2493 If no RolloverStrategy
2494 is configured, RollingRandomAccessFileAppender will
2495 use the
2496 <a href="#DefaultRolloverStrategy">DefaultRolloverStrategy</a>.
2497 </p>
2498 <p>
2499 File locking is not supported by the RollingRandomAccessFileAppender.
2500 </p>
2501 <table>
2502 <caption align="top">RollingRandomAccessFileAppender Parameters</caption>
2503 <tr>
2504 <th>Parameter Name</th>
2505 <th>Type</th>
2506 <th>Description</th>
2507 </tr>
2508 <tr>
2509 <td>append</td>
2510 <td>boolean</td>
2511 <td>When true - the default, records will be appended to the end
2512 of the file. When set to false,
2513 the file will be cleared before
2514 new records are written.
2515 </td>
2516 </tr>
2517 <tr>
2518 <td>filter</td>
2519 <td>Filter</td>
2520 <td>A Filter to determine if the event should be handled by this
2521 Appender. More than one Filter
2522 may be used by using a
2523 CompositeFilter.
2524 </td>
2525 </tr>
2526 <tr>
2527 <td>fileName</td>
2528 <td>String</td>
2529 <td>The name of the file to write to. If the file, or any of its
2530 parent directories, do not exist,
2531 they will be created.
2532 </td>
2533 </tr>
2534 <tr>
2535 <td>filePattern</td>
2536 <td>String</td>
2537 <td>
2538 The pattern of the file name of the archived log file. The format
2539 of the pattern should is
2540 dependent on the RolloverPolicy that is
2541 used. The DefaultRolloverPolicy
2542 will accept both
2543 a date/time
2544 pattern compatible with
2545 <a
2546 href="http://download.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html">
2547 SimpleDateFormat</a>
2548
2549 and/or a %i which represents an integer counter. The pattern
2550 also supports interpolation at
2551 runtime so any of the Lookups (such
2552 as the
2553 <a href="./lookups.html#DateLookup">DateLookup</a>
2554 can
2555 be included in the pattern.
2556 </td>
2557 </tr>
2558 <tr>
2559 <td>immediateFlush</td>
2560 <td>boolean</td>
2561 <td><p>When set to true - the default, each write will be followed by a flush.
2562 This will guarantee the data is written
2563 to disk but could impact performance.</p>
2564 <p>Flushing after every write is only useful when using this
2565 appender with synchronous loggers. Asynchronous loggers and
2566 appenders will automatically flush at the end of a batch of events,
2567 even if immediateFlush is set to false. This also guarantees
2568 the data is written to disk but is more efficient.</p>
2569 </td>
2570 </tr>
2571 <tr>
2572 <td>bufferSize</td>
2573 <td>int</td>
2574 <td>The buffer size, defaults to 262,144 bytes (256 * 1024).</td>
2575 </tr>
2576 <tr>
2577 <td>layout</td>
2578 <td>Layout</td>
2579 <td>The Layout to use to format the LogEvent</td>
2580 </tr>
2581
2582 <tr>
2583 <td>name</td>
2584 <td>String</td>
2585 <td>The name of the Appender.</td>
2586 </tr>
2587 <tr>
2588 <td>policy</td>
2589 <td>TriggeringPolicy</td>
2590 <td>The policy to use to determine if a rollover should occur.
2591 </td>
2592 </tr>
2593 <tr>
2594 <td>strategy</td>
2595 <td>RolloverStrategy</td>
2596 <td>The strategy to use to determine the name and location of the
2597 archive file.
2598 </td>
2599 </tr>
2600 <tr>
2601 <td>ignoreExceptions</td>
2602 <td>boolean</td>
2603 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
2604 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
2605 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
2606 <a href="#FailoverAppender">FailoverAppender</a>.</td>
2607 </tr>
2608 </table>
2609 <a name="FRFA_TriggeringPolicies" />
2610 <h4>Triggering Policies</h4>
2611 <p>
2612 See
2613 <a href="#TriggeringPolicies">RollingFileAppender Triggering Policies</a>.
2614 </p>
2615 <a name="FRFA_RolloverStrategies" />
2616 <h4>Rollover Strategies</h4>
2617 <p>
2618 See
2619 <a href="#RolloverStrategies">RollingFileAppender Rollover Strategies</a>.
2620 </p>
2621
2622 <p>
2623 Below is a sample configuration that uses a RollingRandomAccessFileAppender
2624 with both the time and size based
2625 triggering policies, will create
2626 up to 7 archives on the same day (1-7) that
2627 are stored in a
2628 directory
2629 based on the current year and month, and will compress
2630 each
2631 archive using gzip:
2632 </p>
2633
2634 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2635 <Configuration status="warn" name="MyApp" packages="">
2636 <Appenders>
2637 <RollingRandomAccessFile name="RollingRandomAccessFile" fileName="logs/app.log"
2638 filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
2639 <PatternLayout>
2640 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
2641 </PatternLayout>
2642 <Policies>
2643 <TimeBasedTriggeringPolicy />
2644 <SizeBasedTriggeringPolicy size="250 MB"/>
2645 </Policies>
2646 </RollingRandomAccessFile>
2647 </Appenders>
2648 <Loggers>
2649 <Root level="error">
2650 <AppenderRef ref="RollingRandomAccessFile"/>
2651 </Root>
2652 </Loggers>
2653 </Configuration>]]></pre>
2654 <p>
2655 This second example shows a rollover strategy that will keep up to
2656 20 files before removing them.
2657 </p>
2658 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2659 <Configuration status="warn" name="MyApp" packages="">
2660 <Appenders>
2661 <RollingRandomAccessFile name="RollingRandomAccessFile" fileName="logs/app.log"
2662 filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
2663 <PatternLayout>
2664 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
2665 </PatternLayout>
2666 <Policies>
2667 <TimeBasedTriggeringPolicy />
2668 <SizeBasedTriggeringPolicy size="250 MB"/>
2669 </Policies>
2670 <DefaultRolloverStrategy max="20"/>
2671 </RollingRandomAccessFile>
2672 </Appenders>
2673 <Loggers>
2674 <Root level="error">
2675 <AppenderRef ref="RollingRandomAccessFile"/>
2676 </Root>
2677 </Loggers>
2678 </Configuration>]]></pre>
2679 <p>
2680 Below is a sample configuration that uses a RollingRandomAccessFileAppender
2681 with both the time and size based
2682 triggering policies, will create
2683 up to 7 archives on the same day (1-7) that
2684 are stored in a
2685 directory
2686 based on the current year and month, and will compress
2687 each
2688 archive using gzip and will roll every 6 hours when the hour is
2689 divisible
2690 by 6:
2691 </p>
2692
2693 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2694 <Configuration status="warn" name="MyApp" packages="">
2695 <Appenders>
2696 <RollingRandomAccessFile name="RollingRandomAccessFile" fileName="logs/app.log"
2697 filePattern="logs/$${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}-%i.log.gz">
2698 <PatternLayout>
2699 <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
2700 </PatternLayout>
2701 <Policies>
2702 <TimeBasedTriggeringPolicy interval="6" modulate="true"/>
2703 <SizeBasedTriggeringPolicy size="250 MB"/>
2704 </Policies>
2705 </RollingRandomAccessFile>
2706 </Appenders>
2707 <Loggers>
2708 <Root level="error">
2709 <AppenderRef ref="RollingRandomAccessFile"/>
2710 </Root>
2711 </Loggers>
2712 </Configuration>]]></pre>
2713 </subsection>
2714 <a name="RoutingAppender"/>
2715 <subsection name="RoutingAppender">
2716 <p>
2717 The RoutingAppender evaluates LogEvents and then routes them to a subordinate Appender. The target
2718 Appender may be an appender previously configured and may be referenced by its name or the
2719 Appender can be dynamically created as needed. The RoutingAppender should be configured after any
2720 Appenders it references to allow it to shut down properly.
2721 </p>
2722 <table>
2723 <caption align="top">RoutingAppender Parameters</caption>
2724 <tr>
2725 <th>Parameter Name</th>
2726 <th>Type</th>
2727 <th>Description</th>
2728 </tr>
2729 <tr>
2730 <td>filter</td>
2731 <td>Filter</td>
2732 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
2733 may be used by using a CompositeFilter.</td>
2734 </tr>
2735 <tr>
2736 <td>name</td>
2737 <td>String</td>
2738 <td>The name of the Appender.</td>
2739 </tr>
2740 <tr>
2741 <td>rewritePolicy</td>
2742 <td>RewritePolicy</td>
2743 <td>The RewritePolicy that will manipulate the LogEvent.</td>
2744 </tr>
2745 <tr>
2746 <td>routes</td>
2747 <td>Routes</td>
2748 <td>Contains one or more Route declarations to identify the criteria for choosing Appenders.</td>
2749 </tr>
2750 <tr>
2751 <td>ignoreExceptions</td>
2752 <td>boolean</td>
2753 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
2754 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
2755 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
2756 <a href="#FailoverAppender">FailoverAppender</a>.</td>
2757 </tr>
2758 </table>
2759 <h4>Routes</h4>
2760 <p>
2761 The Routes element accepts a single, required attribute named "pattern". The pattern is evaluated
2762 against all the registered Lookups and the result is used to select a Route. Each Route may be
2763 configured with a key. If the key matches the result of evaluating the pattern then that Route
2764 will be selected. If no key is specified on a Route then that Route is the default. Only one Route
2765 can be configured as the default.
2766 </p>
2767 <p>
2768 Each Route must reference an Appender. If the Route contains a ref attribute then the
2769 Route will reference an Appender that was defined in the configuration. If the Route contains an
2770 Appender definition then an Appender will be created within the context of the RoutingAppender and
2771 will be reused each time a matching Appender name is referenced through a Route.
2772 </p>
2773 <p>
2774 Below is a sample configuration that uses a RoutingAppender to route all Audit events to
2775 a FlumeAppender and all other events will be routed to a RollingFileAppender that captures only
2776 the specific event type. Note that the AuditAppender was predefined while the RollingFileAppenders
2777 are created as needed.
2778 </p>
2779
2780 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2781 <Configuration status="warn" name="MyApp" packages="">
2782 <Appenders>
2783 <Flume name="AuditLogger" compress="true">
2784 <Agent host="192.168.10.101" port="8800"/>
2785 <Agent host="192.168.10.102" port="8800"/>
2786 <RFC5424Layout enterpriseNumber="18060" includeMDC="true" appName="MyApp"/>
2787 </Flume>
2788 <Routing name="Routing">
2789 <Routes pattern="$${sd:type}">
2790 <Route>
2791 <RollingFile name="Rolling-${sd:type}" fileName="${sd:type}.log"
2792 filePattern="${sd:type}.%i.log.gz">
2793 <PatternLayout>
2794 <pattern>%d %p %c{1.} [%t] %m%n</pattern>
2795 </PatternLayout>
2796 <SizeBasedTriggeringPolicy size="500" />
2797 </RollingFile>
2798 </Route>
2799 <Route ref="AuditLogger" key="Audit"/>
2800 </Routes>
2801 </Routing>
2802 </Appenders>
2803 <Loggers>
2804 <Root level="error">
2805 <AppenderRef ref="Routing"/>
2806 </Root>
2807 </Loggers>
2808 </Configuration>]]></pre>
2809 </subsection>
2810 <a name="SMTPAppender"/>
2811 <subsection name="SMTPAppender">
2812 <p>
2813 Sends an e-mail when a specific logging event occurs, typically on errors or fatal errors.
2814 </p>
2815 <p>
2816 The number of logging events delivered in this e-mail depend on the value of
2817 <b>BufferSize</b> option. The <code>SMTPAppender</code> keeps only the last
2818 <code>BufferSize</code> logging events in its cyclic buffer. This keeps
2819 memory requirements at a reasonable level while still delivering useful
2820 application context. All events in the buffer are included in the email.
2821 The buffer will contain the most recent events of level TRACE to WARN
2822 preceding the event that triggered the email.
2823 </p>
2824 <p>
2825 The default behavior is to trigger sending an email whenever an ERROR or higher
2826 severity event is logged and to format it as HTML. The circumstances on when the
2827 email is sent can be controlled by setting one or more filters on the Appender.
2828 As with other Appenders, the formatting can be controlled by specifying a Layout
2829 for the Appender.
2830 </p>
2831 <table>
2832 <caption align="top">SMTPAppender Parameters</caption>
2833 <tr>
2834 <th>Parameter Name</th>
2835 <th>Type</th>
2836 <th>Description</th>
2837 </tr>
2838 <tr>
2839 <td>bcc</td>
2840 <td>String</td>
2841 <td>The comma-separated list of BCC email addresses.</td>
2842 </tr>
2843 <tr>
2844 <td>cc</td>
2845 <td>String</td>
2846 <td>The comma-separated list of CC email addresses.</td>
2847 </tr>
2848 <tr>
2849 <td>bufferSize</td>
2850 <td>integer</td>
2851 <td>The maximum number of log events to be buffered for inclusion in the message. Defaults to 512.</td>
2852 </tr>
2853 <tr>
2854 <td>filter</td>
2855 <td>Filter</td>
2856 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
2857 may be used by using a CompositeFilter.
2858 </td>
2859 </tr>
2860 <tr>
2861 <td>from</td>
2862 <td>String</td>
2863 <td>The email address of the sender.</td>
2864 </tr>
2865 <tr>
2866 <td>layout</td>
2867 <td>Layout</td>
2868 <td>The Layout to use to format the LogEvent. The default is SerializedLayout.</td>
2869 </tr>
2870 <tr>
2871 <td>name</td>
2872 <td>String</td>
2873 <td>The name of the Appender.</td>
2874 </tr>
2875 <tr>
2876 <td>replyTo</td>
2877 <td>String</td>
2878 <td>The comma-separated list of reply-to email addresses.</td>
2879 </tr>
2880 <tr>
2881 <td>smtpDebug</td>
2882 <td>boolean</td>
2883 <td>When set to true enables session debugging on STDOUT. Defaults to false.</td>
2884 </tr>
2885 <tr>
2886 <td>smtpHost</td>
2887 <td>String</td>
2888 <td>The SMTP hostname to send to. This parameter is required.</td>
2889 </tr>
2890 <tr>
2891 <td>smtpPassword</td>
2892 <td>String</td>
2893 <td>The password required to authenticate against the SMTP server.</td>
2894 </tr>
2895 <tr>
2896 <td>smtpPort</td>
2897 <td>integer</td>
2898 <td>The SMTP port to send to. </td>
2899 </tr>
2900 <tr>
2901 <td>smtpProtocol</td>
2902 <td>String</td>
2903 <td>The SMTP transport protocol (such as "smtps", defaults to "smtp").</td>
2904 </tr>
2905 <tr>
2906 <td>smtpUsername</td>
2907 <td>String</td>
2908 <td>The username required to authenticate against the SMTP server.</td>
2909 </tr>
2910 <tr>
2911 <td>ignoreExceptions</td>
2912 <td>boolean</td>
2913 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
2914 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
2915 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
2916 <a href="#FailoverAppender">FailoverAppender</a>.</td>
2917 </tr>
2918 <tr>
2919 <td>to</td>
2920 <td>String</td>
2921 <td>The comma-separated list of recipient email addresses.</td>
2922 </tr>
2923 </table>
2924 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2925 <Configuration status="warn" name="MyApp" packages="">
2926 <Appenders>
2927 <SMTP name="Mail" subject="Error Log" to="errors@logging.apache.org" from="test@logging.apache.org"
2928 smtpHost="localhost" smtpPort="25" bufferSize="50">
2929 </SMTP>
2930 </Appenders>
2931 <Loggers>
2932 <Root level="error">
2933 <AppenderRef ref="Mail"/>
2934 </Root>
2935 </Loggers>
2936 </Configuration>]]></pre>
2937 </subsection>
2938 <a name="SocketAppender"/>
2939 <subsection name="SocketAppender">
2940 <p>
2941 The <code>SocketAppender</code> is an OutputStreamAppender that writes its output to a remote destination
2942 specified by a host and port. The data can be sent over either TCP or UDP and can be sent in any format.
2943 The default format is to send a Serialized LogEvent. Log4j 2 contains a SocketServer which is capable
2944 of receiving serialized LogEvents and routing them through the logging system on the server. You can optionally
2945 secure communication with SSL.
2946 </p>
2947 <table>
2948 <caption align="top"><code>SocketAppender</code> Parameters</caption>
2949 <tr>
2950 <th>Parameter Name</th>
2951 <th>Type</th>
2952 <th>Description</th>
2953 </tr>
2954 <tr>
2955 <td>name</td>
2956 <td>String</td>
2957 <td>The name of the Appender.</td>
2958 </tr>
2959 <tr>
2960 <td>host</td>
2961 <td>String</td>
2962 <td>The name or address of the system that is listening for log events. This parameter is required.</td>
2963 </tr>
2964 <tr>
2965 <td>port</td>
2966 <td>integer</td>
2967 <td>The port on the host that is listening for log events. This parameter must be specified.</td>
2968 </tr>
2969 <tr>
2970 <td>protocol</td>
2971 <td>String</td>
2972 <td>"TCP" (default), "SSL" or "UDP".</td>
2973 </tr>
2974 <tr>
2975 <td>SSL</td>
2976 <td>SslConfiguration</td>
2977 <td>Contains the configuration for the KeyStore and TrustStore.</td>
2978 </tr>
2979 <tr>
2980 <td>filter</td>
2981 <td>Filter</td>
2982 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
2983 may be used by using a CompositeFilter.</td>
2984 </tr>
2985 <tr>
2986 <td>immediateFail</td>
2987 <td>boolean</td>
2988 <td>When set to true, log events will not wait to try to reconnect and will fail immediately if the
2989 socket is not available.</td>
2990 </tr>
2991 <tr>
2992 <td>immediateFlush</td>
2993 <td>boolean</td>
2994 <td>When set to true - the default, each write will be followed by a flush.
2995 This will guarantee the data is written
2996 to disk but could impact performance.</td>
2997 </tr>
2998 <tr>
2999 <td>layout</td>
3000 <td>Layout</td>
3001 <td>The Layout to use to format the LogEvent. The default is SerializedLayout.</td>
3002 </tr>
3003 <tr>
3004 <td>reconnectionDelayMillis</td>
3005 <td>integer</td>
3006 <td>If set to a value greater than 0, after an error the SocketManager will attempt to reconnect to
3007 the server after waiting the specified number of milliseconds. If the reconnect fails then
3008 an exception will be thrown (which can be caught by the application if <code>ignoreExceptions</code> is
3009 set to <code>false</code>).</td>
3010 </tr>
3011 <tr>
3012 <td>connectTimeoutMillis</td>
3013 <td>integer</td>
3014 <td>The connect timeout in milliseconds. The default is 0 (infinite timeout, like Socket.connect()
3015 methods).</td>
3016 </tr>
3017 <tr>
3018 <td>ignoreExceptions</td>
3019 <td>boolean</td>
3020 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
3021 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
3022 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
3023 <a href="#FailoverAppender">FailoverAppender</a>.</td>
3024 </tr>
3025 </table>
3026
3027 <p>
3028 This is an unsecured TCP configuration:
3029 </p>
3030 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
3031 <Configuration status="warn" name="MyApp" packages="">
3032 <Appenders>
3033 <Socket name="socket" host="localhost" port="9500">
3034 <SerializedLayout />
3035 </Socket>
3036 </Appenders>
3037 <Loggers>
3038 <Root level="error">
3039 <AppenderRef ref="socket"/>
3040 </Root>
3041 </Loggers>
3042 </Configuration>]]></pre>
3043
3044 <p>
3045 This is a secured SSL configuration:
3046 </p>
3047 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
3048 <Configuration status="warn" name="MyApp" packages="">
3049 <Appenders>
3050 <Socket name="socket" host="localhost" port="9500">
3051 <SerializedLayout />
3052 <SSL>
3053 <KeyStore location="log4j2-keystore.jks" password="changeme"/>
3054 <TrustStore location="truststore.jks" password="changeme"/>
3055 </SSL>
3056 </Socket>
3057 </Appenders>
3058 <Loggers>
3059 <Root level="error">
3060 <AppenderRef ref="socket"/>
3061 </Root>
3062 </Loggers>
3063 </Configuration>]]></pre>
3064
3065 </subsection>
3066 <a name="SyslogAppender"/>
3067 <subsection name="SyslogAppender">
3068 <p>
3069 The <code>SyslogAppender</code> is a <code>SocketAppender</code> that writes its output to a remote destination
3070 specified by a host and port in a format that conforms with either the BSD Syslog format or the RFC 5424
3071 format. The data can be sent over either TCP or UDP.
3072 </p>
3073 <table>
3074 <caption align="top"><code>SyslogAppender</code> Parameters</caption>
3075 <tr>
3076 <th>Parameter Name</th>
3077 <th>Type</th>
3078 <th>Description</th>
3079 </tr>
3080 <tr>
3081 <td>advertise</td>
3082 <td>boolean</td>
3083 <td>Indicates whether the appender should be advertised.</td>
3084 </tr>
3085 <tr>
3086 <td>appName</td>
3087 <td>String</td>
3088 <td>The value to use as the APP-NAME in the RFC 5424 syslog record.</td>
3089 </tr>
3090 <tr>
3091 <td>charset</td>
3092 <td>String</td>
3093 <td>The character set to use when converting the syslog String to a byte array. The String must be
3094 a valid <a href="http://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html">Charset</a>.
3095 If not specified, the default system Charset will be used.</td>
3096 </tr>
3097 <tr>
3098 <td>connectTimeoutMillis</td>
3099 <td>integer</td>
3100 <td>The connect timeout in milliseconds. The default is 0 (infinite timeout, like Socket.connect()
3101 methods).</td>
3102 </tr>
3103 <tr>
3104 <td>enterpriseNumber</td>
3105 <td>integer</td>
3106 <td>The IANA enterprise number as described in
3107 <a href="http://tools.ietf.org/html/rfc5424#section-7.2.2">RFC 5424</a></td>
3108 </tr>
3109 <tr>
3110 <td>filter</td>
3111 <td>Filter</td>
3112 <td>A Filter to determine if the event should be handled by this Appender. More than one Filter
3113 may be used by using a CompositeFilter.</td>
3114 </tr>
3115 <tr>
3116 <td>facility</td>
3117 <td>String</td>
3118 <td>The facility is used to try to classify the message. The facility option must be set to one of
3119 "KERN", "USER", "MAIL", "DAEMON", "AUTH", "SYSLOG", "LPR", "NEWS", "UUCP", "CRON", "AUTHPRIV",
3120 "FTP", "NTP", "AUDIT", "ALERT", "CLOCK", "LOCAL0", "LOCAL1", "LOCAL2", "LOCAL3", "LOCAL4", "LOCAL5",
3121 "LOCAL6", or "LOCAL7". These values may be specified as upper or lower case characters.</td>
3122 </tr>
3123 <tr>
3124 <td>format</td>
3125 <td>String</td>
3126 <td>If set to "RFC5424" the data will be formatted in accordance with RFC 5424. Otherwise, it will
3127 be formatted as a BSD Syslog record. Note that although BSD Syslog records are required to be
3128 1024 bytes or shorter the SyslogLayout does not truncate them. The RFC5424Layout also does not
3129 truncate records since the receiver must accept records of up to 2048 bytes and may accept records
3130 that are longer.</td>
3131 </tr>
3132 <tr>
3133 <td>host</td>
3134 <td>String</td>
3135 <td>The name or address of the system that is listening for log events. This parameter is required.</td>
3136 </tr>
3137 <tr>
3138 <td>id</td>
3139 <td>String</td>
3140 <td>The default structured data id to use when formatting according to RFC 5424. If the LogEvent contains
3141 a StructuredDataMessage the id from the Message will be used instead of this value.</td>
3142 </tr>
3143 <tr>
3144 <td>ignoreExceptions</td>
3145 <td>boolean</td>
3146 <td>The default is <code>true</code>, causing exceptions encountered while appending events to be
3147 internally logged and then ignored. When set to <code>false</code> exceptions will be propagated to the
3148 caller, instead. You must set this to <code>false</code> when wrapping this Appender in a
3149 <a href="#FailoverAppender">FailoverAppender</a>.</td>
3150 </tr>
3151 <tr>
3152 <td>immediateFail</td>
3153 <td>boolean</td>
3154 <td>When set to true, log events will not wait to try to reconnect and will fail immediately if the
3155 socket is not available.</td>
3156 </tr>
3157 <tr>
3158 <td>immediateFlush</td>
3159 <td>boolean</td>
3160 <td>When set to true - the default, each write will be followed by a flush.
3161 This will guarantee the data is written
3162 to disk but could impact performance.</td>
3163 </tr>
3164 <tr>
3165 <td>includeMDC</td>
3166 <td>boolean</td>
3167 <td>Indicates whether data from the ThreadContextMap will be included in the RFC 5424 Syslog record.
3168 Defaults to true.</td>
3169 </tr>
3170 <tr>
3171 <td>loggerFields</td>
3172 <td>List of KeyValuePairs</td>
3173 <td>Allows arbitrary PatternLayout patterns to be included as specified ThreadContext fields; no default
3174 specified. To use, include a &gt;LoggerFields&lt; nested element, containing one or more
3175 &gt;KeyValuePair&lt; elements. Each &gt;KeyValuePair&lt; must have a key attribute, which
3176 specifies the key name which will be used to identify the field within the MDC Structured Data element,
3177 and a value attribute, which specifies the PatternLayout pattern to use as the value.</td>
3178 </tr>
3179 <tr>
3180 <td>mdcExcludes</td>
3181 <td>String</td>
3182 <td>A comma separated list of mdc keys that should be excluded from the LogEvent. This is mutually
3183 exclusive with the mdcIncludes attribute. This attribute only applies to RFC 5424 syslog records.</td>
3184 </tr>
3185 <tr>
3186 <td>mdcIncludes</td>
3187 <td>String</td>
3188 <td>A comma separated list of mdc keys that should be included in the FlumeEvent. Any keys in the MDC
3189 not found in the list will be excluded. This option is mutually exclusive with the mdcExcludes
3190 attribute. This attribute only applies to RFC 5424 syslog records.</td>
3191 </tr>
3192 <tr>
3193 <td>mdcRequired</td>
3194 <td>String</td>
3195 <td>A comma separated list of mdc keys that must be present in the MDC. If a key is not present a
3196 LoggingException will be thrown. This attribute only applies to RFC 5424 syslog records.</td>
3197 </tr>
3198 <tr>
3199 <td>mdcPrefix</td>
3200 <td>String</td>
3201 <td>A string that should be prepended to each MDC key in order to distinguish it from event attributes.
3202 The default string is "mdc:". This attribute only applies to RFC 5424 syslog records.</td>
3203 </tr>
3204 <tr>
3205 <td>messageId</td>
3206 <td>String</td>
3207 <td>The default value to be used in the MSGID field of RFC 5424 syslog records. </td>
3208 </tr>
3209 <tr>
3210 <td>name</td>
3211 <td>String</td>
3212 <td>The name of the Appender.</td>
3213 </tr>
3214 <tr>
3215 <td>newLine</td>
3216 <td>boolean</td>
3217 <td>If true, a newline will be appended to the end of the syslog record. The default is false.</td>
3218 </tr>
3219 <tr>
3220 <td>port</td>
3221 <td>integer</td>
3222 <td>The port on the host that is listening for log events. This parameter must be specified.</td>
3223 </tr>
3224 <tr>
3225 <td>protocol</td>
3226 <td>String</td>
3227 <td>"TCP" or "UDP". This parameter is required.</td>
3228 </tr>
3229 <tr>
3230 <td>SSL</td>
3231 <td>SslConfiguration</td>
3232 <td>Contains the configuration for the KeyStore and TrustStore.</td>
3233 </tr>
3234 <tr>
3235 <td>reconnectionDelayMillis</td>
3236 <td>integer</td>
3237 <td>If set to a value greater than 0, after an error the SocketManager will attempt to reconnect to
3238 the server after waiting the specified number of milliseconds. If the reconnect fails then
3239 an exception will be thrown (which can be caught by the application if <code>ignoreExceptions</code> is
3240 set to <code>false</code>).</td>
3241 </tr>
3242 </table>
3243 <p>
3244 A sample syslogAppender configuration that is configured with two <code>SyslogAppender</code>s, one using the BSD
3245 format and one using RFC 5424.
3246 </p>
3247
3248 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
3249 <Configuration status="warn" name="MyApp" packages="">
3250 <Appenders>
3251 <Syslog name="bsd" host="localhost" port="514" protocol="TCP"/>
3252 <Syslog name="RFC5424" format="RFC5424" host="localhost" port="8514"
3253 protocol="TCP" appName="MyApp" includeMDC="true"
3254 facility="LOCAL0" enterpriseNumber="18060" newLine="true"
3255 messageId="Audit" id="App"/>
3256 </Appenders>
3257 <Loggers>
3258 <Logger name="com.mycorp" level="error">
3259 <AppenderRef ref="RFC5424"/>
3260 </Logger>
3261 <Root level="error">
3262 <AppenderRef ref="bsd"/>
3263 </Root>
3264 </Loggers>
3265 </Configuration>]]></pre>
3266
3267 <p>
3268 For SSL this appender writes its output to a remote destination specified by a host and port over SSL in
3269 a format that conforms with either the BSD Syslog format or the RFC 5424 format.
3270 </p>
3271
3272 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
3273 <Configuration status="warn" name="MyApp" packages="">
3274 <Appenders>
3275 <TLSSyslog name="bsd" host="localhost" port="6514">
3276 <SSL>
3277 <KeyStore location="log4j2-keystore.jks" password="changeme"/>
3278 <TrustStore location="truststore.jks" password="changeme"/>
3279 </SSL>
3280 </TLSSyslog>
3281 </Appenders>
3282 <Loggers>
3283 <Root level="error">
3284 <AppenderRef ref="bsd"/>
3285 </Root>
3286 </Loggers>
3287 </Configuration>]]></pre>
3288 </subsection>
3289
3290 <a name="ZeroMQAppender"/>
3291 <subsection name="ZeroMQ Appender">
3292 <p>
3293 The ZeroMQ appender uses the <a href="https://github.com/zeromq/jeromq">JeroMQ</a> library to send log
3294 events to one or more endpoints.
3295 </p>
3296 <p>
3297 This is a simple JeroMQ configuration:
3298 </p>
3299 <pre class="prettyprint linenums"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
3300 <Configuration name="JeroMQAppenderTest" status="TRACE">
3301 <Appenders>
3302 <JeroMQ name="JeroMQAppender">
3303 <Property name="endpoint">tcp://*:5556</Property>
3304 <Property name="endpoint">ipc://info-topic</Property>
3305 </JeroMQ>
3306 </Appenders>
3307 <Loggers>
3308 <Root level="info">
3309 <AppenderRef ref="JeroMQAppender"/>
3310 </Root>
3311 </Loggers>
3312 </Configuration>]]></pre>
3313 <p>
3314 The table below describes all options. Please consult the JeroMQ and ZeroMQ documentation for details.
3315 </p>
3316 <table>
3317 <caption align="top">JeroMQ Parameters</caption>
3318 <tr>
3319 <th>Parameter Name</th>
3320 <th>Type</th>
3321 <th>Description</th>
3322 </tr>
3323 <tr>
3324 <td>name</td>
3325 <td>String</td>
3326 <td>The name of the Appender.</td>
3327 </tr>
3328 <tr>
3329 <td>Layout</td>
3330 <td>Layout</td>
3331 <td>The Layout of the Appender.</td>
3332 </tr>
3333 <tr>
3334 <td>Filters</td>
3335 <td>Filter</td>
3336 <td>The Filters of the Appender.</td>
3337 </tr>
3338 <tr>
3339 <td>Property</td>
3340 <td>Property</td>
3341 <td>One or more Property elements, named <code>endpoint</code>.</td>
3342 </tr>
3343 <tr>
3344 <td>ignoreExceptions</td>
3345 <td>boolean</td>
3346 <td>If true, exceptions will be logged and suppressed. If false errors will be logged and then passed to the application.</td>
3347 </tr>
3348 <tr>
3349 <td>affinity</td>
3350 <td>long</td>
3351 <td>The ZMQ_AFFINITY option. Defaults to 0.</td>
3352 </tr>
3353 <tr>
3354 <td>backlog</td>
3355 <td>long</td>
3356 <td>The ZMQ_BACKLOG option. Defaults to 100.</td>
3357 </tr>
3358 <tr>
3359 <td>delayAttachOnConnect</td>
3360 <td>boolean</td>
3361 <td>The ZMQ_DELAY_ATTACH_ON_CONNECT option. Defaults to false.</td>
3362 </tr>
3363 <tr>
3364 <td>identity</td>
3365 <td>byte[]</td>
3366 <td>The ZMQ_IDENTITY option. Defaults to none.</td>
3367 </tr>
3368 <tr>
3369 <td>ipv4Only</td>
3370 <td>boolean</td>
3371 <td>The ZMQ_IPV4ONLY option. Defaults to true.</td>
3372 </tr>
3373 <tr>
3374 <td>linger</td>
3375 <td>long</td>
3376 <td>The ZMQ_LINGER option. Defaults to -1.</td>
3377 </tr>
3378 <tr>
3379 <td>maxMsgSize</td>
3380 <td>long</td>
3381 <td>The ZMQ_MAXMSGSIZE option. Defaults to -1.</td>
3382 </tr>
3383 <tr>
3384 <td>rcvHwm</td>
3385 <td>long</td>
3386 <td>The ZMQ_RCVHWM option. Defaults to 1000.</td>
3387 </tr>
3388 <tr>
3389 <td>receiveBufferSize</td>
3390 <td>long</td>
3391 <td>The ZMQ_RCVBUF option. Defaults to 0.</td>
3392 </tr>
3393 <tr>
3394 <td>receiveTimeOut</td>
3395 <td>int</td>
3396 <td>The ZMQ_RCVTIMEO option. Defaults to -1.</td>
3397 </tr>
3398 <tr>
3399 <td>reconnectIVL</td>
3400 <td>long</td>
3401 <td>The ZMQ_RECONNECT_IVL option. Defaults to 100.</td>
3402 </tr>
3403 <tr>
3404 <td>reconnectIVLMax</td>
3405 <td>long</td>
3406 <td>The ZMQ_RECONNECT_IVL_MAX option. Defaults to 0.</td>
3407 </tr>
3408 <tr>
3409 <td>sendBufferSize</td>
3410 <td>long</td>
3411 <td>The ZMQ_SNDBUF option. Defaults to 0.</td>
3412 </tr>
3413 <tr>
3414 <td>sendTimeOut</td>
3415 <td>int</td>
3416 <td>The ZMQ_SNDTIMEO option. Defaults to -1.</td>
3417 </tr>
3418 <tr>
3419 <td>sndHwm</td>
3420 <td>long</td>
3421 <td>The ZMQ_SNDHWM option. Defaults to 1000.</td>
3422 </tr>
3423 <tr>
3424 <td>tcpKeepAlive</td>
3425 <td>int</td>
3426 <td>The ZMQ_TCP_KEEPALIVE option. Defaults to -1.</td>
3427 </tr>
3428 <tr>
3429 <td>tcpKeepAliveCount</td>
3430 <td>long</td>
3431 <td>The ZMQ_TCP_KEEPALIVE_CNT option. Defaults to -1.</td>
3432 </tr>
3433 <tr>
3434 <td>tcpKeepAliveIdle</td>
3435 <td>long</td>
3436 <td>The ZMQ_TCP_KEEPALIVE_IDLE option. Defaults to -1.</td>
3437 </tr>
3438 <tr>
3439 <td>tcpKeepAliveInterval</td>
3440 <td>long</td>
3441 <td>The ZMQ_TCP_KEEPALIVE_INTVL option. Defaults to -1.</td>
3442 </tr>
3443 <tr>
3444 <td>xpubVerbose</td>
3445 <td>boolean</td>
3446 <td>The ZMQ_XPUB_VERBOSE option. Defaults to false.</td>
3447 </tr>
3448 </table>
3449 </subsection>
3450
3451 </section>
3452 </body>
3453 </document>
280280 This gives you more flexibility at the cost of a slight loss in performance (compared to making
281281 all loggers asynchronous). Use the <tt>&lt;asyncRoot&gt;</tt> or <tt>&lt;asyncLogger&gt;</tt>
282282 configuration elements to specify the loggers that need to be asynchronous.
283 The same configuration file can also contain <tt>&lt;root&gt;</tt> and
283 A configuration can contain only one root logger (either a <tt>&lt;root&gt;</tt>
284 or an <tt>&lt;asyncRoot&gt;</tt> element), but otherwise async and non-async loggers may be
285 combined.
286 For example, a configuration file containing <tt>&lt;asyncLogger&gt;</tt> elements
287 can also contain <tt>&lt;root&gt;</tt> and
284288 <tt>&lt;logger&gt;</tt> elements for the synchronous loggers.
285289 </p>
286290 <p>
274274 <subsection name="Automatic Reconfiguration">
275275 <p>
276276 When configured from a File, Log4j has the ability to automatically detect changes to the configuration
277 file and reconfigure itself. If the monitorInterval attribute is specified on the configuration element
278 and is set to a non-zero value then the file will be checked the next time a log event is evaluated
277 file and reconfigure itself. If the <code>monitorInterval</code> attribute is specified on the configuration
278 element and is set to a non-zero value then the file will be checked the next time a log event is evaluated
279279 and/or logged and the monitorInterval has elapsed since the last check. The example below shows how
280280 to configure the attribute so that the configuration file will be checked for changes only after at
281281 least 30 seconds have elapsed. The minimum interval is 5 seconds.
358358 as the action being performed for a specific user, route output to Flume or a log reporting system,
359359 etc. Being able to do this requires understanding the syntax of the configuration files.
360360 </p>
361 <a name="XML"/>
362 <h4>Configuration with XML</h4>
363361 <p>
364362 The configuration element in the XML file accepts several attributes:
365363 </p>
806804
807805 </Configuration>
808806 ]]></pre>
807 <a name="Properties"/>
808 <h4>Configuration with Properties</h4>
809 <p>
810 As of version 2.4, Log4j now supports configuration via properties files. Note that the property
811 syntax is NOT the same as the syntax used in Log4j 1. Like the XML and JSON configurations, properties
812 configurations define the configuration in terms of plugins and attributes to the plugins.
813 </p>
814 <p>
815 The properties configuration requires that you list the identifiers of the appenders, filters and loggers,
816 in a comma separated list in properties with those names. Each of those components will then be expected
817 to be defined in sets of properties that begin with <i>component.identifier</i>. The identifier does not
818 have to match the name of the component being defined but must uniquely identify all the attributes and
819 subcomponents that are part of the component. Each individual component MUST have a "type" attribute
820 specified that identifies the component's Plugin type.
821 </p>
822 <p>
823 Unlike the base components, when creating subcomponents you cannot specify an element containing a list of
824 identifiers. Instead, you must define the wrapper element with its type as is shown in the policies
825 definition in the rolling file appender below. You then define each of the subcomponents below that
826 wrapper element, as the TimeBasedTriggeringPolicy and SizeBasedTriggeringPolicy are defined below.
827 </p>
828 <p>
829 Properties configuration files support the advertiser, monitorInterval, name, packages, shutdownHook,
830 status, and verbose attrbutes. See <a href="#ConfigurationSyntax">Configuration Syntax</a> for the
831 definitions of these attributes.
832 </p>
833 <pre class="prettyprint linenums">
834 status = error
835 name = PropertiesConfig
836
837 property.filename = target/rolling/rollingtest.log
838
839 filters = threshold
840
841 filter.threshold.type = ThresholdFilter
842 filter.threshold.level = debug
843
844 appenders = console, rolling, list
845
846 appender.console.type = Console
847 appender.console.name = STDOUT
848 appender.console.layout.type = PatternLayout
849 appender.console.layout.pattern = %m%n
850
851 appender.rolling.type = RollingFile
852 appender.rolling.name = RollingFile
853 appender.rolling.fileName = ${filename}
854 appender.rolling.filePattern = target/rolling2/test1-%d{MM-dd-yy-HH-mm-ss}-%i.log.gz
855 appender.rolling.layout.type = PatternLayout
856 appender.rolling.layout.pattern = %d %p %C{1.} [%t] %m%n
857 appender.rolling.policies.type = Policies
858 appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
859 appender.rolling.policies.time.interval = 2
860 appender.rolling.policies.time.modulate = true
861 appender.rolling.policies.size.type = SizeBasedTriggeringPolicy
862 appender.rolling.policies.size.size=100MB
863
864 appender.list.type = List
865 appender.list.name = List
866 appender.list.filters = threshold
867 appender.list.filter.threshold.type = ThresholdFilter
868 appender.list.filter.threshold.level = error
869
870 loggers = rolling
871
872 logger.rolling.name = org.apache.logging.log4j.core.appender.rolling
873 logger.rolling.level = debug
874 logger.rolling.additivity = false
875 logger.rolling.appenderRefs = rolling
876 logger.rolling.appenderRef.rolling.ref = RollingFile
877
878 rootLogger.level = info
879 rootLogger.appenderRefs = stdout
880 rootLogger.appenderRef.stdout.ref = STDOUT
881 </pre>
809882 </subsection>
810883 <a name="PropertySubstitution"/>
811884 <subsection name="Property Substitution">
901974 A JVM input argument accessed through JMX, but not a main argument;
902975 see <a class="javadoc" href="http://docs.oracle.com/javase/6/docs/api/java/lang/management/RuntimeMXBean.html#getInputArguments--">RuntimeMXBean.getInputArguments()</a>.
903976 Not available on Android.</td>
977 </tr>
978 <tr>
979 <td>log4j</td>
980 <td>Log4j configuration properties. The expressions <code>${dollar}{log4j:configLocation}</code> and
981 <code>${dollar}{log4j:configParentLocation}</code> respectively provide the absolute path
982 to the log4j configuration file and its parent folder.</td>
904983 </tr>
905984 <tr>
906985 <td>main</td>
2626 <body>
2727 <section name="Custom Configurations">
2828 <p>
29 Log4j 2 provides a few ways for applications to create their own custom configurations.
29 Log4j 2 provides a few ways for applications to create their own custom configurations:
3030 </p>
31 <ul>
32 <li>Specify a custom ConfigurationFactory</li>
33 <li>Use the Configurator</li>
34 <li>Modify the current Configuration after initialization</li>
35 </ul>
36 <a name="ConfigurationBuilder"/>
37 <subsection name="The ConfigurationBuilder API">
38 <p>
39 Starting with release 2.4, Log4j provides a ConfigurationBuilder and a set of component builders that
40 allow a Configuration to be created fairly easily.
41 Actual configuration objects like LoggerConfig or Appender can be unwieldy; they require a lot
42 of knowledge on Log4j internals which makes them difficult to work with if all you want is
43 create a Configuration.
44 </p>
45 <p>
46 The new ConfigurationBuilder API (in the <code>org.apache.logging.log4j.core.config.builder.api</code> package)
47 allows users to create Configurations in code by constructing component <i>definitions</i>.
48 There is no need to work directly with actual configuration objects.
49 Component definitions are added to the ConfigurationBuilder, and once all the definitions have
50 been collected all the actual configuration objects (like Loggers and Appenders) are constructed.
51 </p>
52 <p>
53 ConfigurationBuilder has convenience methods for the base components that can be configured such as
54 Loggers, Appenders, Filter, Properties, etc.
55 However, Log4j 2's plugin mechanism means that users can create any number of custom components.
56 As a trade-off, the ConfigurationBuilder API provides only a limited number of "strongly typed"
57 convenience methods like <code>newLogger()</code>, <code>newLayout()</code> etc.
58 The generic <code>builder.newComponent()</code> method can be used if no convenience method exists
59 for the component you want to configure.
60 </p>
61 <p>
62 For example, the builder does not know what components can be configured on specific components
63 such as the RollingFileAppender vs. the RoutingAppender. To specify a triggering policy on a
64 RollingFileAppender you would use builder.newComponent().
65 </p>
66 </subsection>
3167 <a name="ConfigurationFactory"/>
32 <subsection name="Add a New Configuration via ConfigurationFactory">
33 <p>
34 The easiest way to create a custom Configuration is to extend one of the standard Configuration classes
68 <subsection name="Understanding ConfigurationFactory">
69 <p>
70 Log4j 2 will search for available ConfigurationFactories and then select the one to use. The
71 selected ConfigurationFactory creates the Configuration that Log4j will use. Here is how Log4j finds
72 the available ConfigurationFactories:
73 </p>
74 <ol>
75 <li>A system property named "log4j.configurationFactory" can be set with the name of the ConfigurationFactory to be used.</li>
76 <li><code>ConfigurationFactory.setConfigurationFactory(ConfigurationFactory)</code> can be called with the instance of the
77 ConfigurationFactory to be used. This must be called before any other calls to Log4j.</li>
78 <li>A ConfigurationFactory implementation can be added to the classpath and configured as a plugin
79 in the "ConfigurationFactory" category.
80 The Order annotation can be used to specify the relative priority when multiple applicable
81 ConfigurationFactories are found.</li>
82 </ol>
83 <p>
84 ConfigurationFactories have the concept of "supported types", which basically maps to the
85 file extension of the configuration file that the ConfigurationFactory can handle.
86 If a configuration file location is specified, ConfigurationFactories whose supported type
87 does not include "*" or the matching file extension will not be used.
88 </p>
89 </subsection>
90 <a name="Example"/>
91 <subsection name="Using ConfigurationBuilder with a Custom ConfigurationFactory">
92 <p>
93 One way to programmatically configure Log4j 2 is to create a custom ConfigurationFactory
94 that uses the <a href="#ConfigurationBuilder">ConfigurationBuilder</a> to create a Configuration.
95 The below example overrides the <code>getConfiguration()</code> method to return a
96 Configuration created by the ConfigurationBuilder.
97 This will cause the Configuration to automatically be hooked into Log4j when the LoggerContext is created.
98 In the example below, because it specifies a supported type of "*" it will override any configuration files provided.
99 </p>
100 <pre class="prettyprint linenum"><![CDATA[
101 @Plugin(name = "CustomConfigurationFactory", category = ConfigurationFactory.CATEGORY)
102 @Order(50)
103 public class CustomConfigurationFactory extends ConfigurationFactory {
104
105 static Configuration createConfiguration(final String name, ConfigurationBuilder<BuiltConfiguration> builder) {
106 builder.setConfigurationName(name);
107 builder.setStatusLevel(Level.ERROR);
108 builder.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.NEUTRAL).
109 addAttribute("level", Level.DEBUG));
110 AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE").
111 addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
112 appenderBuilder.add(builder.newLayout("PatternLayout").
113 addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable"));
114 appenderBuilder.add(builder.newFilter("MarkerFilter", Filter.Result.DENY,
115 Filter.Result.NEUTRAL).addAttribute("marker", "FLOW"));
116 builder.add(appenderBuilder);
117 builder.add(builder.newLogger("org.apache.logging.log4j", Level.DEBUG).
118 add(builder.newAppenderRef("Stdout")).
119 addAttribute("additivity", false));
120 builder.add(builder.newRootLogger(Level.ERROR).add(builder.newAppenderRef("Stdout")));
121 return builder.build();
122 }
123
124 @Override
125 public Configuration getConfiguration(ConfigurationSource source) {
126 return getConfiguration(source.toString(), null);
127 }
128
129 @Override
130 public Configuration getConfiguration(final String name, final URI configLocation) {
131 ConfigurationBuilder<BuiltConfiguration> builder = newConfigurationBuilder();
132 return createConfiguration(name, builder);
133 }
134
135 @Override
136 protected String[] getSupportedTypes() {
137 return new String[] {"*"};
138 }
139 }]]></pre>
140 </subsection>
141 <a name="Configurator"/>
142 <subsection name="Using ConfigurationBuilder with the Configurator">
143 <p>
144 An alternative to a custom ConfigurationFactory is to configure with the <code>Configurator</code>.
145 Once a Configuration object has been constructed, it can be passed to one of the
146 <code>Configurator.initialize</code> methods to set up the Log4j configuration.
147 </p>
148 <p>
149 Using the Configurator in this manner allows the application control over when Log4j is initialized.
150 However, should any logging be attempted before Configurator.initialize() is called then the
151 default configuration will be used for those log events.
152 </p>
153 <pre class="prettyprint linenum"><![CDATA[
154 ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
155 builder.setStatusLevel(Level.ERROR);
156 builder.setConfigurationName("BuilderTest");
157 builder.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.NEUTRAL)
158 .addAttribute("level", Level.DEBUG));
159 AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE").addAttribute("target",
160 ConsoleAppender.Target.SYSTEM_OUT);
161 appenderBuilder.add(builder.newLayout("PatternLayout").
162 addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable"));
163 appenderBuilder.add(builder.newFilter("MarkerFilter", Filter.Result.DENY, Filter.Result.NEUTRAL).
164 addAttribute("marker", "FLOW"));
165 builder.add(appenderBuilder);
166 builder.add(builder.newLogger("org.apache.logging.log4j", Level.DEBUG).
167 add(builder.newAppenderRef("Stdout")).addAttribute("additivity", false));
168 builder.add(builder.newRootLogger(Level.ERROR).add(builder.newAppenderRef("Stdout")));
169 ctx = Configurator.initialize(builder.build());
170 ]]></pre>
171 </subsection>
172
173 <a name="Hybrid"/>
174 <subsection name="Combining Configuration File with Programmatic Configuration">
175 <p>
176 Sometimes you want to configure with a configuration file but do some additional programmatic
177 configuration. A possible use case might be that you want to allow for a flexible configuration using XML
178 but at the same time make sure there are a few configuration elements that are always present that can't be removed.
179 </p>
180 <p>
181 The easiest way to achieve this is to extend one of the standard Configuration classes
35182 (XMLConfiguration, JSONConfiguration) and then create a new ConfigurationFactory for the extended class.
36183 After the standard configuration completes the custom configuration can be added to it.
37184 </p>
90237 }</pre>
91238 </subsection>
92239 <a name="AddingToCurrent"/>
93 <subsection name="Programatically Adding to the Current Configuration">
240 <subsection name="Programmatically Adding to the Current Configuration">
94241 <p>
95242 Applications sometimes have the need to customize logging separate from the actual configuration.
96243 Log4j allows this although it suffers from a few limitations:
168168 <p>
169169 The built-in log levels have a set of convenience methods on the Logger
170170 interface that makes them easier to use. For example, the Logger interface
171 has fourteen <tt>debug()</tt> methods that support the DEBUG level:
171 has 24 <tt>debug()</tt> methods that support the DEBUG level:
172172 </p>
173173 <pre class="prettyprint">
174174 // convenience methods for the built-in DEBUG level
185185 debug(Object, Throwable)
186186 debug(String)
187187 debug(String, Object...)
188 debug(String, Throwable)</pre>
188 debug(String, Throwable)
189 // lambda support methods added in 2.4
190 debug(Marker, MessageSupplier)
191 debug(Marker, MessageSupplier, Throwable)
192 debug(Marker, String, Supplier&lt;?&gt;...)
193 debug(Marker, Supplier&lt;?&gt;)
194 debug(Marker, Supplier&lt;?&gt;, Throwable)
195 debug(MessageSupplier)
196 debug(MessageSupplier, Throwable)
197 debug(String, Supplier&lt;?&gt;...)
198 debug(Supplier&lt;?&gt;)
199 debug(Supplier&lt;?&gt;, Throwable)</pre>
189200 <p>
190201 Similar methods exist for the other built-in levels.
191202 Custom levels, in contrast, need to pass in the log level as an extra parameter.
201212 <pre class="prettyprint">
202213 // nice to have: descriptive methods and no need to pass the level as a parameter
203214 logger.verbose("a verbose message");
204 logger.diag("another message");</pre>
215 logger.diag("another message");
216 logger.diag("java 8 lambda expression: {}", () -> someMethod());</pre>
205217 <p>The standard Logger interface cannot provide convenience methods for
206218 custom levels, but the next few sections introduce a code generation tool
207219 to create loggers that aim to make custom levels as easy to use
274286 // instead of Logger logger = LogManager.getLogger(MyService.class):
275287 private static final ExtLogger logger = ExtLogger.create(MyService.class);
276288
277 public void someMethod() {
289 public void demoExtendedLogger() {
278290 // ...
279291 logger.trace("the built-in TRACE level");
280292 logger.verbose("a custom level: a VERBOSE message");
285297 logger.warn("the built-in WARN level");
286298 logger.error("the built-in ERROR level");
287299 logger.fatal("the built-in FATAL level");
300 logger.notice("java 8 lambda expression only executed if NOTICE is enabled: {}", () -> someMethod());
288301 // ...
289302 }
290303 ...
296309 Use the following command to generate a logger wrapper that adds methods to the built-in ones:
297310 </p>
298311 <pre class="prettyprint">
299 java -cp log4j-core-${Log4jReleaseVersion}.jar org.apache.logging.log4j.core.tools.Generate${dollar}ExtendedLogger} \
312 java -cp log4j-core-${Log4jReleaseVersion}.jar org.apache.logging.log4j.core.tools.Generate${dollar}ExtendedLogger \
300313 com.mycomp.ExtLogger DIAG=350 NOTICE=450 VERBOSE=550 > com/mycomp/ExtLogger.java</pre>
301314 <p>
302315 This will generate source code for a logger wrapper that has the convenience methods
125125 toAccount.deposit(amount);
126126 fromAccount.withdraw(amount);
127127 String confirm = UUID.randomUUID().toString();
128 StructuredDataMessage msg = new StructureDataMessage(confirm, null, "transfer");
128 StructuredDataMessage msg = new StructuredDataMessage(confirm, null, "transfer");
129129 msg.put("toAccount", toAccount);
130130 msg.put("fromAccount", fromAccount);
131131 msg.put("amount", amount);
101101 and Pattern Converters without requiring any changes to Log4j.</li>
102102 <li>Due to the Plugin system configuration is simpler. Entries in the configuration
103103 do not require a class name to be specified.</li>
104 <li>Support for <a href="customloglevels.html">custom log levels</a>.
105 Custom log levels can be defined in code or in configuration.</li>
106 <li>Support for <a href="api.html#LambdaSupport">lambda expressions</a>.
107 Client code running on Java 8 can use lambda expressions to lazily construct a log message only if
108 the requested log level is enabled. Explicit level checks are not needed, resulting in cleaner code.</li>
104109 <li>Support for <a href="messages.html">Message objects</a>. Messages allow support for interesting and
105110 complex constructs to be passed through the logging system and be efficiently
106111 manipulated. Users are free to create their own
6767 For more details, see Oracle's documentation on
6868 <a href="http://docs.oracle.com/javase/7/docs/technotes/guides/management/agent.html#gdenl">Remote
6969 Monitoring and Management</a>.</p>
70 </subsection>
71 <subsection name="RMI impact on Garbage Collection">
72 <a name="RMI_GC" />
73 <p>
74 Be aware that RMI by default triggers a full GC every hour.
75 See the <a href="http://docs.oracle.com/javase/7/docs/technotes/guides/rmi/sunrmiproperties.html">Oracle
76 documentation</a> for the <code>sun.rmi.dgc.server.gcInterval</code> and <code>sun.rmi.dgc.client.gcInterval</code> properties.
77 The default value of both properties is 3600000 milliseconds (one hour). Before Java 6, it was one minute.
78 </p><p>
79 The two sun.rmi arguments reflect whether your JVM is running in server or client mode.
80 If you want to modify the GC interval time it may be best to specify both properties to ensure the argument is picked up by the JVM.
81 </p><p>
82 An alternative may be to disable explicit calls to <code>System.gc()</code> altogether with
83 <code>-XX:+DisableExplicitGC</code>, or (if you are using the CMS or G1 collector)
84 add <code>-XX:+ExplicitGCInvokesConcurrent</code> to ensure the full GCs are done
85 concurrently in parallel with your application instead of forcing a stop-the-world collection.
86 </p>
7087 </subsection>
7188 </section>
7289 <section name="Log4j Instrumented Components">
4343 many more types of Appenders. However, this means you need to configure most Layouts with a ${Charset} to
4444 ensure the byte array contains correct values.
4545 </p>
46 <p>
47 The root class for layouts that use a Charset is <code>org.apache.logging.log4j.core.layout.AbstractStringLayout</code>
48 where the default there is UTF-8. Each layout that extends <code>org.apache.logging.log4j.core.layout.AbstractStringLayout</code>
49 can provide its own default. See each layout below.
50 </p>
51 <a name="CSVLayouts"/>
52 <subsection name="CSV Layouts">
53 <p>
54 The CSV layout can be used in two ways: First, using <code>CsvParameterLayout</code> to log event parameters
55 to create a custom database, usually to a logger and file appender uniquely configured for this purpose.
56 Second, using <code>CsvLogEventLayout</code> to log events to create a database, as an alternative to using a
57 full DBMS or using a JDBC driver that supports the CSV format.
58 </p>
59 <p>
60 The <code>CsvParameterLayout</code> converts an event's parameters into a CSV record, ignoring the message.
61 To log CSV records, you can use the usual Logger methods <code>info()</code>, <code>debug()</code>, and so on:
62 </p>
63 <pre class="prettyprint linenums">
64 logger.info("Ignored", value1, value2, value3);
65 </pre>
66 <p>
67 Which will create the CSV record:
68 </p>
69 <pre class="prettyprint linenums">
70 value1, value2, value3
71 </pre>
72 <p>
73 Alternatively, you can use a <code>ObjectArrayMessage</code>, which only carries parameters:
74 </p>
75 <pre class="prettyprint linenums">
76 logger.info(new ObjectArrayMessage(value1, value2, value3));
77 </pre>
78 <p>
79 The layouts CsvParameterLayout and CsvLogEventLayout are configured with the following parameters:
80 </p>
81 <table>
82 <caption>CsvParameterLayout and CsvLogEventLayout</caption>
83 <tr>
84 <th>Parameter Name</th>
85 <th>Type</th>
86 <th>Description</th>
87 </tr>
88 <tr>
89 <td>format</td>
90 <td>String</td>
91 <td>
92 One of the predefined formats: <code>Default</code>, <code>Excel</code>, <code>MySQL</code>,
93 <code>RFC4180</code>, <code>TDF</code>.
94 See
95 <a href="https://commons.apache.org/proper/commons-csv/archives/1.2/apidocs/org/apache/commons/csv/CSVFormat.Predefined.html">CSVFormat.Predefined</a>.
96 </td>
97 </tr>
98 <tr>
99 <td>delimiter</td>
100 <td>Character</td>
101 <td>Sets the delimiter of the format to the specified character.</td>
102 </tr>
103 <tr>
104 <td>escape</td>
105 <td>Character</td>
106 <td>Sets the escape character of the format to the specified character.</td>
107 </tr>
108 <tr>
109 <td>quote</td>
110 <td>Character</td>
111 <td>Sets the quoteChar of the format to the specified character.</td>
112 </tr>
113 <tr>
114 <td>quoteMode</td>
115 <td>String</td>
116 <td>
117 Sets the output quote policy of the format to the specified value. One of: <code>ALL</code>,
118 <code>MINIMAL</code>, <code>NON_NUMERIC</code>, <code>NONE</code>.
119 </td>
120 </tr>
121 <tr>
122 <td>nullString</td>
123 <td>String</td>
124 <td>Writes null as the given nullString when writing records.</td>
125 </tr>
126 <tr>
127 <td>recordSeparator</td>
128 <td>String</td>
129 <td>Sets the record separator of the format to the specified String.</td>
130 </tr>
131 <tr>
132 <td>charset</td>
133 <td>Charset</td>
134 <td>The output Charset.</td>
135 </tr>
136 <tr>
137 <td>header</td>
138 <td>Sets the header to include when the stream is opened.</td>
139 <td>Desc.</td>
140 </tr>
141 <tr>
142 <td>footer</td>
143 <td>Sets the footer to include when the stream is closed.</td>
144 <td>Desc.</td>
145 </tr>
146 </table>
147 <p>
148 Logging as a CSV events looks like this:
149 </p>
150 <pre class="prettyprint linenums">
151 logger.debug("one={}, two={}, three={}", 1, 2, 3);
152 </pre>
153 <p>
154 Produces a CSV record with the following fields:
155 <ol>
156 <li>Time Nanos</li>
157 <li>Time Millis</li>
158 <li>Level</li>
159 <li>Thread Name</li>
160 <li>Formatted Message</li>
161 <li>Logger FQCN</li>
162 <li>Logger Name</li>
163 <li>Marker</li>
164 <li>Thrown Proxy</li>
165 <li>Source</li>
166 <li>Context Map</li>
167 <li>Context Stack</li>
168 </ol>
169 </p>
170 <pre class="prettyprint linenums">
171 0,1441617184044,DEBUG,main,"one=1, two=2, three=3",org.apache.logging.log4j.spi.AbstractLogger,,,,org.apache.logging.log4j.core.layout.CsvLogEventLayoutTest.testLayout(CsvLogEventLayoutTest.java:98),{},[]
172 </pre>
173 </subsection>
46174 <a name="JSONLayout"/>
47175 <subsection name="JSONLayout">
48176 <!-- From Javadoc of org.apache.logging.log4j.core.layout.JSONLayout -->
88216 <p>
89217 Appenders using this layout should have their <code>charset</code> set to <code>UTF-8</code> or
90218 <code>UTF-16</code>, otherwise events containing non-ASCII characters could result in corrupted log files.
91 The default charset is <code>UTF-8</code>.
219 If not specified, this layout uses UTF-8.
92220 </p>
93221 <h4>Pretty vs. compact JSON</h4>
94222 <p>
158286 <td>charset</td>
159287 <td>String</td>
160288 <td>The character set to use when converting the HTML String to a byte array. The value must be
161 a valid ${Charset}. If not specified, the default system Charset will be used.</td>
289 a valid ${Charset}. If not specified, this layout uses UTF-8.</td>
162290 </tr>
163291 <tr>
164292 <td>contentType</td>
231359 <td>charset</td>
232360 <td>String</td>
233361 <td>The character set to use when converting the syslog String to a byte array. The String must be
234 a valid ${Charset}. If not specified, the default system Charset will be used.
362 a valid ${Charset}. If not specified, this layout uses UTF-8.
235363 </td>
236364 </tr>
237365 <tr>
812940 </tr>
813941 <tr>
814942 <td align="center">
943 <a name="NanoTime" />
944 <b>N</b><br />
945 <b>nano</b>
946 </td>
947 <td><p>Outputs the result of <code>System.nanoTime()</code> at the time the log event was created.</p>
948 </td>
949 </tr>
950 <tr>
951 <td align="center">
815952 <b>p</b>|<b>level</b>{<em>level</em>=<em>label</em>, <em>level</em>=<em>label</em>, ...}
816953 <b>p</b>|<b>level</b>{length=<em>n</em>}
817954 <b>p</b>|<b>level</b>{lowerCase=<em>true</em>|<em>false</em>}
10381175 </tr>
10391176 <tr>
10401177 <td align="center">
1041 <b>X</b>{key}<br />
1042 <b>mdc</b>{key}<br />
1043 <b>MDC</b>{key}
1178 <b>X</b>{key[,key2...]}<br />
1179 <b>mdc</b>{key[,key2...]}<br />
1180 <b>MDC</b>{key[,key2...]}
10441181 </td>
10451182 <td>
10461183 <p>Outputs the Thread Context Map (also known as the Mapped Diagnostic Context or MDC)
10471184 associated with the thread that generated the logging event. The
10481185 <b>X</b>
1049 conversion character can be followed by the key for the
1186 conversion character can be followed by one or more keys for the
10501187 map placed between braces, as in
10511188 <b>%X{clientNumber}</b>
10521189 where
10531190 <code>clientNumber</code>
10541191 is the key. The value in the MDC
1055 corresponding to the key will be output. If no additional sub-option
1056 is specified, then the entire contents of the MDC key value pair set
1057 is output using a format {{key1,val1},{key2,val2}}
1192 corresponding to the key will be output.</p>
1193 <p>If a list of keys are provided, such as <b>%X{name, number}</b>, then each key that is present in the
1194 ThreadContext will be output using the format {name=val1, number=val2}. The key/value pairs will be
1195 printed in the order they appear in the list.</p>
1196 <p>If no sub-options are specified then the entire contents of the MDC key value pair set
1197 is output using a format {key1=val1, key2=val2}. The key/value pairs will be printed in sorted order.
10581198 </p>
10591199 <p>See the
10601200 <a class="javadoc" href="../log4j-api/apidocs/org/apache/logging/log4j/ThreadContext.html">ThreadContext</a>
11461286 are dropped. This behavior deviates from the printf function in C
11471287 where truncation is done from the end.
11481288 </p>
1289 <p>Truncation from the end is possible by appending a minus character
1290 right after the period. In that case, if the maximum field width
1291 is eight and the data item is ten characters long, then the last
1292 two characters of the data item are dropped.
1293 </p>
11491294 <p>Below are various format modifier examples for the category
11501295 conversion specifier.
11511296 </p>
12021347 <td>Right pad with spaces if the category name is shorter than 20
12031348 characters. However, if category name is longer than 30 characters,
12041349 then truncate from the beginning.
1350 </td>
1351 </tr>
1352 <tr>
1353 <td align="center">%-20.-30c</td>
1354 <td align="center">true</td>
1355 <td align="center">20</td>
1356 <td align="center">30</td>
1357 <td>Right pad with spaces if the category name is shorter than 20
1358 characters. However, if category name is longer than 30 characters,
1359 then truncate from the end.
12051360 </td>
12061361 </tr>
12071362 <caption align="top">Pattern Converters</caption>
14001555 <td>charset</td>
14011556 <td>String</td>
14021557 <td>The character set to use when converting the syslog String to a byte array. The String must be
1403 a valid ${Charset}. If not specified, the default system Charset will be used.</td>
1558 a valid ${Charset}. If not specified, this layout uses UTF-8.</td>
14041559 </tr>
14051560 <tr>
14061561 <td>facility</td>
14691624 <p>
14701625 Appenders using this layout should have their <code>charset</code> set to <code>UTF-8</code> or
14711626 <code>UTF-16</code>, otherwise events containing non ASCII characters could result in corrupted log files.
1627 If not specified, this layout uses UTF-8.
14721628 </p>
14731629 <h4>Pretty vs. compact XML</h4>
14741630 <p>
175175 </p>
176176 <p><strong>Java's JMX module is not available on Android.</strong></p>
177177 </subsection>
178 <a name="Log4jConfigLookup"/>
179 <subsection name="Log4j Configuration Location Lookup">
180 <p>
181 Log4j configuration properties. The expressions
182 <code>${log4j:configLocation}</code> and <code>${log4j:configParentLocation}</code>
183 respectively provide the absolute path to the log4j configuration file
184 and its parent folder.
185 </p><p>
186 The example below uses this lookup to place log files in a directory relative
187 to the log4j configuration file.
188 </p>
189 <pre class="prettyprint linenums"><![CDATA[
190 <File name="Application" fileName="${log4j:configParentLocation}/logs/application.log">
191 <PatternLayout>
192 <pattern>%d %p %c{1.} [%t] %m%n</pattern>
193 </PatternLayout>
194 </File>]]></pre>
195 </subsection>
178196 <a name="AppMainArgsLookup"/>
179197 <subsection name="Main Arguments Lookup (Application)">
180198 <p>
182200 the main arguments of the application to Log4j:
183201 </p>
184202 <pre class="prettyprint linenums"><![CDATA[
185 import org.apache.logging.log4j.core.lookup.MapLookup;
203 import org.apache.logging.log4j.core.lookup.MainMapLookup;
186204
187205 public static void main(String args[]) {
188 MapLookup.setMainArguments(args);
206 MainMapLookup.setMainArguments(args);
189207 ...
190208 }]]></pre>
191209 <p>
303321 </Routes>
304322 </Routing>]]></pre>
305323 </subsection>
324 <subsection name="Marker Lookup">
325 <p>
326 The marker lookup allows you to use markers in interesting configurations like a routing appender.
327 Consider the following YAML configuration and code that logs to different files based on markers:
328 </p>
329 <pre class="prettyprint linenums"><![CDATA[
330 Configuration:
331 status: debug
332
333 Appenders:
334 Console:
335 RandomAccessFile:
336 - name: SQL_APPENDER
337 fileName: logs/sql.log
338 PatternLayout:
339 Pattern: "%d{ISO8601_BASIC} %-5level %logger{1} %X %msg%n"
340 - name: PAYLOAD_APPENDER
341 fileName: logs/payload.log
342 PatternLayout:
343 Pattern: "%d{ISO8601_BASIC} %-5level %logger{1} %X %msg%n"
344 - name: PERFORMANCE_APPENDER
345 fileName: logs/performance.log
346 PatternLayout:
347 Pattern: "%d{ISO8601_BASIC} %-5level %logger{1} %X %msg%n"
348
349 Routing:
350 name: ROUTING_APPENDER
351 Routes:
352 pattern: "$${marker:}"
353 Route:
354 - key: PERFORMANCE
355 ref: PERFORMANCE_APPENDER
356 - key: PAYLOAD
357 ref: PAYLOAD_APPENDER
358 - key: SQL
359 ref: SQL_APPENDER
360
361 Loggers:
362 Root:
363 level: trace
364 AppenderRef:
365 - ref: ROUTING_APPENDER]]></pre>
366 <pre class="prettyprint linenums"><![CDATA[
367 public static final Marker SQL = MarkerFactory.getMarker("SQL");
368 public static final Marker PAYLOAD = MarkerFactory.getMarker("PAYLOAD");
369 public static final Marker PERFORMANCE = MarkerFactory.getMarker("PERFORMANCE");
370
371 final Logger logger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
372
373 logger.info(SQL, "Message in Sql.log");
374 logger.info(PAYLOAD, "Message in Payload.log");
375 logger.info(PERFORMANCE, "Message in Performance.log");]]></pre>
376 <p>
377 Note the key part of the configuration is <code>pattern: "$${marker:}"</code>. This will produce three log files,
378 each with a log event for a specific marker. Log4j will route the log event with the <code>SQL</code> marker to
379 <code>sql.log</code>, the log event with the <code>PAYLOAD</code> marker to <code>payload.log</code>, and so on.
380 </p>
381 <p>
382 You can use the notation <code>"${marker:name}"</code> and <code>"$${marker:name}"</code> to check for the
383 existence of a marker where <code>name</code> is the marker name. If the marker exists, the expression returns
384 the name, otherwise <code>null</code>.
385 </p>
386 </subsection>
306387 <a name="StructuredDataLookup"/>
307388 <subsection name="Structured Data Lookup">
308389 <p>
7575 <li>
7676 Calls to <code>org.apache.log4j.Logger.setLevel()</code> or similar methods are not supported in the API.
7777 Applications should remove these. Equivalent functionality is provided in the Log4j 2 implementation
78 classes but may leave the application susceptible to changes in Log4j 2 internals.
78 classes, see <code>org.apache.logging.log4j.core.config.Configurator.setLevel()</code>, but may leave
79 the application susceptible to changes in Log4j 2 internals.
7980 </li>
8081 <li>
8182 Where appropriate, applications should convert to use parameterized messages instead of String
8283 concatenation.
84 </li>
85 <li>
86 <a href="http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/MDC.html"><code>org.apache.log4j.MDC</code></a> and
87 <a href="http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/NDC.html"><code>org.apache.log4j.NDC</code></a>
88 have been replaced by the <a href="thread-context.html">Thread Context</a>.
8389 </li>
8490 </ol>
8591 </subsection>
2727 Some Log4J features depend on external libraries. This page lists the required and optional
2828 dependencies.
2929 </p>
30 <p>
31 As of version 2.4, Log4J requires Java 7. Versions 2.3 and earlier require Java 6.
32 </p>
3033
3134 <a name="log4j-api" />
3235 <h4>log4j-api</h4>
4952 <th>Requirements</th>
5053 </tr>
5154 <tr>
55 <td>CSV Layout</td>
56 <td><a href="https://commons.apache.org/proper/commons-csv/">Apache Commons CSV</a></td>
57 </tr>
58 <tr>
5259 <td>XML configuration</td>
5360 <td>-</td>
5461 </tr>
8693 entity that the user implements. It also requires an appropriate JDBC driver
8794 </td>
8895 </tr>
96 <tr>
97 <td>bzip2, Deflate, Pack200, and XZ compression on rollover</td>
98 <td><a href="http://commons.apache.org/proper/commons-compress/">Apache Commons Compress</a>.
99 In addition, XZ requires <a href="http://tukaani.org/xz/java.html">XZ for Java</a>.
100 </td>
101 </tr>
102 <tr>
103 <td>ZeroMQ Appender</td>
104 <td>
105 The ZeroMQ appender uses the <a href="https://github.com/zeromq/jeromq">JeroMQ</a> library which is
106 licensed under the terms of the GNU Lesser General Public License (LGPL). For details see the
107 files <code>COPYING</code> and <code>COPYING.LESSER</code> included with the JeroMQ distribution.
108 </td>
109 </tr>
89110 </table>
90111
91112 <a name="log4j-jcl" />