You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by pk...@apache.org on 2022/03/29 14:05:36 UTC

[logging-log4j2] 16/25: Add missing util classes in org.apache.log4j.pattern.

This is an automated email from the ASF dual-hosted git repository.

pkarwasz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit a129b245a1a1507b82170d667a29c559b522025b
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sat Feb 5 16:29:12 2022 -0500

    Add missing util classes in org.apache.log4j.pattern.
    
    - Log4j 1.2 bridge missed org.apache.log4j.pattern.FormattingInfo.
    - Log4j 1.2 bridge missed org.apache.log4j.pattern.NameAbbreviator.
---
 .../org/apache/log4j/pattern/FormattingInfo.java   | 128 ++++++++
 .../org/apache/log4j/pattern/NameAbbreviator.java  | 345 +++++++++++++++++++++
 .../apache/log4j/pattern/FormattingInfoTest.java   |  92 ++++++
 .../apache/log4j/pattern/NameAbbreviatorTest.java  | 329 ++++++++++++++++++++
 src/changes/changes.xml                            |   9 +
 5 files changed, 903 insertions(+)

diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/pattern/FormattingInfo.java b/log4j-1.2-api/src/main/java/org/apache/log4j/pattern/FormattingInfo.java
new file mode 100644
index 0000000..d8faaf4
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/pattern/FormattingInfo.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.pattern;
+
+/**
+ * Modifies the output of a pattern converter for a specified minimum and maximum width and alignment.
+ */
+public final class FormattingInfo {
+    /**
+     * Array of spaces.
+     */
+    private static final char[] SPACES = new char[] {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '};
+
+    /**
+     * Default instance.
+     */
+    private static final FormattingInfo DEFAULT = new FormattingInfo(false, 0, Integer.MAX_VALUE);
+
+    /**
+     * Gets default instance.
+     *
+     * @return default instance.
+     */
+    public static FormattingInfo getDefault() {
+        return DEFAULT;
+    }
+
+    /**
+     * Minimum length.
+     */
+    private final int minLength;
+
+    /**
+     * Maximum length.
+     */
+    private final int maxLength;
+
+    /**
+     * Alignment.
+     */
+    private final boolean leftAlign;
+
+    /**
+     * Creates new instance.
+     *
+     * @param leftAlign left align if true.
+     * @param minLength minimum length.
+     * @param maxLength maximum length.
+     */
+    public FormattingInfo(final boolean leftAlign, final int minLength, final int maxLength) {
+        this.leftAlign = leftAlign;
+        this.minLength = minLength;
+        this.maxLength = maxLength;
+    }
+
+    /**
+     * Adjust the content of the buffer based on the specified lengths and alignment.
+     *
+     * @param fieldStart start of field in buffer.
+     * @param buffer buffer to be modified.
+     */
+    public void format(final int fieldStart, final StringBuffer buffer) {
+        final int rawLength = buffer.length() - fieldStart;
+
+        if (rawLength > maxLength) {
+            buffer.delete(fieldStart, buffer.length() - maxLength);
+        } else if (rawLength < minLength) {
+            if (leftAlign) {
+                final int fieldEnd = buffer.length();
+                buffer.setLength(fieldStart + minLength);
+
+                for (int i = fieldEnd; i < buffer.length(); i++) {
+                    buffer.setCharAt(i, ' ');
+                }
+            } else {
+                int padLength = minLength - rawLength;
+
+                for (; padLength > 8; padLength -= 8) {
+                    buffer.insert(fieldStart, SPACES);
+                }
+
+                buffer.insert(fieldStart, SPACES, 0, padLength);
+            }
+        }
+    }
+
+    /**
+     * Get maximum length.
+     *
+     * @return maximum length.
+     */
+    public int getMaxLength() {
+        return maxLength;
+    }
+
+    /**
+     * Get minimum length.
+     *
+     * @return minimum length.
+     */
+    public int getMinLength() {
+        return minLength;
+    }
+
+    /**
+     * Determine if left aligned.
+     *
+     * @return true if left aligned.
+     */
+    public boolean isLeftAligned() {
+        return leftAlign;
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/pattern/NameAbbreviator.java b/log4j-1.2-api/src/main/java/org/apache/log4j/pattern/NameAbbreviator.java
new file mode 100644
index 0000000..8905ecb
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/pattern/NameAbbreviator.java
@@ -0,0 +1,345 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.pattern;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * NameAbbreviator generates abbreviated logger and class names.
+ */
+public abstract class NameAbbreviator {
+
+    /**
+     * Abbreviator that drops starting path elements.
+     */
+    private static class DropElementAbbreviator extends NameAbbreviator {
+        /**
+         * Maximum number of path elements to output.
+         */
+        private final int count;
+
+        /**
+         * Create new instance.
+         *
+         * @param count maximum number of path elements to output.
+         */
+        public DropElementAbbreviator(final int count) {
+            this.count = count;
+        }
+
+        /**
+         * Abbreviate name.
+         *
+         * @param buf buffer to append abbreviation.
+         * @param nameStart start of name to abbreviate.
+         */
+        @Override
+        public void abbreviate(final int nameStart, final StringBuffer buf) {
+            int i = count;
+            for (int pos = buf.indexOf(".", nameStart); pos != -1; pos = buf.indexOf(".", pos + 1)) {
+                if (--i == 0) {
+                    buf.delete(nameStart, pos + 1);
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Abbreviator that drops starting path elements.
+     */
+    private static class MaxElementAbbreviator extends NameAbbreviator {
+        /**
+         * Maximum number of path elements to output.
+         */
+        private final int count;
+
+        /**
+         * Create new instance.
+         *
+         * @param count maximum number of path elements to output.
+         */
+        public MaxElementAbbreviator(final int count) {
+            this.count = count;
+        }
+
+        /**
+         * Abbreviate name.
+         *
+         * @param buf buffer to append abbreviation.
+         * @param nameStart start of name to abbreviate.
+         */
+        @Override
+        public void abbreviate(final int nameStart, final StringBuffer buf) {
+            // We substract 1 from 'len' when assigning to 'end' to avoid out of
+            // bounds exception in return r.substring(end+1, len). This can happen if
+            // precision is 1 and the category name ends with a dot.
+            int end = buf.length() - 1;
+
+            final String bufString = buf.toString();
+            for (int i = count; i > 0; i--) {
+                end = bufString.lastIndexOf(".", end - 1);
+
+                if ((end == -1) || (end < nameStart)) {
+                    return;
+                }
+            }
+
+            buf.delete(nameStart, end + 1);
+        }
+    }
+
+    /**
+     * Abbreviator that simply appends full name to buffer.
+     */
+    private static class NOPAbbreviator extends NameAbbreviator {
+        /**
+         * Constructor.
+         */
+        public NOPAbbreviator() {
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void abbreviate(final int nameStart, final StringBuffer buf) {
+        }
+    }
+
+    /**
+     * Pattern abbreviator.
+     *
+     *
+     */
+    private static class PatternAbbreviator extends NameAbbreviator {
+        /**
+         * Element abbreviation patterns.
+         */
+        private final PatternAbbreviatorFragment[] fragments;
+
+        /**
+         * Create PatternAbbreviator.
+         *
+         * @param fragments element abbreviation patterns.
+         */
+        public PatternAbbreviator(final List fragments) {
+            if (fragments.size() == 0) {
+                throw new IllegalArgumentException("fragments must have at least one element");
+            }
+
+            this.fragments = new PatternAbbreviatorFragment[fragments.size()];
+            fragments.toArray(this.fragments);
+        }
+
+        /**
+         * Abbreviate name.
+         *
+         * @param buf buffer that abbreviated name is appended.
+         * @param nameStart start of name.
+         */
+        @Override
+        public void abbreviate(final int nameStart, final StringBuffer buf) {
+            //
+            // all non-terminal patterns are executed once
+            //
+            int pos = nameStart;
+
+            for (int i = 0; (i < (fragments.length - 1)) && (pos < buf.length()); i++) {
+                pos = fragments[i].abbreviate(buf, pos);
+            }
+
+            //
+            // last pattern in executed repeatedly
+            //
+            final PatternAbbreviatorFragment terminalFragment = fragments[fragments.length - 1];
+
+            while ((pos < buf.length()) && (pos >= 0)) {
+                pos = terminalFragment.abbreviate(buf, pos);
+            }
+        }
+    }
+
+    /**
+     * Fragment of an pattern abbreviator.
+     *
+     */
+    private static class PatternAbbreviatorFragment {
+        /**
+         * Count of initial characters of element to output.
+         */
+        private final int charCount;
+
+        /**
+         * Character used to represent dropped characters. '\0' indicates no representation of dropped characters.
+         */
+        private final char ellipsis;
+
+        /**
+         * Creates a PatternAbbreviatorFragment.
+         *
+         * @param charCount number of initial characters to preserve.
+         * @param ellipsis character to represent elimination of characters, '\0' if no ellipsis is desired.
+         */
+        public PatternAbbreviatorFragment(final int charCount, final char ellipsis) {
+            this.charCount = charCount;
+            this.ellipsis = ellipsis;
+        }
+
+        /**
+         * Abbreviate element of name.
+         *
+         * @param buf buffer to receive element.
+         * @param startPos starting index of name element.
+         * @return starting index of next element.
+         */
+        public int abbreviate(final StringBuffer buf, final int startPos) {
+            int nextDot = buf.toString().indexOf(".", startPos);
+
+            if (nextDot != -1) {
+                if ((nextDot - startPos) > charCount) {
+                    buf.delete(startPos + charCount, nextDot);
+                    nextDot = startPos + charCount;
+
+                    if (ellipsis != '\0') {
+                        buf.insert(nextDot, ellipsis);
+                        nextDot++;
+                    }
+                }
+
+                nextDot++;
+            }
+
+            return nextDot;
+        }
+    }
+
+    /**
+     * Default (no abbreviation) abbreviator.
+     */
+    private static final NameAbbreviator DEFAULT = new NOPAbbreviator();
+
+    /**
+     * Gets an abbreviator.
+     *
+     * For example, "%logger{2}" will output only 2 elements of the logger name, %logger{-2} will drop 2 elements from the
+     * logger name, "%logger{1.}" will output only the first character of the non-final elements in the name,
+     * "%logger{1~.2~} will output the first character of the first element, two characters of the second and subsequent
+     * elements and will use a tilde to indicate abbreviated characters.
+     *
+     * @param pattern abbreviation pattern.
+     * @return abbreviator, will not be null.
+     */
+    public static NameAbbreviator getAbbreviator(final String pattern) {
+        if (pattern.length() > 0) {
+            // if pattern is just spaces and numbers then
+            // use MaxElementAbbreviator
+            final String trimmed = pattern.trim();
+
+            if (trimmed.length() == 0) {
+                return DEFAULT;
+            }
+
+            int i = 0;
+            if (trimmed.length() > 0) {
+                if (trimmed.charAt(0) == '-') {
+                    i++;
+                }
+                for (; (i < trimmed.length()) && (trimmed.charAt(i) >= '0') && (trimmed.charAt(i) <= '9'); i++) {
+                }
+            }
+
+            //
+            // if all blanks and digits
+            //
+            if (i == trimmed.length()) {
+                final int elements = Integer.parseInt(trimmed);
+                if (elements >= 0) {
+                    return new MaxElementAbbreviator(elements);
+                } else {
+                    return new DropElementAbbreviator(-elements);
+                }
+            }
+
+            final ArrayList fragments = new ArrayList(5);
+            char ellipsis;
+            int charCount;
+            int pos = 0;
+
+            while ((pos < trimmed.length()) && (pos >= 0)) {
+                int ellipsisPos = pos;
+
+                if (trimmed.charAt(pos) == '*') {
+                    charCount = Integer.MAX_VALUE;
+                    ellipsisPos++;
+                } else {
+                    if ((trimmed.charAt(pos) >= '0') && (trimmed.charAt(pos) <= '9')) {
+                        charCount = trimmed.charAt(pos) - '0';
+                        ellipsisPos++;
+                    } else {
+                        charCount = 0;
+                    }
+                }
+
+                ellipsis = '\0';
+
+                if (ellipsisPos < trimmed.length()) {
+                    ellipsis = trimmed.charAt(ellipsisPos);
+
+                    if (ellipsis == '.') {
+                        ellipsis = '\0';
+                    }
+                }
+
+                fragments.add(new PatternAbbreviatorFragment(charCount, ellipsis));
+                pos = trimmed.indexOf(".", pos);
+
+                if (pos == -1) {
+                    break;
+                }
+
+                pos++;
+            }
+
+            return new PatternAbbreviator(fragments);
+        }
+
+        //
+        // no matching abbreviation, return defaultAbbreviator
+        //
+        return DEFAULT;
+    }
+
+    /**
+     * Gets default abbreviator.
+     *
+     * @return default abbreviator.
+     */
+    public static NameAbbreviator getDefaultAbbreviator() {
+        return DEFAULT;
+    }
+
+    /**
+     * Abbreviates a name in a StringBuffer.
+     *
+     * @param nameStart starting position of name in buf.
+     * @param buf buffer, may not be null.
+     */
+    public abstract void abbreviate(final int nameStart, final StringBuffer buf);
+}
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/pattern/FormattingInfoTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/pattern/FormattingInfoTest.java
new file mode 100644
index 0000000..d4a396d
--- /dev/null
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/pattern/FormattingInfoTest.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.pattern;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for FormattingInfo.
+ *
+ * @author Curt Arnold
+ *
+ */
+public class FormattingInfoTest extends TestCase {
+    /**
+     * Create a new instance.
+     *
+     * @param name test name
+     */
+    public FormattingInfoTest(final String name) {
+        super(name);
+    }
+
+    /**
+     * Check constructor
+     *
+     */
+    public void testConstructor() {
+        FormattingInfo field = new FormattingInfo(true, 3, 6);
+        assertNotNull(field);
+        assertEquals(3, field.getMinLength());
+        assertEquals(6, field.getMaxLength());
+        assertEquals(true, field.isLeftAligned());
+    }
+
+    /**
+     * Check that getDefault does not return null.
+     *
+     */
+    public void testGetDefault() {
+        FormattingInfo field = FormattingInfo.getDefault();
+        assertNotNull(field);
+        assertEquals(0, field.getMinLength());
+        assertEquals(Integer.MAX_VALUE, field.getMaxLength());
+        assertEquals(false, field.isLeftAligned());
+    }
+
+    /**
+     * Add padding to left since field is not minimum width.
+     */
+    public void testPadLeft() {
+        StringBuffer buf = new StringBuffer("foobar");
+        FormattingInfo field = new FormattingInfo(false, 5, 10);
+        field.format(2, buf);
+        assertEquals("fo obar", buf.toString());
+    }
+
+    /**
+     * Add padding to right since field is not minimum width.
+     */
+    public void testPadRight() {
+        StringBuffer buf = new StringBuffer("foobar");
+        FormattingInfo field = new FormattingInfo(true, 5, 10);
+        field.format(2, buf);
+        assertEquals("foobar ", buf.toString());
+    }
+
+    /**
+     * Field exceeds maximum width
+     */
+    public void testTruncate() {
+        StringBuffer buf = new StringBuffer("foobar");
+        FormattingInfo field = new FormattingInfo(true, 0, 3);
+        field.format(2, buf);
+        assertEquals("fobar", buf.toString());
+    }
+
+}
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/pattern/NameAbbreviatorTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/pattern/NameAbbreviatorTest.java
new file mode 100644
index 0000000..5494a59
--- /dev/null
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/pattern/NameAbbreviatorTest.java
@@ -0,0 +1,329 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.pattern;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for NameAbbrevator.
+ *
+ */
+public class NameAbbreviatorTest extends TestCase {
+    /**
+     * Create a new instance.
+     *
+     * @param name test name
+     */
+    public NameAbbreviatorTest(final String name) {
+        super(name);
+    }
+
+    /**
+     * Check that getAbbreviator(" ") returns default abbreviator.
+     *
+     */
+    public void testBlank() {
+        NameAbbreviator abbrev = NameAbbreviator.getAbbreviator("   ");
+        NameAbbreviator defaultAbbrev = NameAbbreviator.getDefaultAbbreviator();
+        assertTrue(abbrev == defaultAbbrev);
+    }
+
+    /**
+     * Check that blanks are trimmed in evaluating abbreviation pattern.
+     */
+    public void testBlankOne() {
+        NameAbbreviator abbrev = NameAbbreviator.getAbbreviator(" 1 ");
+        StringBuffer buf = new StringBuffer("DEBUG - ");
+        int fieldStart = buf.length();
+        buf.append("org.example.foo.bar");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - bar", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        buf.append("bar");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - bar", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - ", buf.toString());
+    }
+
+    /**
+     * Check that getDefaultAbbreviator does not return null.
+     *
+     */
+    public void testGetDefault() {
+        NameAbbreviator abbrev = NameAbbreviator.getDefaultAbbreviator();
+        assertNotNull(abbrev);
+    }
+
+    /**
+     * Check that getAbbreviator("-1").abbreviate() drops first name element.
+     *
+     */
+    public void testMinusOne() {
+        NameAbbreviator abbrev = NameAbbreviator.getAbbreviator("-1");
+        StringBuffer buf = new StringBuffer("DEBUG - ");
+        int fieldStart = buf.length();
+        buf.append("org.example.foo.bar");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - example.foo.bar", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        buf.append("bar");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - bar", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - ", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        buf.append(".");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - ", buf.toString());
+
+    }
+
+    /**
+     * Check that getAbbreviator("1.*.2").abbreviate drops all but the first character from the first element, uses all of
+     * the second element and drops all but the first two characters of the rest of the non-final elements.
+     *
+     */
+    public void testMulti() {
+        NameAbbreviator abbrev = NameAbbreviator.getAbbreviator("1.*.2");
+        StringBuffer buf = new StringBuffer("DEBUG - ");
+        int fieldStart = buf.length();
+        buf.append("org.example.foo.bar");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - o.example.fo.bar", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        buf.append("org.example.foo.");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - o.example.fo.", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        buf.append("foo.bar");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - f.bar", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        buf.append("bar");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - bar", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - ", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        buf.append(".");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - .", buf.toString());
+    }
+
+    /**
+     * Check that getAbbreviator("1").abbreviate() drops all but the final name element.
+     *
+     */
+    public void testOne() {
+        NameAbbreviator abbrev = NameAbbreviator.getAbbreviator("1");
+        StringBuffer buf = new StringBuffer("DEBUG - ");
+        int fieldStart = buf.length();
+        buf.append("org.example.foo.bar");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - bar", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        buf.append("bar");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - bar", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - ", buf.toString());
+    }
+
+    /**
+     * Check that getAbbreviator("1.").abbreviate abbreviates non-final elements to one character.
+     *
+     */
+    public void testOneDot() {
+        NameAbbreviator abbrev = NameAbbreviator.getAbbreviator("1.");
+        StringBuffer buf = new StringBuffer("DEBUG - ");
+        int fieldStart = buf.length();
+        buf.append("org.example.foo.bar");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - o.e.f.bar", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        buf.append("org.example.foo.");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - o.e.f.", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        buf.append("foo.bar");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - f.bar", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        buf.append("bar");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - bar", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - ", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        buf.append(".");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - .", buf.toString());
+    }
+
+    /**
+     * Check that getAbbreviator("1~.").abbreviate abbreviates non-final elements to one character and a tilde.
+     *
+     */
+    public void testOneTildeDot() {
+        NameAbbreviator abbrev = NameAbbreviator.getAbbreviator("1~.");
+        StringBuffer buf = new StringBuffer("DEBUG - ");
+        int fieldStart = buf.length();
+        buf.append("org.example.foo.bar");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - o~.e~.f~.bar", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        buf.append("org.example.foo.");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - o~.e~.f~.", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        buf.append("foo.bar");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - f~.bar", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        buf.append("bar");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - bar", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - ", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        buf.append(".");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - .", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        buf.append("o.e.f.bar");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - o.e.f.bar", buf.toString());
+    }
+
+    /**
+     * Check that getAbbreviator("2").abbreviate drops all but the last two elements.
+     *
+     */
+    public void testTwo() {
+        NameAbbreviator abbrev = NameAbbreviator.getAbbreviator("2");
+        StringBuffer buf = new StringBuffer("DEBUG - ");
+        int fieldStart = buf.length();
+        buf.append("org.example.foo.bar");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - foo.bar", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        buf.append("foo.bar");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - foo.bar", buf.toString());
+
+        buf.setLength(0);
+        buf.append("DEBUG - ");
+        fieldStart = buf.length();
+        buf.append("bar");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - bar", buf.toString());
+    }
+
+    /**
+     * Check that "0" drops all name content.
+     *
+     */
+    public void testZero() {
+        NameAbbreviator abbrev = NameAbbreviator.getAbbreviator("0");
+        StringBuffer buf = new StringBuffer("DEBUG - ");
+        int fieldStart = buf.length();
+        buf.append("org.example.foo.bar");
+        abbrev.abbreviate(fieldStart, buf);
+        assertEquals("DEBUG - ", buf.toString());
+    }
+
+}
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 0226b41..61b691b 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -334,6 +334,15 @@
       <action dev="ggregory" type="fix" due-to="Gary Gregory">
         Log4j 1.2 bridge missing some LocationInfo constructors.
       </action>
+      <action dev="ggregory" type="fix" due-to="Gary Gregory">
+        Log4j 1.2 bridge missed 
+      </action>
+      <action dev="ggregory" type="fix" due-to="Gary Gregory">
+        Log4j 1.2 bridge missed org.apache.log4j.pattern.FormattingInfo.
+      </action>
+      <action dev="ggregory" type="fix" due-to="Gary Gregory">
+        Log4j 1.2 bridge missed org.apache.log4j.pattern.NameAbbreviator.
+      </action>
       <action dev="ggregory" type="fix">
         JndiManager reverts to 2.17.0 behavior: Read the system property for each call.
       </action>