summaryrefslogtreecommitdiffstats
path: root/config-model
diff options
context:
space:
mode:
authorOla Aunrønning <olaa@vespa.ai>2024-05-03 12:49:05 +0200
committerGitHub <noreply@github.com>2024-05-03 12:49:05 +0200
commiteb7ae3955bb40f2c4456a4d3a4c0b73591d15dcb (patch)
tree9830f331a4936c1358127bc3b3a6a52d2a1b57f3 /config-model
parent85664b834b2883dd47b6d551b296ed87a0cb2d0f (diff)
parent3132665b8407b455646bbe2d48d806018de57b6e (diff)
Merge pull request #31047 from vespa-engine/arnej/add-resource-attributes
add some resource attributes and more per-service labels
Diffstat (limited to 'config-model')
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/ApplicationConfigProducerRoot.java9
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/AbstractService.java1
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/admin/otel/OpenTelemetryCollector.java6
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/admin/otel/OpenTelemetryConfigGenerator.java121
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/admin/otel/OpenTelemetryConfigGeneratorTest.java55
5 files changed, 180 insertions, 12 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..3f7ca7b46a7 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,15 @@ 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()) {
+ if (entry.getValue() != null) {
+ g.writeStringField(entry.getKey(), entry.getValue());
+ }
+ }
g.writeEndObject();
}
g.writeEndObject();
@@ -123,6 +141,37 @@ 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 {
+ if (value == null) return;
+ 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 +208,7 @@ public class OpenTelemetryConfigGenerator {
}
g.writeFieldName("processors");
g.writeStartArray();
+ g.writeString("resource");
g.writeEndArray();
{
g.writeFieldName("exporters");
@@ -186,6 +236,7 @@ public class OpenTelemetryConfigGenerator {
g.writeStartObject();
addReceivers(g);
addExporters(g);
+ addProcessors(g);
addServiceBlock(g);
g.writeEndObject(); // root
g.close();
@@ -203,4 +254,70 @@ public class OpenTelemetryConfigGenerator {
List<String> referencedPaths() {
return List.of(ca_file, cert_file, key_file);
}
+
+ private String zoneAttr() {
+ if (zone == null) return null;
+ return zone.environment().value() + "." + zone.region().value();
+ }
+ private String appIdAttr() {
+ if (applicationId == null) return null;
+ return applicationId.toFullString();
+ }
+ private String systemAttr() {
+ if (zone == null) return null;
+ return zone.system().value();
+ }
+ private String tenantAttr() {
+ if (applicationId == null) return null;
+ return applicationId.tenant().value();
+ }
+ private String appNameAttr() {
+ if (applicationId == null) return null;
+ return applicationId.application().value();
+ }
+ private String appInstanceAttr() {
+ if (applicationId == null) return null;
+ return applicationId.instance().value();
+ }
+ private String cloudAttr() {
+ if (zone == null) return null;
+ return zone.cloud().name().value();
+ }
+
+ private String getDeploymentCluster(ClusterSpec cluster) {
+ if (applicationId == null) return null;
+ if (zone == null) return null;
+ String appString = applicationId.toFullString();
+ return String.join(".", appString,
+ zone.environment().value(),
+ zone.region().value(),
+ cluster.id().value());
+ }
+
+ private Map<String, String> serviceAttributes(Service svc) {
+ Map<String, String> dimvals = new LinkedHashMap<>();
+ dimvals.put("instance", svc.getServiceName()); // should maybe be "local_service_name" ?
+ dimvals.put("instanceType", svc.getServiceType()); // maybe "local_service_type", or remove
+ 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));
+ // overrides value above
+ dimvals.put(PublicDimensions.INTERNAL_CLUSTER_TYPE, cluster.type().name());
+ // alternative to above
+ dimvals.put(PublicDimensions.INTERNAL_CLUSTER_ID, cluster.id().value());
+ cluster.group().ifPresent(group -> dimvals.put(PublicDimensions.GROUP_ID, group.toString()));
+ });
+ }
+ return dimvals;
+ }
}
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/admin/otel/OpenTelemetryConfigGeneratorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/admin/otel/OpenTelemetryConfigGeneratorTest.java
index 7c4968aac84..c24fcb27dc9 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/admin/otel/OpenTelemetryConfigGeneratorTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/admin/otel/OpenTelemetryConfigGeneratorTest.java
@@ -2,8 +2,24 @@
package com.yahoo.vespa.model.admin.otel;
import com.yahoo.config.model.ApplicationConfigProducerRoot.StatePortInfo;
+import com.yahoo.config.model.producer.TreeConfigProducer;
+import com.yahoo.config.model.test.MockRoot;
+import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.ClusterMembership;
+import com.yahoo.config.provision.Environment;
+import com.yahoo.config.provision.HostSpec;
+import com.yahoo.config.provision.NodeResources;
+import com.yahoo.config.provision.RegionName;
+import com.yahoo.config.provision.SystemName;
+import com.yahoo.config.provision.Zone;
+import com.yahoo.vespa.model.AbstractService;
+import com.yahoo.vespa.model.Host;
+import com.yahoo.vespa.model.HostResource;
+import com.yahoo.vespa.model.AbstractService;
+import com.yahoo.vespa.model.PortAllocBridge;
import org.junit.jupiter.api.Test;
import java.util.List;
+import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
/**
@@ -13,10 +29,45 @@ public class OpenTelemetryConfigGeneratorTest {
@Test
void testBuildsYaml() {
- var generator = new OpenTelemetryConfigGenerator(null);
- generator.addStatePorts(List.of(new StatePortInfo("localhost", 19098, "config-sentinel", "sentinel")));
+ var mockZone = new Zone(SystemName.PublicCd, Environment.prod, RegionName.from("mock"));
+ var app = ApplicationId.from("mytenant", "myapp", "myinstance");
+ var generator = new OpenTelemetryConfigGenerator(mockZone, app);
+ var root = new MockRoot();
+
+ var mockHost = new Host(root, "localhost2.local");
+ var mockVersion = new com.yahoo.component.Version(8);
+ var mockCluster = ClusterMembership.from("container/feeding/2/3", mockVersion, Optional.empty());
+ var noResource = NodeResources.unspecified();
+ var mockHostSpec = new HostSpec("localhost1.local",
+ noResource, noResource, noResource,
+ mockCluster,
+ Optional.empty(), Optional.empty(), Optional.empty());
+ var mockHostResource = new HostResource(mockHost, mockHostSpec);
+ var mockSvc1 = new MockService(root, "sentinel");
+ mockSvc1.setHostResource(mockHostResource);
+ var mockPort1 = new StatePortInfo("localhost", 19098, mockSvc1);
+
+ var mockSvc2 = new MockService(root, "searchnode");
+ mockSvc2.setProp("clustername", "mycluster");
+ mockSvc2.setProp("clustertype", "mockup");
+ var mockPort2 = new StatePortInfo("other.host.local", 19102, mockSvc2);
+
+ generator.addStatePorts(List.of(mockPort1, mockPort2));
String yaml = generator.generate();
+ // System.err.println(">>>\n" + yaml + "\n<<<");
assertTrue(yaml.contains("sentinel"));
}
+ static class MockService extends AbstractService {
+ private final String name;
+ public MockService(TreeConfigProducer<?> parent, String name) {
+ super(parent, name);
+ this.name = name;
+ }
+ public String getServiceName() { return name; }
+ public String getServiceType() { return "dummy"; }
+ @Override public int getPortCount() { return 0; }
+ @Override public void allocatePorts(int start, PortAllocBridge from) { }
+ }
+
}