diff options
author | Arne Juul <arnej@vespa.ai> | 2024-04-24 18:19:28 +0000 |
---|---|---|
committer | Arne Juul <arnej@vespa.ai> | 2024-04-24 18:19:28 +0000 |
commit | f53f584170288eb4c3698ee99a605c7255cc8d99 (patch) | |
tree | 515213395dcdd819a79576ebdcefa4092e4d20db /config-model/src/main/java | |
parent | f148e789a1cbf1d2aa81b03090765ca9c3b4da94 (diff) |
add some resource attributes and more per-service labels
Diffstat (limited to 'config-model/src/main/java')
4 files changed, 119 insertions, 10 deletions
diff --git a/config-model/src/main/java/com/yahoo/config/model/ApplicationConfigProducerRoot.java b/config-model/src/main/java/com/yahoo/config/model/ApplicationConfigProducerRoot.java index f324ceef5ab..2461fc64172 100644 --- a/config-model/src/main/java/com/yahoo/config/model/ApplicationConfigProducerRoot.java +++ b/config-model/src/main/java/com/yahoo/config/model/ApplicationConfigProducerRoot.java @@ -233,10 +233,7 @@ public class ApplicationConfigProducerRoot extends TreeConfigProducer<AnyConfigP } } - // add cluster type? - // add cluster name? - public record StatePortInfo(String hostName, int portNumber, - String serviceName, String serviceType) + public record StatePortInfo(String hostName, int portNumber, Service service) {} public List<StatePortInfo> getStatePorts() { @@ -244,8 +241,6 @@ public class ApplicationConfigProducerRoot extends TreeConfigProducer<AnyConfigP for (HostResource modelHost : hostSystem().getHosts()) { String hostName = modelHost.getHostname(); for (Service modelService : modelHost.getServices()) { - String serviceName = modelService.getServiceName(); - String serviceType = modelService.getServiceType(); PortsMeta portsMeta = modelService.getPortsMeta(); for (int i = 0; i < portsMeta.getNumPorts(); i++) { int portNumber = modelService.getRelativePort(i); @@ -256,7 +251,7 @@ public class ApplicationConfigProducerRoot extends TreeConfigProducer<AnyConfigP if (tag.equals("http")) isHttp = true; } if (hasState && isHttp) { - result.add(new StatePortInfo(hostName, portNumber, serviceName, serviceType)); + result.add(new StatePortInfo(hostName, portNumber, modelService)); } } } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/AbstractService.java b/config-model/src/main/java/com/yahoo/vespa/model/AbstractService.java index d8149486b32..806f14da265 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/AbstractService.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/AbstractService.java @@ -342,6 +342,7 @@ public abstract class AbstractService extends TreeConfigProducer<AnyConfigProduc return getServicePropertyString(key, null); } + @Override public String getServicePropertyString(String key, String defStr) { Object result = serviceProperties.get(key); return (result == null) ? defStr : result.toString(); diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/otel/OpenTelemetryCollector.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/otel/OpenTelemetryCollector.java index fcd587622da..03b96b12c03 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/otel/OpenTelemetryCollector.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/otel/OpenTelemetryCollector.java @@ -5,6 +5,7 @@ import com.yahoo.cloud.config.OpenTelemetryConfig; import com.yahoo.config.model.ApplicationConfigProducerRoot; import com.yahoo.config.model.deploy.DeployState; import com.yahoo.config.model.producer.TreeConfigProducer; +import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.Zone; import com.yahoo.vespa.model.AbstractService; import com.yahoo.vespa.model.PortAllocBridge; @@ -17,10 +18,12 @@ import java.util.Optional; public class OpenTelemetryCollector extends AbstractService implements OpenTelemetryConfig.Producer { private final Zone zone; + private final ApplicationId applicationId; public OpenTelemetryCollector(TreeConfigProducer<?> parent) { super(parent, "otelcol"); this.zone = null; + this.applicationId = null; setProp("clustertype", "admin"); setProp("clustername", "admin"); } @@ -28,6 +31,7 @@ public class OpenTelemetryCollector extends AbstractService implements OpenTelem public OpenTelemetryCollector(TreeConfigProducer<?> parent, DeployState deployState) { super(parent, "otelcol"); this.zone = deployState.zone(); + this.applicationId = deployState.getProperties().applicationId(); setProp("clustertype", "admin"); setProp("clustername", "admin"); } @@ -50,7 +54,7 @@ public class OpenTelemetryCollector extends AbstractService implements OpenTelem @Override public void getConfig(OpenTelemetryConfig.Builder builder) { - var generator = new OpenTelemetryConfigGenerator(zone); + var generator = new OpenTelemetryConfigGenerator(zone, applicationId); AnyConfigProducer pp = this; AnyConfigProducer p = pp.getParent(); while (p != null && p != pp) { diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/otel/OpenTelemetryConfigGenerator.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/otel/OpenTelemetryConfigGenerator.java index 36eab6a04b3..eceadaabc9e 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/otel/OpenTelemetryConfigGenerator.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/otel/OpenTelemetryConfigGenerator.java @@ -1,16 +1,23 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.model.admin.otel; +import ai.vespa.metricsproxy.metric.dimensions.PublicDimensions; import com.fasterxml.jackson.core.JsonEncoding; import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonGenerator; import com.yahoo.config.model.ApplicationConfigProducerRoot.StatePortInfo; +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.ClusterMembership; +import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.Zone; +import com.yahoo.vespa.model.Service; import java.io.ByteArrayOutputStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import static com.yahoo.vespa.defaults.Defaults.getDefaults; @@ -24,8 +31,12 @@ public class OpenTelemetryConfigGenerator { private final String cert_file; private final String key_file; private List<StatePortInfo> statePorts = new ArrayList<>(); + private final Zone zone; + private final ApplicationId applicationId; - OpenTelemetryConfigGenerator(Zone zone) { + OpenTelemetryConfigGenerator(Zone zone, ApplicationId applicationId) { + this.zone = zone; + this.applicationId = applicationId; boolean isCd = true; boolean isPublic = true; if (zone != null) { @@ -81,8 +92,13 @@ public class OpenTelemetryConfigGenerator { if (useTls) addTls(g); { g.writeFieldName("labels"); + var dimVals = serviceAttributes(statePort.service()); + // these will be tagged as dimension-name/label-value + // attributes on all metrics from this /state/v1 port g.writeStartObject(); - g.writeStringField("service_type", statePort.serviceType()); + for (var entry : dimVals.entrySet()) { + g.writeStringField(entry.getKey(), entry.getValue()); + } g.writeEndObject(); } g.writeEndObject(); @@ -123,6 +139,36 @@ public class OpenTelemetryConfigGenerator { } g.writeEndObject(); // file } + private void addProcessors(JsonGenerator g) throws java.io.IOException { + g.writeFieldName("processors"); + g.writeStartObject(); + addResourceProcessor(g); + g.writeEndObject(); + } + private void addResourceProcessor(JsonGenerator g) throws java.io.IOException { + g.writeFieldName("resource"); + g.writeStartObject(); + g.writeFieldName("attributes"); + g.writeStartArray(); + // common attributes for all metrics from all services; + // which application and which cloud/system/zone/environment + addAttributeInsert(g, PublicDimensions.ZONE, zoneAttr()); + addAttributeInsert(g, PublicDimensions.APPLICATION_ID, appIdAttr()); + addAttributeInsert(g, "system", systemAttr()); + addAttributeInsert(g, "tenantName", tenantAttr()); + addAttributeInsert(g, "applicationName", appNameAttr()); + addAttributeInsert(g, "instanceName", appInstanceAttr()); + addAttributeInsert(g, "cloud", cloudAttr()); + g.writeEndArray(); + g.writeEndObject(); + } + private void addAttributeInsert(JsonGenerator g, String key, String value) throws java.io.IOException { + g.writeStartObject(); + g.writeStringField("key", key); + g.writeStringField("value", value); + g.writeStringField("action", "insert"); + g.writeEndObject(); + } private void addServiceBlock(JsonGenerator g) throws java.io.IOException { g.writeFieldName("service"); g.writeStartObject(); @@ -159,6 +205,7 @@ public class OpenTelemetryConfigGenerator { } g.writeFieldName("processors"); g.writeStartArray(); + g.writeString("resource"); g.writeEndArray(); { g.writeFieldName("exporters"); @@ -186,6 +233,7 @@ public class OpenTelemetryConfigGenerator { g.writeStartObject(); addReceivers(g); addExporters(g); + addProcessors(g); addServiceBlock(g); g.writeEndObject(); // root g.close(); @@ -203,4 +251,65 @@ public class OpenTelemetryConfigGenerator { List<String> referencedPaths() { return List.of(ca_file, cert_file, key_file); } + + private String zoneAttr() { + if (zone == null) return "noZone"; + return zone.environment().value() + "." + zone.region().value(); + } + private String appIdAttr() { + if (applicationId == null) return "noApp"; + return applicationId.toFullString(); + } + private String systemAttr() { + if (zone == null) return "noSystem"; + return zone.system().value(); + } + private String tenantAttr() { + if (applicationId == null) return "noTenant"; + return applicationId.tenant().value(); + } + private String appNameAttr() { + if (applicationId == null) return "noAppName"; + return applicationId.application().value(); + } + private String appInstanceAttr() { + if (applicationId == null) return "noAppInstance"; + return applicationId.instance().value(); + } + private String cloudAttr() { + if (zone == null) return "noCloud"; + return zone.cloud().name().value(); + } + private String getDeploymentCluster(ClusterSpec cluster) { + return String.join(".", applicationId.toFullString(), + zone.environment().value(), zone.region().value(), + cluster.id().value()); + } + + private Map<String, String> serviceAttributes(Service svc) { + Map<String, String> dimvals = new LinkedHashMap<>(); + dimvals.put("service_name", svc.getServiceName()); // used to be "instance" + dimvals.put("service_type", svc.getServiceType()); // added, do we need it? + String cName = svc.getServicePropertyString("clustername", null); + if (cName != null) { + // what about "clusterid" below, is it always the same? + dimvals.put("clustername", cName); + } + String cType = svc.getServicePropertyString("clustertype", null); + if (cType != null) { + dimvals.put("clustertype", cType); + } + var hostResource = svc.getHost(); + if (hostResource != null) { + hostResource.spec().membership().map(ClusterMembership::cluster).ifPresent(cluster -> { + dimvals.put(PublicDimensions.DEPLOYMENT_CLUSTER, getDeploymentCluster(cluster)); + // same as above? + dimvals.put(PublicDimensions.INTERNAL_CLUSTER_TYPE, cluster.type().name()); + // same as above? + dimvals.put(PublicDimensions.INTERNAL_CLUSTER_ID, cluster.id().value()); + cluster.group().ifPresent(group -> dimvals.put(PublicDimensions.GROUP_ID, group.toString())); + }); + } + return dimvals; + } } |