diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
new file mode 100644
index 0000000000..22e41d0717
--- /dev/null
+++ b/.github/workflows/maven.yml
@@ -0,0 +1,97 @@
+name: Maven CI Build
+
+on: [push]
+
+jobs:
+ JDK6Toolchain:
+ name: Toolchain 1.6, JDK 11, OS ${{ matrix.os }}
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [ubuntu-18.04, ubuntu-20.04, windows-2019, windows-2022]
+ fail-fast: true
+ max-parallel: 2
+ steps:
+ - uses: actions/checkout@v1
+ - name: Install Toolchain JDK
+ uses: battila7/jdk-via-jabba@v1
+ with:
+ jdk: zulu@1.6.119
+ javaHomeEnvironmentVariable: TOOLCHAIN_JDK
+ addBinDirectoryToPath: false
+ - name: Configure Maven for Toolchain
+ shell: bash
+ run: |
+ mkdir -p $HOME/.m2 && cat >$HOME/.m2/toolchains.xml < Please also see: {@link http://logging.apache.org/log4j/1.2/faq.html#mdcmemoryleak} Please also see: Memory leak FAQ. WARNING: This version of JDBCAppender
- is very likely to be completely replaced in the future. Moreoever,
- it does not log exceptions.
-
- Each append call adds to an The Overriding the {@link #getLogStatement} method allows more
- explicit control of the statement used for logging.
-
- For use as a base class:
-
- ArrayList
buffer. When
- the buffer is filled each log event is placed in a sql statement
- (configurable) and executed.
-
- BufferSize, db URL, User, & Password are
- configurable options in the standard log4j ways.
-
- setSql(String sql)
sets the SQL statement to be
- used for logging -- this statement is sent to a
- PatternLayout
(either created automaticly by the
- appender or added by the user). Therefore by default all the
- conversion patterns in PatternLayout
can be used
- inside of the statement. (see the test cases for examples)
-
-
-
-
-
- @author Kevin Steppe (ksteppe@pacbell.net)
+ Changed in 1.2.18+ to complain about its use and do nothing else.
+ See the log4j 1.2 homepage
+ for more information on why this class is disabled since 1.2.18.
+ @author Kevin Steppe (ksteppe@pacbell.net)
+ @deprecated
*/
public class JDBCAppender extends org.apache.log4j.AppenderSkeleton {
- /**
- * URL of the DB for default connection handling
- */
+ static final String JDBC_UNSUPPORTED =
+ "ERROR-LOG4J-NETWORKING-UNSUPPORTED: JDBC unsupported!" +
+ " This is a breaking change in Log4J 1 >=1.2.18. Change your config to stop using JDBC!";
+
protected String databaseURL = "jdbc:odbc:myDB";
- /**
- * User to connect as for default connection handling
- */
protected String databaseUser = "me";
- /**
- * User to use for default connection handling
- */
protected String databasePassword = "mypassword";
- /**
- * Connection used by default. The connection is opened the first time it
- * is needed and then held open until the appender is closed (usually at
- * garbage collection). This behavior is best modified by creating a
- * sub-class and overriding the getConnection()
to pass any connection
- you want. Typically this is used to enable application wide
- connection pooling.
-
- closeConnection(Connection con)
-- if
- you override getConnection make sure to implement
- closeConnection
to handle the connection you
- generated. Typically this would return the connection to the
- pool it came from.
+ The JDBCAppender provides for sending log events to a database
+ in Log4j up to 1.2.17.
- getLogStatement(LoggingEvent event)
to
- produce specialized or dynamic statements. The default uses the
- sql option value.
-
- getConnection
and
- * closeConnection
methods.
- */
protected Connection connection = null;
- /**
- * Stores the string given to the pattern layout for conversion into a SQL
- * statement, eg: insert into LogTable (Thread, Class, Message) values
- * ("%t", "%c", "%m").
- *
- * Be careful of quotes in your messages!
- *
- * Also see PatternLayout.
- */
protected String sqlStatement = "";
- /**
- * size of LoggingEvent buffer before writting to the database.
- * Default is 1.
- */
protected int bufferSize = 1;
- /**
- * ArrayList holding the buffer of Logging Events.
- */
protected ArrayList buffer;
- /**
- * Helper object for clearing out the buffer
- */
protected ArrayList removes;
- private boolean locationInfo = false;
-
public JDBCAppender() {
- super();
- buffer = new ArrayList(bufferSize);
- removes = new ArrayList(bufferSize);
+ LogLog.error(JDBC_UNSUPPORTED);
}
- /**
- * Gets whether the location of the logging request call
- * should be captured.
- *
- * @since 1.2.16
- * @return the current value of the LocationInfo option.
- */
public boolean getLocationInfo() {
- return locationInfo;
+ return false;
}
- /**
- * The LocationInfo option takes a boolean value. By default, it is
- * set to false which means there will be no effort to extract the location
- * information related to the event. As a result, the event that will be
- * ultimately logged will likely to contain the wrong location information
- * (if present in the log format).
- *
- *
- * Location information extraction is comparatively very slow and should be
- * avoided unless performance is not a concern.
- *
JMS {@link Topic topics} and {@link TopicConnectionFactory topic - * connection factories} are administered objects that are retrieved - * using JNDI messaging which in turn requires the retrieval of a JNDI - * {@link Context}. - - *
There are two common methods for retrieving a JNDI {@link - * Context}. If a file resource named jndi.properties is - * available to the JNDI API, it will use the information found - * therein to retrieve an initial JNDI context. To obtain an initial - * context, your code will simply call: - -
- InitialContext jndiContext = new InitialContext(); -- - *
Calling the no-argument InitialContext()
method
- * will also work from within Enterprise Java Beans (EJBs) because it
- * is part of the EJB contract for application servers to provide each
- * bean an environment naming context (ENC).
-
- *
In the second approach, several predetermined properties are set
- * and these properties are passed to the InitialContext
- * constructor to connect to the naming service provider. For example,
- * to connect to JBoss naming service one would write:
-
-
- Properties env = new Properties( ); - env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); - env.put(Context.PROVIDER_URL, "jnp://hostname:1099"); - env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces"); - InitialContext jndiContext = new InitialContext(env); -- - * where hostname is the host where the JBoss application - * server is running. - * - *
To connect to the the naming service of Weblogic application - * server one would write: - -
- Properties env = new Properties( ); - env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory"); - env.put(Context.PROVIDER_URL, "t3://localhost:7001"); - InitialContext jndiContext = new InitialContext(env); -- - *
Other JMS providers will obviously require different values.
- *
- * The initial JNDI context can be obtained by calling the
- * no-argument InitialContext()
method in EJBs. Only
- * clients running in a separate JVM need to be concerned about the
- * jndi.properties file and calling {@link
- * InitialContext#InitialContext()} or alternatively correctly
- * setting the different properties before calling {@link
- * InitialContext#InitialContext(java.util.Hashtable)} method.
-
-
- @author Ceki Gülcü */
+ * A simple appender that used to publish to a JMS Topic in Log4j up to 1.2.17.
+ *
+ * Changed in 1.2.18+ to complain about its use and do nothing else.
+ * See the log4j 1.2 homepage
+ * for more information on why this class is disabled since 1.2.18.
+ *
+ * @author Ceki Gülcü
+ * @deprecated
+ * @noinspection unused
+ */
public class JMSAppender extends AppenderSkeleton {
- String securityPrincipalName;
- String securityCredentials;
- String initialContextFactoryName;
- String urlPkgPrefixes;
- String providerURL;
- String topicBindingName;
- String tcfBindingName;
- String userName;
- String password;
- boolean locationInfo;
-
- TopicConnection topicConnection;
- TopicSession topicSession;
- TopicPublisher topicPublisher;
+ static final String JMS_UNSUPPORTED =
+ "ERROR-LOG4J-NETWORKING-UNSUPPORTED: JMS unsupported!" +
+ " This is a breaking change in Log4J 1 >=1.2.18. Change your config to stop using JMS!";
public
JMSAppender() {
+ LogLog.error(JMS_UNSUPPORTED);
}
- /**
- The TopicConnectionFactoryBindingName option takes a
- string value. Its value will be used to lookup the appropriate
- TopicConnectionFactory
from the JNDI context.
- */
public
void setTopicConnectionFactoryBindingName(String tcfBindingName) {
- this.tcfBindingName = tcfBindingName;
}
- /**
- Returns the value of the TopicConnectionFactoryBindingName option.
- */
public
String getTopicConnectionFactoryBindingName() {
- return tcfBindingName;
+ return null;
}
- /**
- The TopicBindingName option takes a
- string value. Its value will be used to lookup the appropriate
- Topic
from the JNDI context.
- */
public
void setTopicBindingName(String topicBindingName) {
- this.topicBindingName = topicBindingName;
}
- /**
- Returns the value of the TopicBindingName option.
- */
public
String getTopicBindingName() {
- return topicBindingName;
+ return null;
}
-
- /**
- Returns value of the LocationInfo property which
- determines whether location (stack) info is sent to the remote
- subscriber. */
public
boolean getLocationInfo() {
- return locationInfo;
+ return false;
}
- /**
- * Options are activated and become effective only after calling
- * this method.*/
public void activateOptions() {
- TopicConnectionFactory topicConnectionFactory;
-
- try {
- Context jndi;
-
- LogLog.debug("Getting initial context.");
- if(initialContextFactoryName != null) {
- Properties env = new Properties( );
- env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactoryName);
- if(providerURL != null) {
- env.put(Context.PROVIDER_URL, providerURL);
- } else {
- LogLog.warn("You have set InitialContextFactoryName option but not the "
- +"ProviderURL. This is likely to cause problems.");
- }
- if(urlPkgPrefixes != null) {
- env.put(Context.URL_PKG_PREFIXES, urlPkgPrefixes);
- }
-
- if(securityPrincipalName != null) {
- env.put(Context.SECURITY_PRINCIPAL, securityPrincipalName);
- if(securityCredentials != null) {
- env.put(Context.SECURITY_CREDENTIALS, securityCredentials);
- } else {
- LogLog.warn("You have set SecurityPrincipalName option but not the "
- +"SecurityCredentials. This is likely to cause problems.");
- }
- }
- jndi = new InitialContext(env);
- } else {
- jndi = new InitialContext();
- }
-
- LogLog.debug("Looking up ["+tcfBindingName+"]");
- topicConnectionFactory = (TopicConnectionFactory) lookup(jndi, tcfBindingName);
- LogLog.debug("About to create TopicConnection.");
- if(userName != null) {
- topicConnection = topicConnectionFactory.createTopicConnection(userName,
- password);
- } else {
- topicConnection = topicConnectionFactory.createTopicConnection();
- }
-
- LogLog.debug("Creating TopicSession, non-transactional, "
- +"in AUTO_ACKNOWLEDGE mode.");
- topicSession = topicConnection.createTopicSession(false,
- Session.AUTO_ACKNOWLEDGE);
-
- LogLog.debug("Looking up topic name ["+topicBindingName+"].");
- Topic topic = (Topic) lookup(jndi, topicBindingName);
-
- LogLog.debug("Creating TopicPublisher.");
- topicPublisher = topicSession.createPublisher(topic);
-
- LogLog.debug("Starting TopicConnection.");
- topicConnection.start();
-
- jndi.close();
- } catch(JMSException e) {
- errorHandler.error("Error while activating options for appender named ["+name+
- "].", e, ErrorCode.GENERIC_FAILURE);
- } catch(NamingException e) {
- errorHandler.error("Error while activating options for appender named ["+name+
- "].", e, ErrorCode.GENERIC_FAILURE);
- } catch(RuntimeException e) {
- errorHandler.error("Error while activating options for appender named ["+name+
- "].", e, ErrorCode.GENERIC_FAILURE);
- }
}
protected Object lookup(Context ctx, String name) throws NamingException {
- try {
- return ctx.lookup(name);
- } catch(NameNotFoundException e) {
- LogLog.error("Could not find name ["+name+"].");
- throw e;
- }
+ LogLog.error(JMS_UNSUPPORTED);
+ throw new NameNotFoundException(JMS_UNSUPPORTED);
}
+ /** @noinspection UnusedReturnValue*/
protected boolean checkEntryConditions() {
- String fail = null;
-
- if(this.topicConnection == null) {
- fail = "No TopicConnection";
- } else if(this.topicSession == null) {
- fail = "No TopicSession";
- } else if(this.topicPublisher == null) {
- fail = "No TopicPublisher";
- }
-
- if(fail != null) {
- errorHandler.error(fail +" for JMSAppender named ["+name+"].");
- return false;
- } else {
- return true;
- }
+ errorHandler.error(JMS_UNSUPPORTED);
+ return false;
}
- /**
- Close this JMSAppender. Closing releases all resources used by the
- appender. A closed appender cannot be re-opened. */
public synchronized void close() {
- // The synchronized modifier avoids concurrent append and close operations
-
if(this.closed) {
return;
}
LogLog.debug("Closing appender ["+name+"].");
this.closed = true;
-
- try {
- if(topicSession != null) {
- topicSession.close();
- }
- if(topicConnection != null) {
- topicConnection.close();
- }
- } catch(JMSException e) {
- LogLog.error("Error while closing JMSAppender ["+name+"].", e);
- } catch(RuntimeException e) {
- LogLog.error("Error while closing JMSAppender ["+name+"].", e);
- }
- // Help garbage collection
- topicPublisher = null;
- topicSession = null;
- topicConnection = null;
}
- /**
- This method called by {@link AppenderSkeleton#doAppend} method to
- do most of the real appending work. */
public void append(LoggingEvent event) {
- if(!checkEntryConditions()) {
- return;
- }
-
- try {
- ObjectMessage msg = topicSession.createObjectMessage();
- if(locationInfo) {
- event.getLocationInformation();
- }
- msg.setObject(event);
- topicPublisher.publish(msg);
- } catch(JMSException e) {
- errorHandler.error("Could not publish message in JMSAppender ["+name+"].", e,
- ErrorCode.GENERIC_FAILURE);
- } catch(RuntimeException e) {
- errorHandler.error("Could not publish message in JMSAppender ["+name+"].", e,
- ErrorCode.GENERIC_FAILURE);
- }
+ checkEntryConditions();
}
- /**
- * Returns the value of the InitialContextFactoryName option.
- * See {@link #setInitialContextFactoryName} for more details on the
- * meaning of this option.
- * */
public String getInitialContextFactoryName() {
- return initialContextFactoryName;
+ return null;
}
- /**
- * Setting the InitialContextFactoryName method will cause
- * this JMSAppender
instance to use the {@link
- * InitialContext#InitialContext(Hashtable)} method instead of the
- * no-argument constructor. If you set this option, you should also
- * at least set the ProviderURL option.
- *
- * @see #setProviderURL(String)
- * */
public void setInitialContextFactoryName(String initialContextFactoryName) {
- this.initialContextFactoryName = initialContextFactoryName;
}
public String getProviderURL() {
- return providerURL;
+ return null;
}
public void setProviderURL(String providerURL) {
- this.providerURL = providerURL;
}
String getURLPkgPrefixes( ) {
- return urlPkgPrefixes;
+ return null;
}
public void setURLPkgPrefixes(String urlPkgPrefixes ) {
- this.urlPkgPrefixes = urlPkgPrefixes;
}
public String getSecurityCredentials() {
- return securityCredentials;
+ return null;
}
public void setSecurityCredentials(String securityCredentials) {
- this.securityCredentials = securityCredentials;
}
-
-
+
public String getSecurityPrincipalName() {
- return securityPrincipalName;
+ return null;
}
public void setSecurityPrincipalName(String securityPrincipalName) {
- this.securityPrincipalName = securityPrincipalName;
}
public String getUserName() {
- return userName;
+ return null;
}
- /**
- * The user name to use when {@link
- * TopicConnectionFactory#createTopicConnection(String, String)
- * creating a topic session}. If you set this option, you should
- * also set the Password option. See {@link
- * #setPassword(String)}.
- * */
public void setUserName(String userName) {
- this.userName = userName;
}
public String getPassword() {
- return password;
+ return null;
}
- /**
- * The paswword to use when creating a topic session.
- */
public void setPassword(String password) {
- this.password = password;
}
-
- /**
- If true, the information sent to the remote subscriber will
- include caller's location information. By default no location
- information is sent to the subscriber. */
public void setLocationInfo(boolean locationInfo) {
- this.locationInfo = locationInfo;
}
- /**
- * Returns the TopicConnection used for this appender. Only valid after
- * activateOptions() method has been invoked.
- */
protected TopicConnection getTopicConnection() {
- return topicConnection;
+ throw new IllegalStateException(JMS_UNSUPPORTED);
}
- /**
- * Returns the TopicSession used for this appender. Only valid after
- * activateOptions() method has been invoked.
- */
protected TopicSession getTopicSession() {
- return topicSession;
+ throw new IllegalStateException(JMS_UNSUPPORTED);
}
- /**
- * Returns the TopicPublisher used for this appender. Only valid after
- * activateOptions() method has been invoked.
- */
protected TopicPublisher getTopicPublisher() {
- return topicPublisher;
+ throw new IllegalStateException(JMS_UNSUPPORTED);
}
- /**
- * The JMSAppender sends serialized events and consequently does not
- * require a layout.
- */
public boolean requiresLayout() {
return false;
}
diff --git a/src/main/java/org/apache/log4j/net/JMSSink.java b/src/main/java/org/apache/log4j/net/JMSSink.java
deleted file mode 100644
index 6a02831e1a..0000000000
--- a/src/main/java/org/apache/log4j/net/JMSSink.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.log4j.net;
-
-import org.apache.log4j.Logger;
-import org.apache.log4j.PropertyConfigurator;
-import org.apache.log4j.spi.LoggingEvent;
-import org.apache.log4j.xml.DOMConfigurator;
-
-import javax.jms.JMSException;
-import javax.jms.ObjectMessage;
-import javax.jms.Session;
-import javax.jms.Topic;
-import javax.jms.TopicConnection;
-import javax.jms.TopicConnectionFactory;
-import javax.jms.TopicSession;
-import javax.jms.TopicSubscriber;
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import javax.naming.NameNotFoundException;
-import javax.naming.NamingException;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-
-/**
- * A simple application that consumes logging events sent by a {@link
- * JMSAppender}.
- *
- *
- * @author Ceki Gülcü
- * */
-public class JMSSink implements javax.jms.MessageListener {
-
- static Logger logger = Logger.getLogger(JMSSink.class);
-
- static public void main(String[] args) throws Exception {
- if(args.length != 5) {
- usage("Wrong number of arguments.");
- }
-
- String tcfBindingName = args[0];
- String topicBindingName = args[1];
- String username = args[2];
- String password = args[3];
-
-
- String configFile = args[4];
-
- if(configFile.endsWith(".xml")) {
- DOMConfigurator.configure(configFile);
- } else {
- PropertyConfigurator.configure(configFile);
- }
-
- new JMSSink(tcfBindingName, topicBindingName, username, password);
-
- BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
- // Loop until the word "exit" is typed
- System.out.println("Type \"exit\" to quit JMSSink.");
- while(true){
- String s = stdin.readLine( );
- if (s.equalsIgnoreCase("exit")) {
- System.out.println("Exiting. Kill the application if it does not exit "
- + "due to daemon threads.");
- return;
- }
- }
- }
-
- public JMSSink( String tcfBindingName, String topicBindingName, String username,
- String password) {
-
- try {
- Context ctx = new InitialContext();
- TopicConnectionFactory topicConnectionFactory;
- topicConnectionFactory = (TopicConnectionFactory) lookup(ctx,
- tcfBindingName);
-
- TopicConnection topicConnection =
- topicConnectionFactory.createTopicConnection(username,
- password);
- topicConnection.start();
-
- TopicSession topicSession = topicConnection.createTopicSession(false,
- Session.AUTO_ACKNOWLEDGE);
-
- Topic topic = (Topic)ctx.lookup(topicBindingName);
-
- TopicSubscriber topicSubscriber = topicSession.createSubscriber(topic);
-
- topicSubscriber.setMessageListener(this);
-
- } catch(JMSException e) {
- logger.error("Could not read JMS message.", e);
- } catch(NamingException e) {
- logger.error("Could not read JMS message.", e);
- } catch(RuntimeException e) {
- logger.error("Could not read JMS message.", e);
- }
- }
-
- public void onMessage(javax.jms.Message message) {
- LoggingEvent event;
- Logger remoteLogger;
-
- try {
- if(message instanceof ObjectMessage) {
- ObjectMessage objectMessage = (ObjectMessage) message;
- event = (LoggingEvent) objectMessage.getObject();
- remoteLogger = Logger.getLogger(event.getLoggerName());
- remoteLogger.callAppenders(event);
- } else {
- logger.warn("Received message is of type "+message.getJMSType()
- +", was expecting ObjectMessage.");
- }
- } catch(JMSException jmse) {
- logger.error("Exception thrown while processing incoming message.",
- jmse);
- }
- }
-
-
- protected static Object lookup(Context ctx, String name) throws NamingException {
- try {
- return ctx.lookup(name);
- } catch(NameNotFoundException e) {
- logger.error("Could not find name ["+name+"].");
- throw e;
- }
- }
-
- static void usage(String msg) {
- System.err.println(msg);
- System.err.println("Usage: java " + JMSSink.class.getName()
- + " TopicConnectionFactoryBindingName TopicBindingName username password configFile");
- System.exit(1);
- }
-}
diff --git a/src/main/java/org/apache/log4j/net/SMTPAppender.java b/src/main/java/org/apache/log4j/net/SMTPAppender.java
index 9162d07a53..f6add1def5 100644
--- a/src/main/java/org/apache/log4j/net/SMTPAppender.java
+++ b/src/main/java/org/apache/log4j/net/SMTPAppender.java
@@ -48,6 +48,8 @@
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.Date;
import java.util.Properties;
@@ -74,6 +76,8 @@ class implements TriggeringEventEvaluator.
Since 1.2.16, SMTP over SSL is supported by setting SMTPProtocol to "smpts".
+ Since 1.2.18, warns when using an smtp host that is not the local loopback.
+
@author Ceki Gülcü
@since 1.0 */
public class SMTPAppender extends AppenderSkeleton
@@ -134,6 +138,8 @@ public class SMTPAppender extends AppenderSkeleton
recipient, from, etc. */
public
void activateOptions() {
+ warnInCaseOfInsecureSMTP();
+
Session session = createSession();
msg = new MimeMessage(session);
@@ -154,7 +160,29 @@ void activateOptions() {
((OptionHandler) evaluator).activateOptions();
}
}
-
+
+ void warnInCaseOfInsecureSMTP() {
+ boolean local = false;
+ if (smtpHost != null) {
+ try {
+ if (InetAddress.getByName(smtpHost).isLoopbackAddress()) {
+ local = true;
+ }
+ } catch (UnknownHostException e) {
+ // hope it'll work out later
+ }
+ }
+ if (!local) {
+ if ("smtps".equals(smtpProtocol)) {
+ LogLog.warn("WARN-LOG4J-NETWORKING-REMOTE-SMTPS: logging to remote SMTPS host '" +
+ smtpHost + "'! Log4J 1.2 cannot verify the host, upgrade to Log4J 2!");
+ } else {
+ LogLog.warn("WARN-LOG4J-NETWORKING-REMOTE-SMTP: logging to remote SMTP host '" +
+ smtpHost + "'! SMTP is an unencrypted protocol.");
+ }
+ }
+ }
+
/**
* Address message.
* @param msg message, may not be null.
diff --git a/src/main/java/org/apache/log4j/net/SimpleSocketServer.java b/src/main/java/org/apache/log4j/net/SimpleSocketServer.java
deleted file mode 100644
index 2afdbff899..0000000000
--- a/src/main/java/org/apache/log4j/net/SimpleSocketServer.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.log4j.net;
-
-import java.net.ServerSocket;
-import java.net.Socket;
-
-import org.apache.log4j.LogManager;
-import org.apache.log4j.Logger;
-import org.apache.log4j.PropertyConfigurator;
-import org.apache.log4j.xml.DOMConfigurator;
-
-
-/**
- * A simple {@link SocketNode} based server.
- *
-
- Usage: java org.apache.log4j.net.SimpleSocketServer port configFile - - where port is a port number where the server listens and - configFile is a configuration file fed to the {@link - PropertyConfigurator} or to {@link DOMConfigurator} if an XML file. -- * - * @author Ceki Gülcü - * - * @since 0.8.4 - * */ -public class SimpleSocketServer { - - static Logger cat = Logger.getLogger(SimpleSocketServer.class); - - static int port; - - public - static - void main(String argv[]) { - if(argv.length == 2) { - init(argv[0], argv[1]); - } else { - usage("Wrong number of arguments."); - } - - try { - cat.info("Listening on port " + port); - ServerSocket serverSocket = new ServerSocket(port); - while(true) { - cat.info("Waiting to accept a new client."); - Socket socket = serverSocket.accept(); - cat.info("Connected to client at " + socket.getInetAddress()); - cat.info("Starting new socket node."); - new Thread(new SocketNode(socket, - LogManager.getLoggerRepository()),"SimpleSocketServer-" + port).start(); - } - } catch(Exception e) { - e.printStackTrace(); - } - } - - - static void usage(String msg) { - System.err.println(msg); - System.err.println( - "Usage: java " +SimpleSocketServer.class.getName() + " port configFile"); - System.exit(1); - } - - static void init(String portStr, String configFile) { - try { - port = Integer.parseInt(portStr); - } catch(java.lang.NumberFormatException e) { - e.printStackTrace(); - usage("Could not interpret port number ["+ portStr +"]."); - } - - if(configFile.endsWith(".xml")) { - DOMConfigurator.configure(configFile); - } else { - PropertyConfigurator.configure(configFile); - } - } -} diff --git a/src/main/java/org/apache/log4j/net/SocketAppender.java b/src/main/java/org/apache/log4j/net/SocketAppender.java index 88f0049835..8f305e6ff6 100644 --- a/src/main/java/org/apache/log4j/net/SocketAppender.java +++ b/src/main/java/org/apache/log4j/net/SocketAppender.java @@ -97,6 +97,10 @@ is slow but still faster than the rate of (log) event production @author Ceki Gülcü + @deprecated + The server side of the log4j socket protocol has been disabled + in Log4j >= 1.2.18. Change your config to ship logs using a + modern and secure protocol! @since 0.8.4 */ public class SocketAppender extends AppenderSkeleton { diff --git a/src/main/java/org/apache/log4j/net/SocketHubAppender.java b/src/main/java/org/apache/log4j/net/SocketHubAppender.java index 74d7186ea0..d8ba449b60 100644 --- a/src/main/java/org/apache/log4j/net/SocketHubAppender.java +++ b/src/main/java/org/apache/log4j/net/SocketHubAppender.java @@ -18,252 +18,63 @@ package org.apache.log4j.net; import java.io.IOException; -import java.io.InterruptedIOException; -import java.io.ObjectOutputStream; -import java.net.InetAddress; import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketException; -import java.util.Vector; import org.apache.log4j.AppenderSkeleton; -import org.apache.log4j.helpers.CyclicBuffer; import org.apache.log4j.helpers.LogLog; import org.apache.log4j.spi.LoggingEvent; /** Sends {@link LoggingEvent} objects to a set of remote log servers, - usually a {@link SocketNode SocketNodes}. - -
Acts just like {@link SocketAppender} except that instead of
- connecting to a given remote log server,
- SocketHubAppender
accepts connections from the remote
- log servers as clients. It can accept more than one connection.
- When a log event is received, the event is sent to the set of
- currently connected remote log servers. Implemented this way it does
- not require any update to the configuration file to send data to
- another remote log server. The remote log server simply connects to
- the host and port the SocketHubAppender
is running on.
-
-
The SocketHubAppender
does not store events such
- that the remote side will events that arrived after the
- establishment of its connection. Once connected, events arrive in
- order as guaranteed by the TCP protocol.
+ usually a {@link SocketNode SocketNodes} in Log4j up to 1.2.17.
-
This implementation borrows heavily from the {@link - SocketAppender}. - -
The SocketHubAppender has the following characteristics: - -
SocketHubAppender
does not use a layout. It
- ships a serialized {@link LoggingEvent} object to the remote side.
-
- SocketHubAppender
relies on the TCP
- protocol. Consequently, if the remote side is reachable, then log
- events will eventually arrive at remote client.
-
- On the other hand, if the network link is up, but the remote - client is down, the client will not be blocked when making log - requests but the log events will be lost due to client - unavailability. - -
The single remote client case extends to multiple clients - connections. The rate of logging will be determined by the slowest - link. - -
SocketHubAppender
exits
- before the SocketHubAppender
is closed either
- explicitly or subsequent to garbage collection, then there might
- be untransmitted data in the pipe which might be lost. This is a
- common problem on Windows based systems.
-
- To avoid lost data, it is usually sufficient to {@link #close}
- the SocketHubAppender
either explicitly or by calling
- the {@link org.apache.log4j.LogManager#shutdown} method before
- exiting the application.
-
-
address
and port
. */
public
SocketHubAppender(int _port) {
- port = _port;
- startServer();
+ LogLog.error(SOCKET_HUB_UNSUPPORTED);
}
- /**
- Set up the socket server on the specified port. */
public
void activateOptions() {
- if (advertiseViaMulticastDNS) {
- zeroConf = new ZeroConfSupport(ZONE, port, getName());
- zeroConf.advertise();
- }
- startServer();
}
- /**
- Close this appender.
- This will mark the appender as closed and - call then {@link #cleanUp} method. */ synchronized public void close() { - if(closed) { - return; - } - - LogLog.debug("closing SocketHubAppender " + getName()); - this.closed = true; - if (advertiseViaMulticastDNS) { - zeroConf.unadvertise(); - } - cleanUp(); - - LogLog.debug("SocketHubAppender " + getName() + " closed"); } - /** - Release the underlying ServerMonitor thread, and drop the connections - to all connected remote servers. */ - public + public void cleanUp() { - // stop the monitor thread - LogLog.debug("stopping ServerSocket"); - serverMonitor.stopMonitor(); - serverMonitor = null; - - // close all of the connections - LogLog.debug("closing client connections"); - while (oosList.size() != 0) { - ObjectOutputStream oos = (ObjectOutputStream)oosList.elementAt(0); - if(oos != null) { - try { - oos.close(); - } catch(InterruptedIOException e) { - Thread.currentThread().interrupt(); - LogLog.error("could not close oos.", e); - } catch(IOException e) { - LogLog.error("could not close oos.", e); - } - - oosList.removeElementAt(0); - } - } } - /** - Append an event to all of current connections. */ public void append(LoggingEvent event) { - if (event != null) { - // set up location info if requested - if (locationInfo) { - event.getLocationInformation(); - } - if (application != null) { - event.setProperty("application", application); - } - event.getNDC(); - event.getThreadName(); - event.getMDCCopy(); - event.getRenderedMessage(); - event.getThrowableStrRep(); - - if (buffer != null) { - buffer.add(event); - } - } - - // if no event or no open connections, exit now - if ((event == null) || (oosList.size() == 0)) { - return; - } - - // loop through the current set of open connections, appending the event to each - for (int streamCount = 0; streamCount < oosList.size(); streamCount++) { - - ObjectOutputStream oos = null; - try { - oos = (ObjectOutputStream)oosList.elementAt(streamCount); - } - catch (ArrayIndexOutOfBoundsException e) { - // catch this, but just don't assign a value - // this should not really occur as this method is - // the only one that can remove oos's (besides cleanUp). - } - - // list size changed unexpectedly? Just exit the append. - if (oos == null) { - break; - } - - try { - oos.writeObject(event); - oos.flush(); - // Failing to reset the object output stream every now and - // then creates a serious memory leak. - // right now we always reset. TODO - set up frequency counter per oos? - oos.reset(); - } - catch(IOException e) { - if (e instanceof InterruptedIOException) { - Thread.currentThread().interrupt(); - } - // there was an io exception so just drop the connection - oosList.removeElementAt(streamCount); - LogLog.debug("dropped connection"); - - // decrement to keep the counter in place (for loop always increments) - streamCount--; - } - } } /** @@ -274,241 +85,50 @@ boolean requiresLayout() { return false; } - /** - The Port option takes a positive integer representing - the port where the server is waiting for connections. */ public void setPort(int _port) { - port = _port; } - /** - * The App option takes a string value which should be the name of the application getting logged. If property was already set (via system - * property), don't set here. - */ - public + public void setApplication(String lapp) { - this.application = lapp; } - /** - * Returns value of the Application option. - */ - public + public String getApplication() { - return application; + return null; } - /** - Returns value of the Port option. */ public int getPort() { - return port; + return 0; } - /** - * The BufferSize option takes a positive integer representing the number of events this appender will buffer and send to newly connected - * clients. - */ - public + public void setBufferSize(int _bufferSize) { - buffer = new CyclicBuffer(_bufferSize); } - /** - * Returns value of the bufferSize option. - */ - public + public int getBufferSize() { - if (buffer == null) { - return 0; - } else { - return buffer.getMaxSize(); - } + return 0; } - /** - The LocationInfo option takes a boolean value. If true, - the information sent to the remote host will include location - information. By default no location information is sent to the server. */ public void setLocationInfo(boolean _locationInfo) { - locationInfo = _locationInfo; } - /** - Returns value of the LocationInfo option. */ public boolean getLocationInfo() { - return locationInfo; + return false; } public void setAdvertiseViaMulticastDNS(boolean advertiseViaMulticastDNS) { - this.advertiseViaMulticastDNS = advertiseViaMulticastDNS; } public boolean isAdvertiseViaMulticastDNS() { - return advertiseViaMulticastDNS; + return false; } - /** - Start the ServerMonitor thread. */ - private - void startServer() { - serverMonitor = new ServerMonitor(port, oosList); - } - - /** - * Creates a server socket to accept connections. - * @param socketPort port on which the socket should listen, may be zero. - * @return new socket. - * @throws IOException IO error when opening the socket. - */ protected ServerSocket createServerSocket(final int socketPort) throws IOException { - return new ServerSocket(socketPort); - } - - /** - This class is used internally to monitor a ServerSocket - and register new connections in a vector passed in the - constructor. */ - private class ServerMonitor implements Runnable { - private int port; - private Vector oosList; - private boolean keepRunning; - private Thread monitorThread; - - /** - Create a thread and start the monitor. */ - public - ServerMonitor(int _port, Vector _oosList) { - port = _port; - oosList = _oosList; - keepRunning = true; - monitorThread = new Thread(this); - monitorThread.setDaemon(true); - monitorThread.setName("SocketHubAppender-Monitor-" + port); - monitorThread.start(); - } - - /** - Stops the monitor. This method will not return until - the thread has finished executing. */ - public synchronized void stopMonitor() { - if (keepRunning) { - LogLog.debug("server monitor thread shutting down"); - keepRunning = false; - try { - if (serverSocket != null) { - serverSocket.close(); - serverSocket = null; - } - } catch (IOException ioe) {} - - try { - monitorThread.join(); - } - catch (InterruptedException e) { - Thread.currentThread().interrupt(); - // do nothing? - } - - // release the thread - monitorThread = null; - LogLog.debug("server monitor thread shut down"); - } - } - - private - void sendCachedEvents(ObjectOutputStream stream) throws IOException { - if (buffer != null) { - for (int i = 0; i < buffer.length(); i++) { - stream.writeObject(buffer.get(i)); - } - stream.flush(); - stream.reset(); - } - } - - /** - Method that runs, monitoring the ServerSocket and adding connections as - they connect to the socket. */ - public - void run() { - serverSocket = null; - try { - serverSocket = createServerSocket(port); - serverSocket.setSoTimeout(1000); - } - catch (Exception e) { - if (e instanceof InterruptedIOException || e instanceof InterruptedException) { - Thread.currentThread().interrupt(); - } - LogLog.error("exception setting timeout, shutting down server socket.", e); - keepRunning = false; - return; - } - - try { - try { - serverSocket.setSoTimeout(1000); - } - catch (SocketException e) { - LogLog.error("exception setting timeout, shutting down server socket.", e); - return; - } - - while (keepRunning) { - Socket socket = null; - try { - socket = serverSocket.accept(); - } - catch (InterruptedIOException e) { - // timeout occurred, so just loop - } - catch (SocketException e) { - LogLog.error("exception accepting socket, shutting down server socket.", e); - keepRunning = false; - } - catch (IOException e) { - LogLog.error("exception accepting socket.", e); - } - - // if there was a socket accepted - if (socket != null) { - try { - InetAddress remoteAddress = socket.getInetAddress(); - LogLog.debug("accepting connection from " + remoteAddress.getHostName() - + " (" + remoteAddress.getHostAddress() + ")"); - - // create an ObjectOutputStream - ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); - if (buffer != null && buffer.length() > 0) { - sendCachedEvents(oos); - } - - // add it to the oosList. OK since Vector is synchronized. - oosList.addElement(oos); - } catch (IOException e) { - if (e instanceof InterruptedIOException) { - Thread.currentThread().interrupt(); - } - LogLog.error("exception creating output stream on socket.", e); - } - } - } - } - finally { - // close the socket - try { - serverSocket.close(); - } catch(InterruptedIOException e) { - Thread.currentThread().interrupt(); - } catch (IOException e) { - // do nothing with it? - } - } - } + throw new IOException(SOCKET_HUB_UNSUPPORTED); } } - diff --git a/src/main/java/org/apache/log4j/net/SocketNode.java b/src/main/java/org/apache/log4j/net/SocketNode.java index e977f1333a..ae3827f2fa 100644 --- a/src/main/java/org/apache/log4j/net/SocketNode.java +++ b/src/main/java/org/apache/log4j/net/SocketNode.java @@ -17,13 +17,9 @@ package org.apache.log4j.net; -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InterruptedIOException; -import java.io.ObjectInputStream; import java.net.Socket; -import org.apache.log4j.Logger; +import org.apache.log4j.helpers.LogLog; import org.apache.log4j.spi.LoggerRepository; import org.apache.log4j.spi.LoggingEvent; @@ -31,94 +27,29 @@ /** Read {@link LoggingEvent} objects sent from a remote client using - Sockets (TCP). These logging events are logged according to local - policy, as if they were generated locally. + Sockets (TCP) in Log4j up to 1.2.17. -
For example, the socket node might decide to log events to a - local file and also resent them to a second socket node. + Changed in 1.2.18+ to complain about its use and do nothing else. + See the log4j 1.2 homepage + for more information on why this class is disabled since 1.2.18. - @author Ceki Gülcü + @author Ceki Gülcü - @since 0.8.4 + @since 0.8.4 + @deprecated + @noinspection unused */ public class SocketNode implements Runnable { - Socket socket; - LoggerRepository hierarchy; - ObjectInputStream ois; - - static Logger logger = Logger.getLogger(SocketNode.class); + static final String SOCKET_NODE_UNSUPPORTED = + "ERROR-LOG4J-NETWORKING-UNSUPPORTED: SocketNode unsupported!" + + " This is a breaking change in Log4J 1 >=1.2.18. Stop using this class!"; public SocketNode(Socket socket, LoggerRepository hierarchy) { - this.socket = socket; - this.hierarchy = hierarchy; - try { - ois = new ObjectInputStream( - new BufferedInputStream(socket.getInputStream())); - } catch(InterruptedIOException e) { - Thread.currentThread().interrupt(); - logger.error("Could not open ObjectInputStream to "+socket, e); - } catch(IOException e) { - logger.error("Could not open ObjectInputStream to "+socket, e); - } catch(RuntimeException e) { - logger.error("Could not open ObjectInputStream to "+socket, e); - } + LogLog.error(SOCKET_NODE_UNSUPPORTED); } - //public - //void finalize() { - //System.err.println("-------------------------Finalize called"); - // System.err.flush(); - //} - public void run() { - LoggingEvent event; - Logger remoteLogger; - - try { - if (ois != null) { - while(true) { - // read an event from the wire - event = (LoggingEvent) ois.readObject(); - // get a logger from the hierarchy. The name of the logger is taken to be the name contained in the event. - remoteLogger = hierarchy.getLogger(event.getLoggerName()); - //event.logger = remoteLogger; - // apply the logger-level filter - if(event.getLevel().isGreaterOrEqual(remoteLogger.getEffectiveLevel())) { - // finally log the event as if was generated locally - remoteLogger.callAppenders(event); - } - } - } - } catch(java.io.EOFException e) { - logger.info("Caught java.io.EOFException closing conneciton."); - } catch(java.net.SocketException e) { - logger.info("Caught java.net.SocketException closing conneciton."); - } catch(InterruptedIOException e) { - Thread.currentThread().interrupt(); - logger.info("Caught java.io.InterruptedIOException: "+e); - logger.info("Closing connection."); - } catch(IOException e) { - logger.info("Caught java.io.IOException: "+e); - logger.info("Closing connection."); - } catch(Exception e) { - logger.error("Unexpected exception. Closing conneciton.", e); - } finally { - if (ois != null) { - try { - ois.close(); - } catch(Exception e) { - logger.info("Could not close connection.", e); - } - } - if (socket != null) { - try { - socket.close(); - } catch(InterruptedIOException e) { - Thread.currentThread().interrupt(); - } catch(IOException ex) { - } - } - } + LogLog.error(SOCKET_NODE_UNSUPPORTED); } } diff --git a/src/main/java/org/apache/log4j/net/SocketServer.java b/src/main/java/org/apache/log4j/net/SocketServer.java deleted file mode 100644 index fda74adef3..0000000000 --- a/src/main/java/org/apache/log4j/net/SocketServer.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.log4j.net; - -import java.io.File; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.util.Hashtable; - -import org.apache.log4j.Hierarchy; -import org.apache.log4j.Level; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; -import org.apache.log4j.PropertyConfigurator; -import org.apache.log4j.spi.LoggerRepository; -import org.apache.log4j.spi.RootLogger; - - -/** - A {@link SocketNode} based server that uses a different hierarchy - for each client. - -
- Usage: java org.apache.log4j.net.SocketServer port configFile configDir - - where port is a part number where the server listens, - configFile is a configuration file fed to the {@link PropertyConfigurator} and - configDir is a path to a directory containing configuration files, possibly one for each client host. -- -
The configFile
is used to configure the log4j
- default hierarchy that the SocketServer
will use to
- report on its actions.
-
-
When a new connection is opened from a previously unknown
- host, say foo.bar.net
, then the
- SocketServer
will search for a configuration file
- called foo.bar.net.lcf
under the directory
- configDir
that was passed as the third argument. If
- the file can be found, then a new hierarchy is instantiated and
- configured using the configuration file
- foo.bar.net.lcf
. If and when the host
- foo.bar.net
opens another connection to the server,
- then the previously configured hierarchy is used.
-
-
In case there is no file called foo.bar.net.lcf
- under the directory configDir
, then the
- generic hierarchy is used. The generic hierarchy is
- configured using a configuration file called
- generic.lcf
under the configDir
- directory. If no such file exists, then the generic hierarchy will be
- identical to the log4j default hierarchy.
-
-
Having different client hosts log using different hierarchies - ensures the total independence of the clients with respect to - their logging settings. - -
Currently, the hierarchy that will be used for a given request
- depends on the IP address of the client host. For example, two
- separate applications running on the same host and logging to the
- same server will share the same hierarchy. This is perfectly safe
- except that it might not provide the right amount of independence
- between applications. The SocketServer
is intended
- as an example to be enhanced in order to implement more elaborate
- policies.
-
-
- @author Ceki Gülcü
-
- @since 1.0 */
-
-public class SocketServer {
-
- static String GENERIC = "generic";
- static String CONFIG_FILE_EXT = ".lcf";
-
- static Logger cat = Logger.getLogger(SocketServer.class);
- static SocketServer server;
- static int port;
-
- // key=inetAddress, value=hierarchy
- Hashtable hierarchyMap;
- LoggerRepository genericHierarchy;
- File dir;
-
- public
- static
- void main(String argv[]) {
- if(argv.length == 3) {
- init(argv[0], argv[1], argv[2]);
- } else {
- usage("Wrong number of arguments.");
- }
-
- try {
- cat.info("Listening on port " + port);
- ServerSocket serverSocket = new ServerSocket(port);
- while(true) {
- cat.info("Waiting to accept a new client.");
- Socket socket = serverSocket.accept();
- InetAddress inetAddress = socket.getInetAddress();
- cat.info("Connected to client at " + inetAddress);
-
- LoggerRepository h = (LoggerRepository) server.hierarchyMap.get(inetAddress);
- if(h == null) {
- h = server.configureHierarchy(inetAddress);
- }
-
- cat.info("Starting new socket node.");
- new Thread(new SocketNode(socket, h)).start();
- }
- }
- catch(Exception e) {
- e.printStackTrace();
- }
- }
-
-
- static
- void usage(String msg) {
- System.err.println(msg);
- System.err.println(
- "Usage: java " +SocketServer.class.getName() + " port configFile directory");
- System.exit(1);
- }
-
- static
- void init(String portStr, String configFile, String dirStr) {
- try {
- port = Integer.parseInt(portStr);
- }
- catch(java.lang.NumberFormatException e) {
- e.printStackTrace();
- usage("Could not interpret port number ["+ portStr +"].");
- }
-
- PropertyConfigurator.configure(configFile);
-
- File dir = new File(dirStr);
- if(!dir.isDirectory()) {
- usage("["+dirStr+"] is not a directory.");
- }
- server = new SocketServer(dir);
- }
-
-
- public
- SocketServer(File directory) {
- this.dir = directory;
- hierarchyMap = new Hashtable(11);
- }
-
- // This method assumes that there is no hiearchy for inetAddress
- // yet. It will configure one and return it.
- LoggerRepository configureHierarchy(InetAddress inetAddress) {
- cat.info("Locating configuration file for "+inetAddress);
- // We assume that the toSting method of InetAddress returns is in
- // the format hostname/d1.d2.d3.d4 e.g. torino/192.168.1.1
- String s = inetAddress.toString();
- int i = s.indexOf("/");
- if(i == -1) {
- cat.warn("Could not parse the inetAddress ["+inetAddress+
- "]. Using default hierarchy.");
- return genericHierarchy();
- } else {
- String key = s.substring(0, i);
-
- File configFile = new File(dir, key+CONFIG_FILE_EXT);
- if(configFile.exists()) {
- Hierarchy h = new Hierarchy(new RootLogger(Level.DEBUG));
- hierarchyMap.put(inetAddress, h);
-
- new PropertyConfigurator().doConfigure(configFile.getAbsolutePath(), h);
-
- return h;
- } else {
- cat.warn("Could not find config file ["+configFile+"].");
- return genericHierarchy();
- }
- }
- }
-
- LoggerRepository genericHierarchy() {
- if(genericHierarchy == null) {
- File f = new File(dir, GENERIC+CONFIG_FILE_EXT);
- if(f.exists()) {
- genericHierarchy = new Hierarchy(new RootLogger(Level.DEBUG));
- new PropertyConfigurator().doConfigure(f.getAbsolutePath(), genericHierarchy);
- } else {
- cat.warn("Could not find config file ["+f+
- "]. Will use the default hierarchy.");
- genericHierarchy = LogManager.getLoggerRepository();
- }
- }
- return genericHierarchy;
- }
-}
diff --git a/src/main/java/org/apache/log4j/net/SyslogAppender.java b/src/main/java/org/apache/log4j/net/SyslogAppender.java
index b0246453c9..294027df60 100644
--- a/src/main/java/org/apache/log4j/net/SyslogAppender.java
+++ b/src/main/java/org/apache/log4j/net/SyslogAppender.java
@@ -37,6 +37,9 @@
/**
Use SyslogAppender to send log messages to a remote syslog daemon.
+ Since Log4J 1.2.18, will log a warning if the remote syslog daemon
+ is not a local loopback (127.x.x.x or ::1/128).
+
@author Ceki Gülcü
@author Anders Kristensen
*/
diff --git a/src/main/java/org/apache/log4j/net/TelnetAppender.java b/src/main/java/org/apache/log4j/net/TelnetAppender.java
index 5b49a2c92d..b36747ea70 100644
--- a/src/main/java/org/apache/log4j/net/TelnetAppender.java
+++ b/src/main/java/org/apache/log4j/net/TelnetAppender.java
@@ -22,216 +22,83 @@
import org.apache.log4j.spi.LoggingEvent;
import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.InterruptedIOException;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.Vector;
/**
-
The TelnetAppender is a log4j appender that specializes in - writing to a read-only socket. The output is provided in a - telnet-friendly way so that a log can be monitored over TCP/IP. - Clients using telnet connect to the socket and receive log data. - This is handy for remote monitoring, especially when monitoring a - servlet. - -
Here is a list of the available configuration options: - -
Name | -Requirement | -Description | -Sample Value | -
---|---|---|---|
Port | -optional | -This parameter determines the port to use for announcing log events. The default port is 23 (telnet). | -5875 | -
This method of triggering roll over has the advantage of being - operating system independent, fast and reliable. - -
A simple application {@link Roller} is provided to initiate the - roll over. - -
Note that the initiator is not authenticated. Anyone can trigger
- a rollover. In production environments, it is recommended that you
- add some form of protection to prevent undesired rollovers.
+ Port property for a "RollOver" message in Log4j up to 1.2.17.
+ Changed in 1.2.18+ to complain about its use and act as a regular
+ FileAppender otherwise. This may mean your files stop rolling over
+ if you keep using this class! See
+ the log4j 1.2 homepage
+ for more information on why this class is disabled since 1.2.18.
@author Ceki Gülcü
- @since version 0.9.0 */
+ @since version 0.9.0
+ @noinspection unused
+*/
public class ExternallyRolledFileAppender extends RollingFileAppender {
-
- /**
- The string constant sent to initiate a roll over. Current value of
- this string constant is RollOver.
- */
+ static final String EXTERNAL_ROLLING_UNSUPPORTED =
+ "ERROR-LOG4J-NETWORKING-UNSUPPORTED: External Rolled File Appender unsupported!" +
+ " This is a breaking change in Log4J 1 >=1.2.18. Change your config to stop using it!";
static final public String ROLL_OVER = "RollOver";
-
- /**
- The string constant sent to acknowledge a roll over. Current value of
- this string constant is OK.
- */
static final public String OK = "OK";
- int port = 0;
- HUP hup;
-
- /**
- The default constructor does nothing but calls its super-class
- constructor. */
public
ExternallyRolledFileAppender() {
+ super();
+ LogLog.error(EXTERNAL_ROLLING_UNSUPPORTED);
}
- /**
- The Port [roperty is used for setting the port for
- listening to external roll over messages.
- */
public
void setPort(int port) {
- this.port = port;
}
- /**
- Returns value of the Port option.
- */
public
int getPort() {
- return port;
+ return 0;
}
/**
@@ -94,96 +62,5 @@ int getPort() {
public
void activateOptions() {
super.activateOptions();
- if(port != 0) {
- if(hup != null) {
- hup.interrupt();
- }
- hup = new HUP(this, port);
- hup.setDaemon(true);
- hup.start();
- }
- }
-}
-
-
-class HUP extends Thread {
-
- int port;
- ExternallyRolledFileAppender er;
-
- HUP(ExternallyRolledFileAppender er, int port) {
- this.er = er;
- this.port = port;
- }
-
- public
- void run() {
- while(!isInterrupted()) {
- try {
- ServerSocket serverSocket = new ServerSocket(port);
- while(true) {
- Socket socket = serverSocket.accept();
- LogLog.debug("Connected to client at " + socket.getInetAddress());
- new Thread(new HUPNode(socket, er), "ExternallyRolledFileAppender-HUP").start();
- }
- } catch(InterruptedIOException e) {
- Thread.currentThread().interrupt();
- e.printStackTrace();
- } catch(IOException e) {
- e.printStackTrace();
- } catch(RuntimeException e) {
- e.printStackTrace();
- }
- }
}
}
-
-class HUPNode implements Runnable {
-
- Socket socket;
- DataInputStream dis;
- DataOutputStream dos;
- ExternallyRolledFileAppender er;
-
- public
- HUPNode(Socket socket, ExternallyRolledFileAppender er) {
- this.socket = socket;
- this.er = er;
- try {
- dis = new DataInputStream(socket.getInputStream());
- dos = new DataOutputStream(socket.getOutputStream());
- } catch(InterruptedIOException e) {
- Thread.currentThread().interrupt();
- e.printStackTrace();
- } catch(IOException e) {
- e.printStackTrace();
- } catch(RuntimeException e) {
- e.printStackTrace();
- }
- }
-
- public void run() {
- try {
- String line = dis.readUTF();
- LogLog.debug("Got external roll over signal.");
- if(ExternallyRolledFileAppender.ROLL_OVER.equals(line)) {
- synchronized(er) {
- er.rollOver();
- }
- dos.writeUTF(ExternallyRolledFileAppender.OK);
- }
- else {
- dos.writeUTF("Expecting [RollOver] string.");
- }
- dos.close();
- } catch(InterruptedIOException e) {
- Thread.currentThread().interrupt();
- LogLog.error("Unexpected exception. Exiting HUPNode.", e);
- } catch(IOException e) {
- LogLog.error("Unexpected exception. Exiting HUPNode.", e);
- } catch(RuntimeException e) {
- LogLog.error("Unexpected exception. Exiting HUPNode.", e);
- }
- }
-}
-
diff --git a/src/main/resources/META-INF/LICENSE b/src/main/resources/META-INF/LICENSE
deleted file mode 100644
index 6279e5206d..0000000000
--- a/src/main/resources/META-INF/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright 1999-2005 The Apache Software Foundation
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/src/main/resources/META-INF/NOTICE b/src/main/resources/META-INF/NOTICE
deleted file mode 100644
index 0375732360..0000000000
--- a/src/main/resources/META-INF/NOTICE
+++ /dev/null
@@ -1,5 +0,0 @@
-Apache log4j
-Copyright 2007 The Apache Software Foundation
-
-This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
\ No newline at end of file
diff --git a/src/site/apt/index.apt b/src/site/apt/index.apt
index d06334d105..4421f69cc5 100644
--- a/src/site/apt/index.apt
+++ b/src/site/apt/index.apt
@@ -13,85 +13,47 @@
~~ See the License for the specific language governing permissions and
~~ limitations under the License.
-Apache log4j\u2122 1.2
-
- Welcome to Apache log4j, a logging library for Java. Apache log4j
- is an Apache Software Foundation Project and developed by a dedicated
- team of Committers of the Apache Software Foundation.
- For more info, please see {{{http://www.apache.org}The Apache Software Foundation}}.
- Apache log4j is also part of a project which is known as {{{http://logging.apache.org}Apache Logging}}.
- Please see the {{{/license.html}License}}.
-
- If you are interested in the recent changes, visit our {{{/changes-report.html}changes report}}.
-
-* Why logging?
+Security Vulnerabilities
- Inserting log statements into your code is a low-tech method
- for debugging it. It may also be the only way because
- debuggers are not always available or applicable. This is
- often the case for distributed applications.
+ Several security vulnerabilities have been identified in Log4J 1 up to
+ and including 1.2.17. All users should upgrade to Log4J 2. For users that
+ cannot upgrade, certain fixes are made available in a new security fix
+ release 1.2.18:
- On the other hand, some people argue that log statements
- pollute source code and decrease legibility. (We believe that
- the contrary is true). In the Java language where a
- preprocessor is not available, log statements increase the
- size of the code and reduce its speed, even when logging is
- turned off. Given that a reasonably sized application may
- contain thousands of log statements, speed is of particular
- importance.
+ * {{{https://www.cvedetails.com/cve/CVE-2019-17571/}CVE-2019-17571}}. Log4J 1.2.17 includes an insecure SocketServer. It has been removed from Log4J 1.2.18.
-* Why log4j?
+ * {{{https://www.cvedetails.com/cve/CVE-2019-17571/}CVE-2020-9488}}. Log4J 1.2.17 includes a potentially insecure SMTPAppender. This is *not* fixed in Log4J 1.2.18, but it now warns against certain insecure configurations. SMTPAppender has not been fully disabled because usage with a local loopback SMTP server may be safe enough for you depending on your application.
- With log4j it is possible to enable logging at runtime
- without modifying the application binary. The log4j package is
- designed so that these statements can remain in shipped code
- without incurring a heavy performance cost. Logging behavior
- can be controlled by editing a configuration file, without
- touching the application binary.
+ * {{{https://www.cvedetails.com/cve/CVE-2019-17571/}CVE-2021-4104}}. Log4J 1.2.17 includes an insecure JMSAppender. It has been disabled in Log4J 1.2.18. The related JMSSink has been removed.
- Logging equips the developer with detailed context for
- application failures. On the other hand, testing provides
- quality assurance and confidence in the application. Logging
- and testing should not be confused. They are
- complementary. When logging is wisely used, it can prove to be
- an essential tool.
+ * (no CVE). Log4J 1.2.17 includes a potentially insecure JDBCAppender. It has been disabled in Log4J 1.2.18.
- One of the distinctive features of log4j is the notion of
- inheritance in loggers. Using a logger
- hierarchy it is possible to control which log
- statements are output at arbitrarily fine granularity but also
- great ease. This helps to reduce the volume of logged output and
- the cost of logging.
+ * (no CVE). Log4J 1.2.17 includes an ExternalRollingFileAppender that listens on an unencrypted socket for RollOver messages. It's networking functionality has been removed in Log4J 1.2.18. This also means it will no longer roll over files, so consider switching to DailyRollingFileAppender.
- The target of the log output can be a file, an
- OutputStream, a java.io.Writer, a
- remote log4j server, a remote Unix Syslog daemon, or many other output targets.
-* Performance
+ Please note Log4J 1 remains End Of Life. It could contain other vulnerabilities.
+ There is no support provided for Log4J 1, and all users should upgrade to Log4J 2.
- On an AMD Duron clocked at 800Mhz running JDK 1.3.1, it costs
- about 5 nanoseconds to determine if a logging statement should
- be logged or not. Actual logging is also quite fast, ranging
- from 21 microseconds using the SimpleLayout, 37
- microseconds using the TTCCLayout. The performance of the
- PatternLayout is almost as good as the dedicated layouts,
- except that it is much more flexible.
+Bug fixes
-* Roadmap
+ Several other bugfixes have been made. In particular, the version
+ detection algorithm in Log4J 1.2.17 that caused MDC not to work with
+ Java 9 or higher (see
+ {{{https://blogs.apache.org/logging/entry/moving_on_to_log4j_2}Log4j 1.2 is broken on Java 9}})
+ has been removed.
- The package is being constantly improved thanks to input from
- users and code contributed by authors in the community.
+ Log4J 1.2.18 may work for you in Java 1.4 up to and including Java 17.
- Please note, the team is currently working on log4j 2 which will replace
- log4j 1 in near future.
+ Please note Log4J 1 remains End Of Life. It contains other known bugs.
+ There is no support provided for Log4J 1, and all users should upgrade to Log4J 2.
-* Get involved
-
- We are glad about help! Please make sure you have read the
- {{{http://www.apache.org/foundation/getinvolved.html}Get Involved}} document.
- Then join the {{{http://logging.apache.org/log4j/1.2/mail-lists.html}dev mailinglist}}
- and fix issues from {{{https://issues.apache.org/bugzilla/describecomponents.cgi?product=Log4j}Bugzilla}}.
+Apache log4j\u2122 1.2
- You can obtain the code via {{{source-repository.html}SVN}} or our {{{http://git.apache.org/log4j.git/}Git mirror}}.
+ Apache log4j 1.2 is a really old logging library for Java. Apache log4j
+ is an Apache Software Foundation Project.
+ The new version 2 is developed by a dedicated team of Committers of the Apache Software Foundation.
+ For more info, please see {{{http://www.apache.org}The Apache Software Foundation}}.
+ Apache log4j is also part of a project which is known as {{{http://logging.apache.org}Apache Logging}}.
+ Please see the {{{/license.html}License}}.
diff --git a/src/site/apt/roadmap.apt b/src/site/apt/roadmap.apt
deleted file mode 100644
index 13c60d435c..0000000000
--- a/src/site/apt/roadmap.apt
+++ /dev/null
@@ -1,22 +0,0 @@
-~~ Licensed to the Apache Software Foundation (ASF) under one or more
-~~ contributor license agreements. See the NOTICE file distributed with
-~~ this work for additional information regarding copyright ownership.
-~~ The ASF licenses this file to You under the Apache License, Version 2.0
-~~ (the "License"); you may not use this file except in compliance with
-~~ the License. You may obtain a copy of the License at
-~~
-~~ http://www.apache.org/licenses/LICENSE-2.0
-~~
-~~ Unless required by applicable law or agreed to in writing, software
-~~ distributed under the License is distributed on an "AS IS" BASIS,
-~~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-~~ See the License for the specific language governing permissions and
-~~ limitations under the License.
-
-Apache log4j 1.2 Roadmap
-
- Apache log4j 1.2 is mature and widely deployed. Significant
- changes are unlikely. Bug fixes and maintenance releases are not anticipated.
-
- The current version is {{{http://logging.apache.org/log4j/2.0/index.html}Apache log4j 2}}
-
diff --git a/src/site/default-site-macros.vm b/src/site/default-site-macros.vm
new file mode 100644
index 0000000000..20eb354e29
--- /dev/null
+++ b/src/site/default-site-macros.vm
@@ -0,0 +1,494 @@
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements. See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership. The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License. You may obtain a copy of the License at
+##
+## http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied. See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+#macro ( link $href $name $target $img $position $alt $border $width $height $title )
+#**##set ( $linkTitle = ' title="' + $name + '"' )
+#**##if( $target )
+#* *##set ( $linkTarget = ' target="' + $target + '"' )
+#**##else
+#* *##set ( $linkTarget = "" )
+#**##end
+#**##if ( $decoration.isLink( $href ) )
+#* *##set ( $linkClass = ' class="externalLink"' )
+#**##else
+#* *##set ( $linkClass = "" )
+#**##end
+#**##if ( $img )
+#* *##if ( $position == "left" )
+#* *##image($img $alt $border $width $height $title)$name##
+#* *##else
+#* *#$name #image($img $alt $border $width $height $title)##
+#* *##end
+#**##else
+#* *#$name##
+#**##end
+#end
+##
+#macro ( image $img $alt $border $width $height $title )
+#**##if( $img )
+#* *##if ( !$decoration.isLink( $img ) )
+#* *##set ( $imgSrc = $PathTool.calculateLink( $img, $relativePath ) )
+#* *##set ( $imgSrc = $imgSrc.replaceAll( '\\', '/' ) )
+#* *##set ( $imgSrc = ' src="' + $imgSrc + '"' )
+#* *##else
+#* *##set ( $imgSrc = ' src="' + $img + '"' )
+#* *##end
+#* *##if( $alt )
+#* *##set ( $imgAlt = ' alt="' + $alt + '"' )
+#* *##else
+#* *##set ( $imgAlt = ' alt=""' )
+#* *##end
+#* *##if( $border )
+#* *##set ( $imgBorder = ' border="' + $border + '"' )
+#* *##else
+#* *##set ( $imgBorder = "" )
+#* *##end
+#* *##if( $width )
+#* *##set ( $imgWidth = ' width="' + $width + '"' )
+#* *##else
+#* *##set ( $imgWidth = "" )
+#* *##end
+#* *##if( $height )
+#* *##set ( $imgHeight = ' height="' + $height + '"' )
+#* *##else
+#* *##set ( $imgHeight = "" )
+#* *##end
+#* *##if( $title )
+#* *##set ( $imgTitle = ' title="' + $title + '"' )
+#* *##else
+#* *##set ( $imgTitle = "" )
+#* *##end
+#* *###
+#**##end
+#end
+##
+#macro ( banner $banner $id )
+#**##if ( $banner )
+#* *##if( $banner.href )
+#* *##set ( $hrf = $banner.href )
+#* *##if ( !$decoration.isLink( $hrf ) )
+#* *##set ( $hrf = $PathTool.calculateLink( $hrf, $relativePath ) )
+#* *##set ( $hrf = $hrf.replaceAll( '\\', '/' ) )
+#* *##if ( ( $hrf == '' ) )
+#* *##set ( $hrf = './' )
+#* *##end
+#* *##end
+#* *###
+#* *##else
+#* *#
##
+#* *##else
+#* *#$banner.name
+#* *##end
+##
+#* *##if( $banner.href )
+#* *###
+#* *##else
+#* *#
On August 5, 2015 the Logging Services Project + Management Committee announced that Log4j 1.x had reached end of life. + For complete text of the announcement please see the + Apache Blog. + Users of Log4j 1 are recommended to upgrade to + Apache Log4j 2.
+#* *#$bodyContent +-$> sudo apt-get install maven2 subversion mingw32 xemacs21 openssh-server +$> sudo apt-get install maven3 git mingw32 xemacs21 openssh-server-
-c:\>cd "\Program Files\Java\jdk_1.6.0_16\include\win32 -c:\>scp jni_md.h username@hostname: - -$> export JNI_WIN32_INCLUDE_DIR=/home/username -- -
Create a local ssh key with no passphrase to enable "deployment" of site back to the local machine using scp.
@@ -107,12 +98,14 @@ $ ssh -l USERNAME people.apache.org $ ssh localhost -Before you build, please make sure you have a nonblocking editor set as SVN editor. Like:
+Instructions not tested for Log4J 1.2.18. The switch to Maven 3 and git probably mean changes. Make sure to check the INSTALL file at https://github.com/apache/log4j/blob/trunk/INSTALL
+ +Before you build, please make sure you have a nonblocking editor set as GIT editor. Like:
-$ export SVN_EDITOR=xemacs +$ export GIT_EDITOR=xemacs
Other checks:
@@ -122,16 +115,17 @@ $ export SVN_EDITOR=xemacs to the date the release candidate is created.The release artifacts were originally built by:
+ +Untested: the release artifacts might be buildable with:
-$> svn co http://svn.apache.org/repos/asf/logging/log4j/trunk log4j +$> git clone git@github.com:apache/log4j.git $> cd log4j $> mvn package release:prepare $> mvn release:perform-
Note: you'll be ask for a SVN tagname. Please use the following pattern: v1.2.17-RC1.
+Note: you'll be ask for a git tagname. Please use the following pattern: v1.2.17-RC1.
Attention: this is an non-interactive build. In some cases it is necessary @@ -140,11 +134,7 @@ to the release plugin commands. This is surely not safe because your password can be seen clearly.
-Sometimes iz might be necessary to disable keystore on Ubuntu machines when the automatic svn commit fails. To do this, add the following line to .subversion/config in your [auth] section:
- -password-stores =- -
The release artifacts can be rebuilt by:
+Outdated: The release artifacts can be rebuilt by:
$ mvn release:perform -DconnectionUrl=scm:svn:https://svn.apache.org/repos/asf/logging/log4j/tags/v1_2_16 @@ -172,7 +162,7 @@ $ mvn release:perform -DconnectionUrl=scm:svn:https://svn.apache.org/repos/asf/l-
Building site and artifacts from a tag:
+Outdated: building site and artifacts from a tag:
$ svn co https://svn.apache.org/repos/asf/logging/log4j/tags/v1_2_16 @@ -199,7 +189,7 @@ The staged version can be published to the main public site by executing "svn update" in /www/logging.apache.org/log4j/1.2 on people.apache.org. -If a vote has failed
+Outdated: If a vote has failed
http://people.apache.org/builds/logging/repo/log4j/log4j/
If a RC has passed the vote, these steps are necessary:
@@ -224,4 +214,4 @@ $> svn mv https://svn.apache.org/repos/asf/logging/log4j/tags/log4j-1.2.17-RC1 h