Index: core/pom.xml IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/pom.xml (revision 1448517) +++ core/pom.xml (revision ) @@ -59,6 +59,12 @@ true + javax.jmdns + jmdns + 3.4.1 + test + + oro oro test Index: core/src/main/java/org/apache/logging/log4j/core/layout/RFC5424Layout.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/layout/RFC5424Layout.java (revision 1448517) +++ core/src/main/java/org/apache/logging/log4j/core/layout/RFC5424Layout.java (revision ) @@ -16,6 +16,7 @@ */ package org.apache.logging.log4j.core.layout; +import java.util.HashMap; import org.apache.logging.log4j.LoggingException; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.Configuration; @@ -182,6 +183,20 @@ parser = (PatternParser) config.getComponent(COMPONENT_KEY); } return parser; + } + + /** + * RFC5424Layout's content format is specified by:

+ * Key: "structured" Value: "true"

+ * Key: "format" Value: "RFC5424"

+ * @return Map of content format keys supporting RFC5424Layout + */ + public Map getContentFormat() + { + Map result = new HashMap(); + result.put("structured", "true"); + result.put("formatType", "RFC5424"); + return result; } /** Index: core/src/main/java/org/apache/logging/log4j/core/layout/SyslogLayout.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/layout/SyslogLayout.java (revision 1448517) +++ core/src/main/java/org/apache/logging/log4j/core/layout/SyslogLayout.java (revision ) @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j.core.layout; +import java.util.HashMap; +import java.util.Map; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.plugins.Plugin; import org.apache.logging.log4j.core.config.plugins.PluginAttr; @@ -67,7 +69,7 @@ } /** - * Formats a {@link org.apache.logging.log4j.core.LogEvent} in conformance with the log4j.dtd. + * Formats a {@link org.apache.logging.log4j.core.LogEvent} in conformance with the BSD Log record format. * * @param event The LogEvent * @return the event formatted as a String. @@ -119,6 +121,24 @@ if (buf.charAt(index) == '0') { buf.setCharAt(index, ' '); } + } + + /** + * SyslogLayout's content format is specified by:

+ * Key: "structured" Value: "false"

+ * Key: "dateFormat" Value: "MMM dd HH:mm:ss "

+ * Key: "format" Value: "TIMESTAMP PROP(HOSTNAME) MESSAGE"

+ * Key: "formatType" Value: "logfilepatternreceiver" (format uses the keywords supported by LogFilePatternReceiver) + * @return Map of content format keys supporting SyslogLayout + */ + public Map getContentFormat() + { + Map result = new HashMap(); + result.put("structured", "false"); + result.put("formatType", "logfilepatternreceiver"); + result.put("dateFormat", dateFormat.toPattern()); + result.put("format", "TIMESTAMP PROP(HOSTNAME) MESSAGE"); + return result; } /** Index: core/src/main/java/org/apache/logging/log4j/core/config/BaseConfiguration.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/config/BaseConfiguration.java (revision 1448517) +++ core/src/main/java/org/apache/logging/log4j/core/config/BaseConfiguration.java (revision ) @@ -38,6 +38,7 @@ import org.apache.logging.log4j.core.lookup.MapLookup; import org.apache.logging.log4j.core.lookup.StrLookup; import org.apache.logging.log4j.core.lookup.StrSubstitutor; +import org.apache.logging.log4j.core.net.Advertiser; import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.PropertiesUtil; @@ -83,6 +84,8 @@ */ protected ConfigurationMonitor monitor = new DefaultConfigurationMonitor(); + protected Advertiser advertiser = new DefaultAdvertiser(); + private String name; private ConcurrentMap> appenders = new ConcurrentHashMap>(); @@ -303,6 +306,10 @@ public ConfigurationMonitor getConfigurationMonitor() { return monitor; + } + + public Advertiser getAdvertiser() { + return advertiser; } /** Index: core/src/test/resources/log4j-socket.xml IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/test/resources/log4j-socket.xml (revision 1448517) +++ core/src/test/resources/log4j-socket.xml (revision ) @@ -1,7 +1,7 @@ - \ No newline at end of file Index: core/src/test/java/org/apache/logging/log4j/core/appender/FileAppenderTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/test/java/org/apache/logging/log4j/core/appender/FileAppenderTest.java (revision 1448517) +++ core/src/test/java/org/apache/logging/log4j/core/appender/FileAppenderTest.java (revision ) @@ -18,6 +18,7 @@ import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.config.DefaultConfiguration; import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.layout.PatternLayout; @@ -141,7 +142,7 @@ private static void writer(final boolean lock, final int count, final String name) throws Exception { final Layout layout = PatternLayout.createLayout(PatternLayout.SIMPLE_CONVERSION_PATTERN, null, null, null); final FileAppender app = FileAppender.createAppender(FILENAME, "true", Boolean.toString(lock), "test", "false", - "false", "false", layout, null); + "false", "false", layout, null, "false", null, null); final Thread t = Thread.currentThread(); app.start(); assertTrue("Appender did not start", app.isStarted()); Index: core/src/main/java/org/apache/logging/log4j/core/Layout.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/Layout.java (revision 1448517) +++ core/src/main/java/org/apache/logging/log4j/core/Layout.java (revision ) @@ -17,6 +17,7 @@ package org.apache.logging.log4j.core; import java.io.Serializable; +import java.util.Map; /** * Lays out a {@linkplain LogEvent} in different formats. @@ -83,4 +84,12 @@ * @return the content type. */ String getContentType(); + + /** + * Returns a description of the content format. + * + * @return a Map of key/value pairs describing the Layout-specific content format, or an empty Map if no content format descriptors are specified. + * + */ + Map getContentFormat(); } Index: core/src/main/java/org/apache/logging/log4j/core/appender/AbstractManager.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/appender/AbstractManager.java (revision 1448517) +++ core/src/main/java/org/apache/logging/log4j/core/appender/AbstractManager.java (revision ) @@ -129,4 +129,14 @@ public String getName() { return name; } + + /** + * Provide a description of the content format supported by this Manager. Default implementation returns an empty (unspecified) Map. + * + * @return a Map of key/value pairs describing the Manager-specific content format, or an empty Map if no content format descriptors are specified. + * + */ + public Map getContentFormat() { + return new HashMap(); + } } Index: core/src/main/java/org/apache/logging/log4j/core/net/TCPSocketManager.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/net/TCPSocketManager.java (revision 1448517) +++ core/src/main/java/org/apache/logging/log4j/core/net/TCPSocketManager.java (revision ) @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j.core.net; +import java.util.HashMap; +import java.util.Map; import org.apache.logging.log4j.core.appender.AppenderRuntimeException; import org.apache.logging.log4j.core.appender.ManagerFactory; import org.apache.logging.log4j.core.appender.OutputStreamManager; @@ -132,6 +134,19 @@ } /** + * TCPSocketManager's content format is specified by:

+ * Key: "protocol" Value: "tcp" + * @return Map of content format keys supporting TCPSocketManager + */ + public Map getContentFormat() + { + Map result = new HashMap(super.getContentFormat()); + result.put("protocol", "tcp"); + return result; + } + + + /** * Handles recoonecting to a Thread. */ private class Reconnector extends Thread { @@ -214,7 +229,7 @@ public TCPSocketManager createManager(final String name, final FactoryData data) { InetAddress address; - OutputStream os = null; + OutputStream os; try { address = InetAddress.getByName(data.host); } catch (final UnknownHostException ex) { Index: core/src/test/java/org/apache/logging/log4j/core/appender/SyslogAppenderTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/test/java/org/apache/logging/log4j/core/appender/SyslogAppenderTest.java (revision 1448517) +++ core/src/test/java/org/apache/logging/log4j/core/appender/SyslogAppenderTest.java (revision ) @@ -212,7 +212,7 @@ private SyslogAppender createAppender(final String protocol, final String format) { return SyslogAppender.createAppender("localhost", PORT, protocol, "-1", "Test", "true", "false", "LOCAL0", "Audit", "18060", "true", "RequestContext", "true", null, "TestApp", "Test", null, "ipAddress,loginId", null, format, null, - null, null, null); + null, null, null, null); } public static class UDPSocketServer extends Thread { Index: core/src/main/java/org/apache/logging/log4j/core/net/AbstractSocketManager.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/net/AbstractSocketManager.java (revision 1448517) +++ core/src/main/java/org/apache/logging/log4j/core/net/AbstractSocketManager.java (revision ) @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j.core.net; +import java.util.HashMap; +import java.util.Map; import org.apache.logging.log4j.core.appender.OutputStreamManager; import java.io.OutputStream; @@ -55,4 +57,18 @@ this.port = port; } + /** + * AbstractSocketManager's content format is specified by:

+ * Key: "port" Value: provided "port" param

+ * Key: "address" Value: provided "address" param + * @return Map of content format keys supporting AbstractSocketManager + */ + public Map getContentFormat() + { + Map result = new HashMap(super.getContentFormat()); + result.put("port", Integer.toString(port)); + result.put("address", address.getHostAddress()); + + return result; + } } Index: core/src/main/java/org/apache/logging/log4j/core/appender/FileAppender.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/appender/FileAppender.java (revision 1448517) +++ core/src/main/java/org/apache/logging/log4j/core/appender/FileAppender.java (revision ) @@ -16,13 +16,15 @@ */ package org.apache.logging.log4j.core.appender; +import java.util.HashMap; +import java.util.Map; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; -import org.apache.logging.log4j.core.config.plugins.Plugin; -import org.apache.logging.log4j.core.config.plugins.PluginAttr; -import org.apache.logging.log4j.core.config.plugins.PluginElement; -import org.apache.logging.log4j.core.config.plugins.PluginFactory; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.plugins.*; import org.apache.logging.log4j.core.layout.PatternLayout; +import org.apache.logging.log4j.core.net.Advertiser; +import org.apache.logging.log4j.core.net.ZeroConfSupport; /** * File Appender. @@ -33,8 +35,16 @@ private final String fileName; private FileAppender(final String name, final Layout layout, final Filter filter, final FileManager manager, - final String filename, final boolean handleException, final boolean immediateFlush) { + final String filename, final boolean handleException, final boolean immediateFlush, Advertiser advertiser) { super(name, layout, filter, handleException, immediateFlush, manager); + if (advertiser != null) + { + Map configuration = new HashMap(layout.getContentFormat()); + configuration.putAll(manager.getContentFormat()); + configuration.put("contentType", layout.getContentType()); + configuration.put("name", name); + advertiser.advertise(configuration); + } this.fileName = filename; } @@ -72,14 +82,18 @@ @PluginAttr("suppressExceptions") final String suppress, @PluginAttr("bufferedIO") final String bufferedIO, @PluginElement("layout") Layout layout, - @PluginElement("filters") final Filter filter) { + @PluginElement("filters") final Filter filter, + @PluginAttr("advertise") final String advertise, + @PluginAttr("advertiseURI") final String advertiseURI, + @PluginConfiguration final Configuration config) { final boolean isAppend = append == null ? true : Boolean.valueOf(append); final boolean isLocking = locking == null ? false : Boolean.valueOf(locking); boolean isBuffered = bufferedIO == null ? true : Boolean.valueOf(bufferedIO); + boolean isAdvertise = advertise == null ? false : Boolean.valueOf(advertise); if (isLocking && isBuffered) { if (bufferedIO != null) { - LOGGER.warn("Locking and buffering are mutually exclusive. No buffereing will occur for " + fileName); + LOGGER.warn("Locking and buffering are mutually exclusive. No buffering will occur for " + fileName); } isBuffered = false; } @@ -96,13 +110,14 @@ return null; } - final FileManager manager = FileManager.getFileManager(fileName, isAppend, isLocking, isBuffered); + final FileManager manager = FileManager.getFileManager(fileName, isAppend, isLocking, isBuffered, advertiseURI); if (manager == null) { return null; } if (layout == null) { layout = PatternLayout.createLayout(null, null, null, null); } - return new FileAppender(name, layout, filter, manager, fileName, handleExceptions, isFlush); + + return new FileAppender(name, layout, filter, manager, fileName, handleExceptions, isFlush, isAdvertise ? config.getAdvertiser() : null); } } Index: core/src/main/java/org/apache/logging/log4j/core/appender/FileManager.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/appender/FileManager.java (revision 1448517) +++ core/src/main/java/org/apache/logging/log4j/core/appender/FileManager.java (revision ) @@ -24,6 +24,8 @@ import java.io.OutputStream; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; +import java.util.HashMap; +import java.util.Map; /** @@ -35,11 +37,13 @@ private final boolean isAppend; private final boolean isLocking; + private final String advertiseURI; - protected FileManager(final String fileName, final OutputStream os, final boolean append, final boolean locking) { + protected FileManager(final String fileName, final OutputStream os, final boolean append, final boolean locking, String advertiseURI) { super(os, fileName); this.isAppend = append; this.isLocking = locking; + this.advertiseURI = advertiseURI; } /** @@ -48,15 +52,16 @@ * @param append true if the file should be appended to, false if it should be overwritten. * @param locking true if the file should be locked while writing, false otherwise. * @param bufferedIO true if the contents should be buffered as they are written. + * @param advertiseURI the URI to use when advertising the file via MulticastDNS * @return A FileManager for the File. */ public static FileManager getFileManager(final String fileName, final boolean append, boolean locking, - final boolean bufferedIO) { + final boolean bufferedIO, String advertiseURI) { if (locking && bufferedIO) { locking = false; } - return (FileManager) getManager(fileName, new FactoryData(append, locking, bufferedIO), FACTORY); + return (FileManager) getManager(fileName, new FactoryData(append, locking, bufferedIO, advertiseURI), FACTORY); } @Override @@ -112,23 +117,38 @@ } /** + * FileManager's content format is specified by:

+ * Key: "fileURI" Value: provided "advertiseURI" param + * @return Map of content format keys supporting FileManager + */ + public Map getContentFormat() + { + Map result = new HashMap(super.getContentFormat()); + result.put("fileURI", advertiseURI); + return result; + } + + /** * Factory Data. */ private static class FactoryData { private final boolean append; private final boolean locking; private final boolean bufferedIO; + private final String advertiseURI; /** * Constructor. * @param append Append status. * @param locking Locking status. * @param bufferedIO Buffering flag. + * @param advertiseURI the URI to use when advertising via MulticastDNS */ - public FactoryData(final boolean append, final boolean locking, final boolean bufferedIO) { + public FactoryData(final boolean append, final boolean locking, final boolean bufferedIO, String advertiseURI) { this.append = append; this.locking = locking; this.bufferedIO = bufferedIO; + this.advertiseURI = advertiseURI; } } @@ -156,7 +176,7 @@ if (data.bufferedIO) { os = new BufferedOutputStream(os); } - return new FileManager(name, os, data.append, data.locking); + return new FileManager(name, os, data.append, data.locking, data.advertiseURI); } catch (final FileNotFoundException ex) { LOGGER.error("FileManager (" + name + ") " + ex); } Index: core/src/test/java/org/apache/logging/log4j/core/net/SocketServerTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/test/java/org/apache/logging/log4j/core/net/SocketServerTest.java (revision 1448517) +++ core/src/test/java/org/apache/logging/log4j/core/net/SocketServerTest.java (revision ) @@ -24,6 +24,9 @@ import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.core.appender.ConsoleAppender; +import org.apache.logging.log4j.core.appender.FileAppender; +import org.apache.logging.log4j.core.config.DefaultConfiguration; +import org.apache.logging.log4j.core.layout.XMLLayout; import org.apache.logging.log4j.test.appender.ListAppender; import org.apache.logging.log4j.core.appender.SocketAppender; import org.apache.logging.log4j.core.filter.AbstractFilter; @@ -33,6 +36,8 @@ import org.junit.BeforeClass; import org.junit.Test; +import java.io.File; +import java.net.InetAddress; import java.util.List; import java.util.Map; import java.util.concurrent.ArrayBlockingQueue; @@ -92,8 +97,18 @@ final Filter socketFilter = new ThreadFilter(Filter.Result.NEUTRAL, Filter.Result.DENY); final Filter serverFilter = new ThreadFilter(Filter.Result.DENY, Filter.Result.NEUTRAL); final SocketAppender appender = SocketAppender.createAppender("localhost", PORT, "tcp", "-1", - "Test", null, null, null, socketFilter); + "tcp socket appender", null, null, "true", null, socketFilter, new DefaultConfiguration()); appender.start(); + final FileAppender fileAppender = FileAppender.createAppender("/Users/admin/log4j2log.txt", "true", "false", "file appender name", + "false", "false", "false", PatternLayout.createLayout("%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %m%n", + null, null, null), null, "true", new File("/Users/admin/log4j2log.txt").toURI().toString(), new DefaultConfiguration()); + + fileAppender.start(); + final SocketAppender udpappender = SocketAppender.createAppender("localhost", "8202", "udp", "-1", + "udp socket appender", "false", "false", "true", XMLLayout.createLayout("true", "true", "true", null), null, new DefaultConfiguration()); + udpappender.start(); + + final ListAppender listApp = new ListAppender("Events", serverFilter, null, false, false); listApp.start(); final PatternLayout layout = PatternLayout.createLayout("%m %ex%n", null, null, null); @@ -104,6 +119,8 @@ // set appender on root and set level to debug root.addAppender(appender); + root.addAppender(fileAppender); + root.addAppender(udpappender); root.addAppender(listApp); root.setAdditive(false); root.setLevel(Level.DEBUG); Index: core/src/main/java/org/apache/logging/log4j/core/net/ZeroConfSupport.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/net/ZeroConfSupport.java (revision ) +++ core/src/main/java/org/apache/logging/log4j/core/net/ZeroConfSupport.java (revision ) @@ -0,0 +1,232 @@ +/* + * 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.logging.log4j.core.net; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Hashtable; +import java.util.Map; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.status.StatusLogger; + +/** + * Advertise an entity via ZeroConf/MulticastDNS and the JmDNS library. + * + */ +public class ZeroConfSupport implements Advertiser { + protected static final Logger LOGGER = StatusLogger.getLogger(); + private static Object jmDNS = initializeJMDNS(); + + private static Class jmDNSClass; + private static Class serviceInfoClass; + + public ZeroConfSupport() + { + //no arg constructor for reflection + } + + /** + * Advertise the provided entity. + * + * Properties map provided in advertise method must include a "name" entry + * but may also provide "protocol" (tcp/udp) as well as a "port" entry + * + * @param properties the properties representing the entity to advertise + * @return the object which can be used to unadvertise, or null if advertisement was unsuccessful + */ + public Object advertise(Map properties) { + //default to tcp if "protocol" was not set + String protocol = properties.get("protocol"); + String zone = "._log4j._"+(protocol != null ? protocol : "tcp") + ".local."; + //default to 4555 if "port" was not set + String portString = properties.get("port"); + int port = (portString != null ? Integer.parseInt(portString) : 4555); + + String name = properties.get("name"); + + //if version 3 is available, use it to constuct a serviceInfo instance, otherwise support the version1 API + if (jmDNS != null) + { + boolean isVersion3 = false; + try { + //create method is in version 3, not version 1 + jmDNSClass.getMethod("create", (Class[])null); + isVersion3 = true; + } catch (NoSuchMethodException e) { + //no-op + } + System.out.println("building: " + zone); + Object serviceInfo; + if (isVersion3) { + serviceInfo = buildServiceInfoVersion3(zone, port, name, properties); + } else { + serviceInfo = buildServiceInfoVersion1(zone, port, name, properties); + } + + try { + Method method = jmDNSClass.getMethod("registerService", new Class[]{serviceInfoClass}); + method.invoke(jmDNS, serviceInfo); + } catch(IllegalAccessException e) { + LOGGER.warn("Unable to invoke registerService method", e); + } catch(NoSuchMethodException e) { + LOGGER.warn("No registerService method", e); + } catch(InvocationTargetException e) { + LOGGER.warn("Unable to invoke registerService method", e); + } + return serviceInfo; + } + else + { + LOGGER.warn("JMDNS not available - will not advertise ZeroConf support"); + return null; + } + } + + /** + * Unadvertise the previously advertised entity + * @param serviceInfo + */ + public void unadvertise(Object serviceInfo) { + if (jmDNS != null) { + try { + Method method = jmDNSClass.getMethod("unregisterService", new Class[]{serviceInfoClass}); + method.invoke(jmDNS, serviceInfo); + } catch(IllegalAccessException e) { + LOGGER.warn("Unable to invoke unregisterService method", e); + } catch(NoSuchMethodException e) { + LOGGER.warn("No unregisterService method", e); + } catch(InvocationTargetException e) { + LOGGER.warn("Unable to invoke unregisterService method", e); + } + } + } + + private static Object createJmDNSVersion1() + { + try { + return jmDNSClass.newInstance(); + } catch (InstantiationException e) { + LOGGER.warn("Unable to instantiate JMDNS", e); + } catch (IllegalAccessException e) { + LOGGER.warn("Unable to instantiate JMDNS", e); + } + return null; + } + + private static Object createJmDNSVersion3() + { + try { + Method jmDNSCreateMethod = jmDNSClass.getMethod("create", (Class[])null); + return jmDNSCreateMethod.invoke(null, (Object[])null); + } catch (IllegalAccessException e) { + LOGGER.warn("Unable to instantiate jmdns class", e); + } catch (NoSuchMethodException e) { + LOGGER.warn("Unable to access constructor", e); + } catch (InvocationTargetException e) { + LOGGER.warn("Unable to call constructor", e); + } + return null; + } + + private Object buildServiceInfoVersion1(String zone, int port, String name, Map properties) { + //version 1 uses a hashtable + Hashtable hashtableProperties = new Hashtable(properties); + try { + Class[] args = new Class[6]; + args[0] = String.class; + args[1] = String.class; + args[2] = int.class; + args[3] = int.class; //weight (0) + args[4] = int.class; //priority (0) + args[5] = Hashtable.class; + Constructor constructor = serviceInfoClass.getConstructor(args); + Object[] values = new Object[6]; + values[0] = zone; + values[1] = name; + values[2] = port; + values[3] = 0; + values[4] = 0; + values[5] = hashtableProperties; + return constructor.newInstance(values); + } catch (IllegalAccessException e) { + LOGGER.warn("Unable to construct ServiceInfo instance", e); + } catch (NoSuchMethodException e) { + LOGGER.warn("Unable to get ServiceInfo constructor", e); + } catch (InstantiationException e) { + LOGGER.warn("Unable to construct ServiceInfo instance", e); + } catch (InvocationTargetException e) { + LOGGER.warn("Unable to construct ServiceInfo instance", e); + } + return null; + } + + private Object buildServiceInfoVersion3(String zone, int port, String name, Map properties) { + try { + Class[] args = new Class[6]; + args[0] = String.class; //zone/type + args[1] = String.class; //display name + args[2] = int.class; //port + args[3] = int.class; //weight (0) + args[4] = int.class; //priority (0) + args[5] = Map.class; + Method serviceInfoCreateMethod = serviceInfoClass.getMethod("create", args); + Object[] values = new Object[6]; + values[0] = zone; + values[1] = name; + values[2] = port; + values[3] = 0; + values[4] = 0; + values[5] = properties; + return serviceInfoCreateMethod.invoke(null, values); + } catch (IllegalAccessException e) { + LOGGER.warn("Unable to invoke create method", e); + } catch (NoSuchMethodException e) { + LOGGER.warn("Unable to find create method", e); + } catch (InvocationTargetException e) { + LOGGER.warn("Unable to invoke create method", e); + } + return null; + } + + private static Object initializeJMDNS() { + try { + jmDNSClass = Class.forName("javax.jmdns.JmDNS"); + serviceInfoClass = Class.forName("javax.jmdns.ServiceInfo"); + //if version 3 is available, use it to constuct a serviceInfo instance, otherwise support the version1 API + boolean isVersion3 = false; + try { + //create method is in version 3, not version 1 + jmDNSClass.getMethod("create", (Class[])null); + isVersion3 = true; + } catch (NoSuchMethodException e) { + //no-op + } + + if (isVersion3) { + return createJmDNSVersion3(); + } else { + return createJmDNSVersion1(); + } + } catch (ClassNotFoundException e) { + LOGGER.warn("JmDNS or serviceInfo class not found", e); + } catch (ExceptionInInitializerError e2) { + LOGGER.warn("JmDNS or serviceInfo class not found", e2); + } + return null; + } +} Index: core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java (revision 1448517) +++ core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java (revision ) @@ -22,6 +22,7 @@ import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.filter.Filterable; import org.apache.logging.log4j.core.lookup.StrSubstitutor; +import org.apache.logging.log4j.core.net.Advertiser; import java.util.Map; @@ -80,4 +81,6 @@ void addComponent(String name, Object object); ConfigurationMonitor getConfigurationMonitor(); + + Advertiser getAdvertiser(); } Index: core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfiguration.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfiguration.java (revision 1448517) +++ core/src/main/java/org/apache/logging/log4j/core/config/DefaultConfiguration.java (revision ) @@ -21,6 +21,7 @@ import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.appender.ConsoleAppender; import org.apache.logging.log4j.core.layout.PatternLayout; +import org.apache.logging.log4j.core.net.Advertiser; import org.apache.logging.log4j.util.PropertiesUtil; /** @@ -59,6 +60,16 @@ final Level level = levelName != null && Level.valueOf(levelName) != null ? Level.valueOf(levelName) : Level.ERROR; root.setLevel(level); + + try { + advertiser = (Advertiser) Class.forName("org.apache.logging.log4j.core.net.ZeroConfSupport").newInstance(); + } catch (InstantiationException e) { + //ignore + } catch (IllegalAccessException e) { + //ignore + } catch (ClassNotFoundException e) { + //ignore + } } @Override Index: core/src/main/java/org/apache/logging/log4j/core/net/DatagramSocketManager.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/net/DatagramSocketManager.java (revision 1448517) +++ core/src/main/java/org/apache/logging/log4j/core/net/DatagramSocketManager.java (revision ) @@ -16,6 +16,10 @@ */ package org.apache.logging.log4j.core.net; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.Map; import org.apache.logging.log4j.core.appender.ManagerFactory; import java.io.OutputStream; @@ -29,13 +33,14 @@ /** * The Constructor. - * @param os The OutputStream. * @param name The unique name of the connection. + * @param os The OutputStream. + * @param address * @param host The host to connect to. * @param port The port on the host. */ - protected DatagramSocketManager(final OutputStream os, final String name, final String host, final int port) { - super(name, os, null, host, port); + protected DatagramSocketManager(final String name, final OutputStream os, InetAddress address, final String host, final int port) { + super(name, os, address, host, port); } /** @@ -56,6 +61,19 @@ } /** + * DatagramSocketManager's content format is specified by:

