From 4cbf1712ac0a22ba3fbb89aa1eaf5856c8e0d815 Mon Sep 17 00:00:00 2001 From: "Juan F. Codagnone" Date: Wed, 6 Jul 2016 20:39:23 -0300 Subject: [PATCH 1/2] extract stack concatenation to standalone method --- .../logentries/log4j/LogentriesAppender.java | 26 +++++++++++-------- .../log4j/LogentriesAppenderTest.java | 5 ++++ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/logentries/log4j/LogentriesAppender.java b/src/main/java/com/logentries/log4j/LogentriesAppender.java index 8183660..dedebc7 100644 --- a/src/main/java/com/logentries/log4j/LogentriesAppender.java +++ b/src/main/java/com/logentries/log4j/LogentriesAppender.java @@ -152,22 +152,26 @@ protected void append( LoggingEvent event) { // Append stack trace if present and layout does not handle it if (layout.ignoresThrowable()) { String[] stack = event.getThrowableStrRep(); - if (stack != null) - { - int len = stack.length; - formattedEvent += ", "; - for(int i = 0; i < len; i++) - { - formattedEvent += stack[i]; - if(i < len - 1) - formattedEvent += "\u2028"; - } - } + if (stack != null && stack.length > 0) + formattedEvent = appendFormatedEvent(formattedEvent, stack); } // Prepare to be queued this.le_async.addLineToQueue(formattedEvent); } + private static final String EXCEPTION_SEPARATOR = ", "; + + static String appendFormatedEvent(String formattedEvent, final String[] stack) { + final int len = stack.length; + formattedEvent += EXCEPTION_SEPARATOR; + for(int i = 0; i < len; i++) + { + formattedEvent += stack[i]; + if(i < len - 1) + formattedEvent += "\u2028"; + } + return formattedEvent; + } /** * Closes all connections to Logentries diff --git a/src/test/java/com/logentries/log4j/LogentriesAppenderTest.java b/src/test/java/com/logentries/log4j/LogentriesAppenderTest.java index 064ff45..450b49f 100644 --- a/src/test/java/com/logentries/log4j/LogentriesAppenderTest.java +++ b/src/test/java/com/logentries/log4j/LogentriesAppenderTest.java @@ -1,5 +1,6 @@ package com.logentries.log4j; +import static com.logentries.log4j.LogentriesAppender.*; import static org.junit.Assert.*; import org.junit.Test; @@ -26,4 +27,8 @@ public void settersTest() { assertEquals(le.le_async.getSsl(),true); } + @Test + public void testAppendFormatedEvent() { + assertEquals("foo, a\u2028b\u2028c", appendFormatedEvent("foo", new String[]{"a","b", "c"})); + } } From ce29dfcf6c5f6723ab9f2c4374fd52a00a93b3ca Mon Sep 17 00:00:00 2001 From: "Juan F. Codagnone" Date: Wed, 6 Jul 2016 20:43:52 -0300 Subject: [PATCH 2/2] LoggentriesAppender: memory efficient concatenation for layout.ignoresThrowable() Allocate just the right amount of characters once. Before this change the stack gets concatenated with string concatenation operator. In such scenary, the optimization proposed on JLS-15.18.1 may not apply to the code valid (it is not a one liner). Oracle 1.8.0_77i7-4510U CPU @ 2.00GHz, for 60 deep stacktrace exception ("a tipical exception") Legacy code (extracted as an static method): n: 98,999 min: 210,397 nanoseconds max: 5,640,727 nanoseconds mean: 256,441 nanoseconds std dev: 68,782 nanoseconds median: 242,984 nanoseconds After: n: 98,999 min: 2,555 nanoseconds max: 2,930,444 nanoseconds mean: 5,038 nanoseconds std dev: 2,2034 nanoseconds median: 3,803 nanoseconds Methodology: final int n = 100000; final DescriptiveStatistics statistics = new DescriptiveStatistics(n); final String []stack = { // .... }; for (int i = 0 ; i < n ; i++) { final long t0 = System.nanoTime(); LogentriesAppender.appendFormatedEvent("fooo", stack); final long t1 = System.nanoTime(); if(i > 1000) { statistics.addValue(t1-t0); } } System.out.println(statistics); DescriptiveStatistics is provided by org.apache.commons:commons-math:2.2 --- .../logentries/log4j/LogentriesAppender.java | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/logentries/log4j/LogentriesAppender.java b/src/main/java/com/logentries/log4j/LogentriesAppender.java index dedebc7..5f0cb28 100644 --- a/src/main/java/com/logentries/log4j/LogentriesAppender.java +++ b/src/main/java/com/logentries/log4j/LogentriesAppender.java @@ -161,16 +161,31 @@ protected void append( LoggingEvent event) { } private static final String EXCEPTION_SEPARATOR = ", "; - static String appendFormatedEvent(String formattedEvent, final String[] stack) { + static String appendFormatedEvent(final String formattedEvent, final String[] stack) { final int len = stack.length; - formattedEvent += EXCEPTION_SEPARATOR; - for(int i = 0; i < len; i++) - { - formattedEvent += stack[i]; - if(i < len - 1) - formattedEvent += "\u2028"; + + // calculate buffer size + int buffSize = formattedEvent.length() + + EXCEPTION_SEPARATOR.length() + + len - 1 + ; + for (int i = 0; i < len; i++) { + buffSize += stack[i].length(); } - return formattedEvent; + + // concatenate + final StringBuilder sb = new StringBuilder(buffSize); + sb.append(formattedEvent); + sb.append(EXCEPTION_SEPARATOR); + + for (int i = 0; i < len; i++) { + sb.append(stack[i]); + if (i < len - 1) { + sb.append('\u2028'); + } + } + // assert sb.capacity() == sb.length(); + return sb.toString(); } /**