├── .gitignore
├── .settings
└── .gitignore
├── .travis.yml
├── 3rdparty_license.txt
├── LICENSE.txt
├── README.md
├── jdbc-perf-logger-agent
├── .gitignore
├── .settings
│ ├── .gitignore
│ ├── org.eclipse.jdt.core.prefs
│ └── org.eclipse.jdt.ui.prefs
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── ch
│ │ └── sla
│ │ └── jdbcperflogger
│ │ └── agent
│ │ ├── Agent.java
│ │ ├── DriverInterceptor.java
│ │ └── package-info.java
│ └── test
│ └── java
│ └── ch
│ └── sla
│ └── jdbcperflogger
│ └── agent
│ └── AgentIT.java
├── jdbc-perf-logger-driver
├── .gitignore
├── .settings
│ ├── .gitignore
│ ├── org.eclipse.jdt.core.prefs
│ └── org.eclipse.jdt.ui.prefs
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── ch
│ │ │ └── sla
│ │ │ └── jdbcperflogger
│ │ │ ├── DatabaseType.java
│ │ │ ├── DriverConfig.java
│ │ │ ├── Logger.java
│ │ │ ├── PerfLoggerConstants.java
│ │ │ ├── StatementType.java
│ │ │ ├── TxCompletionType.java
│ │ │ ├── driver
│ │ │ ├── LoggingConnectionInvocationHandler.java
│ │ │ ├── LoggingPreparedStatementInvocationHandler.java
│ │ │ ├── LoggingResultSetInvocationHandler.java
│ │ │ ├── LoggingStatementInvocationHandler.java
│ │ │ ├── Utils.java
│ │ │ ├── WrappingDriver.java
│ │ │ └── package-info.java
│ │ │ ├── logger
│ │ │ ├── LogSender.java
│ │ │ ├── PerfLogger.java
│ │ │ ├── PerfLoggerClientThread.java
│ │ │ ├── PerfLoggerRemoting.java
│ │ │ ├── PerfLoggerServerThread.java
│ │ │ ├── RecordingLogSender.java
│ │ │ ├── SocketLogSender.java
│ │ │ └── package-info.java
│ │ │ ├── model
│ │ │ ├── AbstractBeforeStatementExecutionLog.java
│ │ │ ├── BatchedNonPreparedStatementsLog.java
│ │ │ ├── BatchedPreparedStatementsLog.java
│ │ │ ├── BufferFullLogMessage.java
│ │ │ ├── ConnectionInfo.java
│ │ │ ├── LogMessage.java
│ │ │ ├── PreparedStatementValuesHolder.java
│ │ │ ├── ResultSetLog.java
│ │ │ ├── SqlTypedValue.java
│ │ │ ├── StatementExecutedLog.java
│ │ │ ├── StatementLog.java
│ │ │ ├── TxCompleteLog.java
│ │ │ └── package-info.java
│ │ │ └── package-info.java
│ └── resources
│ │ ├── .gitignore
│ │ ├── META-INF
│ │ └── services
│ │ │ └── java.sql.Driver
│ │ └── jdbcperflogger-fallback.xml
│ └── test
│ ├── java
│ └── ch
│ │ └── sla
│ │ └── jdbcperflogger
│ │ ├── DriverConfigTest.java
│ │ ├── driver
│ │ ├── UtilsTest.java
│ │ ├── WrappingDriverJava8Test.java
│ │ ├── WrappingDriverTest.java
│ │ └── WrappingDriverUnloadTest.java
│ │ └── logger
│ │ ├── MyClassLoader.java
│ │ ├── PerfLoggerClientThreadTest.java
│ │ ├── PerfLoggerServerThreadTest.java
│ │ └── PerfLoggerTest.java
│ ├── resources
│ ├── jdbcperflogger.xml
│ ├── log4j.dtd
│ ├── log4j.xml
│ └── logging.properties
│ └── resourcesNonClasspath
│ └── test.txt
├── jdbc-perf-logger-gui
├── .gitignore
├── .settings
│ ├── .gitignore
│ ├── org.eclipse.jdt.core.prefs
│ └── org.eclipse.jdt.ui.prefs
├── pom.xml
└── src
│ ├── main
│ ├── appassembler
│ │ └── unixBinTemplate
│ ├── assembly
│ │ └── distrib.xml
│ ├── config
│ │ ├── example-jdbcperflogger.xml
│ │ └── log4j.xml
│ ├── java
│ │ └── ch
│ │ │ └── sla
│ │ │ └── jdbcperflogger
│ │ │ └── console
│ │ │ ├── db
│ │ │ ├── DetailedViewStatementLog.java
│ │ │ ├── LogRepositoryConstants.java
│ │ │ ├── LogRepositoryRead.java
│ │ │ ├── LogRepositoryReadJdbc.java
│ │ │ ├── LogRepositoryUpdate.java
│ │ │ ├── LogRepositoryUpdateJdbc.java
│ │ │ ├── LogSearchCriteria.java
│ │ │ ├── ResultSetAnalyzer.java
│ │ │ ├── StatementFullyExecutedLog.java
│ │ │ └── package-info.java
│ │ │ ├── net
│ │ │ ├── AbstractLogReceiver.java
│ │ │ ├── ClientLogReceiver.java
│ │ │ ├── LogPersister.java
│ │ │ ├── ServerLogReceiver.java
│ │ │ └── package-info.java
│ │ │ └── ui
│ │ │ ├── CustomTable.java
│ │ │ ├── CustomTableCellRenderer.java
│ │ │ ├── CustomTableRowSorter.java
│ │ │ ├── GuiUtils.java
│ │ │ ├── HostPort.java
│ │ │ ├── IClientConnectionDelegate.java
│ │ │ ├── LogExporter.java
│ │ │ ├── PerfLoggerController.java
│ │ │ ├── PerfLoggerGuiMain.java
│ │ │ ├── PerfLoggerGuiMainFrame.java
│ │ │ ├── PerfLoggerPanel.java
│ │ │ ├── ResultSetDataModel.java
│ │ │ ├── StatementTimestampTableCellRenderer.java
│ │ │ ├── WelcomePanel.java
│ │ │ └── package-info.java
│ └── resources
│ │ ├── .gitignore
│ │ ├── icons
│ │ ├── 32px-Edit-clear.png
│ │ ├── 32px-Edit-copy_purple.png
│ │ ├── 32px-Media-playback-pause.png
│ │ ├── 32px-Media-record.png
│ │ ├── forkme_right_green_007200.png
│ │ ├── network-offline.png
│ │ └── network-transmit-receive.png
│ │ └── initdb.sql
│ └── test
│ ├── java
│ └── ch
│ │ └── sla
│ │ └── jdbcperflogger
│ │ └── console
│ │ ├── db
│ │ ├── AbstractLogRepositoryTest.java
│ │ ├── LogRepositoryReadJdbcTest.java
│ │ └── LogRepositoryUpdateJdbcTest.java
│ │ └── net
│ │ └── ServerLogReceiverTest.java
│ └── resources
│ ├── log4j.dtd
│ └── log4j.xml
├── lombok.config
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | .classpath
2 | .DS_Store
3 | .idea
4 | .project
5 | *.iml
6 | *.log
7 | pom.xml.*
8 | target
9 | /.java-version
10 | /logdb
11 | /release.properties
12 | /PerfLoggerGuiMain*.launch
13 |
--------------------------------------------------------------------------------
/.settings/.gitignore:
--------------------------------------------------------------------------------
1 | !/org.eclipse.jdt.core.prefs
2 | !/org.eclipse.jdt.ui.prefs
3 | /*
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | dist: xenial
2 | language: java
3 | jdk:
4 | - openjdk8
5 | - openjdk11
6 | script: mvn clean verify
7 |
8 | env:
9 | global:
10 | # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
11 | # via the "travis encrypt" command using the project repo's public key
12 | - secure: "lsTdhAiNAYTfpi14mofp3W8HauFE5tj40TOuyGgNGfNNCuk0dktAuAnBVZyb/ylaRqedzMJ7LCBjFZFkycMdh0nQO9TgEav0WaFjflDIuUg6BhWi+sV/uNVUBUtUC5eXYEZbBlhJ+a2h4/oCSgPdRVrNdPQxunMZHegrFYzKWk4="
13 |
14 | addons:
15 | coverity_scan:
16 | project:
17 | name: "sylvainlaurent/JDBC-Performance-Logger"
18 | description: "A JDBC driver wrapper and GUI to analyze statement performance"
19 | notification_email: slaurent@apache.org
20 | build_command_prepend: "mvn clean"
21 | build_command: "mvn -DskipTests=true compile"
22 | branch_pattern: master
23 | cache:
24 | directories:
25 | - $HOME/.m2
26 |
--------------------------------------------------------------------------------
/3rdparty_license.txt:
--------------------------------------------------------------------------------
1 | This project uses the following third-party libraries/resources :
2 |
3 | - H2Database : dual licensed and available under a modified version of the MPL 1.1 (Mozilla Public License) or under the (unmodified) EPL 1.0 (Eclipse Public License). An original copy of the license agreement can be found at: http://www.h2database.com/html/license.html
4 | - JUnit : Eclipse Public License 1.0. https://github.com/junit-team/junit
5 | - Log4J : The Apache Software License, Version 2.0. http://logging.apache.org/log4j/1.2/
6 | - Findbugs / JSR305 : The Apache Software License, Version 2.0. http://findbugs.sourceforge.net/
7 | - Firesoft RSyntaxArea : LGPL 2.1. http://fifesoft.com/rsyntaxtextarea/
8 | - SLF4J : QOS.ch license, identical to MIT. http://www.slf4j.org/
9 | - Icons from the Tango Desktop Project : licenses under the Creative Commons License. http://en.wikipedia.org/wiki/Tango_Desktop_Project
10 |
11 | Among those, the binary distribution redistributes the following :
12 | - H2Database
13 | - Log4J
14 | - Findbugs / JSR305
15 | - Firesoft RSyntaxArea
16 | - SLF4J
17 | - Icons from the Tango Desktop Project
18 | - Byte Buddy
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/sylvainlaurent/JDBC-Performance-Logger)
2 |
3 | # JDBC Performance Logger
4 |
5 | ## Purpose
6 | Measuring performance of SQL statements executed through JDBC.
7 |
8 | (click on the image below for an overview of the features)
9 | [](https://www.thinglink.com/scene/512018881544454146)
10 |
11 |
12 | ## Why yet another project?
13 | Although other tools already exist around JDBC performance monitoring ([log4jdbc](http://code.google.com/p/log4jdbc/), [P6Spy](http://sourceforge.net/projects/p6spy/), [JDbMonitor](http://www.jdbmonitor.com/)...), I did not find the features I was looking for : a GUI, measurement of statement execution and ResultSet iteration, cumulative measures, commit duration...
14 |
15 | ## Features
16 | - Graphical console (Swing-based) with analysis feature
17 | - filter/highlight based on statement text, minimum execution time
18 | - advanced filtering using custom SQL WHERE clause against the embedded H2 DB
19 | - group statements to count executions of identical statements and measure cumulated time
20 | - support for multiple connections
21 | - the connection between the monitored java application (JDBC proxy driver) and the console can be initiated from either side
22 | - Logging of bound values of prepared statements, including the name of the set* method called to bind the value (very helpful to distinguish setDate and setTimestamp to understand [why Oracle does not use an index](http://docs.oracle.com/cd/E16655_01/java.121/e17657/apxref.htm#JJDBC28919) )
23 | - Separate measure of statement execution time, results fetch time and result set usage time (includes result processing like creation of java object)
24 | - Measures connection creation and commit/rollback durations
25 | - Handling of batched statements
26 | - Logging of SQLExceptions
27 | - Displays the `queryTimeout` of each statement (no value means 0 or no timeout) (since 0.5.0)
28 | - Displays the `autoCommit` status of each statement (since 0.6.0)
29 | - Supports new java 8 methods like `executeLargeUpdate` (since 0.6.2)
30 | - Java agent (since 0.8.0)
31 |
32 | ## Requirements
33 | - java 8 (since 0.9)
34 |
35 | ## How to download
36 | - The package containing both the console and driver is available here : https://github.com/sylvainlaurent/JDBC-Performance-Logger/releases
37 | - The driver is also available on Maven Central :
38 |
39 | ```xml
40 |
41 | com.github.sylvainlaurent.jdbcperflogger
42 | jdbc-perf-logger-agent
43 | ...
44 |
45 | ```
46 | or
47 |
48 | ```xml
49 |
50 | com.github.sylvainlaurent.jdbcperflogger
51 | jdbc-perf-logger-driver
52 | ...
53 |
54 | ```
55 |
56 | ## How to setup the JDBC Driver
57 | The driver can be setup in different ways:
58 |
59 | ### As a java agent (recommended/most simple way)
60 | Just launch the JVM with `-javaagent:path/to/jdbc-perf-logger-agent-x.y.z.jar`
61 |
62 | The agent jar file is available in the `lib` directory of the zip or tar.gz distribution or as a maven artifact as shown above.
63 |
64 | ### Manual configuration
65 | - If using maven, add the `` snippet above (replacing the version with the latest one) to your `pom.xml`
66 | - If NOT using maven, add `jdbc-perf-logger-driver` jar file to the classpath of the JDBC-client application (the file can be found in the `lib` directory of the binary distribution)
67 | - Change the driver class name to `ch.sla.jdbcperflogger.driver.WrappingDriver`
68 | - Prefix your current JDBC URL with `jdbcperflogger:`, example: `jdbcperflogger:jdbc:h2:mem:` or `jdbcperflogger:jdbc:oracle:thin:@myhost:1521:orcl`
69 |
70 | ### Advanced configuration
71 | - (optional) add a `jdbcperflogger.xml` file to the classpath (see the [example file](/jdbc-perf-logger-gui/src/main/config/example-jdbcperflogger.xml/) for indications). If both the driver and console are used on the same machine, there's nothing to do: the driver will try to connect to the console on localhost:4561.
72 | - (optional) the location of the config file can be overriden with the System property `jdbcperflogger.config.location`. Example : `java -Djdbcperflogger.config.location=/Users/me/myjdbcperflogger.xml ....`
73 |
74 | ## How to use the graphical console
75 | - launch `bin/jdbc-performance-logger-gui.sh` (unix/MacOS) or `bin\jdbc-performance-logger-gui.bat` (requires java 8 JRE)
76 | - by default the console waits for connections from jdbc-logger-drivers on port 4561. All statements will be logged to the same tab
77 | - The console can also connect to a jdbc-perf-logger-driver instance on a specific host and port. A tab is created for each host/port combination.
78 | - Once a tab is opened, the status of the connection is indicated at the bottom of the panel. If the connection is broken and was initiated by the console, the console will try to reconnect regularly. If the connection was initiated by the driver, the latter will try to reconnect regularly.
79 | - by default the console only keeps the last 20'000 statements. The number can be changed by adding the System property `maxLoggedStatements` when launching the console.
80 |
81 | ## Tested databases
82 | - H2 (lightly, used for our own unit tests)
83 | - Oracle 10.2/11.2/12.1
84 | - MySQL 5.1
85 |
86 | ## Current limitations
87 | - No DataSource nor XADataSource class provided
88 | - Only the first ResultSet of queries is logged (`Statement.getMoreResults()` works but no effort has been put to log the fetching of those ResultSets)
89 |
90 | ## Potential ClassLoader issues
91 | **There should not be any problem when using the "java agent way".**
92 |
93 | For the "driver way", here are the rules to observe :
94 | - The jdbc-perf-logger-driver must be able to use your bare JDBC driver
95 | - The DataSource you use must be able to use the jdbc-perf-logger-driver classes
96 |
97 | Here are the most common cases with Tomcat :
98 | - Tomcat _shared.loader_ includes
99 | - the DataSource implementation (which is by default for tomcat 7 DataSource)
100 | - the bare JDBC driver
101 | - the jdbc-perf-logger driver
102 | This is the case if you place your JDBC driver and jdbc-perf-logger driver in the `lib` directory of `CATALINA_BASE` or `CATALINA_HOME`.
103 | This can also be done by configuring the `catalina.properties` file.
104 | - your WAR file embeds the jars for
105 | - the DataSource implementation
106 | - the bare JDBC driver
107 | - the jdbc-perf-logger driver
108 | - the JVM classpath includes the bare JDBC driver and the jdbc-perf-logger driver and the Tomcat _shared.loader_ includes the DataSource implementation.
109 |
110 | ## Source code
111 | The source code is available on GitHub : https://github.com/sylvainlaurent/JDBC-Performance-Logger
112 |
113 | ### How to build source
114 | Use Maven and a JDK >=8, and run `mvn clean verify` in the root directory of the git repository. The binary distribution is then available in `jdbc-perf-logger-gui`.
115 |
116 | ### How to create a release
117 | `mvn release:prepare release:perform` and answer the questions about version number.
118 |
119 | Then push the commits and tags to github.
120 |
121 | ## License
122 | This software is licensed under the Apache Sotware License version 2.0, see [LICENSE.txt](LICENSE.txt).
123 |
124 | This software uses and redistributes third-party software, see [3rdparty_license.txt](3rdparty_license.txt).
125 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-agent/.gitignore:
--------------------------------------------------------------------------------
1 | /dependency-reduced-pom.xml
2 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-agent/.settings/.gitignore:
--------------------------------------------------------------------------------
1 | !/org.eclipse.jdt.core.prefs
2 | !/org.eclipse.jdt.ui.prefs
3 | /*
--------------------------------------------------------------------------------
/jdbc-perf-logger-agent/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 |
4 | com.github.sylvainlaurent.jdbcperflogger
5 | jdbc-perf-logger
6 | 0.9.1-SNAPSHOT
7 |
8 | jdbc-perf-logger-agent
9 |
10 |
11 |
12 | com.github.sylvainlaurent.jdbcperflogger
13 | jdbc-perf-logger-driver
14 |
15 |
16 | org.eclipse.jdt
17 | org.eclipse.jdt.annotation
18 |
19 | provided
20 |
21 |
22 | net.bytebuddy
23 | byte-buddy
24 | 1.10.9
25 |
26 |
27 | junit
28 | junit
29 | test
30 |
31 |
32 | org.mockito
33 | mockito-core
34 | test
35 |
36 |
37 | com.h2database
38 | h2
39 | test
40 |
41 |
42 | org.apache.derby
43 | derby
44 | 10.13.1.1
45 |
46 |
47 |
48 |
49 |
50 |
51 | org.apache.maven.plugins
52 | maven-jar-plugin
53 |
54 |
55 | true
56 |
57 | true
58 |
59 |
60 | ch.sla.jdbcperflogger.agent.Agent
61 | ch.sla.jdbcperflogger.agent.Agent
62 | true
63 |
64 |
65 |
66 |
67 |
68 | org.apache.maven.plugins
69 | maven-shade-plugin
70 | 3.2.3
71 |
72 |
73 |
74 | com.github.sylvainlaurent.jdbcperflogger:jdbc-perf-logger-driver
75 | net.bytebuddy:byte-buddy
76 |
77 |
78 |
79 |
80 | net.bytebuddy
81 | ch.sla.jdbcperflogger.agent.net.bytebuddy
82 |
83 |
84 |
85 |
86 |
87 | package
88 |
89 | shade
90 |
91 |
92 |
93 |
94 |
95 | maven-dependency-plugin
96 | 3.1.2
97 |
98 |
99 |
100 | properties
101 |
102 |
103 |
104 |
105 |
106 | org.apache.maven.plugins
107 | maven-failsafe-plugin
108 |
109 | -javaagent:${project.build.directory}/${project.build.finalName}.jar
110 | -Dwrapped.driver.url="${org.apache.derby:derby:jar}"
111 |
112 |
113 | com.github.sylvainlaurent.jdbcperflogger:jdbc-perf-logger-driver
114 | net.bytebuddy:byte-buddy
115 | org.apache.derby:derby
116 |
117 |
118 |
119 |
120 |
121 |
122 |
124 |
125 | org.eclipse.m2e
126 | lifecycle-mapping
127 | 1.0.0
128 |
129 |
130 |
131 |
132 |
133 | org.apache.maven.plugins
134 | maven-dependency-plugin
135 | [3.0.2,)
136 |
137 | properties
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-agent/src/main/java/ch/sla/jdbcperflogger/agent/Agent.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger.agent;
2 |
3 | import static net.bytebuddy.matcher.ElementMatchers.named;
4 |
5 | import java.io.IOException;
6 | import java.lang.instrument.Instrumentation;
7 | import java.sql.Driver;
8 |
9 | import org.eclipse.jdt.annotation.Nullable;
10 |
11 | import ch.sla.jdbcperflogger.driver.WrappingDriver;
12 | import net.bytebuddy.agent.builder.AgentBuilder;
13 | import net.bytebuddy.description.type.TypeDescription;
14 | import net.bytebuddy.dynamic.DynamicType.Builder;
15 | import net.bytebuddy.implementation.MethodDelegation;
16 | import net.bytebuddy.matcher.ElementMatchers;
17 | import net.bytebuddy.utility.JavaModule;
18 |
19 | public class Agent {
20 | protected static final String PREFIX = "[jdbc-perf-logger-agent]";
21 | private static boolean loaded = false;
22 |
23 | public static void premain(final String agentArgs, final Instrumentation inst) throws IOException {
24 | installAgent(agentArgs, inst);
25 | }
26 |
27 | public static void agentmain(final String agentArgs, final Instrumentation inst) {
28 | installAgent(agentArgs, inst);
29 | }
30 |
31 | private static void installAgent(final String agentArgs, final Instrumentation inst) {
32 | System.out.print(PREFIX + " Loading...");
33 | // final ByteBuddy byteBuddy = new ByteBuddy().with(Implementation.Context.Disabled.Factory.INSTANCE);
34 |
35 | new AgentBuilder.Default()//
36 | .with(new AgentBuilder.Listener.Adapter() {
37 | @Override
38 | public void onError(final String typeName, final @Nullable ClassLoader classLoader,
39 | final @Nullable JavaModule module,
40 | final boolean loaded1, final Throwable throwable) {
41 | System.err.println(PREFIX + " ERROR " + typeName);
42 | throwable.printStackTrace(System.err);
43 | }
44 |
45 | })//
46 | // .with(byteBuddy)//
47 | // .with(AgentBuilder.InitializationStrategy.NoOp.INSTANCE)//
48 | // .with(AgentBuilder.RedefinitionStrategy.REDEFINITION)//
49 | // .with(AgentBuilder.TypeStrategy.Default.REBASE)//
50 | .type(ElementMatchers.isSubTypeOf(Driver.class).and(ElementMatchers.noneOf(WrappingDriver.class)))//
51 | .transform(new AgentBuilder.Transformer() {
52 |
53 | @Override
54 | public Builder> transform(final Builder> builder, final TypeDescription typeDescription,
55 | final @Nullable ClassLoader classLoader, final @Nullable JavaModule module) {
56 | System.out.println(PREFIX + " Transforming " + typeDescription + " for interception");
57 | return builder//
58 | .method(named("connect"))//
59 | .intercept(MethodDelegation.withDefaultConfiguration()
60 | .filter(ElementMatchers.isMethod().and(named("connect")))
61 | .to(new DriverInterceptor()))//
62 | ;
63 | }
64 | })//
65 | .installOn(inst);
66 |
67 | // TODO: intercept javax.sql.DataSource, javax.sql.PooledConnection.getConnection()...
68 |
69 | loaded = true;
70 | System.out.println("OK");
71 | }
72 |
73 | public static boolean isLoaded() {
74 | return loaded;
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-agent/src/main/java/ch/sla/jdbcperflogger/agent/DriverInterceptor.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger.agent;
2 |
3 | import java.sql.Connection;
4 | import java.util.concurrent.Callable;
5 |
6 | import org.eclipse.jdt.annotation.Nullable;
7 |
8 | import ch.sla.jdbcperflogger.driver.WrappingDriver;
9 | import net.bytebuddy.implementation.bind.annotation.SuperCall;
10 |
11 | public class DriverInterceptor {
12 | public @Nullable Connection connect(final String url, final java.util.Properties info,
13 | @SuperCall final Callable<@Nullable Connection> originalConnectionCreator) throws Exception {
14 |
15 | return WrappingDriver.INSTANCE.wrapConnection(url, info, originalConnectionCreator);
16 | }
17 | }
--------------------------------------------------------------------------------
/jdbc-perf-logger-agent/src/main/java/ch/sla/jdbcperflogger/agent/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | @NonNullByDefault
17 | package ch.sla.jdbcperflogger.agent;
18 |
19 | import org.eclipse.jdt.annotation.NonNullByDefault;
20 |
21 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-agent/src/test/java/ch/sla/jdbcperflogger/agent/AgentIT.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger.agent;
2 |
3 | import static java.util.Objects.requireNonNull;
4 | import static org.junit.Assert.assertEquals;
5 | import static org.junit.Assert.assertTrue;
6 |
7 | import java.io.File;
8 | import java.lang.reflect.Proxy;
9 | import java.net.URL;
10 | import java.net.URLClassLoader;
11 | import java.sql.Connection;
12 | import java.sql.Driver;
13 | import java.sql.DriverManager;
14 | import java.sql.SQLException;
15 | import java.util.Properties;
16 |
17 | import org.junit.Before;
18 | import org.junit.Test;
19 |
20 | import ch.sla.jdbcperflogger.driver.LoggingConnectionInvocationHandler;
21 | import ch.sla.jdbcperflogger.driver.WrappingDriver;
22 |
23 | public class AgentIT {
24 |
25 | private static final String WRAPPED_DRIVER = "org.apache.derby.jdbc.EmbeddedDriver";
26 |
27 | @Before
28 | public void setup() {
29 | // assertTrue(Agent.isLoaded());
30 | }
31 |
32 | @Test
33 | public void returns_a_wrapped_connection_when_using_normal_url() throws SQLException {
34 | final Connection connection = DriverManager.getConnection("jdbc:h2:mem:", "sa", "");
35 | assertTrue("is proxy", Proxy.isProxyClass(connection.getClass()));
36 | assertEquals(LoggingConnectionInvocationHandler.class, Proxy.getInvocationHandler(connection).getClass());
37 | }
38 |
39 | @Test
40 | public void returns_a_wrapped_connection_when_using_jdbcperf_url() throws SQLException {
41 | final Connection connection = DriverManager.getConnection(WrappingDriver.URL_PREFIX + "jdbc:h2:mem:", "sa", "");
42 | assertTrue("is proxy", Proxy.isProxyClass(connection.getClass()));
43 | assertEquals(LoggingConnectionInvocationHandler.class, Proxy.getInvocationHandler(connection).getClass());
44 | }
45 |
46 | @Test(expected = ClassNotFoundException.class)
47 | public void wrapped_driver_is_not_in_classpath() throws ClassNotFoundException {
48 | Class.forName(WRAPPED_DRIVER);
49 | }
50 |
51 | @Test()
52 | public void load_wrapped_from_sub_classloader() throws Exception {
53 | final File wrappedDriverJarFile = new File(System.getProperty("wrapped.driver.url"));
54 | final URLClassLoader childClassLoader = new URLClassLoader(new URL[] { wrappedDriverJarFile.toURI().toURL() });
55 | // register the driver in the DriverManager
56 | @SuppressWarnings("unchecked")
57 | final Class driverClass = (Class) Class.forName(WRAPPED_DRIVER, true,
58 | childClassLoader);
59 | final Driver driver = driverClass.newInstance();
60 |
61 | final Connection connection = requireNonNull(
62 | driver.connect("jdbc:derby:memory:myDB;create=true", new Properties()));
63 | assertTrue("is proxy", Proxy.isProxyClass(connection.getClass()));
64 | assertEquals(LoggingConnectionInvocationHandler.class, Proxy.getInvocationHandler(connection).getClass());
65 |
66 | boolean foundInterfaceLoadedBySubClassLoader = false;
67 | for (final Class> itf : connection.getClass().getInterfaces()) {
68 | if (itf.getClassLoader() == childClassLoader) {
69 | foundInterfaceLoadedBySubClassLoader = true;
70 | }
71 | }
72 | assertTrue("Should have found an interface loaded by the subclassloader", foundInterfaceLoadedBySubClassLoader);
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/.gitignore:
--------------------------------------------------------------------------------
1 | /dependency-reduced-pom.xml
2 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/.settings/.gitignore:
--------------------------------------------------------------------------------
1 | !/org.eclipse.jdt.core.prefs
2 | !/org.eclipse.jdt.ui.prefs
3 | /*
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 |
4 | com.github.sylvainlaurent.jdbcperflogger
5 | jdbc-perf-logger
6 | 0.9.1-SNAPSHOT
7 |
8 |
9 | jdbc-perf-logger-driver
10 | jar
11 |
12 | JDBC Performance Logger Driver
13 |
14 |
15 |
16 | com.h2database
17 | h2
18 | test
19 |
20 |
26 |
27 | org.eclipse.jdt
28 | org.eclipse.jdt.annotation
29 |
30 | true
31 |
32 |
33 | org.hsqldb
34 | hsqldb
35 | 2.5.0
36 | test
37 |
38 |
39 | junit
40 | junit
41 | test
42 |
43 |
44 | org.mockito
45 | mockito-core
46 | test
47 |
48 |
49 | org.slf4j
50 | jul-to-slf4j
51 | test
52 |
53 |
54 | org.slf4j
55 | slf4j-log4j12
56 | test
57 |
58 |
59 | org.apache.derby
60 | derby
61 | 10.10.1.1
62 | test
63 |
64 |
65 | org.awaitility
66 | awaitility
67 | test
68 |
69 |
70 |
71 |
72 |
73 | org.codehaus.mojo
74 | animal-sniffer-maven-plugin
75 |
76 |
77 | org.codehaus.mojo.signature
78 | java18
79 | 1.0
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/DatabaseType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger;
17 |
18 |
19 | public enum DatabaseType {
20 | ORACLE, GENERIC
21 | }
22 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/DriverConfig.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger;
2 |
3 | import java.io.FileInputStream;
4 | import java.io.FileNotFoundException;
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 | import java.net.InetSocketAddress;
8 | import java.util.ArrayList;
9 | import java.util.HashMap;
10 | import java.util.List;
11 | import java.util.Map;
12 | import java.util.Map.Entry;
13 |
14 | import javax.xml.parsers.DocumentBuilder;
15 | import javax.xml.parsers.DocumentBuilderFactory;
16 | import javax.xml.parsers.ParserConfigurationException;
17 |
18 | import org.eclipse.jdt.annotation.NonNull;
19 | import org.eclipse.jdt.annotation.Nullable;
20 | import org.w3c.dom.Document;
21 | import org.w3c.dom.Element;
22 | import org.w3c.dom.NamedNodeMap;
23 | import org.w3c.dom.NodeList;
24 | import org.xml.sax.SAXException;
25 |
26 | public class DriverConfig {
27 | private final static Logger LOGGER = Logger.getLogger(DriverConfig.class);
28 |
29 | public final static DriverConfig INSTANCE;
30 |
31 | @Nullable
32 | private Integer serverPort;
33 | private final List clientAddresses = new ArrayList();
34 | private final Map driverPrefixToClassName = new HashMap();
35 |
36 | static {
37 |
38 | final InputStream configFileStream = openConfigFile();
39 | INSTANCE = parseConfig(configFileStream);
40 | }
41 |
42 | static DriverConfig parseConfig(final InputStream configFileStream) {
43 | try {
44 | final DriverConfig config = new DriverConfig();
45 | final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
46 | final DocumentBuilder docBuilder = dbf.newDocumentBuilder();
47 | final Document doc = docBuilder.parse(configFileStream);
48 | final Element root = (Element) doc.getElementsByTagName("jdbc-perf-logger").item(0);
49 |
50 | {
51 | final NodeList localServersList = root.getElementsByTagName("local-server");
52 | for (int i = 0; i < localServersList.getLength(); i++) {
53 | final String port = localServersList.item(i).getAttributes().getNamedItem("port").getTextContent();
54 | config.serverPort = Integer.parseInt(port);
55 | }
56 | }
57 |
58 | {
59 | final NodeList targetClientList = root.getElementsByTagName("target-console");
60 | for (int i = 0; i < targetClientList.getLength(); i++) {
61 | final NamedNodeMap attributes = targetClientList.item(i).getAttributes();
62 | @NonNull
63 | final String host = attributes.getNamedItem("host").getTextContent();
64 | @NonNull
65 | final String port = attributes.getNamedItem("port").getTextContent();
66 | config.clientAddresses.add(InetSocketAddress.createUnresolved(host, Integer.parseInt(port)));
67 | }
68 | }
69 |
70 | final NodeList jdbcDriversRootNodesList = doc.getElementsByTagName("jdbc-drivers");
71 | if (jdbcDriversRootNodesList.getLength() > 0) {
72 | final NodeList jdbcDriversNodeList = ((Element) jdbcDriversRootNodesList.item(0))
73 | .getElementsByTagName("jdbc-driver");
74 | for (int i = 0; i < jdbcDriversNodeList.getLength(); i++) {
75 | final Element jdbcDriverNode = ((Element) jdbcDriversNodeList.item(i));
76 | final NodeList prefixNode = jdbcDriverNode.getElementsByTagName("prefix");
77 | final NodeList classNameNode = jdbcDriverNode.getElementsByTagName("driver-class-name");
78 | if (prefixNode.getLength() > 0 && classNameNode.getLength() > 0) {
79 | final String prefix = prefixNode.item(0).getTextContent();
80 | final String className = classNameNode.item(0).getTextContent();
81 | if (prefix != null && className != null) {
82 | config.driverPrefixToClassName.put(prefix.trim(), className.trim());
83 | }
84 | }
85 | }
86 | }
87 |
88 | return config;
89 | } catch (final ParserConfigurationException e) {
90 | throw new RuntimeException(e);
91 | } catch (final IOException e) {
92 | throw new RuntimeException(e);
93 | } catch (final SAXException e) {
94 | throw new RuntimeException(e);
95 | }
96 | }
97 |
98 | static InputStream openConfigFile() {
99 | String location = System.getProperty(PerfLoggerConstants.CONFIG_FILE_LOCATION_PROP_KEY);
100 | if (location == null) {
101 | LOGGER.debug("No System property " + PerfLoggerConstants.CONFIG_FILE_LOCATION_PROP_KEY
102 | + " defined, looking for config at " + PerfLoggerConstants.CONFIG_FILE_DEFAULT_LOCATION);
103 | location = PerfLoggerConstants.CONFIG_FILE_DEFAULT_LOCATION;
104 | }
105 |
106 | InputStream configFileStream = openConfigFile(location);
107 | if (configFileStream == null) {
108 | location = PerfLoggerConstants.CONFIG_FILE_FALLBACK_LOCATION;
109 | configFileStream = openConfigFile(location);
110 | if (configFileStream == null) {
111 | throw new RuntimeException(
112 | "Unexpected: cannot find " + PerfLoggerConstants.CONFIG_FILE_FALLBACK_LOCATION);
113 | }
114 | }
115 | LOGGER.info("Using config file " + location);
116 |
117 | return configFileStream;
118 | }
119 |
120 | @Nullable
121 | static InputStream openConfigFile(final String location) {
122 | InputStream configFileStream = PerfLoggerConstants.class.getResourceAsStream("/" + location);
123 | if (configFileStream == null) {
124 | LOGGER.debug("Cannot find config file " + location + " in the classpath, trying on filesystem");
125 |
126 | try {
127 | configFileStream = new FileInputStream(location);
128 | } catch (final FileNotFoundException e) {
129 | LOGGER.debug("Cannot find config file " + location + " on the filesystem");
130 | // not found, just return null
131 | }
132 | }
133 | return configFileStream;
134 |
135 | }
136 |
137 | @Nullable
138 | public Integer getServerPort() {
139 | return serverPort;
140 | }
141 |
142 | public List getClientAddresses() {
143 | return clientAddresses;
144 | }
145 |
146 | @Nullable
147 | public String getClassNameForJdbcUrl(final String jdbcUrl) {
148 | for (final Entry driver : driverPrefixToClassName.entrySet()) {
149 | if (jdbcUrl.startsWith(driver.getKey())) {
150 | return driver.getValue();
151 | }
152 | }
153 | return null;
154 | }
155 |
156 | }
157 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/Logger.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger;
2 |
3 | import java.util.logging.Level;
4 |
5 | import org.eclipse.jdt.annotation.Nullable;
6 |
7 | /**
8 | * Abstraction for logging.
9 | *
10 | * @author slaurent
11 | */
12 | public class Logger {
13 | private final java.util.logging.Logger julLogger;
14 |
15 | private Logger(final java.util.logging.Logger julLogger) {
16 | this.julLogger = julLogger;
17 | }
18 |
19 | public static Logger getLogger(final Class> clazz) {
20 | return new Logger(java.util.logging.Logger.getLogger(clazz.getName()));
21 | }
22 |
23 | public static Logger getLogger(final String loggerName) {
24 | return new Logger(java.util.logging.Logger.getLogger(loggerName));
25 | }
26 |
27 | public void debug(final String msg) {
28 | julLogger.log(Level.FINE, msg);
29 | }
30 |
31 | public void debug(final String msg, final @Nullable Throwable exc) {
32 | julLogger.log(Level.FINE, msg, exc);
33 |
34 | }
35 |
36 | public void info(final String msg) {
37 | julLogger.log(Level.INFO, msg);
38 |
39 | }
40 |
41 | public void info(final String msg, final Throwable e) {
42 | julLogger.log(Level.INFO, msg, e);
43 | }
44 |
45 | public void warn(final String msg) {
46 | julLogger.log(Level.WARNING, msg);
47 | }
48 |
49 | public void warn(final String msg, final @Nullable Throwable e) {
50 | julLogger.log(Level.WARNING, msg, e);
51 | }
52 |
53 | public void error(final String msg) {
54 | julLogger.log(Level.SEVERE, msg);
55 | }
56 |
57 | public void error(final String msg, final Throwable e) {
58 | julLogger.log(Level.SEVERE, msg, e);
59 | }
60 |
61 | public boolean isDebugEnabled() {
62 | return julLogger.isLoggable(Level.FINE);
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/PerfLoggerConstants.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger;
2 |
3 | public class PerfLoggerConstants {
4 | public final static String CONFIG_FILE_DEFAULT_LOCATION = "jdbcperflogger.xml";
5 | public final static String CONFIG_FILE_FALLBACK_LOCATION = "jdbcperflogger-fallback.xml";
6 | public final static String CONFIG_FILE_LOCATION_PROP_KEY = "jdbcperflogger.config.location";
7 |
8 | private PerfLoggerConstants() {
9 |
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/StatementType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package ch.sla.jdbcperflogger;
18 |
19 | import java.util.EnumSet;
20 |
21 | public enum StatementType {
22 | BASE_NON_PREPARED_STMT(1), //
23 | BASE_PREPARED_STMT(2), //
24 | NON_PREPARED_QUERY_STMT(3), //
25 | PREPARED_QUERY_STMT(4), //
26 | PREPARED_BATCH_EXECUTION(5), //
27 | NON_PREPARED_BATCH_EXECUTION(6), //
28 | TRANSACTION(7);
29 |
30 | private static StatementType[] vals;
31 |
32 | private final int id;
33 |
34 | StatementType(final int id) {
35 | this.id = id;
36 | }
37 |
38 | static {
39 | vals = new StatementType[8];
40 | for (final StatementType type : EnumSet.allOf(StatementType.class)) {
41 | vals[type.id] = type;
42 | }
43 | }
44 |
45 | public int getId() {
46 | return id;
47 | }
48 |
49 | public static StatementType fromId(final int id) {
50 | final StatementType statementType = vals[id];
51 | if (statementType == null) {
52 | throw new IllegalArgumentException("unhandled ID for StatementType: " + id);
53 | }
54 | return statementType;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/TxCompletionType.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger;
2 |
3 | public enum TxCompletionType {
4 | COMMIT, ROLLBACK, SET_SAVE_POINT, ROLLBACK_TO_SAVEPOINT
5 | }
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/driver/LoggingConnectionInvocationHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.driver;
17 |
18 | import java.lang.reflect.InvocationHandler;
19 | import java.lang.reflect.Method;
20 | import java.lang.reflect.Proxy;
21 | import java.sql.Connection;
22 | import java.sql.PreparedStatement;
23 | import java.sql.Savepoint;
24 | import java.sql.Statement;
25 | import java.util.Properties;
26 | import java.util.UUID;
27 |
28 | import org.eclipse.jdt.annotation.Nullable;
29 |
30 | import ch.sla.jdbcperflogger.DatabaseType;
31 | import ch.sla.jdbcperflogger.TxCompletionType;
32 | import ch.sla.jdbcperflogger.logger.PerfLogger;
33 |
34 | public class LoggingConnectionInvocationHandler implements InvocationHandler {
35 | private final UUID connectionUuid;
36 | private final int connectionId;
37 | private final Connection wrappedConnection;
38 | private final DatabaseType databaseType;
39 | private final String url;
40 | private final Properties connectionProperties;
41 |
42 | LoggingConnectionInvocationHandler(final int connectionId, final Connection wrappedConnection, final String url,
43 | final Properties connectionProperties) {
44 | connectionUuid = UUID.randomUUID();
45 | this.connectionId = connectionId;
46 | this.wrappedConnection = wrappedConnection;
47 | databaseType = Utils.getDatabaseType(wrappedConnection);
48 | this.url = url;
49 | this.connectionProperties = connectionProperties;
50 | }
51 |
52 | @Override
53 | @Nullable
54 | public Object invoke(@Nullable final Object proxy, final Method method, final Object @Nullable [] args)
55 | throws Throwable {
56 |
57 | final String methodName = method.getName();
58 |
59 | TxCompletionType txCompletionType = null;
60 | String savePointDescription = null;
61 | if ("commit".equals(methodName)) {
62 | txCompletionType = TxCompletionType.COMMIT;
63 | } else if ("rollback".equals(methodName)) {
64 | if (args == null) {
65 | txCompletionType = TxCompletionType.ROLLBACK;
66 | } else {
67 | txCompletionType = TxCompletionType.ROLLBACK_TO_SAVEPOINT;
68 | final Savepoint savepoint = (Savepoint) args[0];
69 | savePointDescription = savepoint.toString();
70 | }
71 | } else if ("setSavepoint".equals(methodName)) {
72 | txCompletionType = TxCompletionType.SET_SAVE_POINT;
73 | }
74 | final long startTimeStamp = System.currentTimeMillis();
75 | long startNanos = -1;
76 | if (txCompletionType != null) {
77 | startNanos = System.nanoTime();
78 | }
79 |
80 | final Object result = Utils.invokeUnwrapException(wrappedConnection, method, args);
81 | if (result != null) {
82 | if ("createStatement".equals(methodName)) {
83 | return Proxy.newProxyInstance(result.getClass().getClassLoader(),
84 | Utils.extractAllInterfaces(result.getClass()),
85 | new LoggingStatementInvocationHandler(connectionUuid, (Statement) result, databaseType));
86 | } else if (("prepareStatement".equals(methodName) || "prepareCall".equals(methodName)) && args != null) {
87 | return Proxy.newProxyInstance(result.getClass().getClassLoader(),
88 | Utils.extractAllInterfaces(result.getClass()), new LoggingPreparedStatementInvocationHandler(
89 | connectionUuid, (PreparedStatement) result, (String) args[0], databaseType));
90 | }
91 |
92 | }
93 |
94 | if (txCompletionType != null) {
95 | if (txCompletionType == TxCompletionType.SET_SAVE_POINT && result != null) {
96 | final Savepoint savepoint = (Savepoint) result;
97 | savePointDescription = savepoint.toString();
98 | }
99 | PerfLogger.logTransactionComplete(connectionUuid, startTimeStamp, txCompletionType,
100 | System.nanoTime() - startNanos, savePointDescription);
101 | }
102 |
103 | return result;
104 | }
105 |
106 | public UUID getConnectionUuid() {
107 | return connectionUuid;
108 | }
109 |
110 | public int getConnectionId() {
111 | return connectionId;
112 | }
113 |
114 | public String getUrl() {
115 | return url;
116 | }
117 |
118 | public Properties getConnectionProperties() {
119 | return connectionProperties;
120 | }
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/driver/LoggingResultSetInvocationHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.driver;
17 |
18 | import java.lang.reflect.InvocationHandler;
19 | import java.lang.reflect.Method;
20 | import java.sql.ResultSet;
21 | import java.util.UUID;
22 |
23 | import org.eclipse.jdt.annotation.Nullable;
24 |
25 | import ch.sla.jdbcperflogger.logger.PerfLogger;
26 |
27 | public class LoggingResultSetInvocationHandler implements InvocationHandler {
28 | private final ResultSet wrappedResultSet;
29 | private final UUID logId;
30 | private final long fetchStartTime;
31 | private boolean closed;
32 | private int nbRowsIterated;
33 | private long fetchDurationNanos;
34 |
35 | LoggingResultSetInvocationHandler(final ResultSet rset, final UUID logId) {
36 | wrappedResultSet = rset;
37 | this.logId = logId;
38 | fetchStartTime = System.nanoTime();
39 | }
40 |
41 | @Override
42 | @Nullable
43 | public Object invoke(@Nullable final Object proxy, final Method method, final Object @Nullable [] args)
44 | throws Throwable {
45 | final long methodStartTime = System.nanoTime();
46 | final Object result = Utils.invokeUnwrapException(wrappedResultSet, method, args);
47 | final long oneRowFetchDurationNanos = System.nanoTime() - methodStartTime;
48 |
49 | final String methodName = method.getName();
50 | if (args == null || args.length == 0) {
51 | if ("close".equals(methodName)) {
52 | if (!closed) {
53 | closed = true;
54 | PerfLogger.logClosedResultSet(logId, System.nanoTime() - fetchStartTime, fetchDurationNanos,
55 | nbRowsIterated);
56 | }
57 | } else if ("next".equals(methodName)) {
58 | fetchDurationNanos += oneRowFetchDurationNanos;
59 | if (Boolean.TRUE.equals(result)) {
60 | nbRowsIterated++;
61 | }
62 | }
63 | }
64 | return result;
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/driver/Utils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.driver;
17 |
18 | import java.lang.reflect.InvocationTargetException;
19 | import java.lang.reflect.Method;
20 | import java.sql.Connection;
21 | import java.sql.SQLException;
22 | import java.util.Collections;
23 | import java.util.HashSet;
24 | import java.util.Set;
25 |
26 | import org.eclipse.jdt.annotation.Nullable;
27 |
28 | import ch.sla.jdbcperflogger.DatabaseType;
29 | import ch.sla.jdbcperflogger.Logger;
30 |
31 | public final class Utils {
32 | private final static Logger LOGGER = Logger.getLogger(Utils.class);
33 |
34 | private Utils() {
35 |
36 | }
37 |
38 | static DatabaseType getDatabaseType(final Connection connection) {
39 | String dbProduct;
40 | try {
41 | dbProduct = connection.getMetaData().getDatabaseProductName();
42 | } catch (final SQLException e) {
43 | LOGGER.error("cannot get db product name");
44 | return DatabaseType.GENERIC;
45 | }
46 | if ("Oracle".equals(dbProduct)) {
47 | return DatabaseType.ORACLE;
48 | }
49 | return DatabaseType.GENERIC;
50 | }
51 |
52 | @Nullable
53 | static Object invokeUnwrapException(final Object target, final Method method, final Object @Nullable [] args)
54 | throws Throwable {
55 | try {
56 | return method.invoke(target, args);
57 | } catch (final InvocationTargetException e) {
58 | throw e.getCause();
59 | }
60 | }
61 |
62 | static Object invokeUnwrapExceptionReturnNonNull(final Object target, final Method method,
63 | final Object @Nullable [] args) throws Throwable {
64 | try {
65 | final Object result = method.invoke(target, args);
66 | assert result != null;
67 | return result;
68 | } catch (final InvocationTargetException e) {
69 | throw e.getCause();
70 | }
71 | }
72 |
73 | static Class>[] extractAllInterfaces(final Class> clazz) {
74 | final Set> interfaces = new HashSet>();
75 | for (Class> currClazz = clazz; currClazz != null; currClazz = currClazz.getSuperclass()) {
76 | Collections.addAll(interfaces, currClazz.getInterfaces());
77 | }
78 |
79 | return interfaces.toArray(new Class[interfaces.size()]);
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/driver/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | @NonNullByDefault
17 | package ch.sla.jdbcperflogger.driver;
18 |
19 | import org.eclipse.jdt.annotation.NonNullByDefault;
20 |
21 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/logger/LogSender.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger.logger;
2 |
3 | import ch.sla.jdbcperflogger.model.LogMessage;
4 |
5 | public interface LogSender {
6 |
7 | void postLog(LogMessage log);
8 |
9 | }
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/logger/PerfLoggerClientThread.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.logger;
17 |
18 | import java.io.Closeable;
19 | import java.io.IOException;
20 | import java.net.InetSocketAddress;
21 | import java.net.Socket;
22 | import java.security.AccessController;
23 | import java.security.PrivilegedAction;
24 | import java.util.concurrent.TimeUnit;
25 |
26 | import ch.sla.jdbcperflogger.Logger;
27 |
28 | class PerfLoggerClientThread extends Thread implements Closeable {
29 | private final static Logger LOGGER = Logger.getLogger(PerfLoggerClientThread.class);
30 |
31 | private static final int CONNECT_TIMEOUT_MS = 30000;
32 |
33 | volatile boolean done;
34 |
35 | private final InetSocketAddress socketAddress;
36 |
37 | private Socket socket;
38 |
39 | static PerfLoggerClientThread spawn(final InetSocketAddress socketAddress) {
40 | // avoid Classloader leaks
41 |
42 | return AccessController.doPrivileged(new PrivilegedAction() {
43 | @Override
44 | public PerfLoggerClientThread run() {
45 | final ClassLoader savedClassLoader = Thread.currentThread().getContextClassLoader();
46 | try {
47 | Thread.currentThread().setContextClassLoader(null);
48 |
49 | final PerfLoggerClientThread thread = new PerfLoggerClientThread(socketAddress);
50 | thread.start();
51 | return thread;
52 | } finally {
53 | Thread.currentThread().setContextClassLoader(savedClassLoader);
54 | }
55 |
56 | }
57 | });
58 | }
59 |
60 | private PerfLoggerClientThread(final InetSocketAddress socketAddress) {
61 | this.setDaemon(true);
62 | this.setName("PerfLoggerClient " + socketAddress);
63 | this.socketAddress = socketAddress;
64 | }
65 |
66 | @Override
67 | public void run() {
68 | while (!done) {
69 | try {
70 | final InetSocketAddress resolvedAddress = new InetSocketAddress(socketAddress.getHostName(),
71 | socketAddress.getPort());
72 | socket = new Socket();
73 | socket.connect(resolvedAddress, CONNECT_TIMEOUT_MS);
74 | } catch (final IOException e) {
75 | LOGGER.debug("Unable to connect to " + socketAddress + ", will try again later", e);
76 | quietSleep(30);
77 | continue;
78 | }
79 | LOGGER.debug("Connected to " + socketAddress);
80 | try {
81 | final SocketLogSender sender = new SocketLogSender(socket);
82 | PerfLoggerRemoting.senders.add(sender);
83 | sender.run();
84 | } catch (final IOException e) {
85 | LOGGER.info("Error in connection with " + socketAddress + ", will try again later", e);
86 | }
87 | }
88 | LOGGER.debug("Client for " + socketAddress + "closed");
89 | }
90 |
91 | @Override
92 | public void close() {
93 | done = true;
94 | try {
95 | socket.close();
96 | } catch (final IOException e) {
97 | LOGGER.info("Error closing socket at port" + socket.getLocalPort());
98 | }
99 | }
100 |
101 | private void quietSleep(final int seconds) {
102 | try {
103 | Thread.sleep(TimeUnit.SECONDS.toMillis(seconds));
104 | } catch (final InterruptedException e) {
105 | }
106 | }
107 | }
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/logger/PerfLoggerRemoting.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.logger;
17 |
18 | import java.io.Closeable;
19 | import java.io.IOException;
20 | import java.net.InetSocketAddress;
21 | import java.util.ArrayList;
22 | import java.util.Date;
23 | import java.util.List;
24 | import java.util.Map;
25 | import java.util.Set;
26 | import java.util.WeakHashMap;
27 | import java.util.concurrent.CopyOnWriteArraySet;
28 |
29 | import ch.sla.jdbcperflogger.DriverConfig;
30 | import ch.sla.jdbcperflogger.driver.LoggingConnectionInvocationHandler;
31 | import ch.sla.jdbcperflogger.model.ConnectionInfo;
32 | import ch.sla.jdbcperflogger.model.LogMessage;
33 |
34 | public class PerfLoggerRemoting {
35 |
36 | final static Set senders = new CopyOnWriteArraySet();
37 | final static Map connectionToInfo = new WeakHashMap();
38 | final static List remotingThreads = new ArrayList();
39 |
40 | public static synchronized void start() {
41 | final Integer serverPort = DriverConfig.INSTANCE.getServerPort();
42 | if (serverPort != null) {
43 | remotingThreads.add(PerfLoggerServerThread.spawn(serverPort));
44 | }
45 | for (final InetSocketAddress clientAddress : DriverConfig.INSTANCE.getClientAddresses()) {
46 | remotingThreads.add(PerfLoggerClientThread.spawn(clientAddress));
47 | }
48 | }
49 |
50 | public static synchronized void stop() {
51 | for (final Closeable thread : remotingThreads) {
52 | try {
53 | thread.close();
54 | } catch (final IOException e) {
55 | // ignore
56 | }
57 | }
58 | remotingThreads.clear();
59 | }
60 |
61 | private PerfLoggerRemoting() {
62 | }
63 |
64 | public static void connectionCreated(final LoggingConnectionInvocationHandler connectionHandler,
65 | final long connectionCreationDuration) {
66 | final ConnectionInfo info = new ConnectionInfo(connectionHandler.getConnectionUuid(),
67 | connectionHandler.getConnectionId(), connectionHandler.getUrl(), new Date(), connectionCreationDuration,
68 | connectionHandler.getConnectionProperties());
69 | synchronized (connectionToInfo) {
70 | connectionToInfo.put(connectionHandler, info);
71 | postLog(info);
72 | }
73 | }
74 |
75 | static void postLog(final LogMessage log) {
76 | for (final LogSender sender : senders) {
77 | sender.postLog(log);
78 | }
79 | }
80 |
81 | public static void addSender(final LogSender sender) {
82 | senders.add(sender);
83 | }
84 |
85 | public static void removeSender(final LogSender sender) {
86 | senders.remove(sender);
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/logger/PerfLoggerServerThread.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.logger;
17 |
18 | import java.io.Closeable;
19 | import java.io.IOException;
20 | import java.net.ServerSocket;
21 | import java.net.Socket;
22 | import java.security.AccessController;
23 | import java.security.PrivilegedAction;
24 |
25 | import ch.sla.jdbcperflogger.Logger;
26 |
27 | class PerfLoggerServerThread extends Thread implements Closeable {
28 | private final static Logger LOGGER = Logger.getLogger(PerfLoggerServerThread.class);
29 |
30 | ServerSocket serverSocket;
31 | volatile boolean done;
32 |
33 | static PerfLoggerServerThread spawn(final int serverPort) {
34 | // avoid Classloader leaks
35 |
36 | return AccessController.doPrivileged(new PrivilegedAction() {
37 | @Override
38 | public PerfLoggerServerThread run() {
39 | final ClassLoader savedClassLoader = Thread.currentThread().getContextClassLoader();
40 | try {
41 | Thread.currentThread().setContextClassLoader(null);
42 |
43 | final PerfLoggerServerThread thread = new PerfLoggerServerThread(serverPort);
44 | thread.start();
45 | return thread;
46 | } finally {
47 | Thread.currentThread().setContextClassLoader(savedClassLoader);
48 | }
49 |
50 | }
51 | });
52 | }
53 |
54 | private PerfLoggerServerThread(final int serverPort) {
55 | this.setDaemon(true);
56 | this.setName("PerfLoggerServer acceptor port " + serverPort);
57 | try {
58 | serverSocket = new ServerSocket(serverPort);
59 | } catch (final IOException e) {
60 | throw new RuntimeException(e);
61 | }
62 | }
63 |
64 | @Override
65 | public void run() {
66 | try {
67 | while (!done) {
68 | try {
69 | final Socket socket = serverSocket.accept();
70 | LOGGER.debug("Got client connection from " + socket);
71 | final SocketLogSender sender = new SocketLogSender(socket);
72 | final Thread logSenderThread = new Thread(sender, "PerfLoggerServer " + socket.getInetAddress()
73 | + ":" + socket.getPort());
74 | logSenderThread.setDaemon(true);
75 | logSenderThread.start();
76 | PerfLoggerRemoting.senders.add(sender);
77 | } catch (final IOException e) {
78 | LOGGER.error("error while accepting socket", e);
79 | }
80 | }
81 | } finally {
82 | try {
83 | serverSocket.close();
84 | } catch (final IOException e) {
85 | LOGGER.error("error while closing socket", e);
86 | }
87 | }
88 | }
89 |
90 | @Override
91 | public void close() {
92 | done = true;
93 | try {
94 | serverSocket.close();
95 | } catch (final IOException e) {
96 | LOGGER.error("error closing socket at " + serverSocket.getLocalPort(), e);
97 | }
98 | }
99 | }
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/logger/RecordingLogSender.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger.logger;
2 |
3 | import java.util.concurrent.LinkedBlockingDeque;
4 |
5 | import org.eclipse.jdt.annotation.Nullable;
6 |
7 | import ch.sla.jdbcperflogger.model.LogMessage;
8 |
9 | public class RecordingLogSender implements LogSender {
10 | private static final int DEFAULT_RETAINED_LOG_MESSAGES_COUNT = 50;
11 | private final LinkedBlockingDeque queue;
12 |
13 | public RecordingLogSender() {
14 | this(DEFAULT_RETAINED_LOG_MESSAGES_COUNT);
15 | }
16 |
17 | public RecordingLogSender(final int retainedLogMessagesCount) {
18 | queue = new LinkedBlockingDeque(retainedLogMessagesCount);
19 |
20 | }
21 |
22 | @Override
23 | public void postLog(final LogMessage log) {
24 | while (!queue.offerFirst(log)) {
25 | queue.pollLast();
26 | }
27 | }
28 |
29 | public LogMessage[] getRecordedLogMessages() {
30 | return queue.toArray(new LogMessage[0]);
31 | }
32 |
33 | public void clearLogs() {
34 | queue.clear();
35 | }
36 |
37 | public @Nullable LogMessage lastLogMessage(final int index) {
38 | final LogMessage[] logs = getRecordedLogMessages();
39 | if (logs.length <= index) {
40 | return null;
41 | }
42 | return logs[index];
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/logger/SocketLogSender.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger.logger;
2 |
3 | import java.io.IOException;
4 | import java.io.ObjectOutputStream;
5 | import java.net.Socket;
6 | import java.net.SocketException;
7 | import java.util.concurrent.BlockingQueue;
8 | import java.util.concurrent.LinkedBlockingQueue;
9 | import java.util.concurrent.TimeUnit;
10 | import java.util.concurrent.atomic.AtomicBoolean;
11 |
12 | import ch.sla.jdbcperflogger.Logger;
13 | import ch.sla.jdbcperflogger.model.BufferFullLogMessage;
14 | import ch.sla.jdbcperflogger.model.ConnectionInfo;
15 | import ch.sla.jdbcperflogger.model.LogMessage;
16 |
17 | // public for tests
18 | public class SocketLogSender implements Runnable, LogSender {
19 | private final static Logger LOGGER2 = Logger.getLogger(SocketLogSender.class);
20 |
21 | private final BlockingQueue logsToSend = new LinkedBlockingQueue(10000);
22 | private final Socket socket;
23 | private final AtomicBoolean queueFull = new AtomicBoolean();
24 |
25 | SocketLogSender(final Socket socket) throws SocketException {
26 | this.socket = socket;
27 | socket.setKeepAlive(true);
28 | socket.setSoTimeout((int) TimeUnit.SECONDS.toMillis(10));
29 | }
30 |
31 | /* (non-Javadoc)
32 | * @see ch.sla.jdbcperflogger.logger.LogSender#postLog(ch.sla.jdbcperflogger.model.LogMessage)
33 | */
34 | @Override
35 | public void postLog(final LogMessage log) {
36 | final boolean posted = logsToSend.offer(log);
37 | if (!posted) {
38 | queueFull.set(true);
39 | LOGGER2.warn("queue full, dropping remote log of statement");
40 | }
41 | }
42 |
43 | @Override
44 | public void run() {
45 | // first send all current connections information to the socket
46 | synchronized (PerfLoggerRemoting.connectionToInfo) {
47 | for (final ConnectionInfo connectionInfo : PerfLoggerRemoting.connectionToInfo.values()) {
48 | logsToSend.offer(connectionInfo);
49 | }
50 | }
51 |
52 | ObjectOutputStream oos = null;
53 | try {
54 | oos = new ObjectOutputStream(socket.getOutputStream());
55 | int cnt = 0;
56 | while (true) {
57 | try {
58 | if (queueFull.compareAndSet(true, false)) {
59 | oos.writeUnshared(new BufferFullLogMessage(System.currentTimeMillis()));
60 | }
61 |
62 | final LogMessage log = logsToSend.poll(10, TimeUnit.SECONDS);
63 | if (log != null) {
64 | oos.writeUnshared(log);
65 | } else {
66 | // check the socket state
67 | if (socket.isClosed() || !socket.isConnected()) {
68 | // client disconnected
69 | break;
70 | }
71 | oos.writeUnshared(null);
72 | }
73 | cnt = (cnt + 1) % 10;
74 | if (cnt == 0) {
75 | // avoid mem leak when the stream keeps back
76 | // references to serialized objects
77 | oos.reset();
78 | }
79 | } catch (final InterruptedException e) {
80 | break;
81 | }
82 | }
83 | } catch (final IOException e) {
84 | LOGGER2.warn("socket error", e);
85 | } finally {
86 | LOGGER2.info("closing connection with " + socket);
87 | PerfLoggerRemoting.senders.remove(this);
88 | if (oos != null) {
89 | try {
90 | oos.close();
91 | } catch (final IOException ignored) {
92 | }
93 | }
94 | try {
95 | socket.close();
96 | } catch (final IOException e) {
97 | LOGGER2.error("error while closing socket", e);
98 | }
99 | }
100 | }
101 | }
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/logger/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | @NonNullByDefault
17 | package ch.sla.jdbcperflogger.logger;
18 |
19 | import org.eclipse.jdt.annotation.NonNullByDefault;
20 |
21 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/model/AbstractBeforeStatementExecutionLog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.model;
17 |
18 | import java.util.UUID;
19 |
20 | import ch.sla.jdbcperflogger.StatementType;
21 |
22 | public class AbstractBeforeStatementExecutionLog implements LogMessage {
23 |
24 | private static final long serialVersionUID = 1L;
25 |
26 | private final UUID connectionUuid;
27 | private final UUID logId;
28 | private final long timestamp;
29 | private final StatementType statementType;
30 | private final String threadName;
31 | private final int timeout;
32 | private final boolean autoCommit;
33 | private final int transactionIsolation;
34 |
35 | public AbstractBeforeStatementExecutionLog(final UUID connectionId, final UUID logId, final long timestamp,
36 | final StatementType statementType, final String threadName, final int timeout, final boolean autoCommit, int transactionIsolation) {
37 | connectionUuid = connectionId;
38 | this.logId = logId;
39 | this.timestamp = timestamp;
40 | this.statementType = statementType;
41 | this.threadName = threadName;
42 | this.timeout = timeout;
43 | this.autoCommit = autoCommit;
44 | this.transactionIsolation = transactionIsolation;
45 | }
46 |
47 | public UUID getConnectionUuid() {
48 | return connectionUuid;
49 | }
50 |
51 | public UUID getLogId() {
52 | return logId;
53 | }
54 |
55 | public long getTimestamp() {
56 | return timestamp;
57 | }
58 |
59 | public StatementType getStatementType() {
60 | return statementType;
61 | }
62 |
63 | public String getThreadName() {
64 | return threadName;
65 | }
66 |
67 | public int getTimeout() {
68 | return timeout;
69 | }
70 |
71 | public boolean isAutoCommit() {
72 | return autoCommit;
73 | }
74 |
75 | public int getTransactionIsolation() {
76 | return transactionIsolation;
77 | }
78 | }
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/model/BatchedNonPreparedStatementsLog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.model;
17 |
18 | import java.util.ArrayList;
19 | import java.util.Collections;
20 | import java.util.List;
21 | import java.util.UUID;
22 |
23 | import ch.sla.jdbcperflogger.StatementType;
24 |
25 | public class BatchedNonPreparedStatementsLog extends AbstractBeforeStatementExecutionLog {
26 |
27 | private static final long serialVersionUID = 1L;
28 |
29 | private final List sqlList;
30 |
31 | public BatchedNonPreparedStatementsLog(final UUID connectionId, final UUID logId, final long timestamp,
32 | final List sqlList, final String threadName, final int timeout, final boolean autoCommit,
33 | final int transactionIsolation) {
34 | super(connectionId, logId, timestamp, StatementType.NON_PREPARED_BATCH_EXECUTION, threadName, timeout,
35 | autoCommit, transactionIsolation);
36 | this.sqlList = Collections.unmodifiableList(new ArrayList(sqlList));
37 | }
38 |
39 | public List getSqlList() {
40 | return sqlList;
41 | }
42 |
43 | @Override
44 | public String toString() {
45 | return "BatchedNonPreparedStatementsLog["//
46 | + "logId=" + getLogId()//
47 | + ", timestamp=" + getTimestamp()//
48 | + ", statementType=" + getStatementType()//
49 | + ", threadName=" + getThreadName()//
50 | + ", timeout=" + getTimeout()//
51 | + ", autocommit=" + isAutoCommit()//
52 | + ", getTransactionIsolation=" + getTransactionIsolation()//
53 | + ", sqlList=" + sqlList//
54 | + "]";
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/model/BatchedPreparedStatementsLog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.model;
17 |
18 | import java.util.ArrayList;
19 | import java.util.Collections;
20 | import java.util.List;
21 | import java.util.UUID;
22 |
23 | import ch.sla.jdbcperflogger.StatementType;
24 |
25 | public class BatchedPreparedStatementsLog extends AbstractBeforeStatementExecutionLog {
26 |
27 | private static final long serialVersionUID = 1L;
28 |
29 | private final String rawSql;
30 | private final List sqlList;
31 |
32 | public BatchedPreparedStatementsLog(final UUID connectionId, final UUID logId, final long timestamp,
33 | final String rawSql, final List sqlList, final String threadName, final int timeout,
34 | final boolean autoCommit, final int transactionIsolation) {
35 | super(connectionId, logId, timestamp, StatementType.PREPARED_BATCH_EXECUTION, threadName, timeout, autoCommit, transactionIsolation);
36 | this.rawSql = rawSql;
37 | this.sqlList = Collections.unmodifiableList(new ArrayList(sqlList));
38 | }
39 |
40 | public String getRawSql() {
41 | return rawSql;
42 | }
43 |
44 | public List getSqlList() {
45 | return sqlList;
46 | }
47 |
48 | @Override
49 | public String toString() {
50 | return "BatchedPreparedStatementsLog["//
51 | + "logId=" + getLogId()//
52 | + ", rawSql=" + rawSql//
53 | + ", timestamp=" + getTimestamp()//
54 | + ", statementType=" + getStatementType()//
55 | + ", threadName=" + getThreadName()//
56 | + ", timeout=" + getTimeout()//
57 | + ", autocommit=" + isAutoCommit()//
58 | + ", transactionIsolation=" + getTransactionIsolation()//
59 | + "]";
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/model/BufferFullLogMessage.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger.model;
2 |
3 | public class BufferFullLogMessage implements LogMessage {
4 | private static final long serialVersionUID = 1L;
5 | private final long timestamp;
6 |
7 | public BufferFullLogMessage(final long tstamp) {
8 | this.timestamp = tstamp;
9 | }
10 |
11 | public long getTimestamp() {
12 | return timestamp;
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/model/ConnectionInfo.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger.model;
2 |
3 | import java.util.Date;
4 | import java.util.Properties;
5 | import java.util.UUID;
6 |
7 | public class ConnectionInfo implements LogMessage {
8 | private static final long serialVersionUID = 1L;
9 |
10 | private final UUID uuid;
11 | private final int connectionNumber;
12 | private final String url;
13 | private final Date creationDate;
14 | private final long connectionCreationDuration;
15 | /**
16 | * Connection props without password
17 | */
18 | private final Properties connectionProperties;
19 |
20 | public ConnectionInfo(final UUID uuid, final int connectionNumber, final String url, final Date creationDate,
21 | final long connectionCreationDuration, final Properties connectionProperties) {
22 | this.uuid = uuid;
23 | this.connectionNumber = connectionNumber;
24 | this.url = url;
25 | this.creationDate = creationDate;
26 | this.connectionCreationDuration = connectionCreationDuration;
27 | this.connectionProperties = connectionProperties;
28 | }
29 |
30 | public UUID getUuid() {
31 | return uuid;
32 | }
33 |
34 | public int getConnectionNumber() {
35 | return connectionNumber;
36 | }
37 |
38 | public String getUrl() {
39 | return url;
40 | }
41 |
42 | public Date getCreationDate() {
43 | return creationDate;
44 | }
45 |
46 | public Properties getConnectionProperties() {
47 | return connectionProperties;
48 | }
49 |
50 | public long getConnectionCreationDuration() {
51 | return connectionCreationDuration;
52 | }
53 |
54 | @Override
55 | public String toString() {
56 | return "ConnectionInfo["//
57 | + "connectionId=" + uuid//
58 | + ", connectionNumber=" + connectionNumber//
59 | + ", url=" + url//
60 | + ", creationDate=" + creationDate//
61 | + ", connectionCreationDuration=" + connectionCreationDuration//
62 | + "]";
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/model/LogMessage.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.model;
17 |
18 | import java.io.Serializable;
19 |
20 | public interface LogMessage extends Serializable {
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/model/PreparedStatementValuesHolder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.model;
17 |
18 | import java.io.Serializable;
19 | import java.util.HashMap;
20 |
21 | /**
22 | * Map from parameter index or name to value.
23 | *
24 | * @author slaurent
25 | *
26 | */
27 | public class PreparedStatementValuesHolder extends HashMap {
28 | private static final long serialVersionUID = 1L;
29 |
30 | public PreparedStatementValuesHolder() {
31 | super(10);
32 | }
33 |
34 | public PreparedStatementValuesHolder(final PreparedStatementValuesHolder original) {
35 | super(original);
36 | }
37 |
38 | public PreparedStatementValuesHolder copy() {
39 | return new PreparedStatementValuesHolder(this);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/model/ResultSetLog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.model;
17 |
18 | import java.util.UUID;
19 |
20 | public class ResultSetLog implements LogMessage {
21 |
22 | private static final long serialVersionUID = 1L;
23 |
24 | private final UUID logId;
25 |
26 | private final long resultSetUsageDurationNanos;
27 | private final long fetchDurationNanos;
28 | private final int nbRowsIterated;
29 |
30 | public ResultSetLog(final UUID logId, final long resultSetIterationTimeNanos, final long fetchDurationNanos,
31 | final int nbRowsIterated) {
32 | this.logId = logId;
33 | this.resultSetUsageDurationNanos = resultSetIterationTimeNanos;
34 | this.fetchDurationNanos = fetchDurationNanos;
35 | this.nbRowsIterated = nbRowsIterated;
36 | }
37 |
38 | public UUID getLogId() {
39 | return logId;
40 | }
41 |
42 | public long getResultSetUsageDurationNanos() {
43 | return resultSetUsageDurationNanos;
44 | }
45 |
46 | public long getFetchDurationNanos() {
47 | return fetchDurationNanos;
48 | }
49 |
50 | public int getNbRowsIterated() {
51 | return nbRowsIterated;
52 | }
53 |
54 | @Override
55 | public String toString() {
56 | return "ResultSetLog["//
57 | + "logId=" + logId//
58 | + ", resultSetUsageDurationNanos=" + resultSetUsageDurationNanos//
59 | + ", fetchDurationNanos=" + fetchDurationNanos//
60 | + ", nbRowsIterated=" + nbRowsIterated//
61 | + "]";
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/model/SqlTypedValue.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.model;
17 |
18 | import org.eclipse.jdt.annotation.Nullable;
19 |
20 | public class SqlTypedValue {
21 | @Nullable
22 | public final Object value;
23 | @Nullable
24 | public final Integer sqlType;
25 | @Nullable
26 | public final String setter;
27 |
28 | public SqlTypedValue(@Nullable final Object value, final @Nullable Integer sqlType) {
29 | this.value = value;
30 | this.sqlType = sqlType;
31 | setter = null;
32 | }
33 |
34 | public SqlTypedValue(final Object value, final String setter) {
35 | this.value = value;
36 | sqlType = -1;
37 | this.setter = setter;
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/model/StatementExecutedLog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.model;
17 |
18 | import java.util.UUID;
19 |
20 | import org.eclipse.jdt.annotation.Nullable;
21 |
22 | public class StatementExecutedLog implements LogMessage {
23 |
24 | private static final long serialVersionUID = 1L;
25 |
26 | private final UUID logId;
27 | private final long executionTimeNanos;
28 | @Nullable
29 | private final Long updateCount;
30 | @Nullable
31 | private final String sqlException;
32 |
33 | public StatementExecutedLog(final UUID logId, final long executionTimeNanos, @Nullable final Long updateCount,
34 | @Nullable final String sqlException) {
35 | this.logId = logId;
36 | this.executionTimeNanos = executionTimeNanos;
37 | this.updateCount = updateCount;
38 | this.sqlException = sqlException;
39 | }
40 |
41 | public UUID getLogId() {
42 | return logId;
43 | }
44 |
45 | public long getExecutionTimeNanos() {
46 | return executionTimeNanos;
47 | }
48 |
49 | @Nullable
50 | public Long getUpdateCount() {
51 | return updateCount;
52 | }
53 |
54 | @Nullable
55 | public String getSqlException() {
56 | return sqlException;
57 | }
58 |
59 | @Override
60 | public String toString() {
61 | return "StatementExecutedLog["//
62 | + "logId=" + logId//
63 | + ", executionTimeNanos=" + executionTimeNanos//
64 | + ", updateCount=" + updateCount//
65 | + "]";
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/model/StatementLog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.model;
17 |
18 | import java.util.UUID;
19 |
20 | import ch.sla.jdbcperflogger.StatementType;
21 |
22 | public class StatementLog extends AbstractBeforeStatementExecutionLog {
23 |
24 | private static final long serialVersionUID = 1L;
25 |
26 | private final String rawSql;
27 | private final String filledSql;
28 | private final boolean preparedStatement;
29 |
30 | public StatementLog(final UUID connectionId, final UUID logId, final long timestamp,
31 | final StatementType statementType, final String sql, final String threadName, final int timeout,
32 | final boolean autoCommit, final int transactionIsolation) {
33 | super(connectionId, logId, timestamp, statementType, threadName, timeout, autoCommit, transactionIsolation);
34 | rawSql = sql;
35 | filledSql = sql;
36 | preparedStatement = false;
37 | }
38 |
39 | public StatementLog(final UUID connectionId, final UUID logId, final long timestamp,
40 | final StatementType statementType, final String rawSql, final String filledSql, final String threadName,
41 | final int timeout, final boolean autoCommit, int transactionIsolation) {
42 | super(connectionId, logId, timestamp, statementType, threadName, timeout, autoCommit, transactionIsolation);
43 | this.rawSql = rawSql;
44 | this.filledSql = filledSql;
45 | preparedStatement = true;
46 | }
47 |
48 | public String getRawSql() {
49 | return rawSql;
50 | }
51 |
52 | public String getFilledSql() {
53 | return filledSql;
54 | }
55 |
56 | public boolean isPreparedStatement() {
57 | return preparedStatement;
58 | }
59 |
60 | @Override
61 | public String toString() {
62 | return "StatementLog["//
63 | + "logId=" + getLogId()//
64 | + ", timestamp=" + getTimestamp()//
65 | + ", statementType=" + getStatementType()//
66 | + ", threadName=" + getThreadName()//
67 | + ", timeout=" + getTimeout()//
68 | + ", autocommit=" + isAutoCommit()//
69 | + ", getTransactionIsolation=" + getTransactionIsolation()//
70 | + ", rawSql=" + rawSql//
71 | + ", filledSql=" + filledSql//
72 | + ", preparedStatement=" + preparedStatement//
73 | + "]";
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/model/TxCompleteLog.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger.model;
2 |
3 | import java.util.UUID;
4 |
5 | import org.eclipse.jdt.annotation.Nullable;
6 |
7 | import ch.sla.jdbcperflogger.TxCompletionType;
8 |
9 | public class TxCompleteLog implements LogMessage {
10 | private static final long serialVersionUID = 1L;
11 |
12 | private final UUID connectionUuid;
13 | private final long timestamp;
14 | private final TxCompletionType completionType;
15 | private final long executionTimeNanos;
16 | private final String threadName;
17 | @Nullable
18 | private final String savePointDescription;
19 |
20 | public TxCompleteLog(final UUID connectionUuid, final long timestamp, final TxCompletionType completionType,
21 | final long executionTimeNanos, final String threadName, final @Nullable String savePointDescription) {
22 | this.connectionUuid = connectionUuid;
23 | this.timestamp = timestamp;
24 | this.completionType = completionType;
25 | this.executionTimeNanos = executionTimeNanos;
26 | this.threadName = threadName;
27 | this.savePointDescription = savePointDescription;
28 | }
29 |
30 | public UUID getConnectionUuid() {
31 | return connectionUuid;
32 | }
33 |
34 | public long getTimestamp() {
35 | return timestamp;
36 | }
37 |
38 | public TxCompletionType getCompletionType() {
39 | return completionType;
40 | }
41 |
42 | public long getExecutionTimeNanos() {
43 | return executionTimeNanos;
44 | }
45 |
46 | public String getThreadName() {
47 | return threadName;
48 | }
49 |
50 | @Nullable
51 | public String getSavePointDescription() {
52 | return savePointDescription;
53 | }
54 |
55 | @Override
56 | public String toString() {
57 | return "TxCompleteLog["//
58 | + "connectionUuid=" + connectionUuid//
59 | + ", timestamp=" + timestamp//
60 | + ", completionType=" + completionType//
61 | + ", executionTimeNanos=" + executionTimeNanos//
62 | + ", threadName=" + threadName//
63 | + ", savePointDescription=" + savePointDescription//
64 | + "]";
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/model/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | @NonNullByDefault
17 | package ch.sla.jdbcperflogger.model;
18 |
19 | import org.eclipse.jdt.annotation.NonNullByDefault;
20 |
21 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/java/ch/sla/jdbcperflogger/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | @NonNullByDefault
17 | package ch.sla.jdbcperflogger;
18 |
19 | import org.eclipse.jdt.annotation.NonNullByDefault;
20 |
21 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/resources/.gitignore:
--------------------------------------------------------------------------------
1 | /log4j.xml
2 | /jdbcperflogger.xml
3 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/resources/META-INF/services/java.sql.Driver:
--------------------------------------------------------------------------------
1 | ch.sla.jdbcperflogger.driver.WrappingDriver
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/main/resources/jdbcperflogger-fallback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | jdbc:oracle:
8 | oracle.jdbc.OracleDriver
9 |
10 |
11 | jdbc:h2:
12 | org.h2.Driver
13 |
14 |
15 | jdbc:hsqldb:
16 | org.hsqldb.jdbc.JDBCDriver
17 |
18 |
19 | jdbc:mysql:
20 | com.mysql.jdbc.Driver
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/test/java/ch/sla/jdbcperflogger/DriverConfigTest.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger;
2 |
3 | import static org.junit.Assert.assertEquals;
4 | import static org.junit.Assert.assertNotNull;
5 | import static org.junit.Assert.assertNull;
6 | import static org.junit.Assert.assertTrue;
7 |
8 | import java.io.BufferedReader;
9 | import java.io.IOException;
10 | import java.io.InputStream;
11 | import java.io.InputStreamReader;
12 | import java.net.InetSocketAddress;
13 |
14 | import org.junit.Test;
15 |
16 | public class DriverConfigTest {
17 |
18 | private static final String TEST_TXT = "src/test/resourcesNonClasspath/test.txt";
19 |
20 | @SuppressWarnings("null")
21 | @Test
22 | public void testDefaultConfig() throws Exception {
23 | assertEquals(8889, DriverConfig.INSTANCE.getServerPort().intValue());
24 | assertEquals(1, DriverConfig.INSTANCE.getClientAddresses().size());
25 | final InetSocketAddress defaultClientAddress = DriverConfig.INSTANCE.getClientAddresses().get(0);
26 | assertEquals("localhost", defaultClientAddress.getHostName());
27 | assertEquals(4561, defaultClientAddress.getPort());
28 |
29 | assertEquals("oracle.jdbc.OracleDriver", DriverConfig.INSTANCE.getClassNameForJdbcUrl("jdbc:oracle:"));
30 | assertEquals("oracle.jdbc.OracleDriver", DriverConfig.INSTANCE.getClassNameForJdbcUrl("jdbc:oracle:thin:toto"));
31 | assertEquals("com.MyDriver", DriverConfig.INSTANCE.getClassNameForJdbcUrl("jdbc:mydriver:"));
32 | assertNull(DriverConfig.INSTANCE.getClassNameForJdbcUrl("jdbc:mynonexisting:"));
33 | }
34 |
35 | @Test
36 | public void testOpenFallbackConfigFile() throws Exception {
37 | final InputStream is = DriverConfig.openConfigFile(PerfLoggerConstants.CONFIG_FILE_FALLBACK_LOCATION);
38 | assertNotNull(is);
39 | is.close();
40 | }
41 |
42 | @Test
43 | public void testOpenFileNotInClasspath() throws Exception {
44 | InputStream is = DriverConfig.openConfigFile(TEST_TXT);
45 | assertNotNull(is);
46 | is.close();
47 |
48 | is = DriverConfig.openConfigFile("src/test/resourcesNonClasspath/notfound.txt");
49 | assertNull(is);
50 | }
51 |
52 | @Test
53 | public void testOpenDefaultConfigFile() throws Exception {
54 | final InputStream is = DriverConfig.openConfigFile();
55 | assertNotNull(is);
56 | is.close();
57 | }
58 |
59 | @Test
60 | public void testOpenSystemSpecifiedInexistentConfigFile() throws Exception {
61 | System.setProperty(PerfLoggerConstants.CONFIG_FILE_LOCATION_PROP_KEY, "dummy");
62 | final InputStream is = DriverConfig.openConfigFile();
63 | assertNotNull(is);
64 |
65 | final String line = readFirstLine(is);
66 | assertTrue(line.contains("fallback"));
67 | is.close();
68 | }
69 |
70 | @Test
71 | public void testOpenSystemSpecifiedConfigFileMalformed() throws Exception {
72 | System.setProperty(PerfLoggerConstants.CONFIG_FILE_LOCATION_PROP_KEY, TEST_TXT);
73 | final InputStream is = DriverConfig.openConfigFile();
74 | assertNotNull(is);
75 |
76 | final String line = readFirstLine(is);
77 | assertTrue(line.contains("HELLO"));
78 | is.close();
79 | }
80 |
81 | private String readFirstLine(final InputStream is) throws IOException {
82 | return new BufferedReader(new InputStreamReader(is)).readLine();
83 | }
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/test/java/ch/sla/jdbcperflogger/driver/UtilsTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.driver;
17 |
18 | import java.io.Serializable;
19 | import java.util.Collection;
20 | import java.util.Collections;
21 | import java.util.HashSet;
22 | import java.util.Set;
23 |
24 | import org.junit.Assert;
25 | import org.junit.Test;
26 |
27 | public class UtilsTest {
28 |
29 | @Test
30 | public void testExtractAllInterfaces() {
31 | final Class>[] intfs = Utils.extractAllInterfaces(HashSet.class);
32 | final Set> coll = new HashSet>();
33 | Collections.addAll(coll, intfs);
34 | Assert.assertTrue(coll.contains(Collection.class));
35 | Assert.assertTrue(coll.contains(Serializable.class));
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/test/java/ch/sla/jdbcperflogger/driver/WrappingDriverUnloadTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 Matthias Mueller
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.driver;
17 |
18 | import static org.awaitility.Awaitility.await;
19 |
20 | import java.io.IOException;
21 | import java.net.ServerSocket;
22 | import java.net.Socket;
23 | import java.util.concurrent.Callable;
24 | import java.util.concurrent.TimeUnit;
25 |
26 | import org.junit.Test;
27 |
28 | import ch.sla.jdbcperflogger.DriverConfig;
29 |
30 | public class WrappingDriverUnloadTest {
31 |
32 | private static final int WAIT_TIME = 10;
33 |
34 | @SuppressWarnings("null")
35 | @Test
36 | public void testUnload() throws Exception {
37 | final Integer serverPort = DriverConfig.INSTANCE.getServerPort();
38 | final int clientPort = DriverConfig.INSTANCE.getClientAddresses().get(0).getPort();
39 | final ServerSocket logReceiver = new ServerSocket(clientPort);
40 |
41 | await().atMost(WAIT_TIME, TimeUnit.SECONDS).until(portInUse(clientPort));
42 |
43 | WrappingDriver.load();
44 |
45 | try {
46 | await().atMost(WAIT_TIME, TimeUnit.SECONDS).until(portInUse(serverPort));
47 |
48 | final Socket client = logReceiver.accept();
49 | final int remotePort = client.getPort();
50 |
51 | // following line is commented, not working on macOS
52 | // await().atMost(WAIT_TIME, TimeUnit.SECONDS).until(portInUse(remotePort));
53 |
54 | client.close();
55 | logReceiver.close();
56 |
57 | WrappingDriver.unload();
58 | await().atMost(WAIT_TIME, TimeUnit.SECONDS).until(portNotInUse(clientPort));
59 | await().atMost(WAIT_TIME, TimeUnit.SECONDS).until(portNotInUse(serverPort));
60 | await().atMost(WAIT_TIME, TimeUnit.SECONDS).until(portNotInUse(remotePort));
61 | } finally {
62 | WrappingDriver.load();
63 | await().atMost(WAIT_TIME, TimeUnit.SECONDS).until(portInUse(serverPort));
64 | }
65 | }
66 |
67 | protected Callable portInUse(final int port) {
68 | return () -> !canOpenPort(port);
69 | }
70 |
71 | protected Callable portNotInUse(final int port) {
72 | return () -> canOpenPort(port);
73 | }
74 |
75 | protected boolean canOpenPort(final int port) {
76 | try (
77 | ServerSocket serverSocket = new ServerSocket(port)) {
78 | return true;
79 | } catch (final IOException e) {
80 | return false;
81 | }
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/test/java/ch/sla/jdbcperflogger/logger/MyClassLoader.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger.logger;
2 |
3 | import java.net.URL;
4 | import java.net.URLClassLoader;
5 |
6 | class MyClassLoader extends URLClassLoader {
7 |
8 | public MyClassLoader() {
9 | super(new URL[0]);
10 | }
11 |
12 | }
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/test/java/ch/sla/jdbcperflogger/logger/PerfLoggerClientThreadTest.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger.logger;
2 |
3 | import java.io.IOException;
4 | import java.net.InetSocketAddress;
5 |
6 | import org.junit.Assert;
7 | import org.junit.Test;
8 |
9 | public class PerfLoggerClientThreadTest {
10 |
11 | @Test
12 | public void testCCL() throws InterruptedException, IOException {
13 | final ClassLoader oldCcl = currentCcl();
14 | try {
15 | final MyClassLoader myClassLoader = new MyClassLoader();
16 | Thread.currentThread().setContextClassLoader(myClassLoader);
17 |
18 | final PerfLoggerClientThread thread = PerfLoggerClientThread.spawn(new InetSocketAddress("localhost", 0));
19 | Thread.sleep(1000);
20 | final ClassLoader classLoaderInsideThread = thread.getContextClassLoader();
21 | thread.done = true;
22 | thread.interrupt();
23 | thread.join();
24 |
25 | Assert.assertNotSame(myClassLoader, classLoaderInsideThread);
26 | } finally {
27 | Thread.currentThread().setContextClassLoader(oldCcl);
28 | }
29 | }
30 |
31 | private static ClassLoader currentCcl() {
32 | return Thread.currentThread().getContextClassLoader();
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/test/java/ch/sla/jdbcperflogger/logger/PerfLoggerServerThreadTest.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger.logger;
2 |
3 | import java.io.IOException;
4 |
5 | import org.junit.Assert;
6 | import org.junit.Test;
7 |
8 | public class PerfLoggerServerThreadTest {
9 |
10 | @Test
11 | public void testCCL() throws InterruptedException, IOException {
12 | final ClassLoader oldCcl = currentCcl();
13 | try {
14 | final MyClassLoader myClassLoader = new MyClassLoader();
15 | Thread.currentThread().setContextClassLoader(myClassLoader);
16 |
17 | final PerfLoggerServerThread thread = PerfLoggerServerThread.spawn(0);
18 | Thread.sleep(1000);
19 | final ClassLoader classLoaderInsideThread = thread.getContextClassLoader();
20 | thread.serverSocket.close();
21 | thread.done = true;
22 | thread.interrupt();
23 | thread.join();
24 |
25 | Assert.assertNotSame(myClassLoader, classLoaderInsideThread);
26 | } finally {
27 | Thread.currentThread().setContextClassLoader(oldCcl);
28 | }
29 | }
30 |
31 | private static ClassLoader currentCcl() {
32 | return Thread.currentThread().getContextClassLoader();
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/test/resources/jdbcperflogger.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | jdbc:oracle:
7 | oracle.jdbc.OracleDriver
8 |
9 |
10 | jdbc:mydriver:
11 | com.MyDriver
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/test/resources/log4j.dtd:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
22 |
23 |
26 |
27 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
58 |
59 |
60 |
61 |
62 |
65 |
69 |
70 |
71 |
74 |
75 |
76 |
79 |
80 |
81 |
82 |
83 |
84 |
87 |
88 |
89 |
90 |
91 |
94 |
95 |
96 |
100 |
101 |
102 |
103 |
104 |
108 |
109 |
110 |
111 |
115 |
116 |
117 |
118 |
119 |
120 |
125 |
126 |
127 |
128 |
129 |
133 |
134 |
135 |
136 |
138 |
139 |
140 |
142 |
143 |
144 |
147 |
148 |
149 |
150 |
154 |
155 |
156 |
159 |
160 |
161 |
164 |
165 |
166 |
170 |
171 |
172 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
193 |
194 |
195 |
196 |
198 |
199 |
200 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
220 |
221 |
222 |
223 |
224 |
228 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/test/resources/log4j.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/test/resources/logging.properties:
--------------------------------------------------------------------------------
1 | # since the driver uses java.util.logging, for tests we bridge it to slf4j
2 | handlers = org.slf4j.bridge.SLF4JBridgeHandler
3 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-driver/src/test/resourcesNonClasspath/test.txt:
--------------------------------------------------------------------------------
1 | HELLO
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/.gitignore:
--------------------------------------------------------------------------------
1 | /logdb
2 | /PerfLoggerGuiMain.launch
3 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/.settings/.gitignore:
--------------------------------------------------------------------------------
1 | !/org.eclipse.jdt.core.prefs
2 | !/org.eclipse.jdt.ui.prefs
3 | /*
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 |
4 | com.github.sylvainlaurent.jdbcperflogger
5 | jdbc-perf-logger
6 | 0.9.1-SNAPSHOT
7 |
8 |
9 | jdbc-perf-logger-gui
10 | jar
11 |
12 | jdbc-perf-logger-gui
13 |
14 |
15 |
16 | org.projectlombok
17 | lombok
18 | 1.18.12
19 | provided
20 |
21 |
22 | junit
23 | junit
24 | test
25 |
26 |
27 | com.github.sylvainlaurent.jdbcperflogger
28 | jdbc-perf-logger-agent
29 |
30 | provided
31 |
32 |
33 | com.github.sylvainlaurent.jdbcperflogger
34 | jdbc-perf-logger-driver
35 |
36 |
37 | org.slf4j
38 | slf4j-api
39 |
40 |
41 | org.slf4j
42 | slf4j-log4j12
43 |
44 |
45 | log4j
46 | log4j
47 | runtime
48 |
49 |
50 | com.h2database
51 | h2
52 |
53 |
54 | com.fifesoft
55 | rsyntaxtextarea
56 | 3.1.1
57 |
58 |
59 | org.eclipse.jdt
60 | org.eclipse.jdt.annotation
61 | provided
62 |
63 |
64 | org.mockito
65 | mockito-core
66 | test
67 |
68 |
69 |
70 |
71 |
72 |
73 | org.codehaus.mojo
74 | appassembler-maven-plugin
75 | 2.1.0
76 |
77 |
78 |
79 | ch.sla.jdbcperflogger.console.ui.PerfLoggerGuiMain
80 | jdbc-perf-logger-gui
81 |
82 | 20m
83 | 256m
84 |
85 |
86 |
87 |
88 | .sh
89 |
90 | flat
91 | lib
92 | true
93 |
94 |
95 | ${project.basedir}/src/main/appassembler/unixBinTemplate
96 | false
97 |
98 |
99 |
100 | package
101 |
102 | assemble
103 |
104 |
105 |
106 |
107 |
108 | maven-assembly-plugin
109 | 3.2.0
110 |
111 |
112 |
113 | src/main/assembly/distrib.xml
114 |
115 |
116 |
117 |
118 | package
119 |
120 | single
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/appassembler/unixBinTemplate:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | @LICENSE_HEADER@
3 |
4 | # resolve links - $0 may be a softlink
5 | PRG="$0"
6 |
7 | while [ -h "$PRG" ]; do
8 | ls=`ls -ld "$PRG"`
9 | link=`expr "$ls" : '.*-> \(.*\)$'`
10 | if expr "$link" : '/.*' > /dev/null; then
11 | PRG="$link"
12 | else
13 | PRG=`dirname "$PRG"`/"$link"
14 | fi
15 | done
16 |
17 | PRGDIR=`dirname "$PRG"`
18 | BASEDIR=`cd "$PRGDIR/.." >/dev/null; pwd`
19 | cd "$BASEDIR"
20 |
21 | @ENV_SETUP@
22 |
23 | # OS specific support. $var _must_ be set to either true or false.
24 | cygwin=false;
25 | darwin=false;
26 | case "`uname`" in
27 | CYGWIN*) cygwin=true ;;
28 | Darwin*) darwin=true
29 | if [ -z "$JAVA_VERSION" ] ; then
30 | JAVA_VERSION="CurrentJDK"
31 | else
32 | echo "Using Java version: $JAVA_VERSION"
33 | fi
34 | if [ -z "$JAVA_HOME" ]; then
35 | if [ -x "/usr/libexec/java_home" ]; then
36 | JAVA_HOME=`/usr/libexec/java_home`
37 | else
38 | JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/${JAVA_VERSION}/Home
39 | fi
40 | fi
41 | ;;
42 | esac
43 |
44 | if [ -z "$JAVA_HOME" ] ; then
45 | if [ -r /etc/gentoo-release ] ; then
46 | JAVA_HOME=`java-config --jre-home`
47 | fi
48 | fi
49 |
50 | # For Cygwin, ensure paths are in UNIX format before anything is touched
51 | if $cygwin ; then
52 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
53 | [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
54 | fi
55 |
56 | # If a specific java binary isn't specified search for the standard 'java' binary
57 | if [ -z "$JAVACMD" ] ; then
58 | if [ -n "$JAVA_HOME" ] ; then
59 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
60 | # IBM's JDK on AIX uses strange locations for the executables
61 | JAVACMD="$JAVA_HOME/jre/sh/java"
62 | else
63 | JAVACMD="$JAVA_HOME/bin/java"
64 | fi
65 | else
66 | JAVACMD=`which java`
67 | fi
68 | fi
69 |
70 | if [ ! -x "$JAVACMD" ] ; then
71 | echo "Error: JAVA_HOME is not defined correctly." 1>&2
72 | echo " We cannot execute $JAVACMD" 1>&2
73 | exit 1
74 | fi
75 |
76 | if [ -z "$REPO" ]
77 | then
78 | REPO="$BASEDIR"/@REPO@
79 | fi
80 |
81 | CLASSPATH=$CLASSPATH_PREFIX:@CLASSPATH@
82 |
83 | # For Cygwin, switch paths to Windows format before running java
84 | if $cygwin; then
85 | [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
86 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
87 | [ -n "$HOME" ] && HOME=`cygpath --path --windows "$HOME"`
88 | [ -n "$BASEDIR" ] && BASEDIR=`cygpath --path --windows "$BASEDIR"`
89 | [ -n "$REPO" ] && REPO=`cygpath --path --windows "$REPO"`
90 | fi
91 |
92 | exec "$JAVACMD" $JAVA_OPTS @EXTRA_JVM_ARGUMENTS@ \
93 | -classpath "$CLASSPATH" \
94 | -Dapp.name="@APP_NAME@" \
95 | -Dapp.pid="$$" \
96 | -Dapp.repo="$REPO" \
97 | -Dapp.home="$BASEDIR" \
98 | -Dbasedir="$BASEDIR" \
99 | @MAINCLASS@ \
100 | @APP_ARGUMENTS@"$@"@UNIX_BACKGROUND@
101 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/assembly/distrib.xml:
--------------------------------------------------------------------------------
1 |
3 | distrib
4 |
5 | zip
6 | tar.gz
7 |
8 |
9 |
10 | target/appassembler
11 | .
12 |
13 | **/*.sh
14 |
15 |
16 |
17 | target/appassembler
18 | .
19 |
20 | **/*.sh
21 |
22 | 744
23 |
24 |
25 | ../
26 | .
27 |
28 | README.md
29 | LICENSE.txt
30 | 3rdparty_license.txt
31 |
32 |
33 |
34 | ../jdbc-perf-logger-agent/target/
35 | lib
36 |
37 | jdbc-perf-logger-agent-*.jar
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/config/example-jdbcperflogger.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 |
8 | jdbc:oracle:
9 | oracle.jdbc.OracleDriver
10 |
11 |
12 | jdbc:h2:
13 | org.h2.Driver
14 |
15 |
16 | jdbc:hsqldb:
17 | org.hsqldb.jdbc.JDBCDriver
18 |
19 |
20 | jdbc:mysql:
21 | com.mysql.jdbc.Driver
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/config/log4j.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/java/ch/sla/jdbcperflogger/console/db/DetailedViewStatementLog.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger.console.db;
2 |
3 | import java.util.UUID;
4 |
5 | import lombok.Getter;
6 | import lombok.ToString;
7 | import org.eclipse.jdt.annotation.Nullable;
8 |
9 | import ch.sla.jdbcperflogger.StatementType;
10 | import ch.sla.jdbcperflogger.model.ConnectionInfo;
11 |
12 | @Getter
13 | @ToString
14 | public class DetailedViewStatementLog {
15 | private final UUID logId;
16 | private final long timestamp;
17 | @Nullable
18 | private final StatementType statementType;
19 | private final String rawSql;
20 | private final String filledSql;
21 | private final String threadName;
22 | @Nullable
23 | private final String sqlException;
24 | private final ConnectionInfo connectionInfo;
25 |
26 | public DetailedViewStatementLog(final UUID logId, final ConnectionInfo connectionInfo, final long timestamp,
27 | @Nullable final StatementType statementType, final String rawSql, final String filledSql,
28 | final String threadName, @Nullable final String exception) {
29 | this.logId = logId;
30 | this.connectionInfo = connectionInfo;
31 | this.timestamp = timestamp;
32 | this.statementType = statementType;
33 | this.rawSql = rawSql;
34 | this.filledSql = filledSql;
35 | this.threadName = threadName;
36 | sqlException = exception;
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/java/ch/sla/jdbcperflogger/console/db/LogRepositoryConstants.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger.console.db;
2 |
3 | public class LogRepositoryConstants {
4 |
5 | public static final String AUTOCOMMIT_COLUMN = "AUTOCOMMIT";
6 | public static final String AVG_EXEC_PLUS_RSET_USAGE_TIME_COLUMN = "AVG_EXEC_PLUS_RSET_USAGE_TIME";
7 | public static final String BATCHED_STMT_ORDER = "BATCHED_STMT_ORDER";
8 | public static final String CONNECTION_NUMBER_COLUMN = "connectionNumber";
9 | public static final String ERROR_COLUMN = "ERROR";
10 | public static final String EXEC_COUNT_COLUMN = "EXEC_COUNT";
11 | public static final String EXEC_PLUS_RSET_USAGE_TIME = "EXEC_PLUS_RSET_USAGE_TIME";
12 | public static final String EXEC_TIME_COLUMN = "execution_time";
13 | public static final String FETCH_TIME_COLUMN = "fetch_time";
14 | public static final String FILLED_SQL_COLUMN = "FILLEDSQL";
15 | public static final String ID_COLUMN = "ID";
16 | public static final String MAX_EXEC_PLUS_RSET_USAGE_TIME_COLUMN = "MAX_EXEC_PLUS_RSET_USAGE_TIME";
17 | public static final String MIN_EXEC_PLUS_RSET_USAGE_TIME_COLUMN = "MIN_EXEC_PLUS_RSET_USAGE_TIME";
18 | public static final String NB_ROWS_COLUMN = "NBROWS";
19 | public static final String RAW_SQL_COLUMN = "RAWSQL";
20 | public static final String RSET_USAGE_TIME = "RSET_USAGE_TIME";
21 | public static final String STMT_TYPE_COLUMN = "STATEMENTTYPE";
22 | public static final String THREAD_NAME_COLUMN = "threadName";
23 | public static final String TIMEOUT_COLUMN = "TIMEOUT";
24 | public static final String TOTAL_EXEC_PLUS_RSET_USAGE_TIME_COLUMN = "TOTAL_EXEC_PLUS_RSET_USAGE_TIME";
25 | public static final String TRANSACTION_ISOLATION_COLUMN = "TRANSACTION_ISOLATION";
26 | public static final String TSTAMP_COLUMN = "TSTAMP";
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/java/ch/sla/jdbcperflogger/console/db/LogRepositoryRead.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger.console.db;
2 |
3 | import java.util.UUID;
4 |
5 | import org.eclipse.jdt.annotation.Nullable;
6 |
7 | public interface LogRepositoryRead {
8 |
9 | void getStatements(LogSearchCriteria searchCriteria, ResultSetAnalyzer analyzer, boolean withFilledSql);
10 |
11 | void getStatementsGroupByRawSQL(LogSearchCriteria searchCriteria, ResultSetAnalyzer analyzer);
12 |
13 | void getStatementsGroupByFilledSQL(LogSearchCriteria searchCriteria, ResultSetAnalyzer analyzer);
14 |
15 | void getBatchStatementExecutions(UUID logId, ResultSetAnalyzer analyzer);
16 |
17 | @Nullable
18 | DetailedViewStatementLog getStatementLog(long id);
19 |
20 | int countStatements();
21 |
22 | long getTotalExecAndFetchTimeNanos();
23 |
24 | long getTotalExecAndFetchTimeNanos(LogSearchCriteria searchCriteria);
25 |
26 | void dispose();
27 | }
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/java/ch/sla/jdbcperflogger/console/db/LogRepositoryUpdate.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger.console.db;
2 |
3 | import java.util.Collection;
4 |
5 | import org.eclipse.jdt.annotation.Nullable;
6 |
7 | import ch.sla.jdbcperflogger.model.BatchedNonPreparedStatementsLog;
8 | import ch.sla.jdbcperflogger.model.BatchedPreparedStatementsLog;
9 | import ch.sla.jdbcperflogger.model.ConnectionInfo;
10 | import ch.sla.jdbcperflogger.model.ResultSetLog;
11 | import ch.sla.jdbcperflogger.model.StatementExecutedLog;
12 | import ch.sla.jdbcperflogger.model.StatementLog;
13 | import ch.sla.jdbcperflogger.model.TxCompleteLog;
14 |
15 | public interface LogRepositoryUpdate {
16 |
17 | void addConnection(ConnectionInfo connectionInfo);
18 |
19 | void addStatementLog(StatementLog log);
20 |
21 | void addStatementFullyExecutedLog(final Collection logs);
22 |
23 | void updateLogAfterExecution(StatementExecutedLog log);
24 |
25 | void updateLogWithResultSetLog(ResultSetLog log);
26 |
27 | void addBatchedPreparedStatementsLog(BatchedPreparedStatementsLog log);
28 |
29 | void addBatchedNonPreparedStatementsLog(BatchedNonPreparedStatementsLog log);
30 |
31 | void addTxCompletionLog(final TxCompleteLog log);
32 |
33 | void clear();
34 |
35 | void deleteStatementLog(final long... logIds);
36 |
37 | void dispose();
38 |
39 | long getLastModificationTime();
40 |
41 | void setLastLostMessageTime(@Nullable Long timestamp);
42 |
43 | @Nullable
44 | Long getLastLostMessageTime();
45 | }
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/java/ch/sla/jdbcperflogger/console/db/LogSearchCriteria.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger.console.db;
2 |
3 | import org.eclipse.jdt.annotation.NonNullByDefault;
4 |
5 | @NonNullByDefault({})
6 | public class LogSearchCriteria {
7 | private String filter;
8 | private Long minDurationNanos;
9 | private boolean removeTransactionCompletions;
10 | private String sqlPassThroughFilter;
11 |
12 | public String getFilter() {
13 | return filter;
14 | }
15 |
16 | public void setFilter(final String filter) {
17 | this.filter = filter;
18 | }
19 |
20 | public Long getMinDurationNanos() {
21 | return minDurationNanos;
22 | }
23 |
24 | public void setMinDurationNanos(final Long minDurationNanos) {
25 | this.minDurationNanos = minDurationNanos;
26 | }
27 |
28 | public boolean isRemoveTransactionCompletions() {
29 | return removeTransactionCompletions;
30 | }
31 |
32 | public void setRemoveTransactionCompletions(final boolean removeTransactionCompletions) {
33 | this.removeTransactionCompletions = removeTransactionCompletions;
34 | }
35 |
36 | public boolean atLeastOneFilterApplied() {
37 | return (filter != null && !filter.isEmpty()) || minDurationNanos != null || removeTransactionCompletions;
38 | }
39 |
40 | public String getSqlPassThroughFilter() {
41 | return sqlPassThroughFilter;
42 | }
43 |
44 | public void setSqlPassThroughFilter(final String sqlPassThroughFilter) {
45 | this.sqlPassThroughFilter = sqlPassThroughFilter;
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/java/ch/sla/jdbcperflogger/console/db/ResultSetAnalyzer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.console.db;
17 |
18 | import java.sql.ResultSet;
19 | import java.sql.SQLException;
20 |
21 | public interface ResultSetAnalyzer {
22 | void analyze(ResultSet resultSet) throws SQLException;
23 | }
24 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/java/ch/sla/jdbcperflogger/console/db/StatementFullyExecutedLog.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger.console.db;
2 |
3 | import java.util.UUID;
4 |
5 | import org.eclipse.jdt.annotation.Nullable;
6 |
7 | import ch.sla.jdbcperflogger.StatementType;
8 | import ch.sla.jdbcperflogger.model.ResultSetLog;
9 | import ch.sla.jdbcperflogger.model.StatementExecutedLog;
10 | import ch.sla.jdbcperflogger.model.StatementLog;
11 |
12 | public class StatementFullyExecutedLog {
13 | private final StatementLog statementLog;
14 | private final StatementExecutedLog statementExecutedLog;
15 | @Nullable
16 | private final ResultSetLog resultSetLog;
17 |
18 | public StatementFullyExecutedLog(final StatementLog statementLog, final StatementExecutedLog statementExecutedLog,
19 | @Nullable final ResultSetLog resultSetLog) {
20 | this.statementLog = statementLog;
21 | this.statementExecutedLog = statementExecutedLog;
22 | this.resultSetLog = resultSetLog;
23 | }
24 |
25 | public UUID getConnectionUuid() {
26 | return statementLog.getConnectionUuid();
27 | }
28 |
29 | public UUID getLogId() {
30 | return statementLog.getLogId();
31 | }
32 |
33 | public long getTimestamp() {
34 | return statementLog.getTimestamp();
35 | }
36 |
37 | public StatementType getStatementType() {
38 | return statementLog.getStatementType();
39 | }
40 |
41 | public String getThreadName() {
42 | return statementLog.getThreadName();
43 | }
44 |
45 | public int getTimeout() {
46 | return statementLog.getTimeout();
47 | }
48 |
49 | public boolean isAutoCommit() {
50 | return statementLog.isAutoCommit();
51 | }
52 |
53 | public int getTransactionIsolation() {
54 | return statementLog.getTransactionIsolation();
55 | }
56 |
57 | public String getRawSql() {
58 | return statementLog.getRawSql();
59 | }
60 |
61 | public String getFilledSql() {
62 | return statementLog.getFilledSql();
63 | }
64 |
65 | public boolean isPreparedStatement() {
66 | return statementLog.isPreparedStatement();
67 | }
68 |
69 | public long getExecutionTimeNanos() {
70 | return statementExecutedLog.getExecutionTimeNanos();
71 | }
72 |
73 | public long getExecutionPlusResultSetUsageTimeNanos() {
74 | return statementExecutedLog.getExecutionTimeNanos() + getResultSetUsageDurationNanosDefault0();
75 | }
76 |
77 | @Nullable
78 | public Long getUpdateCount() {
79 | return statementExecutedLog.getUpdateCount();
80 | }
81 |
82 | @Nullable
83 | public String getSqlException() {
84 | return statementExecutedLog.getSqlException();
85 | }
86 |
87 | @Nullable
88 | public Long getResultSetUsageDurationNanos() {
89 | // extracted to local variable to make eclipse null-analysis happy...
90 | final ResultSetLog resultSetLog2 = resultSetLog;
91 | return resultSetLog2 != null ? resultSetLog2.getResultSetUsageDurationNanos() : null;
92 | }
93 |
94 | public long getResultSetUsageDurationNanosDefault0() {
95 | final Long nanos = getResultSetUsageDurationNanos();
96 | if (nanos != null) {
97 | return nanos.longValue();
98 | } else {
99 | return 0L;
100 | }
101 | }
102 |
103 | @Nullable
104 | public Long getFetchDurationNanos() {
105 | // extracted to local variable to make eclipse null-analysis happy...
106 | final ResultSetLog resultSetLog2 = resultSetLog;
107 | return resultSetLog2 != null ? resultSetLog2.getFetchDurationNanos() : null;
108 | }
109 |
110 | @Nullable
111 | public Integer getNbRowsIterated() {
112 | // extracted to local variable to make eclipse null-analysis happy...
113 | final ResultSetLog resultSetLog2 = resultSetLog;
114 | return resultSetLog2 != null ? resultSetLog2.getNbRowsIterated() : null;
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/java/ch/sla/jdbcperflogger/console/db/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | @NonNullByDefault
17 | package ch.sla.jdbcperflogger.console.db;
18 |
19 | import org.eclipse.jdt.annotation.NonNullByDefault;
20 |
21 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/java/ch/sla/jdbcperflogger/console/net/AbstractLogReceiver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.console.net;
17 |
18 | import java.io.EOFException;
19 | import java.io.IOException;
20 | import java.io.InputStream;
21 | import java.io.ObjectInputStream;
22 | import java.net.Socket;
23 | import java.net.SocketTimeoutException;
24 |
25 | import org.eclipse.jdt.annotation.Nullable;
26 |
27 | import org.slf4j.Logger;
28 | import org.slf4j.LoggerFactory;
29 |
30 | import ch.sla.jdbcperflogger.model.LogMessage;
31 |
32 | public abstract class AbstractLogReceiver extends Thread {
33 | private final static Logger LOGGER = LoggerFactory.getLogger(AbstractLogReceiver.class);
34 |
35 | // Visible for testing
36 | protected int SOCKET_TIMEOUT = 60 * 1000;
37 |
38 | protected volatile boolean connected;
39 | protected volatile boolean paused = false;
40 | protected volatile boolean disposed = false;
41 | @Nullable
42 | protected Throwable lastConnectionError;
43 |
44 | public AbstractLogReceiver() {
45 | this.setDaemon(true);
46 | }
47 |
48 | /**
49 | * @return the current number of connections with this log receiver
50 | */
51 | public int getConnectionsCount() {
52 | return connected ? 1 : 0;
53 | }
54 |
55 | public void pauseReceivingLogs() {
56 | paused = true;
57 | }
58 |
59 | public void resumeReceivingLogs() {
60 | paused = false;
61 | }
62 |
63 | public boolean isPaused() {
64 | return paused;
65 | }
66 |
67 | public void dispose() {
68 | disposed = true;
69 | }
70 |
71 | protected void handleConnection(final Socket socket, final LogPersister logPersister) throws IOException {
72 | socket.setKeepAlive(true);
73 | socket.setSoTimeout(SOCKET_TIMEOUT);
74 |
75 | final InputStream is = socket.getInputStream();
76 |
77 | try (ObjectInputStream ois = new ObjectInputStream(is)) {
78 | connected = true;
79 | while (!disposed) {
80 | Object o;
81 | try {
82 | o = ois.readObject();
83 | } catch (final ClassNotFoundException e) {
84 | LOGGER.error(
85 | "unknown class, maybe the client is not compatible with the GUI? the msg will be skipped",
86 | e);
87 | continue;
88 | } catch (final EOFException e) {
89 | LOGGER.debug("The remote closed its connection");
90 | lastConnectionError = e;
91 | break;
92 | } catch (final SocketTimeoutException e) {
93 | LOGGER.debug("timeout while reading socket");
94 | lastConnectionError = e;
95 | continue;
96 | }
97 | if (o == null || paused || disposed) {
98 | continue;
99 | }
100 |
101 | logPersister.putMessage((LogMessage) o);
102 |
103 | }
104 | } finally {
105 | connected = false;
106 | LOGGER.debug("Closing socket " + socket);
107 | socket.close();
108 | }
109 |
110 | }
111 |
112 | public abstract boolean isServerMode();
113 |
114 | public @Nullable Throwable getLastConnectionError() {
115 | return lastConnectionError;
116 | }
117 |
118 | }
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/java/ch/sla/jdbcperflogger/console/net/ClientLogReceiver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.console.net;
17 |
18 | import java.io.IOException;
19 | import java.net.InetSocketAddress;
20 | import java.net.Socket;
21 | import java.util.concurrent.TimeUnit;
22 |
23 | import org.slf4j.Logger;
24 | import org.slf4j.LoggerFactory;
25 |
26 | import ch.sla.jdbcperflogger.console.db.LogRepositoryUpdate;
27 |
28 | public class ClientLogReceiver extends AbstractLogReceiver {
29 | private final static Logger LOGGER = LoggerFactory.getLogger(ClientLogReceiver.class);
30 |
31 | final InetSocketAddress targetRemoteAddress;
32 | private final LogRepositoryUpdate logRepository;
33 |
34 | public ClientLogReceiver(final String targetHost, final int targetPort, final LogRepositoryUpdate logRepository) {
35 | targetRemoteAddress = InetSocketAddress.createUnresolved(targetHost, targetPort);
36 | this.logRepository = logRepository;
37 | }
38 |
39 | @Override
40 | public void run() {
41 | try (LogPersister logPersister = new LogPersister(logRepository)) {
42 | logPersister.start();
43 | while (!disposed) {
44 | try {
45 | LOGGER.debug("Trying to connect to {}:{}", targetRemoteAddress.getHostName(),
46 | targetRemoteAddress, targetRemoteAddress.getPort());
47 | final Socket socket = new Socket(targetRemoteAddress.getHostName(), targetRemoteAddress.getPort());
48 | LOGGER.info("Connected to remote {}", targetRemoteAddress);
49 | handleConnection(socket, logPersister);
50 | } catch (final IOException e) {
51 | lastConnectionError = e;
52 | LOGGER.debug("expected error", e);
53 | }
54 | LOGGER.debug("Sleeping before trying to connect again to remote {}", targetRemoteAddress);
55 | try {
56 | Thread.sleep(TimeUnit.SECONDS.toMillis(10));
57 | } catch (final InterruptedException ignored) {
58 | }
59 |
60 | }
61 | }
62 |
63 | }
64 |
65 | @Override
66 | public boolean isServerMode() {
67 | return false;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/java/ch/sla/jdbcperflogger/console/net/LogPersister.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger.console.net;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.concurrent.ArrayBlockingQueue;
6 | import java.util.concurrent.BlockingQueue;
7 | import java.util.concurrent.TimeUnit;
8 |
9 | import org.eclipse.jdt.annotation.Nullable;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | import ch.sla.jdbcperflogger.console.db.LogRepositoryUpdate;
14 | import ch.sla.jdbcperflogger.console.db.StatementFullyExecutedLog;
15 | import ch.sla.jdbcperflogger.model.BatchedNonPreparedStatementsLog;
16 | import ch.sla.jdbcperflogger.model.BatchedPreparedStatementsLog;
17 | import ch.sla.jdbcperflogger.model.BufferFullLogMessage;
18 | import ch.sla.jdbcperflogger.model.ConnectionInfo;
19 | import ch.sla.jdbcperflogger.model.LogMessage;
20 | import ch.sla.jdbcperflogger.model.ResultSetLog;
21 | import ch.sla.jdbcperflogger.model.StatementExecutedLog;
22 | import ch.sla.jdbcperflogger.model.StatementLog;
23 | import ch.sla.jdbcperflogger.model.TxCompleteLog;
24 |
25 | class LogPersister extends Thread implements AutoCloseable {
26 | final static Logger LOGGER = LoggerFactory.getLogger(LogPersister.class);
27 |
28 | private volatile boolean disposed = false;
29 | protected final LogRepositoryUpdate logRepository;
30 | private final BlockingQueue logs = new ArrayBlockingQueue<>(10000);
31 |
32 | LogPersister(final LogRepositoryUpdate logRepository) {
33 | this.logRepository = logRepository;
34 | this.setName("LogPersister");
35 | }
36 |
37 | void putMessage(final LogMessage msg) {
38 | try {
39 | logs.put(msg);
40 | } catch (final InterruptedException e) {
41 | LOGGER.warn("interrupted", e);
42 | }
43 | }
44 |
45 | @Override
46 | public void close() {
47 | disposed = true;
48 | try {
49 | this.join();
50 | } catch (final InterruptedException e) {
51 | LOGGER.error("error while waiting for LogPersister thread to finish", e);
52 | }
53 | }
54 |
55 | @Override
56 | public void run() {
57 | final List drainedLogs = new ArrayList<>(1000);
58 | final List statementFullyExecutedLogs = new ArrayList<>(
59 | 100);
60 |
61 | while (!disposed) {
62 | @Nullable
63 | LogMessage logMessage;
64 | try {
65 | logMessage = logs.poll(1, TimeUnit.SECONDS);
66 | } catch (final InterruptedException e) {
67 | LOGGER.warn("interrupted", e);
68 | continue;
69 | }
70 |
71 | if (logMessage == null) {
72 | continue;
73 | }
74 | drainedLogs.clear();
75 | drainedLogs.add(logMessage);
76 | logs.drainTo(drainedLogs);
77 |
78 | for (int i = 0; i < drainedLogs.size(); i++) {
79 | logMessage = drainedLogs.get(i);
80 | if (i < drainedLogs.size() - 2 && logMessage instanceof StatementLog
81 | && drainedLogs.get(i + 1) instanceof StatementExecutedLog) {
82 | final StatementExecutedLog statementExecutedLog = (StatementExecutedLog) drainedLogs.get(i + 1);
83 | ResultSetLog resultSetLog = null;
84 | if (drainedLogs.get(i + 2) instanceof ResultSetLog) {
85 | resultSetLog = (ResultSetLog) drainedLogs.get(i + 2);
86 | }
87 | final StatementFullyExecutedLog statementFullyExecutedLog = new StatementFullyExecutedLog(
88 | (StatementLog) logMessage, statementExecutedLog, resultSetLog);
89 | statementFullyExecutedLogs.add(statementFullyExecutedLog);
90 |
91 | i += 1 + (resultSetLog != null ? 1 : 0);
92 | continue;
93 | }
94 |
95 | if (!statementFullyExecutedLogs.isEmpty()) {
96 | logRepository.addStatementFullyExecutedLog(statementFullyExecutedLogs);
97 | statementFullyExecutedLogs.clear();
98 | }
99 |
100 | if (logMessage instanceof ConnectionInfo) {
101 | logRepository.addConnection((ConnectionInfo) logMessage);
102 | } else if (logMessage instanceof StatementLog) {
103 | logRepository.addStatementLog((StatementLog) logMessage);
104 | } else if (logMessage instanceof StatementExecutedLog) {
105 | logRepository.updateLogAfterExecution((StatementExecutedLog) logMessage);
106 | } else if (logMessage instanceof ResultSetLog) {
107 | logRepository.updateLogWithResultSetLog((ResultSetLog) logMessage);
108 | } else if (logMessage instanceof BatchedNonPreparedStatementsLog) {
109 | logRepository.addBatchedNonPreparedStatementsLog((BatchedNonPreparedStatementsLog) logMessage);
110 | } else if (logMessage instanceof BatchedPreparedStatementsLog) {
111 | logRepository.addBatchedPreparedStatementsLog((BatchedPreparedStatementsLog) logMessage);
112 | } else if (logMessage instanceof TxCompleteLog) {
113 | logRepository.addTxCompletionLog((TxCompleteLog) logMessage);
114 | } else if (logMessage instanceof BufferFullLogMessage) {
115 | logRepository.setLastLostMessageTime(((BufferFullLogMessage) logMessage).getTimestamp());
116 | } else {
117 | throw new IllegalArgumentException("unexpected log, class=" + logMessage.getClass());
118 | }
119 | }
120 |
121 | if (!statementFullyExecutedLogs.isEmpty()) {
122 | logRepository.addStatementFullyExecutedLog(statementFullyExecutedLogs);
123 | statementFullyExecutedLogs.clear();
124 | }
125 |
126 | }
127 | }
128 |
129 | }
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/java/ch/sla/jdbcperflogger/console/net/ServerLogReceiver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.console.net;
17 |
18 | import java.io.IOException;
19 | import java.net.ServerSocket;
20 | import java.net.Socket;
21 | import java.net.SocketTimeoutException;
22 | import java.util.Set;
23 | import java.util.concurrent.CopyOnWriteArraySet;
24 | import java.util.concurrent.CountDownLatch;
25 | import java.util.concurrent.TimeUnit;
26 |
27 | import org.eclipse.jdt.annotation.NonNull;
28 | import org.eclipse.jdt.annotation.Nullable;
29 |
30 | import org.slf4j.Logger;
31 | import org.slf4j.LoggerFactory;
32 |
33 | import ch.sla.jdbcperflogger.console.db.LogRepositoryUpdate;
34 |
35 | public class ServerLogReceiver extends AbstractLogReceiver {
36 | final static Logger LOGGER = LoggerFactory.getLogger(ServerLogReceiver.class);
37 |
38 | private final Set childReceivers = new CopyOnWriteArraySet<>();
39 | private final LogRepositoryUpdate logRepository;
40 | private int listenPort;
41 | @Nullable
42 | private volatile ServerSocket serverSocket;
43 | private final CountDownLatch serverStartedLatch = new CountDownLatch(1);
44 |
45 | public ServerLogReceiver(final int listenPort, final LogRepositoryUpdate logRepository) {
46 | this.listenPort = listenPort;
47 | this.logRepository = logRepository;
48 | }
49 |
50 | @Override
51 | public void dispose() {
52 | super.dispose();
53 | try {
54 | final ServerSocket serverSocketLocalVar = serverSocket;
55 | if (serverSocketLocalVar != null) {
56 | serverSocketLocalVar.close();
57 | }
58 | } catch (final IOException e) {
59 | LOGGER.error("error while closing socket", e);
60 | }
61 | try {
62 | this.join();
63 | } catch (final InterruptedException e) {
64 | // ignore
65 | }
66 | }
67 |
68 | // visible for testing
69 | protected int getListenPort() {
70 | return listenPort;
71 | }
72 |
73 | @Override
74 | public int getConnectionsCount() {
75 | int cnt = 0;
76 | // it's thread-safe to iterate over childReceivers because it's a CopyOnWriteArraySet
77 | for (final AbstractLogReceiver receiver : childReceivers) {
78 | cnt += receiver.getConnectionsCount();
79 | }
80 | return cnt;
81 | }
82 |
83 | @Override
84 | public void run() {
85 | try (ServerSocket serverSocketLocalVar = new ServerSocket(listenPort)) {
86 | // if listenPort is 0, a port has been chosen by the OS
87 | listenPort = serverSocketLocalVar.getLocalPort();
88 | serverSocketLocalVar.setSoTimeout((int) TimeUnit.MINUTES.toMillis(5));
89 | serverSocket = serverSocketLocalVar;
90 | this.setName("ServerLogReceiver " + listenPort);
91 |
92 | try (LogPersister logPersister = new LogPersister(logRepository)) {
93 | logPersister.start();
94 |
95 | // signal threads that might be waiting for the server to be ready
96 | serverStartedLatch.countDown();
97 |
98 | while (!disposed) {
99 | try {
100 | LOGGER.debug("Waiting for client connections on " + serverSocketLocalVar);
101 | @NonNull
102 | final Socket socket = serverSocketLocalVar.accept();
103 | LOGGER.debug("Got client connection from " + socket);
104 |
105 | final AbstractLogReceiver logReceiver = new AbstractLogReceiver() {
106 | @Override
107 | public void run() {
108 | try {
109 | handleConnection(socket, logPersister);
110 | } catch (final IOException e) {
111 | LOGGER.error("error while receiving logs from " + socket.getRemoteSocketAddress(),
112 | e);
113 | } finally {
114 | childReceivers.remove(this);
115 | }
116 | }
117 |
118 | @Override
119 | public boolean isServerMode() {
120 | return true;
121 | }
122 |
123 | };
124 | logReceiver.setName("LogReceiver " + socket.getRemoteSocketAddress());
125 | if (isPaused()) {
126 | logReceiver.pauseReceivingLogs();
127 | }
128 | childReceivers.add(logReceiver);
129 | logReceiver.start();
130 | } catch (final SocketTimeoutException e) {
131 | LOGGER.debug("timeout while accepting socket", e);
132 | } catch (final IOException e) {
133 | if (!disposed) {
134 | LOGGER.error("error while accepting socket", e);
135 | } else {
136 | LOGGER.debug("error while accepting socket, the server has been closed", e);
137 | }
138 | }
139 | }
140 | } finally {
141 | LOGGER.debug("Closing server socket " + serverSocketLocalVar);
142 | if (!serverSocketLocalVar.isClosed()) {
143 | try {
144 | serverSocketLocalVar.close();
145 | } catch (final IOException e) {
146 | LOGGER.error("error while closing socket", e);
147 | }
148 | }
149 | }
150 | } catch (final IOException e) {
151 | lastConnectionError = e;
152 | throw new RuntimeException(e);
153 | }
154 |
155 | }
156 |
157 | @Override
158 | public boolean isServerMode() {
159 | return true;
160 | }
161 |
162 | @Override
163 | public void pauseReceivingLogs() {
164 | super.pauseReceivingLogs();
165 | for (final AbstractLogReceiver child : childReceivers) {
166 | child.pauseReceivingLogs();
167 | }
168 | }
169 |
170 | @Override
171 | public void resumeReceivingLogs() {
172 | super.resumeReceivingLogs();
173 | for (final AbstractLogReceiver child : childReceivers) {
174 | child.resumeReceivingLogs();
175 | }
176 | }
177 |
178 | // visible for testing
179 | void waitUntilServerIsReady() throws InterruptedException {
180 | serverStartedLatch.await();
181 | }
182 |
183 | }
184 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/java/ch/sla/jdbcperflogger/console/net/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | @NonNullByDefault
17 | package ch.sla.jdbcperflogger.console.net;
18 |
19 | import org.eclipse.jdt.annotation.NonNullByDefault;
20 |
21 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/java/ch/sla/jdbcperflogger/console/ui/CustomTable.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.console.ui;
17 |
18 | import ch.sla.jdbcperflogger.StatementType;
19 | import ch.sla.jdbcperflogger.console.db.LogRepositoryConstants;
20 |
21 | import org.eclipse.jdt.annotation.Nullable;
22 | import javax.swing.*;
23 | import javax.swing.table.JTableHeader;
24 | import javax.swing.table.TableCellRenderer;
25 | import java.awt.*;
26 | import java.awt.event.MouseEvent;
27 | import java.math.BigDecimal;
28 |
29 | public class CustomTable extends JTable {
30 | private static final long serialVersionUID = 1L;
31 |
32 | private static final Color ERROR_COLOR = Color.RED;
33 | private static final Color DEFAULT_BG_COLOR = Color.WHITE;
34 | private static final Color HIGHLIGHT_COLOR = Color.ORANGE;
35 | private static final Color COMMIT_COLOR = new Color(204, 255, 102);
36 | private static final Color ROLLBACK_COLOR = Color.PINK;
37 |
38 | @Nullable
39 | private String txtToHighlightUpper;
40 | @Nullable
41 | private Long minDurationNanoToHighlight;
42 |
43 | CustomTable(final ResultSetDataModel tm) {
44 | super(tm);
45 | }
46 |
47 | // Implement table header tool tips.
48 | @Override
49 | protected JTableHeader createDefaultTableHeader() {
50 | return new JTableHeader(columnModel) {
51 | private static final long serialVersionUID = 1L;
52 |
53 | @Override
54 | public String getToolTipText(@Nullable final MouseEvent e) {
55 | assert e != null;
56 | final java.awt.Point p = e.getPoint();
57 | final int index = columnModel.getColumnIndexAtX(p.x);
58 | if (index >= 0) {
59 | return columnModel.getColumn(index).getHeaderValue().toString();
60 | } else {
61 | return "";
62 | }
63 | }
64 | };
65 | }
66 |
67 | @Override
68 | public Component prepareRenderer(@Nullable final TableCellRenderer renderer, final int row, final int column) {
69 | assert renderer != null;
70 | final Component component = super.prepareRenderer(renderer, row, column);
71 |
72 | if (!this.getSelectionModel().isSelectedIndex(row)) {
73 | final ResultSetDataModel model = (ResultSetDataModel) getModel();
74 | final int modelIndex = convertRowIndexToModel(row);
75 |
76 | Color bgColor = DEFAULT_BG_COLOR;
77 | final StatementType statementType = (StatementType) model.getValueAt(modelIndex,
78 | LogRepositoryConstants.STMT_TYPE_COLUMN);
79 | final String sql = (String) model.getValueAt(modelIndex, LogRepositoryConstants.RAW_SQL_COLUMN);
80 |
81 | if (statementType == StatementType.TRANSACTION && sql != null) {
82 | if (sql.contains("COMMIT")) {
83 | bgColor = COMMIT_COLOR;
84 | } else if (sql.contains("ROLLBACK")) {
85 | bgColor = ROLLBACK_COLOR;
86 | }
87 | }
88 | final Integer error = (Integer) model.getValueAt(modelIndex, LogRepositoryConstants.ERROR_COLUMN);
89 | if (error != null && error.intValue() != 0) {
90 | bgColor = ERROR_COLOR;
91 | } else if (txtToHighlightUpper != null) {
92 | if (sql != null && sql.toUpperCase().contains(txtToHighlightUpper)) {
93 | bgColor = HIGHLIGHT_COLOR;
94 | }
95 | } else {
96 | final Long minDurationNanoToHighlight2 = minDurationNanoToHighlight;
97 | if (minDurationNanoToHighlight2 != null) {
98 | Long duration = (Long) model.getValueAt(modelIndex,
99 | LogRepositoryConstants.EXEC_PLUS_RSET_USAGE_TIME);
100 | if (duration == null) {
101 | // in case we are in group by mode
102 | final BigDecimal val = (BigDecimal) model.getValueAt(modelIndex,
103 | LogRepositoryConstants.TOTAL_EXEC_PLUS_RSET_USAGE_TIME_COLUMN);
104 | if (val != null) {
105 | duration = val.longValue();
106 | }
107 | }
108 | if (duration != null && duration.longValue() >= minDurationNanoToHighlight2.longValue()) {
109 | bgColor = HIGHLIGHT_COLOR;
110 | }
111 | }
112 | }
113 | component.setBackground(bgColor);
114 | }
115 | return component;
116 | }
117 |
118 | public void setTxtToHighlight(@Nullable final String txtToHighlight) {
119 | if (txtToHighlight != null) {
120 | txtToHighlightUpper = txtToHighlight.toUpperCase();
121 | } else {
122 | txtToHighlightUpper = null;
123 | }
124 | }
125 |
126 | public void setMinDurationNanoToHighlight(@Nullable final Long minDurationNanoToHighlight) {
127 | this.minDurationNanoToHighlight = minDurationNanoToHighlight;
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/java/ch/sla/jdbcperflogger/console/ui/CustomTableCellRenderer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.console.ui;
17 |
18 | import java.awt.Color;
19 | import java.awt.Component;
20 | import java.util.function.BiFunction;
21 | import java.util.function.Function;
22 |
23 | import org.eclipse.jdt.annotation.Nullable;
24 | import javax.swing.JTable;
25 | import javax.swing.table.DefaultTableCellRenderer;
26 |
27 | import ch.sla.jdbcperflogger.StatementType;
28 | import ch.sla.jdbcperflogger.console.db.LogRepositoryConstants;
29 |
30 | import static java.sql.Connection.*;
31 |
32 | @SuppressWarnings("serial")
33 | public class CustomTableCellRenderer extends DefaultTableCellRenderer {
34 |
35 | @Override
36 | public Component getTableCellRendererComponent(@Nullable final JTable table, @Nullable final Object value,
37 | final boolean isSelected, final boolean hasFocus, final int row, final int column) {
38 | assert table != null;
39 |
40 | final CustomTableCellRenderer component = (CustomTableCellRenderer) super.getTableCellRendererComponent(table,
41 | value, isSelected, hasFocus, row, column);
42 |
43 | final int columnModelIndex = table.convertColumnIndexToModel(column);
44 |
45 | final ResultSetDataModel dataModel = (ResultSetDataModel) table.getModel();
46 | if (LogRepositoryConstants.STMT_TYPE_COLUMN.equals(dataModel.getColumnName(columnModelIndex))) {
47 | final int modelRowIndex = table.convertRowIndexToModel(row);
48 | final StatementType statementType = (StatementType) dataModel.getValueAt(modelRowIndex, columnModelIndex);
49 | assert statementType != null;
50 | switch (statementType) {
51 | case BASE_NON_PREPARED_STMT:
52 | component.setForeground(Color.ORANGE);
53 | component.setText("S");
54 | break;
55 | case NON_PREPARED_QUERY_STMT:
56 | component.setForeground(Color.RED);
57 | component.setText("Q");
58 | break;
59 | case NON_PREPARED_BATCH_EXECUTION:
60 | component.setForeground(Color.MAGENTA);
61 | component.setText("B");
62 | break;
63 | case PREPARED_BATCH_EXECUTION:
64 | component.setForeground(Color.BLUE);
65 | component.setText("PB");
66 | break;
67 | case BASE_PREPARED_STMT:
68 | component.setForeground(Color.CYAN);
69 | component.setText("PS");
70 | break;
71 | case PREPARED_QUERY_STMT:
72 | component.setForeground(Color.GREEN);
73 | component.setText("PQ");
74 | break;
75 | case TRANSACTION:
76 | component.setForeground(Color.DARK_GRAY);
77 | component.setText("TX");
78 | break;
79 | }
80 |
81 | component.setToolTipText(value + " (use STATEMENTTYPE=" + statementType.getId()
82 | + " in the \"Advanced filter\")");
83 | } else if (LogRepositoryConstants.TRANSACTION_ISOLATION_COLUMN.equals(dataModel.getColumnName(columnModelIndex))) {
84 | final int modelRowIndex = table.convertRowIndexToModel(row);
85 | final Integer transactionIsolation = (Integer) dataModel.getValueAt(modelRowIndex, columnModelIndex);
86 | if (transactionIsolation != null ) {
87 | final Function toDescription = text -> text + " (" + transactionIsolation + ")";
88 | switch (transactionIsolation) {
89 | case TRANSACTION_READ_UNCOMMITTED:
90 | component.setText("RU");
91 | component.setToolTipText(toDescription.apply("Read Uncommitted"));
92 | break;
93 | case TRANSACTION_READ_COMMITTED:
94 | component.setText("RC");
95 | component.setToolTipText(toDescription.apply("Read Committed"));
96 | break;
97 | case TRANSACTION_REPEATABLE_READ:
98 | component.setText("RR");
99 | component.setToolTipText(toDescription.apply("Repeatable Read"));
100 | break;
101 | case TRANSACTION_SERIALIZABLE:
102 | component.setText("SE");
103 | component.setToolTipText(toDescription.apply("Serializable"));
104 | break;
105 | }
106 | }
107 |
108 | } else if (value != null) {
109 | component.setToolTipText(value.toString());
110 | }
111 |
112 | return component;
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/java/ch/sla/jdbcperflogger/console/ui/CustomTableRowSorter.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger.console.ui;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import javax.swing.SortOrder;
7 | import javax.swing.table.TableRowSorter;
8 |
9 | import ch.sla.jdbcperflogger.console.db.LogRepositoryConstants;
10 |
11 | /**
12 | * Custom {@link TableRowSorter} that allows to sort on statement ID when the user wants to sort on the timestamp. This
13 | * allows to have a correct order even if 2 statements occurred at the same millisecond.
14 | *
15 | * @author slaurent
16 | *
17 | */
18 | public class CustomTableRowSorter extends TableRowSorter {
19 | public CustomTableRowSorter(final ResultSetDataModel datamodel) {
20 | super(datamodel);
21 | }
22 |
23 | @Override
24 | public void toggleSortOrder(final int column) {
25 | if (LogRepositoryConstants.TSTAMP_COLUMN.equals(getModel().getColumnName(column))) {
26 | // sort on ID instead
27 | setMaxSortKeys(2);
28 | final List keys = new ArrayList<>(getSortKeys());
29 | if (keys.size() <= 1) {
30 | keys.clear();
31 | keys.add(new SortKey(column, SortOrder.DESCENDING));
32 | keys.add(new SortKey(0, SortOrder.DESCENDING));
33 | } else {
34 | final SortOrder previousOrder = keys.get(0).getSortOrder();
35 | final SortOrder newOrder = previousOrder == SortOrder.ASCENDING ? SortOrder.DESCENDING
36 | : SortOrder.ASCENDING;
37 | keys.set(0, new SortKey(column, newOrder));
38 | keys.set(1, new SortKey(0, newOrder));
39 | }
40 | setSortKeys(keys);
41 | } else {
42 | setMaxSortKeys(1);
43 | super.toggleSortOrder(column);
44 | }
45 |
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/java/ch/sla/jdbcperflogger/console/ui/GuiUtils.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger.console.ui;
2 |
3 | import java.awt.Desktop;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.net.URI;
7 | import java.net.URISyntaxException;
8 | import java.util.Properties;
9 |
10 | import org.eclipse.jdt.annotation.Nullable;
11 |
12 | import org.slf4j.Logger;
13 | import org.slf4j.LoggerFactory;
14 |
15 | public class GuiUtils {
16 | private final static Logger LOGGER = LoggerFactory.getLogger(WelcomePanel.class);
17 |
18 | static String getAppVersion() {
19 | final Properties mavenProps = new Properties();
20 | try (@Nullable
21 | InputStream pomPropsFile = WelcomePanel.class
22 | .getResourceAsStream("/META-INF/maven/com.github.sylvainlaurent.jdbcperflogger/jdbc-perf-logger-gui/pom.properties")) {
23 | if (pomPropsFile != null) {
24 | mavenProps.load(pomPropsFile);
25 | }
26 | return mavenProps.getProperty("version");
27 | } catch (final IOException e) {
28 | LOGGER.warn("", e);
29 | return "unknown";
30 | }
31 | }
32 |
33 | static void openWebSite(final String address) {
34 | if (Desktop.isDesktopSupported()) {
35 | try {
36 | final URI uri = new URI(address);
37 | Desktop.getDesktop().browse(uri);
38 | } catch (URISyntaxException | IOException e) {
39 | throw new RuntimeException("unexpected", e);
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/java/ch/sla/jdbcperflogger/console/ui/HostPort.java:
--------------------------------------------------------------------------------
1 | package ch.sla.jdbcperflogger.console.ui;
2 |
3 | import org.eclipse.jdt.annotation.Nullable;
4 |
5 | public class HostPort implements Comparable {
6 | private final String host;
7 | private final int port;
8 |
9 | public HostPort(final String host, final int port) {
10 | this.host = host;
11 | this.port = port;
12 | }
13 |
14 | public String getHost() {
15 | return host;
16 | }
17 |
18 | public int getPort() {
19 | return port;
20 | }
21 |
22 | @Override
23 | public String toString() {
24 | return host + ":" + port;
25 | }
26 |
27 | @Override
28 | public int compareTo( final HostPort o) {
29 | int cmp = host.compareToIgnoreCase(o.host);
30 | if (cmp != 0) {
31 | return cmp;
32 | }
33 | cmp = port - o.port;
34 | return cmp;
35 | }
36 |
37 | @Override
38 | public int hashCode() {
39 | final int prime = 31;
40 | int result = 1;
41 | result = prime * result + host.hashCode();
42 | result = prime * result + port;
43 | return result;
44 | }
45 |
46 | @Override
47 | public boolean equals(@Nullable final Object obj) {
48 | if (this == obj) {
49 | return true;
50 | }
51 | if (obj == null) {
52 | return false;
53 | }
54 | if (getClass() != obj.getClass()) {
55 | return false;
56 | }
57 | final HostPort other = (HostPort) obj;
58 | return compareTo(other) == 0;
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/java/ch/sla/jdbcperflogger/console/ui/IClientConnectionDelegate.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.console.ui;
17 |
18 | public interface IClientConnectionDelegate {
19 | void createClientConnection(String host, int port);
20 |
21 | void close(PerfLoggerController perLoggercController);
22 | }
23 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/java/ch/sla/jdbcperflogger/console/ui/PerfLoggerGuiMain.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.console.ui;
17 |
18 | import java.awt.Dimension;
19 | import java.awt.Frame;
20 | import java.util.HashMap;
21 | import java.util.Map;
22 | import java.util.prefs.BackingStoreException;
23 | import java.util.prefs.Preferences;
24 |
25 | import org.eclipse.jdt.annotation.Nullable;
26 | import javax.swing.JPanel;
27 | import javax.swing.SwingUtilities;
28 | import javax.swing.ToolTipManager;
29 | import javax.swing.UIManager;
30 | import javax.swing.UnsupportedLookAndFeelException;
31 |
32 | import org.slf4j.Logger;
33 | import org.slf4j.LoggerFactory;
34 |
35 | import ch.sla.jdbcperflogger.console.db.LogRepositoryRead;
36 | import ch.sla.jdbcperflogger.console.db.LogRepositoryReadJdbc;
37 | import ch.sla.jdbcperflogger.console.db.LogRepositoryUpdate;
38 | import ch.sla.jdbcperflogger.console.db.LogRepositoryUpdateJdbc;
39 | import ch.sla.jdbcperflogger.console.net.AbstractLogReceiver;
40 | import ch.sla.jdbcperflogger.console.net.ClientLogReceiver;
41 | import ch.sla.jdbcperflogger.console.net.ServerLogReceiver;
42 |
43 | public class PerfLoggerGuiMain implements IClientConnectionDelegate {
44 | private static final String LOOK_AND_FEEL_CLASS_NAME_PREF_KEY = "lookAndFeelClassName";
45 |
46 | private final static Logger LOGGER = LoggerFactory.getLogger(PerfLoggerGuiMain.class);
47 |
48 | private final PerfLoggerGuiMainFrame frmJdbcPerformanceLogger;
49 |
50 | private final Map connectionsToLogController = new HashMap<>();
51 | private static final Preferences prefs = Preferences.userNodeForPackage(PerfLoggerGuiMain.class);
52 |
53 | /**
54 | * Launch the application.
55 | */
56 | public static void main(final String[] args) {
57 | LOGGER.debug("PerfLoggerGuiMain starting...");
58 | SwingUtilities.invokeLater(() -> {
59 | installLookAndFeel();
60 |
61 | try {
62 | final PerfLoggerGuiMain window = new PerfLoggerGuiMain();
63 | window.frmJdbcPerformanceLogger.setVisible(true);
64 | } catch (final Exception e) {
65 | e.printStackTrace();
66 | }
67 | });
68 | }
69 |
70 | private static void installLookAndFeel() {
71 | final String lfClassName = getPreferredLookAndFeel();
72 | try {
73 | if (lfClassName != null) {
74 | UIManager.setLookAndFeel(lfClassName);
75 | } else {
76 | UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
77 | }
78 | } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
79 | | UnsupportedLookAndFeelException e) {
80 | LOGGER.warn("Error setting LookAndFeel", e);
81 | }
82 | }
83 |
84 | @Nullable
85 | static String getPreferredLookAndFeel() {
86 | return prefs.get(LOOK_AND_FEEL_CLASS_NAME_PREF_KEY, null);
87 | }
88 |
89 | static void savePreferredLookAndFeel(final @Nullable String lfClassName) {
90 | if (lfClassName == null) {
91 | prefs.remove(LOOK_AND_FEEL_CLASS_NAME_PREF_KEY);
92 | } else {
93 | prefs.put(LOOK_AND_FEEL_CLASS_NAME_PREF_KEY, lfClassName);
94 | }
95 | try {
96 | prefs.sync();
97 | } catch (final BackingStoreException e) {
98 | throw new IllegalArgumentException(e);
99 | }
100 | }
101 |
102 | /**
103 | * Create the application.
104 | */
105 | public PerfLoggerGuiMain() {
106 | ToolTipManager.sharedInstance().setInitialDelay(500);
107 |
108 | frmJdbcPerformanceLogger = new PerfLoggerGuiMainFrame();
109 |
110 | final JPanel welcomePanel = new WelcomePanel(this);
111 | frmJdbcPerformanceLogger.addTab("Welcome", welcomePanel);
112 |
113 | // TODO make server port configurable
114 | final PerfLoggerController serverPerfLoggerController = createServer(4561);
115 | frmJdbcPerformanceLogger.addTab("*:4561", serverPerfLoggerController.getPanel());
116 |
117 | frmJdbcPerformanceLogger.pack();
118 | frmJdbcPerformanceLogger.setExtendedState(Frame.MAXIMIZED_BOTH);
119 | frmJdbcPerformanceLogger.setMinimumSize(new Dimension(600, 500));
120 |
121 | }
122 |
123 | @Override
124 | public void createClientConnection(final String host, final int port) {
125 | final PerfLoggerController clientPerfLoggerController = connectToClient(host, port);
126 | frmJdbcPerformanceLogger.addTab(host + ":" + port, clientPerfLoggerController.getPanel());
127 | }
128 |
129 | @Override
130 | public void close(final PerfLoggerController perfLoggerController) {
131 | frmJdbcPerformanceLogger.removeTab(perfLoggerController.getPanel());
132 | connectionsToLogController.entrySet().removeIf(entry -> entry.getValue() == perfLoggerController);
133 | }
134 |
135 | private PerfLoggerController connectToClient(final String targetHost, final int targetPort) {
136 | final String hostAndPort = targetHost + "_" + targetPort;
137 | PerfLoggerController perfLoggerController = connectionsToLogController.get(hostAndPort);
138 | if (perfLoggerController == null) {
139 | final LogRepositoryUpdate logRepositoryUpdate = new LogRepositoryUpdateJdbc(hostAndPort);
140 | final LogRepositoryRead logRepositoryRead = new LogRepositoryReadJdbc(hostAndPort);
141 | final AbstractLogReceiver logReceiver = new ClientLogReceiver(targetHost, targetPort, logRepositoryUpdate);
142 | logReceiver.start();
143 |
144 | perfLoggerController = new PerfLoggerController(this, logReceiver, logRepositoryUpdate, logRepositoryRead);
145 | connectionsToLogController.put(hostAndPort, perfLoggerController);
146 | }
147 | return perfLoggerController;
148 | }
149 |
150 | private PerfLoggerController createServer(final int listeningPort) {
151 | final LogRepositoryUpdate logRepositoryUpdate = new LogRepositoryUpdateJdbc("server_" + listeningPort);
152 | final LogRepositoryRead logRepositoryRead = new LogRepositoryReadJdbc("server_" + listeningPort);
153 |
154 | final AbstractLogReceiver logReceiver = new ServerLogReceiver(listeningPort, logRepositoryUpdate);
155 | logReceiver.start();
156 |
157 | return new PerfLoggerController(this, logReceiver, logRepositoryUpdate, logRepositoryRead);
158 | }
159 |
160 | }
161 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/java/ch/sla/jdbcperflogger/console/ui/PerfLoggerGuiMainFrame.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.console.ui;
17 |
18 | import java.awt.BorderLayout;
19 | import java.awt.Component;
20 |
21 | import javax.swing.*;
22 |
23 | @SuppressWarnings("serial")
24 | public class PerfLoggerGuiMainFrame extends JFrame {
25 |
26 | private final JTabbedPane tabbedPane;
27 |
28 | /**
29 | * Create the frame.
30 | */
31 | public PerfLoggerGuiMainFrame() {
32 | this.setTitle("JDBC Performance Logger");
33 | // TODO handle clean exit
34 | this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
35 |
36 | tabbedPane = new JTabbedPane(SwingConstants.TOP);
37 | this.getContentPane().add(tabbedPane, BorderLayout.CENTER);
38 |
39 | this.pack();
40 | // this.setMinimumSize(this.getSize());
41 | // this.setBounds(100, 100, 900, 600);
42 | }
43 |
44 | void addTab(final String tabName, final Component tab) {
45 | tabbedPane.add(tabName, tab);
46 | tabbedPane.setSelectedComponent(tab);
47 | }
48 |
49 | void removeTab(final Component tab) {
50 | tabbedPane.remove(tab);
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/jdbc-perf-logger-gui/src/main/java/ch/sla/jdbcperflogger/console/ui/ResultSetDataModel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Sylvain LAURENT
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package ch.sla.jdbcperflogger.console.ui;
17 |
18 | import java.util.ArrayList;
19 | import java.util.List;
20 | import java.util.concurrent.TimeUnit;
21 |
22 | import org.eclipse.jdt.annotation.Nullable;
23 | import javax.swing.table.AbstractTableModel;
24 |
25 | import ch.sla.jdbcperflogger.StatementType;
26 | import ch.sla.jdbcperflogger.console.db.LogRepositoryConstants;
27 |
28 | class ResultSetDataModel extends AbstractTableModel {
29 |
30 | private static final long serialVersionUID = 1L;
31 | private List columnNames = new ArrayList<>();
32 | private List> columnTypes = new ArrayList<>();
33 | private List