Skip to content

Commit f8952cf

Browse files
cbornetmichaelsembwever
authored andcommitted
CNDB-15631: CNDB-8641: Add a metric to count all request errors (#1983)
riptano/cndb#8641 PR in CNDB: riptano/cndb#15306 This pull request introduces new metrics for tracking invalid and other error requests for CQL statements, and integrates these metrics into the query failure notification logic. The main changes are the addition of the `AllRequestsMetrics` class, updates to the `ClientRequestsMetrics` class to include these new metrics, and modifications to the query event notification methods to record errors using the new metrics. Metrics added: * org.apache.cassandra.metrics.ClientRequest.Timeouts.All * org.apache.cassandra.metrics.ClientRequest.Unavailables.All * org.apache.cassandra.metrics.ClientRequest.Failures.All * org.apache.cassandra.metrics.ClientRequest.Invalid.All * org.apache.cassandra.metrics.ClientRequest.OtherErrors.All Note: only requests for which a tenant can be identified are counted.
1 parent 43dbe78 commit f8952cf

File tree

4 files changed

+212
-0
lines changed

4 files changed

+212
-0
lines changed

src/java/org/apache/cassandra/cql3/QueryEvents.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@
3333

3434
import org.apache.cassandra.cql3.statements.AuthenticationStatement;
3535
import org.apache.cassandra.cql3.statements.BatchStatement;
36+
import org.apache.cassandra.exceptions.InvalidRequestException;
37+
import org.apache.cassandra.exceptions.RequestFailureException;
38+
import org.apache.cassandra.exceptions.RequestTimeoutException;
39+
import org.apache.cassandra.exceptions.UnavailableException;
40+
import org.apache.cassandra.metrics.ClientRequestsMetrics;
41+
import org.apache.cassandra.metrics.ClientRequestsMetricsProvider;
3642
import org.apache.cassandra.service.QueryState;
3743
import org.apache.cassandra.transport.Message;
3844
import org.apache.cassandra.transport.messages.ResultMessage;
@@ -83,12 +89,31 @@ public void notifyQuerySuccess(CQLStatement statement,
8389
}
8490
}
8591

