http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlMarkerMixIn.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlMarkerMixIn.java b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlMarkerMixIn.java new file mode 100644 index 0000000..9fa0e8a --- /dev/null +++ b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlMarkerMixIn.java @@ -0,0 +1,79 @@ +/* + * 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.jackson.xml; + +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.core.jackson.MarkerMixIn; +import org.apache.logging.log4j.core.jackson.XmlConstants; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +/** + * Jackson mix-in for {@link Marker}. + * <p> + * If we want to deal with more than one {@link Marker} implementation then recode these annotations to include + * metadata. + * </p> + * <p> + * <em>Consider this class private.</em> + * </p> + * <p> + * Example XML: + * </p> + * + * <pre> +<Marker name="Marker1"> + <Parents> + <Marker name="ParentMarker1"> + <Parents> + <Marker name="GrandMotherMarker"/> + <Marker name="GrandFatherMarker"/> + </Parents> + </Marker> + <Marker name="ParentMarker2"/> + </Parents> +</Marker> + * </pre> + * + * @see Marker + */ +// Alternate for multiple Marker implementation. +// @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class") +@JsonDeserialize(as = org.apache.logging.log4j.MarkerManager.Log4jMarker.class) +abstract class XmlMarkerMixIn extends MarkerMixIn { + public static final String ATTR_NAME = "name"; + private static final long serialVersionUID = 1L; + + @JsonCreator + protected XmlMarkerMixIn(@JsonProperty(ATTR_NAME) final String name) { + super(name); + } + + @Override + @JacksonXmlProperty(isAttribute = true) + public abstract String getName(); + + @Override + @JacksonXmlElementWrapper(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_PARENTS) + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_MARKER) + public abstract Marker[] getParents(); + +}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlSetupContextInitializer.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlSetupContextInitializer.java b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlSetupContextInitializer.java new file mode 100644 index 0000000..442f9ab --- /dev/null +++ b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlSetupContextInitializer.java @@ -0,0 +1,42 @@ +package org.apache.logging.log4j.jackson.xml; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; +import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.jackson.ExtendedStackTraceElementMixIn; +import org.apache.logging.log4j.core.jackson.LevelMixIn; +import org.apache.logging.log4j.core.jackson.ThrowableProxyMixIn; +import org.apache.logging.log4j.core.jackson.ThrowableProxyWithStacktraceAsStringMixIn; +import org.apache.logging.log4j.core.jackson.ThrowableProxyWithoutStacktraceMixIn; +import org.apache.logging.log4j.core.time.Instant; + +import com.fasterxml.jackson.databind.Module.SetupContext; +import com.fasterxml.jackson.databind.module.SimpleModule; + +/** + * Used to set up {@link SetupContext} from different {@link SimpleModule}s. + * <p> + * <em>Consider this class private.</em> + * </p> + */ +class XmlSetupContextInitializer { + + public void setupModule(final SetupContext context, final boolean includeStacktrace, + final boolean stacktraceAsString) { + // JRE classes: we cannot edit those with Jackson annotations + context.setMixInAnnotations(StackTraceElement.class, XmlStackTraceElementMixIn.class); + // Log4j API classes: we do not want to edit those with Jackson annotations because the API module should not + // depend on Jackson. + context.setMixInAnnotations(Marker.class, XmlMarkerMixIn.class); + context.setMixInAnnotations(Level.class, LevelMixIn.class); + context.setMixInAnnotations(Instant.class, XmlInstantMixIn.class); + context.setMixInAnnotations(LogEvent.class, XmlLogEventWithContextListMixIn.class); + // Log4j Core classes: we do not want to bring in Jackson at runtime if we do not have to. + context.setMixInAnnotations(ExtendedStackTraceElement.class, ExtendedStackTraceElementMixIn.class); + context.setMixInAnnotations(ThrowableProxy.class, includeStacktrace + ? (stacktraceAsString ? ThrowableProxyWithStacktraceAsStringMixIn.class : ThrowableProxyMixIn.class) + : ThrowableProxyWithoutStacktraceMixIn.class); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlStackTraceElementMixIn.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlStackTraceElementMixIn.java b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlStackTraceElementMixIn.java new file mode 100644 index 0000000..abdba98 --- /dev/null +++ b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/XmlStackTraceElementMixIn.java @@ -0,0 +1,39 @@ +package org.apache.logging.log4j.jackson.xml; + +import org.apache.logging.log4j.core.jackson.StackTraceElementMixIn; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +abstract class XmlStackTraceElementMixIn extends StackTraceElementMixIn { + + @JsonCreator + protected XmlStackTraceElementMixIn( + // @formatter:off + @JsonProperty(ATTR_CLASS) final String declaringClass, + @JsonProperty(ATTR_METHOD) final String methodName, + @JsonProperty(ATTR_FILE) final String fileName, + @JsonProperty(ATTR_LINE) final int lineNumber) + // @formatter:on + { + super(declaringClass, methodName, fileName, lineNumber); + } + + @Override + @JacksonXmlProperty(localName = ATTR_CLASS, isAttribute = true) + protected abstract String getClassName(); + + @Override + @JacksonXmlProperty(localName = ATTR_FILE, isAttribute = true) + protected abstract String getFileName(); + + @Override + @JacksonXmlProperty(localName = ATTR_LINE, isAttribute = true) + protected abstract int getLineNumber(); + + @Override + @JacksonXmlProperty(localName = ATTR_METHOD, isAttribute = true) + protected abstract String getMethodName(); + +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/layout/Log4jXmlPrettyPrinter.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/layout/Log4jXmlPrettyPrinter.java b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/layout/Log4jXmlPrettyPrinter.java new file mode 100644 index 0000000..24c5ef0 --- /dev/null +++ b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/layout/Log4jXmlPrettyPrinter.java @@ -0,0 +1,41 @@ +package org.apache.logging.log4j.jackson.xml.layout; + +import javax.xml.stream.XMLStreamException; + +import org.codehaus.stax2.XMLStreamWriter2; + +import com.fasterxml.jackson.dataformat.xml.util.DefaultXmlPrettyPrinter; + +/** + * When <Event>s are written into a XML file; the "Event" object is not the root element, but an element named + * <Events> created using {@link XmlLayout#getHeader()} and {@link XmlLayout#getFooter()} methods. + * <p> + * {@link com.fasterxml.jackson.dataformat.xml.util.DefaultXmlPrettyPrinter} is used to print the Event object into + * XML; hence it assumes <Event> tag as the root element, so it prints the <Event> tag without any + * indentation. To add an indentation to the <Event> tag; hence an additional indentation for any + * sub-elements, this class is written. As an additional task, to avoid the blank line printed after the ending + * </Event> tag, {@link #writePrologLinefeed(XMLStreamWriter2)} method is also overridden. + * </p> + */ +class Log4jXmlPrettyPrinter extends DefaultXmlPrettyPrinter { + + private static final long serialVersionUID = 1L; + + Log4jXmlPrettyPrinter(final int nesting) { + _nesting = nesting; + } + + /** + * Sets the nesting level to 1 rather than 0, so the "Event" tag will get indentation of next level below root. + */ + @Override + public DefaultXmlPrettyPrinter createInstance() { + return new Log4jXmlPrettyPrinter(XmlJacksonFactory.DEFAULT_INDENT); + } + + @Override + public void writePrologLinefeed(final XMLStreamWriter2 sw) throws XMLStreamException { + // nothing + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/layout/XmlJacksonFactory.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/layout/XmlJacksonFactory.java b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/layout/XmlJacksonFactory.java new file mode 100644 index 0000000..0289c71 --- /dev/null +++ b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/layout/XmlJacksonFactory.java @@ -0,0 +1,54 @@ +package org.apache.logging.log4j.jackson.xml.layout; + +import org.apache.logging.log4j.core.jackson.AbstractJacksonFactory; +import org.apache.logging.log4j.core.jackson.JsonConstants; +import org.apache.logging.log4j.core.jackson.XmlConstants; +import org.apache.logging.log4j.jackson.xml.Log4jXmlObjectMapper; + +import com.fasterxml.jackson.core.PrettyPrinter; +import com.fasterxml.jackson.databind.ObjectMapper; + +class XmlJacksonFactory extends AbstractJacksonFactory { + + static final int DEFAULT_INDENT = 1; + + public XmlJacksonFactory(final boolean includeStacktrace, final boolean stacktraceAsString) { + super(includeStacktrace, stacktraceAsString); + } + + @Override + protected String getPropertyNameForContextMap() { + return XmlConstants.ELT_CONTEXT_MAP; + } + + @Override + protected String getPropertyNameForNanoTime() { + return JsonConstants.ELT_NANO_TIME; + } + + @Override + protected String getPropertyNameForSource() { + return XmlConstants.ELT_SOURCE; + } + + @Override + protected String getPropertyNameForStackTrace() { + return XmlConstants.ELT_EXTENDED_STACK_TRACE; + } + + @Override + protected PrettyPrinter newCompactPrinter() { + // Yes, null is the proper answer. + return null; + } + + @Override + protected ObjectMapper newObjectMapper() { + return new Log4jXmlObjectMapper(includeStacktrace, stacktraceAsString); + } + + @Override + protected PrettyPrinter newPrettyPrinter() { + return new Log4jXmlPrettyPrinter(DEFAULT_INDENT); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayout.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayout.java b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayout.java new file mode 100644 index 0000000..c305c33 --- /dev/null +++ b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayout.java @@ -0,0 +1,226 @@ +/* + * 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.jackson.xml.layout; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.Node; +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; +import org.apache.logging.log4j.core.jackson.AbstractJacksonLayout; +import org.apache.logging.log4j.core.jackson.XmlConstants; +import org.apache.logging.log4j.core.util.KeyValuePair; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Appends a series of {@code event} elements as defined in the <a href="log4j.dtd">log4j.dtd</a>. + * + * <h3>Complete well-formed XML vs. fragment XML</h3> + * <p> + * If you configure {@code complete="true"}, the appender outputs a well-formed XML document where the default namespace + * is the log4j namespace {@value XmlConstants#XML_NAMESPACE}. By default, with {@code complete="false"}, you should + * include the output as an <em>external entity</em> in a separate file to form a well-formed XML document. + * </p> + * <p> + * If {@code complete="false"}, the appender does not write the XML processing instruction and the root element. + * </p> + * <h3>Encoding</h3> + * <p> + * Appenders using this layout should have their {@code charset} set to {@code UTF-8} or {@code UTF-16}, otherwise + * events containing non-ASCII characters could result in corrupted log files. + * </p> + * <h3>Pretty vs. compact XML</h3> + * <p> + * By default, the XML layout is not compact (compact = not "pretty") with {@code compact="false"}, which means the + * appender uses end-of-line characters and indents lines to format the XML. If {@code compact="true"}, then no + * end-of-line or indentation is used. Message content may contain, of course, end-of-lines. + * </p> + * <h3>Additional Fields</h3> + * <p> + * This property allows addition of custom fields into generated JSON. + * {@code <XmlLayout><KeyValuePair key="foo" value="bar"/></XmlLayout>} inserts {@code <foo>bar</foo>} directly into XML + * output. Supports Lookup expressions. + * </p> + */ +@Plugin(name = "XmlLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true) +public final class XmlLayout extends AbstractJacksonLayout { + + public static class Builder<B extends Builder<B>> extends AbstractJacksonLayout.Builder<B> + implements org.apache.logging.log4j.core.util.Builder<XmlLayout> { + + public Builder() { + super(); + setCharset(StandardCharsets.UTF_8); + } + + @Override + public XmlLayout build() { + return new XmlLayout(getConfiguration(), isLocationInfo(), isProperties(), isComplete(), isCompact(), + getCharset(), isIncludeStacktrace(), isStacktraceAsString(), isIncludeNullDelimiter(), + getAdditionalFields()); + } + } + + @JacksonXmlRootElement(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_EVENT) + public static class XmlLogEventWithAdditionalFields extends LogEventWithAdditionalFields { + + public XmlLogEventWithAdditionalFields(final Object logEvent, final Map<String, String> additionalFields) { + super(logEvent, additionalFields); + } + + } + + private static final String ROOT_TAG = "Events"; + + /** + * Creates an XML Layout using the default settings. + * + * @return an XML Layout. + */ + public static XmlLayout createDefaultLayout() { + return new XmlLayout(null, false, false, false, false, StandardCharsets.UTF_8, true, false, false, null); + } + + /** + * Creates an XML Layout. + * + * @param locationInfo + * If "true", includes the location information in the generated XML. + * @param properties + * If "true", includes the thread context map in the generated XML. + * @param complete + * If "true", includes the XML header and footer, defaults to "false". + * @param compact + * If "true", does not use end-of-lines and indentation, defaults to "false". + * @param charset + * The character set to use, if {@code null}, uses "UTF-8". + * @param includeStacktrace + * If "true", includes the stacktrace of any Throwable in the generated XML, defaults to "true". + * @return An XML Layout. + * + * @deprecated Use {@link #newBuilder()} instead + */ + @Deprecated + public static XmlLayout createLayout(final boolean locationInfo, final boolean properties, final boolean complete, + final boolean compact, final Charset charset, final boolean includeStacktrace) { + return new XmlLayout(null, locationInfo, properties, complete, compact, charset, includeStacktrace, false, + false, null); + } + + @PluginBuilderFactory + public static <B extends Builder<B>> B newBuilder() { + return new Builder<B>().asBuilder(); + } + + /** + * @deprecated Use {@link #newBuilder()} instead + */ + @Deprecated + protected XmlLayout(final boolean locationInfo, final boolean properties, final boolean complete, + final boolean compact, final Charset charset, final boolean includeStacktrace) { + this(null, locationInfo, properties, complete, compact, charset, includeStacktrace, false, false, null); + } + + private XmlLayout(final Configuration config, final boolean locationInfo, final boolean properties, + final boolean complete, final boolean compact, final Charset charset, final boolean includeStacktrace, + final boolean stacktraceAsString, final boolean includeNullDelimiter, + final KeyValuePair[] additionalFields) { + super(config, + new XmlJacksonFactory(includeStacktrace, stacktraceAsString).newWriter(locationInfo, properties, + compact), + charset, compact, complete, false, null, null, includeNullDelimiter, additionalFields); + } + + @Override + protected LogEventWithAdditionalFields createLogEventWithAdditionalFields(final LogEvent event, + final Map<String, String> additionalFieldsMap) { + return new XmlLogEventWithAdditionalFields(event, additionalFieldsMap); + } + + /** + * Gets this XmlLayout's content format. Specified by: + * <ul> + * <li>Key: "dtd" Value: "log4j-events.dtd"</li> + * <li>Key: "version" Value: "2.0"</li> + * </ul> + * + * @return Map of content format keys supporting XmlLayout + */ + @Override + public Map<String, String> getContentFormat() { + final Map<String, String> result = new HashMap<>(); + // result.put("dtd", "log4j-events.dtd"); + result.put("xsd", "log4j-events.xsd"); + result.put("version", "2.0"); + return result; + } + + /** + * @return The content type. + */ + @Override + public String getContentType() { + return "text/xml; charset=" + this.getCharset(); + } + + /** + * Returns appropriate XML footer. + * + * @return a byte array containing the footer, closing the XML root element. + */ + @Override + public byte[] getFooter() { + if (!complete) { + return null; + } + return getBytes("</" + ROOT_TAG + '>' + this.eol); + } + + /** + * Returns appropriate XML headers. + * <ol> + * <li>XML processing instruction</li> + * <li>XML root element</li> + * </ol> + * + * @return a byte array containing the header. + */ + @Override + public byte[] getHeader() { + if (!complete) { + return null; + } + final StringBuilder buf = new StringBuilder(); + buf.append("<?xml version=\"1.0\" encoding=\""); + buf.append(this.getCharset().name()); + buf.append("\"?>"); + buf.append(this.eol); + // Make the log4j namespace the default namespace, no need to use more space with a namespace prefix. + buf.append('<'); + buf.append(ROOT_TAG); + buf.append(" xmlns=\"" + XmlConstants.XML_NAMESPACE + "\">"); + buf.append(this.eol); + return buf.toString().getBytes(this.getCharset()); + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/parser/XmlLogEventParser.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/parser/XmlLogEventParser.java b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/parser/XmlLogEventParser.java new file mode 100644 index 0000000..32776a2 --- /dev/null +++ b/log4j-layout-jackson-xml/java/org/apache/logging/log4j/jackson/xml/parser/XmlLogEventParser.java @@ -0,0 +1,32 @@ +/* + * 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.jackson.xml.parser; + +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.parser.AbstractJacksonLogEventParser; +import org.apache.logging.log4j.jackson.xml.Log4jXmlObjectMapper; + +/** + * Parses the output from XmlLayout layout into instances of {@link LogEvent}. + */ +public class XmlLogEventParser extends AbstractJacksonLogEventParser { + + public XmlLogEventParser() { + super(new Log4jXmlObjectMapper()); + } + +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/pom.xml ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/pom.xml b/log4j-layout-jackson-xml/pom.xml new file mode 100644 index 0000000..4a8989d --- /dev/null +++ b/log4j-layout-jackson-xml/pom.xml @@ -0,0 +1,171 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- ~ 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. --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j</artifactId> + <version>3.0.0-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>log4j-layout-jackson-xml</artifactId> + <name>Apache Log4j Layout for Jackson XML</name> + <description> + Apache Log4j Layout for Jackson XML. + </description> + <properties> + <log4jParentDir>${basedir}/..</log4jParentDir> + <docLabel>Log4j Layout for Jackson XML Documentation</docLabel> + <projectDir>/log4j-layout-xml</projectDir> + <module.name>org.apache.logging.log4j.jackson.xml</module.name> + </properties> + + <dependencies> + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-layout-jackson</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.dataformat</groupId> + <artifactId>jackson-dataformat-xml</artifactId> + </dependency> + <!-- Test Dependencies --> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency> + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-api</artifactId> + <type>test-jar</type> + </dependency> + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-core</artifactId> + <type>test-jar</type> + </dependency> + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-layout-jackson</artifactId> + <type>test-jar</type> + <version>${project.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <configuration> + <instructions> + <Fragment-Host>org.apache.logging.log4j.jackson.xml</Fragment-Host> + <Export-Package>*</Export-Package> + </instructions> + </configuration> + </plugin> + </plugins> + </build> + <reporting> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-changes-plugin</artifactId> + <version>${changes.plugin.version}</version> + <reportSets> + <reportSet> + <reports> + <report>changes-report</report> + </reports> + </reportSet> + </reportSets> + <configuration> + <issueLinkTemplate>%URL%/show_bug.cgi?id=%ISSUE%</issueLinkTemplate> + <useJql>true</useJql> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-checkstyle-plugin</artifactId> + <version>${checkstyle.plugin.version}</version> + <configuration> + <!--<propertiesLocation>${vfs.parent.dir}/checkstyle.properties</propertiesLocation> --> + <configLocation>${log4jParentDir}/checkstyle.xml</configLocation> + <suppressionsLocation>${log4jParentDir}/checkstyle-suppressions.xml</suppressionsLocation> + <enableRulesSummary>false</enableRulesSummary> + <propertyExpansion>basedir=${basedir}</propertyExpansion> + <propertyExpansion>licensedir=${log4jParentDir}/checkstyle-header.txt</propertyExpansion> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <version>${javadoc.plugin.version}</version> + <configuration> + <bottom><![CDATA[<p align="center">Copyright © {inceptionYear}-{currentYear} {organizationName}. All Rights Reserved.<br /> + Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, the Apache Logging project logo, + and the Apache Log4j logo are trademarks of The Apache Software Foundation.</p>]]></bottom> + <!-- module link generation is completely broken in the javadoc plugin for a multi-module non-aggregating project --> + <detectOfflineLinks>false</detectOfflineLinks> + <linksource>true</linksource> + </configuration> + <reportSets> + <reportSet> + <id>non-aggregate</id> + <reports> + <report>javadoc</report> + </reports> + </reportSet> + </reportSets> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>findbugs-maven-plugin</artifactId> + <version>${findbugs.plugin.version}</version> + <configuration> + <fork>true</fork> + <jvmArgs>-Duser.language=en</jvmArgs> + <threshold>Normal</threshold> + <effort>Default</effort> + <excludeFilterFile>${log4jParentDir}/findbugs-exclude-filter.xml</excludeFilterFile> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jxr-plugin</artifactId> + <version>${jxr.plugin.version}</version> + <reportSets> + <reportSet> + <id>non-aggregate</id> + <reports> + <report>jxr</report> + </reports> + </reportSet> + <reportSet> + <id>aggregate</id> + <reports> + <report>aggregate</report> + </reports> + </reportSet> + </reportSets> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-pmd-plugin</artifactId> + <version>${pmd.plugin.version}</version> + <configuration> + <targetJdk>${maven.compiler.target}</targetJdk> + </configuration> + </plugin> + </plugins> + </reporting> +</project> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/AbstractLogEventXmlMixIn.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/AbstractLogEventXmlMixIn.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/AbstractLogEventXmlMixIn.java new file mode 100644 index 0000000..9d8687d --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/AbstractLogEventXmlMixIn.java @@ -0,0 +1,135 @@ +/* + * 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.jackson.xml; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.ThreadContext.ContextStack; +import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.time.Instant; +import org.apache.logging.log4j.jackson.AbstractLogEventMixIn; +import org.apache.logging.log4j.jackson.ContextDataAsEntryListDeserializer; +import org.apache.logging.log4j.jackson.Log4jStackTraceElementDeserializer; +import org.apache.logging.log4j.jackson.MessageSerializer; +import org.apache.logging.log4j.jackson.SimpleMessageDeserializer; +import org.apache.logging.log4j.jackson.XmlConstants; +import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.util.ReadOnlyStringMap; + +import com.fasterxml.jackson.annotation.JsonFilter; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** +* <pre>AbstractLogEventMixIn +*ââ XmlLogEventMixIn +*âââââ XmlLogEventWithContextListMixIn +*âââââ XmlLogEventWithContextMapMixIn +*ââ JsonLogEventMixIn +*âââââ JsonLogEventWithContextListMixIn +*âââââ JsonLogEventWithContextMapMixIn</pre> +*/ +@JacksonXmlRootElement(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_EVENT) +@JsonFilter(AbstractLogEventMixIn.JSON_FILTER_ID) +@JsonPropertyOrder({ + // @formatter:off + AbstractLogEventMixIn.ATTR_THREAD, + AbstractLogEventMixIn.ATTR_LEVEL, + AbstractLogEventMixIn.ATTR_LOGGER_NAME, + AbstractLogEventMixIn.ATTR_LOGGER_FQCN, + AbstractLogEventMixIn.ATTR_END_OF_BATCH, + XmlConstants.ELT_INSTANT, + XmlConstants.ELT_MARKER, + XmlConstants.ELT_MESSAGE, + AbstractLogEventXmlMixIn.ELT_THROWN, + XmlConstants.ELT_CONTEXT_MAP, + XmlConstants.ELT_CONTEXT_STACK, + XmlConstants.ELT_SOURCE}) + // @formatter:on +public abstract class AbstractLogEventXmlMixIn extends AbstractLogEventMixIn { + + public static final String ELT_THROWN = "Thrown"; + + private static final long serialVersionUID = 1L; + + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_MAP) + @JsonSerialize(using = ContextDataAsEntryListXmlSerializer.class) + @JsonDeserialize(using = ContextDataAsEntryListDeserializer.class) + @Override + public abstract ReadOnlyStringMap getContextData(); + + @JacksonXmlElementWrapper(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_STACK) + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_STACK_ITEM) + @Override + public abstract ContextStack getContextStack(); + + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_INSTANT) + @Override + public abstract Instant getInstant(); + + @JacksonXmlProperty(isAttribute = true) + @Override + public abstract Level getLevel(); + + @JacksonXmlProperty(isAttribute = true) + @Override + public abstract String getLoggerFqcn(); + + @JacksonXmlProperty(isAttribute = true) + @Override + public abstract String getLoggerName(); + + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_MARKER) + @Override + public abstract Marker getMarker(); + + @JsonSerialize(using = MessageSerializer.class) + @JsonDeserialize(using = SimpleMessageDeserializer.class) + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_MESSAGE) + @Override + public abstract Message getMessage(); + + @JsonDeserialize(using = Log4jStackTraceElementDeserializer.class) + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_SOURCE) + @Override + public abstract StackTraceElement getSource(); + + @Override + @JacksonXmlProperty(isAttribute = true, localName = ATTR_THREAD_ID) + public abstract long getThreadId(); + + @Override + @JacksonXmlProperty(isAttribute = true, localName = ATTR_THREAD) + public abstract String getThreadName(); + + @Override + @JacksonXmlProperty(isAttribute = true, localName = ATTR_THREAD_PRIORITY) + public abstract int getThreadPriority(); + + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_THROWN) + @Override + public abstract ThrowableProxy getThrownProxy(); + + @JacksonXmlProperty(isAttribute = true) + @Override + public abstract boolean isEndOfBatch(); + +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ContextDataAsEntryListXmlSerializer.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ContextDataAsEntryListXmlSerializer.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ContextDataAsEntryListXmlSerializer.java new file mode 100644 index 0000000..b916c44 --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ContextDataAsEntryListXmlSerializer.java @@ -0,0 +1,37 @@ +/* + * 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.jackson.xml; + +import org.apache.logging.log4j.jackson.ContextDataAsEntryListSerializer; +import org.apache.logging.log4j.jackson.MapEntry; + +public class ContextDataAsEntryListXmlSerializer extends ContextDataAsEntryListSerializer { + + private static final long serialVersionUID = 1L; + + @Override + protected MapEntry createMapEntry(final String key, final String value) { + return new XmlMapEntry(key, value); + } + + @Override + protected MapEntry[] createMapEntryArray(final int size) { + return new XmlMapEntry[size]; + } + +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ExtendedStackTraceElementXmlMixIn.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ExtendedStackTraceElementXmlMixIn.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ExtendedStackTraceElementXmlMixIn.java new file mode 100644 index 0000000..224ef40 --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ExtendedStackTraceElementXmlMixIn.java @@ -0,0 +1,68 @@ +package org.apache.logging.log4j.jackson.xml; + +import org.apache.logging.log4j.core.impl.ExtendedClassInfo; +import org.apache.logging.log4j.jackson.ExtendedStackTraceElementMixIn; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +public abstract class ExtendedStackTraceElementXmlMixIn extends ExtendedStackTraceElementMixIn { + + private static final long serialVersionUID = 1L; + + @JsonCreator + public ExtendedStackTraceElementXmlMixIn( + // @formatter:off + @JsonProperty(ATTR_CLASS) final String declaringClass, + @JsonProperty(ATTR_METHOD) final String methodName, + @JsonProperty(ATTR_FILE) final String fileName, + @JsonProperty(ATTR_LINE) final int lineNumber, + @JsonProperty(ATTR_EXACT) final boolean exact, + @JsonProperty(ATTR_LOCATION) final String location, + @JsonProperty(ATTR_VERSION) final String version + // @formatter:on + ) { + super(declaringClass, methodName, fileName, lineNumber, exact, location, version); + } + + @Override + @JacksonXmlProperty(localName = ATTR_CLASS, isAttribute = true) + public abstract String getClassName(); + + @Override + @JacksonXmlProperty(isAttribute = true) + public abstract boolean getExact(); + + @Override + @JsonIgnore + public abstract ExtendedClassInfo getExtraClassInfo(); + + @Override + @JacksonXmlProperty(localName = ATTR_FILE, isAttribute = true) + public abstract String getFileName(); + + @Override + @JacksonXmlProperty(localName = ATTR_LINE, isAttribute = true) + public abstract int getLineNumber(); + + @Override + @JacksonXmlProperty(isAttribute = true) + public abstract String getLocation(); + + @Override + @JacksonXmlProperty(localName = ATTR_METHOD, isAttribute = true) + public abstract String getMethodName(); + + @JsonIgnore + abstract StackTraceElement getStackTraceElement(); + + @Override + @JacksonXmlProperty(isAttribute = true) + public abstract String getVersion(); + + @Override + @JsonIgnore + public abstract boolean isNativeMethod(); +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/InstantXmlMixIn.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/InstantXmlMixIn.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/InstantXmlMixIn.java new file mode 100644 index 0000000..df5a5ce --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/InstantXmlMixIn.java @@ -0,0 +1,56 @@ +/* + * 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.jackson.xml; + +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.core.time.Instant; +import org.apache.logging.log4j.jackson.InstantMixIn; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +/** + * Jackson mix-in for {@link Instant}. + * <p> + * <em>Consider this class private.</em> + * </p> + * + * @see Marker + */ +abstract class InstantXmlMixIn extends InstantMixIn { + + @JsonCreator + protected InstantXmlMixIn( + // @formatter:off + @JsonProperty(ATTR_EPOCH_SECOND) final long epochSecond, + @JsonProperty(ATTR_NANO_OF_SECOND) final int nanoOfSecond) + // @formatter:on + { + super(epochSecond, nanoOfSecond); + } + + @Override + @JacksonXmlProperty(localName = ATTR_EPOCH_SECOND, isAttribute = true) + public abstract long getEpochSecond(); + + @Override + @JacksonXmlProperty(localName = ATTR_NANO_OF_SECOND, isAttribute = true) + public abstract int getNanoOfSecond(); + +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/Log4jXmlModule.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/Log4jXmlModule.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/Log4jXmlModule.java new file mode 100644 index 0000000..76166b0 --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/Log4jXmlModule.java @@ -0,0 +1,52 @@ +/* + * 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.jackson.xml; + +import org.apache.logging.log4j.jackson.SimpleModuleInitializer; + +import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule; + +/** + * <p> + * <em>Consider this class private.</em> + * </p> + * <p> + * Extends Jackson's {@link JacksonXmlModule} for Log4j XML's specific needs. + * </p> + */ +final class Log4jXmlModule extends JacksonXmlModule { + + private static final long serialVersionUID = 1L; + private final boolean includeStacktrace; + private final boolean stacktraceAsString; + + Log4jXmlModule(final boolean includeStacktrace, final boolean stacktraceAsString) { + super(); + this.includeStacktrace = includeStacktrace; + this.stacktraceAsString = stacktraceAsString; + // MUST init here. + // Calling this from setupModule is too late! + new SimpleModuleInitializer().initialize(this, false); + } + + @Override + public void setupModule(final SetupContext context) { + // Calling super is a MUST! + super.setupModule(context); + new XmlSetupContextInitializer().setupModule(context, includeStacktrace, stacktraceAsString); + } +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/Log4jXmlObjectMapper.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/Log4jXmlObjectMapper.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/Log4jXmlObjectMapper.java new file mode 100644 index 0000000..ec802f4 --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/Log4jXmlObjectMapper.java @@ -0,0 +1,48 @@ +/* + * 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.jackson.xml; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; + +/** + * A Jackson XML {@link ObjectMapper} initialized for Log4j. + * <p> + * <em>Consider this class private.</em> + * </p> + */ +public class Log4jXmlObjectMapper extends XmlMapper { + + private static final long serialVersionUID = 1L; + + /** + * Create a new instance using the {@code Log4jXmlModule}. + */ + public Log4jXmlObjectMapper() { + this(true, false); + } + + /** + * Create a new instance using the {@code Log4jXmlModule}. + */ + public Log4jXmlObjectMapper(final boolean includeStacktrace, final boolean stacktraceAsString) { + super(new Log4jXmlModule(includeStacktrace, stacktraceAsString)); + this.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); + } + +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/LogEventWithContextListXmlMixIn.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/LogEventWithContextListXmlMixIn.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/LogEventWithContextListXmlMixIn.java new file mode 100644 index 0000000..04f1d3d --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/LogEventWithContextListXmlMixIn.java @@ -0,0 +1,48 @@ +/* + * 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.jackson.xml; + +import org.apache.logging.log4j.jackson.ContextDataAsEntryListDeserializer; +import org.apache.logging.log4j.jackson.XmlConstants; +import org.apache.logging.log4j.util.ReadOnlyStringMap; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +/** + * <pre> + * AbstractLogEventMixIn +*ââ AbstractLogEventXmlMixIn +*âââââ LogEventWithContextListXmlMixIn +*âââââ LogEventWithContextMapXmlMixIn +*ââ JsonLogEventMixIn +*âââââ JsonLogEventWithContextListMixIn +*âââââ JsonLogEventWithContextMapMixIn + * </pre> + */ +public abstract class LogEventWithContextListXmlMixIn extends AbstractLogEventXmlMixIn { + + private static final long serialVersionUID = 1L; + + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CONTEXT_MAP) + @JsonSerialize(using = ContextDataAsEntryListXmlSerializer.class) + @JsonDeserialize(using = ContextDataAsEntryListDeserializer.class) + @Override + public abstract ReadOnlyStringMap getContextData(); + +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/MarkerXmlMixIn.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/MarkerXmlMixIn.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/MarkerXmlMixIn.java new file mode 100644 index 0000000..a101ed5 --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/MarkerXmlMixIn.java @@ -0,0 +1,79 @@ +/* + * 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.jackson.xml; + +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.jackson.MarkerMixIn; +import org.apache.logging.log4j.jackson.XmlConstants; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +/** + * Jackson mix-in for {@link Marker}. + * <p> + * If we want to deal with more than one {@link Marker} implementation then recode these annotations to include + * metadata. + * </p> + * <p> + * <em>Consider this class private.</em> + * </p> + * <p> + * Example XML: + * </p> + * + * <pre> +<Marker name="Marker1"> + <Parents> + <Marker name="ParentMarker1"> + <Parents> + <Marker name="GrandMotherMarker"/> + <Marker name="GrandFatherMarker"/> + </Parents> + </Marker> + <Marker name="ParentMarker2"/> + </Parents> +</Marker> + * </pre> + * + * @see Marker + */ +// Alternate for multiple Marker implementation. +// @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class") +@JsonDeserialize(as = org.apache.logging.log4j.MarkerManager.Log4jMarker.class) +abstract class MarkerXmlMixIn extends MarkerMixIn { + public static final String ATTR_NAME = "name"; + private static final long serialVersionUID = 1L; + + @JsonCreator + protected MarkerXmlMixIn(@JsonProperty(ATTR_NAME) final String name) { + super(name); + } + + @Override + @JacksonXmlProperty(isAttribute = true) + public abstract String getName(); + + @Override + @JacksonXmlElementWrapper(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_PARENTS) + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_MARKER) + public abstract Marker[] getParents(); + +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/StackTraceElementXmlMixIn.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/StackTraceElementXmlMixIn.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/StackTraceElementXmlMixIn.java new file mode 100644 index 0000000..93a3a45 --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/StackTraceElementXmlMixIn.java @@ -0,0 +1,40 @@ +package org.apache.logging.log4j.jackson.xml; + +import org.apache.logging.log4j.jackson.StackTraceElementConstants; +import org.apache.logging.log4j.jackson.StackTraceElementMixIn; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +abstract class StackTraceElementXmlMixIn extends StackTraceElementMixIn { + + @JsonCreator + protected StackTraceElementXmlMixIn( + // @formatter:off + @JsonProperty(StackTraceElementConstants.ATTR_CLASS) final String declaringClass, + @JsonProperty(StackTraceElementConstants.ATTR_METHOD) final String methodName, + @JsonProperty(StackTraceElementConstants.ATTR_FILE) final String fileName, + @JsonProperty(StackTraceElementConstants.ATTR_LINE) final int lineNumber) + // @formatter:on + { + super(declaringClass, methodName, fileName, lineNumber); + } + + @Override + @JacksonXmlProperty(localName = StackTraceElementConstants.ATTR_CLASS, isAttribute = true) + protected abstract String getClassName(); + + @Override + @JacksonXmlProperty(localName = StackTraceElementConstants.ATTR_FILE, isAttribute = true) + protected abstract String getFileName(); + + @Override + @JacksonXmlProperty(localName = StackTraceElementConstants.ATTR_LINE, isAttribute = true) + protected abstract int getLineNumber(); + + @Override + @JacksonXmlProperty(localName = StackTraceElementConstants.ATTR_METHOD, isAttribute = true) + protected abstract String getMethodName(); + +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithStacktraceAsStringXmlMixIn.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithStacktraceAsStringXmlMixIn.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithStacktraceAsStringXmlMixIn.java new file mode 100644 index 0000000..9cc85c3 --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithStacktraceAsStringXmlMixIn.java @@ -0,0 +1,77 @@ +/* + * 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.jackson.xml; + +import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; +import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.jackson.ThrowableProxyWithStacktraceAsStringMixIn; +import org.apache.logging.log4j.jackson.XmlConstants; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +public abstract class ThrowableProxyWithStacktraceAsStringXmlMixIn extends ThrowableProxyWithStacktraceAsStringMixIn { + + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CAUSE) + private ThrowableProxyWithStacktraceAsStringMixIn causeProxy; + + @JacksonXmlProperty(isAttribute = true) + private int commonElementCount; + + @JsonIgnore + private ExtendedStackTraceElement[] extendedStackTrace; + + @JacksonXmlProperty(isAttribute = true) + private String localizedMessage; + + @JacksonXmlProperty(isAttribute = true) + private String message; + + @JacksonXmlProperty(isAttribute = true) + private String name; + + @JsonIgnore + private transient Throwable throwable; + + @Override + @JsonIgnore + public abstract String getCauseStackTraceAsString(); + + @Override + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_EXTENDED_STACK_TRACE) + public abstract String getExtendedStackTraceAsString(); + + @Override + @JsonIgnore + public abstract StackTraceElement[] getStackTrace(); + + @Override + @JacksonXmlElementWrapper(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_SUPPRESSED) + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_SUPPRESSED_ITEM) + public abstract ThrowableProxy[] getSuppressedProxies(); + + @Override + @JsonIgnore + public abstract String getSuppressedStackTrace(); + + @Override + @JsonIgnore + public abstract Throwable getThrowable(); + +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithoutStacktraceXmlMixIn.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithoutStacktraceXmlMixIn.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithoutStacktraceXmlMixIn.java new file mode 100644 index 0000000..4ecffae --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyWithoutStacktraceXmlMixIn.java @@ -0,0 +1,60 @@ +package org.apache.logging.log4j.jackson.xml; + +import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; +import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.jackson.ThrowableProxyWithoutStacktraceMixIn; +import org.apache.logging.log4j.jackson.XmlConstants; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +public abstract class ThrowableProxyWithoutStacktraceXmlMixIn extends ThrowableProxyWithoutStacktraceMixIn { + + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CAUSE) + private ThrowableProxyWithoutStacktraceMixIn causeProxy; + + @JacksonXmlProperty(isAttribute = true) + private int commonElementCount; + + @JsonIgnore + private ExtendedStackTraceElement[] extendedStackTrace; + + @JacksonXmlProperty(isAttribute = true) + private String localizedMessage; + + @JacksonXmlProperty(isAttribute = true) + private String message; + + @JacksonXmlProperty(isAttribute = true) + private String name; + + @JsonIgnore + private transient Throwable throwable; + + @Override + @JsonIgnore + public abstract String getCauseStackTraceAsString(); + + @Override + @JsonIgnore + public abstract String getExtendedStackTraceAsString(); + + @Override + @JsonIgnore + public abstract StackTraceElement[] getStackTrace(); + + @Override + @JacksonXmlElementWrapper(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_SUPPRESSED) + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_SUPPRESSED_ITEM) + public abstract ThrowableProxy[] getSuppressedProxies(); + + @Override + @JsonIgnore + public abstract String getSuppressedStackTrace(); + + @Override + @JsonIgnore + public abstract Throwable getThrowable(); + +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyXmlMixIn.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyXmlMixIn.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyXmlMixIn.java new file mode 100644 index 0000000..b52f7f6 --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/ThrowableProxyXmlMixIn.java @@ -0,0 +1,78 @@ +/* + * 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.jackson.xml; + +import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; +import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.jackson.ThrowableProxyMixIn; +import org.apache.logging.log4j.jackson.XmlConstants; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +public abstract class ThrowableProxyXmlMixIn extends ThrowableProxyMixIn { + + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_CAUSE) + private ThrowableProxyMixIn causeProxy; + + @JacksonXmlProperty(isAttribute = true) + private int commonElementCount; + + @JacksonXmlElementWrapper(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_EXTENDED_STACK_TRACE) + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_EXTENDED_STACK_TRACE_ITEM) + private ExtendedStackTraceElement[] extendedStackTrace; + + @JacksonXmlProperty(isAttribute = true) + private String localizedMessage; + + @JacksonXmlProperty(isAttribute = true) + private String message; + + @JacksonXmlProperty(isAttribute = true) + private String name; + + @JsonIgnore + private transient Throwable throwable; + + @Override + @JsonIgnore + public abstract String getCauseStackTraceAsString(); + + @Override + @JsonIgnore + public abstract String getExtendedStackTraceAsString(); + + @Override + @JsonIgnore + public abstract StackTraceElement[] getStackTrace(); + + @Override + @JacksonXmlElementWrapper(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_SUPPRESSED) + @JacksonXmlProperty(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_SUPPRESSED_ITEM) + public abstract ThrowableProxy[] getSuppressedProxies(); + + @Override + @JsonIgnore + public abstract String getSuppressedStackTrace(); + + @Override + @JsonIgnore + public abstract Throwable getThrowable(); + +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/XmlMapEntry.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/XmlMapEntry.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/XmlMapEntry.java new file mode 100644 index 0000000..2500c11 --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/XmlMapEntry.java @@ -0,0 +1,41 @@ +/* + * 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.jackson.xml; + +import org.apache.logging.log4j.jackson.MapEntry; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +@JsonPropertyOrder({ "key", "value" }) +class XmlMapEntry extends MapEntry { + + @JacksonXmlProperty(isAttribute = true) + private String key; + + @JacksonXmlProperty(isAttribute = true) + private String value; + + @JsonCreator + public XmlMapEntry(@JsonProperty("key") final String key, @JsonProperty("value") final String value) { + super(key, value); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/XmlSetupContextInitializer.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/XmlSetupContextInitializer.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/XmlSetupContextInitializer.java new file mode 100644 index 0000000..4cc5124 --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/XmlSetupContextInitializer.java @@ -0,0 +1,38 @@ +package org.apache.logging.log4j.jackson.xml; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.impl.ExtendedStackTraceElement; +import org.apache.logging.log4j.core.impl.ThrowableProxy; +import org.apache.logging.log4j.core.time.Instant; +import org.apache.logging.log4j.jackson.LevelMixIn; + +import com.fasterxml.jackson.databind.Module.SetupContext; +import com.fasterxml.jackson.databind.module.SimpleModule; + +/** + * Used to set up {@link SetupContext} from different {@link SimpleModule}s. + * <p> + * <em>Consider this class private.</em> + * </p> + */ +class XmlSetupContextInitializer { + + public void setupModule(final SetupContext context, final boolean includeStacktrace, + final boolean stacktraceAsString) { + // JRE classes: we cannot edit those with Jackson annotations + context.setMixInAnnotations(StackTraceElement.class, StackTraceElementXmlMixIn.class); + // Log4j API classes: we do not want to edit those with Jackson annotations because the API module should not + // depend on Jackson. + context.setMixInAnnotations(Marker.class, MarkerXmlMixIn.class); + context.setMixInAnnotations(Level.class, LevelMixIn.class); + context.setMixInAnnotations(Instant.class, InstantXmlMixIn.class); + context.setMixInAnnotations(LogEvent.class, LogEventWithContextListXmlMixIn.class); + // Log4j Core classes: we do not want to bring in Jackson at runtime if we do not have to. + context.setMixInAnnotations(ExtendedStackTraceElement.class, ExtendedStackTraceElementXmlMixIn.class); + context.setMixInAnnotations(ThrowableProxy.class, includeStacktrace + ? (stacktraceAsString ? ThrowableProxyWithStacktraceAsStringXmlMixIn.class : ThrowableProxyXmlMixIn.class) + : ThrowableProxyWithoutStacktraceXmlMixIn.class); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/Log4jXmlPrettyPrinter.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/Log4jXmlPrettyPrinter.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/Log4jXmlPrettyPrinter.java new file mode 100644 index 0000000..6956861 --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/Log4jXmlPrettyPrinter.java @@ -0,0 +1,41 @@ +package org.apache.logging.log4j.jackson.xml.layout; + +import javax.xml.stream.XMLStreamException; + +import org.codehaus.stax2.XMLStreamWriter2; + +import com.fasterxml.jackson.dataformat.xml.util.DefaultXmlPrettyPrinter; + +/** + * When <Event>s are written into a XML file; the "Event" object is not the root element, but an element named + * <Events> created using {@link XmlLayout#getHeader()} and {@link XmlLayout#getFooter()} methods. + * <p> + * {@link com.fasterxml.jackson.dataformat.xml.util.DefaultXmlPrettyPrinter} is used to print the Event object into + * XML; hence it assumes <Event> tag as the root element, so it prints the <Event> tag without any + * indentation. To add an indentation to the <Event> tag; hence an additional indentation for any + * sub-elements, this class is written. As an additional task, to avoid the blank line printed after the ending + * </Event> tag, the {@code #writePrologLinefeed(XMLStreamWriter2)} method is also overridden. + * </p> + */ +class Log4jXmlPrettyPrinter extends DefaultXmlPrettyPrinter { + + private static final long serialVersionUID = 1L; + + Log4jXmlPrettyPrinter(final int nesting) { + _nesting = nesting; + } + + /** + * Sets the nesting level to 1 rather than 0, so the "Event" tag will get indentation of next level below root. + */ + @Override + public DefaultXmlPrettyPrinter createInstance() { + return new Log4jXmlPrettyPrinter(XmlJacksonFactory.DEFAULT_INDENT); + } + + @Override + public void writePrologLinefeed(final XMLStreamWriter2 sw) throws XMLStreamException { + // nothing + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlJacksonFactory.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlJacksonFactory.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlJacksonFactory.java new file mode 100644 index 0000000..0cfba5b --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlJacksonFactory.java @@ -0,0 +1,54 @@ +package org.apache.logging.log4j.jackson.xml.layout; + +import org.apache.logging.log4j.jackson.AbstractJacksonFactory; +import org.apache.logging.log4j.jackson.JsonConstants; +import org.apache.logging.log4j.jackson.XmlConstants; +import org.apache.logging.log4j.jackson.xml.Log4jXmlObjectMapper; + +import com.fasterxml.jackson.core.PrettyPrinter; +import com.fasterxml.jackson.databind.ObjectMapper; + +class XmlJacksonFactory extends AbstractJacksonFactory { + + static final int DEFAULT_INDENT = 1; + + public XmlJacksonFactory(final boolean includeStacktrace, final boolean stacktraceAsString) { + super(includeStacktrace, stacktraceAsString); + } + + @Override + protected String getPropertyNameForContextMap() { + return XmlConstants.ELT_CONTEXT_MAP; + } + + @Override + protected String getPropertyNameForNanoTime() { + return JsonConstants.ELT_NANO_TIME; + } + + @Override + protected String getPropertyNameForSource() { + return XmlConstants.ELT_SOURCE; + } + + @Override + protected String getPropertyNameForStackTrace() { + return XmlConstants.ELT_EXTENDED_STACK_TRACE; + } + + @Override + protected PrettyPrinter newCompactPrinter() { + // Yes, null is the proper answer. + return null; + } + + @Override + protected ObjectMapper newObjectMapper() { + return new Log4jXmlObjectMapper(includeStacktrace, stacktraceAsString); + } + + @Override + protected PrettyPrinter newPrettyPrinter() { + return new Log4jXmlPrettyPrinter(DEFAULT_INDENT); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0eb5212e/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayout.java ---------------------------------------------------------------------- diff --git a/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayout.java b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayout.java new file mode 100644 index 0000000..6d723b0 --- /dev/null +++ b/log4j-layout-jackson-xml/src/main/java/org/apache/logging/log4j/jackson/xml/layout/XmlLayout.java @@ -0,0 +1,226 @@ +/* + * 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.jackson.xml.layout; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.Node; +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; +import org.apache.logging.log4j.core.util.KeyValuePair; +import org.apache.logging.log4j.jackson.AbstractJacksonLayout; +import org.apache.logging.log4j.jackson.XmlConstants; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Appends a series of {@code event} elements as defined in the <a href="log4j.dtd">log4j.dtd</a>. + * + * <h3>Complete well-formed XML vs. fragment XML</h3> + * <p> + * If you configure {@code complete="true"}, the appender outputs a well-formed XML document where the default namespace + * is the log4j namespace {@value XmlConstants#XML_NAMESPACE}. By default, with {@code complete="false"}, you should + * include the output as an <em>external entity</em> in a separate file to form a well-formed XML document. + * </p> + * <p> + * If {@code complete="false"}, the appender does not write the XML processing instruction and the root element. + * </p> + * <h3>Encoding</h3> + * <p> + * Appenders using this layout should have their {@code charset} set to {@code UTF-8} or {@code UTF-16}, otherwise + * events containing non-ASCII characters could result in corrupted log files. + * </p> + * <h3>Pretty vs. compact XML</h3> + * <p> + * By default, the XML layout is not compact (compact = not "pretty") with {@code compact="false"}, which means the + * appender uses end-of-line characters and indents lines to format the XML. If {@code compact="true"}, then no + * end-of-line or indentation is used. Message content may contain, of course, end-of-lines. + * </p> + * <h3>Additional Fields</h3> + * <p> + * This property allows addition of custom fields into generated JSON. + * {@code <XmlLayout><KeyValuePair key="foo" value="bar"/></XmlLayout>} inserts {@code <foo>bar</foo>} directly into XML + * output. Supports Lookup expressions. + * </p> + */ +@Plugin(name = "XmlLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true) +public final class XmlLayout extends AbstractJacksonLayout { + + public static class Builder<B extends Builder<B>> extends AbstractJacksonLayout.Builder<B> + implements org.apache.logging.log4j.core.util.Builder<XmlLayout> { + + public Builder() { + super(); + setCharset(StandardCharsets.UTF_8); + } + + @Override + public XmlLayout build() { + return new XmlLayout(getConfiguration(), isLocationInfo(), isProperties(), isComplete(), isCompact(), + getCharset(), isIncludeStacktrace(), isStacktraceAsString(), isIncludeNullDelimiter(), + getAdditionalFields()); + } + } + + @JacksonXmlRootElement(namespace = XmlConstants.XML_NAMESPACE, localName = XmlConstants.ELT_EVENT) + public static class XmlLogEventWithAdditionalFields extends LogEventWithAdditionalFields { + + public XmlLogEventWithAdditionalFields(final Object logEvent, final Map<String, String> additionalFields) { + super(logEvent, additionalFields); + } + + } + + private static final String ROOT_TAG = "Events"; + + /** + * Creates an XML Layout using the default settings. + * + * @return an XML Layout. + */ + public static XmlLayout createDefaultLayout() { + return new XmlLayout(null, false, false, false, false, StandardCharsets.UTF_8, true, false, false, null); + } + + /** + * Creates an XML Layout. + * + * @param locationInfo + * If "true", includes the location information in the generated XML. + * @param properties + * If "true", includes the thread context map in the generated XML. + * @param complete + * If "true", includes the XML header and footer, defaults to "false". + * @param compact + * If "true", does not use end-of-lines and indentation, defaults to "false". + * @param charset + * The character set to use, if {@code null}, uses "UTF-8". + * @param includeStacktrace + * If "true", includes the stacktrace of any Throwable in the generated XML, defaults to "true". + * @return An XML Layout. + * + * @deprecated Use {@link #newBuilder()} instead + */ + @Deprecated + public static XmlLayout createLayout(final boolean locationInfo, final boolean properties, final boolean complete, + final boolean compact, final Charset charset, final boolean includeStacktrace) { + return new XmlLayout(null, locationInfo, properties, complete, compact, charset, includeStacktrace, false, + false, null); + } + + @PluginBuilderFactory + public static <B extends Builder<B>> B newBuilder() { + return new Builder<B>().asBuilder(); + } + + /** + * @deprecated Use {@link #newBuilder()} instead + */ + @Deprecated + protected XmlLayout(final boolean locationInfo, final boolean properties, final boolean complete, + final boolean compact, final Charset charset, final boolean includeStacktrace) { + this(null, locationInfo, properties, complete, compact, charset, includeStacktrace, false, false, null); + } + + private XmlLayout(final Configuration config, final boolean locationInfo, final boolean properties, + final boolean complete, final boolean compact, final Charset charset, final boolean includeStacktrace, + final boolean stacktraceAsString, final boolean includeNullDelimiter, + final KeyValuePair[] additionalFields) { + super(config, + new XmlJacksonFactory(includeStacktrace, stacktraceAsString).newWriter(locationInfo, properties, + compact), + charset, compact, complete, false, null, null, includeNullDelimiter, additionalFields); + } + + @Override + protected LogEventWithAdditionalFields createLogEventWithAdditionalFields(final LogEvent event, + final Map<String, String> additionalFieldsMap) { + return new XmlLogEventWithAdditionalFields(event, additionalFieldsMap); + } + + /** + * Gets this XmlLayout's content format. Specified by: + * <ul> + * <li>Key: "dtd" Value: "log4j-events.dtd"</li> + * <li>Key: "version" Value: "2.0"</li> + * </ul> + * + * @return Map of content format keys supporting XmlLayout + */ + @Override + public Map<String, String> getContentFormat() { + final Map<String, String> result = new HashMap<>(); + // result.put("dtd", "log4j-events.dtd"); + result.put("xsd", "log4j-events.xsd"); + result.put("version", "2.0"); + return result; + } + + /** + * @return The content type. + */ + @Override + public String getContentType() { + return "text/xml; charset=" + this.getCharset(); + } + + /** + * Returns appropriate XML footer. + * + * @return a byte array containing the footer, closing the XML root element. + */ + @Override + public byte[] getFooter() { + if (!complete) { + return null; + } + return getBytes("</" + ROOT_TAG + '>' + this.eol); + } + + /** + * Returns appropriate XML headers. + * <ol> + * <li>XML processing instruction</li> + * <li>XML root element</li> + * </ol> + * + * @return a byte array containing the header. + */ + @Override + public byte[] getHeader() { + if (!complete) { + return null; + } + final StringBuilder buf = new StringBuilder(); + buf.append("<?xml version=\"1.0\" encoding=\""); + buf.append(this.getCharset().name()); + buf.append("\"?>"); + buf.append(this.eol); + // Make the log4j namespace the default namespace, no need to use more space with a namespace prefix. + buf.append('<'); + buf.append(ROOT_TAG); + buf.append(" xmlns=\"" + XmlConstants.XML_NAMESPACE + "\">"); + buf.append(this.eol); + return buf.toString().getBytes(this.getCharset()); + } +}
