[java-identity-provider] branch main updated: IDP-1731 - Add metric to detect connectors in failure state
Scott Cantor
cantor.2 at osu.edu
Wed Dec 30 18:45:06 UTC 2020
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch main
in repository java-identity-provider.
View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=f69e8afa6f9680c8c701ec260b34a8bbaf4887ed
The following commit(s) were added to refs/heads/main by this push:
new f69e8afa6 IDP-1731 - Add metric to detect connectors in failure state
f69e8afa6 is described below
commit f69e8afa6f9680c8c701ec260b34a8bbaf4887ed
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Dec 30 13:45:03 2020 -0500
IDP-1731 - Add metric to detect connectors in failure state
https://issues.shibboleth.net/jira/browse/IDP-1731
---
.../attribute/resolver/AbstractDataConnector.java | 59 ++++++++++++++--------
.../idp/attribute/resolver/DataConnector.java | 13 +++++
.../impl/AttributeResolverServiceGaugeSet.java | 44 ++++++++++++++--
idp-war/src/main/webapp/WEB-INF/jsp/status.jsp | 25 ++++++---
4 files changed, 109 insertions(+), 32 deletions(-)
diff --git a/idp-attribute-resolver-api/src/main/java/net/shibboleth/idp/attribute/resolver/AbstractDataConnector.java b/idp-attribute-resolver-api/src/main/java/net/shibboleth/idp/attribute/resolver/AbstractDataConnector.java
index a8c6425be..22627e740 100644
--- a/idp-attribute-resolver-api/src/main/java/net/shibboleth/idp/attribute/resolver/AbstractDataConnector.java
+++ b/idp-attribute-resolver-api/src/main/java/net/shibboleth/idp/attribute/resolver/AbstractDataConnector.java
@@ -55,6 +55,9 @@ public abstract class AbstractDataConnector extends AbstractResolverPlugin<Map<S
/** cache for the log prefix - to save multiple recalculations. */
@Nullable private String logPrefix;
+ /** When did this connector last work? */
+ @Nullable private Instant lastSuccess;
+
/** When did this connector last fail? */
@Nullable private Instant lastFail;
@@ -81,7 +84,7 @@ public abstract class AbstractDataConnector extends AbstractResolverPlugin<Map<S
* @return ID of the {@link AbstractDataConnector} whose values will be used in the event that this data connector
* experiences an error
*/
- @Override @Nullable public String getFailoverDataConnectorId() {
+ @Nullable public String getFailoverDataConnectorId() {
return failoverDataConnectorId;
}
@@ -99,6 +102,24 @@ public abstract class AbstractDataConnector extends AbstractResolverPlugin<Map<S
failoverDataConnectorId = StringSupport.trimOrNull(id);
}
+ /**
+ * Set the time when this connector last worked.
+ *
+ * @param time what to set
+ *
+ * @since 4.1.0
+ */
+ public void setLastSuccess(@Nullable final Instant time) {
+ lastSuccess = time;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Nullable public Instant getLastSuccess() {
+ return lastSuccess;
+ }
+
/**
* Set the time when this connector last failed.
*
@@ -111,7 +132,7 @@ public abstract class AbstractDataConnector extends AbstractResolverPlugin<Map<S
/**
* {@inheritDoc}
*/
- @Override @Nullable public Instant getLastFail() {
+ @Nullable public Instant getLastFail() {
return lastFail;
}
@@ -121,11 +142,13 @@ public abstract class AbstractDataConnector extends AbstractResolverPlugin<Map<S
* @param delay what to set
*/
public void setNoRetryDelay(@Nonnull final Duration delay) {
+ ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
noRetryDelay = delay;
}
/** {@inheritDoc} */
- @Override @Nonnull public Duration getNoRetryDelay() {
+ @Nonnull public Duration getNoRetryDelay() {
return noRetryDelay;
}
@@ -141,11 +164,9 @@ public abstract class AbstractDataConnector extends AbstractResolverPlugin<Map<S
exportAllAttributes = what;
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Deprecated(since = "4.1.0", forRemoval = true)
- @Override public boolean isExportAllAttributes() {
+ public boolean isExportAllAttributes() {
return exportAllAttributes;
}
@@ -160,13 +181,19 @@ public abstract class AbstractDataConnector extends AbstractResolverPlugin<Map<S
exportAttributes = Set.copyOf(what);
}
- /**
- * {@inheritDoc}
- */
- @Override @Nonnull @NonnullElements @Unmodifiable public Collection<String> getExportAttributes() {
+ /** {@inheritDoc} */
+ @Nonnull @NonnullElements @Unmodifiable public Collection<String> getExportAttributes() {
return exportAttributes;
}
+ /** {@inheritDoc} */
+ @Override protected void doInitialize() throws ComponentInitializationException {
+ super.doInitialize();
+
+ // The Id is now definitive. Just in case it was used prior to that, reset the getPrefixCache
+ logPrefix = null;
+ }
+
/**
* {@inheritDoc}
*
@@ -182,6 +209,7 @@ public abstract class AbstractDataConnector extends AbstractResolverPlugin<Map<S
final Map<String, IdPAttribute> result;
try {
result = doDataConnectorResolve(resolutionContext, workContext);
+ setLastSuccess(Instant.now());
} catch (final NoResultAnErrorResolutionException | MultipleResultAnErrorResolutionException e) {
// Do not record these failures, they are 'expected'
throw e;
@@ -204,15 +232,6 @@ public abstract class AbstractDataConnector extends AbstractResolverPlugin<Map<S
return result;
}
- /** {@inheritDoc} */
- @Override protected void doInitialize() throws ComponentInitializationException {
-
- super.doInitialize();
-
- // The Id is now definitive. Just in case it was used prior to that, reset the getPrefixCache
- logPrefix = null;
- }
-
/**
* Retrieves a collection of attributes from some data source.
*
diff --git a/idp-attribute-resolver-api/src/main/java/net/shibboleth/idp/attribute/resolver/DataConnector.java b/idp-attribute-resolver-api/src/main/java/net/shibboleth/idp/attribute/resolver/DataConnector.java
index ca85576d0..ecbc30972 100644
--- a/idp-attribute-resolver-api/src/main/java/net/shibboleth/idp/attribute/resolver/DataConnector.java
+++ b/idp-attribute-resolver-api/src/main/java/net/shibboleth/idp/attribute/resolver/DataConnector.java
@@ -43,6 +43,19 @@ public interface DataConnector extends ResolverPlugin<Map<String, IdPAttribute>>
*/
@Nonnull Duration getNoRetryDelay();
+ /**
+ * Get the time when this connector last succeeded.
+ *
+ * TODO: Remove default in V5.
+ *
+ * @return when it last succeeded
+ *
+ * @since 4.1.0
+ */
+ @Nullable default Instant getLastSuccess() {
+ return Instant.now();
+ }
+
/**
* Get the time when this connector last failed. This will be set for any exception regardless of the setting of
* {@link #isPropagateResolutionExceptions()}
diff --git a/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/impl/AttributeResolverServiceGaugeSet.java b/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/impl/AttributeResolverServiceGaugeSet.java
index 3a42f381c..3544ce9df 100644
--- a/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/impl/AttributeResolverServiceGaugeSet.java
+++ b/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/impl/AttributeResolverServiceGaugeSet.java
@@ -53,11 +53,45 @@ public class AttributeResolverServiceGaugeSet extends ReloadableServiceGaugeSet<
*
* @param metricName name to include in metric names produced by this set
*/
+// Checkstyle: AnonInnerLength|MethodLength OFF
public AttributeResolverServiceGaugeSet(
@Nonnull @NotEmpty @ParameterName(name="metricName") final String metricName) {
super(metricName);
-// Checkstyle: AnonInnerLength OFF
+ getMetricMap().put(
+ MetricRegistry.name(DEFAULT_METRIC_NAME, metricName, "success"),
+ new Gauge<Map<String,Instant>>() {
+ public Map<String,Instant> getValue() {
+ final Map<String,Instant> mapBuilder = new HashMap<>();
+ final ServiceableComponent<AttributeResolver> component =
+ getService().getServiceableComponent();
+ if (component != null) {
+ try {
+ final Object resolver = component.getComponent();
+ if (resolver instanceof AttributeResolverImpl) {
+ final Collection<DataConnector> connectors =
+ ((AttributeResolverImpl) resolver).getDataConnectors().values();
+ for (final DataConnector connector: connectors) {
+ if (connector.getLastSuccess() != null) {
+ mapBuilder.put(connector.getId(), connector.getLastSuccess());
+ }
+ }
+ } else if (resolver instanceof AttributeResolver) {
+ log.debug("{}: Cannot get Data Connector success " +
+ " information from unsupported class type {}",
+ getLogPrefix(), resolver.getClass());
+ } else {
+ log.warn("{}: Injected Service was not for an AttributeResolver ({})",
+ getLogPrefix(), resolver.getClass());
+ }
+ } finally {
+ component.unpinComponent();
+ }
+ }
+ return Map.copyOf(mapBuilder);
+ }
+ });
+
getMetricMap().put(
MetricRegistry.name(DEFAULT_METRIC_NAME, metricName, "failure"),
new Gauge<Map<String,Instant>>() {
@@ -77,11 +111,11 @@ public class AttributeResolverServiceGaugeSet extends ReloadableServiceGaugeSet<
}
}
} else if (resolver instanceof AttributeResolver) {
- log.debug("{} : Cannot get Data Connector failure " +
+ log.debug("{}: Cannot get Data Connector failure " +
" information from unsupported class type {}",
getLogPrefix(), resolver.getClass());
} else {
- log.warn("{} : Injected Service was not for an AttributeResolver ({})",
+ log.warn("{}: Injected Service was not for an AttributeResolver ({})",
getLogPrefix(), resolver.getClass());
}
} finally {
@@ -91,9 +125,9 @@ public class AttributeResolverServiceGaugeSet extends ReloadableServiceGaugeSet<
return Map.copyOf(mapBuilder);
}
});
-// Checkstyle: AnonInnerLength ON
}
+// Checkstyle: AnonInnerLength|MethodLength ON
/** {@inheritDoc} */
@Override
@@ -106,7 +140,7 @@ public class AttributeResolverServiceGaugeSet extends ReloadableServiceGaugeSet<
if (component.getComponent() instanceof AttributeResolver) {
return;
}
- log.error("{} : Injected service was not for an AttributeResolver ({})",
+ log.error("{}: Injected service was not for an AttributeResolver ({})",
getLogPrefix(), component.getClass());
throw new ComponentInitializationException("Injected service was not for an AttributeResolver");
} finally {
diff --git a/idp-war/src/main/webapp/WEB-INF/jsp/status.jsp b/idp-war/src/main/webapp/WEB-INF/jsp/status.jsp
index 055a93ad6..3fbd94fbd 100644
--- a/idp-war/src/main/webapp/WEB-INF/jsp/status.jsp
+++ b/idp-war/src/main/webapp/WEB-INF/jsp/status.jsp
@@ -137,19 +137,30 @@ for (final ReloadableService service : (Collection<ReloadableService>) request.g
out.println("No Attribute Resolver Gauge Set Found");
continue;
}
- final Gauge<Map<String,Instant>> gauge = (Gauge<Map<String,Instant>>) metrics.getMetrics().get("net.shibboleth.idp.attribute.resolver.failure");
- Set<Entry<String, Instant>> entrySet = gauge.getValue().entrySet();
- if (entrySet.isEmpty()) {
+ final Gauge<Map<String,Instant>> failGauge =
+ (Gauge<Map<String,Instant>>) metrics.getMetrics().get("net.shibboleth.idp.attribute.resolver.failure");
+ final Set<Entry<String,Instant>> failSet = failGauge.getValue().entrySet();
+ if (failSet.isEmpty()) {
out.println("\tNo Data Connector has ever failed");
out.println();
continue;
}
- for (final Entry<String, Instant> en : entrySet) {
- final Instant lastFail = en.getValue();
+ final Gauge<Map<String,Instant>> successGauge =
+ (Gauge<Map<String,Instant>>) metrics.getMetrics().get("net.shibboleth.idp.attribute.resolver.success");
+ final Map<String,Instant> successMap = successGauge.getValue();
+ final ArrayList<String> failingConnectors = new ArrayList<>();
+ for (final Entry<String, Instant> en : failSet) {
final String connectorId = en.getKey();
+ final Instant lastFail = en.getValue();
out.println("\tDataConnector " + connectorId + ": last failed at " + dateTimeFormatter.format(lastFail));
out.println();
- }
- }
+ final Instant lastSuccess = successMap.get(connectorId);
+ if (lastSuccess == null || lastSuccess.isBefore(lastFail)) {
+ failingConnectors.add(connectorId);
+ }
+ }
+ out.println("\tCurrently failing: " + failingConnectors);
+ out.println();
+ }
}
%>
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list