From e8b20619da13eb97b976f528df00881e2d0f7248 Mon Sep 17 00:00:00 2001 From: Ola Aunronning Date: Mon, 8 Apr 2024 13:52:44 +0200 Subject: Otel on logserver WIP --- config-model-api/abi-spec.json | 3 +- .../com/yahoo/config/model/api/ModelContext.java | 1 + .../yahoo/config/model/deploy/TestProperties.java | 7 ++++ .../model/admin/LogserverContainerCluster.java | 3 ++ .../model/admin/otel/OpenTelemetryCollector.java | 43 ++++++++++++++++++++ .../admin/otel/OpenTelemetryConfigGenerator.java | 46 ++++++++++++++++++++++ .../model/builder/xml/dom/DomAdminV4Builder.java | 12 ++++++ .../vespa/model/admin/DedicatedAdminV4Test.java | 21 ++++++++++ configdefinitions/src/vespa/open-telemetry.def | 5 +++ .../config/server/deploy/ModelContextImpl.java | 3 ++ .../src/main/java/com/yahoo/vespa/flags/Flags.java | 6 +++ 11 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 config-model/src/main/java/com/yahoo/vespa/model/admin/otel/OpenTelemetryCollector.java create mode 100644 config-model/src/main/java/com/yahoo/vespa/model/admin/otel/OpenTelemetryConfigGenerator.java create mode 100644 configdefinitions/src/vespa/open-telemetry.def diff --git a/config-model-api/abi-spec.json b/config-model-api/abi-spec.json index 9a975f1b727..2b2a51e1cc5 100644 --- a/config-model-api/abi-spec.json +++ b/config-model-api/abi-spec.json @@ -1324,7 +1324,8 @@ "public java.lang.String unknownConfigDefinition()", "public int searchHandlerThreadpool()", "public boolean alwaysMarkPhraseExpensive()", - "public boolean sortBlueprintsByCost()" + "public boolean sortBlueprintsByCost()", + "public boolean logserverOtelCol()" ], "fields" : [ ] }, diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java index 4a4d4648deb..7af9d9644e4 100644 --- a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java @@ -112,6 +112,7 @@ public interface ModelContext { @ModelFeatureFlag(owners = {"hmusum"}) default int searchHandlerThreadpool() { return 2; } @ModelFeatureFlag(owners = {"baldersheim"}) default boolean alwaysMarkPhraseExpensive() { return false; } @ModelFeatureFlag(owners = {"baldersheim"}) default boolean sortBlueprintsByCost() { return false; } + @ModelFeatureFlag(owners = {"olaa"}) default boolean logserverOtelCol() { return false; } } /** Warning: As elsewhere in this package, do not make backwards incompatible changes that will break old config models! */ diff --git a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java index 11d3a48ee51..72eabafadf6 100644 --- a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java +++ b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java @@ -83,6 +83,7 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea private boolean allowUserFilters = true; private List dataplaneTokens; private int contentLayerMetadataFeatureLevel = 0; + private boolean logserverOtelCol = false; @Override public ModelContext.FeatureFlags featureFlags() { return this; } @Override public boolean multitenant() { return multitenant; } @@ -139,6 +140,7 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea @Override public boolean allowUserFilters() { return allowUserFilters; } @Override public List dataplaneTokens() { return dataplaneTokens; } @Override public int contentLayerMetadataFeatureLevel() { return contentLayerMetadataFeatureLevel; } + @Override public boolean logserverOtelCol() { return logserverOtelCol; } public TestProperties sharedStringRepoNoReclaim(boolean sharedStringRepoNoReclaim) { this.sharedStringRepoNoReclaim = sharedStringRepoNoReclaim; @@ -369,6 +371,11 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea return this; } + public TestProperties setLogserverOtelCol(boolean logserverOtelCol) { + this.logserverOtelCol = logserverOtelCol; + return this; + } + public static class Spec implements ConfigServerSpec { private final String hostName; diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/LogserverContainerCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/LogserverContainerCluster.java index 654c81f0519..629ce54d9dd 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/LogserverContainerCluster.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/LogserverContainerCluster.java @@ -5,6 +5,8 @@ import com.yahoo.config.model.deploy.DeployState; import com.yahoo.config.model.producer.TreeConfigProducer; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.search.config.QrStartConfig; +import com.yahoo.vespa.model.admin.otel.OpenTelemetryCollector; +import com.yahoo.vespa.model.admin.otel.OpenTelemetryConfigGenerator; import com.yahoo.vespa.model.container.ContainerCluster; import com.yahoo.vespa.model.container.PlatformBundles; import com.yahoo.vespa.model.container.component.Handler; @@ -29,6 +31,7 @@ public class LogserverContainerCluster extends ContainerCluster parent, String config) { + super(parent, "otelcol"); + setProp("clustertype", "admin"); + setProp("clustername", "admin"); + this.config = config; + } + + /** + * @return the startup command for the otelcol wrapper + */ + @Override + public Optional getStartupCommand() { + return Optional.of("exec $ROOT/bin/vespa-otelcol-start"); + } + + + @Override + public void allocatePorts(int start, PortAllocBridge from) {} + + @Override + public int getPortCount() { + return 0; + } + + @Override + public void getConfig(OpenTelemetryConfig.Builder builder) { + builder.config(config); + } +} 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 new file mode 100644 index 00000000000..7d18cf36f58 --- /dev/null +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/otel/OpenTelemetryConfigGenerator.java @@ -0,0 +1,46 @@ +// 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; + +/** + * @author olaa + */ +public class OpenTelemetryConfigGenerator { + + // For now - just create dummy config + /* + TODO: Create config + 1. polling /state/v1 handler of every service + 2. Processing with mapping/filtering from metric sets + 3. Exporter to correct endpoint (alternatively amended) + */ + public static String generate() { + + return """ + receivers: + prometheus_simple: + collection_interval: 60s + endpoint: 'localhost:4080' + metrics_path: '/state/v1/metrics + params: + format: 'prometheus' + tls: + ca_file: '/opt/vespa/var/vespa//trust-store.pem' + cert_file: '/var/lib/sia/certs/vespa.external.cd.tenant.cert.pem' + insecure_skip_verify: true + key_file: '/var/lib/sia/keys/vespa.external.cd.tenant.key.pem' + exporters: + file: + path: /opt/vespa/logs/vespa/otel-test.json + rotation: + max_megabytes: 10 + max_days: 3 + max_backups: 1 + service: + pipelines: + metrics: + receivers: [ prometheus_simple ] + processors: [ ] + exporters: [ file ] + """; + } +} diff --git a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminV4Builder.java b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminV4Builder.java index f722cf375f3..79866980170 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminV4Builder.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminV4Builder.java @@ -4,6 +4,7 @@ package com.yahoo.vespa.model.builder.xml.dom; import com.yahoo.config.model.ConfigModelContext; import com.yahoo.config.model.api.ConfigServerSpec; import com.yahoo.config.model.deploy.DeployState; +import com.yahoo.config.model.producer.TreeConfigProducer; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.vespa.model.HostResource; import com.yahoo.vespa.model.HostSystem; @@ -12,6 +13,8 @@ import com.yahoo.vespa.model.admin.Logserver; import com.yahoo.vespa.model.admin.LogserverContainer; import com.yahoo.vespa.model.admin.LogserverContainerCluster; import com.yahoo.vespa.model.admin.Slobrok; +import com.yahoo.vespa.model.admin.otel.OpenTelemetryCollector; +import com.yahoo.vespa.model.admin.otel.OpenTelemetryConfigGenerator; import com.yahoo.vespa.model.container.Container; import com.yahoo.vespa.model.container.ContainerModel; import org.w3c.dom.Element; @@ -113,9 +116,18 @@ public class DomAdminV4Builder extends DomAdminBuilderBase { logServerCluster.addContainer(container); admin.addAndInitializeService(deployState, hostResource, container); admin.setLogserverContainerCluster(logServerCluster); + if (deployState.featureFlags().logserverOtelCol()) + addOtelcol(admin, deployState, hostResource); context.getConfigModelRepoAdder().add(logserverClusterModel); } + + private void addOtelcol(TreeConfigProducer parent, DeployState deployState, HostResource hostResource) { + var otelcol = new OpenTelemetryCollector(parent, OpenTelemetryConfigGenerator.generate()); + otelcol.setHostResource(hostResource); + otelcol.initService(deployState); + } + private Collection allocateHosts(HostSystem hostSystem, String clusterId, NodesSpecification nodesSpecification) { return nodesSpecification.provision(hostSystem, ClusterSpec.Type.admin, diff --git a/config-model/src/test/java/com/yahoo/vespa/model/admin/DedicatedAdminV4Test.java b/config-model/src/test/java/com/yahoo/vespa/model/admin/DedicatedAdminV4Test.java index 326fb633877..8265dac9751 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/admin/DedicatedAdminV4Test.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/admin/DedicatedAdminV4Test.java @@ -212,6 +212,27 @@ public class DedicatedAdminV4Test { METRICS_PROXY_CONTAINER.serviceName, LOGSERVER_CONTAINER.serviceName); } + @Test + void testOtelServiceWhenFeatureFlagEnabled() throws Exception { + String services = "" + + " " + + " " + + " " + + " " + + " " + + ""; + + VespaModel model = createModel(hosts, services, new DeployState.Builder() + .zone(new Zone(SystemName.Public, Environment.dev, RegionName.defaultName())) + .properties(new TestProperties() + .setLogserverOtelCol(true) + .setHostedVespa(true))); + assertEquals(1, model.getHosts().size()); + // Should create a logserver container on the same node as logserver + assertHostContainsServices(model, "hosts/myhost0", "slobrok", "logd", "logserver", "opentelemetrycollector", + METRICS_PROXY_CONTAINER.serviceName, LOGSERVER_CONTAINER.serviceName); + } + private Set serviceNames(VespaModel model, String hostname) { SentinelConfig config = model.getConfig(SentinelConfig.class, hostname); return config.service().stream().map(SentinelConfig.Service::name).collect(Collectors.toSet()); diff --git a/configdefinitions/src/vespa/open-telemetry.def b/configdefinitions/src/vespa/open-telemetry.def new file mode 100644 index 00000000000..15a0e92b32c --- /dev/null +++ b/configdefinitions/src/vespa/open-telemetry.def @@ -0,0 +1,5 @@ +# Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +namespace=cloud.config + +# For now - store entire config in one string +config string diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java index 26732d2e20f..d3c7a8f1c3e 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java @@ -206,6 +206,7 @@ public class ModelContextImpl implements ModelContext { private final int contentLayerMetadataFeatureLevel; private final String unknownConfigDefinition; private final int searchHandlerThreadpool; + private final boolean logserverOtelCol; public FeatureFlags(FlagSource source, ApplicationId appId, Version version) { this.defaultTermwiseLimit = flagValue(source, appId, version, Flags.DEFAULT_TERM_WISE_LIMIT); @@ -248,6 +249,7 @@ public class ModelContextImpl implements ModelContext { this.searchHandlerThreadpool = flagValue(source, appId, version, Flags.SEARCH_HANDLER_THREADPOOL); this.alwaysMarkPhraseExpensive = flagValue(source, appId, version, Flags.ALWAYS_MARK_PHRASE_EXPENSIVE); this.sortBlueprintsByCost = flagValue(source, appId, version, Flags.SORT_BLUEPRINTS_BY_COST); + this.logserverOtelCol = flagValue(source, appId, version, Flags.LOGSERVER_OTELCOL_AGENT); } @Override public int heapSizePercentage() { return heapPercentage; } @@ -298,6 +300,7 @@ public class ModelContextImpl implements ModelContext { @Override public String unknownConfigDefinition() { return unknownConfigDefinition; } @Override public int searchHandlerThreadpool() { return searchHandlerThreadpool; } @Override public boolean sortBlueprintsByCost() { return sortBlueprintsByCost; } + @Override public boolean logserverOtelCol() { return logserverOtelCol; } private static V flagValue(FlagSource source, ApplicationId appId, Version vespaVersion, UnboundFlag flag) { return flag.bindTo(source) diff --git a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java index 03a713f37f5..2c780990723 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java @@ -422,6 +422,12 @@ public class Flags { "Role definitions for the system", "Takes effect immediately"); + public static UnboundBooleanFlag LOGSERVER_OTELCOL_AGENT = defineFeatureFlag( + "logserver-otelcol-agent", false, + List.of("olaa"), "2024-04-03", "2024-12-31", + "Whether logserver container should run otel agent", + "Takes effect at redeployment", INSTANCE_ID); + /** WARNING: public for testing: All flags should be defined in {@link Flags}. */ public static UnboundBooleanFlag defineFeatureFlag(String flagId, boolean defaultValue, List owners, String createdAt, String expiresAt, String description, -- cgit v1.2.3