Repository: cayenne
Updated Branches:
  refs/heads/master 5855ffc71 -> 7694a64d3


CAY-2485 Added CompactSl4jJdbcEventLogger.


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/a07bba55
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/a07bba55
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/a07bba55

Branch: refs/heads/master
Commit: a07bba5542a79f534b80bab28de2b1354a52d593
Parents: 20b166a
Author: kkomyak <const1...@gmail.com>
Authored: Wed Oct 10 11:18:17 2018 +0300
Committer: kkomyak <const1...@gmail.com>
Committed: Thu Oct 11 16:40:30 2018 +0300

----------------------------------------------------------------------
 cayenne-server/pom.xml                          |   6 +
 .../cayenne/log/CompactSl4jJdbcEventLogger.java | 201 +++++++++++++++++++
 .../log/CompactSl4jJdbcEventLoggerTest.java     | 109 ++++++++++
 .../cayenne/log/Slf4jJdbcEventLoggerTest.java   |   4 -
 .../org/apache/cayenne/log/TestAppender.java    |  16 ++
 .../src/test/resources/logback-test.xml         |  42 ++++
 6 files changed, 374 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/a07bba55/cayenne-server/pom.xml
----------------------------------------------------------------------
diff --git a/cayenne-server/pom.xml b/cayenne-server/pom.xml
index 0ede0dd..e965ffa 100644
--- a/cayenne-server/pom.xml
+++ b/cayenne-server/pom.xml
@@ -46,6 +46,12 @@
 
                <!-- Test dependencies -->
                <dependency>
+                       <groupId>ch.qos.logback</groupId>
+                       <artifactId>logback-classic</artifactId>
+                       <version>1.0.13</version>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
                        <groupId>junit</groupId>
                        <artifactId>junit</artifactId>
                        <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/cayenne/blob/a07bba55/cayenne-server/src/main/java/org/apache/cayenne/log/CompactSl4jJdbcEventLogger.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/log/CompactSl4jJdbcEventLogger.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/log/CompactSl4jJdbcEventLogger.java
