[java-opensaml] branch main updated: Migrate some general metrics support classes out of IdP.
Scott Cantor
cantor.2 at osu.edu
Mon Oct 10 20:04:17 UTC 2022
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch main
in repository java-opensaml.
View the commit online:
http://git.shibboleth.net/view/?p=java-opensaml.git;a=commit;h=bc5bb05d9b1b0162330239bfc942dbefa29b70e5
The following commit(s) were added to refs/heads/main by this push:
new bc5bb05d9 Migrate some general metrics support classes out of IdP.
bc5bb05d9 is described below
commit bc5bb05d9b1b0162330239bfc942dbefa29b70e5
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Mon Oct 10 16:04:14 2022 -0400
Migrate some general metrics support classes out of IdP.
---
opensaml-core-impl/pom.xml | 35 ++-
.../opensaml/core/metrics/impl/CoreGaugeSet.java | 203 ++++++++++++++
.../opensaml/core/metrics/impl/HTTPReporter.java | 305 +++++++++++++++++++++
3 files changed, 537 insertions(+), 6 deletions(-)
diff --git a/opensaml-core-impl/pom.xml b/opensaml-core-impl/pom.xml
index 779d8e207..76878c4f7 100644
--- a/opensaml-core-impl/pom.xml
+++ b/opensaml-core-impl/pom.xml
@@ -27,20 +27,37 @@
<artifactId>opensaml-core-api</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>opensaml-security-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
- <groupId>commons-codec</groupId>
- <artifactId>commons-codec</artifactId>
+ <groupId>io.dropwizard.metrics</groupId>
+ <artifactId>metrics-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.dropwizard.metrics</groupId>
+ <artifactId>metrics-json</artifactId>
</dependency>
<dependency>
- <groupId>com.google.guava</groupId>
- <artifactId>guava</artifactId>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
</dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.datatype</groupId>
+ <artifactId>jackson-datatype-jsr310</artifactId>
+ </dependency>
<dependency>
- <groupId>io.dropwizard.metrics</groupId>
- <artifactId>metrics-core</artifactId>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpcore</artifactId>
</dependency>
<!-- Provided Dependencies -->
@@ -55,6 +72,12 @@
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <scope>test</scope>
+ </dependency>
+
<dependency>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-core</artifactId>
diff --git a/opensaml-core-impl/src/main/java/org/opensaml/core/metrics/impl/CoreGaugeSet.java b/opensaml-core-impl/src/main/java/org/opensaml/core/metrics/impl/CoreGaugeSet.java
new file mode 100644
index 000000000..10dd5dd08
--- /dev/null
+++ b/opensaml-core-impl/src/main/java/org/opensaml/core/metrics/impl/CoreGaugeSet.java
@@ -0,0 +1,203 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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 org.opensaml.core.metrics.impl;
+
+import com.codahale.metrics.Gauge;
+import com.codahale.metrics.Metric;
+import com.codahale.metrics.MetricFilter;
+import com.codahale.metrics.MetricSet;
+import com.codahale.metrics.RatioGauge;
+
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+
+/**
+ * A set of gauges for core system information.
+ */
+public class CoreGaugeSet implements MetricSet, MetricFilter {
+
+ /** The map of gauges. */
+ @Nonnull @NonnullElements private final Map<String,Metric> gauges;
+
+// Checkstyle: MethodLength OFF
+ /** Constructor. */
+ public CoreGaugeSet() {
+ gauges = new HashMap<>();
+
+ gauges.put(
+ "host.name",
+ new Gauge<String>() {
+ public String getValue() {
+ try {
+ return InetAddress.getLocalHost().getHostName();
+ } catch (final UnknownHostException e) {
+ return null;
+ }
+ }
+ });
+
+ gauges.put(
+ "os.name",
+ new Gauge<String>() {
+ public String getValue() {
+ return System.getProperty("os.name");
+ }
+ });
+
+ gauges.put(
+ "os.version",
+ new Gauge<String>() {
+ public String getValue() {
+ return System.getProperty("os.version");
+ }
+ });
+
+ gauges.put(
+ "os.arch",
+ new Gauge<String>() {
+ public String getValue() {
+ return System.getProperty("os.arch");
+ }
+ });
+
+ gauges.put(
+ "java.class.path",
+ new Gauge<String>() {
+ public String getValue() {
+ return System.getProperty("java.class.path");
+ }
+ });
+
+ gauges.put(
+ "java.home",
+ new Gauge<String>() {
+ public String getValue() {
+ return System.getProperty("java.home");
+ }
+ });
+
+ gauges.put(
+ "java.vendor",
+ new Gauge<String>() {
+ public String getValue() {
+ return System.getProperty("java.vendor");
+ }
+ });
+
+ gauges.put(
+ "java.vendor.url",
+ new Gauge<String>() {
+ public String getValue() {
+ return System.getProperty("java.vendor.url");
+ }
+ });
+
+ gauges.put(
+ "java.version",
+ new Gauge<String>() {
+ public String getValue() {
+ return System.getProperty("java.version");
+ }
+ });
+
+ gauges.put(
+ "cores.available",
+ new Gauge<Integer>() {
+ public Integer getValue() {
+ return Runtime.getRuntime().availableProcessors();
+ }
+ });
+
+ gauges.put(
+ "memory.free.bytes",
+ new Gauge<Long>() {
+ public Long getValue() {
+ return Runtime.getRuntime().freeMemory();
+ }
+ });
+
+ gauges.put(
+ "memory.free.megs",
+ new Gauge<Long>() {
+ public Long getValue() {
+ return Runtime.getRuntime().freeMemory() / (1024 * 1024);
+ }
+ });
+
+ gauges.put(
+ "memory.used.bytes",
+ new Gauge<Long>() {
+ public Long getValue() {
+ final Runtime runtime = Runtime.getRuntime();
+ return runtime.totalMemory() - runtime.freeMemory();
+ }
+ });
+
+ gauges.put(
+ "memory.used.megs",
+ new Gauge<Long>() {
+ public Long getValue() {
+ final Runtime runtime = Runtime.getRuntime();
+ return (runtime.totalMemory() - runtime.freeMemory()) / (1024 * 1024);
+ }
+ });
+
+ gauges.put(
+ "memory.max.bytes",
+ new Gauge<Long>() {
+ public Long getValue() {
+ return Runtime.getRuntime().maxMemory();
+ }
+ });
+
+ gauges.put(
+ "memory.max.megs",
+ new Gauge<Long>() {
+ public Long getValue() {
+ return Runtime.getRuntime().maxMemory() / (1024 * 1024);
+ }
+ });
+
+ gauges.put(
+ "memory.usage",
+ new RatioGauge() {
+ protected Ratio getRatio() {
+ final Runtime runtime = Runtime.getRuntime();
+ return Ratio.of(runtime.totalMemory() - runtime.freeMemory(), runtime.totalMemory());
+ }
+ });
+ }
+// Checkstyle: MethodLength ON
+
+ /** {@inheritDoc} */
+ public Map<String,Metric> getMetrics() {
+ return Collections.unmodifiableMap(gauges);
+ }
+
+ /** {@inheritDoc} */
+ public boolean matches(final String name, final Metric metric) {
+ return gauges.containsKey(name);
+ }
+
+}
\ No newline at end of file
diff --git a/opensaml-core-impl/src/main/java/org/opensaml/core/metrics/impl/HTTPReporter.java b/opensaml-core-impl/src/main/java/org/opensaml/core/metrics/impl/HTTPReporter.java
new file mode 100644
index 000000000..85d937f2f
--- /dev/null
+++ b/opensaml-core-impl/src/main/java/org/opensaml/core/metrics/impl/HTTPReporter.java
@@ -0,0 +1,305 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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 org.opensaml.core.metrics.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.SortedMap;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.entity.EntityBuilder;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.entity.ContentType;
+import org.opensaml.security.httpclient.HttpClientSecurityParameters;
+import org.opensaml.security.httpclient.HttpClientSecuritySupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.codahale.metrics.Counter;
+import com.codahale.metrics.Gauge;
+import com.codahale.metrics.Histogram;
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.MetricFilter;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.ScheduledReporter;
+import com.codahale.metrics.Timer;
+import com.codahale.metrics.json.MetricsModule;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectWriter;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+
+import net.shibboleth.shared.annotation.ParameterName;
+import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.component.InitializableComponent;
+import net.shibboleth.shared.component.UninitializedComponentException;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.StringSupport;
+
+/**
+ * A metrics reporter that runs at scheduled times and posts a JSON feed of metrics to a designated endpoint.
+ */
+public class HTTPReporter extends ScheduledReporter implements InitializableComponent {
+
+ /** Default date/time format string. */
+ @Nonnull @NotEmpty public static final String DEFAULT_DT_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZZ";
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(HTTPReporter.class);
+
+ /** Registry of metrics. */
+ @Nonnull private final MetricRegistry metricRegistry;
+
+ /** Filter to apply. */
+ @Nonnull private final MetricFilter metricFilter;
+
+ /** Rate unit. */
+ @Nonnull private final TimeUnit rateUnit;
+
+ /** Duration unit. */
+ @Nonnull private final TimeUnit durationUnit;
+
+ /** HTTP Client used to post the data. */
+ @NonnullAfterInit private HttpClient httpClient;
+
+ /** URL to the collection point. */
+ @NonnullAfterInit @NotEmpty private String collectorURL;
+
+ /** HTTP client security parameters. */
+ @Nullable private HttpClientSecurityParameters httpClientSecurityParameters;
+
+ /** JSON object mapper to produce output. */
+ @NonnullAfterInit private ObjectMapper jsonMapper;
+
+ /** Formatting string for {@link DateFormat} fields. */
+ @Nullable private String dateTimeFormat;
+
+ /** Whether this component has been initialized. */
+ private boolean isInitialized;
+
+ /**
+ * Constructor.
+ *
+ * @param registry the registry of metrics to report
+ * @param name the reporter name
+ * @param filter filter to apply
+ */
+ public HTTPReporter(@Nonnull @ParameterName(name="registry") final MetricRegistry registry,
+ @Nonnull @NotEmpty @ParameterName(name="name") final String name,
+ @Nullable @ParameterName(name="filter") final MetricFilter filter) {
+ super(registry, name, filter, TimeUnit.SECONDS, TimeUnit.SECONDS);
+ metricRegistry = registry;
+ metricFilter = filter != null ? filter : MetricFilter.ALL;
+ rateUnit = TimeUnit.SECONDS;
+ durationUnit = TimeUnit.SECONDS;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param registry the registry of metrics to report
+ * @param name the reporter name
+ * @param filter filter to apply
+ * @param rUnit unit to apply to rate information
+ * @param dUnit unit to apply to duration information
+ */
+ public HTTPReporter(@Nonnull @ParameterName(name="registry") final MetricRegistry registry,
+ @Nonnull @NotEmpty @ParameterName(name="name") final String name,
+ @Nullable @ParameterName(name="filter") final MetricFilter filter,
+ @Nonnull @ParameterName(name="rUnit") final TimeUnit rUnit,
+ @Nonnull @ParameterName(name="dUnit") final TimeUnit dUnit) {
+ super(registry, name, filter, rUnit, dUnit);
+ metricRegistry = registry;
+ metricFilter = filter != null ? filter : MetricFilter.ALL;
+ rateUnit = rUnit;
+ durationUnit = dUnit;
+ }
+
+// Checkstyle: ParameterNumber OFF
+ /**
+ * Constructor.
+ *
+ * @param registry the registry of metrics to report
+ * @param name the reporter name
+ * @param filter filter to apply
+ * @param rUnit unit to apply to rate information
+ * @param dUnit unit to apply to duration information
+ * @param executor task scheduler
+ */
+ public HTTPReporter(@Nonnull @ParameterName(name="registry") final MetricRegistry registry,
+ @Nonnull @NotEmpty @ParameterName(name="name") final String name,
+ @Nullable @ParameterName(name="filter") final MetricFilter filter,
+ @Nonnull @ParameterName(name="rUnit") final TimeUnit rUnit,
+ @Nonnull @ParameterName(name="dUnit") final TimeUnit dUnit,
+ @Nonnull @ParameterName(name="executor") final ScheduledExecutorService executor) {
+ super(registry, name, filter, rUnit, dUnit, executor);
+ metricRegistry = registry;
+ metricFilter = filter != null ? filter : MetricFilter.ALL;
+ rateUnit = rUnit;
+ durationUnit = dUnit;
+ }
+// Checkstyle: ParameterNumber ON
+
+ /**
+ * Set the {@link HttpClient} to use.
+ *
+ * @param client client to use
+ */
+ public void setHttpClient(@Nonnull final HttpClient client) {
+ doSetterPreconditions();
+ httpClient = Constraint.isNotNull(client, "HttpClient cannot be null");
+ }
+
+ /**
+ * Set the collection point to supply the data to.
+ *
+ * @param url URL to post data to
+ */
+ public void setCollectorURL(@Nonnull @NotEmpty final String url) {
+ doSetterPreconditions();
+ collectorURL = Constraint.isNotNull(StringSupport.trimOrNull(url), "Collector URL cannot be null or empty");
+ }
+
+ /**
+ * Set the optional client security parameters.
+ *
+ * @param params the new client security parameters
+ */
+ public void setHttpClientSecurityParameters(@Nullable final HttpClientSecurityParameters params) {
+ doSetterPreconditions();
+ httpClientSecurityParameters = params;
+ }
+
+ /**
+ * Set the {@link DateFormat} formatting string to apply when writing {@link DateFormat}-valued fields.
+ *
+ * @param format formatting string
+ */
+ public void setDateTimeFormat(@Nullable @NotEmpty final String format) {
+ doSetterPreconditions();
+ dateTimeFormat = StringSupport.trimOrNull(format);
+ }
+
+ /**
+ * Helper for a setter method to check the standard preconditions.
+ */
+ private final void doSetterPreconditions() {
+ if (!isInitialized()) {
+ throw new UninitializedComponentException(
+ "HTTPReported has not yet been initialized and cannot be used.");
+ }
+ }
+
+ /** {@inheritDoc} */
+ public boolean isInitialized() {
+ return isInitialized;
+ }
+
+ /** {@inheritDoc} */
+ public void initialize() throws ComponentInitializationException {
+ if (!isInitialized) {
+ if (httpClient == null || collectorURL == null) {
+ throw new ComponentInitializationException("HttpClient and collection URL cannot be null");
+ }
+
+ jsonMapper = new ObjectMapper().registerModule(
+ new MetricsModule(rateUnit, durationUnit, true, metricFilter));
+ jsonMapper.registerModule(new JavaTimeModule());
+ jsonMapper.setDateFormat(new SimpleDateFormat(dateTimeFormat != null ? dateTimeFormat : DEFAULT_DT_FORMAT));
+ jsonMapper.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false);
+
+ isInitialized = true;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void stop() {
+ super.stop();
+ httpClient = null;
+ httpClientSecurityParameters = null;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void report() {
+ synchronized (this) {
+ try {
+ final HttpPost httpRequest = new HttpPost(collectorURL);
+ final HttpClientContext httpContext = buildHttpContext(httpRequest);
+
+ final ByteArrayOutputStream output = new ByteArrayOutputStream(4096);
+ final ObjectWriter writer = jsonMapper.writer();
+ writer.writeValue(output, metricRegistry);
+
+ // Construct streamed request body.
+ final EntityBuilder entityBuilder = EntityBuilder.create();
+ entityBuilder.setContentType(ContentType.APPLICATION_JSON);
+ entityBuilder.setBinary(output.toByteArray());
+ httpRequest.setEntity(entityBuilder.build());
+
+ final HttpResponse response = httpClient.execute(httpRequest, httpContext);
+ HttpClientSecuritySupport.checkTLSCredentialEvaluated(httpContext, httpRequest.getURI().getScheme());
+
+ if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+ log.debug("Metrics delivered successfully to collector");
+ } else {
+ log.error("Collector responded with HTTP status {}", response.getStatusLine().getStatusCode());
+ }
+ } catch (final IOException e) {
+ log.error("Error sending metric registry to collection point {}", collectorURL, e);
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void report(final SortedMap<String, Gauge> gauges, final SortedMap<String, Counter> counters,
+ final SortedMap<String, Histogram> histograms, final SortedMap<String, Meter> meters,
+ final SortedMap<String, Timer> timers) {
+ throw new UnsupportedOperationException("The per-metric report method should never be called.");
+ }
+
+
+ /**
+ * Build the {@link HttpClientContext} instance to be used by the HttpClient.
+ *
+ * @param request the HTTP client request
+ * @return the client context instance
+ */
+ @Nonnull private HttpClientContext buildHttpContext(@Nonnull final HttpUriRequest request) {
+ final HttpClientContext clientContext = HttpClientContext.create();
+ HttpClientSecuritySupport.marshalSecurityParameters(clientContext, httpClientSecurityParameters, false);
+ HttpClientSecuritySupport.addDefaultTLSTrustEngineCriteria(clientContext, request);
+ return clientContext;
+ }
+
+}
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list