mirror of
https://github.com/nosqlbench/nosqlbench.git
synced 2024-11-22 16:56:40 -06:00
Notify user when using error=count vs. counter.
This commit is contained in:
parent
b1d5411afd
commit
9bc3a2fd14
@ -72,8 +72,8 @@ This is the error handler stack:
|
|||||||
these histos is how long the operation was pending before the related
|
these histos is how long the operation was pending before the related
|
||||||
error occurred.
|
error occurred.
|
||||||
- **count** - keep a count in metrics for the exception, under the name
|
- **count** - keep a count in metrics for the exception, under the name
|
||||||
errorcounts.classname, using the simple class name.
|
errorcounts.classname, using the simple class name. Starting with v4.17 onward, use **counter**.
|
||||||
- **counter** - same as **count**, added for compatibility with the newer
|
- **counter** - same as **count**, starting with v4.17 onward, added for compatibility with the newer
|
||||||
universal error handler. This one is the preferred name.
|
universal error handler. This one is the preferred name.
|
||||||
- **ignore** - do nothing, do not even retry or count
|
- **ignore** - do nothing, do not even retry or count
|
||||||
|
|
||||||
|
@ -16,8 +16,12 @@
|
|||||||
|
|
||||||
package io.nosqlbench.engine.api.activityapi.errorhandling.modular.handlers;
|
package io.nosqlbench.engine.api.activityapi.errorhandling.modular.handlers;
|
||||||
|
|
||||||
|
import io.nosqlbench.engine.api.activityapi.errorhandling.modular.ErrorDetail;
|
||||||
import io.nosqlbench.engine.api.activityapi.errorhandling.modular.ErrorHandler;
|
import io.nosqlbench.engine.api.activityapi.errorhandling.modular.ErrorHandler;
|
||||||
import io.nosqlbench.nb.annotations.Service;
|
import io.nosqlbench.nb.annotations.Service;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is here to allow the classic name 'count' to work although the
|
* This is here to allow the classic name 'count' to work although the
|
||||||
@ -25,4 +29,12 @@ import io.nosqlbench.nb.annotations.Service;
|
|||||||
*/
|
*/
|
||||||
@Service(value = ErrorHandler.class, selector = "count")
|
@Service(value = ErrorHandler.class, selector = "count")
|
||||||
public class CountErrorHandler extends CounterErrorHandler {
|
public class CountErrorHandler extends CounterErrorHandler {
|
||||||
|
|
||||||
|
private static final Logger logger = LogManager.getLogger(CountErrorHandler.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ErrorDetail handleError(String name, Throwable t, long cycle, long durationInNanos, ErrorDetail detail) {
|
||||||
|
logger.warn("Starting with v4.17 onward, use 'counter'. See cql-errors.md for usage.");
|
||||||
|
return super.handleError(name, t, cycle, durationInNanos, detail);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,14 @@ import com.codahale.metrics.Counter;
|
|||||||
import com.codahale.metrics.Histogram;
|
import com.codahale.metrics.Histogram;
|
||||||
import com.codahale.metrics.Meter;
|
import com.codahale.metrics.Meter;
|
||||||
import com.codahale.metrics.Timer;
|
import com.codahale.metrics.Timer;
|
||||||
import io.nosqlbench.engine.api.activityapi.errorhandling.ErrorMetrics;
|
|
||||||
import io.nosqlbench.api.engine.activityimpl.ActivityDef;
|
import io.nosqlbench.api.engine.activityimpl.ActivityDef;
|
||||||
|
import io.nosqlbench.engine.api.activityapi.errorhandling.ErrorMetrics;
|
||||||
|
import io.nosqlbench.engine.api.activityapi.errorhandling.modular.handlers.CountErrorHandler;
|
||||||
|
import io.nosqlbench.engine.api.activityapi.errorhandling.modular.handlers.CounterErrorHandler;
|
||||||
|
import io.nosqlbench.util.NBMock;
|
||||||
|
import org.apache.logging.log4j.Level;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.core.Logger;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -29,20 +35,22 @@ import java.util.List;
|
|||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
|
|
||||||
public class NBErrorHandlerTest {
|
class NBErrorHandlerTest {
|
||||||
|
|
||||||
|
private static final String ERROR_HANDLER_APPENDER_NAME = "ErrorHandler";
|
||||||
private final RuntimeException runtimeException = new RuntimeException("test exception");
|
private final RuntimeException runtimeException = new RuntimeException("test exception");
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNullConfig() {
|
void testNullConfig() {
|
||||||
ErrorMetrics errorMetrics = new ErrorMetrics(ActivityDef.parseActivityDef("alias=testalias_stop"));
|
ErrorMetrics errorMetrics = new ErrorMetrics(ActivityDef.parseActivityDef("alias=testalias_stop"));
|
||||||
NBErrorHandler errhandler = new NBErrorHandler(() -> "stop", () -> errorMetrics);
|
NBErrorHandler errhandler = new NBErrorHandler(() -> "stop", () -> errorMetrics);
|
||||||
assertThatExceptionOfType(RuntimeException.class)
|
assertThatExceptionOfType(RuntimeException.class)
|
||||||
.isThrownBy(() -> errhandler.handleError(runtimeException, 1, 2));
|
.isThrownBy(() -> errhandler.handleError(runtimeException, 1, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMultipleWithRetry() {
|
void testMultipleWithRetry() {
|
||||||
ErrorMetrics errorMetrics = new ErrorMetrics(ActivityDef.parseActivityDef("alias=testalias_wr"));
|
ErrorMetrics errorMetrics = new ErrorMetrics(ActivityDef.parseActivityDef("alias=testalias_wr"));
|
||||||
NBErrorHandler eh = new NBErrorHandler(() -> "warn,retry", () -> errorMetrics);
|
NBErrorHandler eh = new NBErrorHandler(() -> "warn,retry", () -> errorMetrics);
|
||||||
ErrorDetail detail = eh.handleError(runtimeException, 1, 2);
|
ErrorDetail detail = eh.handleError(runtimeException, 1, 2);
|
||||||
@ -50,11 +58,24 @@ public class NBErrorHandlerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHistogramErrorHandler() {
|
void testWarnErrorHandler() {
|
||||||
|
Logger logger = (Logger) LogManager.getLogger("ERRORS");
|
||||||
|
NBMock.LogAppender appender = NBMock.registerTestLogger(ERROR_HANDLER_APPENDER_NAME, logger, Level.WARN);
|
||||||
|
|
||||||
|
ErrorMetrics errorMetrics = new ErrorMetrics(ActivityDef.parseActivityDef("alias=testalias_warn"));
|
||||||
|
NBErrorHandler eh = new NBErrorHandler(() -> "warn", () -> errorMetrics);
|
||||||
|
ErrorDetail detail = eh.handleError(runtimeException, 1, 2);
|
||||||
|
|
||||||
|
assertThat(detail.isRetryable()).isFalse();
|
||||||
|
assertThat(appender.getFirstEntry()).contains("error with cycle");
|
||||||
|
appender.cleanup(logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testHistogramErrorHandler() {
|
||||||
ErrorMetrics errorMetrics = new ErrorMetrics(ActivityDef.parseActivityDef("alias=testalias_histos"));
|
ErrorMetrics errorMetrics = new ErrorMetrics(ActivityDef.parseActivityDef("alias=testalias_histos"));
|
||||||
NBErrorHandler eh = new NBErrorHandler(() -> "histogram", () -> {
|
NBErrorHandler eh = new NBErrorHandler(() -> "histogram", () -> errorMetrics);
|
||||||
return errorMetrics;
|
|
||||||
});
|
|
||||||
ErrorDetail detail = eh.handleError(runtimeException, 1, 2);
|
ErrorDetail detail = eh.handleError(runtimeException, 1, 2);
|
||||||
assertThat(detail.isRetryable()).isFalse();
|
assertThat(detail.isRetryable()).isFalse();
|
||||||
List<Histogram> histograms = errorMetrics.getExceptionHistoMetrics().getHistograms();
|
List<Histogram> histograms = errorMetrics.getExceptionHistoMetrics().getHistograms();
|
||||||
@ -62,11 +83,9 @@ public class NBErrorHandlerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTimerErrorHandler() {
|
void testTimerErrorHandler() {
|
||||||
ErrorMetrics errorMetrics = new ErrorMetrics(ActivityDef.parseActivityDef("alias=testalias_timers"));
|
ErrorMetrics errorMetrics = new ErrorMetrics(ActivityDef.parseActivityDef("alias=testalias_timers"));
|
||||||
NBErrorHandler eh = new NBErrorHandler(() -> "timer", () -> {
|
NBErrorHandler eh = new NBErrorHandler(() -> "timer", () -> errorMetrics);
|
||||||
return errorMetrics;
|
|
||||||
});
|
|
||||||
ErrorDetail detail = eh.handleError(runtimeException, 1, 2);
|
ErrorDetail detail = eh.handleError(runtimeException, 1, 2);
|
||||||
assertThat(detail.isRetryable()).isFalse();
|
assertThat(detail.isRetryable()).isFalse();
|
||||||
List<Timer> histograms = errorMetrics.getExceptionTimerMetrics().getTimers();
|
List<Timer> histograms = errorMetrics.getExceptionTimerMetrics().getTimers();
|
||||||
@ -74,23 +93,42 @@ public class NBErrorHandlerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCounterErrorHandler() {
|
void testCounterErrorHandler() {
|
||||||
|
Logger logger = (Logger) LogManager.getLogger(CounterErrorHandler.class);
|
||||||
|
NBMock.LogAppender appender = NBMock.registerTestLogger(ERROR_HANDLER_APPENDER_NAME, logger, Level.INFO);
|
||||||
|
|
||||||
ErrorMetrics errorMetrics = new ErrorMetrics(ActivityDef.parseActivityDef("alias=testalias_counters"));
|
ErrorMetrics errorMetrics = new ErrorMetrics(ActivityDef.parseActivityDef("alias=testalias_counters"));
|
||||||
NBErrorHandler eh = new NBErrorHandler(() -> "counter", () -> {
|
NBErrorHandler eh = new NBErrorHandler(() -> "counter", () -> errorMetrics);
|
||||||
return errorMetrics;
|
|
||||||
});
|
|
||||||
ErrorDetail detail = eh.handleError(runtimeException, 1, 2);
|
ErrorDetail detail = eh.handleError(runtimeException, 1, 2);
|
||||||
assertThat(detail.isRetryable()).isFalse();
|
assertThat(detail.isRetryable()).isFalse();
|
||||||
List<Counter> histograms = errorMetrics.getExceptionCountMetrics().getCounters();
|
List<Counter> histograms = errorMetrics.getExceptionCountMetrics().getCounters();
|
||||||
assertThat(histograms).hasSize(1);
|
assertThat(histograms).hasSize(1);
|
||||||
|
|
||||||
|
assertThat(appender.getFirstEntry()).isNull();
|
||||||
|
appender.cleanup(logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMeterErrorHandler() {
|
void testCountErrorHandler() {
|
||||||
|
Logger logger = (Logger) LogManager.getLogger(CountErrorHandler.class);
|
||||||
|
NBMock.LogAppender appender = NBMock.registerTestLogger(ERROR_HANDLER_APPENDER_NAME, logger, Level.WARN);
|
||||||
|
|
||||||
|
ErrorMetrics errorMetrics = new ErrorMetrics(ActivityDef.parseActivityDef("alias=testalias_count"));
|
||||||
|
NBErrorHandler eh = new NBErrorHandler(() -> "count", () -> errorMetrics);
|
||||||
|
ErrorDetail detail = eh.handleError(runtimeException, 1, 2);
|
||||||
|
assertThat(detail.isRetryable()).isFalse();
|
||||||
|
List<Counter> histograms = errorMetrics.getExceptionCountMetrics().getCounters();
|
||||||
|
assertThat(histograms).hasSize(1);
|
||||||
|
|
||||||
|
assertThat(appender.getFirstEntry()).contains("Starting with v4.17 onward, use 'counter'");
|
||||||
|
appender.cleanup(logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMeterErrorHandler() {
|
||||||
ErrorMetrics errorMetrics = new ErrorMetrics(ActivityDef.parseActivityDef("alias=testalias_meters"));
|
ErrorMetrics errorMetrics = new ErrorMetrics(ActivityDef.parseActivityDef("alias=testalias_meters"));
|
||||||
NBErrorHandler eh = new NBErrorHandler(() -> "meter", () -> {
|
NBErrorHandler eh = new NBErrorHandler(() -> "meter", () -> errorMetrics);
|
||||||
return errorMetrics;
|
|
||||||
});
|
|
||||||
ErrorDetail detail = eh.handleError(runtimeException, 1, 2);
|
ErrorDetail detail = eh.handleError(runtimeException, 1, 2);
|
||||||
assertThat(detail.isRetryable()).isFalse();
|
assertThat(detail.isRetryable()).isFalse();
|
||||||
List<Meter> histograms = errorMetrics.getExceptionMeterMetrics().getMeters();
|
List<Meter> histograms = errorMetrics.getExceptionMeterMetrics().getMeters();
|
||||||
@ -98,13 +136,29 @@ public class NBErrorHandlerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCodeShorthand() {
|
void testCodeShorthand() {
|
||||||
ErrorMetrics errorMetrics = new ErrorMetrics(ActivityDef.parseActivityDef("alias=testalias_meters"));
|
ErrorMetrics errorMetrics = new ErrorMetrics(ActivityDef.parseActivityDef("alias=testalias_meters"));
|
||||||
NBErrorHandler eh = new NBErrorHandler(() -> "handler=code code=42", () -> {
|
NBErrorHandler eh = new NBErrorHandler(() -> "handler=code code=42", () -> errorMetrics);
|
||||||
return errorMetrics;
|
|
||||||
});
|
|
||||||
ErrorDetail detail = eh.handleError(runtimeException, 1, 2);
|
ErrorDetail detail = eh.handleError(runtimeException, 1, 2);
|
||||||
assertThat(detail.isRetryable()).isFalse();
|
assertThat(detail.isRetryable()).isFalse();
|
||||||
assertThat(detail.resultCode).isEqualTo(42);
|
assertThat(detail.resultCode).isEqualTo(42);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testErrorLogAppender() {
|
||||||
|
|
||||||
|
Logger logger = (Logger) LogManager.getLogger(ErrorHandler.class);
|
||||||
|
NBMock.LogAppender appender = NBMock.registerTestLogger(ERROR_HANDLER_APPENDER_NAME, logger, Level.DEBUG);
|
||||||
|
|
||||||
|
logger.debug("NBErrorHandler is cool.");
|
||||||
|
logger.debug("I second that.");
|
||||||
|
|
||||||
|
List<String> entries = appender.getEntries();
|
||||||
|
assertThat(entries).hasSize(2);
|
||||||
|
assertThat(appender.getFirstEntry()).isEqualTo("NBErrorHandler is cool.");
|
||||||
|
assertThat(entries.get(1)).isEqualTo("I second that.");
|
||||||
|
appender.cleanup(logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
75
engine-api/src/test/java/io/nosqlbench/util/NBMock.java
Normal file
75
engine-api/src/test/java/io/nosqlbench/util/NBMock.java
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 nosqlbench
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.nosqlbench.util;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.Level;
|
||||||
|
import org.apache.logging.log4j.core.LogEvent;
|
||||||
|
import org.apache.logging.log4j.core.Logger;
|
||||||
|
import org.apache.logging.log4j.core.appender.AbstractAppender;
|
||||||
|
import org.apache.logging.log4j.core.config.Property;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used as collection of test mocks.
|
||||||
|
*/
|
||||||
|
public class NBMock {
|
||||||
|
|
||||||
|
// Registration of test logger provided with appender added for test inspection of logging.
|
||||||
|
public static LogAppender registerTestLogger(String appenderName, Logger logger, Level level) {
|
||||||
|
LogAppender mockedAppender = new NBMock.LogAppender(appenderName);
|
||||||
|
mockedAppender.start();
|
||||||
|
logger.addAppender(mockedAppender);
|
||||||
|
logger.setLevel(level);
|
||||||
|
return (LogAppender) logger.getAppenders().get(appenderName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Appender implementation associated to a specific logger; used to obtain log specific entries in tests.
|
||||||
|
public static class LogAppender extends AbstractAppender {
|
||||||
|
private final List<String> entries = new ArrayList<>(1);
|
||||||
|
|
||||||
|
public LogAppender(String name) {
|
||||||
|
super(name, null, null, false, new Property[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void append(LogEvent event) {
|
||||||
|
entries.add(event.getMessage().getFormattedMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFirstEntry() {
|
||||||
|
if (entries.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return entries.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getEntries() {
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanup(Logger logger) {
|
||||||
|
this.stop();
|
||||||
|
entries.clear();
|
||||||
|
|
||||||
|
if (logger != null) {
|
||||||
|
logger.removeAppender(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -80,7 +80,7 @@ handler list which has the default wildcard error matcher.
|
|||||||
A handler definition is thus comprised of the error matching patterns and
|
A handler definition is thus comprised of the error matching patterns and
|
||||||
the error handling verbs which should be applied when an error matches the
|
the error handling verbs which should be applied when an error matches the
|
||||||
patterns. If the error matching patterns are not provided, then the
|
patterns. If the error matching patterns are not provided, then the
|
||||||
default wildcard pattern and delimtiter `.*:`is automatically prepended.
|
default wildcard pattern and delimiter `.*:`is automatically prepended.
|
||||||
|
|
||||||
### Error Pattern Formats
|
### Error Pattern Formats
|
||||||
|
|
||||||
@ -98,15 +98,15 @@ commas. Alternately, handler verbs may be blocks of JSON or other standard
|
|||||||
NoSQLBench encoding formats, as long as they are protected by quotes:
|
NoSQLBench encoding formats, as long as they are protected by quotes:
|
||||||
|
|
||||||
# basic verb -only form
|
# basic verb -only form
|
||||||
count,warn
|
counter,warn
|
||||||
|
|
||||||
# using JSON
|
# using JSON
|
||||||
"{\"handler\"=\"count\"},{\"handler\"=\"warn\"}"
|
"{\"handler\"=\"counter\"},{\"handler\"=\"warn\"}"
|
||||||
|
|
||||||
# using simplified params form
|
# using simplified params form
|
||||||
"handler=count,handler=warn,handler=code code=42"
|
"handler=counter,handler=warn,handler=code code=42"
|
||||||
|
|
||||||
This shows that handler verbs are really just short-hand for more
|
This shows that handler verbs are really just shorthand for more
|
||||||
canonical object definitions which have their own properties. The handler
|
canonical object definitions which have their own properties. The handler
|
||||||
property is the one that select which handler implementation to use. Each
|
property is the one that select which handler implementation to use. Each
|
||||||
handler implementation may have its own options. Those will be documented
|
handler implementation may have its own options. Those will be documented
|
||||||
|
Loading…
Reference in New Issue
Block a user