Skip to content

Commit 335d0c6

Browse files
committed
Apply SQL_BODY_MAX_LENGTH to ClickHouse plugin span tags
ClickHouseStatementTracingWrapper (clickhouse-0.3.1-plugin) and ClickHousePrepareStatementTracing (clickhouse-0.3.2.x-plugin) wrote the raw SQL straight into the DB_STATEMENT span tag. Other JDBC plugins (mysql-*, postgresql-*, h2, mssql, etc.) route the same tag through SqlBodyUtil#limitSqlBodySize, which truncates the value to JDBCPluginConfig.Plugin.JDBC.SQL_BODY_MAX_LENGTH and appends "...". Without that helper the ClickHouse plugins ignore the user configuration and emit unbounded SQL bodies. Apply SqlBodyUtil#limitSqlBodySize in both interceptors so the tag respects the configured maximum length (and the negative-value sentinel that disables truncation). Add ClickHouseStatementTracingWrapperTest and ClickHousePrepareStatementTracingTest with three cases each (short sql passthrough, truncation at the configured limit, negative limit disables truncation), each restoring the configured limit in tearDown. Update CHANGES.md.
1 parent 489ec3c commit 335d0c6

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 `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+
// 32 chars, twice 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+
// 32 chars, twice the limit, so the helper must truncate to 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)