+ * Key: "protocol" Value: "udp" + * @return Map of content format keys supporting DatagramSocketManager + */ + public Map getContentFormat() + { + Map result = new HashMap(super.getContentFormat()); + result.put("protocol", "udp"); + + return result; + } + + /** * Data for the factory. */ private static class FactoryData { @@ -74,8 +92,15 @@ private static class DatagramSocketManagerFactory implements ManagerFactory { public DatagramSocketManager createManager(final String name, final FactoryData data) { + InetAddress address; final OutputStream os = new DatagramOutputStream(data.host, data.port); - return new DatagramSocketManager(os, name, data.host, data.port); + try { + address = InetAddress.getByName(data.host); + } catch (final UnknownHostException ex) { + LOGGER.error("Could not find address of " + data.host, ex); + return null; + } + return new DatagramSocketManager(name, os, address, data.host, data.port); } } } Index: core/src/main/java/org/apache/logging/log4j/core/layout/HTMLLayout.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/layout/HTMLLayout.java (revision 1448517) +++ core/src/main/java/org/apache/logging/log4j/core/layout/HTMLLayout.java (revision ) @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j.core.layout; +import java.util.HashMap; +import java.util.Map; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.plugins.Plugin; @@ -188,6 +190,15 @@ } return sbuf.toString(); + } + + /** + * HTMLLayout's format is sufficiently specified via the content type. The format could be defined via a DTD, + * but isn't at this time - returning empty Map/unspecified. + * @return empty Map + */ + public Map getContentFormat() { + return new HashMap(); } @Override Index: core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingFileManager.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingFileManager.java (revision 1448517) +++ core/src/main/java/org/apache/logging/log4j/core/appender/rolling/RollingFileManager.java (revision ) @@ -46,8 +46,8 @@ protected RollingFileManager(final String fileName, final String pattern, final OutputStream os, final boolean append, final long size, final long time, final TriggeringPolicy policy, - final RolloverStrategy strategy) { - super(fileName, os, append, false); + final RolloverStrategy strategy, String advertiseURI) { + super(fileName, os, append, false, advertiseURI); this.size = size; this.initialTime = time; this.policy = policy; @@ -64,14 +64,15 @@ * @param bufferedIO true if data should be buffered. * @param policy The TriggeringPolicy. * @param strategy The RolloverStrategy. + * @param advertiseURI the URI to use when advertising the file via MulticastDNS * @return A RollingFileManager. */ public static RollingFileManager getFileManager(final String fileName, final String pattern, final boolean append, final boolean bufferedIO, final TriggeringPolicy policy, - final RolloverStrategy strategy) { + final RolloverStrategy strategy, String advertiseURI) { return (RollingFileManager) getManager(fileName, new FactoryData(pattern, append, - bufferedIO, policy, strategy), factory); + bufferedIO, policy, strategy, advertiseURI), factory); } @Override @@ -228,20 +229,23 @@ private final boolean bufferedIO; private final TriggeringPolicy policy; private final RolloverStrategy strategy; + private final String advertiseURI; /** * Create the data for the factory. * @param pattern The pattern. * @param append The append flag. * @param bufferedIO The bufferedIO flag. + * @param advertiseURI */ public FactoryData(final String pattern, final boolean append, final boolean bufferedIO, - final TriggeringPolicy policy, final RolloverStrategy strategy) { + final TriggeringPolicy policy, final RolloverStrategy strategy, String advertiseURI) { this.pattern = pattern; this.append = append; this.bufferedIO = bufferedIO; this.policy = policy; this.strategy = strategy; + this.advertiseURI = advertiseURI; } } @@ -278,7 +282,7 @@ os = new BufferedOutputStream(os); } return new RollingFileManager(name, data.pattern, os, data.append, size, time, data.policy, - data.strategy); + data.strategy, data.advertiseURI); } catch (final FileNotFoundException ex) { LOGGER.error("FileManager (" + name + ") " + ex); } Index: core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java (revision 1448517) +++ core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java (revision ) @@ -16,17 +16,14 @@ */ package org.apache.logging.log4j.core.appender; +import java.util.HashMap; +import java.util.Map; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; -import org.apache.logging.log4j.core.config.plugins.Plugin; -import org.apache.logging.log4j.core.config.plugins.PluginAttr; -import org.apache.logging.log4j.core.config.plugins.PluginElement; -import org.apache.logging.log4j.core.config.plugins.PluginFactory; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.plugins.*; import org.apache.logging.log4j.core.layout.SerializedLayout; -import org.apache.logging.log4j.core.net.AbstractSocketManager; -import org.apache.logging.log4j.core.net.DatagramSocketManager; -import org.apache.logging.log4j.core.net.Protocol; -import org.apache.logging.log4j.core.net.TCPSocketManager; +import org.apache.logging.log4j.core.net.*; import org.apache.logging.log4j.util.EnglishEnums; /** @@ -38,10 +35,17 @@ protected SocketAppender(final String name, final Layout layout, final Filter filter, final AbstractSocketManager manager, final boolean handleException, - final boolean immediateFlush) { + final boolean immediateFlush, Advertiser advertiser) { super(name, layout, filter, handleException, immediateFlush, manager); - + if (advertiser != null) + { + Map configuration = new HashMap(layout.getContentFormat()); + configuration.putAll(manager.getContentFormat()); + configuration.put("contentType", layout.getContentType()); + configuration.put("name", name); + advertiser.advertise(configuration); - } + } + } /** * @@ -65,10 +69,13 @@ @PluginAttr("name") final String name, @PluginAttr("immediateFlush") final String immediateFlush, @PluginAttr("suppressExceptions") final String suppress, + @PluginAttr("advertise") final String advertise, @PluginElement("layout") Layout layout, - @PluginElement("filters") final Filter filter) { + @PluginElement("filters") final Filter filter, + @PluginConfiguration final Configuration config) { final boolean isFlush = immediateFlush == null ? true : Boolean.valueOf(immediateFlush); + boolean isAdvertise = advertise == null ? false : Boolean.valueOf(advertise); final boolean handleExceptions = suppress == null ? true : Boolean.valueOf(suppress); final int reconnectDelay = delay == null ? 0 : Integer.parseInt(delay); final int port = portNum == null ? 0 : Integer.parseInt(portNum); @@ -87,7 +94,8 @@ if (manager == null) { return null; } - return new SocketAppender(name, layout, filter, manager, handleExceptions, isFlush); + + return new SocketAppender(name, layout, filter, manager, handleExceptions, isFlush, isAdvertise ? config.getAdvertiser() : null); } protected static AbstractSocketManager createSocketManager(final String protocol, final String host, final int port, Index: core/src/main/java/org/apache/logging/log4j/core/appender/RollingFileAppender.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/appender/RollingFileAppender.java (revision 1448517) +++ core/src/main/java/org/apache/logging/log4j/core/appender/RollingFileAppender.java (revision ) @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j.core.appender; +import java.util.HashMap; +import java.util.Map; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LogEvent; @@ -30,6 +32,8 @@ import org.apache.logging.log4j.core.config.plugins.PluginElement; import org.apache.logging.log4j.core.config.plugins.PluginFactory; import org.apache.logging.log4j.core.layout.PatternLayout; +import org.apache.logging.log4j.core.net.Advertiser; +import org.apache.logging.log4j.core.net.ZeroConfSupport; /** * An appender that writes to files andd can roll over at intervals. @@ -43,8 +47,16 @@ private RollingFileAppender(final String name, final Layout layout, final Filter filter, final RollingFileManager manager, final String fileName, - final String filePattern, final boolean handleException, final boolean immediateFlush) { + final String filePattern, final boolean handleException, final boolean immediateFlush, + Advertiser advertiser) { super(name, layout, filter, handleException, immediateFlush, manager); + if (advertiser != null) + { + Map configuration = new HashMap(layout.getContentFormat()); + configuration.put("contentType", layout.getContentType()); + configuration.put("name", name); + advertiser.advertise(configuration); + } this.fileName = fileName; this.filePattern = filePattern; } @@ -106,13 +118,15 @@ @PluginElement("layout") Layout layout, @PluginElement("filter") final Filter filter, @PluginAttr("suppressExceptions") final String suppress, + @PluginAttr("advertise") final String advertise, + @PluginAttr("advertiseURI") final String advertiseURI, @PluginConfiguration final Configuration config) { final boolean isAppend = append == null ? true : Boolean.valueOf(append); final boolean handleExceptions = suppress == null ? true : Boolean.valueOf(suppress); final boolean isBuffered = bufferedIO == null ? true : Boolean.valueOf(bufferedIO); final boolean isFlush = immediateFlush == null ? true : Boolean.valueOf(immediateFlush); - + boolean isAdvertise = advertise == null ? false : Boolean.valueOf(advertise); if (name == null) { LOGGER.error("No name provided for FileAppender"); return null; @@ -138,7 +152,7 @@ } final RollingFileManager manager = RollingFileManager.getFileManager(fileName, filePattern, isAppend, - isBuffered, policy, strategy); + isBuffered, policy, strategy, advertiseURI); if (manager == null) { return null; } @@ -148,6 +162,6 @@ } return new RollingFileAppender(name, layout, filter, manager, fileName, filePattern, - handleExceptions, isFlush); + handleExceptions, isFlush, isAdvertise ? config.getAdvertiser() : null); } } Index: core/src/main/java/org/apache/logging/log4j/core/config/DefaultAdvertiser.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/config/DefaultAdvertiser.java (revision ) +++ core/src/main/java/org/apache/logging/log4j/core/config/DefaultAdvertiser.java (revision ) @@ -0,0 +1,43 @@ +/* + * 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.logging.log4j.core.config; + +import org.apache.logging.log4j.core.net.Advertiser; + +import java.util.Map; + +/** + * The default configuration monitor does not do anything. + */ +public class DefaultAdvertiser implements Advertiser { + + /** + * Returns null. + */ + public Object advertise(Map properties) { + return null; + } + + /** + * Does nothing + * @param object the object to unadvertise + */ + public void unadvertise(Object object) { + //no-op + } + +} Index: core/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java (revision 1448517) +++ core/src/test/java/org/apache/logging/log4j/core/appender/SocketAppenderTest.java (revision ) @@ -23,6 +23,7 @@ import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.DefaultConfiguration; import org.junit.After; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -97,7 +98,7 @@ public void testTCPAppender() throws Exception { final SocketAppender appender = SocketAppender.createAppender("localhost", PORT, "tcp", "-1", - "Test", null, null, null, null); + "Test", null, null, null, null, null, null); appender.start(); // set appender on root and set level to debug @@ -125,7 +126,7 @@ public void testUDPAppender() throws Exception { final SocketAppender appender = SocketAppender.createAppender("localhost", PORT, "udp", "-1", - "Test", null, null, null, null); + "Test", null, null, null, null, null, null); appender.start(); // set appender on root and set level to debug Index: core/src/main/java/org/apache/logging/log4j/core/config/JSONConfiguration.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/config/JSONConfiguration.java (revision 1448517) +++ core/src/main/java/org/apache/logging/log4j/core/config/JSONConfiguration.java (revision ) @@ -21,6 +21,7 @@ import org.apache.logging.log4j.core.config.plugins.PluginType; import org.apache.logging.log4j.core.config.plugins.ResolverUtil; import org.apache.logging.log4j.core.helpers.FileUtils; +import org.apache.logging.log4j.core.net.Advertiser; import org.apache.logging.log4j.status.StatusConsoleListener; import org.apache.logging.log4j.status.StatusListener; import org.apache.logging.log4j.status.StatusLogger; @@ -114,6 +115,11 @@ final int interval = Integer.parseInt(getSubst().replace(entry.getValue())); if (interval > 0 && configFile != null) { monitor = new FileConfigurationMonitor(this, configFile, listeners, interval); + } + } else if ("advertiser".equalsIgnoreCase(entry.getKey())) { + final String advertiserString = getSubst().replace(entry.getValue()); + if (advertiserString != null) { + advertiser = (Advertiser) Class.forName(advertiserString).newInstance(); } } } Index: core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java (revision 1448517) +++ core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java (revision ) @@ -77,7 +77,7 @@ final PatternLayout layout = PatternLayout.createLayout(msgPattern, ctx.getConfiguration(), null, null); //FileOutputStream fos = new FileOutputStream(OUTPUT_FILE + "_mdc"); final FileAppender appender = FileAppender.createAppender(OUTPUT_FILE + "_mdc", "false", "false", "File", "false", - "true", "false", layout, null); + "true", "false", layout, null, "false", null); appender.start(); // set appender on root and set level to debug Index: core/src/test/java/org/apache/logging/log4j/core/appender/rolling/OnStartupTriggeringPolicyTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/test/java/org/apache/logging/log4j/core/appender/rolling/OnStartupTriggeringPolicyTest.java (revision 1448517) +++ core/src/test/java/org/apache/logging/log4j/core/appender/rolling/OnStartupTriggeringPolicyTest.java (revision ) @@ -52,7 +52,7 @@ public MyRollingManager(final TriggeringPolicy policy, final RolloverStrategy strategy) { super("testfile", "target/rolling1/test1-%i.log.gz", new ByteArrayOutputStream(), - false, 0, System.currentTimeMillis(), policy, strategy); + false, 0, System.currentTimeMillis(), policy, strategy, null); } public void setFileTime(final long timestamp) { Index: core/src/main/java/org/apache/logging/log4j/core/net/Advertiser.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/net/Advertiser.java (revision ) +++ core/src/main/java/org/apache/logging/log4j/core/net/Advertiser.java (revision ) @@ -0,0 +1,24 @@ +/* + * 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.logging.log4j.core.net; + +import java.util.Map; + +public interface Advertiser { + Object advertise(Map properties); + void unadvertise(Object advertisedObject); +} Index: core/src/main/java/org/apache/logging/log4j/core/layout/SerializedLayout.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/layout/SerializedLayout.java (revision 1448517) +++ core/src/main/java/org/apache/logging/log4j/core/layout/SerializedLayout.java (revision ) @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j.core.layout; +import java.util.HashMap; +import java.util.Map; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.plugins.Plugin; import org.apache.logging.log4j.core.config.plugins.PluginFactory; @@ -48,7 +50,7 @@ } /** - * Formats a {@link org.apache.logging.log4j.core.LogEvent} in conformance with the log4j.dtd. + * Formats a {@link org.apache.logging.log4j.core.LogEvent} as a serialized byte array of the LogEvent object. * * @param event The LogEvent. * @return the formatted LogEvent. @@ -92,6 +94,14 @@ @Override public byte[] getHeader() { return header; + } + + /** + * SerializedLayout's format is sufficiently specified via the content type, use empty Map/unspecified. + * @return empty Map + */ + public Map getContentFormat() { + return new HashMap(); } /** Index: core/src/main/java/org/apache/logging/log4j/core/config/XMLConfiguration.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/config/XMLConfiguration.java (revision 1448517) +++ core/src/main/java/org/apache/logging/log4j/core/config/XMLConfiguration.java (revision ) @@ -21,6 +21,7 @@ import org.apache.logging.log4j.core.config.plugins.PluginType; import org.apache.logging.log4j.core.config.plugins.ResolverUtil; import org.apache.logging.log4j.core.helpers.FileUtils; +import org.apache.logging.log4j.core.net.Advertiser; import org.apache.logging.log4j.status.StatusConsoleListener; import org.apache.logging.log4j.status.StatusListener; import org.apache.logging.log4j.status.StatusLogger; @@ -138,6 +139,19 @@ final int interval = Integer.parseInt(getSubst().replace(entry.getValue())); if (interval > 0 && configFile != null) { monitor = new FileConfigurationMonitor(this, configFile, listeners, interval); + } + } else if ("advertiser".equalsIgnoreCase(entry.getKey())) { + final String advertiserString = getSubst().replace(entry.getValue()); + if (advertiserString != null) { + try { + advertiser = (Advertiser) Class.forName(advertiserString).newInstance(); + } catch (InstantiationException e) { + System.err.println("InstantiationException attempting to instantiate advertiser: " + advertiserString); + } catch (IllegalAccessException e) { + System.err.println("IllegalAccessException attempting to instantiate advertiser: " + advertiserString); + } catch (ClassNotFoundException e) { + System.err.println("ClassNotFoundException attempting to instantiate advertiser: " + advertiserString); + } } } } Index: core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java (revision 1448517) +++ core/src/main/java/org/apache/logging/log4j/core/appender/SyslogAppender.java (revision ) @@ -27,6 +27,7 @@ import org.apache.logging.log4j.core.layout.RFC5424Layout; import org.apache.logging.log4j.core.layout.SyslogLayout; import org.apache.logging.log4j.core.net.AbstractSocketManager; +import org.apache.logging.log4j.core.net.Advertiser; import org.apache.logging.log4j.core.net.Protocol; /** @@ -40,8 +41,8 @@ private static final String RFC5424 = "RFC5424"; protected SyslogAppender(final String name, final Layout layout, final Filter filter, final boolean handleException, - final boolean immediateFlush, final AbstractSocketManager manager) { - super(name, layout, filter, manager, handleException, immediateFlush); + final boolean immediateFlush, final AbstractSocketManager manager, Advertiser advertiser) { + super(name, layout, filter, manager, handleException, immediateFlush, advertiser); } @@ -100,12 +101,14 @@ @PluginElement("filters") final Filter filter, @PluginConfiguration final Configuration config, @PluginAttr("charset") final String charsetName, - @PluginAttr("exceptionPattern") final String exceptionPattern) { + @PluginAttr("exceptionPattern") final String exceptionPattern, + @PluginAttr("advertise") final String advertise) { final boolean isFlush = immediateFlush == null ? true : Boolean.valueOf(immediateFlush); final boolean handleExceptions = suppress == null ? true : Boolean.valueOf(suppress); final int reconnectDelay = delay == null ? 0 : Integer.parseInt(delay); final int port = portNum == null ? 0 : Integer.parseInt(portNum); + boolean isAdvertise = advertise == null ? false : Boolean.valueOf(advertise); final Layout layout = RFC5424.equalsIgnoreCase(format) ? RFC5424Layout.createLayout(facility, id, ein, includeMDC, mdcId, includeNL, escapeNL, appName, msgId, excludes, includes, required, charsetName, exceptionPattern, config) : @@ -121,6 +124,6 @@ return null; } - return new SyslogAppender(name, layout, filter, handleExceptions, isFlush, manager); + return new SyslogAppender(name, layout, filter, handleExceptions, isFlush, manager, isAdvertise ? config.getAdvertiser() : null); } } Index: core/src/main/java/org/apache/logging/log4j/core/layout/XMLLayout.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/layout/XMLLayout.java (revision 1448517) +++ core/src/main/java/org/apache/logging/log4j/core/layout/XMLLayout.java (revision ) @@ -24,6 +24,7 @@ import java.io.StringWriter; import java.nio.charset.Charset; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -214,6 +215,19 @@ final StringBuilder sbuf = new StringBuilder(); sbuf.append("\r\n"); return sbuf.toString().getBytes(getCharset()); + } + + /** + * XMLLayout's content format is specified by:

+ * Key: "dtd" Value: "log4j.dtd"

+ * Key: "version" Value: "1.2" + * @return Map of content format keys supporting XMLLayout + */ + public Map getContentFormat() { + Map result = new HashMap(); + result.put("dtd", "log4j.dtd"); + result.put("version", "1.2"); + return result; } @Override Index: core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java (revision 1448517) +++ core/src/main/java/org/apache/logging/log4j/core/layout/PatternLayout.java (revision ) @@ -16,6 +16,8 @@ */ package org.apache.logging.log4j.core.layout; +import java.util.HashMap; +import java.util.Map; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.plugins.Plugin; @@ -122,6 +124,22 @@ } final PatternParser parser = createPatternParser(this.config); formatters = parser.parse(pattern); + } + + /** + * PatternLayout's content format is specified by:

+ * Key: "structured" Value: "false"

+ * Key: "formatType" Value: "conversion" (format uses the keywords supported by OptionConverter)

+ * Key: "format" Value: provided "conversionPattern" param + * @return Map of content format keys supporting PatternLayout + */ + public Map getContentFormat() + { + Map result = new HashMap(); + result.put("structured", "false"); + result.put("formatType", "conversion"); + result.put("format", conversionPattern); + return result; } /**