Skip to content

Commit e0e8b3c

Browse files
authored
Apply SQL_BODY_MAX_LENGTH to ClickHouse JDBC plugin span tags (#807)
1 parent 489ec3c commit e0e8b3c

5 files changed

Lines changed: 240 additions & 2 deletions

File tree

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Release Notes.
2424
* Add Elasticsearch Java client (co.elastic.clients:elasticsearch-java) plugin for 7.16.x-9.x.
2525
* Only publish `apm-application-toolkit` modules to Maven Central. Agent and plugins are distributed via download package and Docker images.
2626
* Add unified release script (`tools/releasing/release.sh`) with two-step flow: `prepare-vote` and `vote-passed`.
27+
* Fix an issue where `JDBCPluginConfig.Plugin.JDBC.SQL_BODY_MAX_LENGTH` was not honored by clickhouse-0.3.1 and clickhouse-0.3.2.x plugins.
2728

2829
All issues and pull requests are [here](https://github.com/apache/skywalking/milestone/249?closed=1)
2930

apm-sniffer/apm-sdk-plugin/clickhouse-0.3.1-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/clickhouse/ClickHouseStatementTracingWrapper.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
2424
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
2525
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
26+
import org.apache.skywalking.apm.plugin.jdbc.SqlBodyUtil;
2627
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
2728

2829
/**
@@ -37,7 +38,7 @@ public static <T> T of(ConnectionInfo connectionInfo, String methodName, String
3738
try {
3839
Tags.DB_TYPE.set(span, connectionInfo.getDBType());
3940
Tags.DB_INSTANCE.set(span, connectionInfo.getDatabaseName());
40-
Tags.DB_STATEMENT.set(span, sql);
41+
Tags.DB_STATEMENT.set(span, SqlBodyUtil.limitSqlBodySize(sql));
4142
span.setComponent(connectionInfo.getComponent());
4243
SpanLayer.asDB(span);
4344
return supplier.get();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package org.apache.skywalking.apm.plugin.jdbc.clickhouse;
20+
21+
import java.util.List;
22+
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
23+
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
24+
import org.apache.skywalking.apm.agent.core.context.util.TagValuePair;
25+
import org.apache.skywalking.apm.agent.test.helper.SegmentHelper;
26+
import org.apache.skywalking.apm.agent.test.helper.SpanHelper;
27+
import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
28+
import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
29+
import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
30+
import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
31+
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
32+
import org.apache.skywalking.apm.plugin.jdbc.JDBCPluginConfig;
33+
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
34+
import org.junit.After;
35+
import org.junit.Before;
36+
import org.junit.Rule;
37+
import org.junit.Test;
38+
import org.junit.runner.RunWith;
39+
40+
import static org.hamcrest.CoreMatchers.is;
41+
import static org.hamcrest.MatcherAssert.assertThat;
42+
43+
/**
44+
* Verify that {@link ClickHouseStatementTracingWrapper} truncates the SQL body
45+
* recorded on the exit span according to {@link JDBCPluginConfig.Plugin.JDBC#SQL_BODY_MAX_LENGTH}.
46+
*/
47+
@RunWith(TracingSegmentRunner.class)
48+
public class ClickHouseStatementTracingWrapperTest {
49+
50+
@SegmentStoragePoint
51+
private SegmentStorage segmentStorage;
52+
53+
@Rule
54+
public AgentServiceRule serviceRule = new AgentServiceRule();
55+
56+
private ConnectionInfo connectionInfo;
57+
58+
private int originalLimit;
59+
60+
@Before
61+
public void setUp() {
62+
connectionInfo = new ConnectionInfo(
63+
ComponentsDefine.CLICKHOUSE_JDBC_DRIVER, "ClickHouse", "127.0.0.1", 8123, "default");
64+
originalLimit = JDBCPluginConfig.Plugin.JDBC.SQL_BODY_MAX_LENGTH;
65+
}
66+
67+
@After
68+
public void tearDown() {
69+
JDBCPluginConfig.Plugin.JDBC.SQL_BODY_MAX_LENGTH = originalLimit;
70+
}
71+
72+
@Test
73+
public void shortSqlIsRecordedAsIs() throws Exception {
74+
JDBCPluginConfig.Plugin.JDBC.SQL_BODY_MAX_LENGTH = 2048;
75+
String sql = "SELECT 1";
76+
77+
ClickHouseStatementTracingWrapper.of(connectionInfo, "execute", sql, () -> Boolean.TRUE);
78+
79+
assertThat(dbStatementTagValue(), is(sql));
80+
}
81+
82+
@Test
83+
public void longSqlIsTruncatedToConfiguredLimit() throws Exception {
84+
JDBCPluginConfig.Plugin.JDBC.SQL_BODY_MAX_LENGTH = 16;
85+
// Longer than the limit, so the helper must truncate to first 16 chars and append "..."
86+
String sql = "SELECT * FROM table_with_many_cols";
87+
88+
ClickHouseStatementTracingWrapper.of(connectionInfo, "execute", sql, () -> Boolean.TRUE);
89+
90+
assertThat(dbStatementTagValue(), is(sql.substring(0, 16) + "..."));
91+
}
92+
93+
@Test
94+
public void negativeLimitDisablesTruncation() throws Exception {
95+
JDBCPluginConfig.Plugin.JDBC.SQL_BODY_MAX_LENGTH = -1;
96+
StringBuilder builder = new StringBuilder("SELECT ");
97+
for (int i = 0; i < 1000; i++) {
98+
builder.append("a, ");
99+
}
100+
builder.append("a FROM t");
101+
String sql = builder.toString();
102+
103+
ClickHouseStatementTracingWrapper.of(connectionInfo, "execute", sql, () -> Boolean.TRUE);
104+
105+
assertThat(dbStatementTagValue(), is(sql));
106+
}
107+
108+
private String dbStatementTagValue() {
109+
List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
110+
assertThat(traceSegments.size(), is(1));
111+
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegments.get(0));
112+
assertThat(spans.size(), is(1));
113+
List<TagValuePair> tags = SpanHelper.getTags(spans.get(0));
114+
// tag order: db.type, db.instance, db.statement
115+
return (String) tags.get(2).getValue();
116+
}
117+
}

apm-sniffer/apm-sdk-plugin/clickhouse-0.3.2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/clickhouse/v32/ClickHousePrepareStatementTracing.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
2323
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
2424
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
25+
import org.apache.skywalking.apm.plugin.jdbc.SqlBodyUtil;
2526
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
2627

2728
import java.sql.SQLException;
@@ -39,7 +40,7 @@ public static <T> T of(ConnectionInfo connectionInfo, String methodName, String
3940
try {
4041
Tags.DB_TYPE.set(span, connectionInfo.getDBType());
4142
Tags.DB_INSTANCE.set(span, connectionInfo.getDatabaseName());
42-
Tags.DB_STATEMENT.set(span, sql);
43+
Tags.DB_STATEMENT.set(span, SqlBodyUtil.limitSqlBodySize(sql));
4344
span.setComponent(connectionInfo.getComponent());
4445
SpanLayer.asDB(span);
4546
return supplier.get();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package org.apache.skywalking.apm.plugin.jdbc.clickhouse;
20+
21+
import java.util.List;
22+
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
23+
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
24+
import org.apache.skywalking.apm.agent.core.context.util.TagValuePair;
25+
import org.apache.skywalking.apm.agent.test.helper.SegmentHelper;
26+
import org.apache.skywalking.apm.agent.test.helper.SpanHelper;
27+
import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
28+
import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
29+
import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
30+
import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
31+
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
32+
import org.apache.skywalking.apm.plugin.jdbc.JDBCPluginConfig;
33+
import org.apache.skywalking.apm.plugin.jdbc.clickhouse.v32.ClickHousePrepareStatementTracing;
34+
import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo;
35+
import org.junit.After;
36+
import org.junit.Before;
37+
import org.junit.Rule;
38+
import org.junit.Test;
39+
import org.junit.runner.RunWith;
40+
41+
import static org.hamcrest.CoreMatchers.is;
42+
import static org.hamcrest.MatcherAssert.assertThat;
43+
44+
/**
45+
* Verify that {@link ClickHousePrepareStatementTracing} truncates the SQL body
46+
* recorded on the exit span according to {@link JDBCPluginConfig.Plugin.JDBC#SQL_BODY_MAX_LENGTH}.
47+
*/
48+
@RunWith(TracingSegmentRunner.class)
49+
public class ClickHousePrepareStatementTracingTest {
50+
51+
@SegmentStoragePoint
52+
private SegmentStorage segmentStorage;
53+
54+
@Rule
55+
public AgentServiceRule serviceRule = new AgentServiceRule();
56+
57+
private ConnectionInfo connectionInfo;
58+
59+
private int originalLimit;
60+
61+
@Before
62+
public void setUp() {
63+
connectionInfo = new ConnectionInfo(
64+
ComponentsDefine.CLICKHOUSE_JDBC_DRIVER, "ClickHouse", "127.0.0.1", 8123, "test");
65+
originalLimit = JDBCPluginConfig.Plugin.JDBC.SQL_BODY_MAX_LENGTH;
66+
}
67+
68+
@After
69+
public void tearDown() {
70+
JDBCPluginConfig.Plugin.JDBC.SQL_BODY_MAX_LENGTH = originalLimit;
71+
}
72+
73+
@Test
74+
public void shortSqlIsRecordedAsIs() throws Exception {
75+
JDBCPluginConfig.Plugin.JDBC.SQL_BODY_MAX_LENGTH = 2048;
76+
String sql = "SELECT 1";
77+
78+
ClickHousePrepareStatementTracing.of(connectionInfo, "execute", sql, () -> Boolean.TRUE);
79+
80+
assertThat(dbStatementTagValue(), is(sql));
81+
}
82+
83+
@Test
84+
public void longSqlIsTruncatedToConfiguredLimit() throws Exception {
85+
JDBCPluginConfig.Plugin.JDBC.SQL_BODY_MAX_LENGTH = 16;
86+
// Longer than the configured limit, so the helper must truncate to the first 16 chars and append "..."
87+
String sql = "SELECT * FROM table_with_many_cols";
88+
89+
ClickHousePrepareStatementTracing.of(connectionInfo, "execute", sql, () -> Boolean.TRUE);
90+
91+
assertThat(dbStatementTagValue(), is(sql.substring(0, 16) + "..."));
92+
}
93+
94+
@Test
95+
public void negativeLimitDisablesTruncation() throws Exception {
96+
JDBCPluginConfig.Plugin.JDBC.SQL_BODY_MAX_LENGTH = -1;
97+
StringBuilder builder = new StringBuilder("SELECT ");
98+
for (int i = 0; i < 1000; i++) {
99+
builder.append("a, ");
100+
}
101+
builder.append("a FROM t");
102+
String sql = builder.toString();
103+
104+
ClickHousePrepareStatementTracing.of(connectionInfo, "execute", sql, () -> Boolean.TRUE);
105+
106+
assertThat(dbStatementTagValue(), is(sql));
107+
}
108+
109+
private String dbStatementTagValue() {
110+
List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
111+
assertThat(traceSegments.size(), is(1));
112+
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegments.get(0));
113+
assertThat(spans.size(), is(1));
114+
List<TagValuePair> tags = SpanHelper.getTags(spans.get(0));
115+
// tag order: db.type, db.instance, db.statement
116+
return (String) tags.get(2).getValue();
117+
}
118+
}

0 commit comments

Comments
 (0)