SEBSERV-250,SEBSERV-188

- implemented overall generic incident marker for client connection
handler and removed specific missingPing incident.
- adapted missing ping handling to new overall generic incident marker
This commit is contained in:
anhefti 2022-01-13 13:07:02 +01:00
parent bad7510a63
commit 50aef06db0
12 changed files with 103 additions and 78 deletions

View file

@ -73,6 +73,11 @@ public class ClientConnectionData {
return this.clientConnection.id;
}
@JsonIgnore
public boolean hasAnyIncident() {
return this.missingPing || this.pendingNotification;
}
public ClientConnection getClientConnection() {
return this.clientConnection;
}

View file

@ -67,6 +67,16 @@ public interface ClientIndicator extends IndicatorValue {
* @param event The ClientEvent instance */
void notifyValueChange(ClientEvent event);
/** This gets called on a value change e.g.: when a ClientEvent was received.
* NOTE: that this is called only on the same machine (server-instance) on that the ClientEvent was received.
*
* @param clientEventRecord The ClientEventRecord instance */
void notifyValueChange(ClientEventRecord clientEventRecord);
/** This indicates if the indicator indicates an incident. This is the case if the actual indicator value
* is above or below the max or min value defined by the indicator threshold settings.
*
* @return true if this indicator indicates an incident */
boolean hasIncident();
}

View file

