diff --git a/CHANGELOG.md b/CHANGELOG.md index 7abd1a58d58..26b8afe5810 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ The `strimzi.io/node-pools` and `strimzi.io/kraft` annotations are not required anymore and will be ignored if set. * Make properties `broker.session.timeout.ms`, `broker.heartbeat.interval.ms` and `controller.socket.timeout.ms` configurable * Add monitoring of custom resources using [kubernetes-state-metrics (KSM)](https://github.com/kubernetes/kube-state-metrics) (see [Strimzi proposal 087](https://github.com/strimzi/proposals/blob/main/087-monitoring-of-custom-resources.md)) +* Added support for Strimzi Metrics Reporter to Kafka Connect, Mirror Maker 2 and Kafka Bridge. ### Major changes, deprecations and removals @@ -14,6 +15,7 @@ * Disable Cruise Control network resource goals when resource capacities are not set. * The `strimzi_resource_state` metric in the Cluster Operator is deprecated and is planned to be removed in Strimzi 0.51. Use kube-state-metrics based metrics from the [examples](https://github.com/strimzi/strimzi-kafka-operator/tree/main/examples/metrics/kube-state-metrics) as a replacement. +* The field `.spec.enableMetrics` in KafkaBridge is now deprecated and replaced by `.spec.metricsConfig`. ## 0.47.0 diff --git a/api/src/main/java/io/strimzi/api/kafka/model/bridge/KafkaBridgeSpec.java b/api/src/main/java/io/strimzi/api/kafka/model/bridge/KafkaBridgeSpec.java index 49582c5a4aa..80d6e2df720 100644 --- a/api/src/main/java/io/strimzi/api/kafka/model/bridge/KafkaBridgeSpec.java +++ b/api/src/main/java/io/strimzi/api/kafka/model/bridge/KafkaBridgeSpec.java @@ -8,9 +8,11 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import io.fabric8.kubernetes.api.model.ResourceRequirements; +import io.strimzi.api.annotations.DeprecatedProperty; import io.strimzi.api.kafka.model.common.ClientTls; import io.strimzi.api.kafka.model.common.Constants; import io.strimzi.api.kafka.model.common.HasConfigurableLogging; +import io.strimzi.api.kafka.model.common.HasConfigurableMetrics; import io.strimzi.api.kafka.model.common.HasLivenessProbe; import io.strimzi.api.kafka.model.common.HasReadinessProbe; import io.strimzi.api.kafka.model.common.JvmOptions; @@ -19,11 +21,13 @@ import io.strimzi.api.kafka.model.common.Rack; import io.strimzi.api.kafka.model.common.Spec; import io.strimzi.api.kafka.model.common.authentication.KafkaClientAuthentication; +import io.strimzi.api.kafka.model.common.metrics.MetricsConfig; import io.strimzi.api.kafka.model.common.tracing.Tracing; import io.strimzi.crdgenerator.annotations.Description; import io.strimzi.crdgenerator.annotations.DescriptionFile; import io.strimzi.crdgenerator.annotations.KubeLink; import io.strimzi.crdgenerator.annotations.Minimum; +import io.strimzi.crdgenerator.annotations.PresentInVersions; import io.sundr.builder.annotations.Buildable; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -37,10 +41,10 @@ @JsonPropertyOrder({ "replicas", "image", "bootstrapServers", "tls", "authentication", "http", "adminClient", "consumer", "producer", "resources", "jvmOptions", "logging", "clientRackInitImage", "rack", - "enableMetrics", "livenessProbe", "readinessProbe", "template", "tracing"}) + "enableMetrics", "metricsConfig", "livenessProbe", "readinessProbe", "template", "tracing"}) @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) -public class KafkaBridgeSpec extends Spec implements HasConfigurableLogging, HasLivenessProbe, HasReadinessProbe { +public class KafkaBridgeSpec extends Spec implements HasConfigurableLogging, HasConfigurableMetrics, HasLivenessProbe, HasReadinessProbe { private static final int DEFAULT_REPLICAS = 1; private int replicas = DEFAULT_REPLICAS; @@ -57,6 +61,7 @@ public class KafkaBridgeSpec extends Spec implements HasConfigurableLogging, Has private JvmOptions jvmOptions; private Logging logging; private boolean enableMetrics; + private MetricsConfig metricsConfig; private Probe livenessProbe; private Probe readinessProbe; private KafkaBridgeTemplate template; @@ -76,6 +81,10 @@ public void setReplicas(int replicas) { this.replicas = replicas; } + @Deprecated + @DeprecatedProperty(movedToPath = ".spec.metricsConfig", + description = "The `enableMetrics` configuration is deprecated and will be removed in the future.") + @PresentInVersions("v1alpha1-v1beta2") @JsonInclude(JsonInclude.Include.NON_NULL) @Description("Enable the metrics for the Kafka Bridge. Default is false.") public boolean getEnableMetrics() { @@ -86,6 +95,18 @@ public void setEnableMetrics(boolean enableMetrics) { this.enableMetrics = enableMetrics; } + @Description("Metrics configuration.") + @JsonInclude(JsonInclude.Include.NON_EMPTY) + @Override + public MetricsConfig getMetricsConfig() { + return metricsConfig; + } + + @Override + public void setMetricsConfig(MetricsConfig metricsConfig) { + this.metricsConfig = metricsConfig; + } + @Description("Logging configuration for Kafka Bridge.") @JsonInclude(value = JsonInclude.Include.NON_NULL) @Override diff --git a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaBridgeCluster.java b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaBridgeCluster.java index 4864a906650..a97ac00ed75 100644 --- a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaBridgeCluster.java +++ b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaBridgeCluster.java @@ -35,6 +35,8 @@ import io.strimzi.api.kafka.model.common.JvmOptions; import io.strimzi.api.kafka.model.common.Rack; import io.strimzi.api.kafka.model.common.authentication.KafkaClientAuthentication; +import io.strimzi.api.kafka.model.common.metrics.JmxPrometheusExporterMetrics; +import io.strimzi.api.kafka.model.common.metrics.StrimziMetricsReporter; import io.strimzi.api.kafka.model.common.template.ContainerTemplate; import io.strimzi.api.kafka.model.common.template.DeploymentStrategy; import io.strimzi.api.kafka.model.common.template.DeploymentTemplate; @@ -46,6 +48,10 @@ import io.strimzi.operator.cluster.ClusterOperatorConfig; import io.strimzi.operator.cluster.model.logging.LoggingModel; import io.strimzi.operator.cluster.model.logging.SupportsLogging; +import io.strimzi.operator.cluster.model.metrics.JmxPrometheusExporterModel; +import io.strimzi.operator.cluster.model.metrics.MetricsModel; +import io.strimzi.operator.cluster.model.metrics.StrimziMetricsReporterModel; +import io.strimzi.operator.cluster.model.metrics.SupportsMetrics; import io.strimzi.operator.cluster.model.securityprofiles.ContainerSecurityProviderContextImpl; import io.strimzi.operator.cluster.model.securityprofiles.PodSecurityProviderContextImpl; import io.strimzi.operator.common.Reconciliation; @@ -65,7 +71,17 @@ * Kafka Bridge model class */ @SuppressWarnings({"checkstyle:ClassFanOutComplexity"}) -public class KafkaBridgeCluster extends AbstractModel implements SupportsLogging { +public class KafkaBridgeCluster extends AbstractModel implements SupportsLogging, SupportsMetrics { + /** + * Default Strimzi Metrics Reporter allow list. + * Check example dashboards compatibility in case of changes to existing regexes. + */ + private static final List DEFAULT_METRICS_ALLOW_LIST = List.of( + "kafka_consumer_consumer_metrics.*", + "kafka_producer_kafka_metrics_count_count", + "kafka_producer_producer_metrics.*" + ); + /** * HTTP port configuration */ @@ -77,7 +93,6 @@ public class KafkaBridgeCluster extends AbstractModel implements SupportsLogging protected static final String PASSWORD_VOLUME_MOUNT = "/opt/strimzi/bridge-password/"; protected static final String ENV_VAR_KAFKA_INIT_INIT_FOLDER_KEY = "INIT_FOLDER"; private static final String KAFKA_BRIDGE_CONFIG_VOLUME_NAME = "kafka-bridge-configurations"; - private static final String KAFKA_BRIDGE_CONFIG_VOLUME_MOUNT = "/opt/strimzi/custom-config/"; // Cluster Operator environment variables for custom discovery labels and annotations protected static final String CO_ENV_VAR_CUSTOM_SERVICE_LABELS = "STRIMZI_CUSTOM_KAFKA_BRIDGE_SERVICE_LABELS"; @@ -85,11 +100,10 @@ public class KafkaBridgeCluster extends AbstractModel implements SupportsLogging // Kafka Bridge configuration keys (EnvVariables) protected static final String ENV_VAR_PREFIX = "KAFKA_BRIDGE_"; - protected static final String ENV_VAR_KAFKA_BRIDGE_METRICS_ENABLED = "KAFKA_BRIDGE_METRICS_ENABLED"; protected static final String ENV_VAR_KAFKA_BRIDGE_TRUSTED_CERTS = "KAFKA_BRIDGE_TRUSTED_CERTS"; protected static final String OAUTH_TLS_CERTS_BASE_VOLUME_MOUNT = "/opt/strimzi/oauth-certs/"; protected static final String OAUTH_SECRETS_BASE_VOLUME_MOUNT = "/opt/strimzi/oauth/"; - + protected static final String KAFKA_BRIDGE_CONFIG_VOLUME_MOUNT = "/opt/strimzi/custom-config/"; protected static final String CO_ENV_VAR_CUSTOM_BRIDGE_POD_LABELS = "STRIMZI_CUSTOM_KAFKA_BRIDGE_LABELS"; protected static final String INIT_VOLUME_MOUNT = "/opt/strimzi/init"; @@ -106,8 +120,9 @@ public class KafkaBridgeCluster extends AbstractModel implements SupportsLogging private KafkaBridgeAdminClientSpec kafkaBridgeAdminClient; private KafkaBridgeConsumerSpec kafkaBridgeConsumer; private KafkaBridgeProducerSpec kafkaBridgeProducer; - private boolean isMetricsEnabled = false; + private boolean isLegacyMetricsConfigEnabled = false; private LoggingModel logging; + private MetricsModel metrics; // Templates private PodDisruptionBudgetTemplate templatePodDisruptionBudget; @@ -151,7 +166,7 @@ private KafkaBridgeCluster(Reconciliation reconciliation, HasMetadata resource, * @param sharedEnvironmentProvider Shared environment provider * @return KafkaBridgeCluster instance */ - @SuppressWarnings({"checkstyle:NPathComplexity"}) + @SuppressWarnings({"checkstyle:NPathComplexity", "deprecation"}) public static KafkaBridgeCluster fromCrd(Reconciliation reconciliation, KafkaBridge kafkaBridge, SharedEnvironmentProvider sharedEnvironmentProvider) { @@ -182,7 +197,14 @@ public static KafkaBridgeCluster fromCrd(Reconciliation reconciliation, result.readinessProbeOptions = ProbeUtils.extractReadinessProbeOptionsOrDefault(spec, ProbeUtils.DEFAULT_HEALTHCHECK_OPTIONS); result.livenessProbeOptions = ProbeUtils.extractLivenessProbeOptionsOrDefault(spec, ProbeUtils.DEFAULT_HEALTHCHECK_OPTIONS); - result.isMetricsEnabled = spec.getEnableMetrics(); + + if (spec.getMetricsConfig() instanceof JmxPrometheusExporterMetrics) { + result.metrics = new JmxPrometheusExporterModel(spec); + } else if (spec.getMetricsConfig() instanceof StrimziMetricsReporter) { + result.metrics = new StrimziMetricsReporterModel(spec, DEFAULT_METRICS_ALLOW_LIST); + } else { + result.isLegacyMetricsConfigEnabled = spec.getEnableMetrics(); + } result.setTls(spec.getTls() != null ? spec.getTls() : null); @@ -312,7 +334,7 @@ protected List getVolumeMounts() { return volumeMountList; } - + private List getInitContainerVolumeMounts() { List volumeMountList = new ArrayList<>(); volumeMountList.add(VolumeUtils.createVolumeMount(INIT_VOLUME_NAME, INIT_VOLUME_MOUNT)); @@ -396,7 +418,6 @@ private Container createContainer(ImagePullPolicy imagePullPolicy) { protected List getEnvVars() { List varList = new ArrayList<>(); - varList.add(ContainerUtils.createEnvVar(ENV_VAR_KAFKA_BRIDGE_METRICS_ENABLED, String.valueOf(isMetricsEnabled))); varList.add(ContainerUtils.createEnvVar(ENV_VAR_STRIMZI_GC_LOG_ENABLED, String.valueOf(gcLoggingEnabled))); JvmOptionUtils.javaOptions(varList, jvmOptions); @@ -555,8 +576,7 @@ public ConfigMap generateBridgeConfigMap(MetricsAndLogging metricsAndLogging) { // generate the ConfigMap data entries for the metrics and logging configuration Map data = ConfigMapUtils.generateMetricsAndLogConfigMapData(reconciliation, this, metricsAndLogging); // add the ConfigMap data entry for the bridge HTTP and Kafka clients related configuration - data.put( - BRIDGE_CONFIGURATION_FILENAME, + KafkaBridgeConfigurationBuilder builder = new KafkaBridgeConfigurationBuilder(reconciliation, cluster, bootstrapServers) .withTracing(tracing) .withTls(tls) @@ -564,9 +584,15 @@ public ConfigMap generateBridgeConfigMap(MetricsAndLogging metricsAndLogging) { .withKafkaAdminClient(kafkaBridgeAdminClient) .withKafkaProducer(kafkaBridgeProducer) .withKafkaConsumer(kafkaBridgeConsumer) - .withHttp(http, kafkaBridgeProducer, kafkaBridgeConsumer) - .build() - ); + .withHttp(http, kafkaBridgeProducer, kafkaBridgeConsumer); + + if ((metrics instanceof JmxPrometheusExporterModel) || isLegacyMetricsConfigEnabled) { + builder.withJmxPrometheusExporter((JmxPrometheusExporterModel) metrics, isLegacyMetricsConfigEnabled); + } else if (metrics instanceof StrimziMetricsReporterModel) { + builder.withStrimziMetricsReporter((StrimziMetricsReporterModel) metrics); + } + + data.put(BRIDGE_CONFIGURATION_FILENAME, builder.build()); return ConfigMapUtils .createConfigMap( @@ -591,4 +617,11 @@ public int getReplicas() { public LoggingModel logging() { return logging; } + + /** + * @return Metrics Model instance for configuring Prometheus metrics + */ + public MetricsModel metrics() { + return metrics; + } } diff --git a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaBridgeConfigurationBuilder.java b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaBridgeConfigurationBuilder.java index 3f0eae00fe0..1c5e6e954d3 100644 --- a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaBridgeConfigurationBuilder.java +++ b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaBridgeConfigurationBuilder.java @@ -18,13 +18,19 @@ import io.strimzi.api.kafka.model.common.authentication.KafkaClientAuthenticationScramSha256; import io.strimzi.api.kafka.model.common.authentication.KafkaClientAuthenticationScramSha512; import io.strimzi.api.kafka.model.common.authentication.KafkaClientAuthenticationTls; +import io.strimzi.api.kafka.model.common.metrics.JmxPrometheusExporterMetrics; import io.strimzi.api.kafka.model.common.tracing.Tracing; +import io.strimzi.operator.cluster.model.metrics.JmxPrometheusExporterModel; +import io.strimzi.operator.cluster.model.metrics.StrimziMetricsReporterConfig; +import io.strimzi.operator.cluster.model.metrics.StrimziMetricsReporterModel; import io.strimzi.operator.common.Reconciliation; import java.io.PrintWriter; import java.io.StringWriter; import java.util.stream.Collectors; +import static io.strimzi.api.kafka.model.common.metrics.StrimziMetricsReporter.TYPE_STRIMZI_METRICS_REPORTER; +import static io.strimzi.operator.cluster.model.KafkaBridgeCluster.KAFKA_BRIDGE_CONFIG_VOLUME_MOUNT; import static io.strimzi.operator.cluster.model.KafkaBridgeCluster.OAUTH_SECRETS_BASE_VOLUME_MOUNT; /** @@ -346,6 +352,53 @@ public KafkaBridgeConfigurationBuilder withHttp(KafkaBridgeHttpConfig http, Kafk return this; } + /** + * Configures the Strimzi Metrics Reporter. It is set only if user enables Strimzi Metrics Reporter. + * + * @param model Strimzi Metrics Reporter configuration + * + * @return Returns the builder instance + */ + public KafkaBridgeConfigurationBuilder withStrimziMetricsReporter(StrimziMetricsReporterModel model) { + if (model != null) { + printSectionHeader("Strimzi Metrics Reporter configuration"); + writer.println("bridge.metrics=" + TYPE_STRIMZI_METRICS_REPORTER); + // the kafka. prefix is required by the Bridge to pass Kafka client configurations + writer.println("kafka.metric.reporters=" + StrimziMetricsReporterConfig.KAFKA_CLASS); + writer.println("kafka." + StrimziMetricsReporterConfig.LISTENER_ENABLE + "=false"); + writer.println("kafka." + StrimziMetricsReporterConfig.ALLOW_LIST + "=" + model.getAllowList()); + writer.println(); + } + return this; + } + + /** + * Configures the JMX Prometheus Metrics Exporter. + * + * @param model JMX Prometheus Metrics Exporter configuration + * @param isLegacyMetricsConfigEnabled Flag which indicates whether the metrics are enabled or not in legacy mode. + * + * @return Returns the builder instance + */ + public KafkaBridgeConfigurationBuilder withJmxPrometheusExporter( + JmxPrometheusExporterModel model, boolean isLegacyMetricsConfigEnabled) { + if (model != null || isLegacyMetricsConfigEnabled) { + printSectionHeader("Prometheus JMX Exporter configuration"); + writer.println("bridge.metrics=" + JmxPrometheusExporterMetrics.TYPE_JMX_EXPORTER); + + // if isLegacyMetricsConfigEnabled is not used, we pass the path of the config file. + // If it is used, the Bridge will use the fallback config. + if (!isLegacyMetricsConfigEnabled) { + writer.println("bridge.metrics.exporter.config.path=" + + KAFKA_BRIDGE_CONFIG_VOLUME_MOUNT + JmxPrometheusExporterModel.CONFIG_MAP_KEY); + } + + writer.println(); + } + + return this; + } + /** * Prints the file header which is on the beginning of the configuration file. */ diff --git a/cluster-operator/src/main/java/io/strimzi/operator/cluster/operator/assembly/KafkaBridgeAssemblyOperator.java b/cluster-operator/src/main/java/io/strimzi/operator/cluster/operator/assembly/KafkaBridgeAssemblyOperator.java index c59a9f12788..b0b469deaed 100644 --- a/cluster-operator/src/main/java/io/strimzi/operator/cluster/operator/assembly/KafkaBridgeAssemblyOperator.java +++ b/cluster-operator/src/main/java/io/strimzi/operator/cluster/operator/assembly/KafkaBridgeAssemblyOperator.java @@ -103,7 +103,7 @@ protected Future createOrUpdate(Reconciliation reconciliation .compose(i -> bridgeInitClusterRoleBinding(reconciliation, initCrbName, initCrb)) .compose(i -> deploymentOperations.scaleDown(reconciliation, namespace, bridge.getComponentName(), bridge.getReplicas(), operationTimeoutMs)) .compose(scale -> serviceOperations.reconcile(reconciliation, namespace, KafkaBridgeResources.serviceName(bridge.getCluster()), bridge.generateService())) - .compose(i -> MetricsAndLoggingUtils.metricsAndLogging(reconciliation, configMapOperations, bridge.logging(), null)) + .compose(i -> MetricsAndLoggingUtils.metricsAndLogging(reconciliation, configMapOperations, bridge.logging(), bridge.metrics())) .compose(metricsAndLogging -> { ConfigMap configMap = bridge.generateBridgeConfigMap(metricsAndLogging); podAnnotations.put(Annotations.ANNO_STRIMZI_IO_CONFIGURATION_HASH, Util.hashStub(configMap.getData().get(KafkaBridgeCluster.BRIDGE_CONFIGURATION_FILENAME))); diff --git a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaBridgeClusterTest.java b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaBridgeClusterTest.java index 0b38ca3bae0..ff592bc8dc7 100644 --- a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaBridgeClusterTest.java +++ b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaBridgeClusterTest.java @@ -7,6 +7,8 @@ import io.fabric8.kubernetes.api.model.Affinity; import io.fabric8.kubernetes.api.model.AffinityBuilder; import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapKeySelector; +import io.fabric8.kubernetes.api.model.ConfigMapKeySelectorBuilder; import io.fabric8.kubernetes.api.model.ConfigMapVolumeSource; import io.fabric8.kubernetes.api.model.ConfigMapVolumeSourceBuilder; import io.fabric8.kubernetes.api.model.Container; @@ -58,6 +60,7 @@ import io.strimzi.operator.cluster.ResourceUtils; import io.strimzi.operator.cluster.model.logging.LoggingModel; import io.strimzi.operator.cluster.model.metrics.JmxPrometheusExporterModel; +import io.strimzi.operator.cluster.model.metrics.StrimziMetricsReporterModel; import io.strimzi.operator.common.Reconciliation; import io.strimzi.operator.common.model.InvalidResourceException; import io.strimzi.operator.common.model.Labels; @@ -77,6 +80,7 @@ import static io.strimzi.operator.cluster.model.KafkaBridgeCluster.BRIDGE_CONFIGURATION_FILENAME; import static io.strimzi.operator.cluster.model.KafkaBridgeCluster.ENV_VAR_KAFKA_INIT_INIT_FOLDER_KEY; +import static io.strimzi.operator.cluster.model.metrics.JmxPrometheusExporterModel.CONFIG_MAP_KEY; import static java.util.Collections.emptyMap; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; @@ -142,7 +146,6 @@ private Map expectedSelectorLabels() { protected List getExpectedEnvVars() { List expected = new ArrayList<>(); - expected.add(new EnvVarBuilder().withName(KafkaBridgeCluster.ENV_VAR_KAFKA_BRIDGE_METRICS_ENABLED).withValue(String.valueOf(true)).build()); expected.add(new EnvVarBuilder().withName(KafkaBridgeCluster.ENV_VAR_STRIMZI_GC_LOG_ENABLED).withValue(String.valueOf(JvmOptions.DEFAULT_GC_LOGGING_ENABLED)).build()); return expected; } @@ -158,7 +161,6 @@ private static VolumeMount getVolumeMount(Container container, String volumeName @ParallelTest public void testDefaultValues() { KafkaBridgeCluster kbc = KafkaBridgeCluster.fromCrd(Reconciliation.DUMMY_RECONCILIATION, ResourceUtils.createEmptyKafkaBridge(namespace, cluster), SHARED_ENV_PROVIDER); - assertThat(kbc.image, is("quay.io/strimzi/kafka-bridge:latest")); assertThat(kbc.getReplicas(), is(1)); assertThat(kbc.readinessProbeOptions.getInitialDelaySeconds(), is(15)); @@ -952,20 +954,13 @@ public void testNullClusterRoleBinding() { @ParallelTest public void testKafkaBridgeContainerEnvVarsConflict() { ContainerEnvVar envVar1 = new ContainerEnvVar(); - String testEnvOneKey = KafkaBridgeCluster.ENV_VAR_KAFKA_BRIDGE_METRICS_ENABLED; - String testEnvOneValue = "false"; - envVar1.setName(testEnvOneKey); - envVar1.setValue(testEnvOneValue); - - ContainerEnvVar envVar2 = new ContainerEnvVar(); - String testEnvTwoKey = KafkaBridgeCluster.ENV_VAR_KAFKA_BRIDGE_TRUSTED_CERTS; - String testEnvTwoValue = "PEM certs"; - envVar2.setName(testEnvTwoKey); - envVar2.setValue(testEnvTwoValue); + String testEnvKey = KafkaBridgeCluster.ENV_VAR_KAFKA_BRIDGE_TRUSTED_CERTS; + String testEnvValue = "PEM certs"; + envVar1.setName(testEnvKey); + envVar1.setValue(testEnvValue); List testEnvs = new ArrayList<>(); testEnvs.add(envVar1); - testEnvs.add(envVar2); ContainerTemplate kafkaBridgeContainer = new ContainerTemplate(); kafkaBridgeContainer.setEnv(testEnvs); @@ -985,12 +980,9 @@ public void testKafkaBridgeContainerEnvVarsConflict() { List kafkaEnvVars = KafkaBridgeCluster.fromCrd(Reconciliation.DUMMY_RECONCILIATION, resource, SHARED_ENV_PROVIDER).getEnvVars(); - assertThat("Failed to prevent over writing existing container environment variable: " + testEnvOneKey, - kafkaEnvVars.stream().filter(env -> testEnvOneKey.equals(env.getName())) - .map(EnvVar::getValue).findFirst().orElse("").equals(testEnvOneValue), is(false)); - assertThat("Failed to prevent over writing existing container environment variable: " + testEnvTwoKey, - kafkaEnvVars.stream().filter(env -> testEnvTwoKey.equals(env.getName())) - .map(EnvVar::getValue).findFirst().orElse("").equals(testEnvTwoValue), is(false)); + assertThat("Failed to prevent over writing existing container environment variable: " + testEnvKey, + kafkaEnvVars.stream().filter(env -> testEnvKey.equals(env.getName())) + .map(EnvVar::getValue).findFirst().orElse("").equals(testEnvValue), is(false)); } @ParallelTest @@ -1479,10 +1471,72 @@ public void testConsumerProducerOptions() { public void testConfigurationConfigMap() { KafkaBridgeCluster kb = KafkaBridgeCluster.fromCrd(Reconciliation.DUMMY_RECONCILIATION, this.resource, SHARED_ENV_PROVIDER); ConfigMap configMap = kb.generateBridgeConfigMap(metricsAndLogging); - assertThat(configMap, is(notNullValue())); assertThat(configMap.getData().get(LoggingModel.LOG4J2_CONFIG_MAP_KEY), is(notNullValue())); - assertThat(configMap.getData().get(JmxPrometheusExporterModel.CONFIG_MAP_KEY), is(nullValue())); + assertThat(configMap.getData().get(CONFIG_MAP_KEY), is(nullValue())); assertThat(configMap.getData().get(KafkaBridgeCluster.BRIDGE_CONFIGURATION_FILENAME), is(notNullValue())); } + + @ParallelTest + public void testMetricsParsingFromConfigMap() { + KafkaBridge resource = new KafkaBridgeBuilder(this.resource) + .editSpec() + .withNewJmxPrometheusExporterMetricsConfig() + .withNewValueFrom() + .withConfigMapKeyRef(new ConfigMapKeySelectorBuilder().withName("my-metrics-configuration").withKey("config.yaml").build()) + .endValueFrom() + .endJmxPrometheusExporterMetricsConfig() + .endSpec() + .build(); + KafkaBridgeCluster kbc = KafkaBridgeCluster.fromCrd(Reconciliation.DUMMY_RECONCILIATION, resource, SHARED_ENV_PROVIDER); + + assertThat(kbc.metrics(), is(notNullValue())); + assertThat(((JmxPrometheusExporterModel) kbc.metrics()).getConfigMapName(), is("my-metrics-configuration")); + assertThat(((JmxPrometheusExporterModel) kbc.metrics()).getConfigMapKey(), is("config.yaml")); + } + + @ParallelTest + public void testMetricsParsingNoMetrics() { + KafkaBridge resource = new KafkaBridgeBuilder(this.resource) + .build(); + KafkaBridgeCluster kbc = KafkaBridgeCluster.fromCrd(Reconciliation.DUMMY_RECONCILIATION, resource, SHARED_ENV_PROVIDER); + assertThat(kbc.metrics(), is(nullValue())); + } + + @ParallelTest + public void testStrimziMetricsReporterConfig() { + KafkaBridge resource = new KafkaBridgeBuilder(this.resource) + .editSpec() + .withNewStrimziMetricsReporterConfig() + .withNewValues() + .withAllowList("kafka_producer_producer_metrics.*,kafka_producer_kafka_metrics_count_count") + .endValues() + .endStrimziMetricsReporterConfig() + .endSpec() + .build(); + + KafkaBridgeCluster kbc = KafkaBridgeCluster.fromCrd(Reconciliation.DUMMY_RECONCILIATION, resource, SHARED_ENV_PROVIDER); + + assertThat(kbc.metrics(), is(notNullValue())); + assertThat(((StrimziMetricsReporterModel) kbc.metrics()).getAllowList(), is("kafka_producer_producer_metrics.*,kafka_producer_kafka_metrics_count_count")); + } + + @ParallelTest + public void testJmxPrometheusExporterConfig() { + KafkaBridge resource = new KafkaBridgeBuilder(this.resource) + .editSpec() + .withNewJmxPrometheusExporterMetricsConfig() + .withNewValueFrom() + .withConfigMapKeyRef(new ConfigMapKeySelector("bridge-metrics", "metrics-config.yml", false)) + .endValueFrom() + .endJmxPrometheusExporterMetricsConfig() + .endSpec() + .build(); + + KafkaBridgeCluster kbc = KafkaBridgeCluster.fromCrd(Reconciliation.DUMMY_RECONCILIATION, resource, SHARED_ENV_PROVIDER); + + assertThat(kbc.metrics(), is(notNullValue())); + assertThat(((JmxPrometheusExporterModel) kbc.metrics()).getConfigMapKey(), is("bridge-metrics")); + assertThat(((JmxPrometheusExporterModel) kbc.metrics()).getConfigMapName(), is("metrics-config.yml")); + } } diff --git a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaBridgeConfigurationBuilderTest.java b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaBridgeConfigurationBuilderTest.java index a55a264a05f..ddd7ef4beb7 100644 --- a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaBridgeConfigurationBuilderTest.java +++ b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaBridgeConfigurationBuilderTest.java @@ -12,6 +12,7 @@ import io.strimzi.api.kafka.model.bridge.KafkaBridgeHttpConfigBuilder; import io.strimzi.api.kafka.model.bridge.KafkaBridgeProducerSpec; import io.strimzi.api.kafka.model.bridge.KafkaBridgeProducerSpecBuilder; +import io.strimzi.api.kafka.model.bridge.KafkaBridgeSpecBuilder; import io.strimzi.api.kafka.model.common.ClientTls; import io.strimzi.api.kafka.model.common.ClientTlsBuilder; import io.strimzi.api.kafka.model.common.authentication.KafkaClientAuthenticationOAuth; @@ -24,11 +25,17 @@ import io.strimzi.api.kafka.model.common.authentication.KafkaClientAuthenticationScramSha512Builder; import io.strimzi.api.kafka.model.common.authentication.KafkaClientAuthenticationTls; import io.strimzi.api.kafka.model.common.authentication.KafkaClientAuthenticationTlsBuilder; +import io.strimzi.api.kafka.model.common.metrics.JmxPrometheusExporterMetrics; +import io.strimzi.api.kafka.model.common.metrics.StrimziMetricsReporter; import io.strimzi.api.kafka.model.common.tracing.OpenTelemetryTracing; +import io.strimzi.operator.cluster.model.metrics.JmxPrometheusExporterModel; +import io.strimzi.operator.cluster.model.metrics.StrimziMetricsReporterConfig; +import io.strimzi.operator.cluster.model.metrics.StrimziMetricsReporterModel; import io.strimzi.operator.common.Reconciliation; import io.strimzi.test.annotations.ParallelSuite; import io.strimzi.test.annotations.ParallelTest; +import java.util.List; import java.util.Map; import static io.strimzi.operator.cluster.TestUtils.IsEquivalent.isEquivalent; @@ -592,4 +599,68 @@ public void testHttp() { "http.producer.enabled=true" )); } + + @ParallelTest + public void testWithStrimziMetricsReporter() { + StrimziMetricsReporterModel model = new StrimziMetricsReporterModel( + new KafkaBridgeSpecBuilder() + .withNewStrimziMetricsReporterConfig() + .withNewValues() + .withAllowList("kafka_producer_producer_metrics.*,kafka_producer_kafka_metrics_count_count") + .endValues() + .endStrimziMetricsReporterConfig() + .build(), List.of(".*")); + + String configuration = new KafkaBridgeConfigurationBuilder(Reconciliation.DUMMY_RECONCILIATION, BRIDGE_CLUSTER, BRIDGE_BOOTSTRAP_SERVERS) + .withStrimziMetricsReporter(model) + .build(); + + assertThat(configuration, isEquivalent( + "bridge.id=my-bridge", + "kafka.bootstrap.servers=my-cluster-kafka-bootstrap:9092", + "bridge.metrics=" + StrimziMetricsReporter.TYPE_STRIMZI_METRICS_REPORTER, + "kafka.metric.reporters=" + StrimziMetricsReporterConfig.KAFKA_CLASS, + "kafka." + StrimziMetricsReporterConfig.ALLOW_LIST + "=kafka_producer_producer_metrics.*,kafka_producer_kafka_metrics_count_count", + "kafka." + StrimziMetricsReporterConfig.LISTENER_ENABLE + "=false", + "kafka.security.protocol=PLAINTEXT" + )); + } + + @ParallelTest + public void testWithPrometheusJmxExporterLegacyMode() { + String configuration = new KafkaBridgeConfigurationBuilder(Reconciliation.DUMMY_RECONCILIATION, BRIDGE_CLUSTER, BRIDGE_BOOTSTRAP_SERVERS) + .withJmxPrometheusExporter(null, true) + .build(); + + assertThat(configuration, isEquivalent( + "bridge.id=my-bridge", + "bridge.metrics=" + JmxPrometheusExporterMetrics.TYPE_JMX_EXPORTER, + "kafka.bootstrap.servers=my-cluster-kafka-bootstrap:9092", + "kafka.security.protocol=PLAINTEXT" + )); + } + + @ParallelTest + public void testWithPrometheusJmxExporter() { + JmxPrometheusExporterModel model = new JmxPrometheusExporterModel( + new KafkaBridgeSpecBuilder() + .withNewJmxPrometheusExporterMetricsConfig() + .withNewValueFrom() + .withNewConfigMapKeyRef("bridge-metrics", "metrics.json", false) + .endValueFrom() + .endJmxPrometheusExporterMetricsConfig() + .build()); + + String configuration = new KafkaBridgeConfigurationBuilder(Reconciliation.DUMMY_RECONCILIATION, BRIDGE_CLUSTER, BRIDGE_BOOTSTRAP_SERVERS) + .withJmxPrometheusExporter(model, false) + .build(); + + assertThat(configuration, isEquivalent( + "bridge.id=my-bridge", + "bridge.metrics=" + JmxPrometheusExporterMetrics.TYPE_JMX_EXPORTER, + "kafka.bootstrap.servers=my-cluster-kafka-bootstrap:9092", + "bridge.metrics.exporter.config.path=" + KafkaBridgeCluster.KAFKA_BRIDGE_CONFIG_VOLUME_MOUNT + JmxPrometheusExporterModel.CONFIG_MAP_KEY, + "kafka.security.protocol=PLAINTEXT" + )); + } } diff --git a/cluster-operator/src/test/java/io/strimzi/operator/cluster/operator/assembly/KafkaBridgeAssemblyOperatorTest.java b/cluster-operator/src/test/java/io/strimzi/operator/cluster/operator/assembly/KafkaBridgeAssemblyOperatorTest.java index a51689289e8..e34c24ca5fd 100644 --- a/cluster-operator/src/test/java/io/strimzi/operator/cluster/operator/assembly/KafkaBridgeAssemblyOperatorTest.java +++ b/cluster-operator/src/test/java/io/strimzi/operator/cluster/operator/assembly/KafkaBridgeAssemblyOperatorTest.java @@ -169,7 +169,7 @@ public void testCreateOrUpdateCreatesCluster(VertxTestContext context) { assertThat(dc.getMetadata().getName(), is(bridge.getComponentName())); assertThat(dc, is(bridge.generateDeployment(Map.of( Annotations.ANNO_STRIMZI_AUTH_HASH, "0", - Annotations.ANNO_STRIMZI_IO_CONFIGURATION_HASH, "fe8e7089" + Annotations.ANNO_STRIMZI_IO_CONFIGURATION_HASH, "eeacc2f1" ), true, null, null))); // Verify PodDisruptionBudget @@ -340,7 +340,7 @@ public void testCreateOrUpdateUpdatesCluster(VertxTestContext context) { assertThat(dc.getMetadata().getName(), is(compareTo.getComponentName())); assertThat(dc, is(compareTo.generateDeployment(Map.of( Annotations.ANNO_STRIMZI_AUTH_HASH, "0", - Annotations.ANNO_STRIMZI_IO_CONFIGURATION_HASH, "fe8e7089" + Annotations.ANNO_STRIMZI_IO_CONFIGURATION_HASH, "eeacc2f1" ), true, null, null))); // Verify PodDisruptionBudget diff --git a/development-docs/systemtests/io.strimzi.systemtest.metrics.StrimziMetricsReporterST.md b/development-docs/systemtests/io.strimzi.systemtest.metrics.StrimziMetricsReporterST.md index 2c7c16b5bee..b5e83479f0e 100644 --- a/development-docs/systemtests/io.strimzi.systemtest.metrics.StrimziMetricsReporterST.md +++ b/development-docs/systemtests/io.strimzi.systemtest.metrics.StrimziMetricsReporterST.md @@ -25,6 +25,26 @@
+## testKafkaBridgeMetrics + +**Description:** This test case checks several metrics exposed by KafkaBridge. + +**Steps:** + +| Step | Action | Result | +| - | - | - | +| 1. | Deploy KafkaBridge into {@namespace}. | KafkaBridge is deployed and Ready | +| 2. | Attach producer and consumer clients to KafkaBridge | Clients are up and running, continuously producing and pooling messages | +| 3. | Collect metrics from KafkaBridge pod | Metrics are collected | +| 4. | Check that specific metric is available in collected metrics from KafkaBridge pods | Metric is available with expected value | + +**Labels:** + +* [kafka](labels/kafka.md) +* [metrics](labels/metrics.md) +* [bridge](labels/bridge.md) + + ## testKafkaConnectAndConnectorMetrics **Description:** This test case checks several random metrics exposed by Kafka Connect. diff --git a/documentation/modules/appendix_crds.adoc b/documentation/modules/appendix_crds.adoc index 2c9dd838adb..ac94c84aea1 100644 --- a/documentation/modules/appendix_crds.adoc +++ b/documentation/modules/appendix_crds.adoc @@ -1020,7 +1020,7 @@ It must have the value `password` for the type `KafkaJmxAuthenticationPassword`. [id='type-JmxPrometheusExporterMetrics-{context}'] = `JmxPrometheusExporterMetrics` schema reference -Used in: xref:type-CruiseControlSpec-{context}[`CruiseControlSpec`], xref:type-KafkaClusterSpec-{context}[`KafkaClusterSpec`], xref:type-KafkaConnectSpec-{context}[`KafkaConnectSpec`], xref:type-KafkaMirrorMaker2Spec-{context}[`KafkaMirrorMaker2Spec`], xref:type-ZookeeperClusterSpec-{context}[`ZookeeperClusterSpec`] +Used in: xref:type-CruiseControlSpec-{context}[`CruiseControlSpec`], xref:type-KafkaBridgeSpec-{context}[`KafkaBridgeSpec`], xref:type-KafkaClusterSpec-{context}[`KafkaClusterSpec`], xref:type-KafkaConnectSpec-{context}[`KafkaConnectSpec`], xref:type-KafkaMirrorMaker2Spec-{context}[`KafkaMirrorMaker2Spec`], xref:type-ZookeeperClusterSpec-{context}[`ZookeeperClusterSpec`] The `type` property is a discriminator that distinguishes use of the `JmxPrometheusExporterMetrics` type from xref:type-StrimziMetricsReporter-{context}[`StrimziMetricsReporter`]. @@ -1053,7 +1053,7 @@ Used in: xref:type-ExternalLogging-{context}[`ExternalLogging`], xref:type-JmxPr [id='type-StrimziMetricsReporter-{context}'] = `StrimziMetricsReporter` schema reference -Used in: xref:type-CruiseControlSpec-{context}[`CruiseControlSpec`], xref:type-KafkaClusterSpec-{context}[`KafkaClusterSpec`], xref:type-KafkaConnectSpec-{context}[`KafkaConnectSpec`], xref:type-KafkaMirrorMaker2Spec-{context}[`KafkaMirrorMaker2Spec`], xref:type-ZookeeperClusterSpec-{context}[`ZookeeperClusterSpec`] +Used in: xref:type-CruiseControlSpec-{context}[`CruiseControlSpec`], xref:type-KafkaBridgeSpec-{context}[`KafkaBridgeSpec`], xref:type-KafkaClusterSpec-{context}[`KafkaClusterSpec`], xref:type-KafkaConnectSpec-{context}[`KafkaConnectSpec`], xref:type-KafkaMirrorMaker2Spec-{context}[`KafkaMirrorMaker2Spec`], xref:type-ZookeeperClusterSpec-{context}[`ZookeeperClusterSpec`] The `type` property is a discriminator that distinguishes use of the `StrimziMetricsReporter` type from xref:type-JmxPrometheusExporterMetrics-{context}[`JmxPrometheusExporterMetrics`]. @@ -3784,7 +3784,10 @@ include::../api/io.strimzi.api.kafka.model.bridge.KafkaBridgeSpec.adoc[leveloffs |Configuration of the node label which will be used as the client.rack consumer configuration. |enableMetrics |boolean -|Enable the metrics for the Kafka Bridge. Default is false. +|**The `enableMetrics` property has been deprecated, and should now be configured using `.spec.metricsConfig`.** The `enableMetrics` configuration is deprecated and will be removed in the future. Enable the metrics for the Kafka Bridge. Default is false. +|metricsConfig +|xref:type-JmxPrometheusExporterMetrics-{context}[`JmxPrometheusExporterMetrics`], xref:type-StrimziMetricsReporter-{context}[`StrimziMetricsReporter`] +|Metrics configuration. |livenessProbe |xref:type-Probe-{context}[`Probe`] |Pod liveness checking. diff --git a/packaging/examples/metrics/kafka-bridge-metrics.yaml b/packaging/examples/metrics/kafka-bridge-metrics.yaml index a9e2a89fcf8..6e8db06ca0f 100644 --- a/packaging/examples/metrics/kafka-bridge-metrics.yaml +++ b/packaging/examples/metrics/kafka-bridge-metrics.yaml @@ -7,4 +7,131 @@ spec: bootstrapServers: my-cluster-kafka-bootstrap:9092 http: port: 8080 - enableMetrics: true + metricsConfig: + type: jmxPrometheusExporter + valueFrom: + configMapKeyRef: + name: bridge-metrics + key: metrics-config.yml +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: bridge-metrics + labels: + app: strimzi +data: + metrics-config.yml: | + # See https://github.com/prometheus/jmx_exporter for more info about JMX Prometheus Exporter metrics + lowercaseOutputName: true + rules: + # more specific rules to consumer and producer with topic related information + - pattern: kafka.producer<>([a-z-]+)-total + name: strimzi_bridge_kafka_producer_$4_total + type: COUNTER + labels: + type: "$1" + clientId: "$2" + topic: "$3" + - pattern: kafka.producer<>([a-z-]+) + name: strimzi_bridge_kafka_producer_$4 + type: GAUGE + labels: + type: "$1" + clientId: "$2" + topic: "$3" + - pattern: kafka.consumer<>([a-z-]+)-total + name: strimzi_bridge_kafka_consumer_$4_total + type: COUNTER + labels: + type: "$1" + clientId: "$2" + topic: "$3" + - pattern: kafka.consumer<>([a-z-]+) + name: strimzi_bridge_kafka_consumer_$4 + type: GAUGE + labels: + type: "$1" + clientId: "$2" + topic: "$3" + # more general metrics + - pattern: kafka.(\w+)<>([a-z-]+-total-[a-z-]+) # handles the metrics with total in the middle of the metric name + name: strimzi_bridge_kafka_$1_$4 + type: GAUGE + labels: + type: "$2" + clientId: "$3" + - pattern: kafka.(\w+)<>([a-z-]+)-total + name: strimzi_bridge_kafka_$1_$4_total + type: COUNTER + labels: + type: "$2" + clientId: "$3" + - pattern: kafka.(\w+)<>([a-z-]+) + name: strimzi_bridge_kafka_$1_$4 + type: GAUGE + labels: + type: "$2" + clientId: "$3" + # OAuth Metrics + # WARNING: Make sure that the ordering of the attributes is the same as in MBean names + - pattern: "strimzi.oauth<>(count|totalTimeMs):" + name: "strimzi_oauth_$1_$12" + type: COUNTER + labels: + context: "$2" + kind: "$3" + host: "$4" + path: "$5" + "$6": "$7" + "$8": "$9" + "$10": "$11" + - pattern: "strimzi.oauth<>(count|totalTimeMs):" + name: "strimzi_oauth_$1_$10" + type: COUNTER + labels: + context: "$2" + kind: "$3" + host: "$4" + path: "$5" + "$6": "$7" + "$8": "$9" + - pattern: "strimzi.oauth<>(count|totalTimeMs):" + name: "strimzi_oauth_$1_$8" + type: COUNTER + labels: + context: "$2" + kind: "$3" + host: "$4" + path: "$5" + "$6": "$7" + - pattern: "strimzi.oauth<>(.+):" + name: "strimzi_oauth_$1_$12" + type: GAUGE + labels: + context: "$2" + kind: "$3" + host: "$4" + path: "$5" + "$6": "$7" + "$8": "$9" + "$10": "$11" + - pattern: "strimzi.oauth<>(.+):" + name: "strimzi_oauth_$1_$10" + type: GAUGE + labels: + context: "$2" + kind: "$3" + host: "$4" + path: "$5" + "$6": "$7" + "$8": "$9" + - pattern: "strimzi.oauth<>(.+):" + name: "strimzi_oauth_$1_$8" + type: GAUGE + labels: + context: "$2" + kind: "$3" + host: "$4" + path: "$5" + "$6": "$7" diff --git a/packaging/examples/metrics/strimzi-metrics-reporter/grafana-dashboards/strimzi-kafka-bridge.json b/packaging/examples/metrics/strimzi-metrics-reporter/grafana-dashboards/strimzi-kafka-bridge.json new file mode 100644 index 00000000000..7f9e80cce69 --- /dev/null +++ b/packaging/examples/metrics/strimzi-metrics-reporter/grafana-dashboards/strimzi-kafka-bridge.json @@ -0,0 +1,3025 @@ +{ + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "7.4.5" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus" + }, + { + "type": "panel", + "id": "timeseries", + "name": "Timeseries" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 16, + "links": [], + "panels": [ + { + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 40, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "refId": "A" + } + ], + "title": "Overview", + "type": "row" + }, + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 0, + "y": 1 + }, + "id": 19, + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(strimzi_bridge_http_server_active_connections{container=~\"^.+-bridge\"})", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "HTTP connections", + "type": "stat" + }, + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 4, + "y": 1 + }, + "id": 20, + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(strimzi_bridge_http_server_active_requests{container=~\"^.+-bridge\"})", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "HTTP requests being processed", + "type": "stat" + }, + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "0" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 8, + "y": 1 + }, + "id": 43, + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "count(kafka_producer_kafka_metrics_count_count)", + "format": "time_series", + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "KafkaProducer instances", + "type": "stat" + }, + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "0" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 12, + "y": 1 + }, + "id": 44, + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(kafka_producer_producer_metrics_connection_count)", + "format": "time_series", + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "KafkaProducers connections", + "type": "stat" + }, + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "0" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 1 + }, + "id": 26, + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(kafka_consumer_consumer_coordinator_metrics_last_heartbeat_seconds_ago != bool -1)", + "format": "time_series", + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "KafkaConsumer instances", + "type": "stat" + }, + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "0" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 1 + }, + "id": 42, + "maxDataPoints": 100, + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(kafka_consumer_consumer_metrics_connection_count)", + "format": "time_series", + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "KafkaConsumers connections", + "type": "stat" + }, + { + "collapsed": true, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 38, + "panels": [ + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "records/sec", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 6 + }, + "id": 22, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(rate(kafka_producer_producer_topic_metrics_record_send{topic != \"\"}[5m])) by (client_id, topic)", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "title": "Producer rate", + "type": "timeseries" + }, + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes/sec", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 6 + }, + "id": 24, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(rate(kafka_producer_producer_topic_metrics_byte{topic != \"\"}[5m])) by (clientId, topic)", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "title": "Producer rate", + "type": "timeseries" + }, + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "ms", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 45, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(kafka_producer_producer_node_metrics_request_latency_avg{}) by (client_id)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "Average producer request latency", + "type": "timeseries" + }, + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes/sec", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 14 + }, + "id": 25, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(rate(kafka_consumer_consumer_fetch_manager_metrics_bytes_consumed{topic != \"\"}[5m])) by (clientId, topic)", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "title": "Consumer rate", + "type": "timeseries" + }, + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "records/sec", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 22 + }, + "id": 23, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(rate(kafka_consumer_consumer_fetch_manager_metrics_records_consumed{topic != \"\"}[5m])) by (clientId, topic)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "refId": "B" + } + ], + "title": "Consumer rate", + "type": "timeseries" + }, + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "partitions", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 22 + }, + "id": 28, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(kafka_consumer_consumer_coordinator_metrics_assigned_partitions) by (clientId)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Consumer Assigned Partitions", + "type": "timeseries" + }, + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "sec", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 30 + }, + "id": 46, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(kafka_consumer_consumer_metrics_poll_idle_ratio_avg) by (clientId)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Average consumer idle poll", + "type": "timeseries" + }, + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "commits/sec", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 30 + }, + "id": 41, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(rate(kafka_consumer_consumer_coordinator_metrics_commit[5m])) by (clientId)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Consumer commit rate", + "type": "timeseries" + }, + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "ms", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 38 + }, + "id": 47, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(kafka_consumer_consumer_coordinator_metrics_commit_latency_avg) by (clientId)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Consumer commits latency", + "type": "timeseries" + }, + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "requests/sec", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 38 + }, + "id": 48, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(kafka_consumer_consumer_fetch_manager_metrics_fetch_rate) by (clientId)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Consumer fetch rate", + "type": "timeseries" + }, + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "ms", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 46 + }, + "id": 49, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(kafka_consumer_consumer_fetch_manager_metrics_fetch_latency_avg) by (clientId)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Average consumer fetch latency", + "type": "timeseries" + } + ], + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "refId": "A" + } + ], + "title": "Kafka", + "type": "row" + }, + { + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 36, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "refId": "A" + } + ], + "title": "HTTP", + "type": "row" + }, + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "requests/sec", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "bars", + "fillOpacity": 100, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 7 + }, + "id": 15, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(rate(strimzi_bridge_http_server_requests_total{container=~\"^.+-bridge\"}[5m])) by (method)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Requests rate by HTTP method", + "type": "timeseries" + }, + { + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "requests/sec", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 7 + }, + "id": 17, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(rate(strimzi_bridge_http_server_requests_total{container=~\"^.+-bridge\"}[5m]))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Requests", + "refId": "A" + }, + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(rate(strimzi_bridge_http_server_requests_total{code=~\"^2..$\", container=~\"^.+-bridge\"}[5m]))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "2XX", + "refId": "B" + }, + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(rate(strimzi_bridge_http_server_requests_total{code=~\"^4..$\", container=~\"^.+-bridge\"}[5m]))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "4XX", + "refId": "C" + }, + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(rate(strimzi_bridge_http_server_requests_total{code=~\"^5..$\", container=~\"^.+-bridge\"}[5m]))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "5XX", + "refId": "D" + } + ], + "title": "HTTP Requests and Response rate by codes", + "type": "timeseries" + }, + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes/sec", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 15 + }, + "id": 13, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(rate(strimzi_bridge_http_server_bytes_written_total{container=~\"^.+-bridge\"}[5m])) by (container)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "HTTP send rate", + "type": "timeseries" + }, + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "bytes/sec", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 15 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(rate(strimzi_bridge_http_server_bytes_read_total{container=~\"^.+-bridge\"}[5m])) by (container)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "HTTP receive rate", + "type": "timeseries" + }, + { + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "requests/sec", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 23 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(rate(strimzi_bridge_http_server_requests_total{container=~\"^.+-bridge\",method=\"POST\",path=~\"/topics/[^/]+\"}[5m])) by (path)", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "title": "Send messages rate", + "type": "timeseries" + }, + { + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "requests/sec", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 23 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(rate(strimzi_bridge_http_server_requests_total{container=~\"^.+-bridge\",method=\"POST\",path=~\"/topics/.+/partitions/[0-9]+\"}[5m])) by (path)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Send messages To Partition rate", + "type": "timeseries" + }, + { + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "requests/sec", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 31 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(rate(strimzi_bridge_http_server_requests_total{container=~\"^.+-bridge\",method=\"POST\",path=~\"/consumers/[^/]+\"}[5m])) by (path)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Consumer instance creation rate", + "type": "timeseries" + }, + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "requests/sec", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 31 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(rate(strimzi_bridge_http_server_requests_total{container=~\"^.+-bridge\",method=\"POST\",path=~\"/consumers/.+/instances/.+/subscription\"}[5m])) by (path)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Subscribe to topics rate", + "type": "timeseries" + }, + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "requests/sec", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 31 + }, + "id": 9, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(rate(strimzi_bridge_http_server_requests_total{container=~\"^.+-bridge\",method=\"DELETE\",path=~\"/consumers/.+/instances/.+\"}[5m])) by (path)", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Consumer instance deletion rate", + "type": "timeseries" + }, + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "requests/sec", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 39 + }, + "id": 8, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(rate(strimzi_bridge_http_server_requests_total{container=~\"^.+-bridge\",method=\"GET\",path=~\"/consumers/.+/instances/.+/records\"}[5m])) by (path)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Poll for messages rate", + "type": "timeseries" + }, + { + "datasource": "${DS_PROMETHEUS}", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "requests/sec", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 39 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(rate(strimzi_bridge_http_server_requests_total{container=~\"^.+-bridge\",method=\"POST\",path=~\"/consumers/.+/instances/.+/offsets\"}[5m])) by (path)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Commit offsets rate", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 34, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "refId": "A" + } + ], + "title": "JVM", + "type": "row" + }, + { + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 48 + }, + "id": 30, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(jvm_memory_used_bytes{container=~\"^.+-bridge\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "JVM Memory Used", + "type": "timeseries" + }, + { + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 48 + }, + "id": 31, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(rate(jvm_gc_pause_seconds_sum{container=~\"^.+-bridge\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "JVM GC Time", + "type": "timeseries" + }, + { + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 48 + }, + "id": 32, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "datasource": "${DS_PROMETHEUS}", + "expr": "sum(rate(jvm_gc_pause_seconds_count{container=~\"^.+-bridge\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "title": "JVM GC Count", + "type": "timeseries" + } + ], + "refresh": "5s", + "schemaVersion": 39, + "tags": [ + "Strimzi", + "Kafka", + "Kafka Bridge" + ], + "templating": { + "list": [ + { + "current": {}, + "error": null, + "hide": 0, + "includeAll": false, + "label": "datasource", + "multi": false, + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "kubernetes_namespace", + "options": [], + "query": "query_result(strimzi_bridge_http_server_active_connections)", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "", + "hide": 0, + "includeAll": false, + "label": "Container Name", + "multi": false, + "name": "bridge_container_name", + "options": [], + "query": "query_result(strimzi_bridge_http_server_active_connections{namespace=\"$kubernetes_namespace\"})", + "refresh": 1, + "regex": "/.*container=\"([^\"]*).*/", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Strimzi Kafka Bridge", + "version": 6, + "weekStart": "" +} diff --git a/packaging/examples/metrics/strimzi-metrics-reporter/kafka-bridge-metrics.yaml b/packaging/examples/metrics/strimzi-metrics-reporter/kafka-bridge-metrics.yaml new file mode 100644 index 00000000000..e77821bfd29 --- /dev/null +++ b/packaging/examples/metrics/strimzi-metrics-reporter/kafka-bridge-metrics.yaml @@ -0,0 +1,11 @@ +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaBridge +metadata: + name: my-bridge +spec: + replicas: 1 + bootstrapServers: my-cluster-kafka-bootstrap:9092 + http: + port: 8080 + metricsConfig: + type: strimziMetricsReporter diff --git a/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/046-Crd-kafkabridge.yaml b/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/046-Crd-kafkabridge.yaml index 95e7ff9b72d..b589d44efbd 100644 --- a/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/046-Crd-kafkabridge.yaml +++ b/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/046-Crd-kafkabridge.yaml @@ -444,6 +444,44 @@ spec: enableMetrics: type: boolean description: Enable the metrics for the Kafka Bridge. Default is false. + metricsConfig: + type: object + properties: + type: + type: string + enum: + - jmxPrometheusExporter + - strimziMetricsReporter + description: Metrics type. The supported types are `jmxPrometheusExporter` and `strimziMetricsReporter`. Type `jmxPrometheusExporter` uses the Prometheus JMX Exporter to expose Kafka JMX metrics in Prometheus format through an HTTP endpoint. Type `strimziMetricsReporter` uses the Strimzi Metrics Reporter to directly expose Kafka metrics in Prometheus format through an HTTP endpoint. + valueFrom: + type: object + properties: + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to the key in the ConfigMap containing the configuration. + description: ConfigMap entry where the Prometheus JMX Exporter configuration is stored. + values: + type: object + properties: + allowList: + type: array + items: + type: string + description: A list of regex patterns to filter the metrics to collect. Should contain at least one element. + description: Configuration values for the Strimzi Metrics Reporter. + required: + - type + description: Metrics configuration. + x-kubernetes-validations: + - rule: self.type != 'jmxPrometheusExporter' || has(self.valueFrom) + message: valueFrom property is required livenessProbe: type: object properties: diff --git a/packaging/install/cluster-operator/046-Crd-kafkabridge.yaml b/packaging/install/cluster-operator/046-Crd-kafkabridge.yaml index 8cb6dbe8610..0b108bc5d2e 100644 --- a/packaging/install/cluster-operator/046-Crd-kafkabridge.yaml +++ b/packaging/install/cluster-operator/046-Crd-kafkabridge.yaml @@ -443,6 +443,44 @@ spec: enableMetrics: type: boolean description: Enable the metrics for the Kafka Bridge. Default is false. + metricsConfig: + type: object + properties: + type: + type: string + enum: + - jmxPrometheusExporter + - strimziMetricsReporter + description: Metrics type. The supported types are `jmxPrometheusExporter` and `strimziMetricsReporter`. Type `jmxPrometheusExporter` uses the Prometheus JMX Exporter to expose Kafka JMX metrics in Prometheus format through an HTTP endpoint. Type `strimziMetricsReporter` uses the Strimzi Metrics Reporter to directly expose Kafka metrics in Prometheus format through an HTTP endpoint. + valueFrom: + type: object + properties: + configMapKeyRef: + type: object + properties: + key: + type: string + name: + type: string + optional: + type: boolean + description: Reference to the key in the ConfigMap containing the configuration. + description: ConfigMap entry where the Prometheus JMX Exporter configuration is stored. + values: + type: object + properties: + allowList: + type: array + items: + type: string + description: A list of regex patterns to filter the metrics to collect. Should contain at least one element. + description: Configuration values for the Strimzi Metrics Reporter. + required: + - type + description: Metrics configuration. + x-kubernetes-validations: + - rule: self.type != 'jmxPrometheusExporter' || has(self.valueFrom) + message: valueFrom property is required livenessProbe: type: object properties: diff --git a/systemtest/src/test/java/io/strimzi/systemtest/metrics/StrimziMetricsReporterST.java b/systemtest/src/test/java/io/strimzi/systemtest/metrics/StrimziMetricsReporterST.java index c828c02fa2f..b5c8769c3e5 100644 --- a/systemtest/src/test/java/io/strimzi/systemtest/metrics/StrimziMetricsReporterST.java +++ b/systemtest/src/test/java/io/strimzi/systemtest/metrics/StrimziMetricsReporterST.java @@ -10,15 +10,20 @@ import io.skodjob.annotations.SuiteDoc; import io.skodjob.annotations.TestDoc; import io.skodjob.testframe.resources.KubeResourceManager; +import io.strimzi.api.kafka.model.bridge.KafkaBridgeResources; +import io.strimzi.api.kafka.model.kafka.KafkaResources; import io.strimzi.operator.common.Annotations; import io.strimzi.systemtest.AbstractST; import io.strimzi.systemtest.Environment; import io.strimzi.systemtest.TestConstants; import io.strimzi.systemtest.annotations.ParallelTest; import io.strimzi.systemtest.docs.TestDocsLabels; +import io.strimzi.systemtest.kafkaclients.internalClients.BridgeClients; +import io.strimzi.systemtest.kafkaclients.internalClients.BridgeClientsBuilder; import io.strimzi.systemtest.performance.gather.collectors.BaseMetricsCollector; import io.strimzi.systemtest.resources.operator.SetupClusterOperator; import io.strimzi.systemtest.storage.TestStorage; +import io.strimzi.systemtest.templates.crd.KafkaBridgeTemplates; import io.strimzi.systemtest.templates.crd.KafkaConnectTemplates; import io.strimzi.systemtest.templates.crd.KafkaConnectorTemplates; import io.strimzi.systemtest.templates.crd.KafkaMirrorMaker2Templates; @@ -26,6 +31,7 @@ import io.strimzi.systemtest.templates.crd.KafkaTemplates; import io.strimzi.systemtest.templates.crd.KafkaTopicTemplates; import io.strimzi.systemtest.templates.specific.ScraperTemplates; +import io.strimzi.systemtest.utils.kubeUtils.objects.NetworkPolicyUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.junit.jupiter.api.BeforeAll; @@ -35,6 +41,7 @@ import java.util.concurrent.locks.LockSupport; import static io.strimzi.systemtest.TestTags.ACCEPTANCE; +import static io.strimzi.systemtest.TestTags.BRIDGE; import static io.strimzi.systemtest.TestTags.CONNECT; import static io.strimzi.systemtest.TestTags.CONNECT_COMPONENTS; import static io.strimzi.systemtest.TestTags.METRICS; @@ -43,6 +50,7 @@ import static io.strimzi.systemtest.TestTags.SANITY; import static io.strimzi.systemtest.utils.specific.MetricsUtils.assertMetricValue; import static io.strimzi.systemtest.utils.specific.MetricsUtils.assertMetricValueHigherThanOrEqualTo; +import static io.strimzi.systemtest.utils.specific.MetricsUtils.assertMetricValueNotNull; import static org.junit.jupiter.api.Assumptions.assumeFalse; @Tag(SANITY) @@ -72,6 +80,7 @@ public class StrimziMetricsReporterST extends AbstractST { private static final int TARGET_BROKER_REPLICAS = 3; private static final String CONNECT_CLUSTER_NAME = "my-connect"; private static final String MM2_CLUSTER_NAME = "my-mm2"; + private static final String BRIDGE_NAME = "my-bridge"; private TestStorage testStorage; private BaseMetricsCollector kafkaCollector; @@ -200,6 +209,68 @@ void testMirrorMaker2Metrics() { assertMetricValueHigherThanOrEqualTo(kmm2Collector, "kafka_connect_connect_worker_metrics_task_count", 0.0); } + @ParallelTest + @Tag(BRIDGE) + @Tag(ACCEPTANCE) + @TestDoc( + description = @Desc("This test case checks several metrics exposed by KafkaBridge."), + steps = { + @Step(value = "Deploy KafkaBridge into {@namespace}.", expected = "KafkaBridge is deployed and Ready"), + @Step(value = "Attach producer and consumer clients to KafkaBridge", expected = "Clients are up and running, continuously producing and pooling messages"), + @Step(value = "Collect metrics from KafkaBridge pod", expected = "Metrics are collected"), + @Step(value = "Check that specific metric is available in collected metrics from KafkaBridge pods", expected = "Metric is available with expected value") + }, + labels = { + @Label(value = TestDocsLabels.KAFKA), + @Label(value = TestDocsLabels.METRICS), + @Label(value = TestDocsLabels.BRIDGE) + } + ) + void testKafkaBridgeMetrics() { + KubeResourceManager.get().createResourceWithWait( + KafkaBridgeTemplates.kafkaBridge(testStorage.getNamespaceName(), BRIDGE_NAME, + KafkaResources.plainBootstrapAddress(testStorage.getClusterName()), 1) + .editSpec() + .withNewStrimziMetricsReporterConfig() + .withNewValues() + .withAllowList("kafka.*,strimzi_bridge.*") + .endValues() + .endStrimziMetricsReporterConfig() + .endSpec().build() + ); + + // allow connections from scraper to Bridge pods when NetworkPolicies are set to denied by default + NetworkPolicyUtils.allowNetworkPolicySettingsForBridgeScraper(testStorage.getNamespaceName(), + testStorage.getScraperName(), KafkaBridgeResources.componentName(BRIDGE_NAME)); + + BridgeClients kafkaBridgeClientJob = new BridgeClientsBuilder() + .withNamespaceName(testStorage.getNamespaceName()) + .withProducerName(testStorage.getProducerName()) + .withConsumerName(testStorage.getConsumerName()) + .withBootstrapAddress(KafkaBridgeResources.serviceName(BRIDGE_NAME)) + .withComponentName(KafkaBridgeResources.componentName(BRIDGE_NAME)) + .withTopicName(testStorage.getTopicName()) + .withMessageCount(testStorage.getMessageCount()) + .withPort(TestConstants.HTTP_BRIDGE_DEFAULT_PORT) + .withDelayMs(200) + .withPollInterval(200) + .build(); + + KubeResourceManager.get().createResourceWithoutWait( + kafkaBridgeClientJob.producerStrimziBridge(), + kafkaBridgeClientJob.consumerStrimziBridge() + ); + + BaseMetricsCollector bridgeCollector = kafkaCollector.toBuilder() + .withComponent(KafkaBridgeMetricsComponent.create(testStorage.getNamespaceName(), BRIDGE_NAME)) + .build(); + + bridgeCollector.collectMetricsFromPods(TestConstants.METRICS_COLLECT_TIMEOUT); + + assertMetricValueNotNull(bridgeCollector, "kafka_producer_kafka_metrics_count_count\\{.*}"); + assertMetricValueNotNull(bridgeCollector, "kafka_consumer_consumer_metrics_connection_count\\{.*}"); + } + @BeforeAll void setupEnvironment() { testStorage = new TestStorage(KubeResourceManager.get().getTestContext());