summaryrefslogtreecommitdiffstats
path: root/config-model
diff options
context:
space:
mode:
authorArne Juul <arnej@vespa.ai>2024-04-24 18:19:28 +0000
committerArne Juul <arnej@vespa.ai>2024-04-24 18:19:28 +0000
commitf53f584170288eb4c3698ee99a605c7255cc8d99 (patch)
tree515213395dcdd819a79576ebdcefa4092e4d20db /config-model
parentf148e789a1cbf1d2aa81b03090765ca9c3b4da94 (diff)
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.java113
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/admin/otel/OpenTelemetryConfigGeneratorTest.java28
5 files changed, 145 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..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;
+ }
}
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..8f43fed65d1 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,6 +2,10 @@
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.vespa.model.AbstractService;
+import com.yahoo.vespa.model.PortAllocBridge;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
@@ -13,10 +17,30 @@ public class OpenTelemetryConfigGeneratorTest {
@Test
void testBuildsYaml() {
- var generator = new OpenTelemetryConfigGenerator(null);
- generator.addStatePorts(List.of(new StatePortInfo("localhost", 19098, "config-sentinel", "sentinel")));
+ var generator = new OpenTelemetryConfigGenerator(null, null);
+ var root = new MockRoot();
+ var mockPort1 = new StatePortInfo("localhost", 19098,
+ new MockService(root, "sentinel"));
+ 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) { }
+ }
+
}