@ -17,6 +17,7 @@ import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
@ -74,14 +75,29 @@ public class ClientConnectionDataInternal extends ClientConnectionData {
@Override
@JsonProperty(ATTR_MISSING_PING)
public Boolean getMissingPing() {
return this.pingIndicator != null && this.pingIndicator.isMissingPing();
public final Boolean getMissingPing() {
return this.pingIndicator != null && this.pingIndicator.hasIncident();
}
@Override
@JsonProperty(ATTR_PENDING_NOTIFICATION)
public Boolean pendingNotification() {
public final Boolean pendingNotification() {
return this.pendingNotificationIndication.notifictionPending();
}
@Override
@JsonIgnore
public final boolean hasAnyIncident() {
return pendingNotification() || hasIncident();
}
private boolean hasIncident() {
return this.indicatorMapping.values()
.stream()
.flatMap(Collection::stream)
.filter(ClientIndicator::hasIncident)
.findFirst()
.isPresent();
}
}

View file

@ -847,7 +847,7 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
return connection -> {
if (connection.pingIndicator.missingPingUpdate(now)) {
final boolean missingPing = connection.pingIndicator.isMissingPing();
final boolean missingPing = connection.getMissingPing();
final ClientEventRecord clientEventRecord = new ClientEventRecord(
null,
connection.getConnectionId(),

View file

@ -8,6 +8,8 @@
package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.indicator;
import java.util.Comparator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -21,8 +23,8 @@ public abstract class AbstractClientIndicator implements ClientIndicator {
protected final DistributedIndicatorValueService distributedPingCache;
protected Long indicatorId;
protected Long examId;
protected Long indicatorId = -1L;
protected Long examId = -1L;
protected Long connectionId;
protected boolean cachingEnabled;
protected boolean active = true;
@ -32,6 +34,8 @@ public abstract class AbstractClientIndicator implements ClientIndicator {
protected boolean initialized = false;
protected double currentValue = Double.NaN;
protected double incidentThreshold = 0.0;
public AbstractClientIndicator(final DistributedIndicatorValueService distributedPingCache) {
super();
this.distributedPingCache = distributedPingCache;
@ -44,12 +48,20 @@ public abstract class AbstractClientIndicator implements ClientIndicator {
final boolean active,
final boolean cachingEnabled) {
this.indicatorId = (indicatorDefinition != null && indicatorDefinition.id != null)
? indicatorDefinition.id
: -1;
this.examId = (indicatorDefinition != null && indicatorDefinition.examId != null)
? indicatorDefinition.examId
: -1;
if (indicatorDefinition != null) {
this.incidentThreshold = (!indicatorDefinition.type.inverse)
? indicatorDefinition.thresholds.stream()
.map(t -> t.value)
.max(Comparator.naturalOrder())
.orElse(0.0)
: indicatorDefinition.thresholds.stream()
.map(t -> t.value)
.min(Comparator.naturalOrder())
.orElse(0.0);
this.indicatorId = indicatorDefinition.id;
this.examId = indicatorDefinition.examId;
}
this.connectionId = connectionId;
this.active = active;
this.cachingEnabled = cachingEnabled;

View file

@ -47,13 +47,9 @@ public abstract class AbstractLogLevelCountIndicator extends AbstractLogIndicato
valueChanged(clientEventRecord.getText());
}
private void valueChanged(final String eventText) {
if (this.tags == null || this.tags.length == 0 || hasTag(eventText)) {
if (super.ditributedIndicatorValueRecordId != null) {
this.distributedPingCache.incrementIndicatorValue(super.ditributedIndicatorValueRecordId);
}
this.currentValue = getValue() + 1d;
}
@Override
public final boolean hasIncident() {
return this.currentValue > this.incidentThreshold;
}
@Override
@ -114,4 +110,13 @@ public abstract class AbstractLogLevelCountIndicator extends AbstractLogIndicato
return result;
}
private void valueChanged(final String eventText) {
if (this.tags == null || this.tags.length == 0 || hasTag(eventText)) {
if (super.ditributedIndicatorValueRecordId != null) {
this.distributedPingCache.incrementIndicatorValue(super.ditributedIndicatorValueRecordId);
}
this.currentValue = getValue() + 1d;
}
}
}

View file

@ -33,6 +33,11 @@ public abstract class AbstractPingIndicator extends AbstractClientIndicator {
super.init(indicatorDefinition, connectionId, active, cachingEnabled);
}
@Override
public Set<EventType> observedEvents() {
return this.EMPTY_SET;
}
public final void notifyPing(final long timestamp, final int pingNumber) {
super.currentValue = timestamp;
@ -49,11 +54,4 @@ public abstract class AbstractPingIndicator extends AbstractClientIndicator {
}
}
@Override
public Set<EventType> observedEvents() {
return this.EMPTY_SET;
}
public abstract boolean missingPingUpdate(final long now);
}

View file

@ -48,4 +48,9 @@ public class BatteryStatusIndicator extends AbstractLogNumberIndicator {
return IndicatorType.BATTERY_STATUS;
}
@Override
public final boolean hasIncident() {
return this.currentValue < this.incidentThreshold;
}
}

View file

@ -8,11 +8,7 @@
package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.indicator;
import java.util.Comparator;
import org.joda.time.DateTimeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
@ -32,15 +28,11 @@ import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientEventRecord;
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public final class PingIntervalClientIndicator extends AbstractPingIndicator {
private static final Logger log = LoggerFactory.getLogger(PingIntervalClientIndicator.class);
// This is the default ping error threshold that is set if the threshold cannot be get
// from the ping threshold settings. If the last ping is older then this interval back in time
// then the ping is considered and marked as missing
private static final long DEFAULT_PING_ERROR_THRESHOLD = Constants.SECOND_IN_MILLIS * 5;
private long pingErrorThreshold;
private boolean missingPing = false;
private boolean hidden = false;
public PingIntervalClientIndicator(final DistributedIndicatorValueService distributedPingCache) {
@ -62,35 +54,11 @@ public final class PingIntervalClientIndicator extends AbstractPingIndicator {
super.init(indicatorDefinition, connectionId, active, cachingEnabled);
// init ping error threshold
try {
this.lastCheckVal = getValue();
indicatorDefinition
.getThresholds()
.stream()
.max(Comparator.naturalOrder())
.ifPresent(t -> this.pingErrorThreshold = t.value.longValue());
} catch (final Exception e) {
log.error("Failed to initialize pingErrorThreshold: {}", e.getMessage());
this.pingErrorThreshold = DEFAULT_PING_ERROR_THRESHOLD;
if (this.incidentThreshold <= 0.0) {
this.incidentThreshold = DEFAULT_PING_ERROR_THRESHOLD;
}
// init missing ping indicator
if (!cachingEnabled) {
try {
this.missingPing = this.pingErrorThreshold < getValue();
} catch (final Exception e) {
log.error("Failed to initialize missingPing: {}", e.getMessage());
this.missingPing = true;
}
}
}
@JsonIgnore
public final boolean isMissingPing() {
return this.missingPing;
}
@JsonIgnore
@ -146,25 +114,23 @@ public final class PingIntervalClientIndicator extends AbstractPingIndicator {
}
@Override
public boolean missingPingUpdate(final long now) {
public final boolean hasIncident() {
return getValue() > super.incidentThreshold;
}
private double lastCheckVal = 0;
public final boolean missingPingUpdate(final long now) {
if (this.currentValue <= 0) {
return false;
}
final long value = now - (long) super.currentValue;
if (this.missingPing) {
if (this.pingErrorThreshold > value) {
this.missingPing = false;
return true;
}
} else {
if (this.pingErrorThreshold < value) {
this.missingPing = true;
return true;
}
}
return false;
final double val = now - this.currentValue;
// check if incidentThreshold was passed (up or down) since last update
final boolean result = (this.lastCheckVal < this.incidentThreshold && val >= this.incidentThreshold) ||
(this.lastCheckVal >= this.incidentThreshold && val < this.incidentThreshold);
this.lastCheckVal = val;
return result;
}
}

View file

@ -48,4 +48,9 @@ public class WLANStatusIndicator extends AbstractLogNumberIndicator {
return IndicatorType.WLAN_STATUS;
}
@Override
public final boolean hasIncident() {
return this.currentValue < this.incidentThreshold;
}
}

View file

@ -17,6 +17,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.IndicatorType;
public class IndicatorValueJSONTest {
@ -25,7 +26,7 @@ public class IndicatorValueJSONTest {
final JSONMapper jsonMapper = new JSONMapper();
final DistributedIndicatorValueService mock = Mockito.mock(DistributedIndicatorValueService.class);
final ErrorLogCountClientIndicator indicator = new ErrorLogCountClientIndicator(mock, null);
indicator.init(new Indicator(1L, null, null, null, null, null, null, null), 2L, true, true);
indicator.init(new Indicator(1L, 2L, "test", IndicatorType.NONE, null, null, null, null), 2L, true, true);
final String json = jsonMapper.writeValueAsString(indicator);
assertEquals("{\"id\":1,\"val\":\"NaN\"}", json);
}

View file

@ -19,6 +19,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.IndicatorType;
public class PingIntervalClientIndicatorTest {
@ -68,7 +69,8 @@ public class PingIntervalClientIndicatorTest {
final PingIntervalClientIndicator pingIntervalClientIndicator =
new PingIntervalClientIndicator(distributedPingCache);
pingIntervalClientIndicator.init(new Indicator(2L, null, null, null, null, null, null, null), 1L, true, true);
pingIntervalClientIndicator.init(new Indicator(2L, 3L, "test", IndicatorType.NONE, null, null, null, null), 1L,
true, true);
final JSONMapper jsonMapper = new JSONMapper();
final String json = jsonMapper.writeValueAsString(pingIntervalClientIndicator);
assertEquals("{\"id\":2,\"val\":0.0}", json);