new file mode 100644
index 0000000..38e4370
--- /dev/null
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/log/CompactSl4jJdbcEventLogger.java
@@ -0,0 +1,201 @@
+/*****************************************************************
+ *   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.cayenne.log;
+
+import org.apache.cayenne.access.translator.DbAttributeBinding;
+import org.apache.cayenne.access.translator.ParameterBinding;
+import org.apache.cayenne.configuration.RuntimeProperties;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.map.DbAttribute;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+/**
+ * @since 4.1
+ */
+public class CompactSl4jJdbcEventLogger extends Slf4jJdbcEventLogger {
+
+    private static final String UNION = "UNION";
+    private static final String SELECT = "SELECT";
+    private static final String FROM = "FROM";
+    private static final String SPACE = " ";
+
+    public CompactSl4jJdbcEventLogger(@Inject RuntimeProperties 
runtimeProperties) {
+        super(runtimeProperties);
+    }
+
+    @Override
+    public void logQuery(String sql, ParameterBinding[] bindings) {
+        if (!isLoggable()) {
+            return;
+        }
+
+        String str;
+        if (sql.toUpperCase().contains(UNION)) {
+            str = processUnionSql(sql);
+        } else {
+            str = formatSqlSelectColumns(sql);
+        }
+
+        StringBuilder stringBuilder = new StringBuilder(str);
+        appendParameters(stringBuilder, "bind", bindings);
+        if (stringBuilder.length() < 0) {
+            return;
+        }
+
+        super.logQuery(stringBuilder.toString(), new ParameterBinding[0]);
+    }
+
+    private String processUnionSql(String sql) {
+
+        String modified = Pattern.compile(UNION.toLowerCase(), 
Pattern.CASE_INSENSITIVE).matcher(sql).replaceAll(UNION);
+        String[] queries = modified.split(
+                UNION);
+        List<String> formattedQueries = 
Arrays.stream(queries).map(this::formatSqlSelectColumns).collect(Collectors.toList());
+        StringBuilder buffer = new StringBuilder();
+        boolean used =  false;
+        for (String q: formattedQueries) {
+            if(!used){
+                used = true;
+            } else {
+                buffer.append(SPACE).append(UNION);
+            }
+            buffer.append(q);
+        }
+        return buffer.toString();
+    }
+
+    private String formatSqlSelectColumns(String sql) {
+        int selectIndex = sql.toUpperCase().indexOf(SELECT);
+        if (selectIndex == -1) {
+            return sql;
+        }
+        selectIndex += SELECT.length();
+        int fromIndex = sql.toUpperCase().indexOf(FROM);
+        String columns = sql.substring(selectIndex, fromIndex);
+        String[] columnsArray = columns.split(",");
+        if (columnsArray.length <= 3) {
+            return sql;
+        }
+
+        columns = "(" + columnsArray.length + " columns)";
+        return new StringBuilder(sql.substring(0, selectIndex))
+                .append(SPACE)
+                .append(columns)
+                .append(SPACE)
+                .append(sql, fromIndex, sql.length())
+                .toString();
+    }
+
+    private void appendParameters(StringBuilder buffer, String label, 
ParameterBinding[] bindings) {
+        int bindingLength = bindings.length;
+        if (bindingLength == 0) {
+            return;
+        }
+
+        buildBinding(buffer, label, collectBindings(bindings));
+    }
+
+    @SuppressWarnings("unchecked")
+    private Map<String, List<String>> collectBindings(ParameterBinding[] 
bindings) {
+        Map<String, List<String>> bindingsMap = new HashMap<>();
+
+        String key = null;
+        String value;
+        for (int i = 0; i < bindings.length; i++) {
+            ParameterBinding b = bindings[i];
+
+            if (b.isExcluded()) {
+                continue;
+            }
+
+            if (b instanceof DbAttributeBinding) {
+                DbAttribute attribute = ((DbAttributeBinding) 
b).getAttribute();
+                if (attribute != null) {
+                    key = attribute.getName();
+                }
+            }
+
+            if (b.getExtendedType() != null) {
+                value = b.getExtendedType().toString(b.getValue());
+            } else if(b.getValue() == null) {
+                value = "NULL";
+            } else {
+                value = new StringBuilder(b.getValue().getClass().getName())
+                        .append("@")
+                        
.append(System.identityHashCode(b.getValue())).toString();
+            }
+
+            List<String> objects = bindingsMap.computeIfAbsent(key, k -> new 
ArrayList<>());
+            objects.add(value);
+        }
+
+        return bindingsMap;
+    }
+
+    private void buildBinding(StringBuilder buffer, String label, Map<String, 
List<String>> bindingsMap) {
+        int j = 1;
+        boolean hasIncluded = false;
+        for (String k : bindingsMap.keySet()) {
+            if (!hasIncluded) {
+                hasIncluded = true;
+                buffer.append(" [").append(label).append(": ");
+            } else {
+                buffer.append(", ");
+            }
+            buffer.append(j).append("->").append(k).append(": ");
+
+            List<String> bindingsList = bindingsMap.get(k);
+            if (bindingsList.size() == 1 ) {
+                buffer.append(bindingsList.get(0));
+            } else {
+                buffer.append("{");
+                boolean wasAdded = false;
+                for (Object val : bindingsList) {
+                    if (wasAdded) {
+                        buffer.append(", ");
+                    } else {
+                        wasAdded = true;
+                    }
+                    buffer.append(val);
+                }
+                buffer.append("}");
+            }
+            j++;
+        }
+
+        if (hasIncluded) {
+            buffer.append("]");
+        }
+    }
+
+    @Override
+    public void logBeginTransaction(String transactionLabel) {
+    }
+
+    @Override
+    public void logCommitTransaction(String transactionLabel) {
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/a07bba55/cayenne-server/src/test/java/org/apache/cayenne/log/CompactSl4jJdbcEventLoggerTest.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/log/CompactSl4jJdbcEventLoggerTest.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/log/CompactSl4jJdbcEventLoggerTest.java
new file mode 100644
index 0000000..f7dbe76
--- /dev/null
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/log/CompactSl4jJdbcEventLoggerTest.java
@@ -0,0 +1,109 @@
+/*****************************************************************
+ *   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.cayenne.log;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.spi.LoggingEvent;
+import org.apache.cayenne.access.translator.DbAttributeBinding;
+import org.apache.cayenne.access.types.BooleanType;
+import org.apache.cayenne.access.types.CharType;
+import org.apache.cayenne.access.types.ExtendedType;
+import org.apache.cayenne.access.types.IntegerType;
+import org.apache.cayenne.configuration.DefaultRuntimeProperties;
+import org.apache.cayenne.map.DbAttribute;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.*;
+
+public class CompactSl4jJdbcEventLoggerTest {
+
+    @Before
+    public void before() {
+        TestAppender.events.clear();
+    }
+
+    @Test
+    public void logWithCompact_Union() {
+
+        CompactSl4jJdbcEventLogger compactSl4jJdbcEventLogger = new 
CompactSl4jJdbcEventLogger(new 
DefaultRuntimeProperties(Collections.emptyMap()));
+        DbAttributeBinding[] bindings = createBindings();
+        final List<LoggingEvent> log = TestAppender.events;
+        assertEquals(log.size(), 0);
+
+        compactSl4jJdbcEventLogger.logQuery(
+                "SELECT t0.NAME AS ec0_0, t0.F_KEY1 AS ec0_1, t0.F_KEY2 AS 
ec0_2," +
+                        " t0.PKEY AS ec0_3 FROM COMPOUND_FK_TEST t0 INNER JOIN 
COMPOUND_PK_TEST " +
+                        "t1 ON (t0.F_KEY1 = t1.KEY1 AND t0.F_KEY2 = t1.KEY2) 
WHERE t1.NAME LIKE ?", createBindings());
+        assertEquals(log.size(), 1);
+        LoggingEvent firstLogEntry = log.get(0);
+        assertThat(firstLogEntry.getLevel(), is(Level.INFO));
+        assertThat(firstLogEntry.getMessage(), is("SELECT (4 columns) FROM 
COMPOUND_FK_TEST t0 " +
+                "INNER JOIN COMPOUND_PK_TEST t1 ON (t0.F_KEY1 = t1.KEY1 AND 
t0.F_KEY2 = t1.KEY2) " +
+                "WHERE t1.NAME LIKE ? [bind: 1->t0.NAME: {'', 52, 'true'}, 
2->t0.F_KEY1: 'true'] "));
+        assertThat(firstLogEntry.getLoggerName(), 
is("org.apache.cayenne.log.JdbcEventLogger"));
+
+        compactSl4jJdbcEventLogger.logQuery(
+                "SELECT t0.NAME AS ec0_0, t0.F_KEY1 AS ec0_1, " +
+                        "t0.PKEY AS ec0_3 FROM COMPOUND_FK_TEST t0 INNER JOIN 
COMPOUND_PK_TEST " +
+                        "t1 ON (t0.F_KEY1 = t1.KEY1 AND t0.F_KEY2 = t1.KEY2) 
WHERE t1.NAME LIKE ?" +
+                        "UNION ALL " +
+                        "SELECT t0.NAME AS ec0_0, t0.F_KEY1 AS ec0_1," +
+                        " t0.PKEY AS ec0_3 FROM COMPOUND_FK_TEST t0 INNER JOIN 
COMPOUND_PK_TEST " +
+                        "t1 ON (t0.F_KEY1 = t1.KEY1 AND t0.F_KEY2 = t1.KEY2) 
WHERE t1.NAME LIKE ?" +
+                        "union all " +
+                        "SELECT t0.NAME AS ec0_0, t0.F_KEY1 AS ec0_1, 
t0.F_KEY2 AS ec0_2," +
+                        " t0.PKEY AS ec0_3 FROM COMPOUND_FK_TEST t0 INNER JOIN 
COMPOUND_PK_TEST " +
+                        "t1 ON (t0.F_KEY1 = t1.KEY1 AND t0.F_KEY2 = t1.KEY2) 
WHERE t1.NAME LIKE ?", bindings);
+        assertEquals(log.size(), 2);
+         firstLogEntry = log.get(1);
+        assertThat(firstLogEntry.getLevel(), is(Level.INFO));
+        assertThat(firstLogEntry.getMessage(), is("SELECT t0.NAME AS ec0_0, 
t0.F_KEY1 AS ec0_1, t0.PKEY AS ec0_3 FROM COMPOUND_FK_TEST t0 " +
+                "INNER JOIN COMPOUND_PK_TEST t1 ON (t0.F_KEY1 = t1.KEY1 AND 
t0.F_KEY2 = t1.KEY2) " +
+                "WHERE t1.NAME LIKE ? UNION ALL SELECT t0.NAME AS ec0_0, 
t0.F_KEY1 AS ec0_1, t0.PKEY AS ec0_3 " +
+                "FROM COMPOUND_FK_TEST t0 INNER JOIN COMPOUND_PK_TEST t1 ON 
(t0.F_KEY1 = t1.KEY1 AND t0.F_KEY2 = t1.KEY2) " +
+                "WHERE t1.NAME LIKE ? UNION all SELECT (4 columns) FROM 
COMPOUND_FK_TEST t0 INNER JOIN COMPOUND_PK_TEST t1 ON (t0.F_KEY1 = t1.KEY1 AND 
t0.F_KEY2 = t1.KEY2) " +
+                "WHERE t1.NAME LIKE ? [bind: 1->t0.NAME: {'', 52, 'true'}, 
2->t0.F_KEY1: 'true'] "));
+        assertThat(firstLogEntry.getLoggerName(), 
is("org.apache.cayenne.log.JdbcEventLogger"));
+
+    }
+
+    private DbAttributeBinding [] createBindings() {
+        return new DbAttributeBinding[] { createBinding("t0.NAME", 1, "", new 
CharType(false, false)),
+                                            createBinding("t0.NAME", 2, 52, 
new IntegerType()),
+                                            createBinding("t0.NAME", 3, true, 
new BooleanType()),
+                                            createBinding("t0.F_KEY1", 4, 
true, new BooleanType())};
+    }
+
+    private DbAttributeBinding createBinding(String name, int position, Object 
object, ExtendedType type){
+
+        DbAttributeBinding dbAttributeBinding = new DbAttributeBinding(new 
DbAttribute(name));
+        dbAttributeBinding.setValue(object);
+        dbAttributeBinding.setStatementPosition(position);
+        if (type != null) {
+            dbAttributeBinding.setExtendedType(type);
+        }
+
+        return dbAttributeBinding;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/a07bba55/cayenne-server/src/test/java/org/apache/cayenne/log/Slf4jJdbcEventLoggerTest.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/log/Slf4jJdbcEventLoggerTest.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/log/Slf4jJdbcEventLoggerTest.java
index a41861c..322eb7f 100644
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/log/Slf4jJdbcEventLoggerTest.java
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/log/Slf4jJdbcEventLoggerTest.java
@@ -18,14 +18,10 @@
  ****************************************************************/
 package org.apache.cayenne.log;
 
-import org.apache.cayenne.configuration.DefaultRuntimeProperties;
 import org.apache.cayenne.util.IDUtil;
 import org.junit.Test;
 
-import java.util.Collections;
-
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
 
 public class Slf4jJdbcEventLoggerTest {
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/a07bba55/cayenne-server/src/test/java/org/apache/cayenne/log/TestAppender.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/log/TestAppender.java 
b/cayenne-server/src/test/java/org/apache/cayenne/log/TestAppender.java
new file mode 100644
index 0000000..5560c07
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/log/TestAppender.java
@@ -0,0 +1,16 @@
+package org.apache.cayenne.log;
+
+import ch.qos.logback.classic.spi.LoggingEvent;
+import ch.qos.logback.core.AppenderBase;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TestAppender extends AppenderBase<LoggingEvent> {
+    static List<LoggingEvent> events = new ArrayList<>();
+
+    @Override
+    protected void append(LoggingEvent e) {
+        events.add(e);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/a07bba55/cayenne-server/src/test/resources/logback-test.xml
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/resources/logback-test.xml 
b/cayenne-server/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..616beac
--- /dev/null
+++ b/cayenne-server/src/test/resources/logback-test.xml
@@ -0,0 +1,42 @@
+<configuration>
+
+    <statusListener class="ch.qos.logback.core.status.NopStatusListener" />
+
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <layout class="ch.qos.logback.classic.PatternLayout">
+            <Pattern>
+                %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+            </Pattern>
+        </layout>
+    </appender>
+
+
+    <appender name="TEST-INFO"
+              class="org.apache.cayenne.log.TestAppender">
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <Pattern>
+                %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+            </Pattern>
+        </encoder>
+
+        <rollingPolicy 
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- rollover daily -->
+            <fileNamePattern>archived/error.%d{yyyy-MM-dd}.%i.log
+            </fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy
+                    class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>10MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+        </rollingPolicy>
+
+    </appender>
+
+    <root level="info">
+        <appender-ref ref="TEST-INFO" />
+    </root>
+
+    <logger name="org.apache.cayenne" level="info">
+        <appender-ref ref="STDOUT"/>
+    </logger>
+
+</configuration>
\ No newline at end of file

Reply via email to