92+
private void updateMetrics(CQLStatement statement, Exception cause)
93+
{
94+
if (statement instanceof CQLStatement.SingleKeyspaceCqlStatement)
95+
{
96+
ClientRequestsMetrics metrics = ClientRequestsMetricsProvider.instance.metrics(((CQLStatement.SingleKeyspaceCqlStatement) statement).keyspace());
97+
if (cause instanceof InvalidRequestException)
98+
metrics.allRequestsMetrics.invalid.mark();
99+
else if (cause instanceof UnavailableException)
100+
metrics.allRequestsMetrics.unavailables.mark();
101+
else if (cause instanceof RequestTimeoutException)
102+
metrics.allRequestsMetrics.timeouts.mark();
103+
else if (cause instanceof RequestFailureException)
104+
metrics.allRequestsMetrics.failures.mark();
105+
else
106+
metrics.allRequestsMetrics.otherErrors.mark();
107+
}
108+
}
109+
86110
public void notifyQueryFailure(CQLStatement statement,
87111
String query,
88112
QueryOptions options,
89113
QueryState state,
90114
Exception cause)
91115
{
116+
updateMetrics(statement, cause);
92117
try
93118
{
94119
final String maybeObfuscatedQuery = listeners.size() > 0 ? maybeObfuscatePassword(statement, query) : query;
@@ -128,6 +153,9 @@ public void notifyExecuteFailure(QueryHandler.Prepared prepared,
128153
Exception cause)
129154
{
130155
CQLStatement statement = prepared != null ? prepared.statement : null;
156+
157+
updateMetrics(statement, cause);
158+
131159
String query = prepared != null ? prepared.statement.getRawCQLStatement() : null;
132160
try
133161
{
@@ -182,6 +210,10 @@ public void notifyBatchFailure(List<QueryHandler.Prepared> prepared,
182210
queries.add(p.statement.getRawCQLStatement());
183211
});
184212
}
213+
214+
if (!statements.isEmpty())
215+
updateMetrics(statements.get(0), cause);
216+
185217
try
186218
{
187219
for (Listener listener : listeners)
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
*
3+
* Licensed to the Apache Software Foundation (ASF) under one
4+
* or more contributor license agreements. See the NOTICE file
5+
* distributed with this work for additional information
6+
* regarding copyright ownership. The ASF licenses this file
7+
* to you under the Apache License, Version 2.0 (the
8+
* "License"); you may not use this file except in compliance
9+
* with the License. You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing,
14+
* software distributed under the License is distributed on an
15+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
* KIND, either express or implied. See the License for the
17+
* specific language governing permissions and limitations
18+
* under the License.
19+
*
20+
*/
21+
package org.apache.cassandra.metrics;
22+
23+
24+
import com.codahale.metrics.Meter;
25+
26+
import static org.apache.cassandra.metrics.CassandraMetricsRegistry.Metrics;
27+
28+
29+
public class AllRequestsMetrics extends ClientRequestMetrics
30+
{
31+
public final Meter invalid;
32+
public final Meter otherErrors;
33+
34+
public AllRequestsMetrics(String scope, String prefix)
35+
{
36+
super(scope, prefix);
37+
invalid = Metrics.meter(factory.createMetricName(namePrefix + "Invalid"));
38+
otherErrors = Metrics.meter(factory.createMetricName(namePrefix + "OtherErrors"));
39+
}
40+
41+
@Override
42+
public void release()
43+
{
44+
super.release();
45+
Metrics.remove(factory.createMetricName(namePrefix + "Invalid"));
46+
Metrics.remove(factory.createMetricName(namePrefix + "OtherErrors"));
47+
}
48+
}

src/java/org/apache/cassandra/metrics/ClientRequestsMetrics.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public class ClientRequestsMetrics
3232
public final CASClientWriteRequestMetrics casWriteMetrics;
3333
public final CASClientRequestMetrics casReadMetrics;
3434
public final ViewWriteMetrics viewWriteMetrics;
35+
public final AllRequestsMetrics allRequestsMetrics;
3536
private final Map<ConsistencyLevel, ClientRequestMetrics> readMetricsMap;
3637
private final Map<ConsistencyLevel, ClientWriteRequestMetrics> writeMetricsMap;
3738

@@ -52,6 +53,7 @@ public ClientRequestsMetrics(String namePrefix)
5253
casWriteMetrics = new CASClientWriteRequestMetrics("CASWrite", namePrefix);
5354
casReadMetrics = new CASClientRequestMetrics("CASRead", namePrefix);
5455
viewWriteMetrics = new ViewWriteMetrics("ViewWrite", namePrefix);
56+
allRequestsMetrics = new AllRequestsMetrics("All", namePrefix);
5557
readMetricsMap = new EnumMap<>(ConsistencyLevel.class);
5658
writeMetricsMap = new EnumMap<>(ConsistencyLevel.class);
5759
for (ConsistencyLevel level : ConsistencyLevel.values())
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package org.apache.cassandra.metrics;
20+
21+
import java.util.Collections;
22+
23+
import org.junit.After;
24+
import org.junit.Before;
25+
import org.junit.Test;
26+
27+
import com.codahale.metrics.Meter;
28+
import com.datastax.driver.core.BoundStatement;
29+
import com.datastax.driver.core.PreparedStatement;
30+
import com.datastax.driver.core.Session;
31+
import org.apache.cassandra.cql3.CQLStatement;
32+
import org.apache.cassandra.cql3.CQLTester;
33+
import org.apache.cassandra.cql3.QueryEvents;
34+
import org.apache.cassandra.cql3.QueryOptions;
35+
import org.apache.cassandra.db.ConsistencyLevel;
36+
import org.apache.cassandra.exceptions.ReadFailureException;
37+
import org.apache.cassandra.exceptions.ReadTimeoutException;
38+
import org.apache.cassandra.exceptions.UnavailableException;
39+
import org.apache.cassandra.service.QueryState;
40+
41+
import static org.junit.Assert.assertEquals;
42+
43+
public class ClientRequestsMetricsAllRequestsTest extends CQLTester
44+
{
45+
AllRequestsMetrics metrics = ClientRequestsMetricsProvider.instance.metrics(KEYSPACE).allRequestsMetrics;
46+
47+
@Before
48+
public void setup()
49+
{
50+
createTable("CREATE TABLE %s (id INT PRIMARY KEY, v TEXT)");
51+
}
52+
53+
@After
54+
public void teardown()
55+
{
56+
dropTable("DROP TABLE %s");
57+
}
58+
59+
@Test
60+
public void testInvalidRequest()
61+
{
62+
long before = metrics.invalid.getCount();
63+
try
64+
{
65+
executeNet("INSERT INTO %s (id, v) VALUES (1, ?)");
66+
}
67+
catch (Throwable t)
68+
{
69+
// expected
70+
}
71+
assertEquals(1, metrics.invalid.getCount() - before);
72+
}
73+
74+
@Test
75+
public void testInvalidPreparedRequest()
76+
{
77+
try(Session session = sessionNet())
78+
{
79+
PreparedStatement prepare1 = session.prepare(formatQuery("DELETE FROM %s WHERE id = ?"));
80+
BoundStatement bind = prepare1.bind();
81+
long before = metrics.invalid.getCount();
82+
try
83+
{
84+
session.execute(bind);
85+
}
86+
catch (Throwable t)
87+
{
88+
// expected
89+
}
90+
assertEquals(1, metrics.invalid.getCount() - before);
91+
}
92+
}
93+
94+
@Test
95+
public void testTimeoutRequest()
96+
{
97+
testNotifyQueryFailure(metrics.timeouts, new ReadTimeoutException(ConsistencyLevel.ONE));
98+
}
99+
100+
@Test
101+
public void testUnavailableRequest()
102+
{
103+
testNotifyQueryFailure(metrics.unavailables, UnavailableException.create(ConsistencyLevel.ONE, 1, 0));
104+
}
105+
106+
@Test
107+
public void testFailureRequest()
108+
{
109+
testNotifyQueryFailure(metrics.failures, new ReadFailureException(ConsistencyLevel.ONE, 0, 0, false, Collections.emptyMap()));
110+
}
111+
112+
@Test
113+
public void testOtherErrorRequest()
114+
{
115+
testNotifyQueryFailure(metrics.otherErrors, new RuntimeException());
116+
}
117+
118+
public void testNotifyQueryFailure(Meter meter, Exception exception)
119+
{
120+
CQLStatement cqlStatement = parseStatement("CREATE TABLE %s (id INT PRIMARY KEY, v TEXT)");
121+
long before = meter.getCount();
122+
123+
QueryEvents.instance.notifyQueryFailure(cqlStatement, cqlStatement.getRawCQLStatement(), QueryOptions.DEFAULT,
124+
QueryState.forInternalCalls(), exception);
125+
126+
assertEquals(1, meter.getCount() - before);
127+
}
128+
129+
130+
}

0 commit comments

Comments
 (0)