All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ai.vespa.metricsproxy.metric.model.MetricsPacket Maven / Gradle / Ivy

There is a newer version: 8.441.21
Show newest version
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package ai.vespa.metricsproxy.metric.model;

import ai.vespa.metricsproxy.metric.Metric;

import java.time.Instant;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;

import static java.util.stream.Collectors.joining;

/**
 * Represents a packet of metrics (with meta information) that belong together because they:
 * 
    *
  • share both the same dimensions and consumers, AND
  • *
  • represent the same source, e.g. a vespa service or the system hardware.
  • *
* * @author gjoranv */ public class MetricsPacket { private final int statusCode; private final String statusMessage; private final ServiceId service; private final Instant timestamp; private final Map metrics; private final Map dimensions; private final Set consumers; private MetricsPacket(int statusCode, String statusMessage, Instant timestamp, ServiceId service, Map metrics, Map dimensions, Set consumers ) { this.statusCode = statusCode; this.statusMessage = statusMessage; this.timestamp = timestamp; this.service = service; this.metrics = Collections.unmodifiableMap(metrics); // Retain order for tests this.dimensions = Collections.unmodifiableMap(dimensions); // Retain order for tests this.consumers = Set.copyOf(consumers); } public Map metrics() { return metrics; } public Map dimensions() { return dimensions; } public Set consumers() { return consumers; } public Instant timestamp() { return timestamp; } public ServiceId service() { return service; } public int statusCode() { return statusCode; } public String statusMessage() { return statusMessage; } @Override public String toString() { return "MetricsPacket{" + "statusCode=" + statusCode + ", statusMessage='" + statusMessage + '\'' + ", timestamp=" + timestamp + ", service=" + service.id + ", metrics=" + idMapToString(metrics, id -> id.id) + ", dimensions=" + idMapToString(dimensions, id -> id.id) + ", consumers=" + consumers.stream().map(id -> id.id).collect(joining(",", "[", "]")) + '}'; } private static String idMapToString(Map map, Function idMapper) { return map.entrySet().stream() .map(entry -> idMapper.apply(entry.getKey()) + "=" + entry.getValue()) .collect(joining(",", "{", "}")); } public static class Builder { // Set defaults here, and use null guard in all setters. // Except for 'service' for which we require an explicit non-null value. private ServiceId service; private int statusCode = 0; private String statusMessage = ""; private Instant timestamp = Instant.EPOCH; private Map metrics = new LinkedHashMap<>(); private final Map dimensions = new LinkedHashMap<>(); private Set consumers = Set.of(); public Builder(ServiceId service) { Objects.requireNonNull(service, "Service cannot be null."); this.service = service; } public Builder service(ServiceId service) { if (service == null) throw new IllegalArgumentException("Service cannot be null."); this.service = service; return this; } public Builder statusCode(Integer statusCode) { if (statusCode != null) this.statusCode = statusCode; return this; } public Builder statusMessage(String statusMessage) { if (statusMessage != null) this.statusMessage = statusMessage; return this; } public Builder timestamp(Instant timestamp) { if (timestamp != null) this.timestamp = timestamp; return this; } public Builder putMetrics(Collection extraMetrics) { if (extraMetrics != null) extraMetrics.forEach(metric -> metrics.put(metric.getName(), metric.getValue())); return this; } public Builder putMetric(MetricId id, Number value) { metrics.put(id, value); return this; } public Builder retainMetrics(Set idsToRetain) { metrics.keySet().retainAll(idsToRetain); return this; } public Builder applyOutputNames(Map> outputNamesById) { Map newMetrics = new LinkedHashMap<>(); outputNamesById.forEach((id, outputNames) -> { if (metrics.containsKey(id)) outputNames.forEach(outputName -> newMetrics.put(outputName, metrics.get(id))); }); metrics = newMetrics; return this; } public Builder putDimension(DimensionId id, String value) { dimensions.put(id, value); return this; } public Builder putDimensions(Map extraDimensions) { if (extraDimensions != null) dimensions.putAll(extraDimensions); return this; } public Builder putDimensionsIfAbsent(Map extraDimensions) { if (extraDimensions != null) extraDimensions.forEach(dimensions::putIfAbsent); return this; } /** * Returns a modifiable copy of the dimension IDs of this builder, usually for use with {@link #retainDimensions(Collection)}. */ public Set getDimensionIds() { return new LinkedHashSet<>(dimensions.keySet()); } public String getDimensionValue(DimensionId id) { return dimensions.get(id); } public Builder retainDimensions(Collection idsToRetain) { dimensions.keySet().retainAll(idsToRetain); return this; } public Builder addConsumers(Set extraConsumers) { if ((extraConsumers != null) && !extraConsumers.isEmpty()) { if (consumers.isEmpty()) { if (extraConsumers.size() == 1) { consumers = Set.of(extraConsumers.iterator().next()); return this; } consumers = new LinkedHashSet<>(extraConsumers.size()); } else if (consumers.size() == 1) { var copy = new LinkedHashSet(extraConsumers.size() + 1); copy.addAll(consumers); consumers = copy; } consumers.addAll(extraConsumers); } return this; } public boolean hasConsumer(ConsumerId id) { return consumers.contains(id); } public MetricsPacket build() { return new MetricsPacket(statusCode, statusMessage, timestamp, service, metrics, dimensions, consumers); } public boolean hasMetrics() { return ! metrics.isEmpty(); } public Instant getTimestamp() { return timestamp; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy